@gate-forge/core 0.1.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/LICENSE +202 -0
- package/dist/baselines/adoption.d.ts +76 -0
- package/dist/baselines/adoption.d.ts.map +1 -0
- package/dist/baselines/adoption.js +163 -0
- package/dist/baselines/adoption.js.map +1 -0
- package/dist/baselines/index.d.ts +102 -0
- package/dist/baselines/index.d.ts.map +1 -0
- package/dist/baselines/index.js +186 -0
- package/dist/baselines/index.js.map +1 -0
- package/dist/canonical-json.d.ts +51 -0
- package/dist/canonical-json.d.ts.map +1 -0
- package/dist/canonical-json.js +112 -0
- package/dist/canonical-json.js.map +1 -0
- package/dist/classifier/bind.d.ts +64 -0
- package/dist/classifier/bind.d.ts.map +1 -0
- package/dist/classifier/bind.js +188 -0
- package/dist/classifier/bind.js.map +1 -0
- package/dist/classifier/classify.d.ts +154 -0
- package/dist/classifier/classify.d.ts.map +1 -0
- package/dist/classifier/classify.js +1207 -0
- package/dist/classifier/classify.js.map +1 -0
- package/dist/classifier/glob.d.ts +48 -0
- package/dist/classifier/glob.d.ts.map +1 -0
- package/dist/classifier/glob.js +104 -0
- package/dist/classifier/glob.js.map +1 -0
- package/dist/classifier/index.d.ts +10 -0
- package/dist/classifier/index.d.ts.map +1 -0
- package/dist/classifier/index.js +21 -0
- package/dist/classifier/index.js.map +1 -0
- package/dist/classifier/schema.d.ts +150 -0
- package/dist/classifier/schema.d.ts.map +1 -0
- package/dist/classifier/schema.js +139 -0
- package/dist/classifier/schema.js.map +1 -0
- package/dist/config/index.d.ts +259 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +523 -0
- package/dist/config/index.js.map +1 -0
- package/dist/fingerprints.d.ts +56 -0
- package/dist/fingerprints.d.ts.map +1 -0
- package/dist/fingerprints.js +59 -0
- package/dist/fingerprints.js.map +1 -0
- package/dist/graph/build.d.ts +16 -0
- package/dist/graph/build.d.ts.map +1 -0
- package/dist/graph/build.js +423 -0
- package/dist/graph/build.js.map +1 -0
- package/dist/graph/index.d.ts +12 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +10 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/schema.d.ts +448 -0
- package/dist/graph/schema.d.ts.map +1 -0
- package/dist/graph/schema.js +237 -0
- package/dist/graph/schema.js.map +1 -0
- package/dist/graph/symbols.d.ts +129 -0
- package/dist/graph/symbols.d.ts.map +1 -0
- package/dist/graph/symbols.js +177 -0
- package/dist/graph/symbols.js.map +1 -0
- package/dist/graph/util.d.ts +40 -0
- package/dist/graph/util.d.ts.map +1 -0
- package/dist/graph/util.js +41 -0
- package/dist/graph/util.js.map +1 -0
- package/dist/index.d.ts +683 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +563 -0
- package/dist/index.js.map +1 -0
- package/dist/mapping/resolve.d.ts +177 -0
- package/dist/mapping/resolve.d.ts.map +1 -0
- package/dist/mapping/resolve.js +523 -0
- package/dist/mapping/resolve.js.map +1 -0
- package/dist/policy/coverage.d.ts +79 -0
- package/dist/policy/coverage.d.ts.map +1 -0
- package/dist/policy/coverage.js +119 -0
- package/dist/policy/coverage.js.map +1 -0
- package/dist/policy/evaluate.d.ts +275 -0
- package/dist/policy/evaluate.d.ts.map +1 -0
- package/dist/policy/evaluate.js +382 -0
- package/dist/policy/evaluate.js.map +1 -0
- package/dist/policy/index.d.ts +15 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +14 -0
- package/dist/policy/index.js.map +1 -0
- package/dist/policy/trusted.d.ts +59 -0
- package/dist/policy/trusted.d.ts.map +1 -0
- package/dist/policy/trusted.js +96 -0
- package/dist/policy/trusted.js.map +1 -0
- package/dist/provenance.d.ts +170 -0
- package/dist/provenance.d.ts.map +1 -0
- package/dist/provenance.js +306 -0
- package/dist/provenance.js.map +1 -0
- package/dist/receipt/index.d.ts +74 -0
- package/dist/receipt/index.d.ts.map +1 -0
- package/dist/receipt/index.js +154 -0
- package/dist/receipt/index.js.map +1 -0
- package/dist/report/index.d.ts +100 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +355 -0
- package/dist/report/index.js.map +1 -0
- package/dist/schemas/adoption.d.ts +40 -0
- package/dist/schemas/adoption.d.ts.map +1 -0
- package/dist/schemas/adoption.js +87 -0
- package/dist/schemas/adoption.js.map +1 -0
- package/dist/schemas/baseline.d.ts +19 -0
- package/dist/schemas/baseline.d.ts.map +1 -0
- package/dist/schemas/baseline.js +45 -0
- package/dist/schemas/baseline.js.map +1 -0
- package/dist/schemas/claim.d.ts +32 -0
- package/dist/schemas/claim.d.ts.map +1 -0
- package/dist/schemas/claim.js +34 -0
- package/dist/schemas/claim.js.map +1 -0
- package/dist/schemas/classification-policy.d.ts +84 -0
- package/dist/schemas/classification-policy.d.ts.map +1 -0
- package/dist/schemas/classification-policy.js +130 -0
- package/dist/schemas/classification-policy.js.map +1 -0
- package/dist/schemas/classification-signal.d.ts +125 -0
- package/dist/schemas/classification-signal.d.ts.map +1 -0
- package/dist/schemas/classification-signal.js +126 -0
- package/dist/schemas/classification-signal.js.map +1 -0
- package/dist/schemas/classification.d.ts +120 -0
- package/dist/schemas/classification.d.ts.map +1 -0
- package/dist/schemas/classification.js +154 -0
- package/dist/schemas/classification.js.map +1 -0
- package/dist/schemas/common.d.ts +73 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +60 -0
- package/dist/schemas/common.js.map +1 -0
- package/dist/schemas/coverage-policy.d.ts +89 -0
- package/dist/schemas/coverage-policy.d.ts.map +1 -0
- package/dist/schemas/coverage-policy.js +81 -0
- package/dist/schemas/coverage-policy.js.map +1 -0
- package/dist/schemas/evidence.d.ts +65 -0
- package/dist/schemas/evidence.d.ts.map +1 -0
- package/dist/schemas/evidence.js +64 -0
- package/dist/schemas/evidence.js.map +1 -0
- package/dist/schemas/execution-result.d.ts +214 -0
- package/dist/schemas/execution-result.d.ts.map +1 -0
- package/dist/schemas/execution-result.js +240 -0
- package/dist/schemas/execution-result.js.map +1 -0
- package/dist/schemas/gate-receipt.d.ts +86 -0
- package/dist/schemas/gate-receipt.d.ts.map +1 -0
- package/dist/schemas/gate-receipt.js +193 -0
- package/dist/schemas/gate-receipt.js.map +1 -0
- package/dist/schemas/index.d.ts +22 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +22 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/obligation.d.ts +37 -0
- package/dist/schemas/obligation.d.ts.map +1 -0
- package/dist/schemas/obligation.js +46 -0
- package/dist/schemas/obligation.js.map +1 -0
- package/dist/schemas/plugin.d.ts +19 -0
- package/dist/schemas/plugin.d.ts.map +1 -0
- package/dist/schemas/plugin.js +20 -0
- package/dist/schemas/plugin.js.map +1 -0
- package/dist/schemas/policy.d.ts +73 -0
- package/dist/schemas/policy.d.ts.map +1 -0
- package/dist/schemas/policy.js +46 -0
- package/dist/schemas/policy.js.map +1 -0
- package/dist/schemas/resource.d.ts +26 -0
- package/dist/schemas/resource.d.ts.map +1 -0
- package/dist/schemas/resource.js +29 -0
- package/dist/schemas/resource.js.map +1 -0
- package/dist/schemas/run-manifest.d.ts +72 -0
- package/dist/schemas/run-manifest.d.ts.map +1 -0
- package/dist/schemas/run-manifest.js +125 -0
- package/dist/schemas/run-manifest.js.map +1 -0
- package/dist/schemas/runner-adapter.d.ts +169 -0
- package/dist/schemas/runner-adapter.d.ts.map +1 -0
- package/dist/schemas/runner-adapter.js +2 -0
- package/dist/schemas/runner-adapter.js.map +1 -0
- package/dist/schemas/test-catalog.d.ts +472 -0
- package/dist/schemas/test-catalog.d.ts.map +1 -0
- package/dist/schemas/test-catalog.js +311 -0
- package/dist/schemas/test-catalog.js.map +1 -0
- package/dist/schemas/test-map.d.ts +99 -0
- package/dist/schemas/test-map.d.ts.map +1 -0
- package/dist/schemas/test-map.js +103 -0
- package/dist/schemas/test-map.js.map +1 -0
- package/dist/schemas/verdict.d.ts +73 -0
- package/dist/schemas/verdict.d.ts.map +1 -0
- package/dist/schemas/verdict.js +92 -0
- package/dist/schemas/verdict.js.map +1 -0
- package/dist/schemas/waiver.d.ts +36 -0
- package/dist/schemas/waiver.d.ts.map +1 -0
- package/dist/schemas/waiver.js +42 -0
- package/dist/schemas/waiver.js.map +1 -0
- package/dist/supervision/index.d.ts +170 -0
- package/dist/supervision/index.d.ts.map +1 -0
- package/dist/supervision/index.js +354 -0
- package/dist/supervision/index.js.map +1 -0
- package/dist/testing/clock.d.ts +50 -0
- package/dist/testing/clock.d.ts.map +1 -0
- package/dist/testing/clock.js +75 -0
- package/dist/testing/clock.js.map +1 -0
- package/dist/testing/env.d.ts +66 -0
- package/dist/testing/env.d.ts.map +1 -0
- package/dist/testing/env.js +106 -0
- package/dist/testing/env.js.map +1 -0
- package/dist/testing/gate-runner.d.ts +141 -0
- package/dist/testing/gate-runner.d.ts.map +1 -0
- package/dist/testing/gate-runner.js +173 -0
- package/dist/testing/gate-runner.js.map +1 -0
- package/dist/testing/gf19.d.ts +106 -0
- package/dist/testing/gf19.d.ts.map +1 -0
- package/dist/testing/gf19.js +282 -0
- package/dist/testing/gf19.js.map +1 -0
- package/dist/testing/index.d.ts +20 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +14 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/red-probe.d.ts +138 -0
- package/dist/testing/red-probe.d.ts.map +1 -0
- package/dist/testing/red-probe.js +251 -0
- package/dist/testing/red-probe.js.map +1 -0
- package/dist/testing/temp-repo.d.ts +126 -0
- package/dist/testing/temp-repo.d.ts.map +1 -0
- package/dist/testing/temp-repo.js +214 -0
- package/dist/testing/temp-repo.js.map +1 -0
- package/dist/verdict/cause.d.ts +99 -0
- package/dist/verdict/cause.d.ts.map +1 -0
- package/dist/verdict/cause.js +206 -0
- package/dist/verdict/cause.js.map +1 -0
- package/dist/verdict/evaluate.d.ts +135 -0
- package/dist/verdict/evaluate.d.ts.map +1 -0
- package/dist/verdict/evaluate.js +1513 -0
- package/dist/verdict/evaluate.js.map +1 -0
- package/dist/verdict/index.d.ts +21 -0
- package/dist/verdict/index.d.ts.map +1 -0
- package/dist/verdict/index.js +20 -0
- package/dist/verdict/index.js.map +1 -0
- package/dist/verdict/pack-verifiers.d.ts +97 -0
- package/dist/verdict/pack-verifiers.d.ts.map +1 -0
- package/dist/verdict/pack-verifiers.js +763 -0
- package/dist/verdict/pack-verifiers.js.map +1 -0
- package/dist/verdict/registry.d.ts +180 -0
- package/dist/verdict/registry.d.ts.map +1 -0
- package/dist/verdict/registry.js +67 -0
- package/dist/verdict/registry.js.map +1 -0
- package/dist/waivers/index.d.ts +103 -0
- package/dist/waivers/index.d.ts.map +1 -0
- package/dist/waivers/index.js +192 -0
- package/dist/waivers/index.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.gateforge.yml` loading and validation (pin #6).
|
|
3
|
+
*
|
|
4
|
+
* Fail-closed by design: a missing file, unparsable YAML, an unknown
|
|
5
|
+
* `schemaVersion`, or any schema violation raises
|
|
6
|
+
* {@link GateforgeConfigError} carrying actionable diagnostics — each
|
|
7
|
+
* with the source file, a JSON path, and expected-vs-got detail.
|
|
8
|
+
* Exit code for this failure class is 2 (config/usage error).
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { parse as parseYaml } from 'yaml';
|
|
12
|
+
import { SchemaVersionField, TransportSchema } from '../schemas/common.js';
|
|
13
|
+
import { CoveragePolicySchema } from '../schemas/coverage-policy.js';
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
/**
|
|
16
|
+
* A plugin entry in `.gateforge.yml`. Unlike a run-manifest plugin
|
|
17
|
+
* registration, a config entry also declares HOW to launch the plugin:
|
|
18
|
+
* `subprocess` plugins get `command` (argv, run without network);
|
|
19
|
+
* `in-process` plugins get `module` (a TS module specifier).
|
|
20
|
+
*/
|
|
21
|
+
export const ConfigPluginSchema = z
|
|
22
|
+
.object({
|
|
23
|
+
/** Plugin id, e.g. `gateforge.pack-sqlalchemy`. */
|
|
24
|
+
id: z.string().min(1),
|
|
25
|
+
/** Declared plugin version (handshake-checked at spawn, pin #5). */
|
|
26
|
+
version: z.string().min(1),
|
|
27
|
+
/** Transport over the plugin boundary (ADR 0002). */
|
|
28
|
+
transport: TransportSchema,
|
|
29
|
+
/** argv to spawn (subprocess transport only), executed with no network. */
|
|
30
|
+
command: z.array(z.string().min(1)).min(1).optional(),
|
|
31
|
+
/** Module specifier to import (in-process transport only). */
|
|
32
|
+
module: z.string().min(1).optional(),
|
|
33
|
+
})
|
|
34
|
+
.strict()
|
|
35
|
+
.superRefine((plugin, ctx) => {
|
|
36
|
+
// Issuer reservation (ADR 0003 D2/D6): `gateforge.core` is the
|
|
37
|
+
// ENGINE's suppressive-signal authority. A plugin configured under
|
|
38
|
+
// that id would let ordinary plugin output forge engine-issued
|
|
39
|
+
// declarations, so the id is reserved at config validation — the
|
|
40
|
+
// engine is not a configurable plugin.
|
|
41
|
+
if (plugin.id === 'gateforge.core') {
|
|
42
|
+
ctx.addIssue({
|
|
43
|
+
code: 'custom',
|
|
44
|
+
path: ['id'],
|
|
45
|
+
message: "plugin id 'gateforge.core' is reserved: suppressive classification authority is engine-issued, never plugin-issued",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (plugin.transport === 'subprocess') {
|
|
49
|
+
if (plugin.command === undefined) {
|
|
50
|
+
ctx.addIssue({
|
|
51
|
+
code: 'custom',
|
|
52
|
+
path: ['command'],
|
|
53
|
+
message: `subprocess plugin '${plugin.id}' requires 'command' (argv to spawn)`,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (plugin.module !== undefined) {
|
|
57
|
+
ctx.addIssue({
|
|
58
|
+
code: 'custom',
|
|
59
|
+
path: ['module'],
|
|
60
|
+
message: `subprocess plugin '${plugin.id}' must not declare 'module' (in-process only)`,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
if (plugin.module === undefined) {
|
|
66
|
+
ctx.addIssue({
|
|
67
|
+
code: 'custom',
|
|
68
|
+
path: ['module'],
|
|
69
|
+
message: `in-process plugin '${plugin.id}' requires 'module' (module specifier to import)`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (plugin.command !== undefined) {
|
|
73
|
+
ctx.addIssue({
|
|
74
|
+
code: 'custom',
|
|
75
|
+
path: ['command'],
|
|
76
|
+
message: `in-process plugin '${plugin.id}' must not declare 'command' (subprocess only)`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* Enforcement-mode configuration (plan 2026-09-13 §3.4/§3.3, ADR 0005
|
|
83
|
+
* D1/D4). OPTIONAL and off by default — enabling strict E2E is an
|
|
84
|
+
* explicit, tracked owner decision.
|
|
85
|
+
*/
|
|
86
|
+
export const EnforcementConfigSchema = z
|
|
87
|
+
.object({
|
|
88
|
+
/**
|
|
89
|
+
* `standard` = local hook + mandatory trusted server check (honest
|
|
90
|
+
* about --no-verify); `managed` = authoritative commit broker outside
|
|
91
|
+
* the agent's write/process boundary. Later phases enforce this; the
|
|
92
|
+
* value is recorded here from Phase 0 on.
|
|
93
|
+
*/
|
|
94
|
+
mode: z.enum(['standard', 'managed']).default('standard'),
|
|
95
|
+
/**
|
|
96
|
+
* Strict E2E mode (plan §3.3): when true, a waived or baselined
|
|
97
|
+
* in-scope E2E obligation is NOT proof and cannot authorize the
|
|
98
|
+
* change — the gate reports it blocking (ENFORCEMENT_UNTRUSTED), and
|
|
99
|
+
* required contracts whose proof channel is unavailable fail the
|
|
100
|
+
* setup closed (preflight capability validation).
|
|
101
|
+
*/
|
|
102
|
+
strictE2E: z.boolean().default(false),
|
|
103
|
+
/**
|
|
104
|
+
* The OWNER-APPROVED policy revision digest (ADR 0005 D6 enforcement):
|
|
105
|
+
* the `trustedPolicyDigest` value the owner pinned as the approved
|
|
106
|
+
* policy revision. Gates compare the candidate's recomputed digest
|
|
107
|
+
* against it, so a candidate that edits classifiers, exclusions,
|
|
108
|
+
* waivers, baselines, or coverage cannot authorize its own weaker
|
|
109
|
+
* checks.
|
|
110
|
+
*
|
|
111
|
+
* TRUST BOUNDARY: this value must NEVER come from candidate-controlled
|
|
112
|
+
* files in strict mode. It is honored only when the config document
|
|
113
|
+
* carrying it lives OUTSIDE the candidate repository (loaded through
|
|
114
|
+
* the explicit `GATEFORGE_TRUSTED_CONFIG` path) or when the digest is
|
|
115
|
+
* provisioned through `GATEFORGE_APPROVED_POLICY_DIGEST` /
|
|
116
|
+
* `--approved-policy-digest`. Declaring it in the candidate's own
|
|
117
|
+
* `.gateforge.yml` is never a trusted source: strict gates block with
|
|
118
|
+
* ENFORCEMENT_UNTRUSTED instead of honoring it.
|
|
119
|
+
*/
|
|
120
|
+
approvedPolicyDigest: z
|
|
121
|
+
.string()
|
|
122
|
+
.regex(/^[0-9a-f]{64}$/, 'approvedPolicyDigest must be 64-char lowercase hex')
|
|
123
|
+
.optional(),
|
|
124
|
+
})
|
|
125
|
+
.strict();
|
|
126
|
+
/**
|
|
127
|
+
* One configured diagnostic suite (plan 2026-09-13 §3.5, phase 2 item
|
|
128
|
+
* 8): an EXISTING suite the owner registers for the advisory "red means
|
|
129
|
+
* inspect this" alarm. Gateforge never discovers suites on its own — no
|
|
130
|
+
* directory scans, no executing commands found on disk; everything comes
|
|
131
|
+
* from this explicit, tracked configuration.
|
|
132
|
+
*
|
|
133
|
+
* Only `pytest` is accepted today: other runners stay explicitly
|
|
134
|
+
* unsupported until an adapter exists (plan phase 2 item 6) — a typo'd
|
|
135
|
+
* or aspirational runner name must fail the config load, not silently
|
|
136
|
+
* disable a suite.
|
|
137
|
+
*/
|
|
138
|
+
export const DiagnosticSuiteSchema = z
|
|
139
|
+
.object({
|
|
140
|
+
/** Suite name used in reports and commands, e.g. `backend-pytest`. */
|
|
141
|
+
name: z.string().min(1),
|
|
142
|
+
/** The only runner with an adapter today (fail closed otherwise). */
|
|
143
|
+
runner: z.enum(['pytest']),
|
|
144
|
+
/** Repo-root-relative working directory the argv runs in. */
|
|
145
|
+
cwd: z.string().min(1),
|
|
146
|
+
/**
|
|
147
|
+
* Interpreter + args, e.g. `['python', '-m', 'pytest']`. The adapter
|
|
148
|
+
* appends collection/report flags; it never executes anything beyond
|
|
149
|
+
* this configured argv.
|
|
150
|
+
*/
|
|
151
|
+
argv: z.array(z.string().min(1)).min(1),
|
|
152
|
+
/**
|
|
153
|
+
* Paths handed to the runner VERBATIM (suite-`cwd`-relative), e.g.
|
|
154
|
+
* `['tests']`. The adapter never widens them: gateforge never scans
|
|
155
|
+
* directories the owner did not name here.
|
|
156
|
+
*/
|
|
157
|
+
testPaths: z.array(z.string().min(1)).min(1),
|
|
158
|
+
/** Finite wall-clock bound for one adapter invocation (seconds). */
|
|
159
|
+
timeoutMs: z.number().int().min(1),
|
|
160
|
+
})
|
|
161
|
+
.strict();
|
|
162
|
+
/**
|
|
163
|
+
* The `diagnostics` config section (plan §3.5): registered diagnostic
|
|
164
|
+
* suites. ABSENT = no diagnostic suites (the default; the alarm is
|
|
165
|
+
* opt-in and never a commit blocker by itself).
|
|
166
|
+
*/
|
|
167
|
+
export const DiagnosticsConfigSchema = z
|
|
168
|
+
.object({
|
|
169
|
+
/** Explicitly registered diagnostic suites. */
|
|
170
|
+
suites: z.array(DiagnosticSuiteSchema),
|
|
171
|
+
})
|
|
172
|
+
.strict()
|
|
173
|
+
.superRefine((diagnostics, ctx) => {
|
|
174
|
+
// Duplicate suite names would make `tests diagnose --suite <name>`
|
|
175
|
+
// and per-suite reporting ambiguous — reject at config load.
|
|
176
|
+
const seen = new Set();
|
|
177
|
+
for (let index = 0; index < diagnostics.suites.length; index += 1) {
|
|
178
|
+
const name = diagnostics.suites[index]?.name;
|
|
179
|
+
if (name === undefined)
|
|
180
|
+
continue;
|
|
181
|
+
if (seen.has(name)) {
|
|
182
|
+
ctx.addIssue({
|
|
183
|
+
code: 'custom',
|
|
184
|
+
path: ['suites', index, 'name'],
|
|
185
|
+
message: `duplicate diagnostic suite name '${name}': suite selection must be unambiguous`,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
seen.add(name);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
/**
|
|
192
|
+
* The `.gateforge.yml` document schema (pin #6). All paths are
|
|
193
|
+
* repo-root-relative. Unknown keys are rejected — a typo must fail the
|
|
194
|
+
* config load, not silently disable a subsystem.
|
|
195
|
+
*/
|
|
196
|
+
export const GateforgeConfigSchema = z
|
|
197
|
+
.object({
|
|
198
|
+
schemaVersion: SchemaVersionField,
|
|
199
|
+
/** Project-wide discovery settings. */
|
|
200
|
+
project: z
|
|
201
|
+
.object({
|
|
202
|
+
/** Languages detectors should run for, e.g. ['python']. */
|
|
203
|
+
languages: z.array(z.string().min(1)).min(1),
|
|
204
|
+
/** Path filters applied to discovery. */
|
|
205
|
+
paths: z
|
|
206
|
+
.object({
|
|
207
|
+
/** Globs to include. */
|
|
208
|
+
include: z.array(z.string().min(1)).min(1),
|
|
209
|
+
/** Globs to exclude. */
|
|
210
|
+
exclude: z.array(z.string().min(1)),
|
|
211
|
+
})
|
|
212
|
+
.strict(),
|
|
213
|
+
})
|
|
214
|
+
.strict(),
|
|
215
|
+
/** Plugin set: subprocess (GPP/3) and in-process detectors. */
|
|
216
|
+
plugins: z.array(ConfigPluginSchema),
|
|
217
|
+
/** Path to the policies YAML document. */
|
|
218
|
+
policies: z.string().min(1),
|
|
219
|
+
/**
|
|
220
|
+
* Path to the classification-policy YAML document (plan phase 5,
|
|
221
|
+
* ADR 0003 D5): repository-wide deterministic classification rules.
|
|
222
|
+
* Effective classifications are computed from detector signals on
|
|
223
|
+
* every run; there is no manual classifications document.
|
|
224
|
+
*/
|
|
225
|
+
classificationPolicy: z.string().min(1),
|
|
226
|
+
/** Directory of reviewed evidence adapters (.mjs, engine-loaded). */
|
|
227
|
+
adapters: z.string().min(1),
|
|
228
|
+
/** Directory of waiver documents. */
|
|
229
|
+
waivers: z.string().min(1),
|
|
230
|
+
/** Path to the baseline document (`.gateforge/baselines/obligations.json`). */
|
|
231
|
+
baselines: z.string().min(1),
|
|
232
|
+
/** Changed-file provider selection (architecture contract 5). */
|
|
233
|
+
changed: z
|
|
234
|
+
.object({
|
|
235
|
+
provider: z.enum(['auto', 'local-staged', 'github-pr', 'gitlab-mr']),
|
|
236
|
+
})
|
|
237
|
+
.strict(),
|
|
238
|
+
/** Witness service bounds. */
|
|
239
|
+
witness: z
|
|
240
|
+
.object({
|
|
241
|
+
/** Upper bound for a single witness call, in seconds. */
|
|
242
|
+
maxDurationSeconds: z.number().int().min(1),
|
|
243
|
+
})
|
|
244
|
+
.strict(),
|
|
245
|
+
/** Clock selection: system time, or a fixed instant for determinism. */
|
|
246
|
+
clock: z
|
|
247
|
+
.object({
|
|
248
|
+
mode: z.enum(['system', 'fixed']),
|
|
249
|
+
/** Required with mode 'fixed'; meaningless otherwise (rejected). */
|
|
250
|
+
fixedAt: z.iso.datetime().optional(),
|
|
251
|
+
})
|
|
252
|
+
.strict()
|
|
253
|
+
.superRefine((clock, ctx) => {
|
|
254
|
+
if (clock.mode === 'fixed' && clock.fixedAt === undefined) {
|
|
255
|
+
ctx.addIssue({
|
|
256
|
+
code: 'custom',
|
|
257
|
+
path: ['fixedAt'],
|
|
258
|
+
message: "clock.mode 'fixed' requires 'fixedAt' (ISO-8601 instant)",
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
if (clock.mode === 'system' && clock.fixedAt !== undefined) {
|
|
262
|
+
ctx.addIssue({
|
|
263
|
+
code: 'custom',
|
|
264
|
+
path: ['fixedAt'],
|
|
265
|
+
message: "'fixedAt' is only valid with clock.mode 'fixed'",
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}),
|
|
269
|
+
/**
|
|
270
|
+
* Enforcement modes (plan 2026-09-13 §3.3/§3.4, ADR 0005 D1/D4).
|
|
271
|
+
* ABSENT = feature off (standard mode, strict E2E off) so existing
|
|
272
|
+
* configs keep their exact behavior; enabling strict E2E is opt-in.
|
|
273
|
+
*/
|
|
274
|
+
enforcement: EnforcementConfigSchema.optional(),
|
|
275
|
+
/**
|
|
276
|
+
* Closed-world CRUD coverage policy (plan 2026-09-13 §3.6, ADR 0005
|
|
277
|
+
* D5): tracked, owner-owned enumeration of user-facing tables with
|
|
278
|
+
* required operations and owner dispositions. ABSENT/empty = feature
|
|
279
|
+
* off (opt-in). Validated against the current run's resource
|
|
280
|
+
* inventory on every run when present.
|
|
281
|
+
*/
|
|
282
|
+
coveragePolicy: CoveragePolicySchema.optional(),
|
|
283
|
+
/**
|
|
284
|
+
* Registered diagnostic suites (plan 2026-09-13 §3.5). ABSENT = no
|
|
285
|
+
* suites; the advisory alarm is opt-in via explicit, tracked
|
|
286
|
+
* configuration — gateforge never scans for or launches anything the
|
|
287
|
+
* owner did not register here.
|
|
288
|
+
*/
|
|
289
|
+
diagnostics: DiagnosticsConfigSchema.optional(),
|
|
290
|
+
})
|
|
291
|
+
.strict();
|
|
292
|
+
/** Error raised for any fail-closed config problem. */
|
|
293
|
+
export class GateforgeConfigError extends Error {
|
|
294
|
+
/** All collected diagnostics (first is the primary cause). */
|
|
295
|
+
diagnostics;
|
|
296
|
+
/**
|
|
297
|
+
* Builds the error from diagnostics.
|
|
298
|
+
*
|
|
299
|
+
* Args:
|
|
300
|
+
* diagnostics: nonempty list of actionable diagnostics.
|
|
301
|
+
*/
|
|
302
|
+
constructor(diagnostics) {
|
|
303
|
+
super(formatDiagnostics(diagnostics));
|
|
304
|
+
this.name = 'GateforgeConfigError';
|
|
305
|
+
this.diagnostics = diagnostics;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Renders a diagnostic input value compactly for `got` fields.
|
|
310
|
+
*
|
|
311
|
+
* Args:
|
|
312
|
+
* value: the offending value from the parsed document.
|
|
313
|
+
*
|
|
314
|
+
* Returns:
|
|
315
|
+
* string: single-line, length-capped rendering of the value.
|
|
316
|
+
*/
|
|
317
|
+
function renderGot(value) {
|
|
318
|
+
let rendered;
|
|
319
|
+
if (typeof value === 'string') {
|
|
320
|
+
rendered = JSON.stringify(value);
|
|
321
|
+
}
|
|
322
|
+
else if (value === undefined) {
|
|
323
|
+
rendered = 'undefined';
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
try {
|
|
327
|
+
rendered = JSON.stringify(value) ?? String(value);
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
rendered = String(value);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return rendered.length > 80 ? `${rendered.slice(0, 77)}...` : rendered;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Converts a zod issue path to a JSONPath-style string (`$.a.b[0]`).
|
|
337
|
+
*
|
|
338
|
+
* Args:
|
|
339
|
+
* path: zod issue path segments.
|
|
340
|
+
*
|
|
341
|
+
* Returns:
|
|
342
|
+
* string: JSON path with a leading `$`.
|
|
343
|
+
*/
|
|
344
|
+
export function jsonPathFor(path) {
|
|
345
|
+
let out = '$';
|
|
346
|
+
for (const segment of path) {
|
|
347
|
+
out += typeof segment === 'number' ? `[${String(segment)}]` : `.${String(segment)}`;
|
|
348
|
+
}
|
|
349
|
+
return out;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Reads the offending value out of the original document by issue path.
|
|
353
|
+
* Zod v4 issues do not carry the rejected input, so we recover it here.
|
|
354
|
+
*
|
|
355
|
+
* Args:
|
|
356
|
+
* input: the original parsed document handed to the schema.
|
|
357
|
+
* path: zod issue path segments.
|
|
358
|
+
*
|
|
359
|
+
* Returns:
|
|
360
|
+
* unknown: the value at the path, or undefined when unreachable.
|
|
361
|
+
*/
|
|
362
|
+
function valueAtPath(input, path) {
|
|
363
|
+
let current = input;
|
|
364
|
+
for (const segment of path) {
|
|
365
|
+
if (current === null || typeof current !== 'object') {
|
|
366
|
+
return undefined;
|
|
367
|
+
}
|
|
368
|
+
current = current[segment];
|
|
369
|
+
}
|
|
370
|
+
return current;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Extracts the "expected" detail from a zod issue when available:
|
|
374
|
+
* enum/literal issues carry `values`, type issues carry `expected`.
|
|
375
|
+
*
|
|
376
|
+
* Args:
|
|
377
|
+
* issue: the zod issue.
|
|
378
|
+
*
|
|
379
|
+
* Returns:
|
|
380
|
+
* string | undefined: rendered expectation, when the issue has one.
|
|
381
|
+
*/
|
|
382
|
+
function expectedFromIssue(issue) {
|
|
383
|
+
const record = issue;
|
|
384
|
+
const values = record['values'];
|
|
385
|
+
if (Array.isArray(values) && values.length > 0) {
|
|
386
|
+
return values.map((value) => JSON.stringify(value)).join(' | ');
|
|
387
|
+
}
|
|
388
|
+
return typeof record['expected'] === 'string' ? record['expected'] : undefined;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Converts zod issues into actionable config diagnostics.
|
|
392
|
+
*
|
|
393
|
+
* Args:
|
|
394
|
+
* error: failed zod result error.
|
|
395
|
+
* file: file name to attach to every diagnostic.
|
|
396
|
+
* input: the original parsed document, used to recover got-values.
|
|
397
|
+
*
|
|
398
|
+
* Returns:
|
|
399
|
+
* ConfigDiagnostic[]: one diagnostic per issue, same order.
|
|
400
|
+
*/
|
|
401
|
+
export function diagnosticsFromZodError(error, file, input) {
|
|
402
|
+
return error.issues.map((issue) => {
|
|
403
|
+
const gotValue = input === undefined ? undefined : valueAtPath(input, issue.path);
|
|
404
|
+
return {
|
|
405
|
+
file,
|
|
406
|
+
jsonPath: jsonPathFor(issue.path),
|
|
407
|
+
message: issue.message,
|
|
408
|
+
expected: expectedFromIssue(issue),
|
|
409
|
+
got: gotValue === undefined ? undefined : renderGot(gotValue),
|
|
410
|
+
};
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Formats diagnostics into the multi-line message users see.
|
|
415
|
+
*
|
|
416
|
+
* Args:
|
|
417
|
+
* diagnostics: diagnostics to render.
|
|
418
|
+
*
|
|
419
|
+
* Returns:
|
|
420
|
+
* string: human-readable, single-cause-first listing.
|
|
421
|
+
*/
|
|
422
|
+
export function formatDiagnostics(diagnostics) {
|
|
423
|
+
const head = diagnostics.length === 1
|
|
424
|
+
? 'invalid gateforge config (1 error)'
|
|
425
|
+
: `invalid gateforge config (${String(diagnostics.length)} errors)`;
|
|
426
|
+
const lines = diagnostics.map((diagnostic) => {
|
|
427
|
+
const parts = [diagnostic.file, diagnostic.jsonPath, diagnostic.message];
|
|
428
|
+
if (diagnostic.expected !== undefined) {
|
|
429
|
+
parts.push(`expected: ${diagnostic.expected}`);
|
|
430
|
+
}
|
|
431
|
+
if (diagnostic.got !== undefined) {
|
|
432
|
+
parts.push(`got: ${diagnostic.got}`);
|
|
433
|
+
}
|
|
434
|
+
return ` - ${parts.filter((part) => part.length > 0).join(': ')}`;
|
|
435
|
+
});
|
|
436
|
+
return [head, ...lines].join('\n');
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Validates an already-parsed config document against the schema.
|
|
440
|
+
*
|
|
441
|
+
* Args:
|
|
442
|
+
* input: parsed YAML/JSON document (an unknown value).
|
|
443
|
+
* file: source file name for diagnostics (default '<inline>').
|
|
444
|
+
*
|
|
445
|
+
* Returns:
|
|
446
|
+
* GateforgeConfig: the validated config.
|
|
447
|
+
*
|
|
448
|
+
* Raises:
|
|
449
|
+
* GateforgeConfigError: on any schema violation, including unknown
|
|
450
|
+
* schemaVersion (never migrated) and unknown keys (typos fail loud).
|
|
451
|
+
*/
|
|
452
|
+
export function parseConfig(input, { file = '<inline>' } = {}) {
|
|
453
|
+
// Migration diagnostic (plan phase 5): the authoritative manual
|
|
454
|
+
// classifications document was removed in the automatic-classification
|
|
455
|
+
// cutover. Fail with the exact migration steps, never a generic
|
|
456
|
+
// unknown-key error.
|
|
457
|
+
if (input !== null && typeof input === 'object' && 'classifications' in input) {
|
|
458
|
+
throw new GateforgeConfigError([
|
|
459
|
+
{
|
|
460
|
+
file,
|
|
461
|
+
jsonPath: '$.classifications',
|
|
462
|
+
message: "config key 'classifications' was removed: classification is now automatic. " +
|
|
463
|
+
"Delete the key and add `classificationPolicy: .gateforge/classification-policy.yml` " +
|
|
464
|
+
'(create it with `gateforge init`); its scanRoots gate every closed-world proof. ' +
|
|
465
|
+
'Per-resource entries became `gateforge classify --write-snapshot` output ' +
|
|
466
|
+
'(a derived artifact — never authoritative input) or source declarations.',
|
|
467
|
+
},
|
|
468
|
+
]);
|
|
469
|
+
}
|
|
470
|
+
const result = GateforgeConfigSchema.safeParse(input);
|
|
471
|
+
if (result.success) {
|
|
472
|
+
return result.data;
|
|
473
|
+
}
|
|
474
|
+
throw new GateforgeConfigError(diagnosticsFromZodError(result.error, file, input));
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Loads and validates `.gateforge.yml` from disk. Fail-closed: a missing
|
|
478
|
+
* file, unparsable YAML, or schema violations all raise
|
|
479
|
+
* {@link GateforgeConfigError} with actionable diagnostics.
|
|
480
|
+
*
|
|
481
|
+
* Args:
|
|
482
|
+
* path: config file path (default '.gateforge.yml').
|
|
483
|
+
*
|
|
484
|
+
* Returns:
|
|
485
|
+
* GateforgeConfig: the validated config.
|
|
486
|
+
*
|
|
487
|
+
* Raises:
|
|
488
|
+
* GateforgeConfigError: for missing/unreadable/unparsable/invalid config.
|
|
489
|
+
*/
|
|
490
|
+
export function loadConfig(path = '.gateforge.yml') {
|
|
491
|
+
let raw;
|
|
492
|
+
try {
|
|
493
|
+
raw = readFileSync(path, 'utf8');
|
|
494
|
+
}
|
|
495
|
+
catch (cause) {
|
|
496
|
+
const code = cause.code ?? 'UNKNOWN';
|
|
497
|
+
const hint = code === 'ENOENT'
|
|
498
|
+
? 'run the init command or pass an explicit config path'
|
|
499
|
+
: 'check file permissions';
|
|
500
|
+
throw new GateforgeConfigError([
|
|
501
|
+
{
|
|
502
|
+
file: path,
|
|
503
|
+
jsonPath: '$',
|
|
504
|
+
message: `cannot read config file (${code}); ${hint}`,
|
|
505
|
+
},
|
|
506
|
+
]);
|
|
507
|
+
}
|
|
508
|
+
let document;
|
|
509
|
+
try {
|
|
510
|
+
document = parseYaml(raw);
|
|
511
|
+
}
|
|
512
|
+
catch (cause) {
|
|
513
|
+
throw new GateforgeConfigError([
|
|
514
|
+
{
|
|
515
|
+
file: path,
|
|
516
|
+
jsonPath: '$',
|
|
517
|
+
message: `invalid YAML: ${cause.message.split('\n')[0] ?? 'parse error'}`,
|
|
518
|
+
},
|
|
519
|
+
]);
|
|
520
|
+
}
|
|
521
|
+
return parseConfig(document, { file: path });
|
|
522
|
+
}
|
|
523
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Obligation fingerprint (pin #2): the stable identity a baseline stores.
|
|
3
|
+
*
|
|
4
|
+
* `fingerprint(obligation-ish) = sha256(GF-canonical-JSON of
|
|
5
|
+
* {resourceId, contract, policyId, lifecycle})` where `lifecycle` is the
|
|
6
|
+
* classification lifecycle relevant to that contract. Key order in the
|
|
7
|
+
* input is irrelevant — canonical JSON sorts keys before hashing.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { type BlockingEntry } from './policy/evaluate.js';
|
|
11
|
+
/** Exactly the identity fields hashed into an obligation fingerprint. */
|
|
12
|
+
export declare const FingerprintInputSchema: z.ZodObject<{
|
|
13
|
+
resourceId: z.ZodString;
|
|
14
|
+
contract: z.ZodString;
|
|
15
|
+
policyId: z.ZodString;
|
|
16
|
+
lifecycle: z.ZodObject<{
|
|
17
|
+
create: z.ZodBoolean;
|
|
18
|
+
read: z.ZodBoolean;
|
|
19
|
+
update: z.ZodBoolean;
|
|
20
|
+
delete: z.ZodBoolean;
|
|
21
|
+
deleteSemantics: z.ZodOptional<z.ZodEnum<{
|
|
22
|
+
hard: "hard";
|
|
23
|
+
archive: "archive";
|
|
24
|
+
}>>;
|
|
25
|
+
archiveFields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
26
|
+
updateableFields: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
27
|
+
}, z.core.$strict>;
|
|
28
|
+
}, z.core.$strict>;
|
|
29
|
+
/** Inferred fingerprint-input shape. */
|
|
30
|
+
export type FingerprintInput = z.infer<typeof FingerprintInputSchema>;
|
|
31
|
+
/**
|
|
32
|
+
* Computes the obligation fingerprint (pin #2).
|
|
33
|
+
*
|
|
34
|
+
* Args:
|
|
35
|
+
* input: the obligation identity — resourceId, contract, policyId,
|
|
36
|
+
* and the relevant lifecycle attributes.
|
|
37
|
+
*
|
|
38
|
+
* Returns:
|
|
39
|
+
* string: 64-char lowercase sha256 hex over the GF-canonical-JSON of
|
|
40
|
+
* the identity object. Stable across key order and process runs.
|
|
41
|
+
*/
|
|
42
|
+
export declare function fingerprint(input: FingerprintInput): string;
|
|
43
|
+
/**
|
|
44
|
+
* The BLOCKING-ENTRY fingerprint (phase 8 workstream C): the stable
|
|
45
|
+
* identity a baseline stores for gate red that is not an obligation —
|
|
46
|
+
* unclassified/unresolved resources, detector/graph findings, and stale
|
|
47
|
+
* references. sha256 over the GF-canonical-JSON of the whole entry
|
|
48
|
+
* (kind, resourceId, name, detail, location): any change to the cause —
|
|
49
|
+
* including wording or location of the underlying problem — mints a NEW
|
|
50
|
+
* fingerprint, which the baseline does not contain, which blocks again.
|
|
51
|
+
* That is the fail-closed direction: the adoption baseline forgives the
|
|
52
|
+
* debt exactly as it stood at adoption; anything that shifts must be
|
|
53
|
+
* re-proven, never re-forgiven (the baseline is shrink-only).
|
|
54
|
+
*/
|
|
55
|
+
export declare function blockingEntryFingerprint(entry: BlockingEntry): string;
|
|
56
|
+
//# sourceMappingURL=fingerprints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprints.d.ts","sourceRoot":"","sources":["../src/fingerprints.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE/E,yEAAyE;AACzE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;kBAcxB,CAAC;AAEZ,wCAAwC;AACxC,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAE3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAErE"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Obligation fingerprint (pin #2): the stable identity a baseline stores.
|
|
3
|
+
*
|
|
4
|
+
* `fingerprint(obligation-ish) = sha256(GF-canonical-JSON of
|
|
5
|
+
* {resourceId, contract, policyId, lifecycle})` where `lifecycle` is the
|
|
6
|
+
* classification lifecycle relevant to that contract. Key order in the
|
|
7
|
+
* input is irrelevant — canonical JSON sorts keys before hashing.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { sha256Canonical } from './canonical-json.js';
|
|
11
|
+
import { ContractNameSchema } from './schemas/common.js';
|
|
12
|
+
import { LifecycleSchema } from './schemas/classification.js';
|
|
13
|
+
import { BlockingEntrySchema } from './policy/evaluate.js';
|
|
14
|
+
/** Exactly the identity fields hashed into an obligation fingerprint. */
|
|
15
|
+
export const FingerprintInputSchema = z
|
|
16
|
+
.object({
|
|
17
|
+
/** Resource the obligation attaches to (no colons). */
|
|
18
|
+
resourceId: z
|
|
19
|
+
.string()
|
|
20
|
+
.min(1)
|
|
21
|
+
.regex(/^[^:]+$/, "resourceId must not contain ':'"),
|
|
22
|
+
/** Contract name, e.g. `crud:update`. */
|
|
23
|
+
contract: ContractNameSchema,
|
|
24
|
+
/** Policy id that generated the obligation. */
|
|
25
|
+
policyId: z.string().min(1),
|
|
26
|
+
/** Classification lifecycle attributes relevant to the contract. */
|
|
27
|
+
lifecycle: LifecycleSchema,
|
|
28
|
+
})
|
|
29
|
+
.strict();
|
|
30
|
+
/**
|
|
31
|
+
* Computes the obligation fingerprint (pin #2).
|
|
32
|
+
*
|
|
33
|
+
* Args:
|
|
34
|
+
* input: the obligation identity — resourceId, contract, policyId,
|
|
35
|
+
* and the relevant lifecycle attributes.
|
|
36
|
+
*
|
|
37
|
+
* Returns:
|
|
38
|
+
* string: 64-char lowercase sha256 hex over the GF-canonical-JSON of
|
|
39
|
+
* the identity object. Stable across key order and process runs.
|
|
40
|
+
*/
|
|
41
|
+
export function fingerprint(input) {
|
|
42
|
+
return sha256Canonical(FingerprintInputSchema.parse(input));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The BLOCKING-ENTRY fingerprint (phase 8 workstream C): the stable
|
|
46
|
+
* identity a baseline stores for gate red that is not an obligation —
|
|
47
|
+
* unclassified/unresolved resources, detector/graph findings, and stale
|
|
48
|
+
* references. sha256 over the GF-canonical-JSON of the whole entry
|
|
49
|
+
* (kind, resourceId, name, detail, location): any change to the cause —
|
|
50
|
+
* including wording or location of the underlying problem — mints a NEW
|
|
51
|
+
* fingerprint, which the baseline does not contain, which blocks again.
|
|
52
|
+
* That is the fail-closed direction: the adoption baseline forgives the
|
|
53
|
+
* debt exactly as it stood at adoption; anything that shifts must be
|
|
54
|
+
* re-proven, never re-forgiven (the baseline is shrink-only).
|
|
55
|
+
*/
|
|
56
|
+
export function blockingEntryFingerprint(entry) {
|
|
57
|
+
return sha256Canonical(BlockingEntrySchema.parse(entry));
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=fingerprints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprints.js","sourceRoot":"","sources":["../src/fingerprints.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAsB,MAAM,sBAAsB,CAAC;AAE/E,yEAAyE;AACzE,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC;KACpC,MAAM,CAAC;IACN,uDAAuD;IACvD,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,KAAK,CAAC,SAAS,EAAE,iCAAiC,CAAC;IACtD,yCAAyC;IACzC,QAAQ,EAAE,kBAAkB;IAC5B,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,oEAAoE;IACpE,SAAS,EAAE,eAAe;CAC3B,CAAC;KACD,MAAM,EAAE,CAAC;AAKZ;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,KAAuB;IACjD,OAAO,eAAe,CAAC,sBAAsB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAoB;IAC3D,OAAO,eAAe,CAAC,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|