@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,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy engine (plan §5.2, G2): evaluates declarative policies
|
|
3
|
+
* (`PolicyFile`) against the classified resources of a built
|
|
4
|
+
* {@link ResourceGraph} and produces obligations plus the blocking
|
|
5
|
+
* verdict entries the gate must stay visible for (invariants 1, 8).
|
|
6
|
+
*
|
|
7
|
+
* Semantics (plan §5.2 + ADR 0001):
|
|
8
|
+
* - `crud:create|read|update|delete` obligations are LIFECYCLE-GATED:
|
|
9
|
+
* a contract is emitted only when the classification's lifecycle
|
|
10
|
+
* flag for that operation is `true` (user-facing + `lifecycle.create`
|
|
11
|
+
* ⇒ `crud:create`, etc.). Non-uniform lifecycles fall out naturally:
|
|
12
|
+
* immutable/read-only resources generate only `crud:read`, append-only
|
|
13
|
+
* resources `crud:create` + `crud:read`, archive-not-delete resources
|
|
14
|
+
* `crud:delete` with `deleteSemantics: 'archive'` in the fingerprint.
|
|
15
|
+
* - Non-`crud:` contracts pass through ungated (the policy author
|
|
16
|
+
* explicitly required them).
|
|
17
|
+
* - Internal resources generate NO CRUD obligations — their claims are
|
|
18
|
+
* invalid (ADR 0001). Non-CRUD contracts still apply.
|
|
19
|
+
* - Unclassified and unresolved resources produce blocking entries and
|
|
20
|
+
* no obligations until classified/resolved, but stay gate-visible.
|
|
21
|
+
* So do detector/graph `findings` (a partial discovery must never
|
|
22
|
+
* yield a green gate) and `stale` references (invariant 9).
|
|
23
|
+
* - Policies are evaluated in file order; the first policy generating
|
|
24
|
+
* a given `<resourceId>:<contract>` owns it (obligation ids are
|
|
25
|
+
* unique identities — pin #1's fingerprint keys on them).
|
|
26
|
+
*/
|
|
27
|
+
import { z } from 'zod';
|
|
28
|
+
import { LocationSchema, SchemaVersionField } from '../schemas/common.js';
|
|
29
|
+
import { CauseCodeSchema } from '../schemas/verdict.js';
|
|
30
|
+
import { ObligationSchema } from '../schemas/obligation.js';
|
|
31
|
+
import { PolicyFileSchema } from '../schemas/policy.js';
|
|
32
|
+
import { ClaimSchema } from '../schemas/claim.js';
|
|
33
|
+
import { HTTP_ENDPOINT_RESOURCE_KIND } from '../graph/schema.js';
|
|
34
|
+
import { compareStrings } from '../graph/util.js';
|
|
35
|
+
/** The CRUD contract namespace gated by lifecycle flags. */
|
|
36
|
+
export const CRUD_CONTRACT_PREFIX = 'crud:';
|
|
37
|
+
/**
|
|
38
|
+
* The persistence-level CRUD contract namespace (audit round 5):
|
|
39
|
+
* lifecycle-gated exactly like `crud:`, but graded on the witness's own
|
|
40
|
+
* engine-side observations (absence/presence, before/after deltas,
|
|
41
|
+
* owner-declared archive state). UI-semantic `crud:` contracts stay
|
|
42
|
+
* fail-closed in the verdict engine until a witness-controlled UI
|
|
43
|
+
* observation channel exists.
|
|
44
|
+
*/
|
|
45
|
+
export const PERSISTENCE_CONTRACT_PREFIX = 'persistence:';
|
|
46
|
+
/** The four lifecycle-gated operations, in canonical order. */
|
|
47
|
+
const CRUD_OPERATIONS = ['create', 'read', 'update', 'delete'];
|
|
48
|
+
/**
|
|
49
|
+
* Fail-closed policy-engine error: thrown for policy documents that
|
|
50
|
+
* are structurally invalid (zod) or use the `crud:` namespace with an
|
|
51
|
+
* unknown operation — a config/usage problem, never a silent skip.
|
|
52
|
+
*/
|
|
53
|
+
export class PolicyEvaluationError extends Error {
|
|
54
|
+
constructor(message) {
|
|
55
|
+
super(message);
|
|
56
|
+
this.name = 'PolicyEvaluationError';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Why a resource currently generates no obligations. */
|
|
60
|
+
export const BlockingEntrySchema = z
|
|
61
|
+
.strictObject({
|
|
62
|
+
/**
|
|
63
|
+
* `unclassified` = resolved but lacking any effective classification
|
|
64
|
+
* (the classifier blocked it definitionally); `classification` = a
|
|
65
|
+
* typed classifier block (contradiction, incomplete proof scope,
|
|
66
|
+
* stale/invalid signal, missing adapter) — machine-actionable, the
|
|
67
|
+
* conservative decision stands where one exists; `unresolved`
|
|
68
|
+
* = identity not statically resolvable; `finding` = a detector/graph
|
|
69
|
+
* finding (e.g. PARSE_ERROR) — discovery only partly succeeded, so
|
|
70
|
+
* the gate cannot claim full knowledge; `stale-reference` = an
|
|
71
|
+
* artifact still pointing at a removed resource (invariant 9:
|
|
72
|
+
* nothing silently disappears).
|
|
73
|
+
*/
|
|
74
|
+
kind: z.enum([
|
|
75
|
+
'unclassified',
|
|
76
|
+
'classification',
|
|
77
|
+
'unresolved',
|
|
78
|
+
'finding',
|
|
79
|
+
'stale-reference',
|
|
80
|
+
]),
|
|
81
|
+
/** Plane-qualified id when one could be derived, else `null`. */
|
|
82
|
+
resourceId: z.string().min(1).nullable(),
|
|
83
|
+
/** Bare resource name when known, else `null`. */
|
|
84
|
+
name: z.string().min(1).nullable(),
|
|
85
|
+
/** Single-cause human explanation (invariant 8: explain every block). */
|
|
86
|
+
detail: z.string().min(1),
|
|
87
|
+
/** Source location when known, else `null`. */
|
|
88
|
+
location: LocationSchema.nullable(),
|
|
89
|
+
/**
|
|
90
|
+
* Stable plan §5.4 cause code when the entry maps to one (coverage
|
|
91
|
+
* findings → CRUD_COVERAGE_MISSING, strict-capability preflight →
|
|
92
|
+
* VERIFIER_UNSUPPORTED, strict-mode waivers → ENFORCEMENT_UNTRUSTED).
|
|
93
|
+
* Absent/null for entries without a Phase 0 mapping.
|
|
94
|
+
*/
|
|
95
|
+
cause: CauseCodeSchema.nullish(),
|
|
96
|
+
/** Human next action accompanying `cause`; absent/null when unmapped. */
|
|
97
|
+
nextAction: z.string().min(1).nullish(),
|
|
98
|
+
});
|
|
99
|
+
/**
|
|
100
|
+
* The adopted identity of a classification-blocked resource (two-layer
|
|
101
|
+
* adoption): the ONE canonical string both `gateforge adopt` captures
|
|
102
|
+
* into the receipt's `classificationBlocked` set and the check matches
|
|
103
|
+
* against when waiving — so the two sides can never disagree.
|
|
104
|
+
*
|
|
105
|
+
* - The plane-qualified `resourceId` when the entry carries one (blocks
|
|
106
|
+
* on otherwise-classified resources, e.g. delete-semantics).
|
|
107
|
+
* - Else the bare resource name under a `name:` namespace — a resource
|
|
108
|
+
* with NO derivable plane (PLANE_UNRESOLVED) has no plane-qualified id
|
|
109
|
+
* by definition, and its bare name is the stable, merge-surviving
|
|
110
|
+
* identity. The `name:` prefix keeps the fallback out of the
|
|
111
|
+
* plane-qualified id space (`tenant.users` et al.).
|
|
112
|
+
* - Both the `classification` entry (the typed block) AND the
|
|
113
|
+
* `unclassified` shadow entry (the definitional "no effective
|
|
114
|
+
* classification" block the policy engine emits for the SAME resource)
|
|
115
|
+
* map to the same identity: waiving the resource waives its whole
|
|
116
|
+
* adopted block, or the gate could never return to green.
|
|
117
|
+
*
|
|
118
|
+
* Returns null for entries that are never resource-scoped (document-level
|
|
119
|
+
* classifier blocks — stale targets, invalid signals — and
|
|
120
|
+
* unresolved/finding/stale-reference kinds): those can never be adopted
|
|
121
|
+
* by this layer.
|
|
122
|
+
*/
|
|
123
|
+
export function classificationBlockedIdentity(entry) {
|
|
124
|
+
if (entry.kind !== 'classification' && entry.kind !== 'unclassified')
|
|
125
|
+
return null;
|
|
126
|
+
if (entry.resourceId !== null)
|
|
127
|
+
return entry.resourceId;
|
|
128
|
+
if (entry.name !== null)
|
|
129
|
+
return `name:${entry.name}`;
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
/** Assessment of one watched claim against the generated obligations. */
|
|
133
|
+
export const ClaimAssessmentSchema = z
|
|
134
|
+
.strictObject({
|
|
135
|
+
claim: ClaimSchema,
|
|
136
|
+
status: z.enum(['valid', 'invalid']),
|
|
137
|
+
/** Single-cause reason for `invalid`; `null` when valid. */
|
|
138
|
+
reason: z.string().min(1).nullable(),
|
|
139
|
+
});
|
|
140
|
+
/** The complete policy-engine result. Deterministic; fully sorted. */
|
|
141
|
+
export const PolicyEvaluationResultSchema = z
|
|
142
|
+
.strictObject({
|
|
143
|
+
schemaVersion: SchemaVersionField,
|
|
144
|
+
/** Generated obligations, sorted by id (unique — first policy wins). */
|
|
145
|
+
obligations: z.array(ObligationSchema),
|
|
146
|
+
/**
|
|
147
|
+
* Entries the gate must stay visible for, sorted deterministically:
|
|
148
|
+
* unclassified + unresolved resources, detector/graph findings, and
|
|
149
|
+
* stale references (fail closed — a discovery pass that partly
|
|
150
|
+
* failed or left orphans can never yield a green run).
|
|
151
|
+
*/
|
|
152
|
+
blocking: z.array(BlockingEntrySchema),
|
|
153
|
+
/** Claim assessments, sorted by obligation id then test id. */
|
|
154
|
+
claims: z.array(ClaimAssessmentSchema),
|
|
155
|
+
});
|
|
156
|
+
/**
|
|
157
|
+
* Whether a contract is allowed by a lifecycle. `crud:` and
|
|
158
|
+
* `persistence:` contracts map to their lifecycle flag (`crud:create` ⇔
|
|
159
|
+
* `lifecycle.create === true`, etc. — unknown operations in either
|
|
160
|
+
* namespace are a policy-authoring error); every other contract passes
|
|
161
|
+
* through ungated.
|
|
162
|
+
*
|
|
163
|
+
* Args:
|
|
164
|
+
* contract: the required contract name, e.g. `crud:update`.
|
|
165
|
+
* lifecycle: the classification's lifecycle flags.
|
|
166
|
+
*
|
|
167
|
+
* Returns:
|
|
168
|
+
* boolean: true when an obligation for this contract must be generated.
|
|
169
|
+
* @throws PolicyEvaluationError for `crud:`/`persistence:` contracts
|
|
170
|
+
* outside the four lifecycle operations.
|
|
171
|
+
*/
|
|
172
|
+
export function lifecycleAllowsContract(contract, lifecycle) {
|
|
173
|
+
for (const prefix of [CRUD_CONTRACT_PREFIX, PERSISTENCE_CONTRACT_PREFIX]) {
|
|
174
|
+
if (!contract.startsWith(prefix))
|
|
175
|
+
continue;
|
|
176
|
+
const operation = contract.slice(prefix.length);
|
|
177
|
+
if (!CRUD_OPERATIONS.includes(operation)) {
|
|
178
|
+
throw new PolicyEvaluationError(`policy requires '${contract}' but the namespace is limited to: ` +
|
|
179
|
+
`${CRUD_OPERATIONS.map((op) => `${prefix}${op}`).join(', ')}`);
|
|
180
|
+
}
|
|
181
|
+
return lifecycle[operation] === true;
|
|
182
|
+
}
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Evaluates the policy document against a built resource graph.
|
|
187
|
+
*
|
|
188
|
+
* Args:
|
|
189
|
+
* input: graph + policies (+ claims to assess). The policy document
|
|
190
|
+
* is validated fail-closed; resources are consumed in the graph's
|
|
191
|
+
* deterministic order.
|
|
192
|
+
*
|
|
193
|
+
* Returns:
|
|
194
|
+
* PolicyEvaluationResult: obligations, blocking entries, and claim
|
|
195
|
+
* assessments — all sorted, byte-for-byte deterministic.
|
|
196
|
+
* @throws z.ZodError when the policy document is invalid (config error).
|
|
197
|
+
* @throws PolicyEvaluationError for `crud:` contracts outside the four
|
|
198
|
+
* lifecycle operations.
|
|
199
|
+
*/
|
|
200
|
+
export function evaluatePolicies(input) {
|
|
201
|
+
const policyFile = PolicyFileSchema.parse(input.policies);
|
|
202
|
+
const obligations = [];
|
|
203
|
+
const obligationIds = new Set();
|
|
204
|
+
const blocking = [];
|
|
205
|
+
for (const resource of input.graph.resources) {
|
|
206
|
+
if (resource.classification === null) {
|
|
207
|
+
blocking.push({
|
|
208
|
+
kind: 'unclassified',
|
|
209
|
+
resourceId: resource.id,
|
|
210
|
+
name: resource.name,
|
|
211
|
+
detail: `resource '${resource.id ?? resource.name}' has no effective classification ` +
|
|
212
|
+
'(the classifier blocked it definitionally); run ' +
|
|
213
|
+
`'gateforge explain ${resource.id ?? resource.name}' for the typed ` +
|
|
214
|
+
'reason and its in-code resolution',
|
|
215
|
+
location: resource.location,
|
|
216
|
+
});
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
generateObligations(resource, policyFile.policies, obligations, obligationIds);
|
|
220
|
+
}
|
|
221
|
+
for (const entry of input.graph.unresolved) {
|
|
222
|
+
blocking.push({
|
|
223
|
+
kind: 'unresolved',
|
|
224
|
+
resourceId: null,
|
|
225
|
+
name: null,
|
|
226
|
+
detail: `${entry.reason.code}: ${entry.reason.detail}`,
|
|
227
|
+
location: entry.reason.location,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
// Fail closed on partial discovery: findings (PARSE_ERROR and friends)
|
|
231
|
+
// mean the graph was built from incomplete knowledge — a parse failure
|
|
232
|
+
// can erase resources and obligations — and stale references mean an
|
|
233
|
+
// artifact still points at something removed (invariant 9). Both block
|
|
234
|
+
// the gate; `discover` remains the non-gating introspection surface.
|
|
235
|
+
for (const finding of input.graph.findings) {
|
|
236
|
+
blocking.push({
|
|
237
|
+
kind: 'finding',
|
|
238
|
+
resourceId: null,
|
|
239
|
+
name: null,
|
|
240
|
+
detail: `${finding.code}: ${finding.detail} (detector ${finding.detectorId})`,
|
|
241
|
+
location: finding.locations[0] ?? null,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
for (const stale of input.graph.stale) {
|
|
245
|
+
blocking.push({
|
|
246
|
+
kind: 'stale-reference',
|
|
247
|
+
resourceId: null,
|
|
248
|
+
name: null,
|
|
249
|
+
detail: `stale ${stale.kind} reference '${stale.reference}': ${stale.detail}`,
|
|
250
|
+
location: null,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
blocking.push(...(input.extraBlocking ?? []));
|
|
254
|
+
const claims = assessClaims(input.claims ?? [], obligationIds, input.graph.resources);
|
|
255
|
+
return {
|
|
256
|
+
schemaVersion: 1,
|
|
257
|
+
obligations: sortObligations(obligations),
|
|
258
|
+
blocking: sortBlocking(blocking),
|
|
259
|
+
claims: sortClaims(claims),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Generates obligations for one classified resource: every matching
|
|
264
|
+
* policy's required contract that the lifecycle allows, deduplicated
|
|
265
|
+
* by obligation id (first matching policy owns the id).
|
|
266
|
+
*/
|
|
267
|
+
function generateObligations(resource, policies, obligations, obligationIds) {
|
|
268
|
+
const classification = resource.classification;
|
|
269
|
+
if (classification === null || resource.id === null)
|
|
270
|
+
return;
|
|
271
|
+
const exposure = classification.exposure;
|
|
272
|
+
for (const policy of policies) {
|
|
273
|
+
if (!policyMatches(policy, resource, exposure))
|
|
274
|
+
continue;
|
|
275
|
+
for (const contract of policy.require) {
|
|
276
|
+
if (contract.startsWith(CRUD_CONTRACT_PREFIX) ||
|
|
277
|
+
contract.startsWith(PERSISTENCE_CONTRACT_PREFIX)) {
|
|
278
|
+
if (exposure === 'internal')
|
|
279
|
+
continue; // ADR 0001: internal ⇒ no CRUD obligations
|
|
280
|
+
// ADR 0004 D8: endpoints are routes, not tables. CRUD state
|
|
281
|
+
// obligations flow through the LINKED business resource's own
|
|
282
|
+
// identity; generating persistence contracts against a route
|
|
283
|
+
// would conflate the two planes of meaning.
|
|
284
|
+
if (resource.kind === HTTP_ENDPOINT_RESOURCE_KIND)
|
|
285
|
+
continue;
|
|
286
|
+
if (!lifecycleAllowsContract(contract, classification.lifecycle))
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
const id = `${resource.id}:${contract}`;
|
|
290
|
+
if (obligationIds.has(id))
|
|
291
|
+
continue;
|
|
292
|
+
obligationIds.add(id);
|
|
293
|
+
obligations.push({
|
|
294
|
+
schemaVersion: 1,
|
|
295
|
+
id,
|
|
296
|
+
resourceId: resource.id,
|
|
297
|
+
contract,
|
|
298
|
+
policyId: policy.id,
|
|
299
|
+
lifecycle: classification.lifecycle,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
function policyMatches(policy, resource, exposure) {
|
|
305
|
+
const when = policy.when;
|
|
306
|
+
if (when.kind !== undefined && when.kind !== resource.kind)
|
|
307
|
+
return false;
|
|
308
|
+
if (when.exposure !== undefined && when.exposure !== exposure)
|
|
309
|
+
return false;
|
|
310
|
+
if (when.plane !== undefined && when.plane !== resource.plane)
|
|
311
|
+
return false;
|
|
312
|
+
if (when.capability !== undefined) {
|
|
313
|
+
// Endpoint capability match: the resource must carry a `capabilities`
|
|
314
|
+
// ARRAY containing the exact string. Anything else — absent
|
|
315
|
+
// attribute, non-array value, near-miss strings — never matches
|
|
316
|
+
// (fail closed).
|
|
317
|
+
const capabilities = resource.attributes['capabilities'];
|
|
318
|
+
if (!Array.isArray(capabilities) ||
|
|
319
|
+
!capabilities.some((capability) => capability === when.capability)) {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (when.consumed !== undefined) {
|
|
324
|
+
// Endpoint consumption match: `true` requires the attribute to be
|
|
325
|
+
// EXACTLY true; `false` matches everything else (including absent —
|
|
326
|
+
// non-endpoint resources are "not consumed", never match-excluded).
|
|
327
|
+
if (when.consumed === true && resource.attributes['frontendConsumed'] !== true) {
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
if (when.consumed === false && resource.attributes['frontendConsumed'] === true) {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Assesses claims against the generated obligation set. Claims on
|
|
338
|
+
* internal resources are invalid outright (ADR 0001 — internal
|
|
339
|
+
* resources carry no CRUD obligations and never accept claims);
|
|
340
|
+
* claims whose obligation id was not generated are invalid as unknown;
|
|
341
|
+
* the rest are valid linkages (validity ≠ satisfaction — pin #9).
|
|
342
|
+
*/
|
|
343
|
+
function assessClaims(claims, obligationIds, resources) {
|
|
344
|
+
const internalIds = new Set();
|
|
345
|
+
for (const resource of resources) {
|
|
346
|
+
if (resource.id !== null && resource.classification?.exposure === 'internal') {
|
|
347
|
+
internalIds.add(resource.id);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return claims.map((claim) => {
|
|
351
|
+
const resourceId = claim.obligationId.slice(0, claim.obligationId.indexOf(':'));
|
|
352
|
+
if (internalIds.has(resourceId)) {
|
|
353
|
+
return {
|
|
354
|
+
claim,
|
|
355
|
+
status: 'invalid',
|
|
356
|
+
reason: `resource '${resourceId}' is internal: internal resources carry no CRUD obligations and their claims are invalid (ADR 0001)`,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
if (!obligationIds.has(claim.obligationId)) {
|
|
360
|
+
return {
|
|
361
|
+
claim,
|
|
362
|
+
status: 'invalid',
|
|
363
|
+
reason: `claim references '${claim.obligationId}' which no policy generates`,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
return { claim, status: 'valid', reason: null };
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
function sortObligations(obligations) {
|
|
370
|
+
return [...obligations].sort((a, b) => compareStrings(a.id, b.id));
|
|
371
|
+
}
|
|
372
|
+
function sortBlocking(blocking) {
|
|
373
|
+
return [...blocking].sort((a, b) => compareStrings(a.kind, b.kind) ||
|
|
374
|
+
compareStrings(a.resourceId ?? '', b.resourceId ?? '') ||
|
|
375
|
+
compareStrings(a.name ?? '', b.name ?? '') ||
|
|
376
|
+
compareStrings(a.detail, b.detail));
|
|
377
|
+
}
|
|
378
|
+
function sortClaims(claims) {
|
|
379
|
+
return [...claims].sort((a, b) => compareStrings(a.claim.obligationId, b.claim.obligationId) ||
|
|
380
|
+
compareStrings(a.claim.testId, b.claim.testId));
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=evaluate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../src/policy/evaluate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy engine (G2): declarative policies → obligations, lifecycle
|
|
3
|
+
* gating (plan §5.2), internal-resource claim invalidation (ADR 0001),
|
|
4
|
+
* and gate-visible blocking entries for unclassified/unresolved
|
|
5
|
+
* resources (invariants 1, 8).
|
|
6
|
+
*
|
|
7
|
+
* Also (plan 2026-09-13 Phase 0): the closed-world CRUD coverage
|
|
8
|
+
* evaluator (§3.6) and the protected-policy-ownership foundation
|
|
9
|
+
* (trusted policy digest + weakening check, ADR 0005 D5/D6).
|
|
10
|
+
*/
|
|
11
|
+
export { CRUD_CONTRACT_PREFIX, PERSISTENCE_CONTRACT_PREFIX, BlockingEntrySchema, ClaimAssessmentSchema, PolicyEvaluationError, PolicyEvaluationResultSchema, classificationBlockedIdentity, evaluatePolicies, lifecycleAllowsContract, } from './evaluate.js';
|
|
12
|
+
export type { BlockingEntry, ClaimAssessment, PolicyEvaluationInput, PolicyEvaluationResult, } from './evaluate.js';
|
|
13
|
+
export { evaluateCoveragePolicy, type CoverageInventoryTable, type MappedCoverage, type CoverageConfigError, type CoverageBlockingFinding, type CoveragePolicyResult, } from './coverage.js';
|
|
14
|
+
export { TRUSTED_POLICY_DOMAIN, trustedPolicyDigest, policyWeakenedCandidate, type TrustedPolicyInput, type PolicyWeakeningCheck, } from './trusted.js';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,4BAA4B,EAC5B,6BAA6B,EAC7B,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy engine (G2): declarative policies → obligations, lifecycle
|
|
3
|
+
* gating (plan §5.2), internal-resource claim invalidation (ADR 0001),
|
|
4
|
+
* and gate-visible blocking entries for unclassified/unresolved
|
|
5
|
+
* resources (invariants 1, 8).
|
|
6
|
+
*
|
|
7
|
+
* Also (plan 2026-09-13 Phase 0): the closed-world CRUD coverage
|
|
8
|
+
* evaluator (§3.6) and the protected-policy-ownership foundation
|
|
9
|
+
* (trusted policy digest + weakening check, ADR 0005 D5/D6).
|
|
10
|
+
*/
|
|
11
|
+
export { CRUD_CONTRACT_PREFIX, PERSISTENCE_CONTRACT_PREFIX, BlockingEntrySchema, ClaimAssessmentSchema, PolicyEvaluationError, PolicyEvaluationResultSchema, classificationBlockedIdentity, evaluatePolicies, lifecycleAllowsContract, } from './evaluate.js';
|
|
12
|
+
export { evaluateCoveragePolicy, } from './coverage.js';
|
|
13
|
+
export { TRUSTED_POLICY_DOMAIN, trustedPolicyDigest, policyWeakenedCandidate, } from './trusted.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,4BAA4B,EAC5B,6BAA6B,EAC7B,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAOvB,OAAO,EACL,sBAAsB,GAMvB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,GAGxB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** Domain tag separating trusted-policy digests from every other hash. */
|
|
2
|
+
export declare const TRUSTED_POLICY_DOMAIN = "gateforge.trusted-policy.v1";
|
|
3
|
+
/** One trusted policy/config document's effective bytes. */
|
|
4
|
+
export interface TrustedPolicyInput {
|
|
5
|
+
/** Stable repo-root-relative name, e.g. `.gateforge/policies.yml`. */
|
|
6
|
+
name: string;
|
|
7
|
+
/** The exact effective bytes of the document. */
|
|
8
|
+
bytes: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Computes the trusted policy digest: a domain-separated canonical hash
|
|
12
|
+
* over the named document bytes (each byte-hashed, entries sorted by
|
|
13
|
+
* name). Deterministic — identical policy revisions produce identical
|
|
14
|
+
* digests, so a receipt can bind "evaluated under this policy revision"
|
|
15
|
+
* and any later byte change breaks the binding.
|
|
16
|
+
*
|
|
17
|
+
* Args:
|
|
18
|
+
* inputs: the effective policy/config documents (config, policies,
|
|
19
|
+
* classification policy, adapters, baselines, waivers, runner
|
|
20
|
+
* definitions — the trusted-revision-owned set).
|
|
21
|
+
*
|
|
22
|
+
* Returns:
|
|
23
|
+
* string: 64-char lowercase hex digest.
|
|
24
|
+
*
|
|
25
|
+
* Throws:
|
|
26
|
+
* TypeError: when the same name appears twice (an ambiguous trusted
|
|
27
|
+
* revision is a caller bug, never silently deduplicated).
|
|
28
|
+
*/
|
|
29
|
+
export declare function trustedPolicyDigest(inputs: readonly TrustedPolicyInput[]): string;
|
|
30
|
+
/** The typed outcome of comparing a candidate revision to the trusted one. */
|
|
31
|
+
export type PolicyWeakeningCheck = {
|
|
32
|
+
weakened: false;
|
|
33
|
+
trustedDigest: string;
|
|
34
|
+
candidateDigest: string;
|
|
35
|
+
} | {
|
|
36
|
+
/** True when the candidate is not byte-identical to the trusted revision. */
|
|
37
|
+
weakened: true;
|
|
38
|
+
/** Single-cause fail-closed explanation. */
|
|
39
|
+
reason: string;
|
|
40
|
+
trustedDigest: string;
|
|
41
|
+
candidateDigest: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* The pure weakening check (ADR 0005 D6): a candidate whose policy digest
|
|
45
|
+
* differs from the trusted revision is a WEAKENING CANDIDATE — it may
|
|
46
|
+
* only proceed after a separate trusted update is accepted, never by
|
|
47
|
+
* self-approval. Fail-closed: a missing or malformed digest cannot be
|
|
48
|
+
* verified, so it counts as weakened rather than trusted.
|
|
49
|
+
*
|
|
50
|
+
* Args:
|
|
51
|
+
* trustedDigest: the digest of the trusted policy revision.
|
|
52
|
+
* candidateDigest: the digest of the candidate's effective policy.
|
|
53
|
+
*
|
|
54
|
+
* Returns:
|
|
55
|
+
* PolicyWeakeningCheck: `{weakened: false}` only for an exact, well-formed
|
|
56
|
+
* match; otherwise `{weakened: true, reason}` naming the failure.
|
|
57
|
+
*/
|
|
58
|
+
export declare function policyWeakenedCandidate(trustedDigest: string, candidateDigest: string): PolicyWeakeningCheck;
|
|
59
|
+
//# sourceMappingURL=trusted.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trusted.d.ts","sourceRoot":"","sources":["../../src/policy/trusted.ts"],"names":[],"mappings":"AAiBA,0EAA0E;AAC1E,eAAO,MAAM,qBAAqB,gCAAgC,CAAC;AAEnE,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAYjF;AAED,8EAA8E;AAC9E,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GACnE;IACE,6EAA6E;IAC7E,QAAQ,EAAE,IAAI,CAAC;IACf,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAIN;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,GACtB,oBAAoB,CA6BtB"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protected policy ownership foundation (plan 2026-09-13 Phase 0 item 5,
|
|
3
|
+
* ADR 0005 D6). Classifiers, exclusions, mappings that suppress scope,
|
|
4
|
+
* adapters, runner definitions, gate binaries, CI jobs, baselines, and
|
|
5
|
+
* waivers are TRUSTED-REVISION-OWNED: a candidate change that edits them
|
|
6
|
+
* cannot authorize its own weaker checks. The engine therefore computes a
|
|
7
|
+
* domain-separated digest over the effective policy/config bytes and
|
|
8
|
+
* evaluates candidates against it.
|
|
9
|
+
*
|
|
10
|
+
* Phase 0 delivers the typed foundation only: the digest computation and
|
|
11
|
+
* the pure weakening check, both unit-testable. Receipt binding and real
|
|
12
|
+
* enforcement land in Phases 4-5 (plan §5.1 gate receipt: "trusted
|
|
13
|
+
* policy/verifier digest").
|
|
14
|
+
*/
|
|
15
|
+
import { sha256Canonical, sha256Hex } from '../canonical-json.js';
|
|
16
|
+
import { compareStrings } from '../graph/util.js';
|
|
17
|
+
/** Domain tag separating trusted-policy digests from every other hash. */
|
|
18
|
+
export const TRUSTED_POLICY_DOMAIN = 'gateforge.trusted-policy.v1';
|
|
19
|
+
/**
|
|
20
|
+
* Computes the trusted policy digest: a domain-separated canonical hash
|
|
21
|
+
* over the named document bytes (each byte-hashed, entries sorted by
|
|
22
|
+
* name). Deterministic — identical policy revisions produce identical
|
|
23
|
+
* digests, so a receipt can bind "evaluated under this policy revision"
|
|
24
|
+
* and any later byte change breaks the binding.
|
|
25
|
+
*
|
|
26
|
+
* Args:
|
|
27
|
+
* inputs: the effective policy/config documents (config, policies,
|
|
28
|
+
* classification policy, adapters, baselines, waivers, runner
|
|
29
|
+
* definitions — the trusted-revision-owned set).
|
|
30
|
+
*
|
|
31
|
+
* Returns:
|
|
32
|
+
* string: 64-char lowercase hex digest.
|
|
33
|
+
*
|
|
34
|
+
* Throws:
|
|
35
|
+
* TypeError: when the same name appears twice (an ambiguous trusted
|
|
36
|
+
* revision is a caller bug, never silently deduplicated).
|
|
37
|
+
*/
|
|
38
|
+
export function trustedPolicyDigest(inputs) {
|
|
39
|
+
const seen = new Set();
|
|
40
|
+
for (const input of inputs) {
|
|
41
|
+
if (seen.has(input.name)) {
|
|
42
|
+
throw new TypeError(`trustedPolicyDigest: duplicate policy input name '${input.name}'`);
|
|
43
|
+
}
|
|
44
|
+
seen.add(input.name);
|
|
45
|
+
}
|
|
46
|
+
const files = [...inputs]
|
|
47
|
+
.sort((a, b) => compareStrings(a.name, b.name))
|
|
48
|
+
.map((input) => ({ name: input.name, sha256: sha256Hex(input.bytes) }));
|
|
49
|
+
return sha256Canonical({ domain: TRUSTED_POLICY_DOMAIN, files });
|
|
50
|
+
}
|
|
51
|
+
const DIGEST_PATTERN = /^[0-9a-f]{64}$/;
|
|
52
|
+
/**
|
|
53
|
+
* The pure weakening check (ADR 0005 D6): a candidate whose policy digest
|
|
54
|
+
* differs from the trusted revision is a WEAKENING CANDIDATE — it may
|
|
55
|
+
* only proceed after a separate trusted update is accepted, never by
|
|
56
|
+
* self-approval. Fail-closed: a missing or malformed digest cannot be
|
|
57
|
+
* verified, so it counts as weakened rather than trusted.
|
|
58
|
+
*
|
|
59
|
+
* Args:
|
|
60
|
+
* trustedDigest: the digest of the trusted policy revision.
|
|
61
|
+
* candidateDigest: the digest of the candidate's effective policy.
|
|
62
|
+
*
|
|
63
|
+
* Returns:
|
|
64
|
+
* PolicyWeakeningCheck: `{weakened: false}` only for an exact, well-formed
|
|
65
|
+
* match; otherwise `{weakened: true, reason}` naming the failure.
|
|
66
|
+
*/
|
|
67
|
+
export function policyWeakenedCandidate(trustedDigest, candidateDigest) {
|
|
68
|
+
if (!DIGEST_PATTERN.test(trustedDigest)) {
|
|
69
|
+
return {
|
|
70
|
+
weakened: true,
|
|
71
|
+
reason: `trusted policy digest is missing or malformed ('${trustedDigest}'); a candidate cannot be trusted against an unverifiable revision (fail closed)`,
|
|
72
|
+
trustedDigest,
|
|
73
|
+
candidateDigest,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (!DIGEST_PATTERN.test(candidateDigest)) {
|
|
77
|
+
return {
|
|
78
|
+
weakened: true,
|
|
79
|
+
reason: `candidate policy digest is missing or malformed ('${candidateDigest}'); the candidate's effective policy cannot be verified (fail closed)`,
|
|
80
|
+
trustedDigest,
|
|
81
|
+
candidateDigest,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
if (trustedDigest !== candidateDigest) {
|
|
85
|
+
return {
|
|
86
|
+
weakened: true,
|
|
87
|
+
reason: 'candidate policy digest differs from the trusted policy revision: candidate edits to ' +
|
|
88
|
+
'classifiers, exclusions, scope-suppressing mappings, adapters, runner definitions, ' +
|
|
89
|
+
'baselines, or waivers cannot authorize their own weaker checks (a trusted update is required)',
|
|
90
|
+
trustedDigest,
|
|
91
|
+
candidateDigest,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return { weakened: false, trustedDigest, candidateDigest };
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=trusted.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trusted.js","sourceRoot":"","sources":["../../src/policy/trusted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,0EAA0E;AAC1E,MAAM,CAAC,MAAM,qBAAqB,GAAG,6BAA6B,CAAC;AAUnE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAqC;IACvE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,SAAS,CAAC,qDAAqD,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;QAC1F,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC;SACtB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;SAC9C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1E,OAAO,eAAe,CAAC,EAAE,MAAM,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC;AACnE,CAAC;AAcD,MAAM,cAAc,GAAG,gBAAgB,CAAC;AAExC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,uBAAuB,CACrC,aAAqB,EACrB,eAAuB;IAEvB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QACxC,OAAO;YACL,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,mDAAmD,aAAa,kFAAkF;YAC1J,aAAa;YACb,eAAe;SAChB,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC;QAC1C,OAAO;YACL,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,qDAAqD,eAAe,uEAAuE;YACnJ,aAAa;YACb,eAAe;SAChB,CAAC;IACJ,CAAC;IACD,IAAI,aAAa,KAAK,eAAe,EAAE,CAAC;QACtC,OAAO;YACL,QAAQ,EAAE,IAAI;YACd,MAAM,EACJ,uFAAuF;gBACvF,qFAAqF;gBACrF,+FAA+F;YACjG,aAAa;YACb,eAAe;SAChB,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,CAAC;AAC7D,CAAC"}
|