@atlasent/safeguard-manifest 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # @atlasent/safeguard-manifest
2
+
3
+ Versioned, deterministic projection of the **authoritative safeguard package**
4
+ (`contract/safeguard-pack/`) into the **design / EXPECTED facts** a consumer needs
5
+ to render the console **SafeguardMap** — per protected action: owner, authority,
6
+ expected evidence sources, and expected gates.
7
+
8
+ ## What this is (and is NOT)
9
+
10
+ - **IS:** expected/design truth. What each safeguard is *designed to require*.
11
+ - **IS NOT:** runtime observed state. It carries **no** enforcement mode in
12
+ effect, verification status, coverage, or observed gaps. Those stay live in the
13
+ runtime and are joined by the consumer.
14
+
15
+ The manifest exists so the console never hand-maintains a semantic copy that can
16
+ drift from the Canon / package. This is the single authoritative feed.
17
+
18
+ ## The three states it enables
19
+
20
+ The consumer joins this manifest with live runtime facts to produce a
21
+ reconciliation view over three distinct states:
22
+
23
+ | State | Source |
24
+ |---|---|
25
+ | **Expected** | this manifest (versioned safeguard package) |
26
+ | **Configured** | runtime — current configuration (enforcement mode, bound bundle) |
27
+ | **Proven** | runtime — execution + verification evidence (verification_events, coverage) |
28
+
29
+ A safeguard is **not "covered"** merely because it is in the package (Expected) or
30
+ configured in runtime (Configured) — coverage requires observed runtime + acceptance
31
+ evidence (Proven). Where Expected and Configured/Proven disagree, the consumer
32
+ displays the discrepancy as a **gap**; it must not reconcile or reinterpret it.
33
+
34
+ ## Regeneration & determinism
35
+
36
+ The JSON is generated by `scripts/generate-safeguard-manifest.py` (in the repo
37
+ root) from the authoritative YAML. It is **deterministic** — same inputs produce
38
+ byte-identical output, so CI fails on any unexpected regeneration diff:
39
+
40
+ ```bash
41
+ python3 scripts/generate-safeguard-manifest.py # regenerate
42
+ python3 scripts/generate-safeguard-manifest.py --check # CI: fail if stale
43
+ ```
44
+
45
+ **Do not hand-edit `safeguard-manifest.json`.** Change the authoritative
46
+ `contract/safeguard-pack/*` YAML and regenerate.
47
+
48
+ ## Provenance
49
+
50
+ - `provenance.source_files[]` records the SHA-256 of each authoritative input —
51
+ identifying the exact inputs deterministically (no volatile git SHA / timestamp
52
+ in the artifact, so `--check` stays stable).
53
+ - Release/commit provenance is bound **at publish time** via npm `--provenance`
54
+ (Sigstore keyless, same trust model as the other AtlaSent published packages).
55
+
56
+ ## Distribution & pinning
57
+
58
+ Published through the existing packages release path (`v1_1-release.yml` packs +
59
+ cosign-signs every non-private `packages/*` on a version tag). **Consumers pin an
60
+ explicit `manifest_version` / package version** — never silently consume "latest"
61
+ — and validate the manifest against `safeguard-manifest.schema.json`
62
+ (`schema_version` + provenance) before use.
63
+
64
+ ## Usage
65
+
66
+ ```ts
67
+ import {
68
+ safeguardManifest,
69
+ getSafeguardAction,
70
+ SAFEGUARD_MANIFEST_VERSION,
71
+ } from "@atlasent/safeguard-manifest";
72
+
73
+ const deploy = getSafeguardAction("production.deploy");
74
+ deploy?.owner_role; // expected owner (design)
75
+ deploy?.expected_evidence_sources; // expected evidence sources (design)
76
+ ```
package/index.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ // Type declarations for @atlasent/safeguard-manifest (zero-build package).
2
+ // The manifest carries DESIGN / EXPECTED facts only — no runtime observed state.
3
+
4
+ export interface SafeguardEvidenceSource {
5
+ capability_id: string;
6
+ tools: string[];
7
+ /** Human safeguard label (only present for actions with a product safeguard-map). */
8
+ safeguard?: string;
9
+ source?: string;
10
+ }
11
+
12
+ export interface SafeguardGateSatisfier {
13
+ capability_id: string;
14
+ via_tools: string[];
15
+ }
16
+
17
+ export interface SafeguardExpectedGate {
18
+ gate: string;
19
+ required_assertion_class?: string;
20
+ satisfied_by: SafeguardGateSatisfier[];
21
+ }
22
+
23
+ export interface SafeguardAction {
24
+ id: string;
25
+ business_action: string | null;
26
+ slug: string;
27
+ canon_id: string | null;
28
+ act_id: string | null;
29
+ risk_posture: string | null;
30
+ /** DESIGN facts — the owner/authority the safeguard is designed to require. */
31
+ owner_role: string | null;
32
+ owner_display_name: string | null;
33
+ owner_maps_to_org_role: string | null;
34
+ approver_role: string | null;
35
+ /** Recommended STARTING enforcement mode — a design recommendation, NOT the runtime's observed mode. */
36
+ recommended_lifecycle: string | null;
37
+ expected_gates: SafeguardExpectedGate[];
38
+ expected_evidence_sources: SafeguardEvidenceSource[];
39
+ }
40
+
41
+ export interface SafeguardManifestProvenance {
42
+ source_repo: string;
43
+ source_files: Array<{ path: string; sha256: string }>;
44
+ }
45
+
46
+ export interface SafeguardManifest {
47
+ schema_version: string;
48
+ manifest_version: string;
49
+ kind: "safeguard-manifest";
50
+ generated_by?: string;
51
+ notice?: string;
52
+ provenance: SafeguardManifestProvenance;
53
+ actions: SafeguardAction[];
54
+ }
55
+
56
+ export declare const safeguardManifest: SafeguardManifest;
57
+ export declare const SAFEGUARD_MANIFEST_SCHEMA_VERSION: string;
58
+ export declare const SAFEGUARD_MANIFEST_VERSION: string;
59
+ export declare function getSafeguardAction(idOrSlug: string): SafeguardAction | undefined;
60
+ declare const _default: SafeguardManifest;
61
+ export default _default;
package/index.js ADDED
@@ -0,0 +1,28 @@
1
+ // @atlasent/safeguard-manifest — zero-build entry.
2
+ //
3
+ // The manifest JSON is GENERATED by scripts/generate-safeguard-manifest.py from
4
+ // contract/safeguard-pack/*. This module is a thin, dependency-free re-export so
5
+ // consumers get typed access (see index.d.ts) without a build step.
6
+ // Do not hand-edit safeguard-manifest.json — regenerate it.
7
+
8
+ "use strict";
9
+
10
+ const manifest = require("./safeguard-manifest.json");
11
+
12
+ /** The generated manifest. All values are design/EXPECTED facts. */
13
+ const safeguardManifest = manifest;
14
+
15
+ /** Look up a protected action's expected/design facts by SG-ACT id or slug. */
16
+ function getSafeguardAction(idOrSlug) {
17
+ return manifest.actions.find(function (a) {
18
+ return a.id === idOrSlug || a.slug === idOrSlug;
19
+ });
20
+ }
21
+
22
+ module.exports = {
23
+ safeguardManifest: safeguardManifest,
24
+ getSafeguardAction: getSafeguardAction,
25
+ SAFEGUARD_MANIFEST_SCHEMA_VERSION: manifest.schema_version,
26
+ SAFEGUARD_MANIFEST_VERSION: manifest.manifest_version,
27
+ default: safeguardManifest,
28
+ };
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@atlasent/safeguard-manifest",
3
+ "version": "1.0.0",
4
+ "description": "Versioned, deterministic projection of the authoritative AtlaSent safeguard package into the design/EXPECTED facts (owner, authority, expected evidence sources, expected gates) for the console SafeguardMap. Carries no runtime observed state. Zero-build, zero-dependency. Regenerate via scripts/generate-safeguard-manifest.py; do not hand-edit.",
5
+ "main": "./index.js",
6
+ "types": "./index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./index.d.ts",
10
+ "default": "./index.js"
11
+ },
12
+ "./safeguard-manifest.json": "./safeguard-manifest.json",
13
+ "./schema": "./safeguard-manifest.schema.json"
14
+ },
15
+ "scripts": {
16
+ "generate": "python3 ../../scripts/generate-safeguard-manifest.py",
17
+ "check": "python3 ../../scripts/generate-safeguard-manifest.py --check"
18
+ },
19
+ "files": [
20
+ "index.js",
21
+ "index.d.ts",
22
+ "safeguard-manifest.json",
23
+ "safeguard-manifest.schema.json"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public",
27
+ "provenance": true
28
+ },
29
+ "license": "MIT"
30
+ }
@@ -0,0 +1,527 @@
1
+ {
2
+ "actions": [
3
+ {
4
+ "act_id": "ACT-0001",
5
+ "approver_role": "approver",
6
+ "business_action": "Production deployment",
7
+ "canon_id": "CANON-000001",
8
+ "expected_evidence_sources": [
9
+ {
10
+ "capability_id": "change_review.approved",
11
+ "safeguard": "Review",
12
+ "source": "GitHub",
13
+ "tools": [
14
+ "github"
15
+ ]
16
+ },
17
+ {
18
+ "capability_id": "change_request.approved",
19
+ "tools": [
20
+ "jira",
21
+ "servicenow"
22
+ ]
23
+ },
24
+ {
25
+ "capability_id": "state.snapshot_captured",
26
+ "safeguard": "Artifact identity",
27
+ "source": "build or registry",
28
+ "tools": [
29
+ "github-actions",
30
+ "terraform"
31
+ ]
32
+ }
33
+ ],
34
+ "expected_gates": [
35
+ {
36
+ "gate": "requires_human_approval",
37
+ "satisfied_by": [
38
+ {
39
+ "capability_id": "change_review.approved",
40
+ "via_tools": [
41
+ "github"
42
+ ]
43
+ },
44
+ {
45
+ "capability_id": "change_request.approved",
46
+ "via_tools": [
47
+ "jira",
48
+ "servicenow"
49
+ ]
50
+ }
51
+ ]
52
+ },
53
+ {
54
+ "gate": "requires_state_snapshot",
55
+ "satisfied_by": [
56
+ {
57
+ "capability_id": "state.snapshot_captured",
58
+ "via_tools": [
59
+ "github-actions",
60
+ "terraform"
61
+ ]
62
+ }
63
+ ]
64
+ }
65
+ ],
66
+ "id": "SG-ACT-001",
67
+ "owner_display_name": "Release Owner",
68
+ "owner_maps_to_org_role": "admin",
69
+ "owner_role": "release_owner",
70
+ "recommended_lifecycle": "shadow",
71
+ "risk_posture": "high",
72
+ "slug": "production.deploy"
73
+ },
74
+ {
75
+ "act_id": "ACT-0036",
76
+ "approver_role": "approver",
77
+ "business_action": "Infrastructure change",
78
+ "canon_id": "CANON-000033",
79
+ "expected_evidence_sources": [
80
+ {
81
+ "capability_id": "change_request.approved",
82
+ "tools": [
83
+ "jira",
84
+ "servicenow"
85
+ ]
86
+ },
87
+ {
88
+ "capability_id": "change_review.approved",
89
+ "tools": [
90
+ "github"
91
+ ]
92
+ },
93
+ {
94
+ "capability_id": "state.snapshot_captured",
95
+ "tools": [
96
+ "github-actions",
97
+ "terraform"
98
+ ]
99
+ }
100
+ ],
101
+ "expected_gates": [
102
+ {
103
+ "gate": "requires_human_approval",
104
+ "satisfied_by": [
105
+ {
106
+ "capability_id": "change_request.approved",
107
+ "via_tools": [
108
+ "jira",
109
+ "servicenow"
110
+ ]
111
+ },
112
+ {
113
+ "capability_id": "change_review.approved",
114
+ "via_tools": [
115
+ "github"
116
+ ]
117
+ }
118
+ ]
119
+ },
120
+ {
121
+ "gate": "requires_state_snapshot",
122
+ "satisfied_by": [
123
+ {
124
+ "capability_id": "state.snapshot_captured",
125
+ "via_tools": [
126
+ "github-actions",
127
+ "terraform"
128
+ ]
129
+ }
130
+ ]
131
+ }
132
+ ],
133
+ "id": "SG-ACT-002",
134
+ "owner_display_name": "Infrastructure Owner",
135
+ "owner_maps_to_org_role": "admin",
136
+ "owner_role": "infra_owner",
137
+ "recommended_lifecycle": "shadow",
138
+ "risk_posture": "high",
139
+ "slug": "infrastructure.change"
140
+ },
141
+ {
142
+ "act_id": "ACT-0035",
143
+ "approver_role": "approver",
144
+ "business_action": "Database migration",
145
+ "canon_id": "CANON-000032",
146
+ "expected_evidence_sources": [
147
+ {
148
+ "capability_id": "change_review.approved",
149
+ "tools": [
150
+ "github"
151
+ ]
152
+ },
153
+ {
154
+ "capability_id": "change_request.approved",
155
+ "tools": [
156
+ "jira",
157
+ "servicenow"
158
+ ]
159
+ },
160
+ {
161
+ "capability_id": "state.snapshot_captured",
162
+ "tools": [
163
+ "github-actions",
164
+ "terraform"
165
+ ]
166
+ }
167
+ ],
168
+ "expected_gates": [
169
+ {
170
+ "gate": "requires_human_approval",
171
+ "satisfied_by": [
172
+ {
173
+ "capability_id": "change_review.approved",
174
+ "via_tools": [
175
+ "github"
176
+ ]
177
+ },
178
+ {
179
+ "capability_id": "change_request.approved",
180
+ "via_tools": [
181
+ "jira",
182
+ "servicenow"
183
+ ]
184
+ }
185
+ ]
186
+ },
187
+ {
188
+ "gate": "requires_state_snapshot",
189
+ "satisfied_by": [
190
+ {
191
+ "capability_id": "state.snapshot_captured",
192
+ "via_tools": [
193
+ "github-actions",
194
+ "terraform"
195
+ ]
196
+ }
197
+ ]
198
+ }
199
+ ],
200
+ "id": "SG-ACT-003",
201
+ "owner_display_name": "Database Owner",
202
+ "owner_maps_to_org_role": "admin",
203
+ "owner_role": "dba_owner",
204
+ "recommended_lifecycle": "shadow",
205
+ "risk_posture": "high",
206
+ "slug": "database.migrate"
207
+ },
208
+ {
209
+ "act_id": "ACT-0032",
210
+ "approver_role": "approver",
211
+ "business_action": "Security-control exception",
212
+ "canon_id": "CANON-000029",
213
+ "expected_evidence_sources": [
214
+ {
215
+ "capability_id": "change_request.approved",
216
+ "tools": [
217
+ "jira",
218
+ "servicenow"
219
+ ]
220
+ },
221
+ {
222
+ "capability_id": "caller.mfa_satisfied",
223
+ "tools": [
224
+ "entra-id",
225
+ "okta"
226
+ ]
227
+ },
228
+ {
229
+ "capability_id": "caller.identity_verified",
230
+ "tools": [
231
+ "entra-id",
232
+ "okta"
233
+ ]
234
+ },
235
+ {
236
+ "capability_id": "state.snapshot_captured",
237
+ "tools": [
238
+ "generic-webhook",
239
+ "terraform"
240
+ ]
241
+ },
242
+ {
243
+ "capability_id": "caller.role_membership_asserted",
244
+ "tools": [
245
+ "entra-id",
246
+ "okta"
247
+ ]
248
+ },
249
+ {
250
+ "capability_id": "risk.assessment_recorded",
251
+ "tools": [
252
+ "generic-webhook",
253
+ "servicenow"
254
+ ]
255
+ }
256
+ ],
257
+ "expected_gates": [
258
+ {
259
+ "gate": "requires_human_approval",
260
+ "satisfied_by": [
261
+ {
262
+ "capability_id": "change_request.approved",
263
+ "via_tools": [
264
+ "jira",
265
+ "servicenow"
266
+ ]
267
+ }
268
+ ]
269
+ },
270
+ {
271
+ "gate": "requires_mfa",
272
+ "satisfied_by": [
273
+ {
274
+ "capability_id": "caller.mfa_satisfied",
275
+ "via_tools": [
276
+ "entra-id",
277
+ "okta"
278
+ ]
279
+ }
280
+ ]
281
+ },
282
+ {
283
+ "gate": "requires_verified_actor",
284
+ "satisfied_by": [
285
+ {
286
+ "capability_id": "caller.identity_verified",
287
+ "via_tools": [
288
+ "entra-id",
289
+ "okta"
290
+ ]
291
+ }
292
+ ]
293
+ },
294
+ {
295
+ "gate": "requires_state_snapshot",
296
+ "satisfied_by": [
297
+ {
298
+ "capability_id": "state.snapshot_captured",
299
+ "via_tools": [
300
+ "generic-webhook",
301
+ "terraform"
302
+ ]
303
+ }
304
+ ]
305
+ },
306
+ {
307
+ "gate": "required_assertion_classes",
308
+ "required_assertion_class": "identity",
309
+ "satisfied_by": [
310
+ {
311
+ "capability_id": "caller.identity_verified",
312
+ "via_tools": [
313
+ "entra-id",
314
+ "okta"
315
+ ]
316
+ },
317
+ {
318
+ "capability_id": "caller.role_membership_asserted",
319
+ "via_tools": [
320
+ "entra-id",
321
+ "okta"
322
+ ]
323
+ }
324
+ ]
325
+ },
326
+ {
327
+ "gate": "required_assertion_classes",
328
+ "required_assertion_class": "risk",
329
+ "satisfied_by": [
330
+ {
331
+ "capability_id": "risk.assessment_recorded",
332
+ "via_tools": [
333
+ "generic-webhook",
334
+ "servicenow"
335
+ ]
336
+ }
337
+ ]
338
+ }
339
+ ],
340
+ "id": "SG-ACT-004",
341
+ "owner_display_name": "Security Owner",
342
+ "owner_maps_to_org_role": "owner",
343
+ "owner_role": "security_owner",
344
+ "recommended_lifecycle": "shadow",
345
+ "risk_posture": "critical",
346
+ "slug": "security.breakglass"
347
+ },
348
+ {
349
+ "act_id": "ACT-0031",
350
+ "approver_role": "approver",
351
+ "business_action": "Customer-production-data access",
352
+ "canon_id": "CANON-000028",
353
+ "expected_evidence_sources": [
354
+ {
355
+ "capability_id": "change_request.approved",
356
+ "tools": [
357
+ "jira",
358
+ "servicenow"
359
+ ]
360
+ },
361
+ {
362
+ "capability_id": "change_review.approved",
363
+ "tools": [
364
+ "github"
365
+ ]
366
+ },
367
+ {
368
+ "capability_id": "consent.obtained",
369
+ "tools": [
370
+ "generic-webhook"
371
+ ]
372
+ },
373
+ {
374
+ "capability_id": "data.residency_asserted",
375
+ "tools": [
376
+ "aws",
377
+ "generic-webhook"
378
+ ]
379
+ }
380
+ ],
381
+ "expected_gates": [
382
+ {
383
+ "gate": "requires_human_approval",
384
+ "satisfied_by": [
385
+ {
386
+ "capability_id": "change_request.approved",
387
+ "via_tools": [
388
+ "jira",
389
+ "servicenow"
390
+ ]
391
+ },
392
+ {
393
+ "capability_id": "change_review.approved",
394
+ "via_tools": [
395
+ "github"
396
+ ]
397
+ }
398
+ ]
399
+ },
400
+ {
401
+ "gate": "required_assertion_classes",
402
+ "required_assertion_class": "consent",
403
+ "satisfied_by": [
404
+ {
405
+ "capability_id": "consent.obtained",
406
+ "via_tools": [
407
+ "generic-webhook"
408
+ ]
409
+ }
410
+ ]
411
+ },
412
+ {
413
+ "gate": "required_assertion_classes",
414
+ "required_assertion_class": "residency",
415
+ "satisfied_by": [
416
+ {
417
+ "capability_id": "data.residency_asserted",
418
+ "via_tools": [
419
+ "aws",
420
+ "generic-webhook"
421
+ ]
422
+ }
423
+ ]
424
+ }
425
+ ],
426
+ "id": "SG-ACT-005",
427
+ "owner_display_name": "Data Owner",
428
+ "owner_maps_to_org_role": "admin",
429
+ "owner_role": "data_owner",
430
+ "recommended_lifecycle": "shadow",
431
+ "risk_posture": "high",
432
+ "slug": "data.export"
433
+ },
434
+ {
435
+ "act_id": "ACT-0029",
436
+ "approver_role": "approver",
437
+ "business_action": "AI-agent production action",
438
+ "canon_id": "CANON-000026",
439
+ "expected_evidence_sources": [
440
+ {
441
+ "capability_id": "caller.identity_verified",
442
+ "tools": [
443
+ "generic-webhook",
444
+ "github-actions",
445
+ "okta"
446
+ ]
447
+ },
448
+ {
449
+ "capability_id": "risk.assessment_recorded",
450
+ "tools": [
451
+ "generic-webhook"
452
+ ]
453
+ }
454
+ ],
455
+ "expected_gates": [
456
+ {
457
+ "gate": "requires_verified_actor",
458
+ "satisfied_by": [
459
+ {
460
+ "capability_id": "caller.identity_verified",
461
+ "via_tools": [
462
+ "generic-webhook",
463
+ "github-actions",
464
+ "okta"
465
+ ]
466
+ }
467
+ ]
468
+ },
469
+ {
470
+ "gate": "required_assertion_classes",
471
+ "required_assertion_class": "identity",
472
+ "satisfied_by": [
473
+ {
474
+ "capability_id": "caller.identity_verified",
475
+ "via_tools": [
476
+ "generic-webhook",
477
+ "github-actions",
478
+ "okta"
479
+ ]
480
+ }
481
+ ]
482
+ },
483
+ {
484
+ "gate": "required_assertion_classes",
485
+ "required_assertion_class": "risk",
486
+ "satisfied_by": [
487
+ {
488
+ "capability_id": "risk.assessment_recorded",
489
+ "via_tools": [
490
+ "generic-webhook"
491
+ ]
492
+ }
493
+ ]
494
+ }
495
+ ],
496
+ "id": "SG-ACT-006",
497
+ "owner_display_name": "Agent Owner",
498
+ "owner_maps_to_org_role": "admin",
499
+ "owner_role": "agent_owner",
500
+ "recommended_lifecycle": "shadow",
501
+ "risk_posture": "high",
502
+ "slug": "agent.tool.invoke"
503
+ }
504
+ ],
505
+ "generated_by": "scripts/generate-safeguard-manifest.py",
506
+ "kind": "safeguard-manifest",
507
+ "manifest_version": "1.0.0",
508
+ "notice": "DESIGN/EXPECTED facts only \u2014 no runtime observed state. Deterministic; do not hand-edit.",
509
+ "provenance": {
510
+ "source_files": [
511
+ {
512
+ "path": "contract/safeguard-pack/authority/authority-model.yaml",
513
+ "sha256": "6a303d2ce35ddd4ff7c2539b8ab2ee69411af2d65ab52ebcf0e5f12020fe9c47"
514
+ },
515
+ {
516
+ "path": "contract/safeguard-pack/products/saas-production-safeguard/safeguard-map.yaml",
517
+ "sha256": "e14a8ee6ce3b6a7a2171c0ac3de70a2f713d46f1c808131b5aee9ee241fb68b4"
518
+ },
519
+ {
520
+ "path": "contract/safeguard-pack/protected-actions/safeguard-actions.yaml",
521
+ "sha256": "6932a4c9c7aac3e9e7a17480ca9921ecf1f1942115778963f82488bb2738de68"
522
+ }
523
+ ],
524
+ "source_repo": "AtlaSent-Systems-Inc/atlasent"
525
+ },
526
+ "schema_version": "1.0"
527
+ }
@@ -0,0 +1,98 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://atlasent.io/schemas/safeguard-manifest.schema.json",
4
+ "title": "Safeguard Manifest",
5
+ "description": "Versioned, deterministic projection of the authoritative safeguard package (safeguard-actions + authority-model + safeguard-map) into the design/EXPECTED facts a consumer needs: per protected action, its owner, authority, expected evidence sources, and expected gates. Carries NO runtime observed state (enforcement mode in effect, verification status, coverage, gaps) — those stay live in the runtime. Consumers pin an explicit manifest_version and must validate provenance.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schema_version", "manifest_version", "kind", "provenance", "actions"],
9
+ "properties": {
10
+ "schema_version": { "type": "string", "const": "1.0" },
11
+ "manifest_version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" },
12
+ "kind": { "type": "string", "const": "safeguard-manifest" },
13
+ "generated_by": { "type": "string" },
14
+ "notice": { "type": "string" },
15
+ "provenance": {
16
+ "type": "object",
17
+ "additionalProperties": false,
18
+ "required": ["source_repo", "source_files"],
19
+ "description": "Deterministic input provenance. Release/commit provenance is bound at publish time (npm --provenance / Sigstore), not baked here.",
20
+ "properties": {
21
+ "source_repo": { "type": "string" },
22
+ "source_files": {
23
+ "type": "array",
24
+ "minItems": 1,
25
+ "items": {
26
+ "type": "object",
27
+ "additionalProperties": false,
28
+ "required": ["path", "sha256"],
29
+ "properties": {
30
+ "path": { "type": "string" },
31
+ "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ },
37
+ "actions": {
38
+ "type": "array",
39
+ "minItems": 1,
40
+ "items": {
41
+ "type": "object",
42
+ "additionalProperties": false,
43
+ "required": ["id", "slug", "owner_role", "expected_gates", "expected_evidence_sources"],
44
+ "properties": {
45
+ "id": { "type": "string", "pattern": "^SG-ACT-[0-9]{3}$" },
46
+ "business_action": { "type": ["string", "null"] },
47
+ "slug": { "type": "string" },
48
+ "canon_id": { "type": ["string", "null"] },
49
+ "act_id": { "type": ["string", "null"] },
50
+ "risk_posture": { "type": ["string", "null"] },
51
+ "owner_role": { "type": ["string", "null"] },
52
+ "owner_display_name": { "type": ["string", "null"] },
53
+ "owner_maps_to_org_role": { "type": ["string", "null"] },
54
+ "approver_role": { "type": ["string", "null"] },
55
+ "recommended_lifecycle": { "type": ["string", "null"] },
56
+ "expected_gates": {
57
+ "type": "array",
58
+ "items": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": ["gate", "satisfied_by"],
62
+ "properties": {
63
+ "gate": { "type": "string" },
64
+ "required_assertion_class": { "type": "string" },
65
+ "satisfied_by": {
66
+ "type": "array",
67
+ "items": {
68
+ "type": "object",
69
+ "additionalProperties": false,
70
+ "required": ["capability_id", "via_tools"],
71
+ "properties": {
72
+ "capability_id": { "type": "string" },
73
+ "via_tools": { "type": "array", "items": { "type": "string" } }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ },
80
+ "expected_evidence_sources": {
81
+ "type": "array",
82
+ "items": {
83
+ "type": "object",
84
+ "additionalProperties": false,
85
+ "required": ["capability_id", "tools"],
86
+ "properties": {
87
+ "capability_id": { "type": "string" },
88
+ "tools": { "type": "array", "items": { "type": "string" } },
89
+ "safeguard": { "type": "string" },
90
+ "source": { "type": "string" }
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }