@lannguyensi/harness 0.42.0 → 0.44.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/CHANGELOG.md +62 -0
- package/dist/cli/approve/branch-protection.js +1 -1
- package/dist/cli/approve/branch-protection.js.map +1 -1
- package/dist/cli/dry-run.js +19 -1
- package/dist/cli/dry-run.js.map +1 -1
- package/dist/cli/index.js +4 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/composer.js +6 -6
- package/dist/cli/init/composer.js.map +1 -1
- package/dist/cli/init/profiles.d.ts +1 -1
- package/dist/cli/init/profiles.js +1 -1
- package/dist/cli/init/templates.d.ts +1 -1
- package/dist/cli/init/templates.js +53 -31
- package/dist/cli/init/templates.js.map +1 -1
- package/dist/cli/pack/hook-branch-protection.js +1 -1
- package/dist/cli/pack/hook-branch-protection.js.map +1 -1
- package/dist/cli/pack/hook-post-merge-gate.js +43 -25
- package/dist/cli/pack/hook-post-merge-gate.js.map +1 -1
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js +1 -1
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +1 -1
- package/dist/cli/pack/hook-solution-acceptance.js +1 -1
- package/dist/cli/pack/hook-solution-acceptance.js.map +1 -1
- package/dist/cli/policy/intercept.js +209 -14
- package/dist/cli/policy/intercept.js.map +1 -1
- package/dist/cli/validate/checks.js +2 -2
- package/dist/cli/validate/checks.js.map +1 -1
- package/dist/policy-packs/builtin/branch-protection-runtime.d.ts +1 -1
- package/dist/policy-packs/builtin/branch-protection-runtime.js +1 -1
- package/dist/policy-packs/builtin/branch-protection.js +2 -2
- package/dist/policy-packs/builtin/branch-protection.js.map +1 -1
- package/dist/policy-packs/builtin/post-merge-gate-runtime.d.ts +90 -10
- package/dist/policy-packs/builtin/post-merge-gate-runtime.js +112 -16
- package/dist/policy-packs/builtin/post-merge-gate-runtime.js.map +1 -1
- package/dist/policy-packs/builtin/post-merge-gate.js +40 -23
- package/dist/policy-packs/builtin/post-merge-gate.js.map +1 -1
- package/dist/policy-packs/builtin/solution-acceptance-runtime.d.ts +13 -0
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js +15 -2
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +1 -1
- package/dist/policy-packs/builtin/solution-acceptance.js +1 -1
- package/dist/runtime/bash-match-facts.d.ts +58 -0
- package/dist/runtime/bash-match-facts.js +194 -0
- package/dist/runtime/bash-match-facts.js.map +1 -0
- package/dist/runtime/bash-match-registry.d.ts +75 -0
- package/dist/runtime/bash-match-registry.js +359 -0
- package/dist/runtime/bash-match-registry.js.map +1 -0
- package/dist/runtime/bash-prefix-parse.js +23 -0
- package/dist/runtime/bash-prefix-parse.js.map +1 -1
- package/dist/runtime/command-normalize.d.ts +405 -0
- package/dist/runtime/command-normalize.js +1888 -0
- package/dist/runtime/command-normalize.js.map +1 -0
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/intercept.d.ts +208 -2
- package/dist/runtime/intercept.js +437 -28
- package/dist/runtime/intercept.js.map +1 -1
- package/dist/runtime/read-only-bash.d.ts +43 -0
- package/dist/runtime/read-only-bash.js +73 -10
- package/dist/runtime/read-only-bash.js.map +1 -1
- package/dist/runtime/shell-word.d.ts +21 -0
- package/dist/runtime/shell-word.js +242 -0
- package/dist/runtime/shell-word.js.map +1 -0
- package/dist/schema/policies.js +1 -1
- package/dist/schema/policies.js.map +1 -1
- package/package.json +4 -1
|
@@ -65,8 +65,21 @@ export const DEFAULT_PROTECTED_COMPLETION_TOOLS = [
|
|
|
65
65
|
* load-bearing choke points; hardening this is follow-up `7207d8f9`.
|
|
66
66
|
* Tolerates a leading `cd … &&`, inline `VAR=val` assignments, and `git -C
|
|
67
67
|
* <path> push`.
|
|
68
|
+
*
|
|
69
|
+
* Task 76671e5a: bare `&` added to the boundary alternation (`&&` kept to
|
|
70
|
+
* its left only to mirror `src/runtime/command-normalize.ts`'s alternation
|
|
71
|
+
* order for readability — NOT because order is load-bearing here, unlike
|
|
72
|
+
* that module). Same fix as `d834a065` applied to every policy trigger —
|
|
73
|
+
* bash starts a new command after a single `&`, so `A=x&git push` used to
|
|
74
|
+
* slip past this DENY matcher entirely. Broadening is the stricter direction
|
|
75
|
+
* here (this gates completion actions, it is not an allow-list). Measured:
|
|
76
|
+
* swapping to `&|&&` produces a byte-identical match set for this matcher
|
|
77
|
+
* (a `RegExp.test` existential check over every start offset, not a
|
|
78
|
+
* segmenter — the reasoning that makes order matter in
|
|
79
|
+
* `command-normalize.ts`'s `BOUNDARY_RE`/`AMP_BOUNDARY_RE` does not transfer
|
|
80
|
+
* to a plain `.test()` matcher like this one).
|
|
68
81
|
*/
|
|
69
|
-
export const DEFAULT_PUSH_BASH_RE = /(?:^|\n
|
|
82
|
+
export const DEFAULT_PUSH_BASH_RE = /(?:^|\n|;|\||&&|&|\()\s*(?:\w+=\S+\s+)*(?:git(?:\s+-C\s+\S+)?\s+push|gh\s+pr\s+merge)\b/;
|
|
70
83
|
/**
|
|
71
84
|
* Resolve the completion verbs the gate fires on: the pack's
|
|
72
85
|
* `config.protected_completion_tools` override, else the default set.
|
|
@@ -212,7 +225,7 @@ export function evaluateGate(verdict, currentHead, id) {
|
|
|
212
225
|
if (!verdict) {
|
|
213
226
|
return {
|
|
214
227
|
allowed: false,
|
|
215
|
-
reason: `no solution-acceptance verdict recorded for "${id}" (run
|
|
228
|
+
reason: `no solution-acceptance verdict recorded for "${id}" (run mcp__grounding-mcp__solution_evaluate first)`,
|
|
216
229
|
verdict: null,
|
|
217
230
|
};
|
|
218
231
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solution-acceptance-runtime.js","sourceRoot":"","sources":["../../../src/policy-packs/builtin/solution-acceptance-runtime.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,sEAAsE;AACtE,8EAA8E;AAC9E,4EAA4E;AAC5E,sEAAsE;AACtE,wEAAwE;AACxE,4EAA4E;AAC5E,6CAA6C;AAC7C,EAAE;AACF,uEAAuE;AACvE,yEAAyE;AACzE,2DAA2D;AAC3D,4EAA4E;AAC5E,yEAAyE;AACzE,8EAA8E;AAC9E,2EAA2E;AAC3E,0EAA0E;AAC1E,gEAAgE;AAChE,EAAE;AACF,2EAA2E;AAC3E,oCAAoC;AACpC,EAAE;AACF,0EAA0E;AAC1E,6EAA6E;AAC7E,wEAAwE;AACxE,8DAA8D;AAC9D,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,uEAAuE;AACvE,EAAE;AACF,sEAAsE;AACtE,4EAA4E;AAC5E,4EAA4E;AAC5E,6EAA6E;AAC7E,0EAA0E;AAC1E,2EAA2E;AAC3E,2EAA2E;AAC3E,gBAAgB;AAEhB,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAGhF,MAAM,CAAC,MAAM,SAAS,GAAG,qBAAqB,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kCAAkC,GAAG;IAChD,aAAa;IACb,gBAAgB;IAChB,YAAY;IACZ,qBAAqB;CACb,CAAC;AAEX
|
|
1
|
+
{"version":3,"file":"solution-acceptance-runtime.js","sourceRoot":"","sources":["../../../src/policy-packs/builtin/solution-acceptance-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -154,7 +154,7 @@ harness-managed settings:
|
|
|
154
154
|
## Earning a verdict
|
|
155
155
|
|
|
156
156
|
\`\`\`
|
|
157
|
-
|
|
157
|
+
mcp__grounding-mcp__solution_evaluate({ id: "<active-task-id>" })
|
|
158
158
|
\`\`\`
|
|
159
159
|
|
|
160
160
|
This runs \`preflight run --json\` and records a HEAD-pinned verdict. A
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Policy } from "../schema/index.js";
|
|
2
|
+
/** How a classified head token relates to the engine's own coverage. */
|
|
3
|
+
export type HeadTokenClass = "git" | "non-git-set" | "documented-uncovered";
|
|
4
|
+
export interface HeadTokenFact {
|
|
5
|
+
readonly token: string;
|
|
6
|
+
readonly class: HeadTokenClass;
|
|
7
|
+
}
|
|
8
|
+
/** Exposed for callers that need the full "genuinely not covered today" list (see `bash-match-registry.ts`). */
|
|
9
|
+
export declare const DOCUMENTED_UNCOVERED_HEAD_TOKENS: ReadonlySet<string>;
|
|
10
|
+
export interface PolicyBashMatchFact {
|
|
11
|
+
readonly policyName: string;
|
|
12
|
+
readonly pattern: string;
|
|
13
|
+
readonly headTokens: readonly HeadTokenFact[];
|
|
14
|
+
readonly verbs: readonly string[];
|
|
15
|
+
}
|
|
16
|
+
export interface BashMatchFacts {
|
|
17
|
+
/** Every FULL_TEMPLATE policy name that declares a `bash_match` trigger, verified live. */
|
|
18
|
+
readonly policyNames: readonly string[];
|
|
19
|
+
/** Per-policy detail, in the same order as `policyNames`. */
|
|
20
|
+
readonly policies: readonly PolicyBashMatchFact[];
|
|
21
|
+
/** Every distinct head token gated by ANY `bash_match` policy, flattened. */
|
|
22
|
+
readonly gatedHeadTokens: ReadonlySet<string>;
|
|
23
|
+
/** The classification of a gated head token, or `undefined` if `token` is not gated by any shipped policy at all. */
|
|
24
|
+
classify(token: string): HeadTokenClass | undefined;
|
|
25
|
+
}
|
|
26
|
+
/** Minimal shape this module needs from a policy — decoupled from the full zod-inferred `Policy` so fixtures can be built without constructing an entire manifest. */
|
|
27
|
+
export interface BashMatchPolicyLike {
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly trigger: {
|
|
30
|
+
readonly bash_match?: string | undefined;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Compute verified-fresh `BashMatchFacts` from a LIVE list of parsed
|
|
35
|
+
* policies. Call with `parseManifest(parseYaml(FULL_TEMPLATE)).policies`
|
|
36
|
+
* to get the shipped ground truth (never hand-copy the patterns).
|
|
37
|
+
*
|
|
38
|
+
* Throws descriptively — the caller should let this propagate as a
|
|
39
|
+
* failing test, not swallow it — when:
|
|
40
|
+
* 1. The exact SET of policy names carrying a `bash_match` trigger in
|
|
41
|
+
* the live `policies` differs from the curated map's key set
|
|
42
|
+
* (a policy was added, removed, or renamed).
|
|
43
|
+
* 2. A curated head token or verb is no longer present as a standalone
|
|
44
|
+
* word (`\bTOKEN\b`) in its policy's live pattern (renamed/removed
|
|
45
|
+
* within an otherwise still-existing policy).
|
|
46
|
+
*/
|
|
47
|
+
export declare function extractBashMatchFacts(policies: readonly (BashMatchPolicyLike | Policy)[]): BashMatchFacts;
|
|
48
|
+
/**
|
|
49
|
+
* "Is `token` gated by ANY shipped `bash_match` policy?" — the one-call
|
|
50
|
+
* question both incidents got wrong. Real caller (F8, fix round):
|
|
51
|
+
* `bash-match-registry.ts`'s `checkRegisteredSets` covers-purity check,
|
|
52
|
+
* which asks this once per declared `member` of every
|
|
53
|
+
* "covers-gated-head-tokens" registration. Takes only the `gatedHeadTokens`
|
|
54
|
+
* slice of `BashMatchFacts` (not the full shape) so a caller holding the
|
|
55
|
+
* same narrowed `Pick` `checkRegisteredSets` accepts can call this directly
|
|
56
|
+
* without widening its own parameter type.
|
|
57
|
+
*/
|
|
58
|
+
export declare function isHeadTokenGated(facts: Pick<BashMatchFacts, "gatedHeadTokens">, token: string): boolean;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// Live facts about FULL_TEMPLATE's shipped `bash_match` policies (task
|
|
2
|
+
// `074acf5d`, run `2026-07-28-manifest-facts-drift-guard`).
|
|
3
|
+
//
|
|
4
|
+
// WHY THIS MODULE EXISTS: two consecutive runs shipped/attempted a defect
|
|
5
|
+
// of the exact same CLASS, one day and one file apart.
|
|
6
|
+
// - Run `432db3d3` (merged 2026-07-27), HIGH: `NON_GIT_HEAD_TOKENS`
|
|
7
|
+
// (`command-normalize.ts`) covered 4 of the 8 head tokens a shipped
|
|
8
|
+
// `bash_match` policy actually gates. Closed by
|
|
9
|
+
// `tests/runtime/bash-match-head-token-drift.test.ts`, but scoped to
|
|
10
|
+
// that one set in that one file.
|
|
11
|
+
// - Run `dbc6d303` (halted 2026-07-28), CRITICAL: a NEW module's
|
|
12
|
+
// `INERT_CONSUMER_HEADS` contained `harness` — itself the gated head
|
|
13
|
+
// token of `deny-kill-switch-bypass`. The prior day's guard
|
|
14
|
+
// structurally could not see it: it only ever compared ONE named set
|
|
15
|
+
// (`NON_GIT_HEAD_TOKENS`) against the manifest, never a set someone
|
|
16
|
+
// adds tomorrow.
|
|
17
|
+
// This module answers, ONE call, read live (never hand-copied): "which
|
|
18
|
+
// policies declare a `bash_match`, which head token(s) each anchors on,
|
|
19
|
+
// which verbs, and is token X gated by ANY of them?" — the question both
|
|
20
|
+
// incidents got wrong. `src/runtime/bash-match-registry.ts` builds the
|
|
21
|
+
// generalised, EVERY-registered-set guard on top of the facts this module
|
|
22
|
+
// produces.
|
|
23
|
+
//
|
|
24
|
+
// DESIGN: literal head-token extraction straight out of an arbitrary
|
|
25
|
+
// regex string is fragile (alternations, nested groups, nothing
|
|
26
|
+
// guarantees a token is even a bare word) — the same reasoning the
|
|
27
|
+
// migrated guard's own header carried. A CURATED classification map is
|
|
28
|
+
// used instead, but it is never trusted blind: `extractBashMatchFacts`
|
|
29
|
+
// verifies it against the LIVE policies passed in (call it with
|
|
30
|
+
// `parseManifest(parseYaml(FULL_TEMPLATE)).policies` to get the shipped
|
|
31
|
+
// ground truth) and THROWS descriptively the moment the curated map and
|
|
32
|
+
// the live manifest disagree — a policy added/removed/renamed, or a
|
|
33
|
+
// classified token no longer present in its policy's live pattern. A
|
|
34
|
+
// caller that gets a `BashMatchFacts` back without an exception is
|
|
35
|
+
// holding verified-fresh facts, not a stale copy.
|
|
36
|
+
//
|
|
37
|
+
// LAYERING: this module takes policies as a plain parameter and does not
|
|
38
|
+
// import `FULL_TEMPLATE` itself (that lives in `src/cli/init/templates.ts`,
|
|
39
|
+
// the `cli` layer — `.dependency-cruiser.cjs`'s `runtime-no-upward-imports`
|
|
40
|
+
// rule forbids `runtime/` importing `cli/`). The live wiring (parsing
|
|
41
|
+
// FULL_TEMPLATE and calling this module) happens in test code, which the
|
|
42
|
+
// boundary check does not scan.
|
|
43
|
+
//
|
|
44
|
+
// WHY src/runtime/, NOT tests/ (F8, fix round): this module and
|
|
45
|
+
// `bash-match-registry.ts` are a single shared source of truth that TWO
|
|
46
|
+
// independent test files (`bash-match-head-token-drift.test.ts`,
|
|
47
|
+
// `bash-match-registry.test.ts`) import symmetrically — a module peer
|
|
48
|
+
// test files both depend on belongs beside the engine code it inspects,
|
|
49
|
+
// not inside the test tree that merely happens to hold its only callers
|
|
50
|
+
// today.
|
|
51
|
+
/**
|
|
52
|
+
* The curated ground truth, verified fresh against FULL_TEMPLATE's live
|
|
53
|
+
* policies by `extractBashMatchFacts` every time it runs — see the module
|
|
54
|
+
* header. Keyed by policy name.
|
|
55
|
+
*
|
|
56
|
+
* "documented-uncovered" tokens (fix round 2, finding F1 on the migrated
|
|
57
|
+
* guard — see `command-normalize.ts`'s "SHIPPED BUT NOT COVERED"
|
|
58
|
+
* paragraph for why each is genuinely out of reach today, not merely
|
|
59
|
+
* unimplemented): `env`, `unset`, `tee`, `cp`.
|
|
60
|
+
*/
|
|
61
|
+
const CURATED_BASH_MATCH_FACTS = {
|
|
62
|
+
"review-before-merge-bash": {
|
|
63
|
+
headTokens: [{ token: "gh", class: "non-git-set" }],
|
|
64
|
+
verbs: ["merge"],
|
|
65
|
+
},
|
|
66
|
+
"dogfood-before-release": {
|
|
67
|
+
headTokens: [
|
|
68
|
+
{ token: "npm", class: "non-git-set" },
|
|
69
|
+
{ token: "git", class: "git" },
|
|
70
|
+
],
|
|
71
|
+
verbs: ["publish", "tag"],
|
|
72
|
+
},
|
|
73
|
+
"preflight-before-investigation": {
|
|
74
|
+
headTokens: [{ token: "git", class: "git" }],
|
|
75
|
+
verbs: ["status", "log", "diff", "branch"],
|
|
76
|
+
},
|
|
77
|
+
"review-subagent-before-pr-create-bash": {
|
|
78
|
+
headTokens: [{ token: "gh", class: "non-git-set" }],
|
|
79
|
+
verbs: ["create"],
|
|
80
|
+
},
|
|
81
|
+
"preflight-before-push": {
|
|
82
|
+
headTokens: [{ token: "git", class: "git" }],
|
|
83
|
+
verbs: ["push"],
|
|
84
|
+
},
|
|
85
|
+
"deny-kill-switch-bypass": {
|
|
86
|
+
headTokens: [{ token: "harness", class: "non-git-set" }],
|
|
87
|
+
verbs: ["pause", "resume", "gate", "disable", "enable"],
|
|
88
|
+
},
|
|
89
|
+
"deny-session-env-strip": {
|
|
90
|
+
headTokens: [
|
|
91
|
+
{ token: "env", class: "documented-uncovered" },
|
|
92
|
+
{ token: "unset", class: "documented-uncovered" },
|
|
93
|
+
],
|
|
94
|
+
// Headless trigger alternatives (the bare `<SESSION_VAR>=` form) and
|
|
95
|
+
// multiple independent alternations make a flat verb list misleading
|
|
96
|
+
// rather than merely incomplete — left empty rather than overclaim.
|
|
97
|
+
verbs: [],
|
|
98
|
+
},
|
|
99
|
+
"deny-pause-sentinel-forgery": {
|
|
100
|
+
headTokens: [
|
|
101
|
+
{ token: "tee", class: "documented-uncovered" },
|
|
102
|
+
{ token: "cp", class: "documented-uncovered" },
|
|
103
|
+
],
|
|
104
|
+
// No separate "verb" beyond the head tokens themselves here.
|
|
105
|
+
verbs: [],
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* `documented-uncovered` head tokens are collected from the curated map
|
|
110
|
+
* itself (single source of truth) rather than hand-copied a second time.
|
|
111
|
+
*/
|
|
112
|
+
function documentedUncoveredTokens() {
|
|
113
|
+
const out = new Set();
|
|
114
|
+
for (const fact of Object.values(CURATED_BASH_MATCH_FACTS)) {
|
|
115
|
+
for (const h of fact.headTokens) {
|
|
116
|
+
if (h.class === "documented-uncovered")
|
|
117
|
+
out.add(h.token);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
/** Exposed for callers that need the full "genuinely not covered today" list (see `bash-match-registry.ts`). */
|
|
123
|
+
export const DOCUMENTED_UNCOVERED_HEAD_TOKENS = documentedUncoveredTokens();
|
|
124
|
+
/**
|
|
125
|
+
* Compute verified-fresh `BashMatchFacts` from a LIVE list of parsed
|
|
126
|
+
* policies. Call with `parseManifest(parseYaml(FULL_TEMPLATE)).policies`
|
|
127
|
+
* to get the shipped ground truth (never hand-copy the patterns).
|
|
128
|
+
*
|
|
129
|
+
* Throws descriptively — the caller should let this propagate as a
|
|
130
|
+
* failing test, not swallow it — when:
|
|
131
|
+
* 1. The exact SET of policy names carrying a `bash_match` trigger in
|
|
132
|
+
* the live `policies` differs from the curated map's key set
|
|
133
|
+
* (a policy was added, removed, or renamed).
|
|
134
|
+
* 2. A curated head token or verb is no longer present as a standalone
|
|
135
|
+
* word (`\bTOKEN\b`) in its policy's live pattern (renamed/removed
|
|
136
|
+
* within an otherwise still-existing policy).
|
|
137
|
+
*/
|
|
138
|
+
export function extractBashMatchFacts(policies) {
|
|
139
|
+
const live = policies.filter((p) => p.trigger.bash_match !== undefined);
|
|
140
|
+
const actualNames = [...live.map((p) => p.name)].sort();
|
|
141
|
+
const curatedNames = Object.keys(CURATED_BASH_MATCH_FACTS).sort();
|
|
142
|
+
if (JSON.stringify(actualNames) !== JSON.stringify(curatedNames)) {
|
|
143
|
+
throw new Error(`bash_match facts drift: the live policies declaring a bash_match trigger (${JSON.stringify(actualNames)}) no longer match CURATED_BASH_MATCH_FACTS's classified set (${JSON.stringify(curatedNames)}) in src/runtime/bash-match-facts.ts. A policy was added, removed, or renamed — update the curated map consciously.`);
|
|
144
|
+
}
|
|
145
|
+
const byName = new Map(live.map((p) => [p.name, p]));
|
|
146
|
+
const gatedHeadTokens = new Set();
|
|
147
|
+
const classification = new Map();
|
|
148
|
+
const policyFacts = [];
|
|
149
|
+
for (const policyName of curatedNames) {
|
|
150
|
+
const curated = CURATED_BASH_MATCH_FACTS[policyName];
|
|
151
|
+
const policy = byName.get(policyName);
|
|
152
|
+
const pattern = policy.trigger.bash_match;
|
|
153
|
+
for (const { token, class: cls } of curated.headTokens) {
|
|
154
|
+
assertStandaloneWord(pattern, token, policyName);
|
|
155
|
+
gatedHeadTokens.add(token);
|
|
156
|
+
classification.set(token, cls);
|
|
157
|
+
}
|
|
158
|
+
for (const verb of curated.verbs) {
|
|
159
|
+
assertStandaloneWord(pattern, verb, policyName);
|
|
160
|
+
}
|
|
161
|
+
policyFacts.push({
|
|
162
|
+
policyName,
|
|
163
|
+
pattern,
|
|
164
|
+
headTokens: curated.headTokens,
|
|
165
|
+
verbs: curated.verbs,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
policyNames: actualNames,
|
|
170
|
+
policies: policyFacts,
|
|
171
|
+
gatedHeadTokens,
|
|
172
|
+
classify: (token) => classification.get(token),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function assertStandaloneWord(pattern, word, policyName) {
|
|
176
|
+
const standaloneWordRe = new RegExp(`\\b${word}\\b`);
|
|
177
|
+
if (!standaloneWordRe.test(pattern)) {
|
|
178
|
+
throw new Error(`bash_match facts drift: policy "${policyName}"'s live bash_match pattern no longer contains the classified word "${word}" as a standalone word (pattern: ${pattern}). It was renamed or removed — update CURATED_BASH_MATCH_FACTS in src/runtime/bash-match-facts.ts.`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* "Is `token` gated by ANY shipped `bash_match` policy?" — the one-call
|
|
183
|
+
* question both incidents got wrong. Real caller (F8, fix round):
|
|
184
|
+
* `bash-match-registry.ts`'s `checkRegisteredSets` covers-purity check,
|
|
185
|
+
* which asks this once per declared `member` of every
|
|
186
|
+
* "covers-gated-head-tokens" registration. Takes only the `gatedHeadTokens`
|
|
187
|
+
* slice of `BashMatchFacts` (not the full shape) so a caller holding the
|
|
188
|
+
* same narrowed `Pick` `checkRegisteredSets` accepts can call this directly
|
|
189
|
+
* without widening its own parameter type.
|
|
190
|
+
*/
|
|
191
|
+
export function isHeadTokenGated(facts, token) {
|
|
192
|
+
return facts.gatedHeadTokens.has(token);
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=bash-match-facts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-match-facts.js","sourceRoot":"","sources":["../../src/runtime/bash-match-facts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { BashMatchFacts } from "./bash-match-facts.js";
|
|
2
|
+
export type RegisteredSetIntent = "covers-gated-head-tokens" | "must-not-contain-gated-head-token";
|
|
3
|
+
interface RegisteredHeadTokenSetCommon {
|
|
4
|
+
/** Stable identifier, used in failure messages and by the unregistered-set scan's cross-reference. */
|
|
5
|
+
readonly id: string;
|
|
6
|
+
/** File the set is actually declared in, for failure messages. */
|
|
7
|
+
readonly module: string;
|
|
8
|
+
/** Membership test — `Set.has` or `RegExp.test`, see the module header. */
|
|
9
|
+
readonly has: (token: string) => boolean;
|
|
10
|
+
readonly description: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A "covers-gated-head-tokens" registration — the set exists so the engine
|
|
14
|
+
* RECOGNISES these head tokens. `members` is NON-OPTIONAL (fix round 2,
|
|
15
|
+
* S1): the round-1 shape had this field OPTIONAL, and
|
|
16
|
+
* `checkRegisteredSets`'s covers-purity check (c) simply `continue`d past
|
|
17
|
+
* any registration that omitted it — a new module registered as
|
|
18
|
+
* "covers-gated-head-tokens" WITHOUT `members` measurably passed the full
|
|
19
|
+
* suite (167 files / 3980 tests) even with a gated head token laundered
|
|
20
|
+
* inside its `has()` predicate. Making `members` mandatory on this arm
|
|
21
|
+
* turns that escape into a TYPE ERROR: a covers registration that omits
|
|
22
|
+
* `members` now fails `tsc`, not merely a test. See `checkRegisteredSets`
|
|
23
|
+
* checks (c), (d), (e) below for the three independent things `members`
|
|
24
|
+
* (and `has()`) are cross-checked against.
|
|
25
|
+
*/
|
|
26
|
+
export interface CoversHeadTokenSet extends RegisteredHeadTokenSetCommon {
|
|
27
|
+
readonly intent: "covers-gated-head-tokens";
|
|
28
|
+
readonly members: readonly string[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A "must-not-contain-gated-head-token" registration — the set exists for
|
|
32
|
+
* some OTHER purpose and must never contain a token the manifest itself
|
|
33
|
+
* gates (the dbc6d303 CRITICAL shape). `members` is optional here: no
|
|
34
|
+
* purity/redundancy/predicate-purity semantics apply to this arm — only
|
|
35
|
+
* `has()` is ever asked anything (check (a)).
|
|
36
|
+
*/
|
|
37
|
+
export interface MustNotContainHeadTokenSet extends RegisteredHeadTokenSetCommon {
|
|
38
|
+
readonly intent: "must-not-contain-gated-head-token";
|
|
39
|
+
readonly members?: readonly string[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Discriminated union on `intent` (fix round 2, S1) — see
|
|
43
|
+
* `CoversHeadTokenSet`'s doc for why the split exists.
|
|
44
|
+
*/
|
|
45
|
+
export type RegisteredHeadTokenSet = CoversHeadTokenSet | MustNotContainHeadTokenSet;
|
|
46
|
+
export declare const REGISTERED_HEAD_TOKEN_SETS: readonly RegisteredHeadTokenSet[];
|
|
47
|
+
/**
|
|
48
|
+
* Which of the five independent checks flagged this violation (fix round
|
|
49
|
+
* 2): a fixture test asserting on one check's behaviour must not be
|
|
50
|
+
* silently polluted by another check's unrelated finding on the same
|
|
51
|
+
* (setId, token) pair — see `tests/runtime/bash-match-registry.test.ts`.
|
|
52
|
+
*/
|
|
53
|
+
export type RegistrationCheck = "must-not-contain" | "covers-completeness" | "covers-purity" | "covers-redundancy" | "covers-predicate-purity";
|
|
54
|
+
export interface RegistrationViolation {
|
|
55
|
+
readonly setId: string;
|
|
56
|
+
readonly intent: RegisteredSetIntent;
|
|
57
|
+
readonly token: string;
|
|
58
|
+
readonly check: RegistrationCheck;
|
|
59
|
+
readonly reason: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check every registered set against the live facts. Returns an EMPTY
|
|
63
|
+
* array when clean. `registrations` and `documentedUncovered` default to
|
|
64
|
+
* the real, shipped values (F5 fix-round correction: the
|
|
65
|
+
* `documentedUncovered` default previously silently fell back to an empty
|
|
66
|
+
* set, which raised 4 FALSE violations — tee, cp, env, unset — when called
|
|
67
|
+
* with only `facts`; pinned by
|
|
68
|
+
* `tests/runtime/bash-match-head-token-drift.test.ts`'s
|
|
69
|
+
* "checkRegisteredSets(liveFacts())" defaults test) but accept fixtures —
|
|
70
|
+
* see `tests/runtime/bash-match-registry.test.ts`'s regression tests for
|
|
71
|
+
* the historical incidents, which pass deliberately-broken fixtures to
|
|
72
|
+
* prove this function catches their exact shape.
|
|
73
|
+
*/
|
|
74
|
+
export declare function checkRegisteredSets(facts: Pick<BashMatchFacts, "gatedHeadTokens" | "classify">, registrations?: readonly RegisteredHeadTokenSet[], documentedUncovered?: ReadonlySet<string>): RegistrationViolation[];
|
|
75
|
+
export {};
|