fix(agents): reject nonportable Windows drive links

This commit is contained in:
4gray committed 2026-09-21 07:57:13 +02:00
1 parent 1cdb2019d1
commit 6d2ba2c5f2
3 files changed
+25 -3

No files matched your search

+1 -1
View File
@@ -66,7 +66,7 @@ The first active HTML base href sets reference resolution, including nested srcd
Resolved file URLs use native filesystem conversion, including Windows drive paths.
Explicit srcset attributes must contain at least one parsed candidate.
Image and media references require a nonempty path that resolves to a file, not a directory.
Direct file URLs and file-scheme HTML bases are rejected; use portable repository-relative paths.
Direct file URLs, Windows drive paths and HTML bases using either form are rejected; use portable repository-relative paths.
Image references check file existence without interpreting image fragments as
Markdown headings; document links keep anchor checks even when sharing a target.
SVG image/use hrefs (including xlink), HTML image-input, video, audio, source and track `src` assets and video posters use the same
+8 -2
View File
@@ -41,6 +41,8 @@ async function validateReference(
) {
if (unresolvedReference !== undefined)
return `${source}: unresolved Markdown reference "${unresolvedReference}"`;
if (/^[a-z]:[\\/]/iu.test(target))
return `${source}: use a repository-relative path instead of a Windows drive path: ${target}`;
if (/^file:/iu.test(target))
return `${source}: use a repository-relative path instead of a file URL: ${target}`;
if (image && !target) return `${source}: empty media target`;
@@ -49,8 +51,12 @@ async function validateReference(
try {
let base = pathToFileURL(resolve(rootDir, source));
for (const href of bases) {
if (/^file:/iu.test(href.replace(/[\t\n\r]/gu, '').trimStart()))
return `${source}: use a repository-relative HTML base instead of a file URL`;
if (
/^(?:file:|[a-z]:[\\/])/iu.test(
href.replace(/[\t\n\r]/gu, '').trimStart()
)
)
return `${source}: use a repository-relative HTML base instead of a file URL or Windows drive path`;
base = new URL(href, base);
}
const url = new URL(target, base);
@@ -1850,3 +1850,19 @@ for (const prose of [
);
});
}
for (const reference of [
'[Guide](C:/workspace/docs/missing.md)',
'<a href="c:\\workspace\\docs\\missing.md">Guide</a>',
'<base href="https://example.com/"><a href="D:/docs/guide.md">Guide</a>',
'<base href="C:/workspace/"><a href="docs/example.md">Guide</a>',
'<base href="c:\\workspace\\"><a href="docs/example.md">Guide</a>',
]) {
test(`Windows drive paths require portable references: ${reference}`, async (t) => {
assert.ok(
(await diagnostics(t, { 'AGENTS.md': reference })).some((message) =>
message.includes('repository-relative')
)
);
});
}