mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-12 12:06:16 -08:00
fix(agents): validate generic literal repository paths
This commit is contained in:
1 parent
8467b9406a
commit
a10045f0b2
5 files changed
+99
-9
No files matched your search
@@ -108,7 +108,7 @@ use repository documentation and available CLI discovery.
|
||||
## General Guidelines for working with Nx
|
||||
|
||||
- For workspace exploration, use the `nx-workspace` skill when available;
|
||||
otherwise inspect `project.json`, `pnpm nx show projects` and `pnpm nx graph`.
|
||||
otherwise inspect project-local project.json files, `pnpm nx show projects` and `pnpm nx graph`.
|
||||
- Run project tasks through local `pnpm nx`, not a global Nx installation.
|
||||
- Use the Nx MCP server when available; otherwise use CLI discovery.
|
||||
- Check `node_modules/@nx/<plugin>/PLUGIN.md` for plugin guidance when present.
|
||||
|
||||
@@ -31,6 +31,11 @@ Run `pnpm run agents:validate` after guidance changes. It checks line/byte budge
|
||||
root imports and local navigation links/anchors, including migration destinations.
|
||||
Markdown navigation is parsed with the already-declared `marked` dependency;
|
||||
undefined explicit reference links are errors, and code examples are excluded.
|
||||
Backticked concrete paths in root guidance and the context map are checked from
|
||||
the repository root, including unknown top-level directories and filenames.
|
||||
Write generic filenames as prose; commands, templates, globs, URLs, package
|
||||
aliases and recognized JavaScript globals are excluded. Use Markdown links for
|
||||
ambiguous filenames that resemble code symbols.
|
||||
Heading anchors are derived from parsed text, not HTML sanitization. The Nx test
|
||||
hash includes `marked` so dependency changes invalidate parser coverage.
|
||||
It cannot prove semantic equivalence; review changed contracts as well.
|
||||
|
||||
@@ -11,7 +11,7 @@ are not prerequisites for reading repository contracts.
|
||||
|
||||
| Area / code ownership | Canonical documents | Repository skill |
|
||||
| --- | --- | --- |
|
||||
| Bootstrap, project placement, dependencies, aliases and lint configuration; root Nx config and `project.json` files | [Nx boundaries](../architecture/nx-workspace-boundaries.md), [security overrides](../architecture/dependency-security-overrides.md) | [Nx architecture](../../.codex/skills/iptvnator-nx-architecture/SKILL.md) |
|
||||
| Bootstrap, project placement, dependencies, aliases and lint configuration; root Nx config and project-local project.json files | [Nx boundaries](../architecture/nx-workspace-boundaries.md), [security overrides](../architecture/dependency-security-overrides.md) | [Nx architecture](../../.codex/skills/iptvnator-nx-architecture/SKILL.md) |
|
||||
| Angular conventions; docs and skills maintenance | [Agent workflow](../development/agent-workflow.md) | Use the area's skill below |
|
||||
| Unit, E2E, lint and coverage; `tools/coverage` | [Validation map](../architecture/validation-map.md) | Use the area's validation section |
|
||||
| Electron entry/events/preload and CDP; `apps/electron-backend` | [Debugging and trace flags](../development/electron-debugging.md), [Electron security](../architecture/electron-security.md) | Use the available global electron skill for automation |
|
||||
|
||||
@@ -60,15 +60,26 @@ export function guidanceAnchors(markdown) {
|
||||
}
|
||||
|
||||
function isLiteralRepositoryPath(token) {
|
||||
const local =
|
||||
/^(?:apps|libs|docs|tools|patches|\.codex|\.claude|\.github|\.changes|\.plans)\//u.test(
|
||||
// A typo in the directory or a new root filename must still be checked.
|
||||
// Exclude recognizable prose/code forms instead of allowlisting paths.
|
||||
if (/^(?:@|--|[a-z][a-z\d+.-]*:|\/\/)/iu.test(token)) return false;
|
||||
if (/[^\p{L}\p{N}_./#-]/u.test(token)) return false;
|
||||
if (token.includes('YYYY-MM-DD') || /(?:^|\/)\.\.\.(?:\/|$)/u.test(token))
|
||||
return false;
|
||||
// Recognized JavaScript globals are code-symbol exceptions, not a claim
|
||||
// that every dotted code expression can be distinguished from a filename.
|
||||
if (
|
||||
/^(?:window|document|console|process|globalThis|this|Math|JSON|Object|Array|Promise|Reflect|Symbol)\.[\p{L}_][\p{L}\p{N}_]*$/u.test(
|
||||
token
|
||||
) ||
|
||||
/^(?:AGENTS\.md|CLAUDE\.md|README\.md|package\.json|pnpm-lock\.yaml|pnpm-workspace\.yaml|nx\.json|tsconfig\.base\.json|eslint\.config\.mjs|\.nvmrc)$/u.test(
|
||||
token
|
||||
);
|
||||
)
|
||||
)
|
||||
return false;
|
||||
const path = token.split('#')[0];
|
||||
return (
|
||||
local && !/[\s*?[\]{}<>|]/u.test(token) && !token.includes('YYYY-MM-DD')
|
||||
path.includes('/') ||
|
||||
/^(?:\.[\p{L}\p{N}_-]+|[\p{L}\p{N}_-][\p{L}\p{N}_.-]*\.[\p{L}][\p{L}\p{N}_-]*)$/u.test(
|
||||
path
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -165,6 +165,80 @@ test('literal root paths validate without interpreting commands or globs', async
|
||||
/does not exist/
|
||||
);
|
||||
});
|
||||
for (const path of [
|
||||
'lib/definitely-missing.ts',
|
||||
'services/definitely-missing.ts',
|
||||
'electron-builder.json',
|
||||
'custom.config-format',
|
||||
'.custom-config',
|
||||
'arbitrary/directory',
|
||||
]) {
|
||||
test(`checks generic literal repository path ${path}`, async (t) => {
|
||||
assert.match(
|
||||
(await diagnostics(t, { [map]: '`' + path + '`' })).join('\n'),
|
||||
/does not exist/
|
||||
);
|
||||
assert.deepEqual(
|
||||
await diagnostics(t, { [map]: '`' + path + '`', [path]: '' }),
|
||||
[]
|
||||
);
|
||||
});
|
||||
}
|
||||
test('AGENTS rejects the reported unlisted directory and root filename', async (t) => {
|
||||
const errors = await diagnostics(t, {
|
||||
'AGENTS.md':
|
||||
'`services/definitely-missing.ts` and `electron-builder.json`',
|
||||
});
|
||||
assert.equal(errors.length, 2);
|
||||
assert.match(
|
||||
errors.join('\n'),
|
||||
/does not exist: services\/definitely-missing\.ts/
|
||||
);
|
||||
assert.match(errors.join('\n'), /does not exist: electron-builder\.json/);
|
||||
});
|
||||
test('literal paths retain fragment checks', async (t) => {
|
||||
assert.deepEqual(
|
||||
await diagnostics(t, { [map]: '`docs/example.md#hello-world`' }),
|
||||
[]
|
||||
);
|
||||
assert.match(
|
||||
(await diagnostics(t, { [map]: '`docs/example.md#missing`' })).join(
|
||||
'\n'
|
||||
),
|
||||
/missing anchor/
|
||||
);
|
||||
});
|
||||
test('literal detection excludes commands, templates, URLs, aliases and code expressions', async (t) => {
|
||||
const examples = [
|
||||
'pnpm nx test web',
|
||||
'node tools/example.mjs',
|
||||
'--config=missing.json',
|
||||
'docs/*.md',
|
||||
'docs/{one,two}.md',
|
||||
'docs/<topic>.md',
|
||||
'.plans/YYYY-MM-DD-short-topic.md',
|
||||
'docs/.../example.md',
|
||||
'https://example.com/guide.md',
|
||||
'file:///tmp/example.md',
|
||||
'@iptvnator/services',
|
||||
'@angular/core',
|
||||
'node:fs/promises',
|
||||
'window.electron',
|
||||
'document.body',
|
||||
'process.env',
|
||||
'this.store',
|
||||
'store.setState()',
|
||||
'source?.id',
|
||||
'a/b+c',
|
||||
'$HOME/example.md',
|
||||
];
|
||||
assert.deepEqual(
|
||||
await diagnostics(t, {
|
||||
[map]: examples.map((value) => '`' + value + '`').join(' '),
|
||||
}),
|
||||
[]
|
||||
);
|
||||
});
|
||||
test('rejects traversal and symlink escapes', async (t) => {
|
||||
const rootDir = await fixture(t, {
|
||||
'AGENTS.md': '[Escape](../outside.md) [Symlink](outside)',
|
||||
|
||||
Reference in new issue
Block a user