project-tiny-context-harness 0.8.16 → 0.11.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 +119 -41
- package/assets/README.md +184 -55
- package/assets/README.zh-CN.md +114 -40
- package/assets/agents/AGENTS_CORE.md +2 -2
- package/assets/context_templates/context.toml +6 -1
- package/assets/context_templates/screen-contract.md +16 -0
- package/assets/runtime/windows-job-supervisor/formal_process_supervisor_native_helpers.cs +301 -0
- package/assets/runtime/windows-job-supervisor/formal_process_supervisor_native_run.cs +197 -0
- package/assets/runtime/windows-job-supervisor/formal_process_supervisor_native_types.cs +215 -0
- package/assets/runtime/windows-job-supervisor/windows_job_process_supervisor.ps1 +117 -0
- package/assets/skills/context_development_engineer/SKILL.md +16 -30
- package/assets/skills/context_development_engineer/references/engineering-design-reasoning.md +93 -0
- package/assets/skills/context_surface_contract/SKILL.md +13 -2
- package/assets/skills/context_uiux_design/SKILL.md +7 -3
- package/assets/skills/context_uiux_design/references/task-uiux-analysis.md +82 -0
- package/assets/skills/design-resource-authoring/SKILL.md +18 -9
- package/assets/skills/design-resource-authoring/references/authority-delta-assessment.md +52 -0
- package/assets/skills/design-resource-authoring/references/downstream-handoff.md +22 -6
- package/assets/skills/design-resource-authoring/references/formal-selected-web-app-handoff.md +26 -8
- package/assets/skills/design-resource-authoring/references/implementation-feasibility.md +111 -0
- package/assets/skills/design-resource-authoring/references/open-design-provider.md +45 -7
- package/assets/skills/design-resource-authoring/references/recovery-and-writeback.md +7 -1
- package/assets/skills/design-resource-authoring/references/resource-selection.md +115 -3
- package/assets/skills/design-system-authoring/SKILL.md +23 -17
- package/assets/skills/design-system-authoring/references/authority-adoption.md +19 -9
- package/assets/skills/design-system-authoring/references/open-design-design-system-provider.md +4 -0
- package/assets/skills/long-task-workflow/SKILL.md +6 -6
- package/assets/skills/long-task-workflow/references/authority-lifecycle.md +10 -4
- package/assets/skills/long-task-workflow/references/contract-authoring.md +5 -5
- package/assets/skills/long-task-workflow/references/evidence-design.md +14 -3
- package/assets/skills/long-task-workflow/references/source-authoring.md +11 -8
- package/assets/tools/context_rules.json +53 -0
- package/assets/tools/validate_context.py +302 -77
- package/dist/cli.js +2 -1
- package/dist/commands/context-create.d.ts +1 -0
- package/dist/commands/context-create.js +90 -0
- package/dist/commands/context-inspect.d.ts +1 -0
- package/dist/commands/context-inspect.js +98 -0
- package/dist/commands/context-move.d.ts +1 -0
- package/dist/commands/context-move.js +78 -0
- package/dist/commands/context-register.d.ts +1 -0
- package/dist/commands/context-register.js +110 -0
- package/dist/commands/context-transaction.d.ts +1 -0
- package/dist/commands/context-transaction.js +84 -0
- package/dist/commands/context.d.ts +1 -0
- package/dist/commands/context.js +36 -0
- package/dist/commands/design-authority-delta.d.ts +1 -0
- package/dist/commands/design-authority-delta.js +53 -0
- package/dist/commands/design-authority.d.ts +1 -0
- package/dist/commands/design-authority.js +104 -0
- package/dist/commands/design-resource.js +17 -3
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.js +61 -3
- package/dist/commands/index.js +19 -2
- package/dist/commands/long-task-authoring.js +20 -2
- package/dist/commands/long-task-workdir.d.ts +2 -0
- package/dist/commands/long-task-workdir.js +23 -0
- package/dist/commands/long-task.js +75 -6
- package/dist/commands/route.d.ts +15 -0
- package/dist/commands/route.js +142 -0
- package/dist/index.d.ts +3 -13
- package/dist/index.js +3 -12
- package/dist/lib/cli-exit.d.ts +14 -0
- package/dist/lib/cli-exit.js +19 -0
- package/dist/lib/context-catalog/catalog-default-footprint.d.ts +3 -0
- package/dist/lib/context-catalog/catalog-default-footprint.js +53 -0
- package/dist/lib/context-catalog/catalog-diagnostics.d.ts +9 -0
- package/dist/lib/context-catalog/catalog-diagnostics.js +34 -0
- package/dist/lib/context-catalog/catalog-discovery.d.ts +7 -0
- package/dist/lib/context-catalog/catalog-discovery.js +81 -0
- package/dist/lib/context-catalog/catalog-load.d.ts +8 -0
- package/dist/lib/context-catalog/catalog-load.js +187 -0
- package/dist/lib/context-catalog/catalog-path-validation.d.ts +7 -0
- package/dist/lib/context-catalog/catalog-path-validation.js +62 -0
- package/dist/lib/context-catalog/catalog-paths.d.ts +11 -0
- package/dist/lib/context-catalog/catalog-paths.js +41 -0
- package/dist/lib/context-catalog/catalog-portable-contract.d.ts +15 -0
- package/dist/lib/context-catalog/catalog-portable-contract.js +68 -0
- package/dist/lib/context-catalog/catalog-staged-path-safety.d.ts +1 -0
- package/dist/lib/context-catalog/catalog-staged-path-safety.js +36 -0
- package/dist/lib/context-catalog/catalog-types.d.ts +40 -0
- package/dist/lib/context-catalog/catalog-types.js +1 -0
- package/dist/lib/context-catalog/catalog-validation.d.ts +9 -0
- package/dist/lib/context-catalog/catalog-validation.js +148 -0
- package/dist/lib/context-create/context-create-path.d.ts +2 -0
- package/dist/lib/context-create/context-create-path.js +30 -0
- package/dist/lib/context-create/context-create-template.d.ts +2 -0
- package/dist/lib/context-create/context-create-template.js +95 -0
- package/dist/lib/context-create/context-create-types.d.ts +28 -0
- package/dist/lib/context-create/context-create-types.js +1 -0
- package/dist/lib/context-create/context-create-write.d.ts +1 -0
- package/dist/lib/context-create/context-create-write.js +85 -0
- package/dist/lib/context-create/context-create.d.ts +2 -0
- package/dist/lib/context-create/context-create.js +84 -0
- package/dist/lib/context-default-footprint.d.ts +2 -3
- package/dist/lib/context-default-footprint.js +49 -57
- package/dist/lib/context-doctor/context-doctor-types.d.ts +16 -0
- package/dist/lib/context-doctor/context-doctor-types.js +15 -0
- package/dist/lib/context-doctor/context-doctor.d.ts +2 -0
- package/dist/lib/context-doctor/context-doctor.js +130 -0
- package/dist/lib/context-graph-snapshot.d.ts +5 -0
- package/dist/lib/context-graph-snapshot.js +46 -25
- package/dist/lib/context-inspect/context-inspect-projection.d.ts +9 -0
- package/dist/lib/context-inspect/context-inspect-projection.js +49 -0
- package/dist/lib/context-inspect/context-inspect-render.d.ts +2 -0
- package/dist/lib/context-inspect/context-inspect-render.js +29 -0
- package/dist/lib/context-inspect/context-inspect-types.d.ts +43 -0
- package/dist/lib/context-inspect/context-inspect-types.js +1 -0
- package/dist/lib/context-inspect/context-inspect.d.ts +2 -0
- package/dist/lib/context-inspect/context-inspect.js +104 -0
- package/dist/lib/context-manifest-schema.d.ts +1 -1
- package/dist/lib/context-manifest-schema.js +4 -20
- package/dist/lib/context-markdown/context-markdown-analysis.d.ts +15 -0
- package/dist/lib/context-markdown/context-markdown-analysis.js +245 -0
- package/dist/lib/context-markdown/context-markdown-extract.d.ts +7 -0
- package/dist/lib/context-markdown/context-markdown-extract.js +114 -0
- package/dist/lib/context-markdown/context-markdown-types.d.ts +57 -0
- package/dist/lib/context-markdown/context-markdown-types.js +1 -0
- package/dist/lib/context-move/context-move-input.d.ts +8 -0
- package/dist/lib/context-move/context-move-input.js +17 -0
- package/dist/lib/context-move/context-move-literal-scan.d.ts +20 -0
- package/dist/lib/context-move/context-move-literal-scan.js +213 -0
- package/dist/lib/context-move/context-move-live-validation.d.ts +3 -0
- package/dist/lib/context-move/context-move-live-validation.js +56 -0
- package/dist/lib/context-move/context-move-markdown-plan.d.ts +22 -0
- package/dist/lib/context-move/context-move-markdown-plan.js +39 -0
- package/dist/lib/context-move/context-move-projection.d.ts +3 -0
- package/dist/lib/context-move/context-move-projection.js +11 -0
- package/dist/lib/context-move/context-move-reference-validation.d.ts +11 -0
- package/dist/lib/context-move/context-move-reference-validation.js +64 -0
- package/dist/lib/context-move/context-move-render.d.ts +2 -0
- package/dist/lib/context-move/context-move-render.js +24 -0
- package/dist/lib/context-move/context-move-support.d.ts +10 -0
- package/dist/lib/context-move/context-move-support.js +88 -0
- package/dist/lib/context-move/context-move-transaction-plan.d.ts +24 -0
- package/dist/lib/context-move/context-move-transaction-plan.js +108 -0
- package/dist/lib/context-move/context-move-types.d.ts +74 -0
- package/dist/lib/context-move/context-move-types.js +1 -0
- package/dist/lib/context-move/context-move.d.ts +8 -0
- package/dist/lib/context-move/context-move.js +180 -0
- package/dist/lib/context-mutation/manifest-lossless-patch.d.ts +28 -0
- package/dist/lib/context-mutation/manifest-lossless-patch.js +208 -0
- package/dist/lib/context-mutation/markdown-link-patch.d.ts +34 -0
- package/dist/lib/context-mutation/markdown-link-patch.js +143 -0
- package/dist/lib/context-mutation/markdown-link-spans.d.ts +10 -0
- package/dist/lib/context-mutation/markdown-link-spans.js +179 -0
- package/dist/lib/context-mutation/mutation-cas.d.ts +13 -0
- package/dist/lib/context-mutation/mutation-cas.js +365 -0
- package/dist/lib/context-mutation/mutation-command-support.d.ts +12 -0
- package/dist/lib/context-mutation/mutation-command-support.js +57 -0
- package/dist/lib/context-mutation/mutation-commit.d.ts +12 -0
- package/dist/lib/context-mutation/mutation-commit.js +89 -0
- package/dist/lib/context-mutation/mutation-directories.d.ts +5 -0
- package/dist/lib/context-mutation/mutation-directories.js +56 -0
- package/dist/lib/context-mutation/mutation-file-state.d.ts +14 -0
- package/dist/lib/context-mutation/mutation-file-state.js +137 -0
- package/dist/lib/context-mutation/mutation-journal-file-validation.d.ts +1 -0
- package/dist/lib/context-mutation/mutation-journal-file-validation.js +106 -0
- package/dist/lib/context-mutation/mutation-journal-io.d.ts +5 -0
- package/dist/lib/context-mutation/mutation-journal-io.js +55 -0
- package/dist/lib/context-mutation/mutation-journal-storage.d.ts +18 -0
- package/dist/lib/context-mutation/mutation-journal-storage.js +283 -0
- package/dist/lib/context-mutation/mutation-journal-validation-support.d.ts +16 -0
- package/dist/lib/context-mutation/mutation-journal-validation-support.js +140 -0
- package/dist/lib/context-mutation/mutation-journal-validation.d.ts +3 -0
- package/dist/lib/context-mutation/mutation-journal-validation.js +177 -0
- package/dist/lib/context-mutation/mutation-journal.d.ts +8 -0
- package/dist/lib/context-mutation/mutation-journal.js +111 -0
- package/dist/lib/context-mutation/mutation-live-validation.d.ts +3 -0
- package/dist/lib/context-mutation/mutation-live-validation.js +51 -0
- package/dist/lib/context-mutation/mutation-long-task-guard.d.ts +6 -0
- package/dist/lib/context-mutation/mutation-long-task-guard.js +57 -0
- package/dist/lib/context-mutation/mutation-recovery.d.ts +4 -0
- package/dist/lib/context-mutation/mutation-recovery.js +189 -0
- package/dist/lib/context-mutation/mutation-staged-fs.d.ts +5 -0
- package/dist/lib/context-mutation/mutation-staged-fs.js +56 -0
- package/dist/lib/context-mutation/mutation-types.d.ts +103 -0
- package/dist/lib/context-mutation/mutation-types.js +1 -0
- package/dist/lib/context-register/context-register-input.d.ts +11 -0
- package/dist/lib/context-register/context-register-input.js +43 -0
- package/dist/lib/context-register/context-register-render.d.ts +2 -0
- package/dist/lib/context-register/context-register-render.js +21 -0
- package/dist/lib/context-register/context-register-support.d.ts +6 -0
- package/dist/lib/context-register/context-register-support.js +46 -0
- package/dist/lib/context-register/context-register-types.d.ts +46 -0
- package/dist/lib/context-register/context-register-types.js +1 -0
- package/dist/lib/context-register/context-register.d.ts +8 -0
- package/dist/lib/context-register/context-register.js +155 -0
- package/dist/lib/context-router/context-route-budget.d.ts +15 -0
- package/dist/lib/context-router/context-route-budget.js +14 -0
- package/dist/lib/context-router/context-route-candidates.d.ts +15 -0
- package/dist/lib/context-router/context-route-candidates.js +112 -0
- package/dist/lib/context-router/context-route-order.d.ts +6 -0
- package/dist/lib/context-router/context-route-order.js +53 -0
- package/dist/lib/context-router/context-route-paths.d.ts +16 -0
- package/dist/lib/context-router/context-route-paths.js +109 -0
- package/dist/lib/context-router/context-route-render.d.ts +2 -0
- package/dist/lib/context-router/context-route-render.js +32 -0
- package/dist/lib/context-router/context-route-scan.d.ts +18 -0
- package/dist/lib/context-router/context-route-scan.js +156 -0
- package/dist/lib/context-router/context-route-selection.d.ts +16 -0
- package/dist/lib/context-router/context-route-selection.js +72 -0
- package/dist/lib/context-router/context-route-terms.d.ts +13 -0
- package/dist/lib/context-router/context-route-terms.js +202 -0
- package/dist/lib/context-router/context-route-types.d.ts +101 -0
- package/dist/lib/context-router/context-route-types.js +1 -0
- package/dist/lib/context-router/context-route.d.ts +2 -0
- package/dist/lib/context-router/context-route.js +127 -0
- package/dist/lib/context-units-migration.d.ts +13 -0
- package/dist/lib/context-units-migration.js +217 -0
- package/dist/lib/design-authority-binding.d.ts +7 -0
- package/dist/lib/design-authority-binding.js +96 -0
- package/dist/lib/design-authority-closure.d.ts +3 -0
- package/dist/lib/design-authority-closure.js +201 -0
- package/dist/lib/design-authority-delta-codec-primitives.d.ts +10 -0
- package/dist/lib/design-authority-delta-codec-primitives.js +58 -0
- package/dist/lib/design-authority-delta-codec.d.ts +2 -0
- package/dist/lib/design-authority-delta-codec.js +193 -0
- package/dist/lib/design-authority-delta-types.d.ts +65 -0
- package/dist/lib/design-authority-delta-types.js +6 -0
- package/dist/lib/design-authority-delta-validation.d.ts +2 -0
- package/dist/lib/design-authority-delta-validation.js +16 -0
- package/dist/lib/design-authority-digest.d.ts +8 -0
- package/dist/lib/design-authority-digest.js +36 -0
- package/dist/lib/design-authority-files.d.ts +9 -0
- package/dist/lib/design-authority-files.js +62 -0
- package/dist/lib/design-authority-format.d.ts +2 -0
- package/dist/lib/design-authority-format.js +93 -0
- package/dist/lib/design-authority-links.d.ts +10 -0
- package/dist/lib/design-authority-links.js +137 -0
- package/dist/lib/design-authority-manifest.d.ts +4 -0
- package/dist/lib/design-authority-manifest.js +144 -0
- package/dist/lib/design-authority-tokens.d.ts +9 -0
- package/dist/lib/design-authority-tokens.js +45 -0
- package/dist/lib/design-authority-types.d.ts +80 -0
- package/dist/lib/design-authority-types.js +23 -0
- package/dist/lib/design-md-tool-adapter.d.ts +9 -0
- package/dist/lib/design-md-tool-adapter.js +152 -0
- package/dist/lib/design-md-tool-normalization.d.ts +7 -0
- package/dist/lib/design-md-tool-normalization.js +78 -0
- package/dist/lib/design-md-tool-types.d.ts +99 -0
- package/dist/lib/design-md-tool-types.js +8 -0
- package/dist/lib/design-resource-handoff-bundle.js +5 -0
- package/dist/lib/design-resource-handoff-input-types.d.ts +1 -1
- package/dist/lib/design-resource-handoff-manifest-projection.js +4 -0
- package/dist/lib/design-resource-handoff-set-integrity.js +1 -0
- package/dist/lib/design-resource-handoff-shape.js +18 -2
- package/dist/lib/design-resource-handoff-types.d.ts +8 -0
- package/dist/lib/design-resource-handoff-validation.js +24 -0
- package/dist/lib/design-resource-implementation-feasibility-model.d.ts +35 -0
- package/dist/lib/design-resource-implementation-feasibility-model.js +62 -0
- package/dist/lib/design-resource-implementation-feasibility-shape-sections.d.ts +43 -0
- package/dist/lib/design-resource-implementation-feasibility-shape-sections.js +142 -0
- package/dist/lib/design-resource-implementation-feasibility-shape.d.ts +4 -0
- package/dist/lib/design-resource-implementation-feasibility-shape.js +154 -0
- package/dist/lib/design-resource-implementation-feasibility-source-decision-projection.d.ts +24 -0
- package/dist/lib/design-resource-implementation-feasibility-source-decision-projection.js +106 -0
- package/dist/lib/design-resource-implementation-feasibility-source-decision.d.ts +21 -0
- package/dist/lib/design-resource-implementation-feasibility-source-decision.js +75 -0
- package/dist/lib/design-resource-implementation-feasibility-types.d.ts +135 -0
- package/dist/lib/design-resource-implementation-feasibility-types.js +37 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-cells.d.ts +5 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-cells.js +125 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-document.d.ts +4 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-document.js +167 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-facts.d.ts +3 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-facts.js +76 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-realizations.d.ts +8 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-realizations.js +76 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-support.d.ts +10 -0
- package/dist/lib/design-resource-implementation-feasibility-validation-support.js +75 -0
- package/dist/lib/design-resource-implementation-feasibility-validation.d.ts +3 -0
- package/dist/lib/design-resource-implementation-feasibility-validation.js +138 -0
- package/dist/lib/design-resource-recovery-current.js +22 -0
- package/dist/lib/design-resource-recovery-shape.js +64 -7
- package/dist/lib/design-resource-recovery-types.d.ts +4 -1
- package/dist/lib/design-resource-symbolic-fact-shape.js +9 -1
- package/dist/lib/design-resource-symbolic-fact-types.d.ts +8 -0
- package/dist/lib/design-resource-symbolic-fact-validation.js +25 -0
- package/dist/lib/doctor.d.ts +2 -1
- package/dist/lib/doctor.js +29 -1
- package/dist/lib/fs.js +1 -1
- package/dist/lib/long-task-acceptance-reachability-claims.d.ts +2 -0
- package/dist/lib/long-task-acceptance-reachability-claims.js +279 -0
- package/dist/lib/long-task-acceptance-reachability-design.d.ts +2 -0
- package/dist/lib/long-task-acceptance-reachability-design.js +96 -0
- package/dist/lib/long-task-acceptance-reachability-external.d.ts +9 -0
- package/dist/lib/long-task-acceptance-reachability-external.js +123 -0
- package/dist/lib/long-task-acceptance-reachability-helpers.d.ts +64 -0
- package/dist/lib/long-task-acceptance-reachability-helpers.js +473 -0
- package/dist/lib/long-task-acceptance-reachability-semantic.d.ts +2 -0
- package/dist/lib/long-task-acceptance-reachability-semantic.js +122 -0
- package/dist/lib/long-task-acceptance-reachability-types.d.ts +91 -0
- package/dist/lib/long-task-acceptance-reachability-types.js +1 -0
- package/dist/lib/long-task-acceptance-reachability.d.ts +4 -0
- package/dist/lib/long-task-acceptance-reachability.js +115 -0
- package/dist/lib/long-task-activation-validation.d.ts +6 -0
- package/dist/lib/long-task-activation-validation.js +96 -23
- package/dist/lib/long-task-active-authority-lock-context.d.ts +4 -0
- package/dist/lib/long-task-active-authority-lock-context.js +29 -0
- package/dist/lib/long-task-applicability-identity.d.ts +25 -0
- package/dist/lib/long-task-applicability-identity.js +60 -0
- package/dist/lib/long-task-authoring-preflight-diagnostics.js +8 -0
- package/dist/lib/long-task-authoring-preflight-types.d.ts +2 -0
- package/dist/lib/long-task-authoring-preflight-types.js +9 -0
- package/dist/lib/long-task-authoring-preflight.js +18 -2
- package/dist/lib/long-task-authority-material-diff.js +4 -0
- package/dist/lib/long-task-authority-materials.js +19 -0
- package/dist/lib/long-task-authority-policy.d.ts +3 -0
- package/dist/lib/long-task-authority-policy.js +3 -0
- package/dist/lib/long-task-authority-revision-details.js +2 -1
- package/dist/lib/long-task-authority-types.d.ts +2 -0
- package/dist/lib/long-task-authority.js +2 -0
- package/dist/lib/long-task-check-runner.js +3 -296
- package/dist/lib/long-task-check-shape.js +6 -1
- package/dist/lib/long-task-claim-definitions.js +1 -3
- package/dist/lib/long-task-claim-semantic-proof-floor.d.ts +3 -0
- package/dist/lib/long-task-claim-semantic-proof-floor.js +78 -0
- package/dist/lib/long-task-claims.d.ts +0 -18
- package/dist/lib/long-task-claims.js +15 -14
- package/dist/lib/long-task-command-process.d.ts +9 -0
- package/dist/lib/long-task-command-process.js +178 -0
- package/dist/lib/long-task-compact-authoring.js +3 -0
- package/dist/lib/long-task-compact-projections.js +10 -0
- package/dist/lib/long-task-complete-delivery-evidence-types.d.ts +38 -0
- package/dist/lib/long-task-complete-delivery-evidence-types.js +1 -0
- package/dist/lib/long-task-completion-types.d.ts +109 -0
- package/dist/lib/long-task-completion-types.js +1 -0
- package/dist/lib/long-task-conformance-policy.d.ts +2 -1
- package/dist/lib/long-task-conformance-policy.js +11 -4
- package/dist/lib/long-task-context-authority-topology.js +6 -4
- package/dist/lib/long-task-contract-types.d.ts +52 -1
- package/dist/lib/long-task-counterfactual-sandbox.d.ts +7 -1
- package/dist/lib/long-task-counterfactual-sandbox.js +86 -6
- package/dist/lib/long-task-delivery-compiler-preflight.d.ts +24 -0
- package/dist/lib/long-task-delivery-compiler-preflight.js +32 -0
- package/dist/lib/long-task-delivery-compiler.d.ts +1 -0
- package/dist/lib/long-task-delivery-compiler.js +59 -44
- package/dist/lib/long-task-delivery-parser.d.ts +3 -0
- package/dist/lib/long-task-delivery-parser.js +26 -8
- package/dist/lib/long-task-delivery-types.d.ts +2 -0
- package/dist/lib/long-task-delivery-types.js +2 -0
- package/dist/lib/long-task-delivery-validation.d.ts +11 -3
- package/dist/lib/long-task-delivery-validation.js +23 -8
- package/dist/lib/long-task-design-feasibility-binding-owners.d.ts +6 -0
- package/dist/lib/long-task-design-feasibility-binding-owners.js +52 -0
- package/dist/lib/long-task-design-feasibility-binding.d.ts +14 -0
- package/dist/lib/long-task-design-feasibility-binding.js +114 -0
- package/dist/lib/long-task-design-feasibility-source-closure.d.ts +11 -0
- package/dist/lib/long-task-design-feasibility-source-closure.js +87 -0
- package/dist/lib/long-task-design-obligation.d.ts +50 -0
- package/dist/lib/long-task-design-obligation.js +99 -0
- package/dist/lib/long-task-design-resource-handoff.d.ts +5 -3
- package/dist/lib/long-task-design-resource-handoff.js +64 -4
- package/dist/lib/long-task-design-resource-method-binding.js +20 -2
- package/dist/lib/long-task-effective-external-takeover.d.ts +15 -0
- package/dist/lib/long-task-effective-external-takeover.js +109 -0
- package/dist/lib/long-task-effective-external-ui-takeover.d.ts +5 -0
- package/dist/lib/long-task-effective-external-ui-takeover.js +117 -0
- package/dist/lib/long-task-evidence-capability-codec.js +91 -0
- package/dist/lib/long-task-evidence-capability-runtime.js +62 -14
- package/dist/lib/long-task-evidence-capability-types.d.ts +3 -2
- package/dist/lib/long-task-evidence-v2.d.ts +6 -1
- package/dist/lib/long-task-evidence-v2.js +253 -170
- package/dist/lib/long-task-execution-observation.d.ts +7 -0
- package/dist/lib/long-task-execution-observation.js +21 -4
- package/dist/lib/long-task-expected-authority.d.ts +4 -0
- package/dist/lib/long-task-expected-authority.js +126 -0
- package/dist/lib/long-task-external-confirmation-artifacts.d.ts +9 -0
- package/dist/lib/long-task-external-confirmation-artifacts.js +138 -0
- package/dist/lib/long-task-external-confirmation-attestation.d.ts +20 -0
- package/dist/lib/long-task-external-confirmation-attestation.js +115 -0
- package/dist/lib/long-task-external-confirmation-challenge.d.ts +23 -0
- package/dist/lib/long-task-external-confirmation-challenge.js +164 -0
- package/dist/lib/long-task-external-confirmation-context.d.ts +14 -0
- package/dist/lib/long-task-external-confirmation-context.js +53 -0
- package/dist/lib/long-task-external-confirmation-evaluation.d.ts +11 -0
- package/dist/lib/long-task-external-confirmation-evaluation.js +454 -0
- package/dist/lib/long-task-external-confirmation-expected.d.ts +8 -0
- package/dist/lib/long-task-external-confirmation-expected.js +200 -0
- package/dist/lib/long-task-external-confirmation-identity.d.ts +10 -0
- package/dist/lib/long-task-external-confirmation-identity.js +77 -0
- package/dist/lib/long-task-external-confirmation-plan.d.ts +25 -0
- package/dist/lib/long-task-external-confirmation-plan.js +148 -0
- package/dist/lib/long-task-external-confirmation-preparation.d.ts +4 -0
- package/dist/lib/long-task-external-confirmation-preparation.js +100 -0
- package/dist/lib/long-task-external-confirmation-shape.d.ts +8 -0
- package/dist/lib/long-task-external-confirmation-shape.js +387 -0
- package/dist/lib/long-task-external-confirmation-state.d.ts +10 -0
- package/dist/lib/long-task-external-confirmation-state.js +109 -0
- package/dist/lib/long-task-external-confirmation-types.d.ts +195 -0
- package/dist/lib/long-task-external-confirmation-types.js +1 -0
- package/dist/lib/long-task-final-integrity.d.ts +2 -0
- package/dist/lib/long-task-final-integrity.js +21 -10
- package/dist/lib/long-task-final-v2.d.ts +7 -2
- package/dist/lib/long-task-final-v2.js +179 -55
- package/dist/lib/long-task-finalization-identity.d.ts +27 -0
- package/dist/lib/long-task-finalization-identity.js +58 -0
- package/dist/lib/long-task-finding-context.d.ts +1 -1
- package/dist/lib/long-task-finding-context.js +139 -13
- package/dist/lib/long-task-freshness.d.ts +27 -0
- package/dist/lib/long-task-freshness.js +129 -6
- package/dist/lib/long-task-git.js +3 -3
- package/dist/lib/long-task-material-input-closure.d.ts +3 -0
- package/dist/lib/long-task-material-input-closure.js +92 -0
- package/dist/lib/long-task-obligation-authority-resolution.d.ts +12 -0
- package/dist/lib/long-task-obligation-authority-resolution.js +57 -0
- package/dist/lib/long-task-obligation-semantic-identity.d.ts +16 -0
- package/dist/lib/long-task-obligation-semantic-identity.js +116 -0
- package/dist/lib/long-task-observation-authority.d.ts +11 -0
- package/dist/lib/long-task-observation-authority.js +137 -6
- package/dist/lib/long-task-process-table.d.ts +9 -0
- package/dist/lib/long-task-process-table.js +87 -0
- package/dist/lib/long-task-process-tree.d.ts +8 -0
- package/dist/lib/long-task-process-tree.js +108 -0
- package/dist/lib/long-task-proof-adequacy.d.ts +12 -0
- package/dist/lib/long-task-proof-adequacy.js +57 -0
- package/dist/lib/long-task-proof-capability-floor.d.ts +6 -0
- package/dist/lib/long-task-proof-capability-floor.js +137 -0
- package/dist/lib/long-task-protected-files.d.ts +1 -1
- package/dist/lib/long-task-protected-files.js +1 -1
- package/dist/lib/long-task-repair-frontier-checks.d.ts +8 -0
- package/dist/lib/long-task-repair-frontier-checks.js +93 -0
- package/dist/lib/long-task-repair-frontier-groups.d.ts +2 -0
- package/dist/lib/long-task-repair-frontier-groups.js +64 -0
- package/dist/lib/long-task-repair-frontier-utils.d.ts +6 -0
- package/dist/lib/long-task-repair-frontier-utils.js +27 -0
- package/dist/lib/long-task-repair-frontier.d.ts +14 -0
- package/dist/lib/long-task-repair-frontier.js +132 -0
- package/dist/lib/long-task-risk.d.ts +3 -2
- package/dist/lib/long-task-risk.js +73 -24
- package/dist/lib/long-task-root-shape.js +148 -8
- package/dist/lib/long-task-runner-freeze.d.ts +2 -1
- package/dist/lib/long-task-runner-freeze.js +23 -8
- package/dist/lib/long-task-runtime-types.d.ts +34 -40
- package/dist/lib/long-task-semantic-assurance-policy.js +2 -11
- package/dist/lib/long-task-semantic-contract-types.d.ts +2 -1
- package/dist/lib/long-task-semantic-drift-migration.js +48 -2
- package/dist/lib/long-task-semantic-fact-binding-types.d.ts +20 -0
- package/dist/lib/long-task-semantic-fact-closure.d.ts +5 -1
- package/dist/lib/long-task-semantic-fact-closure.js +33 -5
- package/dist/lib/long-task-semantic-fact-contract-closure.js +176 -1
- package/dist/lib/long-task-semantic-fact-contract-proofs.js +18 -1
- package/dist/lib/long-task-semantic-fact-input-closure.d.ts +16 -2
- package/dist/lib/long-task-semantic-fact-input-closure.js +138 -15
- package/dist/lib/long-task-semantic-fact-provenance-closure.js +1 -1
- package/dist/lib/long-task-semantic-fact-shape.d.ts +2 -1
- package/dist/lib/long-task-semantic-fact-shape.js +35 -1
- package/dist/lib/long-task-semantic-proof-adequacy.d.ts +2 -0
- package/dist/lib/long-task-semantic-proof-adequacy.js +19 -0
- package/dist/lib/long-task-semantic-proof-profile.d.ts +5 -0
- package/dist/lib/long-task-semantic-proof-profile.js +187 -0
- package/dist/lib/long-task-shape-primitives.d.ts +1 -1
- package/dist/lib/long-task-shape-primitives.js +5 -0
- package/dist/lib/long-task-source-anchors.d.ts +10 -0
- package/dist/lib/long-task-source-anchors.js +102 -0
- package/dist/lib/long-task-source-authority-types.d.ts +46 -0
- package/dist/lib/long-task-source-claim-validation.js +36 -0
- package/dist/lib/long-task-source-conservation-facts.d.ts +8 -0
- package/dist/lib/long-task-source-conservation-facts.js +57 -0
- package/dist/lib/long-task-source-conservation-types.d.ts +34 -0
- package/dist/lib/long-task-source-conservation-types.js +1 -0
- package/dist/lib/long-task-source-conservation.d.ts +7 -0
- package/dist/lib/long-task-source-conservation.js +110 -0
- package/dist/lib/long-task-source-fragments.d.ts +6 -0
- package/dist/lib/long-task-source-fragments.js +219 -0
- package/dist/lib/long-task-source-projection-resolution.d.ts +5 -0
- package/dist/lib/long-task-source-projection-resolution.js +57 -0
- package/dist/lib/long-task-source-projection-validation.d.ts +17 -0
- package/dist/lib/long-task-source-projection-validation.js +154 -0
- package/dist/lib/long-task-source-shape.js +14 -6
- package/dist/lib/long-task-source-supersession.d.ts +5 -0
- package/dist/lib/long-task-source-supersession.js +138 -0
- package/dist/lib/long-task-stage-policy.d.ts +7 -2
- package/dist/lib/long-task-stage-policy.js +67 -23
- package/dist/lib/long-task-state.d.ts +18 -4
- package/dist/lib/long-task-state.js +319 -33
- package/dist/lib/long-task-static-observation-freeze.js +4 -3
- package/dist/lib/long-task-status-projection.d.ts +3 -1
- package/dist/lib/long-task-status-projection.js +44 -13
- package/dist/lib/long-task-status-v2.d.ts +10 -6
- package/dist/lib/long-task-status-v2.js +70 -58
- package/dist/lib/long-task-target-policy.d.ts +8 -3
- package/dist/lib/long-task-target-policy.js +40 -9
- package/dist/lib/long-task-terminal-finalization.d.ts +12 -0
- package/dist/lib/long-task-terminal-finalization.js +190 -0
- package/dist/lib/long-task-ui-design-policy.js +15 -4
- package/dist/lib/long-task-ui-surface-policy.d.ts +2 -1
- package/dist/lib/long-task-ui-surface-policy.js +7 -4
- package/dist/lib/long-task-ui-surface-validation.d.ts +3 -1
- package/dist/lib/long-task-ui-surface-validation.js +2 -2
- package/dist/lib/long-task-verifier-counterfactuals.d.ts +11 -0
- package/dist/lib/long-task-verifier-counterfactuals.js +96 -0
- package/dist/lib/long-task-verifier-execution.d.ts +9 -0
- package/dist/lib/long-task-verifier-execution.js +67 -0
- package/dist/lib/long-task-verifier-identity.js +16 -5
- package/dist/lib/long-task-verifier-v2.js +52 -65
- package/dist/lib/long-task-windows-job-supervisor-helper.d.ts +1 -0
- package/dist/lib/long-task-windows-job-supervisor-helper.js +104 -0
- package/dist/lib/long-task-windows-job-supervisor-protocol.d.ts +28 -0
- package/dist/lib/long-task-windows-job-supervisor-protocol.js +124 -0
- package/dist/lib/long-task-windows-job-supervisor-result.d.ts +11 -0
- package/dist/lib/long-task-windows-job-supervisor-result.js +152 -0
- package/dist/lib/long-task-windows-job-supervisor.d.ts +2 -0
- package/dist/lib/long-task-windows-job-supervisor.js +126 -0
- package/dist/lib/long-task-workspace-scope.d.ts +1 -0
- package/dist/lib/long-task-workspace-scope.js +4 -1
- package/dist/lib/long-task-workspace.d.ts +1 -0
- package/dist/lib/long-task-workspace.js +10 -0
- package/dist/lib/migrations.js +43 -2
- package/dist/lib/repository-path-safety.d.ts +3 -0
- package/dist/lib/repository-path-safety.js +39 -3
- package/dist/lib/semantic-fact-input-shape.d.ts +7 -2
- package/dist/lib/semantic-fact-input-shape.js +25 -1
- package/dist/lib/semantic-fact-inventory-types.d.ts +8 -2
- package/dist/lib/semantic-fact-policy-census.d.ts +1 -1
- package/dist/lib/semantic-fact-policy-census.js +5 -2
- package/dist/lib/semantic-fact-policy.d.ts +1 -1
- package/dist/lib/semantic-fact-policy.js +2 -2
- package/dist/lib/semantic-fact-proof-shape.d.ts +1 -1
- package/dist/lib/semantic-fact-property-shape.d.ts +1 -1
- package/dist/lib/validators.d.ts +3 -0
- package/dist/lib/validators.js +45 -157
- package/dist/public-api-core.d.ts +12 -0
- package/dist/public-api-core.js +12 -0
- package/dist/public-api-long-task.d.ts +10 -0
- package/dist/public-api-long-task.js +10 -0
- package/dist/public-types.d.ts +6 -1
- package/dist/schemas/design-authority-delta-assessment-v1.schema.json +191 -0
- package/dist/schemas/long-task-delivery-v2/long-task-delivery-v2.schema.json +166 -2
- package/dist/schemas/long-task-external-confirmation-record-v1.schema.json +155 -0
- package/dist/schemas/long-task-external-confirmation-record-v2.schema.json +209 -0
- package/migrations/README.md +99 -0
- package/package.json +7 -5
- package/source-mappings.yaml +18 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { controlFieldFacts } from "./long-task-control-fields.js";
|
|
2
|
+
export function resolveExpectedAuthority(contract, outcomeKey, assertion, manifest, expectations) {
|
|
3
|
+
const expectation = expectations.find((item) => item.assertion_ref === assertion.key);
|
|
4
|
+
if (expectation)
|
|
5
|
+
return resolveSemanticFactExpectedAuthority(assertion, expectation);
|
|
6
|
+
const fullClaim = outcomeKey
|
|
7
|
+
? `${outcomeKey}.${assertion.claims[0]}`
|
|
8
|
+
: assertion.claims[0];
|
|
9
|
+
const canonical = `contract-claim:${fullClaim}`;
|
|
10
|
+
const sourceAuthorities = contract.source_claims.filter((source) => sourceClaimRefs(source).includes(fullClaim));
|
|
11
|
+
const declared = assertion.expected_authority_ref;
|
|
12
|
+
let authorityStatement = claimAuthorityStatement(contract, outcomeKey, assertion.claims[0]);
|
|
13
|
+
let resolved = canonical;
|
|
14
|
+
if (declared) {
|
|
15
|
+
const source = sourceAuthorities.find((item) => [item.key, `source:${item.key}`].includes(declared));
|
|
16
|
+
const factRef = declared.startsWith("semantic-fact:")
|
|
17
|
+
? declared.slice("semantic-fact:".length)
|
|
18
|
+
: declared;
|
|
19
|
+
const fact = manifest.facts.find((item) => item.key === factRef);
|
|
20
|
+
if (declared === canonical)
|
|
21
|
+
resolved = canonical;
|
|
22
|
+
else if (source) {
|
|
23
|
+
resolved = `source:${source.key}`;
|
|
24
|
+
authorityStatement = source.statement;
|
|
25
|
+
}
|
|
26
|
+
else if (fact)
|
|
27
|
+
return resolveBoundFactAuthority(contract, outcomeKey, assertion, fact);
|
|
28
|
+
else
|
|
29
|
+
fail("expected_authority_ref_unknown", `${outcomeKey ?? "GLOBAL"}:${assertion.key}:${declared}`);
|
|
30
|
+
}
|
|
31
|
+
if ("expected" in assertion &&
|
|
32
|
+
assertion.expected !== true &&
|
|
33
|
+
assertion.expected !== false &&
|
|
34
|
+
!authorityContainsExpected(authorityStatement, assertion.expected))
|
|
35
|
+
fail("expected_value_not_projected_from_authority", `${outcomeKey ?? "GLOBAL"}:${assertion.key}:${resolved}`);
|
|
36
|
+
return resolved;
|
|
37
|
+
}
|
|
38
|
+
function resolveSemanticFactExpectedAuthority(assertion, expectation) {
|
|
39
|
+
const canonical = `semantic-proof:${expectation.proof_ref}`;
|
|
40
|
+
if (assertion.expected_authority_ref &&
|
|
41
|
+
![
|
|
42
|
+
canonical,
|
|
43
|
+
`semantic-fact:${expectation.fact_ref}`,
|
|
44
|
+
expectation.fact_ref,
|
|
45
|
+
expectation.proof_ref,
|
|
46
|
+
].includes(assertion.expected_authority_ref))
|
|
47
|
+
fail("expected_authority_ref_mismatch", `${assertion.key}:${assertion.expected_authority_ref}:${canonical}`);
|
|
48
|
+
return canonical;
|
|
49
|
+
}
|
|
50
|
+
function resolveBoundFactAuthority(contract, outcomeKey, assertion, fact) {
|
|
51
|
+
if (!semanticFactBoundToAssertion(contract, outcomeKey, assertion, fact.key))
|
|
52
|
+
fail("expected_authority_fact_not_bound_to_claim", `${outcomeKey ?? "GLOBAL"}:${assertion.key}:${fact.key}`);
|
|
53
|
+
if ("expected" in assertion &&
|
|
54
|
+
fact.expected.representation === "inline" &&
|
|
55
|
+
JSON.stringify(assertion.expected) !== JSON.stringify(fact.expected.value))
|
|
56
|
+
fail("expected_authority_value_mismatch", `${assertion.key}:${fact.key}`);
|
|
57
|
+
return `semantic-fact:${fact.key}`;
|
|
58
|
+
}
|
|
59
|
+
function semanticFactBoundToAssertion(contract, outcomeKey, assertion, factRef) {
|
|
60
|
+
if (!outcomeKey || !assertion.applicability_ref)
|
|
61
|
+
return false;
|
|
62
|
+
const outcome = contract.outcomes.find((item) => item.key === outcomeKey);
|
|
63
|
+
return Boolean(outcome?.semantic_fact_bindings.facts.some((binding) => binding.fact_ref === factRef &&
|
|
64
|
+
binding.claim_ref === assertion.claims[0] &&
|
|
65
|
+
binding.applicability_ref === assertion.applicability_ref));
|
|
66
|
+
}
|
|
67
|
+
export function claimAuthorityStatement(contract, outcomeKey, localClaim) {
|
|
68
|
+
return outcomeKey
|
|
69
|
+
? outcomeClaimAuthorityStatement(contract, outcomeKey, localClaim)
|
|
70
|
+
: globalClaimAuthorityStatement(contract, localClaim);
|
|
71
|
+
}
|
|
72
|
+
function globalClaimAuthorityStatement(contract, localClaim) {
|
|
73
|
+
if (localClaim.startsWith("non_goal."))
|
|
74
|
+
return (contract.global.product.non_goals.find((item) => `non_goal.${item.key}` === localClaim)?.statement ?? "");
|
|
75
|
+
if (localClaim.startsWith("constraint."))
|
|
76
|
+
return (contract.global.technical.constraints.find((item) => `constraint.${item.key}` === localClaim)?.statement ?? "");
|
|
77
|
+
return (contract.global.technical.forbidden_shortcuts.find((item) => `forbidden_shortcut.${item.key}` === localClaim)?.statement ?? "");
|
|
78
|
+
}
|
|
79
|
+
function outcomeClaimAuthorityStatement(contract, outcomeKey, localClaim) {
|
|
80
|
+
const outcome = contract.outcomes.find((item) => item.key === outcomeKey);
|
|
81
|
+
if (localClaim === "result")
|
|
82
|
+
return outcome.product.observable_result;
|
|
83
|
+
if (localClaim.startsWith("requirement."))
|
|
84
|
+
return keyedStatement(outcome.product.requirements, "requirement", localClaim);
|
|
85
|
+
if (localClaim.startsWith("control."))
|
|
86
|
+
return controlAuthorityStatement(outcome, localClaim);
|
|
87
|
+
if (localClaim === "control_relation_closure")
|
|
88
|
+
return outcome.product.control_relation_closure.statement;
|
|
89
|
+
if (localClaim.startsWith("control_relation."))
|
|
90
|
+
return keyedStatement(outcome.product.control_relations, "control_relation", localClaim);
|
|
91
|
+
if (localClaim.startsWith("non_completing."))
|
|
92
|
+
return keyedStatement(outcome.product.non_completing_outcomes, "non_completing", localClaim);
|
|
93
|
+
if (localClaim.startsWith("obligation."))
|
|
94
|
+
return keyedStatement(outcome.technical.obligations, "obligation", localClaim);
|
|
95
|
+
if (localClaim.startsWith("forbidden_shortcut."))
|
|
96
|
+
return keyedStatement(outcome.technical.forbidden_shortcuts, "forbidden_shortcut", localClaim);
|
|
97
|
+
return (outcome.semantic_fact_bindings.facts.find((item) => item.claim_ref === localClaim)?.fact_ref ?? "");
|
|
98
|
+
}
|
|
99
|
+
function controlAuthorityStatement(outcome, localClaim) {
|
|
100
|
+
const [, controlKey, field] = localClaim.split(".");
|
|
101
|
+
const control = outcome.product.controls.find((item) => item.key === controlKey);
|
|
102
|
+
return control
|
|
103
|
+
? (controlFieldFacts(control).find((item) => item.claim_field === field)
|
|
104
|
+
?.statement ?? "")
|
|
105
|
+
: "";
|
|
106
|
+
}
|
|
107
|
+
function keyedStatement(rows, prefix, localClaim) {
|
|
108
|
+
return (rows.find((item) => `${prefix}.${item.key}` === localClaim)?.statement ?? "");
|
|
109
|
+
}
|
|
110
|
+
function sourceClaimRefs(source) {
|
|
111
|
+
if (source.disposition.type === "decision_required")
|
|
112
|
+
return [];
|
|
113
|
+
if (source.disposition.type === "outcome_result")
|
|
114
|
+
return [source.disposition.ref];
|
|
115
|
+
return source.disposition.refs;
|
|
116
|
+
}
|
|
117
|
+
function authorityContainsExpected(statement, expected) {
|
|
118
|
+
if (typeof expected === "string")
|
|
119
|
+
return statement.includes(expected);
|
|
120
|
+
if (typeof expected === "number")
|
|
121
|
+
return statement.includes(String(expected));
|
|
122
|
+
return statement.includes(JSON.stringify(expected));
|
|
123
|
+
}
|
|
124
|
+
function fail(code, detail) {
|
|
125
|
+
throw new Error(`delivery_contract_invalid:${code}:${detail}`);
|
|
126
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ExternalConfirmationRecordV2 } from "./long-task-external-confirmation-types.js";
|
|
2
|
+
export declare const MAX_TOTAL_EXTERNAL_CONFIRMATION_ARTIFACT_BYTES: number;
|
|
3
|
+
export declare function externalConfirmationArtifactStoreRef(sha256: string): string;
|
|
4
|
+
export declare function captureAndStoreExternalConfirmationArtifacts(repository: string, workdir: string, snapshots: ExternalConfirmationRecordV2["artifact_snapshots"], options?: {
|
|
5
|
+
max_total_bytes?: number;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
export declare function externalArtifactSnapshotIntegrityIssues(repository: string, workdir: string, snapshots: ExternalConfirmationRecordV2["artifact_snapshots"]): Promise<string[]>;
|
|
8
|
+
export declare function captureStoredExternalConfirmationArtifactIdentities(repository: string, workdir: string, snapshots: ExternalConfirmationRecordV2["artifact_snapshots"]): Promise<Record<string, string>>;
|
|
9
|
+
export declare function externalArtifactIntegrityIssues(repository: string, artifacts: Record<string, string>): Promise<string[]>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { lstat, open, readFile, rename, rm } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { assertProtectedRepositoryFile, assertSafeRepositoryFilePath, ensureSafeRepositoryDirectory, } from "./repository-path-safety.js";
|
|
4
|
+
import { runtimePath } from "./long-task-state.js";
|
|
5
|
+
import { sha256Hex } from "./strict-codec.js";
|
|
6
|
+
const ARTIFACT_STORE_FOLDER = "external-confirmations/artifacts";
|
|
7
|
+
const MAX_ARTIFACT_BYTES = 16 * 1024 * 1024;
|
|
8
|
+
export const MAX_TOTAL_EXTERNAL_CONFIRMATION_ARTIFACT_BYTES = 64 * 1024 * 1024;
|
|
9
|
+
export function externalConfirmationArtifactStoreRef(sha256) {
|
|
10
|
+
if (!/^[a-f0-9]{64}$/u.test(sha256))
|
|
11
|
+
throw new Error(`external_confirmation_artifact_hash_invalid:${sha256}`);
|
|
12
|
+
return `${ARTIFACT_STORE_FOLDER}/${sha256}`;
|
|
13
|
+
}
|
|
14
|
+
export async function captureAndStoreExternalConfirmationArtifacts(repository, workdir, snapshots, options = {}) {
|
|
15
|
+
const captured = [];
|
|
16
|
+
let totalBytes = 0;
|
|
17
|
+
for (const [evidenceRef, snapshot] of Object.entries(snapshots).sort(([left], [right]) => left.localeCompare(right))) {
|
|
18
|
+
const expectedStoreRef = externalConfirmationArtifactStoreRef(snapshot.sha256);
|
|
19
|
+
if (snapshot.store_ref !== expectedStoreRef)
|
|
20
|
+
throw new Error(`external_confirmation_artifact_store_ref_mismatch:${evidenceRef}`);
|
|
21
|
+
if (evidenceRef.startsWith(`${ARTIFACT_STORE_FOLDER}/`))
|
|
22
|
+
throw new Error(`external_confirmation_artifact_source_store_ref_not_allowed:${evidenceRef}`);
|
|
23
|
+
const file = await assertProtectedRepositoryFile(repository, path.resolve(repository, ...evidenceRef.split("/")), `external_confirmation_artifact:${evidenceRef}`);
|
|
24
|
+
const info = await lstat(file);
|
|
25
|
+
if (info.size > MAX_ARTIFACT_BYTES)
|
|
26
|
+
throw new Error(`external_confirmation_artifact_too_large:${evidenceRef}:${info.size}`);
|
|
27
|
+
totalBytes += info.size;
|
|
28
|
+
if (totalBytes >
|
|
29
|
+
(options.max_total_bytes ??
|
|
30
|
+
MAX_TOTAL_EXTERNAL_CONFIRMATION_ARTIFACT_BYTES))
|
|
31
|
+
throw new Error(`external_confirmation_artifacts_total_too_large:${totalBytes}`);
|
|
32
|
+
const bytes = await readFile(file);
|
|
33
|
+
if (bytes.length !== info.size || bytes.length !== snapshot.size_bytes)
|
|
34
|
+
throw new Error(`external_confirmation_artifact_size_mismatch:${evidenceRef}`);
|
|
35
|
+
if (sha256Hex(bytes) !== snapshot.sha256)
|
|
36
|
+
throw new Error(`external_confirmation_artifact_content_mismatch:${evidenceRef}`);
|
|
37
|
+
captured.push({ sha256: snapshot.sha256, bytes });
|
|
38
|
+
}
|
|
39
|
+
const unique = new Map(captured.map((row) => [row.sha256, row.bytes]));
|
|
40
|
+
for (const [sha256, bytes] of unique)
|
|
41
|
+
await storeArtifact(repository, workdir, sha256, bytes);
|
|
42
|
+
}
|
|
43
|
+
export async function externalArtifactSnapshotIntegrityIssues(repository, workdir, snapshots) {
|
|
44
|
+
const issues = [];
|
|
45
|
+
for (const [evidenceRef, snapshot] of Object.entries(snapshots).sort(([left], [right]) => left.localeCompare(right))) {
|
|
46
|
+
const expectedStoreRef = externalConfirmationArtifactStoreRef(snapshot.sha256);
|
|
47
|
+
if (snapshot.store_ref !== expectedStoreRef) {
|
|
48
|
+
issues.push(`artifact_store_ref_mismatch:${evidenceRef}`);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const file = await assertProtectedRepositoryFile(repository, runtimePath(workdir, snapshot.store_ref), `external_confirmation_artifact_snapshot:${evidenceRef}`);
|
|
53
|
+
const info = await lstat(file);
|
|
54
|
+
const bytes = await readFile(file);
|
|
55
|
+
if (info.size !== snapshot.size_bytes ||
|
|
56
|
+
bytes.length !== snapshot.size_bytes)
|
|
57
|
+
issues.push(`artifact_snapshot_size_changed:${evidenceRef}`);
|
|
58
|
+
if (sha256Hex(bytes) !== snapshot.sha256)
|
|
59
|
+
issues.push(`artifact_snapshot_content_changed:${evidenceRef}`);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
issues.push(`artifact_snapshot_invalid:${evidenceRef}:${message(error)}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return issues;
|
|
66
|
+
}
|
|
67
|
+
export async function captureStoredExternalConfirmationArtifactIdentities(repository, workdir, snapshots) {
|
|
68
|
+
const result = {};
|
|
69
|
+
for (const snapshot of Object.values(snapshots).sort((left, right) => left.store_ref.localeCompare(right.store_ref)))
|
|
70
|
+
try {
|
|
71
|
+
const file = await assertProtectedRepositoryFile(repository, runtimePath(workdir, snapshot.store_ref), `external_confirmation_artifact_snapshot:${snapshot.store_ref}`);
|
|
72
|
+
result[snapshot.store_ref] = `sha256:${sha256Hex(await readFile(file))}`;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
result[snapshot.store_ref] = `unavailable:${sha256Hex(`${snapshot.sha256}\0${message(error)}`)}`;
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
// Legacy v1 audit helper. It never establishes fulfillment.
|
|
80
|
+
export async function externalArtifactIntegrityIssues(repository, artifacts) {
|
|
81
|
+
const issues = [];
|
|
82
|
+
for (const [relative, expectedHash] of Object.entries(artifacts)) {
|
|
83
|
+
try {
|
|
84
|
+
const file = await assertProtectedRepositoryFile(repository, path.resolve(repository, ...relative.split("/")), `external_confirmation_artifact:${relative}`);
|
|
85
|
+
const actualHash = sha256Hex(await readFile(file));
|
|
86
|
+
if (actualHash !== expectedHash)
|
|
87
|
+
issues.push(`artifact_content_changed:${relative}`);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
issues.push(`artifact_invalid:${relative}:${message(error)}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return issues;
|
|
94
|
+
}
|
|
95
|
+
async function storeArtifact(repository, workdir, sha256, bytes) {
|
|
96
|
+
const storeRef = externalConfirmationArtifactStoreRef(sha256);
|
|
97
|
+
const folder = runtimePath(workdir, ARTIFACT_STORE_FOLDER);
|
|
98
|
+
await ensureSafeRepositoryDirectory(repository, repositoryRelative(repository, folder), "external_confirmation_artifact_store");
|
|
99
|
+
const target = runtimePath(workdir, storeRef);
|
|
100
|
+
const safe = await assertSafeRepositoryFilePath(repository, repositoryRelative(repository, target), `external_confirmation_artifact_store:${sha256}`, { destinationMayBeAbsent: true });
|
|
101
|
+
if (safe.status) {
|
|
102
|
+
const existing = await readFile(safe.absolute);
|
|
103
|
+
if (sha256Hex(existing) !== sha256 || existing.length !== bytes.length)
|
|
104
|
+
throw new Error(`external_confirmation_artifact_store_collision:${sha256}`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const temporary = `${target}.tmp-${process.pid}-${Date.now()}`;
|
|
108
|
+
const handle = await open(temporary, "wx");
|
|
109
|
+
try {
|
|
110
|
+
await handle.writeFile(bytes);
|
|
111
|
+
await handle.sync();
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
await handle.close().catch(() => undefined);
|
|
115
|
+
await rm(temporary, { force: true });
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
await handle.close();
|
|
119
|
+
try {
|
|
120
|
+
await rename(temporary, target);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
await rm(temporary, { force: true });
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function repositoryRelative(repository, candidate) {
|
|
128
|
+
const relative = path.relative(path.resolve(repository), path.resolve(candidate));
|
|
129
|
+
if (!relative ||
|
|
130
|
+
relative === ".." ||
|
|
131
|
+
relative.startsWith(`..${path.sep}`) ||
|
|
132
|
+
path.isAbsolute(relative))
|
|
133
|
+
throw new Error("external_confirmation_artifact_outside_repository");
|
|
134
|
+
return relative.replace(/\\/gu, "/");
|
|
135
|
+
}
|
|
136
|
+
function message(error) {
|
|
137
|
+
return error instanceof Error ? error.message : String(error);
|
|
138
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CompiledExternalConfirmationIdentityAssuranceV2, DeliveryContractV2, ExternalConfirmationV2 } from "./long-task-contract-types.js";
|
|
2
|
+
import type { CompiledDeliveryContractV2, ContextAuthoritySnapshotV2 } from "./long-task-delivery-types.js";
|
|
3
|
+
import type { ExternalConfirmationActorV1, ExternalConfirmationRecordV2 } from "./long-task-external-confirmation-types.js";
|
|
4
|
+
export declare function compileExternalConfirmationIdentityAssurances(input: {
|
|
5
|
+
contract: DeliveryContractV2;
|
|
6
|
+
repository: string;
|
|
7
|
+
source_hashes: Record<string, string>;
|
|
8
|
+
context_snapshot: ContextAuthoritySnapshotV2;
|
|
9
|
+
}): Promise<Record<string, CompiledExternalConfirmationIdentityAssuranceV2>>;
|
|
10
|
+
export declare function externalConfirmationActor(confirmation: ExternalConfirmationV2): ExternalConfirmationActorV1 | null;
|
|
11
|
+
export declare function compiledExternalConfirmationIdentityAssurance(compiled: CompiledDeliveryContractV2, confirmationRef: string): CompiledExternalConfirmationIdentityAssuranceV2 | null;
|
|
12
|
+
export declare function verifyExternalConfirmationAttestation(input: {
|
|
13
|
+
repository: string;
|
|
14
|
+
confirmation_ref: string;
|
|
15
|
+
assurance: CompiledExternalConfirmationIdentityAssuranceV2 | null;
|
|
16
|
+
record: ExternalConfirmationRecordV2;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
verified: boolean;
|
|
19
|
+
issues: string[];
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { createPublicKey, verify } from "node:crypto";
|
|
2
|
+
import { readFile, stat } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { externalConfirmationV2SignablePayload } from "./long-task-external-confirmation-shape.js";
|
|
5
|
+
import { normalizeContextAuthoritySnapshot } from "./long-task-context-authority.js";
|
|
6
|
+
import { assertProtectedRepositoryFile } from "./repository-path-safety.js";
|
|
7
|
+
import { sha256Hex } from "./strict-codec.js";
|
|
8
|
+
const MAX_PUBLIC_KEY_BYTES = 64 * 1024;
|
|
9
|
+
export async function compileExternalConfirmationIdentityAssurances(input) {
|
|
10
|
+
const result = {};
|
|
11
|
+
const context = normalizeContextAuthoritySnapshot(input.context_snapshot);
|
|
12
|
+
const controllingContext = new Set(context.controlling_files);
|
|
13
|
+
for (const confirmation of input.contract.global.acceptance
|
|
14
|
+
.external_confirmations) {
|
|
15
|
+
const assurance = confirmation.actor?.identity_assurance;
|
|
16
|
+
if (!assurance)
|
|
17
|
+
continue;
|
|
18
|
+
if (assurance.scheme === "declared_only") {
|
|
19
|
+
result[confirmation.key] = assurance;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const expectedHash = input.source_hashes[assurance.public_key_ref] ??
|
|
23
|
+
(controllingContext.has(assurance.public_key_ref)
|
|
24
|
+
? context.sha256[assurance.public_key_ref]
|
|
25
|
+
: undefined);
|
|
26
|
+
if (!expectedHash)
|
|
27
|
+
throw new Error(`external_confirmation_public_key_not_controlling_source:${confirmation.key}:${assurance.public_key_ref}`);
|
|
28
|
+
const file = await assertProtectedRepositoryFile(input.repository, path.resolve(input.repository, ...assurance.public_key_ref.split("/")), `external_confirmation_public_key:${confirmation.key}`);
|
|
29
|
+
const info = await stat(file);
|
|
30
|
+
if (info.size > MAX_PUBLIC_KEY_BYTES)
|
|
31
|
+
throw new Error(`external_confirmation_public_key_too_large:${confirmation.key}:${info.size}`);
|
|
32
|
+
const bytes = await readFile(file);
|
|
33
|
+
const actualHash = sha256Hex(bytes);
|
|
34
|
+
if (actualHash !== expectedHash)
|
|
35
|
+
throw new Error(`external_confirmation_public_key_identity_mismatch:${confirmation.key}`);
|
|
36
|
+
assertEd25519PublicKey(bytes, confirmation.key);
|
|
37
|
+
result[confirmation.key] = {
|
|
38
|
+
...assurance,
|
|
39
|
+
public_key_sha256: actualHash,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return Object.fromEntries(Object.entries(result).sort(([left], [right]) => left.localeCompare(right)));
|
|
43
|
+
}
|
|
44
|
+
export function externalConfirmationActor(confirmation) {
|
|
45
|
+
if (!confirmation.actor)
|
|
46
|
+
return null;
|
|
47
|
+
return {
|
|
48
|
+
id: confirmation.actor.id,
|
|
49
|
+
role: confirmation.actor.role,
|
|
50
|
+
authority_kind: confirmation.actor.authority_kind,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function compiledExternalConfirmationIdentityAssurance(compiled, confirmationRef) {
|
|
54
|
+
return (compiled.external_confirmation_identity_assurances?.[confirmationRef] ??
|
|
55
|
+
null);
|
|
56
|
+
}
|
|
57
|
+
export async function verifyExternalConfirmationAttestation(input) {
|
|
58
|
+
const issues = [];
|
|
59
|
+
const assurance = input.assurance;
|
|
60
|
+
if (!assurance || assurance.scheme !== "ed25519")
|
|
61
|
+
return {
|
|
62
|
+
verified: false,
|
|
63
|
+
issues: ["blocking_actor_identity_not_ed25519"],
|
|
64
|
+
};
|
|
65
|
+
if (input.record.attestation.scheme !== assurance.scheme)
|
|
66
|
+
issues.push("attestation_scheme_mismatch");
|
|
67
|
+
if (input.record.attestation.key_id !== assurance.key_id)
|
|
68
|
+
issues.push("attestation_key_id_mismatch");
|
|
69
|
+
let publicKeyBytes;
|
|
70
|
+
try {
|
|
71
|
+
const file = await assertProtectedRepositoryFile(input.repository, path.resolve(input.repository, ...assurance.public_key_ref.split("/")), `external_confirmation_public_key:${input.confirmation_ref}`);
|
|
72
|
+
const info = await stat(file);
|
|
73
|
+
if (info.size > MAX_PUBLIC_KEY_BYTES)
|
|
74
|
+
throw new Error(`public_key_too_large:${info.size}`);
|
|
75
|
+
publicKeyBytes = await readFile(file);
|
|
76
|
+
if (sha256Hex(publicKeyBytes) !== assurance.public_key_sha256)
|
|
77
|
+
issues.push("public_key_identity_stale");
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
issues.push(`public_key_invalid:${message(error)}`);
|
|
81
|
+
return { verified: false, issues };
|
|
82
|
+
}
|
|
83
|
+
if (issues.length)
|
|
84
|
+
return { verified: false, issues };
|
|
85
|
+
try {
|
|
86
|
+
const key = assertEd25519PublicKey(publicKeyBytes, input.confirmation_ref);
|
|
87
|
+
const signature = Buffer.from(input.record.attestation.signature_base64, "base64");
|
|
88
|
+
const verified = verify(null, Buffer.from(externalConfirmationV2SignablePayload(input.record), "utf8"), key, signature);
|
|
89
|
+
return {
|
|
90
|
+
verified,
|
|
91
|
+
issues: verified ? [] : ["attestation_signature_invalid"],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
return {
|
|
96
|
+
verified: false,
|
|
97
|
+
issues: [`attestation_verification_failed:${message(error)}`],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function assertEd25519PublicKey(bytes, confirmationRef) {
|
|
102
|
+
let key;
|
|
103
|
+
try {
|
|
104
|
+
key = createPublicKey(bytes);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
throw new Error(`external_confirmation_public_key_invalid:${confirmationRef}:${message(error)}`);
|
|
108
|
+
}
|
|
109
|
+
if (key.type !== "public" || key.asymmetricKeyType !== "ed25519")
|
|
110
|
+
throw new Error(`external_confirmation_public_key_not_ed25519:${confirmationRef}`);
|
|
111
|
+
return key;
|
|
112
|
+
}
|
|
113
|
+
function message(error) {
|
|
114
|
+
return error instanceof Error ? error.message : String(error);
|
|
115
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CompiledDeliveryContractV2 } from "./long-task-delivery-types.js";
|
|
2
|
+
export interface ExternalConfirmationChallengeV1 {
|
|
3
|
+
schema_version: "long-task-external-confirmation-challenge-v1";
|
|
4
|
+
confirmation_ref: string;
|
|
5
|
+
compiled_identity: string;
|
|
6
|
+
authority_revision: number;
|
|
7
|
+
challenge: string;
|
|
8
|
+
rotated_at: string;
|
|
9
|
+
challenge_state_sha256: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ExternalConfirmationChallengeContext {
|
|
12
|
+
repository: string;
|
|
13
|
+
workdir: string;
|
|
14
|
+
compiled: Pick<CompiledDeliveryContractV2, "compiled_identity" | "authority_revision">;
|
|
15
|
+
}
|
|
16
|
+
export declare function externalConfirmationChallengePath(workdir: string, confirmationRef: string): string;
|
|
17
|
+
export declare function readOrCreateExternalConfirmationChallenge(context: ExternalConfirmationChallengeContext, confirmationRef: string): Promise<ExternalConfirmationChallengeV1>;
|
|
18
|
+
export declare function rotateExternalConfirmationChallenge(context: ExternalConfirmationChallengeContext, confirmationRef: string): Promise<ExternalConfirmationChallengeV1>;
|
|
19
|
+
export declare function readExternalConfirmationChallenge(repository: string, workdir: string, confirmationRef: string): Promise<{
|
|
20
|
+
challenge: ExternalConfirmationChallengeV1 | null;
|
|
21
|
+
error: string | null;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function captureStoredExternalConfirmationChallengeIdentities(repository: string, workdir: string, confirmationRefs: readonly string[]): Promise<Record<string, string>>;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { lstat, open, readFile, rename, rm } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { assertProtectedRepositoryFile, assertSafeRepositoryFilePath, ensureSafeRepositoryDirectory, } from "./repository-path-safety.js";
|
|
5
|
+
import { runtimePath } from "./long-task-state.js";
|
|
6
|
+
import { canonicalJson, canonicalValueJson, sha256Hex, } from "./strict-codec.js";
|
|
7
|
+
const CHALLENGE_FOLDER = "external-confirmations/challenges";
|
|
8
|
+
const MAX_CHALLENGE_RECORD_BYTES = 16 * 1024;
|
|
9
|
+
const HASH = /^[a-f0-9]{64}$/u;
|
|
10
|
+
const CHALLENGE = /^[A-Za-z0-9_-]{43}$/u;
|
|
11
|
+
export function externalConfirmationChallengePath(workdir, confirmationRef) {
|
|
12
|
+
assertConfirmationKey(confirmationRef);
|
|
13
|
+
return runtimePath(workdir, `${CHALLENGE_FOLDER}/${confirmationRef}.json`);
|
|
14
|
+
}
|
|
15
|
+
export async function readOrCreateExternalConfirmationChallenge(context, confirmationRef) {
|
|
16
|
+
const current = await readExternalConfirmationChallenge(context.repository, context.workdir, confirmationRef);
|
|
17
|
+
if (current.error)
|
|
18
|
+
throw new Error(`external_confirmation_challenge_invalid:${confirmationRef}:${current.error}`);
|
|
19
|
+
if (current.challenge &&
|
|
20
|
+
current.challenge.compiled_identity ===
|
|
21
|
+
context.compiled.compiled_identity &&
|
|
22
|
+
current.challenge.authority_revision === context.compiled.authority_revision)
|
|
23
|
+
return current.challenge;
|
|
24
|
+
return rotateExternalConfirmationChallenge(context, confirmationRef);
|
|
25
|
+
}
|
|
26
|
+
export async function rotateExternalConfirmationChallenge(context, confirmationRef) {
|
|
27
|
+
const unsigned = {
|
|
28
|
+
schema_version: "long-task-external-confirmation-challenge-v1",
|
|
29
|
+
confirmation_ref: confirmationRef,
|
|
30
|
+
compiled_identity: context.compiled.compiled_identity,
|
|
31
|
+
authority_revision: context.compiled.authority_revision,
|
|
32
|
+
challenge: randomBytes(32).toString("base64url"),
|
|
33
|
+
rotated_at: new Date().toISOString(),
|
|
34
|
+
};
|
|
35
|
+
const record = parseChallenge({
|
|
36
|
+
...unsigned,
|
|
37
|
+
challenge_state_sha256: sha256Hex(canonicalValueJson(unsigned)),
|
|
38
|
+
});
|
|
39
|
+
await writeChallenge(context.repository, context.workdir, record);
|
|
40
|
+
return record;
|
|
41
|
+
}
|
|
42
|
+
export async function readExternalConfirmationChallenge(repository, workdir, confirmationRef) {
|
|
43
|
+
const file = externalConfirmationChallengePath(workdir, confirmationRef);
|
|
44
|
+
const status = await lstat(file).catch((error) => {
|
|
45
|
+
if (error.code === "ENOENT")
|
|
46
|
+
return null;
|
|
47
|
+
throw error;
|
|
48
|
+
});
|
|
49
|
+
if (!status)
|
|
50
|
+
return { challenge: null, error: null };
|
|
51
|
+
try {
|
|
52
|
+
const protectedFile = await assertProtectedRepositoryFile(repository, file, `external_confirmation_challenge:${confirmationRef}`);
|
|
53
|
+
if (status.size > MAX_CHALLENGE_RECORD_BYTES)
|
|
54
|
+
throw new Error(`challenge_record_too_large:${status.size}`);
|
|
55
|
+
return {
|
|
56
|
+
challenge: parseChallenge(JSON.parse(await readFile(protectedFile, "utf8"))),
|
|
57
|
+
error: null,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
return { challenge: null, error: message(error) };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export async function captureStoredExternalConfirmationChallengeIdentities(repository, workdir, confirmationRefs) {
|
|
65
|
+
const result = {};
|
|
66
|
+
for (const confirmationRef of [...new Set(confirmationRefs)].sort()) {
|
|
67
|
+
const file = externalConfirmationChallengePath(workdir, confirmationRef);
|
|
68
|
+
const status = await lstat(file).catch((error) => {
|
|
69
|
+
if (error.code === "ENOENT")
|
|
70
|
+
return null;
|
|
71
|
+
throw error;
|
|
72
|
+
});
|
|
73
|
+
if (!status) {
|
|
74
|
+
result[confirmationRef] = "absent";
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const protectedFile = await assertProtectedRepositoryFile(repository, file, `external_confirmation_challenge:${confirmationRef}`);
|
|
78
|
+
result[confirmationRef] =
|
|
79
|
+
`sha256:${sha256Hex(await readFile(protectedFile))}`;
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
async function writeChallenge(repository, workdir, record) {
|
|
84
|
+
const file = externalConfirmationChallengePath(workdir, record.confirmation_ref);
|
|
85
|
+
await ensureSafeRepositoryDirectory(repository, repositoryRelative(repository, path.dirname(file)), `external_confirmation_challenge_folder:${record.confirmation_ref}`);
|
|
86
|
+
await assertSafeRepositoryFilePath(repository, repositoryRelative(repository, file), `external_confirmation_challenge:${record.confirmation_ref}`, { destinationMayBeAbsent: true });
|
|
87
|
+
const temporary = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
88
|
+
const handle = await open(temporary, "wx");
|
|
89
|
+
try {
|
|
90
|
+
await handle.writeFile(canonicalJson(record), "utf8");
|
|
91
|
+
await handle.sync();
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
await handle.close().catch(() => undefined);
|
|
95
|
+
await rm(temporary, { force: true });
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
await handle.close();
|
|
99
|
+
try {
|
|
100
|
+
await rename(temporary, file);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
await rm(temporary, { force: true });
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function parseChallenge(value) {
|
|
108
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
109
|
+
throw new Error("challenge_record_not_object");
|
|
110
|
+
const row = value;
|
|
111
|
+
const expectedKeys = [
|
|
112
|
+
"schema_version",
|
|
113
|
+
"confirmation_ref",
|
|
114
|
+
"compiled_identity",
|
|
115
|
+
"authority_revision",
|
|
116
|
+
"challenge",
|
|
117
|
+
"rotated_at",
|
|
118
|
+
"challenge_state_sha256",
|
|
119
|
+
];
|
|
120
|
+
const actualKeys = Object.keys(row).sort();
|
|
121
|
+
if (actualKeys.join("\0") !== [...expectedKeys].sort().join("\0"))
|
|
122
|
+
throw new Error("challenge_record_keys_invalid");
|
|
123
|
+
if (row.schema_version !== "long-task-external-confirmation-challenge-v1")
|
|
124
|
+
throw new Error("challenge_record_schema_invalid");
|
|
125
|
+
if (typeof row.confirmation_ref !== "string" ||
|
|
126
|
+
!/^[a-z0-9][a-z0-9-]*$/u.test(row.confirmation_ref))
|
|
127
|
+
throw new Error("challenge_confirmation_ref_invalid");
|
|
128
|
+
if (typeof row.compiled_identity !== "string" ||
|
|
129
|
+
!HASH.test(row.compiled_identity))
|
|
130
|
+
throw new Error("challenge_compiled_identity_invalid");
|
|
131
|
+
if (!Number.isSafeInteger(row.authority_revision) ||
|
|
132
|
+
row.authority_revision < 0)
|
|
133
|
+
throw new Error("challenge_authority_revision_invalid");
|
|
134
|
+
if (typeof row.challenge !== "string" || !CHALLENGE.test(row.challenge))
|
|
135
|
+
throw new Error("challenge_value_invalid");
|
|
136
|
+
if (typeof row.rotated_at !== "string" ||
|
|
137
|
+
!Number.isFinite(Date.parse(row.rotated_at)) ||
|
|
138
|
+
new Date(Date.parse(row.rotated_at)).toISOString() !== row.rotated_at)
|
|
139
|
+
throw new Error("challenge_timestamp_invalid");
|
|
140
|
+
if (typeof row.challenge_state_sha256 !== "string" ||
|
|
141
|
+
!HASH.test(row.challenge_state_sha256))
|
|
142
|
+
throw new Error("challenge_state_hash_invalid");
|
|
143
|
+
const record = row;
|
|
144
|
+
const { challenge_state_sha256: _hash, ...unsigned } = record;
|
|
145
|
+
if (sha256Hex(canonicalValueJson(unsigned)) !== record.challenge_state_sha256)
|
|
146
|
+
throw new Error("challenge_state_integrity_mismatch");
|
|
147
|
+
return record;
|
|
148
|
+
}
|
|
149
|
+
function repositoryRelative(repository, candidate) {
|
|
150
|
+
const relative = path.relative(path.resolve(repository), path.resolve(candidate));
|
|
151
|
+
if (!relative ||
|
|
152
|
+
relative === ".." ||
|
|
153
|
+
relative.startsWith(`..${path.sep}`) ||
|
|
154
|
+
path.isAbsolute(relative))
|
|
155
|
+
throw new Error("external_confirmation_challenge_outside_repository");
|
|
156
|
+
return relative.replace(/\\/gu, "/");
|
|
157
|
+
}
|
|
158
|
+
function assertConfirmationKey(value) {
|
|
159
|
+
if (!/^[a-z0-9][a-z0-9-]*$/u.test(value))
|
|
160
|
+
throw new Error(`external_confirmation_key_invalid:${value}`);
|
|
161
|
+
}
|
|
162
|
+
function message(error) {
|
|
163
|
+
return error instanceof Error ? error.message : String(error);
|
|
164
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CompiledDeliveryContractV2, WorkspaceManifestV2 } from "./long-task-delivery-types.js";
|
|
2
|
+
import type { ExternalConfirmationCandidateV1, ExternalConfirmationRecord } from "./long-task-external-confirmation-types.js";
|
|
3
|
+
import type { SemanticFactManifestV1 } from "./semantic-fact-types.js";
|
|
4
|
+
export interface ExternalAuthorityContextV1 {
|
|
5
|
+
repository: string;
|
|
6
|
+
workdir: string;
|
|
7
|
+
compiled: CompiledDeliveryContractV2;
|
|
8
|
+
manifest: WorkspaceManifestV2;
|
|
9
|
+
candidate: ExternalConfirmationCandidateV1;
|
|
10
|
+
candidate_dirty: string[];
|
|
11
|
+
semantic_manifest: SemanticFactManifestV1;
|
|
12
|
+
}
|
|
13
|
+
export declare function loadExternalAuthorityContext(workdirInput: string, requireCleanCandidate: boolean): Promise<ExternalAuthorityContextV1>;
|
|
14
|
+
export declare function readSubmittedExternalConfirmationRecord(recordPathInput: string): Promise<ExternalConfirmationRecord>;
|