@agentvibes/guardrails 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +131 -5
- package/dist/astGrep.d.ts +3 -0
- package/dist/astGrep.js +15 -2
- package/dist/astGrep.js.map +1 -1
- package/dist/doctor.js +38 -2
- package/dist/doctor.js.map +1 -1
- package/dist/hookPostedit.js +18 -1
- package/dist/hookPostedit.js.map +1 -1
- package/dist/presetDrift.d.ts +31 -0
- package/dist/presetDrift.js +226 -0
- package/dist/presetDrift.js.map +1 -0
- package/dist/presetDriftTest.d.ts +1 -0
- package/dist/presetDriftTest.js +136 -0
- package/dist/presetDriftTest.js.map +1 -0
- package/dist/repoRules.d.ts +27 -0
- package/dist/repoRules.js +86 -0
- package/dist/repoRules.js.map +1 -0
- package/dist/repoRulesTest.d.ts +1 -0
- package/dist/repoRulesTest.js +122 -0
- package/dist/repoRulesTest.js.map +1 -0
- package/dist/screenScope.d.ts +16 -5
- package/dist/screenScope.js +66 -21
- package/dist/screenScope.js.map +1 -1
- package/dist/screenScopeTest.js +67 -7
- package/dist/screenScopeTest.js.map +1 -1
- package/dist/siblingCloneTest.d.ts +1 -0
- package/dist/siblingCloneTest.js +201 -0
- package/dist/siblingCloneTest.js.map +1 -0
- package/dist/testRules.js +77 -0
- package/dist/testRules.js.map +1 -1
- package/dist/twinCoverageTest.d.ts +1 -0
- package/dist/twinCoverageTest.js +262 -0
- package/dist/twinCoverageTest.js.map +1 -0
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js +33 -8
- package/dist/verify.js.map +1 -1
- package/dist/verifyDiff.js +6 -5
- package/dist/verifyDiff.js.map +1 -1
- package/package.json +7 -3
- package/rules/__fixtures__/demo-mode-by-default/bad.ts +22 -0
- package/rules/__fixtures__/demo-mode-by-default/bad.tsx +22 -0
- package/rules/__fixtures__/demo-mode-by-default/good.ts +21 -0
- package/rules/__fixtures__/demo-mode-by-default/good.tsx +21 -0
- package/rules/__fixtures__/json-roundtrip/bad.ts +6 -0
- package/rules/__fixtures__/json-roundtrip/bad.tsx +8 -0
- package/rules/__fixtures__/json-roundtrip/good.ts +5 -0
- package/rules/__fixtures__/json-roundtrip/good.tsx +7 -0
- package/rules/__fixtures__/kind-if-without-match/bad.ts +17 -0
- package/rules/__fixtures__/kind-if-without-match/bad.tsx +18 -0
- package/rules/__fixtures__/kind-if-without-match/good.ts +14 -0
- package/rules/__fixtures__/kind-if-without-match/good.tsx +13 -0
- package/rules/__fixtures__/literal-union-in-component/components/bad.tsx +16 -0
- package/rules/__fixtures__/literal-union-in-component/components/good.tsx +25 -0
- package/rules/__fixtures__/non-exhaustive-match/bad.tsx +12 -0
- package/rules/__fixtures__/non-exhaustive-match/good.tsx +14 -0
- package/rules/__fixtures__/silent-default-return/bad.ts +9 -0
- package/rules/__fixtures__/silent-default-return/bad.tsx +10 -0
- package/rules/__fixtures__/silent-default-return/good.ts +17 -0
- package/rules/__fixtures__/silent-default-return/good.tsx +11 -0
- package/rules/demo-mode-by-default-ts.yml +17 -1
- package/rules/demo-mode-by-default.yml +17 -1
- package/rules/json-roundtrip-tsx.yml +26 -0
- package/rules/kind-if-without-match-tsx.yml +31 -0
- package/rules/literal-union-in-component-tsx.yml +81 -0
- package/rules/no-local-kit-clone-tsx.yml +16 -0
- package/rules/no-local-kit-clone.yml +16 -0
- package/rules/non-exhaustive-match-tsx.yml +48 -0
- package/rules/silent-default-return-tsx.yml +33 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presetDrift.js","sourceRoot":"","sources":["../src/presetDrift.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { packageRoot } from "./packagePaths.js";
|
|
6
|
+
import { presetDrift } from "./presetDrift.js";
|
|
7
|
+
// Fixtures for the preset-drift guard (is-9c7a78d7). The migration epic
|
|
8
|
+
// is-a70a5963 collapses 37 hand-rolled biome configs into one preset; this is
|
|
9
|
+
// what stops a repo re-growing its own afterwards.
|
|
10
|
+
//
|
|
11
|
+
// Both directions are executed, and so is the opt-in switch: a repo that has
|
|
12
|
+
// not yet migrated must SEE its drift and still exit 0, and the same repo with
|
|
13
|
+
// `[biome] preset = "enforced"` must exit 2. A guard that only ever ran in the
|
|
14
|
+
// enforced direction would not prove the unenforced one is quiet.
|
|
15
|
+
const CLEAN_TS = "export const two = 1 + 1;\n";
|
|
16
|
+
/** The config `guardrails init` writes, plus the two allowances. */
|
|
17
|
+
const CONFORMING = JSON.stringify({
|
|
18
|
+
$schema: "https://biomejs.dev/schemas/2.5.10/schema.json",
|
|
19
|
+
extends: ["@agentvibes/guardrails/biome"],
|
|
20
|
+
// Scoping its own paths is the repo's business, not the preset's.
|
|
21
|
+
files: { includes: ["**/*.ts", "!**/dist"] },
|
|
22
|
+
// A CLI has to print; this is the one rule an override may touch.
|
|
23
|
+
overrides: [{ includes: ["src/**"], linter: { rules: { suspicious: { noConsole: "off" } } } }],
|
|
24
|
+
}, null, 2);
|
|
25
|
+
const NO_EXTENDS = JSON.stringify({ formatter: { indentWidth: 4 } }, null, 2);
|
|
26
|
+
const OWN_KEYS = JSON.stringify({
|
|
27
|
+
extends: ["@agentvibes/guardrails/biome"],
|
|
28
|
+
formatter: { lineWidth: 80 },
|
|
29
|
+
linter: { rules: { style: { useConst: "off" } } },
|
|
30
|
+
assist: { enabled: false },
|
|
31
|
+
javascript: { formatter: { quoteStyle: "single" } },
|
|
32
|
+
json: { formatter: { indentWidth: 4 } },
|
|
33
|
+
}, null, 2);
|
|
34
|
+
const WIDE_OVERRIDE = JSON.stringify({
|
|
35
|
+
extends: ["@agentvibes/guardrails/biome"],
|
|
36
|
+
overrides: [
|
|
37
|
+
{ includes: ["src/**"], linter: { rules: { style: { useConst: "off" } } } },
|
|
38
|
+
{ includes: ["gen/**"], formatter: { enabled: false } },
|
|
39
|
+
],
|
|
40
|
+
}, null, 2);
|
|
41
|
+
function makeRepo(opts) {
|
|
42
|
+
const dir = mkdtempSync(join(tmpdir(), "guardrails-preset-"));
|
|
43
|
+
writeFileSync(join(dir, "a.ts"), CLEAN_TS);
|
|
44
|
+
if (opts.biome !== undefined)
|
|
45
|
+
writeFileSync(join(dir, "biome.json"), opts.biome);
|
|
46
|
+
if (opts.secondConfig !== undefined) {
|
|
47
|
+
mkdirSync(join(dir, "packages", "web"), { recursive: true });
|
|
48
|
+
writeFileSync(join(dir, "packages", "web", "biome.json"), opts.secondConfig);
|
|
49
|
+
}
|
|
50
|
+
if (opts.enforced === true) {
|
|
51
|
+
mkdirSync(join(dir, ".agentvibes"), { recursive: true });
|
|
52
|
+
writeFileSync(join(dir, ".agentvibes", "project.toml"), '[biome]\npreset = "enforced"\n');
|
|
53
|
+
}
|
|
54
|
+
return { dir };
|
|
55
|
+
}
|
|
56
|
+
function run(cwd, command) {
|
|
57
|
+
const res = spawnSync("node", [join(packageRoot, "dist", "cli.js"), command], {
|
|
58
|
+
cwd,
|
|
59
|
+
encoding: "utf8",
|
|
60
|
+
});
|
|
61
|
+
if (res.error)
|
|
62
|
+
throw res.error;
|
|
63
|
+
return { status: res.status ?? -1, out: `${res.stdout}${res.stderr}` };
|
|
64
|
+
}
|
|
65
|
+
function expectStep(step, ok, detail) {
|
|
66
|
+
if (!ok) {
|
|
67
|
+
console.error(`FAIL preset-drift: ${step}\n${detail}`);
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
console.log(` ok preset-drift: ${step}`);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
function main() {
|
|
74
|
+
const repos = [];
|
|
75
|
+
const make = (o) => {
|
|
76
|
+
const r = makeRepo(o);
|
|
77
|
+
repos.push(r);
|
|
78
|
+
return r;
|
|
79
|
+
};
|
|
80
|
+
try {
|
|
81
|
+
let ok = true;
|
|
82
|
+
// ── detection, key by key ────────────────────────────────────────────
|
|
83
|
+
const conforming = make({ biome: CONFORMING });
|
|
84
|
+
ok =
|
|
85
|
+
expectStep("a conforming config reports no drift (extends + files + noConsole override)", presetDrift(conforming.dir).length === 0, JSON.stringify(presetDrift(conforming.dir), null, 2)) && ok;
|
|
86
|
+
const noBiome = make({});
|
|
87
|
+
ok =
|
|
88
|
+
expectStep("a repo with no biome config at all reports no drift", presetDrift(noBiome.dir).length === 0, JSON.stringify(presetDrift(noBiome.dir), null, 2)) && ok;
|
|
89
|
+
const noExtends = make({ biome: NO_EXTENDS });
|
|
90
|
+
ok =
|
|
91
|
+
expectStep("(a) a config that does not extend the preset is drift", presetDrift(noExtends.dir).some((f) => f.key === "extends"), JSON.stringify(presetDrift(noExtends.dir), null, 2)) && ok;
|
|
92
|
+
const ownKeys = make({ biome: OWN_KEYS });
|
|
93
|
+
const ownDetail = presetDrift(ownKeys.dir).find((f) => f.key === "own-keys")?.detail ?? "";
|
|
94
|
+
ok =
|
|
95
|
+
expectStep("(b) formatter, linter, assist, javascript.formatter and json.formatter are all named", ["formatter", "linter", "assist", "javascript.formatter", "json.formatter"].every((k) => ownDetail.includes(k)), ownDetail) && ok;
|
|
96
|
+
const wide = make({ biome: WIDE_OVERRIDE });
|
|
97
|
+
const wideDetail = presetDrift(wide.dir).find((f) => f.key === "overrides")?.detail ?? "";
|
|
98
|
+
ok =
|
|
99
|
+
expectStep("(b) an override touching anything but suspicious.noConsole is drift", wideDetail.includes("overrides[0]") && wideDetail.includes("overrides[1].formatter"), wideDetail) && ok;
|
|
100
|
+
const second = make({ biome: CONFORMING, secondConfig: CONFORMING });
|
|
101
|
+
ok =
|
|
102
|
+
expectStep("(c) a second biome.json in the tree is drift even when both conform", presetDrift(second.dir).some((f) => f.key === "extra-config"), JSON.stringify(presetDrift(second.dir), null, 2)) && ok;
|
|
103
|
+
// ── the opt-in switch, through the CLI ───────────────────────────────
|
|
104
|
+
const unenforced = make({ biome: NO_EXTENDS });
|
|
105
|
+
const u = run(unenforced.dir, "verify");
|
|
106
|
+
ok =
|
|
107
|
+
expectStep("unenforced: verify SAYS the drift and still exits 0", u.status === 0 && u.out.includes("biome preset drift") && u.out.includes("Not gated here"), `exit ${u.status}\n${u.out}`) && ok;
|
|
108
|
+
const enforced = make({ biome: NO_EXTENDS, enforced: true });
|
|
109
|
+
const e = run(enforced.dir, "verify");
|
|
110
|
+
ok =
|
|
111
|
+
expectStep("enforced: the same repo exits 2 with the offending keys named", e.status === 2 && e.out.includes('biome.json has no "extends"'), `exit ${e.status}\n${e.out}`) && ok;
|
|
112
|
+
const enforcedOk = make({ biome: CONFORMING, enforced: true });
|
|
113
|
+
const eo = run(enforcedOk.dir, "verify");
|
|
114
|
+
ok =
|
|
115
|
+
expectStep("enforced + conforming: verify runs normally (exit 0, no drift line)", eo.status === 0 && !eo.out.includes("biome preset drift"), `exit ${eo.status}\n${eo.out}`) && ok;
|
|
116
|
+
const d = run(enforced.dir, "doctor");
|
|
117
|
+
ok =
|
|
118
|
+
expectStep("enforced: doctor exits 1 and prints the drift", d.status === 1 && d.out.includes("DRIFT (enforced here)"), `exit ${d.status}\n${d.out}`) && ok;
|
|
119
|
+
const du = run(unenforced.dir, "doctor");
|
|
120
|
+
ok =
|
|
121
|
+
expectStep("unenforced: doctor still REPORTS the drift, exit unchanged", du.out.includes("drift (not enforced here yet)"), `exit ${du.status}\n${du.out}`) && ok;
|
|
122
|
+
console.log("");
|
|
123
|
+
if (!ok) {
|
|
124
|
+
console.error("preset-drift assertions FAILED");
|
|
125
|
+
return 1;
|
|
126
|
+
}
|
|
127
|
+
console.log("preset-drift fixtures passed");
|
|
128
|
+
return 0;
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
for (const r of repos)
|
|
132
|
+
rmSync(r.dir, { recursive: true, force: true });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
process.exit(main());
|
|
136
|
+
//# sourceMappingURL=presetDriftTest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presetDriftTest.js","sourceRoot":"","sources":["../src/presetDriftTest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** A repo config that ast-grep could not load. */
|
|
2
|
+
export declare class RepoConfigError extends Error {
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* The consuming repo's own `sgconfig.yml`, or undefined when there is none.
|
|
6
|
+
*
|
|
7
|
+
* Returns undefined when `cwd` IS this package: scanning our own config twice
|
|
8
|
+
* would double every finding in our own fixtures and tests.
|
|
9
|
+
*/
|
|
10
|
+
export declare function repoRuleConfig(cwd: string): string | undefined;
|
|
11
|
+
/** Every ast-grep config `verify` should scan with, canon first. */
|
|
12
|
+
export declare function ruleConfigs(cwd: string, canon: string): string[];
|
|
13
|
+
/**
|
|
14
|
+
* `ruleDirs:` as written in a repo config — for `doctor`, so a repo can see
|
|
15
|
+
* WHICH extra rule directories its config contributes rather than only that a
|
|
16
|
+
* config exists. Deliberately a line reader, not a YAML parse: this is a
|
|
17
|
+
* report, and a config shape it cannot read must not stop `doctor` from
|
|
18
|
+
* running (ast-grep is the authority on whether the file loads, and the strict
|
|
19
|
+
* scan in `astGrep.ts` is what reports that).
|
|
20
|
+
*/
|
|
21
|
+
export declare function declaredRuleDirs(configPath: string): string[];
|
|
22
|
+
/** Findings from several configs, minus the duplicates the overlap produces. */
|
|
23
|
+
export declare function dedupeFindings<T extends {
|
|
24
|
+
rule: string;
|
|
25
|
+
file: string;
|
|
26
|
+
line: number;
|
|
27
|
+
}>(findings: T[]): T[];
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { packageRoot } from "./packagePaths.js";
|
|
4
|
+
// Repo-local rules (is-f58cd6b4). `guardrails init` writes an `sgconfig.yml`
|
|
5
|
+
// into the consuming repo and the README tells people to add a second
|
|
6
|
+
// `ruleDir` for rules that encode ONE repo's convention — but `verify` and
|
|
7
|
+
// `verify-diff` only ever scanned with the PACKAGE's own sgconfig.yml, so
|
|
8
|
+
// those rules never ran. Both the intranet (`resource-match-exhaustive`) and
|
|
9
|
+
// DataSpool (`no-connector-fs`, `no-global-fetch`) worked around it by adding a
|
|
10
|
+
// bare `ast-grep scan -c sgconfig.yml` as a second gate stage.
|
|
11
|
+
//
|
|
12
|
+
// The failure mode is this package's least favourite: `verify` printed a
|
|
13
|
+
// finding count, and the count was of a strictly smaller rule set than the
|
|
14
|
+
// repo had asked for. Nothing said so.
|
|
15
|
+
//
|
|
16
|
+
// The fix scans with BOTH configs and merges. Not "the repo's config instead
|
|
17
|
+
// of ours": a repo whose sgconfig.yml forgets the canon `ruleDir` would then
|
|
18
|
+
// silently lose the entire canon, which is the same bug pointing the other
|
|
19
|
+
// way. The canon is always scanned; the repo's config is additive; duplicate
|
|
20
|
+
// findings (the repo's config almost always lists the canon dir too, so every
|
|
21
|
+
// canon finding arrives twice) are deduped by rule + file + line.
|
|
22
|
+
/** A repo config that ast-grep could not load. */
|
|
23
|
+
export class RepoConfigError extends Error {
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The consuming repo's own `sgconfig.yml`, or undefined when there is none.
|
|
27
|
+
*
|
|
28
|
+
* Returns undefined when `cwd` IS this package: scanning our own config twice
|
|
29
|
+
* would double every finding in our own fixtures and tests.
|
|
30
|
+
*/
|
|
31
|
+
export function repoRuleConfig(cwd) {
|
|
32
|
+
if (resolve(cwd) === resolve(packageRoot))
|
|
33
|
+
return undefined;
|
|
34
|
+
const path = join(cwd, "sgconfig.yml");
|
|
35
|
+
if (!existsSync(path))
|
|
36
|
+
return undefined;
|
|
37
|
+
return path;
|
|
38
|
+
}
|
|
39
|
+
/** Every ast-grep config `verify` should scan with, canon first. */
|
|
40
|
+
export function ruleConfigs(cwd, canon) {
|
|
41
|
+
const repo = repoRuleConfig(cwd);
|
|
42
|
+
return repo === undefined ? [canon] : [canon, repo];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* `ruleDirs:` as written in a repo config — for `doctor`, so a repo can see
|
|
46
|
+
* WHICH extra rule directories its config contributes rather than only that a
|
|
47
|
+
* config exists. Deliberately a line reader, not a YAML parse: this is a
|
|
48
|
+
* report, and a config shape it cannot read must not stop `doctor` from
|
|
49
|
+
* running (ast-grep is the authority on whether the file loads, and the strict
|
|
50
|
+
* scan in `astGrep.ts` is what reports that).
|
|
51
|
+
*/
|
|
52
|
+
export function declaredRuleDirs(configPath) {
|
|
53
|
+
const dirs = [];
|
|
54
|
+
let inRuleDirs = false;
|
|
55
|
+
for (const line of readFileSync(configPath, "utf8").split("\n")) {
|
|
56
|
+
if (/^ruleDirs:/.test(line)) {
|
|
57
|
+
inRuleDirs = true;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (inRuleDirs) {
|
|
61
|
+
const item = /^\s+-\s*(.+?)\s*$/.exec(line);
|
|
62
|
+
if (item?.[1] !== undefined) {
|
|
63
|
+
dirs.push(item[1]);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (line.trim() === "" || line.startsWith(" ") || line.startsWith("#"))
|
|
67
|
+
continue;
|
|
68
|
+
inRuleDirs = false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return dirs;
|
|
72
|
+
}
|
|
73
|
+
/** Findings from several configs, minus the duplicates the overlap produces. */
|
|
74
|
+
export function dedupeFindings(findings) {
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
const out = [];
|
|
77
|
+
for (const f of findings) {
|
|
78
|
+
const key = `${f.rule}\0${f.file}\0${f.line}`;
|
|
79
|
+
if (seen.has(key))
|
|
80
|
+
continue;
|
|
81
|
+
seen.add(key);
|
|
82
|
+
out.push(f);
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=repoRules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repoRules.js","sourceRoot":"","sources":["../src/repoRules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { packageRoot } from "./packagePaths.js";
|
|
6
|
+
// Regression fixtures for is-f58cd6b4 — `verify` ignored the consuming repo's
|
|
7
|
+
// own sgconfig.yml, so repo-local rules never ran and the finding count was of
|
|
8
|
+
// a smaller rule set than the repo had asked for, with nothing saying so.
|
|
9
|
+
//
|
|
10
|
+
// The fixture repo is the shape the bug was reported in: an `sgconfig.yml`
|
|
11
|
+
// listing BOTH the canon rule directory and a local one, a file that violates
|
|
12
|
+
// only the local rule, and a file that violates only a canon rule.
|
|
13
|
+
//
|
|
14
|
+
// Measured against the pre-fix build (HEAD's verify.ts, scanning only the
|
|
15
|
+
// package config): 4 of the 6 checks below fail — the local rule reports
|
|
16
|
+
// nothing, it gates nothing, a repo config without the canon ruleDir loses its
|
|
17
|
+
// local rules entirely, and an unparsable repo config reads as "no findings".
|
|
18
|
+
// The other two pass before and after; they pin that the fix did not cost the
|
|
19
|
+
// canon its coverage or start double-reporting it.
|
|
20
|
+
/** Violates only the repo-local rule; no canon rule matches `forbiddenCall()`. */
|
|
21
|
+
const LOCAL_ONLY = "export const boot = () => {\n forbiddenCall()\n}\n";
|
|
22
|
+
/** Violates only a canon rule (`catch-empty`, error tier). */
|
|
23
|
+
const CANON_ONLY = "export const run = () => {\n try { work() } catch (e) { }\n}\n";
|
|
24
|
+
const LOCAL_RULE = `id: no-forbidden-call
|
|
25
|
+
language: typescript
|
|
26
|
+
severity: error
|
|
27
|
+
message: |
|
|
28
|
+
This repo forbids forbiddenCall(). Repo-local rule, not part of the canon.
|
|
29
|
+
rule:
|
|
30
|
+
pattern: "forbiddenCall()"
|
|
31
|
+
`;
|
|
32
|
+
function verify(cwd, target = ".") {
|
|
33
|
+
const res = spawnSync("node", [join(packageRoot, "dist", "cli.js"), "verify", "--json", target], {
|
|
34
|
+
cwd,
|
|
35
|
+
encoding: "utf8",
|
|
36
|
+
});
|
|
37
|
+
if (res.error)
|
|
38
|
+
throw res.error;
|
|
39
|
+
const out = `${res.stdout}${res.stderr}`;
|
|
40
|
+
let findings = [];
|
|
41
|
+
try {
|
|
42
|
+
findings = JSON.parse(res.stdout).findings;
|
|
43
|
+
// ast-grep-ignore: catch-empty -- non-JSON stdout IS the answer for the exit-2 path this test asserts; the caller reads `status` and `out`, and every assertion that wanted findings fails with the raw output attached
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
findings = [];
|
|
47
|
+
}
|
|
48
|
+
return { status: res.status ?? -1, out, findings };
|
|
49
|
+
}
|
|
50
|
+
function makeRepo(sgconfig) {
|
|
51
|
+
const dir = mkdtempSync(join(tmpdir(), "guardrails-repo-rules-"));
|
|
52
|
+
mkdirSync(join(dir, ".ast-grep", "rules"), { recursive: true });
|
|
53
|
+
writeFileSync(join(dir, ".ast-grep", "rules", "no-forbidden-call.yml"), LOCAL_RULE);
|
|
54
|
+
writeFileSync(join(dir, "sgconfig.yml"), sgconfig);
|
|
55
|
+
writeFileSync(join(dir, "local.ts"), LOCAL_ONLY);
|
|
56
|
+
writeFileSync(join(dir, "canon.ts"), CANON_ONLY);
|
|
57
|
+
return dir;
|
|
58
|
+
}
|
|
59
|
+
/** The config `guardrails init` writes, with the local ruleDir uncommented. */
|
|
60
|
+
const BOTH_DIRS = `ruleDirs:
|
|
61
|
+
- ${join(packageRoot, "rules")}
|
|
62
|
+
- .ast-grep/rules
|
|
63
|
+
`;
|
|
64
|
+
/** A repo whose config declares ONLY its local rules — the canon must survive. */
|
|
65
|
+
const LOCAL_DIR_ONLY = `ruleDirs:
|
|
66
|
+
- .ast-grep/rules
|
|
67
|
+
`;
|
|
68
|
+
function expectStep(step, ok, detail) {
|
|
69
|
+
if (!ok) {
|
|
70
|
+
console.error(`FAIL repo-rules: ${step}\n${detail}`);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
console.log(` ok repo-rules: ${step}`);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
function main() {
|
|
77
|
+
const both = makeRepo(BOTH_DIRS);
|
|
78
|
+
const localOnly = makeRepo(LOCAL_DIR_ONLY);
|
|
79
|
+
const brokenConfig = makeRepo("ruleDirs: [\n");
|
|
80
|
+
try {
|
|
81
|
+
const r = verify(both);
|
|
82
|
+
const local = r.findings.filter((f) => f.rule === "no-forbidden-call");
|
|
83
|
+
const canon = r.findings.filter((f) => f.rule === "catch-empty");
|
|
84
|
+
let ok = expectStep("the repo's own rule reports (1 finding on local.ts)", local.length === 1 && local[0]?.file.endsWith("local.ts") === true, r.out);
|
|
85
|
+
// Scoped to local.ts so the exit code cannot be explained by the canon
|
|
86
|
+
// finding in canon.ts — this is the local rule gating, on its own.
|
|
87
|
+
const lonly = verify(both, "local.ts");
|
|
88
|
+
ok =
|
|
89
|
+
expectStep("a repo-local error-tier finding gates verify on its own (exit 1)", lonly.status === 1 && lonly.findings.every((f) => f.rule === "no-forbidden-call"), `exit ${lonly.status}\n${lonly.out}`) && ok;
|
|
90
|
+
ok =
|
|
91
|
+
expectStep("the canon still reports alongside it (catch-empty on canon.ts)", canon.length === 1, r.out) && ok;
|
|
92
|
+
// The overlap: the repo config lists the canon ruleDir too, so without
|
|
93
|
+
// dedupe every canon finding arrives once per config.
|
|
94
|
+
const keys = r.findings.map((f) => `${f.rule}\0${f.file}\0${f.line}`);
|
|
95
|
+
ok =
|
|
96
|
+
expectStep("the canon ruleDir listed in both configs is not double-reported", new Set(keys).size === keys.length, `${keys.length} findings, ${new Set(keys).size} distinct:\n${r.out}`) && ok;
|
|
97
|
+
// A repo config that forgets the canon must not silently lose the canon —
|
|
98
|
+
// that is this same bug pointing the other way.
|
|
99
|
+
const lr = verify(localOnly);
|
|
100
|
+
ok =
|
|
101
|
+
expectStep("a repo config without the canon ruleDir keeps canon coverage", lr.findings.some((f) => f.rule === "catch-empty") &&
|
|
102
|
+
lr.findings.some((f) => f.rule === "no-forbidden-call"), lr.out) && ok;
|
|
103
|
+
// A config ast-grep cannot parse must fail loudly (exit 2), never read as
|
|
104
|
+
// "no findings" — ast-grep exits 8 there and writes nothing to stdout.
|
|
105
|
+
const br = verify(brokenConfig);
|
|
106
|
+
ok =
|
|
107
|
+
expectStep("an unparsable repo config exits 2 with the reason, not 0 with silence", br.status === 2 && br.out.includes("ast-grep exited"), `exit ${br.status}\n${br.out}`) && ok;
|
|
108
|
+
console.log("");
|
|
109
|
+
if (!ok) {
|
|
110
|
+
console.error("repo-local rule assertions FAILED");
|
|
111
|
+
return 1;
|
|
112
|
+
}
|
|
113
|
+
console.log("repo-local rule fixtures passed");
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
for (const d of [both, localOnly, brokenConfig])
|
|
118
|
+
rmSync(d, { recursive: true, force: true });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
process.exit(main());
|
|
122
|
+
//# sourceMappingURL=repoRulesTest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repoRulesTest.js","sourceRoot":"","sources":["../src/repoRulesTest.ts"],"names":[],"mappings":"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"}
|
package/dist/screenScope.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { Finding } from "./findings.js";
|
|
2
2
|
export declare class ScreenScopeError extends Error {
|
|
3
3
|
}
|
|
4
|
+
export interface Scope {
|
|
5
|
+
/** The name in `appliesTo: not-<name>`. */
|
|
6
|
+
readonly name: string;
|
|
7
|
+
/** The key under `[verify]` in .agentvibes/project.toml. */
|
|
8
|
+
readonly tomlKey: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const SCOPES: readonly Scope[];
|
|
11
|
+
/** scope name -> rule ids whose bundled definition declares `appliesTo: not-<scope>`. */
|
|
12
|
+
export declare function scopeExemptRuleIds(dir?: string): Map<string, Set<string>>;
|
|
4
13
|
/** Rule ids whose bundled definition declares `appliesTo: not-screens`. */
|
|
5
14
|
export declare function screenExemptRuleIds(dir?: string): Set<string>;
|
|
6
15
|
/**
|
|
@@ -12,10 +21,12 @@ export declare function screenExemptRuleIds(dir?: string): Set<string>;
|
|
|
12
21
|
* believes it has scoped them.
|
|
13
22
|
*/
|
|
14
23
|
export declare function screensPattern(cwd: string): RegExp | undefined;
|
|
24
|
+
/** Every scope pattern the repo declares, keyed by scope name. */
|
|
25
|
+
export declare function scopePatterns(cwd: string): Map<string, RegExp>;
|
|
15
26
|
/**
|
|
16
|
-
* Drop findings from rules that do not apply to
|
|
17
|
-
* declared to BE
|
|
18
|
-
* those same rules outside the
|
|
19
|
-
* working for the scoping to be worth anything.
|
|
27
|
+
* Drop findings from rules that do not apply to a scope, in files the repo has
|
|
28
|
+
* declared to BE that scope. Everything else passes through untouched —
|
|
29
|
+
* including those same rules outside the scoped paths, which is the half that
|
|
30
|
+
* has to keep working for the scoping to be worth anything.
|
|
20
31
|
*/
|
|
21
|
-
export declare function
|
|
32
|
+
export declare function dropScopeExempt(findings: readonly Finding[], patterns: ReadonlyMap<string, RegExp>, exempt: ReadonlyMap<string, Set<string>>): Finding[];
|
package/dist/screenScope.js
CHANGED
|
@@ -31,11 +31,34 @@ import { readTomlTable } from "./tomlTable.js";
|
|
|
31
31
|
//
|
|
32
32
|
// Absent key = absent behaviour. A repo that says nothing is scanned exactly as
|
|
33
33
|
// it was before this existed.
|
|
34
|
+
//
|
|
35
|
+
// GENERALISED (is-086a90ac). A second fact needed saying and the shape already
|
|
36
|
+
// fitted: `no-local-kit-clone` is error-tier and fires on the six declarations
|
|
37
|
+
// inside `@agentvibes/kit` itself — the canonical definitions the rule tells
|
|
38
|
+
// everyone else to import. Its own header names the fix ("if this IS the
|
|
39
|
+
// canonical definition … it belongs behind the path carve-outs") and its
|
|
40
|
+
// carve-out globs, written while the package did not exist yet, are
|
|
41
|
+
// `**/packages/kit/**` and `**/agentvibes-kit/**`: neither matches a standalone
|
|
42
|
+
// repo whose files verify sees as `src/resource/resource.ts`. No path glob can
|
|
43
|
+
// tell that tree from any other repo's `src/` — only the repo knows, so the
|
|
44
|
+
// repo says it:
|
|
45
|
+
//
|
|
46
|
+
// [verify]
|
|
47
|
+
// kit_source = "^src/"
|
|
48
|
+
//
|
|
49
|
+
// Adding a scope is two lines here plus `appliesTo: not-<scope>` in the rules
|
|
50
|
+
// that stand down for it. The registry is closed on purpose: an unknown scope
|
|
51
|
+
// key in a repo's config is a typo the repo cannot see, and the alternative — a
|
|
52
|
+
// free-form per-rule path map — is the growing allowlist this design refused.
|
|
34
53
|
export class ScreenScopeError extends Error {
|
|
35
54
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
55
|
+
export const SCOPES = [
|
|
56
|
+
{ name: "screens", tomlKey: "screens" },
|
|
57
|
+
{ name: "kit-source", tomlKey: "kit_source" },
|
|
58
|
+
];
|
|
59
|
+
/** scope name -> rule ids whose bundled definition declares `appliesTo: not-<scope>`. */
|
|
60
|
+
export function scopeExemptRuleIds(dir = rulesDir) {
|
|
61
|
+
const byScope = new Map(SCOPES.map((s) => [s.name, new Set()]));
|
|
39
62
|
for (const f of readdirSync(dir)) {
|
|
40
63
|
if (!f.endsWith(".yml"))
|
|
41
64
|
continue;
|
|
@@ -43,10 +66,17 @@ export function screenExemptRuleIds(dir = rulesDir) {
|
|
|
43
66
|
const id = text.match(/^id:\s*(\S+)/m)?.[1];
|
|
44
67
|
if (id === undefined)
|
|
45
68
|
continue;
|
|
46
|
-
|
|
47
|
-
|
|
69
|
+
for (const s of SCOPES) {
|
|
70
|
+
if (new RegExp(`^\\s{2}appliesTo:\\s*not-${s.name}\\s*$`, "m").test(text)) {
|
|
71
|
+
byScope.get(s.name)?.add(id);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
48
74
|
}
|
|
49
|
-
return
|
|
75
|
+
return byScope;
|
|
76
|
+
}
|
|
77
|
+
/** Rule ids whose bundled definition declares `appliesTo: not-screens`. */
|
|
78
|
+
export function screenExemptRuleIds(dir = rulesDir) {
|
|
79
|
+
return scopeExemptRuleIds(dir).get("screens") ?? new Set();
|
|
50
80
|
}
|
|
51
81
|
/**
|
|
52
82
|
* The repo's `[verify] screens` pattern, or undefined when it declares none.
|
|
@@ -57,25 +87,40 @@ export function screenExemptRuleIds(dir = rulesDir) {
|
|
|
57
87
|
* believes it has scoped them.
|
|
58
88
|
*/
|
|
59
89
|
export function screensPattern(cwd) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
90
|
+
return scopePatterns(cwd).get("screens");
|
|
91
|
+
}
|
|
92
|
+
/** Every scope pattern the repo declares, keyed by scope name. */
|
|
93
|
+
export function scopePatterns(cwd) {
|
|
94
|
+
const table = readTomlTable(join(cwd, ".agentvibes", "project.toml"), "verify");
|
|
95
|
+
const out = new Map();
|
|
96
|
+
for (const s of SCOPES) {
|
|
97
|
+
const raw = table[s.tomlKey];
|
|
98
|
+
if (raw === undefined || raw.trim() === "")
|
|
99
|
+
continue;
|
|
100
|
+
try {
|
|
101
|
+
out.set(s.name, new RegExp(raw));
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
throw new ScreenScopeError(`[verify] ${s.tomlKey} = ${JSON.stringify(raw)} is not a valid regular expression (${e.message})`);
|
|
105
|
+
}
|
|
68
106
|
}
|
|
107
|
+
return out;
|
|
69
108
|
}
|
|
70
109
|
/**
|
|
71
|
-
* Drop findings from rules that do not apply to
|
|
72
|
-
* declared to BE
|
|
73
|
-
* those same rules outside the
|
|
74
|
-
* working for the scoping to be worth anything.
|
|
110
|
+
* Drop findings from rules that do not apply to a scope, in files the repo has
|
|
111
|
+
* declared to BE that scope. Everything else passes through untouched —
|
|
112
|
+
* including those same rules outside the scoped paths, which is the half that
|
|
113
|
+
* has to keep working for the scoping to be worth anything.
|
|
75
114
|
*/
|
|
76
|
-
export function
|
|
77
|
-
if (
|
|
115
|
+
export function dropScopeExempt(findings, patterns, exempt) {
|
|
116
|
+
if (patterns.size === 0)
|
|
78
117
|
return [...findings];
|
|
79
|
-
return findings.filter((f) =>
|
|
118
|
+
return findings.filter((f) => {
|
|
119
|
+
for (const [scope, re] of patterns) {
|
|
120
|
+
if (exempt.get(scope)?.has(f.rule) === true && re.test(f.file))
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
});
|
|
80
125
|
}
|
|
81
126
|
//# sourceMappingURL=screenScope.js.map
|
package/dist/screenScope.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screenScope.js","sourceRoot":"","sources":["../src/screenScope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,8EAA8E;AAC9E,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,8EAA8E;AAC9E,+EAA+E;AAC/E,8EAA8E;AAC9E,gFAAgF;AAChF,4CAA4C;AAC5C,EAAE;AACF,gFAAgF;AAChF,iFAAiF;AACjF,+EAA+E;AAC/E,8EAA8E;AAC9E,8DAA8D;AAC9D,EAAE;AACF,aAAa;AACb,8BAA8B;AAC9B,EAAE;AACF,yEAAyE;AACzE,+EAA+E;AAC/E,4EAA4E;AAC5E,4EAA4E;AAC5E,EAAE;AACF,cAAc;AACd,6BAA6B;AAC7B,EAAE;AACF,gFAAgF;AAChF,8BAA8B;AAC9B,MAAM,OAAO,gBAAiB,SAAQ,KAAK;CAAG;
|
|
1
|
+
{"version":3,"file":"screenScope.js","sourceRoot":"","sources":["../src/screenScope.ts"],"names":[],"mappings":"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"}
|