@osstack/compliance 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,837 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ const BUILTIN_PACKS = [{
4
+ id: "engineering-readiness",
5
+ version: "2026.06.22",
6
+ name: "Engineering Readiness",
7
+ certification_claim: "none",
8
+ controls: [
9
+ {
10
+ id: "change-validation",
11
+ title: "Change validation",
12
+ title_zh: "变更验证",
13
+ evidence_path: "verify-results.json",
14
+ description: "Verify gates or scorecard evidence show whether the change was validated.",
15
+ description_zh: "验证门禁或评分卡证据会显示本次变更是否已被验证。",
16
+ },
17
+ {
18
+ id: "automated-decision-trace",
19
+ title: "Automated decision trace",
20
+ title_zh: "自动化决策追踪",
21
+ evidence_path: "policy-decision.json",
22
+ description: "Policy decisions record agent selection and routing rationale.",
23
+ description_zh: "策略决策会记录 agent 选择和路由依据。",
24
+ },
25
+ {
26
+ id: "secure-coding-control",
27
+ title: "Secure coding control",
28
+ title_zh: "安全编码控制",
29
+ evidence_path: "governance-results.json",
30
+ description: "Governance findings map deterministic checks to secure coding evidence.",
31
+ description_zh: "治理发现会把确定性检查映射为安全编码证据。",
32
+ },
33
+ {
34
+ id: "evidence-integrity",
35
+ title: "Evidence integrity",
36
+ title_zh: "证据完整性",
37
+ evidence_path: "manifest.json",
38
+ description: "Proof manifest artifacts carry SHA-256 checksums.",
39
+ description_zh: "Proof manifest 中的产物会携带 SHA-256 checksum。",
40
+ },
41
+ {
42
+ id: "worktree-isolation",
43
+ title: "Worktree isolation evidence",
44
+ title_zh: "Worktree 隔离证据",
45
+ evidence_path: "worktree-status.json",
46
+ description: "Worktree branch and commit evidence show isolated execution context.",
47
+ description_zh: "Worktree 分支和提交证据会显示隔离执行上下文。",
48
+ },
49
+ {
50
+ id: "knowledge-trace",
51
+ title: "Knowledge trace",
52
+ title_zh: "知识追踪",
53
+ evidence_path: "knowledge-results.json",
54
+ description: "Knowledge pack and chunk traces show which retrieved context was used.",
55
+ description_zh: "知识包和 chunk 追踪会显示使用了哪些检索上下文。",
56
+ },
57
+ ],
58
+ }, {
59
+ id: "soc2-lite",
60
+ version: "2026.06.22",
61
+ name: "SOC 2 Lite Internal Mapping",
62
+ certification_claim: "none",
63
+ controls: [
64
+ {
65
+ id: "soc2-change-validation",
66
+ title: "Change validation",
67
+ title_zh: "变更验证",
68
+ evidence_path: "verify-results.json",
69
+ description: "Maps verification results to an internal change-management evidence view.",
70
+ description_zh: "将验证结果映射到内部变更管理证据视图。",
71
+ },
72
+ {
73
+ id: "soc2-automated-decision-trace",
74
+ title: "Automated decision trace",
75
+ title_zh: "自动化决策追踪",
76
+ evidence_path: "policy-decision.json",
77
+ description: "Records the agent selection and routing rationale for audit review.",
78
+ description_zh: "记录 agent 选择和路由依据,供审计复核。",
79
+ },
80
+ {
81
+ id: "soc2-secure-development",
82
+ title: "Secure development checks",
83
+ title_zh: "安全开发检查",
84
+ evidence_path: "governance-results.json",
85
+ description: "Maps deterministic governance findings to secure-development evidence.",
86
+ description_zh: "将确定性治理发现映射为安全开发证据。",
87
+ },
88
+ {
89
+ id: "soc2-evidence-integrity",
90
+ title: "Evidence integrity",
91
+ title_zh: "证据完整性",
92
+ evidence_path: "manifest.json",
93
+ description: "Uses proof manifest checksums as tamper-evident artifact inventory.",
94
+ description_zh: "使用 proof manifest checksum 作为防篡改产物清单。",
95
+ },
96
+ {
97
+ id: "soc2-agent-runtime",
98
+ title: "Agent runtime trace",
99
+ title_zh: "Agent 运行时追踪",
100
+ evidence_path: "agent-runtime.json",
101
+ description: "Shows which agent runtime modes participated in the run.",
102
+ description_zh: "显示参与本次运行的 agent 运行时模式。",
103
+ },
104
+ ],
105
+ }, {
106
+ id: "iso27001-lite",
107
+ version: "2026.06.22",
108
+ name: "ISO 27001 Lite Internal Mapping",
109
+ certification_claim: "none",
110
+ controls: [
111
+ {
112
+ id: "iso-change-control",
113
+ title: "Change control evidence",
114
+ title_zh: "变更控制证据",
115
+ evidence_path: "verify-results.json",
116
+ description: "Verification gates provide internal evidence for change control.",
117
+ description_zh: "验证门禁为变更控制提供内部证据。",
118
+ },
119
+ {
120
+ id: "iso-secure-engineering",
121
+ title: "Secure engineering evidence",
122
+ title_zh: "安全工程证据",
123
+ evidence_path: "governance-results.json",
124
+ description: "Governance checks provide deterministic secure-engineering signals.",
125
+ description_zh: "治理检查提供确定性的安全工程信号。",
126
+ },
127
+ {
128
+ id: "iso-change-isolation",
129
+ title: "Change isolation",
130
+ title_zh: "变更隔离",
131
+ evidence_path: "worktree-status.json",
132
+ description: "Worktree evidence records isolated execution branches and commits.",
133
+ description_zh: "Worktree 证据记录隔离执行分支和提交。",
134
+ },
135
+ {
136
+ id: "iso-evidence-inventory",
137
+ title: "Evidence inventory",
138
+ title_zh: "证据清单",
139
+ evidence_path: "manifest.json",
140
+ description: "Proof manifest lists artifacts with SHA-256 checksums.",
141
+ description_zh: "Proof manifest 会列出带 SHA-256 checksum 的产物。",
142
+ },
143
+ {
144
+ id: "iso-knowledge-source-trace",
145
+ title: "Knowledge source trace",
146
+ title_zh: "知识来源追踪",
147
+ evidence_path: "knowledge-results.json",
148
+ description: "Knowledge traces record retrieved Osstack-native pack and chunk ids.",
149
+ description_zh: "知识追踪会记录检索到的 Osstack-native pack 和 chunk id。",
150
+ },
151
+ ],
152
+ }, {
153
+ id: "eu-ai-act-lite",
154
+ version: "2026.06.22",
155
+ name: "EU AI Act Lite Internal Mapping",
156
+ certification_claim: "none",
157
+ controls: [
158
+ {
159
+ id: "eu-automated-decision-record",
160
+ title: "Automated decision record",
161
+ title_zh: "自动化决策记录",
162
+ evidence_path: "policy-decision.json",
163
+ description: "Policy decision evidence records automated agent selection rationale.",
164
+ description_zh: "策略决策证据会记录自动化 agent 选择依据。",
165
+ },
166
+ {
167
+ id: "eu-agent-runtime-transparency",
168
+ title: "Agent runtime transparency",
169
+ title_zh: "Agent 运行时透明度",
170
+ evidence_path: "agent-runtime.json",
171
+ description: "Agent runtime evidence records auth/invocation mode and role tags.",
172
+ description_zh: "Agent 运行时证据会记录认证/调用模式和角色标签。",
173
+ },
174
+ {
175
+ id: "eu-technical-robustness",
176
+ title: "Technical robustness evidence",
177
+ title_zh: "技术稳健性证据",
178
+ evidence_path: "verify-results.json",
179
+ description: "Verification results show whether the run met its technical gates.",
180
+ description_zh: "验证结果会显示本次运行是否满足技术门禁。",
181
+ },
182
+ {
183
+ id: "eu-risk-and-safety",
184
+ title: "Risk and safety checks",
185
+ title_zh: "风险与安全检查",
186
+ evidence_path: "governance-results.json",
187
+ description: "Governance findings provide deterministic safety and secure-coding signals.",
188
+ description_zh: "治理发现提供确定性的安全与安全编码信号。",
189
+ },
190
+ {
191
+ id: "eu-knowledge-traceability",
192
+ title: "Knowledge traceability",
193
+ title_zh: "知识可追溯性",
194
+ evidence_path: "knowledge-results.json",
195
+ description: "Knowledge evidence records pack and chunk ids used as retrieved context.",
196
+ description_zh: "知识证据会记录作为检索上下文使用的 pack 和 chunk id。",
197
+ },
198
+ ],
199
+ }, {
200
+ id: "internal-audit",
201
+ version: "2026.06.22",
202
+ name: "Internal Audit",
203
+ certification_claim: "none",
204
+ controls: [
205
+ {
206
+ id: "audit-proof-inventory",
207
+ title: "Proof inventory",
208
+ title_zh: "Proof 清单",
209
+ evidence_path: "manifest.json",
210
+ description: "Proof manifest gives the artifact inventory and integrity hashes.",
211
+ description_zh: "Proof manifest 提供产物清单和完整性哈希。",
212
+ },
213
+ {
214
+ id: "audit-validation",
215
+ title: "Validation evidence",
216
+ title_zh: "验证证据",
217
+ evidence_path: "verify-results.json",
218
+ description: "Verification evidence records pass/fail status for the run.",
219
+ description_zh: "验证证据会记录本次运行的通过/失败状态。",
220
+ },
221
+ {
222
+ id: "audit-agent-selection",
223
+ title: "Agent selection evidence",
224
+ title_zh: "Agent 选择证据",
225
+ evidence_path: "policy-decision.json",
226
+ description: "Policy decision evidence records selected agent and reason.",
227
+ description_zh: "策略决策证据会记录被选择的 agent 及原因。",
228
+ },
229
+ {
230
+ id: "audit-runtime",
231
+ title: "Runtime evidence",
232
+ title_zh: "运行时证据",
233
+ evidence_path: "agent-runtime.json",
234
+ description: "Runtime evidence records selected agent modes and roles.",
235
+ description_zh: "运行时证据会记录被选择的 agent 模式和角色。",
236
+ },
237
+ {
238
+ id: "audit-change-isolation",
239
+ title: "Change isolation evidence",
240
+ title_zh: "变更隔离证据",
241
+ evidence_path: "worktree-status.json",
242
+ description: "Worktree evidence records branch, commit, and cleanup status.",
243
+ description_zh: "Worktree 证据会记录分支、提交和清理状态。",
244
+ },
245
+ ],
246
+ }];
247
+ export function listCompliancePacks() {
248
+ return BUILTIN_PACKS.map((pack) => ({
249
+ ...pack,
250
+ controls: pack.controls.map((control) => ({ ...control })),
251
+ }));
252
+ }
253
+ export function getCompliancePack(packId) {
254
+ const pack = BUILTIN_PACKS.find((candidate) => candidate.id === packId);
255
+ if (pack === undefined)
256
+ throw new Error(`unknown compliance pack: ${packId}`);
257
+ return {
258
+ ...pack,
259
+ controls: pack.controls.map((control) => ({ ...control })),
260
+ };
261
+ }
262
+ export async function loadCompliancePack(packDir) {
263
+ const [manifestRaw, controlsRaw, evidenceMapRaw] = await Promise.all([
264
+ readJson(join(packDir, "manifest.json")),
265
+ readJson(join(packDir, "controls.json")),
266
+ readJson(join(packDir, "evidence-map.json")),
267
+ ]);
268
+ const manifest = validateComplianceManifest(manifestRaw);
269
+ const controls = validateComplianceControls(controlsRaw);
270
+ const evidenceMap = validateEvidenceMap(evidenceMapRaw);
271
+ return {
272
+ ...manifest,
273
+ controls: controls.map((control) => ({
274
+ ...control,
275
+ evidence_path: evidenceMap[control.id] ?? missingEvidencePath(control.id),
276
+ })),
277
+ };
278
+ }
279
+ export async function validateCompliancePackFiles(packDir) {
280
+ const [pack, rubricRaw, template] = await Promise.all([
281
+ loadCompliancePack(packDir),
282
+ readJson(join(packDir, "score-rubric.json")),
283
+ readFile(join(packDir, "report-template.md"), "utf-8"),
284
+ ]);
285
+ const rubric = validateScoreRubric(rubricRaw);
286
+ const controlIds = new Set(pack.controls.map((control) => control.id));
287
+ for (const required of rubric.required_present) {
288
+ if (!controlIds.has(required))
289
+ throw new Error(`compliance rubric references unknown control: ${required}`);
290
+ }
291
+ if (!template.includes("External certification claim: `none`")) {
292
+ throw new Error("compliance report template must not claim external certification");
293
+ }
294
+ if (!template.includes("{{controls}}")) {
295
+ throw new Error("compliance report template must include {{controls}}");
296
+ }
297
+ return { pack, required_present: rubric.required_present, template };
298
+ }
299
+ export async function loadProofEvidence(proofDir) {
300
+ const [manifest, verify, policy, agentRuntime, governance, worktree, knowledge] = await Promise.all([
301
+ readJsonIfExists(join(proofDir, "manifest.json")),
302
+ readJsonIfExists(join(proofDir, "verify-results.json")),
303
+ readJsonIfExists(join(proofDir, "policy-decision.json")),
304
+ readJsonIfExists(join(proofDir, "agent-runtime.json")),
305
+ readJsonIfExists(join(proofDir, "governance-results.json")),
306
+ readJsonIfExists(join(proofDir, "worktree-status.json")),
307
+ readJsonIfExists(join(proofDir, "knowledge-results.json")),
308
+ ]);
309
+ return { manifest, verify, policy, agent_runtime: agentRuntime, governance, worktree, knowledge };
310
+ }
311
+ export async function renderComplianceReportFromProofDir(options) {
312
+ const renderOptions = {
313
+ packId: options.packId,
314
+ runId: options.runId,
315
+ evidence: await loadProofEvidence(options.proofDir),
316
+ };
317
+ if (options.language !== undefined) {
318
+ renderOptions.language = options.language;
319
+ }
320
+ return renderComplianceReport(renderOptions);
321
+ }
322
+ export function renderComplianceReport(options) {
323
+ const pack = getCompliancePack(options.packId);
324
+ const text = complianceReportText(options.language ?? "en");
325
+ const rows = pack.controls.map((control) => {
326
+ const status = controlStatus(control, options.evidence);
327
+ const title = localizedControlTitle(control, options.language ?? "en");
328
+ const description = localizedControlDescription(control, options.language ?? "en");
329
+ return `| ${title} | ${proofStatusCell(status)} | \`${control.evidence_path}\` | ${description} |`;
330
+ });
331
+ return [
332
+ `# ${text.title} - ${pack.id}`,
333
+ "",
334
+ `${text.runLabel}${text.labelSeparator}\`${options.runId}\``,
335
+ `${text.packLabel}${text.labelSeparator}\`${pack.id}@${pack.version}\``,
336
+ `${text.certificationClaimLabel}${text.labelSeparator}\`none\``,
337
+ "",
338
+ text.noExternalCertification,
339
+ text.internalMapping(pack.name),
340
+ "",
341
+ `| ${text.controlHeader} | ${text.statusHeader} | ${text.evidenceHeader} | ${text.mappingHeader} |`,
342
+ "|---|---|---|---|",
343
+ ...rows,
344
+ "",
345
+ ].join("\n");
346
+ }
347
+ function localizedControlTitle(control, language) {
348
+ if (language === "zh-CN" && control.title_zh !== undefined)
349
+ return control.title_zh;
350
+ return control.title;
351
+ }
352
+ function localizedControlDescription(control, language) {
353
+ if (language === "zh-CN" && control.description_zh !== undefined)
354
+ return control.description_zh;
355
+ return control.description;
356
+ }
357
+ function complianceReportText(language) {
358
+ if (language === "zh-CN") {
359
+ return {
360
+ title: "Osstack 合规映射报告",
361
+ runLabel: "运行",
362
+ packLabel: "映射包",
363
+ certificationClaimLabel: "外部认证声明",
364
+ labelSeparator: ":",
365
+ noExternalCertification: "此报告不是 SOC 2、ISO 27001、EU AI Act 或第三方认证。",
366
+ internalMapping: (packName) => `它会把 osstack proof 证据映射到内部 ${packName} 视图。`,
367
+ controlHeader: "控制项",
368
+ statusHeader: "状态",
369
+ evidenceHeader: "证据",
370
+ mappingHeader: "映射",
371
+ };
372
+ }
373
+ return {
374
+ title: "Osstack Compliance Report",
375
+ runLabel: "Run",
376
+ packLabel: "Pack",
377
+ certificationClaimLabel: "External certification claim",
378
+ labelSeparator: ": ",
379
+ noExternalCertification: "This report is not a SOC 2, ISO 27001, EU AI Act, or third-party certification.",
380
+ internalMapping: (packName) => `It maps osstack proof evidence to the internal ${packName} view.`,
381
+ controlHeader: "Control",
382
+ statusHeader: "Status",
383
+ evidenceHeader: "Evidence",
384
+ mappingHeader: "Mapping",
385
+ };
386
+ }
387
+ export async function renderProofViewFromProofDir(options) {
388
+ const renderOptions = {
389
+ audience: options.audience,
390
+ runId: options.runId,
391
+ evidence: await loadProofEvidence(options.proofDir),
392
+ };
393
+ if (options.language !== undefined) {
394
+ renderOptions.language = options.language;
395
+ }
396
+ return renderProofView(renderOptions);
397
+ }
398
+ export function renderProofView(options) {
399
+ const language = options.language ?? "en";
400
+ const text = proofViewText(language);
401
+ const controls = proofViewControls(options.audience, language);
402
+ const rows = controls.map((control) => {
403
+ const status = controlStatus(control, options.evidence);
404
+ return `| ${control.title} | ${proofStatusCell(status)} | \`${control.evidence_path}\` | ${control.focus} |`;
405
+ });
406
+ const missing = controls
407
+ .filter((control) => controlStatus(control, options.evidence) === "MISSING")
408
+ .map((control) => text.missingItem(control.title, control.evidence_path, control.focus));
409
+ return [
410
+ `# ${text.title} - ${options.audience}`,
411
+ "",
412
+ `${text.runLabel}${text.labelSeparator}\`${options.runId}\``,
413
+ `${text.audienceLabel}${text.labelSeparator}\`${options.audience}\``,
414
+ "",
415
+ text.description,
416
+ text.missingDescription,
417
+ "",
418
+ `## ${text.missingHeading}`,
419
+ "",
420
+ ...(missing.length > 0 ? missing : [text.noMissingEvidence]),
421
+ "",
422
+ `| ${text.evidenceHeader} | ${text.statusHeader} | ${text.sourceHeader} | ${text.focusHeader} |`,
423
+ "|---|---|---|---|",
424
+ ...rows,
425
+ "",
426
+ ].join("\n");
427
+ }
428
+ export function validateProofEvidence(options) {
429
+ const language = options.language ?? "en";
430
+ const controls = validationControls(options, language);
431
+ const evaluated = controls.map((control) => {
432
+ const status = controlStatus(control, options.evidence);
433
+ return {
434
+ control_id: control.control_id,
435
+ title: control.title,
436
+ evidence_path: control.evidence_path,
437
+ status,
438
+ ...(status === "MISSING" ? { reason: "missing or malformed proof evidence" } : {}),
439
+ };
440
+ });
441
+ const present = evaluated.filter((control) => control.status === "PRESENT");
442
+ const missing = evaluated.filter((control) => control.status === "MISSING");
443
+ return {
444
+ ok: missing.length === 0,
445
+ scope: validationScope(options),
446
+ present,
447
+ missing,
448
+ controls: evaluated,
449
+ };
450
+ }
451
+ function validationControls(options, language) {
452
+ if (options.packId !== undefined) {
453
+ return getCompliancePack(options.packId).controls.map((control) => ({
454
+ control_id: control.id,
455
+ title: localizedControlTitle(control, language),
456
+ evidence_path: control.evidence_path,
457
+ }));
458
+ }
459
+ if (options.audience !== undefined) {
460
+ return proofViewControls(options.audience, language);
461
+ }
462
+ return [
463
+ { control_id: "evidence-integrity", title: "Evidence integrity", evidence_path: "manifest.json" },
464
+ { control_id: "change-validation", title: "Change validation", evidence_path: "verify-results.json" },
465
+ { control_id: "automated-decision-trace", title: "Automated decision trace", evidence_path: "policy-decision.json" },
466
+ { control_id: "agent-runtime-trace", title: "Agent runtime trace", evidence_path: "agent-runtime.json" },
467
+ { control_id: "secure-coding-control", title: "Secure coding control", evidence_path: "governance-results.json" },
468
+ { control_id: "worktree-isolation", title: "Worktree isolation evidence", evidence_path: "worktree-status.json" },
469
+ ];
470
+ }
471
+ function validationScope(options) {
472
+ if (options.packId !== undefined)
473
+ return `compliance:${options.packId}`;
474
+ if (options.audience !== undefined)
475
+ return `audience:${options.audience}`;
476
+ return "proof-core";
477
+ }
478
+ function proofViewText(language) {
479
+ if (language === "zh-CN") {
480
+ return {
481
+ title: "Osstack 证据视图",
482
+ runLabel: "运行",
483
+ audienceLabel: "受众",
484
+ labelSeparator: ":",
485
+ description: "此视图会重排已有 proof 证据,不会创建新证据。",
486
+ missingDescription: "缺失证据会标记为 `MISSING`;此视图不会合成或推断不存在的证据。",
487
+ missingHeading: "缺失证据",
488
+ noMissingEvidence: "此受众视图没有缺失必需证据。",
489
+ evidenceHeader: "证据",
490
+ statusHeader: "状态",
491
+ sourceHeader: "来源",
492
+ focusHeader: "关注点",
493
+ missingItem: (title, evidencePath, focus) => `- **缺失必需证据**:${title}(\`${evidencePath}\`)- ${focus}`,
494
+ };
495
+ }
496
+ return {
497
+ title: "Osstack Proof View",
498
+ runLabel: "Run",
499
+ audienceLabel: "Audience",
500
+ labelSeparator: ": ",
501
+ description: "This view rearranges existing proof evidence and does not create new evidence.",
502
+ missingDescription: "Missing evidence is marked as `MISSING`; this view does not synthesize or infer absent proof.",
503
+ missingHeading: "Missing Evidence",
504
+ noMissingEvidence: "No required evidence is missing for this audience view.",
505
+ evidenceHeader: "Evidence",
506
+ statusHeader: "Status",
507
+ sourceHeader: "Source",
508
+ focusHeader: "Focus",
509
+ missingItem: (title, evidencePath, focus) => `- **REQUIRED EVIDENCE MISSING**: ${title} (\`${evidencePath}\`) - ${focus}`,
510
+ };
511
+ }
512
+ function proofViewControls(audience, language) {
513
+ const byId = new Map(BUILTIN_PACKS[0]?.controls.map((control) => [control.id, control]) ?? []);
514
+ const order = {
515
+ engineer: ["change-validation", "secure-coding-control", "worktree-isolation", "automated-decision-trace", "knowledge-trace", "evidence-integrity"],
516
+ manager: ["change-validation", "automated-decision-trace", "secure-coding-control", "evidence-integrity", "worktree-isolation", "knowledge-trace"],
517
+ auditor: ["evidence-integrity", "automated-decision-trace", "secure-coding-control", "change-validation", "worktree-isolation", "knowledge-trace"],
518
+ customer: ["change-validation", "secure-coding-control", "evidence-integrity", "automated-decision-trace", "worktree-isolation", "knowledge-trace"],
519
+ };
520
+ return order[audience].map((id) => {
521
+ const control = byId.get(id);
522
+ return {
523
+ control_id: id,
524
+ title: control !== undefined ? localizedControlTitle(control, language) : id,
525
+ evidence_path: control?.evidence_path ?? "unknown",
526
+ focus: audienceFocus(audience, id, language),
527
+ };
528
+ });
529
+ }
530
+ function audienceFocus(audience, controlId, language) {
531
+ const focus = {
532
+ en: {
533
+ engineer: {
534
+ "change-validation": "what passed or failed",
535
+ "secure-coding-control": "deterministic findings to fix",
536
+ "worktree-isolation": "branch and commit context",
537
+ "automated-decision-trace": "agent routing rationale",
538
+ "knowledge-trace": "retrieved context used during work",
539
+ "evidence-integrity": "artifact checksum trail",
540
+ },
541
+ manager: {
542
+ "change-validation": "release readiness",
543
+ "automated-decision-trace": "why this agent path was chosen",
544
+ "secure-coding-control": "risk posture",
545
+ "evidence-integrity": "reviewable proof bundle",
546
+ "worktree-isolation": "delivery isolation",
547
+ "knowledge-trace": "context quality",
548
+ },
549
+ auditor: {
550
+ "evidence-integrity": "checksumed artifact inventory",
551
+ "automated-decision-trace": "automated decision record",
552
+ "secure-coding-control": "secure coding evidence",
553
+ "change-validation": "change validation evidence",
554
+ "worktree-isolation": "change isolation evidence",
555
+ "knowledge-trace": "knowledge source trace",
556
+ },
557
+ customer: {
558
+ "change-validation": "delivery validation summary",
559
+ "secure-coding-control": "safety checks summary",
560
+ "evidence-integrity": "tamper-evident bundle",
561
+ "automated-decision-trace": "high-level automation trace",
562
+ "worktree-isolation": "isolated delivery workflow",
563
+ "knowledge-trace": "approved context trace",
564
+ },
565
+ },
566
+ "zh-CN": {
567
+ engineer: {
568
+ "change-validation": "通过或失败的内容",
569
+ "secure-coding-control": "需要修复的确定性发现",
570
+ "worktree-isolation": "分支与提交上下文",
571
+ "automated-decision-trace": "agent 路由依据",
572
+ "knowledge-trace": "工作中使用的检索上下文",
573
+ "evidence-integrity": "证据 checksum 链路",
574
+ },
575
+ manager: {
576
+ "change-validation": "发布就绪度",
577
+ "automated-decision-trace": "为什么选择这条 agent 路径",
578
+ "secure-coding-control": "风险状态",
579
+ "evidence-integrity": "可审查的证据包",
580
+ "worktree-isolation": "交付隔离",
581
+ "knowledge-trace": "上下文质量",
582
+ },
583
+ auditor: {
584
+ "evidence-integrity": "带 checksum 的证据清单",
585
+ "automated-decision-trace": "自动化决策记录",
586
+ "secure-coding-control": "安全编码证据",
587
+ "change-validation": "变更验证证据",
588
+ "worktree-isolation": "变更隔离证据",
589
+ "knowledge-trace": "知识来源追踪",
590
+ },
591
+ customer: {
592
+ "change-validation": "交付验证摘要",
593
+ "secure-coding-control": "安全检查摘要",
594
+ "evidence-integrity": "防篡改证据包",
595
+ "automated-decision-trace": "高层自动化追踪",
596
+ "worktree-isolation": "隔离交付流程",
597
+ "knowledge-trace": "已批准上下文追踪",
598
+ },
599
+ },
600
+ };
601
+ return focus[language][audience][controlId] ?? (language === "zh-CN" ? "证据状态" : "evidence status");
602
+ }
603
+ function controlStatus(control, evidence) {
604
+ switch (control.evidence_path) {
605
+ case "verify-results.json":
606
+ return hasRecordedVerifyEvidence(evidence.verify) ? "PRESENT" : "MISSING";
607
+ case "policy-decision.json":
608
+ return hasRecordedPolicyEvidence(evidence.policy) ? "PRESENT" : "MISSING";
609
+ case "agent-runtime.json":
610
+ return hasRecordedAgentRuntimeEvidence(evidence.agent_runtime) ? "PRESENT" : "MISSING";
611
+ case "governance-results.json":
612
+ return hasGovernanceEvidence(evidence.governance) ? "PRESENT" : "MISSING";
613
+ case "manifest.json":
614
+ return hasProofManifestEvidence(evidence.manifest) ? "PRESENT" : "MISSING";
615
+ case "worktree-status.json":
616
+ return hasRecordedWorktreeEvidence(evidence.worktree) ? "PRESENT" : "MISSING";
617
+ case "knowledge-results.json":
618
+ return hasRecordedKnowledgeEvidence(evidence.knowledge) ? "PRESENT" : "MISSING";
619
+ }
620
+ return "MISSING";
621
+ }
622
+ const SHA256_HEX = /^[a-f0-9]{64}$/;
623
+ function hasRecordedVerifyEvidence(value) {
624
+ if (!hasObject(value) || (value["status"] !== "pass" && value["status"] !== "fail"))
625
+ return false;
626
+ return hasValidNonEmptyArray(value, "results", isVerifyResult);
627
+ }
628
+ function isVerifyResult(value) {
629
+ if (!hasObject(value))
630
+ return false;
631
+ return isNonEmptyString(value["task_id"])
632
+ && typeof value["pass"] === "boolean"
633
+ && (typeof value["score"] === "number" || value["score"] === "unknown")
634
+ && isNonEmptyString(value["reviewer_agent_id"])
635
+ && isNonEmptyString(value["summary"])
636
+ && isNonNegativeInteger(value["event_seq"]);
637
+ }
638
+ function hasRecordedPolicyEvidence(value) {
639
+ if (!hasObject(value) || value["status"] !== "recorded")
640
+ return false;
641
+ return hasValidNonEmptyArray(value, "decisions", isPolicyDecision);
642
+ }
643
+ function isPolicyDecision(value) {
644
+ if (!hasObject(value))
645
+ return false;
646
+ return isNonEmptyString(value["task_id"])
647
+ && isNonEmptyString(value["agent_id"])
648
+ && isNonEmptyString(value["auth_mode"])
649
+ && hasNonEmptyStringArray(value["roles"])
650
+ && isNonEmptyString(value["reason"])
651
+ && isNonNegativeInteger(value["event_seq"]);
652
+ }
653
+ function hasRecordedAgentRuntimeEvidence(value) {
654
+ if (!hasObject(value) || value["status"] !== "recorded")
655
+ return false;
656
+ return hasValidNonEmptyArray(value, "agents", isAgentRuntime);
657
+ }
658
+ function isAgentRuntime(value) {
659
+ if (!hasObject(value))
660
+ return false;
661
+ return isNonEmptyString(value["agent_id"])
662
+ && isNonEmptyString(value["auth_mode"])
663
+ && hasNonEmptyStringArray(value["roles"])
664
+ && hasNonNegativeIntegerArray(value["plan_event_seqs"]);
665
+ }
666
+ function hasGovernanceEvidence(value) {
667
+ return hasObject(value) && (value["status"] === "pass" || value["status"] === "fail");
668
+ }
669
+ function hasProofManifestEvidence(value) {
670
+ if (!hasObject(value))
671
+ return false;
672
+ if (!hasValidNonEmptyArray(value, "artifacts", isProofManifestArtifact))
673
+ return false;
674
+ return hasValidComplianceReports(value);
675
+ }
676
+ function isProofManifestArtifact(value) {
677
+ if (!hasObject(value))
678
+ return false;
679
+ return isNonEmptyString(value["path"])
680
+ && typeof value["sha256"] === "string"
681
+ && SHA256_HEX.test(value["sha256"])
682
+ && isPositiveInteger(value["bytes"]);
683
+ }
684
+ function hasValidComplianceReports(manifest) {
685
+ const reports = manifest["compliance_reports"];
686
+ if (reports === undefined)
687
+ return true;
688
+ if (!Array.isArray(reports))
689
+ return false;
690
+ const artifactPaths = new Set(manifest["artifacts"]
691
+ .filter(hasObject)
692
+ .map((artifact) => artifact["path"])
693
+ .filter((path) => typeof path === "string"));
694
+ return reports.every((report) => {
695
+ if (!hasObject(report))
696
+ return false;
697
+ return isNonEmptyString(report["pack_id"])
698
+ && isNonEmptyString(report["path"])
699
+ && report["certification_claim"] === "none"
700
+ && artifactPaths.has(report["path"]);
701
+ });
702
+ }
703
+ function hasRecordedWorktreeEvidence(value) {
704
+ if (!hasObject(value) || value["status"] !== "recorded")
705
+ return false;
706
+ return hasValidNonEmptyArray(value, "entries", isWorktreeEntry);
707
+ }
708
+ function isWorktreeEntry(value) {
709
+ if (!hasObject(value))
710
+ return false;
711
+ if (!isNonEmptyString(value["task_id"]))
712
+ return false;
713
+ if (value["status"] !== "created" && value["status"] !== "merged" && value["status"] !== "cleaned")
714
+ return false;
715
+ if (!isNonEmptyString(value["branch"]) || !isNonEmptyString(value["path"]))
716
+ return false;
717
+ if (value["status"] === "merged" && !isNonEmptyString(value["commit"]))
718
+ return false;
719
+ return isNonNegativeInteger(value["event_seq"]);
720
+ }
721
+ function hasRecordedKnowledgeEvidence(value) {
722
+ if (!hasObject(value) || value["status"] !== "recorded")
723
+ return false;
724
+ return hasValidNonEmptyArray(value, "results", isKnowledgeResult);
725
+ }
726
+ function isKnowledgeResult(value) {
727
+ if (!hasObject(value))
728
+ return false;
729
+ return isNonEmptyString(value["chunk_id"]) && hasNonEmptyStringArray(value["source_refs"]);
730
+ }
731
+ function hasValidNonEmptyArray(value, key, predicate) {
732
+ return Array.isArray(value[key]) && value[key].length > 0 && value[key].every(predicate);
733
+ }
734
+ function isNonEmptyString(value) {
735
+ return typeof value === "string" && value.length > 0 && value !== "unknown";
736
+ }
737
+ function hasNonEmptyStringArray(value) {
738
+ return Array.isArray(value) && value.length > 0 && value.every(isNonEmptyString);
739
+ }
740
+ function hasNonNegativeIntegerArray(value) {
741
+ return Array.isArray(value) && value.length > 0 && value.every(isNonNegativeInteger);
742
+ }
743
+ function isNonNegativeInteger(value) {
744
+ return Number.isInteger(value) && typeof value === "number" && value >= 0;
745
+ }
746
+ function isPositiveInteger(value) {
747
+ return Number.isInteger(value) && typeof value === "number" && value > 0;
748
+ }
749
+ function proofStatusCell(status) {
750
+ if (status === "PRESENT")
751
+ return "PRESENT";
752
+ return "<strong class=\"osstack-missing-evidence\" style=\"color:#b00020\">MISSING</strong>";
753
+ }
754
+ async function readJsonIfExists(path) {
755
+ try {
756
+ return JSON.parse(await readFile(path, "utf-8"));
757
+ }
758
+ catch {
759
+ return undefined;
760
+ }
761
+ }
762
+ async function readJson(path) {
763
+ return JSON.parse(await readFile(path, "utf-8"));
764
+ }
765
+ function validateComplianceManifest(value) {
766
+ if (!hasObject(value))
767
+ throw new Error("compliance manifest must be an object");
768
+ const certificationClaim = requiredString(value, "certification_claim");
769
+ if (certificationClaim !== "none")
770
+ throw new Error("compliance manifest certification_claim must be none");
771
+ return {
772
+ id: requiredString(value, "id"),
773
+ version: requiredString(value, "version"),
774
+ name: requiredString(value, "name"),
775
+ certification_claim: "none",
776
+ ...(typeof value["description"] === "string" && value["description"].length > 0
777
+ ? { description: value["description"] }
778
+ : {}),
779
+ };
780
+ }
781
+ function validateComplianceControls(value) {
782
+ if (!Array.isArray(value))
783
+ throw new Error("compliance controls must be an array");
784
+ return value.map((control) => {
785
+ if (!hasObject(control))
786
+ throw new Error("compliance control must be an object");
787
+ return {
788
+ id: requiredString(control, "id"),
789
+ title: requiredString(control, "title"),
790
+ description: requiredString(control, "description"),
791
+ ...(typeof control["title_zh"] === "string" && control["title_zh"].length > 0
792
+ ? { title_zh: control["title_zh"] }
793
+ : {}),
794
+ ...(typeof control["description_zh"] === "string" && control["description_zh"].length > 0
795
+ ? { description_zh: control["description_zh"] }
796
+ : {}),
797
+ };
798
+ });
799
+ }
800
+ function validateEvidenceMap(value) {
801
+ if (!hasObject(value))
802
+ throw new Error("compliance evidence-map must be an object");
803
+ const entries = {};
804
+ for (const [key, evidencePath] of Object.entries(value)) {
805
+ if (typeof evidencePath !== "string" || evidencePath.length === 0) {
806
+ throw new Error(`compliance evidence-map entry ${key} must be a non-empty string`);
807
+ }
808
+ entries[key] = evidencePath;
809
+ }
810
+ return entries;
811
+ }
812
+ function validateScoreRubric(value) {
813
+ if (!hasObject(value))
814
+ throw new Error("compliance score-rubric must be an object");
815
+ const minimum = value["minimum_release_ready"];
816
+ if (!hasObject(minimum))
817
+ throw new Error("compliance score-rubric minimum_release_ready must be an object");
818
+ const required = minimum["required_present"];
819
+ if (!Array.isArray(required) || !required.every((item) => typeof item === "string" && item.length > 0)) {
820
+ throw new Error("compliance score-rubric required_present must be an array of strings");
821
+ }
822
+ return { required_present: required };
823
+ }
824
+ function missingEvidencePath(controlId) {
825
+ throw new Error(`compliance evidence-map missing control: ${controlId}`);
826
+ }
827
+ function requiredString(value, key) {
828
+ const field = value[key];
829
+ if (typeof field !== "string" || field.length === 0) {
830
+ throw new Error(`compliance ${key} must be a non-empty string`);
831
+ }
832
+ return field;
833
+ }
834
+ function hasObject(value) {
835
+ return value !== null && typeof value === "object" && !Array.isArray(value);
836
+ }
837
+ //# sourceMappingURL=index.js.map