From 888a0dc766bf214f6d33c3a2470ec5b5f3b39438 Mon Sep 17 00:00:00 2001 From: ci Date: Wed, 2 Sep 2026 21:04:58 -0400 Subject: [PATCH] Add corrective core evidence generation --- README.md | 6 + RESTORE.md | 13 + ci/required-files.txt | 11 + control/v1/control-policy-set.json | 2 +- control/v1/credential-policy-decision.json | 2 +- control/v1/credential-policy.jq | 6 +- control/v1/credential-policy.json | 2 +- control/v1/duty-separation-decision.json | 2 +- control/v1/duty-separation-policy.json | 2 +- control/v1/duty-separation.jq | 2 +- control/v1/evidence-integrity-decision.json | 2 +- control/v1/evidence-integrity-policy.json | 2 +- control/v1/evidence-integrity.jq | 2 +- control/v1/kill-switch-decision.json | 2 +- control/v1/kill-switch-policy.json | 2 +- control/v1/risk-gates-decision.json | 2 +- control/v1/risk-gates-policy.json | 2 +- control/v1/risk-gates.jq | 6 +- core/v2/generation-registry.json | 2 +- .../contracts.jq | 85 + .../core-ingress.sh | 1709 +++++++++++++++++ .../modules/profile_graph.jq | 315 +++ .../modules/result_facts.jq | 151 ++ .../modules/result_truth.jq | 376 ++++ .../modules/schema.jq | 395 ++++ .../modules/stage_request.jq | 374 ++++ orchestrator/v1/state-scanner-driver.sh | 4 +- orchestrator/v1/state-scanner-launcher.sh | 20 +- orchestrator/v1/state-scanner.jq | 4 +- scripts/lib/profile-resolution.sh | 2 +- ...fault-claude-code-producer-adapter.test.sh | 8 +- ...ault-codex-native-reviewer-adapter.test.sh | 10 +- .../test/default-github-forge-adapter.test.sh | 10 +- .../orchestrator-reconciliation-plan.test.sh | 9 +- .../test/orchestrator-state-scanner.test.sh | 6 +- scripts/test/portable-core-schema.test.sh | 89 +- ...table-core-v2-evidence-identity-ledger.tsv | 2 + ...portable-core-v2-evidence-identity.test.sh | 249 +++ .../test/portable-core-v2-fake-forge.test.sh | 5 +- 39 files changed, 3840 insertions(+), 53 deletions(-) create mode 100644 core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/contracts.jq create mode 100644 core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/core-ingress.sh create mode 100644 core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/profile_graph.jq create mode 100644 core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/result_facts.jq create mode 100644 core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/result_truth.jq create mode 100644 core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/schema.jq create mode 100644 core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/stage_request.jq create mode 100644 scripts/test/portable-core-v2-evidence-identity-ledger.tsv create mode 100755 scripts/test/portable-core-v2-evidence-identity.test.sh diff --git a/README.md b/README.md index 8c905b5..d2ecf2e 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,12 @@ The stable `scripts/core-contract.sh` wrapper and inactive resolver select this generation together. This is a repo-only compatibility switch. It does not install the resolver, select a live profile, or qualify a real forge. +The v2 registry also carries one complete, unselected evidence-identity correction. +It requires every passed evidence item to come from the exact selected execution; +incident mismatches remain valid only when all evidence is non-passing. The stable +wrapper still selects the prior v2 generation until a separate atomic cutover binds +the corrective generation's reviewed merge and publisher receipt. + ## Inactive fake adapter contract matrix `adapter-tests/v1/` runs a fixed 2×2 producer/forge matrix against one unrelated diff --git a/RESTORE.md b/RESTORE.md index 53c0d2e..6b1a5f8 100644 --- a/RESTORE.md +++ b/RESTORE.md @@ -308,6 +308,19 @@ materialization in a caller-disposable repository. The package is not qualified It grants no credential, network, publish, push, merge, or remote branch-write capability. The switch does not install the resolver or select a live profile. +Restore the complete unselected v2 evidence-identity generation, its dedicated +ledger, and its focused test from the manifest, then run: + +```sh +bash scripts/test/portable-core-v2-evidence-identity.test.sh +``` + +This proof requires passed evidence to retain the exact selected performer, +binding, environment, capability, and metadata projection. It also proves that +all-non-passing incident mismatches remain preservable. The stable wrapper remains +on the prior generation until the separate atomic cutover; this step grants no +authority, qualification, credential, network, activation, or external effect. + Restore every path in the manifest's inactive fake adapter matrix block, then run: ```sh diff --git a/ci/required-files.txt b/ci/required-files.txt index 032e0b7..c4f28e2 100644 --- a/ci/required-files.txt +++ b/ci/required-files.txt @@ -155,6 +155,17 @@ core/v2/generations/g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa9218 core/v2/generations/g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e/modules/stage_request.jq scripts/test/portable-core-v2-fake-forge.test.sh +# Inactive portable core v2 evidence-identity correction +core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/contracts.jq +core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/core-ingress.sh +core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/profile_graph.jq +core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/result_facts.jq +core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/result_truth.jq +core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/schema.jq +core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/stage_request.jq +scripts/test/portable-core-v2-evidence-identity-ledger.tsv +scripts/test/portable-core-v2-evidence-identity.test.sh + # Inactive fake producer/forge adapter contract matrix adapter-tests/v1/runner.sh adapter-tests/v1/contract.jq diff --git a/control/v1/control-policy-set.json b/control/v1/control-policy-set.json index 0385b47..2de2550 100644 --- a/control/v1/control-policy-set.json +++ b/control/v1/control-policy-set.json @@ -1 +1 @@ -{"body":{"activation_state":"inactive","core_contract":{"generation_id":"g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e","package_ref":{"content_id":"core-contract-package.v2","media_type":"application/vnd.ystack.core-contract+json","sha256":"005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716"},"semantic_identity":"core.contracts.v2"},"fail_mode":"closed","policy_version":"v1","sections":[{"decision_ref":{"content_id":"control-decision.credential-policy","media_type":"application/vnd.ystack.control-decision+json","sha256":"006b78ca2a937f77a870f9b5a9a0137c45702c2e6879979d6112025e90176cc0"},"policy_ref":{"content_id":"control-policy.credential-policy","media_type":"application/vnd.ystack.control-policy+json","sha256":"1ca546132d904900e00db532d5f2091336a8dd9f426be591ac7e9d91f47a69f3"},"section_id":"credential-policy"},{"decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"08f8b496a689ab6fefa976de495fa13e1f9d954cd2b33ee44acd3c70022b4697"},"policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"b33a4022c74c8a1ccb06674c080adf2fc106561c426a7d1dd30fdb9865531dbb"},"section_id":"duty-separation"},{"decision_ref":{"content_id":"control-decision.evidence-integrity","media_type":"application/vnd.ystack.control-decision+json","sha256":"2d73d496b1535b6015843ff4c0c250bc77e476532c088ef9d7885ef393849327"},"policy_ref":{"content_id":"control-policy.evidence-integrity","media_type":"application/vnd.ystack.control-policy+json","sha256":"171b89c49c7dd6a58e4c5aa6ca13e8c95d109acf7f67429ecb33fcf1dae7582a"},"section_id":"evidence-integrity"},{"decision_ref":{"content_id":"control-decision.kill-switch","media_type":"application/vnd.ystack.control-decision+json","sha256":"213516a567c9269dcef1085a7fd84a18ab05f61cfc8042be801f1c0725ba27d2"},"policy_ref":{"content_id":"control-policy.kill-switch","media_type":"application/vnd.ystack.control-policy+json","sha256":"60a1171f13fa763076b31c0d65a3a54e70d2af28860e3a6da9ed6bb0038a15f5"},"section_id":"kill-switch"},{"decision_ref":{"content_id":"control-decision.risk-gates","media_type":"application/vnd.ystack.control-decision+json","sha256":"4e7747a495106727a3cda68f8097fae5687425608c3d66d790182e9747359d5b"},"policy_ref":{"content_id":"control-policy.risk-gates","media_type":"application/vnd.ystack.control-policy+json","sha256":"0286be22ec3d3a31be8e2c00c5e57a5b674c3f6b0e6d03c87a670e51e3141bed"},"section_id":"risk-gates"},{"decision_ref":{"content_id":"control-decision.sandbox","media_type":"application/vnd.ystack.control-decision+json","sha256":"c3e89800147d55f7c726ec66c82031915a4220d3eb7867e143f60d7026223bbd"},"policy_ref":{"content_id":"control-policy.sandbox","media_type":"application/vnd.ystack.control-policy+json","sha256":"4afb62e44fd3ad055d157ee23bfcf2917811b9ec05e4923eaa989d95d53c0a5e"},"section_id":"sandbox"}]},"id":"control-policy-set.v1","kind":"control_policy_set","schema_version":1} +{"body":{"activation_state":"inactive","core_contract":{"generation_id":"g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e","package_ref":{"content_id":"core-contract-package.v2","media_type":"application/vnd.ystack.core-contract+json","sha256":"2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c"},"semantic_identity":"core.contracts.v2"},"fail_mode":"closed","policy_version":"v1","sections":[{"decision_ref":{"content_id":"control-decision.credential-policy","media_type":"application/vnd.ystack.control-decision+json","sha256":"3ced3c3795d81d92f87358c8098663011e30589391dd6383179d2bfcfd722a0e"},"policy_ref":{"content_id":"control-policy.credential-policy","media_type":"application/vnd.ystack.control-policy+json","sha256":"62a71718f965ca37d83c6a5cf88c3f2d953092b4c33a1b8c30e2feb2d8ab9a1e"},"section_id":"credential-policy"},{"decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"25a513104dc08de8e22727901555d0a3fb6008dd8b222f7a604ed50734d4e23e"},"policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"6a86ddbe4432dae9e6e3748295b4b1da7280aa7ca410515531d0059ba2e1d566"},"section_id":"duty-separation"},{"decision_ref":{"content_id":"control-decision.evidence-integrity","media_type":"application/vnd.ystack.control-decision+json","sha256":"109d5061bafc4b5e9fa0ef49ec00a9d806e8c085272b8b92f9fc48676226dc94"},"policy_ref":{"content_id":"control-policy.evidence-integrity","media_type":"application/vnd.ystack.control-policy+json","sha256":"e14bf8ccc36d391d4ccab5b64b931cda02e3369cf0bda4e34a4cd4c3b19da662"},"section_id":"evidence-integrity"},{"decision_ref":{"content_id":"control-decision.kill-switch","media_type":"application/vnd.ystack.control-decision+json","sha256":"61cf6af051efe6438bbf58e1db61aca916bb79c9eb54ff1896e3a7a48143a36a"},"policy_ref":{"content_id":"control-policy.kill-switch","media_type":"application/vnd.ystack.control-policy+json","sha256":"6cc216935f62d1a705c8fa4d7ec6fc076d71313b24b2b0fce5ba63243f1ffad2"},"section_id":"kill-switch"},{"decision_ref":{"content_id":"control-decision.risk-gates","media_type":"application/vnd.ystack.control-decision+json","sha256":"be42e1b8387ba51297e60d40043339886606faecaaf134a4fd1ea0fa15db30b3"},"policy_ref":{"content_id":"control-policy.risk-gates","media_type":"application/vnd.ystack.control-policy+json","sha256":"130c4fc32ddabbddc25b12df7c03ec1ad5bb4925915b4bd90375a0a573c7ef0b"},"section_id":"risk-gates"},{"decision_ref":{"content_id":"control-decision.sandbox","media_type":"application/vnd.ystack.control-decision+json","sha256":"c3e89800147d55f7c726ec66c82031915a4220d3eb7867e143f60d7026223bbd"},"policy_ref":{"content_id":"control-policy.sandbox","media_type":"application/vnd.ystack.control-policy+json","sha256":"4afb62e44fd3ad055d157ee23bfcf2917811b9ec05e4923eaa989d95d53c0a5e"},"section_id":"sandbox"}]},"id":"control-policy-set.v1","kind":"control_policy_set","schema_version":1} diff --git a/control/v1/credential-policy-decision.json b/control/v1/credential-policy-decision.json index 81c0bd6..b31673f 100644 --- a/control/v1/credential-policy-decision.json +++ b/control/v1/credential-policy-decision.json @@ -1 +1 @@ -{"body":{"activation_state":"inactive","decision":"allow-observation-only-evaluation","dependencies":{"duty_separation":{"decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"08f8b496a689ab6fefa976de495fa13e1f9d954cd2b33ee44acd3c70022b4697"},"policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"b33a4022c74c8a1ccb06674c080adf2fc106561c426a7d1dd30fdb9865531dbb"}}},"evaluator":{"driver_ref":{"content_id":"control-evaluator-driver.credential-policy.v1","media_type":"text/x-shellscript","sha256":"5c9bab9d00754d63e4ead770489564db8122c53ab1bc8b6e92c27719265c18f7"},"program_ref":{"content_id":"control-evaluator-program.credential-policy.v1","media_type":"text/x-jq","sha256":"a90bcd3c837af1e2f3f8f4867b679f7a699b6257c56306abe098d5c569a27ed2"}},"fail_mode":"closed","policy_ref":{"content_id":"control-policy.credential-policy","media_type":"application/vnd.ystack.control-policy+json","sha256":"1ca546132d904900e00db532d5f2091336a8dd9f426be591ac7e9d91f47a69f3"},"semantics":{"authority_effect":"none","claim_provenance":"unqualified-input-claim","input_contract":"control-policy-set+public-core-stage-run+duty-evaluation+credential-boundary-claim.v1","output_kind":"credential_policy_evaluation","output_schema_version":1,"qualification_effect":"none","reference_semantics":"identity-only","verdicts":["inconclusive","violated"]}},"id":"control-decision.credential-policy","kind":"credential_policy_decision","schema_version":1} +{"body":{"activation_state":"inactive","decision":"allow-observation-only-evaluation","dependencies":{"duty_separation":{"decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"25a513104dc08de8e22727901555d0a3fb6008dd8b222f7a604ed50734d4e23e"},"policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"6a86ddbe4432dae9e6e3748295b4b1da7280aa7ca410515531d0059ba2e1d566"}}},"evaluator":{"driver_ref":{"content_id":"control-evaluator-driver.credential-policy.v1","media_type":"text/x-shellscript","sha256":"5c9bab9d00754d63e4ead770489564db8122c53ab1bc8b6e92c27719265c18f7"},"program_ref":{"content_id":"control-evaluator-program.credential-policy.v1","media_type":"text/x-jq","sha256":"e91ff0b189ea1962baf4d83bfb4da9accbb48e74487c3d3d92417c313a89c8b8"}},"fail_mode":"closed","policy_ref":{"content_id":"control-policy.credential-policy","media_type":"application/vnd.ystack.control-policy+json","sha256":"62a71718f965ca37d83c6a5cf88c3f2d953092b4c33a1b8c30e2feb2d8ab9a1e"},"semantics":{"authority_effect":"none","claim_provenance":"unqualified-input-claim","input_contract":"control-policy-set+public-core-stage-run+duty-evaluation+credential-boundary-claim.v1","output_kind":"credential_policy_evaluation","output_schema_version":1,"qualification_effect":"none","reference_semantics":"identity-only","verdicts":["inconclusive","violated"]}},"id":"control-decision.credential-policy","kind":"credential_policy_decision","schema_version":1} diff --git a/control/v1/credential-policy.jq b/control/v1/credential-policy.jq index e68b4a2..611d1e8 100644 --- a/control/v1/credential-policy.jq +++ b/control/v1/credential-policy.jq @@ -57,7 +57,7 @@ def expected_core: "6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137", package_ref:{content_id:"core-contract-package.v2", media_type:"application/vnd.ystack.core-contract+json", - sha256:"005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716"}}; + sha256:"2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c"}}; def expected_credential_classes: [{credential_class:"model-inference",delivery:"brokered", @@ -81,10 +81,10 @@ def policy_ok: .duty_separation == { decision_ref:{content_id:"control-decision.duty-separation", media_type:"application/vnd.ystack.control-decision+json", - sha256:"08f8b496a689ab6fefa976de495fa13e1f9d954cd2b33ee44acd3c70022b4697"}, + sha256:"25a513104dc08de8e22727901555d0a3fb6008dd8b222f7a604ed50734d4e23e"}, policy_ref:{content_id:"control-policy.duty-separation", media_type:"application/vnd.ystack.control-policy+json", - sha256:"b33a4022c74c8a1ccb06674c080adf2fc106561c426a7d1dd30fdb9865531dbb"}} and + sha256:"6a86ddbe4432dae9e6e3748295b4b1da7280aa7ca410515531d0059ba2e1d566"}} and .evaluation_mode == "observation-only" and .fail_mode == "closed" and .policy_version == "v1" and .protected_roles == diff --git a/control/v1/credential-policy.json b/control/v1/credential-policy.json index 64e2edf..d5db93d 100644 --- a/control/v1/credential-policy.json +++ b/control/v1/credential-policy.json @@ -1 +1 @@ -{"body":{"activation_state":"inactive","claim_provenance":"unqualified-input-claim","core_contract":{"generation_id_sha256":"6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137","package_ref":{"content_id":"core-contract-package.v2","media_type":"application/vnd.ystack.core-contract+json","sha256":"005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716"},"semantic_identity":"core.contracts.v2"},"credential_classes":[{"credential_class":"model-inference","delivery":"brokered","execution_kinds":["model"],"exposure":"none","roles":["producer","reviewer"],"scope":"single-stage"}],"credential_incompatible_permissions":["core.perm.candidate-repository.write.v2","core.perm.candidate.execute.v1"],"duty_separation":{"decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"08f8b496a689ab6fefa976de495fa13e1f9d954cd2b33ee44acd3c70022b4697"},"policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"b33a4022c74c8a1ccb06674c080adf2fc106561c426a7d1dd30fdb9865531dbb"}},"evaluation_mode":"observation-only","fail_mode":"closed","policy_version":"v1","protected_roles":["ci","execution","forge","identity","producer","publisher","reviewer","verifier"],"reference_semantics":"identity-only"},"id":"control-policy.credential-policy","kind":"credential_policy","schema_version":1} +{"body":{"activation_state":"inactive","claim_provenance":"unqualified-input-claim","core_contract":{"generation_id_sha256":"6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137","package_ref":{"content_id":"core-contract-package.v2","media_type":"application/vnd.ystack.core-contract+json","sha256":"2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c"},"semantic_identity":"core.contracts.v2"},"credential_classes":[{"credential_class":"model-inference","delivery":"brokered","execution_kinds":["model"],"exposure":"none","roles":["producer","reviewer"],"scope":"single-stage"}],"credential_incompatible_permissions":["core.perm.candidate-repository.write.v2","core.perm.candidate.execute.v1"],"duty_separation":{"decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"25a513104dc08de8e22727901555d0a3fb6008dd8b222f7a604ed50734d4e23e"},"policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"6a86ddbe4432dae9e6e3748295b4b1da7280aa7ca410515531d0059ba2e1d566"}},"evaluation_mode":"observation-only","fail_mode":"closed","policy_version":"v1","protected_roles":["ci","execution","forge","identity","producer","publisher","reviewer","verifier"],"reference_semantics":"identity-only"},"id":"control-policy.credential-policy","kind":"credential_policy","schema_version":1} diff --git a/control/v1/duty-separation-decision.json b/control/v1/duty-separation-decision.json index f263902..88e87f6 100644 --- a/control/v1/duty-separation-decision.json +++ b/control/v1/duty-separation-decision.json @@ -1 +1 @@ -{"body":{"activation_state":"inactive","decision":"allow-observation-only-evaluation","evaluator":{"driver_ref":{"content_id":"control-evaluator-driver.duty-separation.v1","media_type":"text/x-shellscript","sha256":"146e73dc880d363e889f32140ac375997fb709e3101de32b8d9603f1f38ca0fa"},"policy_set_validator":{"driver_ref":{"content_id":"control-policy-set-validator-driver.v1","media_type":"text/x-shellscript","sha256":"cf173ad0eaa08244bf636e3937845e894b21f14291fc5e66753e8673bdd2bd2a"},"program_ref":{"content_id":"control-policy-set-validator-program.v1","media_type":"text/x-jq","sha256":"2be97550574ee4522fc0bd14780c92dee3c1b455f2c04b7763b0e437665a8d58"}},"program_ref":{"content_id":"control-evaluator-program.duty-separation.v1","media_type":"text/x-jq","sha256":"ea977f36619a199d965c8f525c428dbc2f4d3a58418373529b8a79bc9488b076"}},"fail_mode":"closed","policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"b33a4022c74c8a1ccb06674c080adf2fc106561c426a7d1dd30fdb9865531dbb"},"semantics":{"authority_effect":"none","input_contract":"control-policy-set+public-core-stage-run.v1","output_kind":"duty_separation_evaluation","output_schema_version":1,"reference_semantics":"identity-only","verdicts":["inconclusive","satisfied","violated"]}},"id":"control-decision.duty-separation","kind":"duty_separation_decision","schema_version":1} +{"body":{"activation_state":"inactive","decision":"allow-observation-only-evaluation","evaluator":{"driver_ref":{"content_id":"control-evaluator-driver.duty-separation.v1","media_type":"text/x-shellscript","sha256":"146e73dc880d363e889f32140ac375997fb709e3101de32b8d9603f1f38ca0fa"},"policy_set_validator":{"driver_ref":{"content_id":"control-policy-set-validator-driver.v1","media_type":"text/x-shellscript","sha256":"cf173ad0eaa08244bf636e3937845e894b21f14291fc5e66753e8673bdd2bd2a"},"program_ref":{"content_id":"control-policy-set-validator-program.v1","media_type":"text/x-jq","sha256":"2be97550574ee4522fc0bd14780c92dee3c1b455f2c04b7763b0e437665a8d58"}},"program_ref":{"content_id":"control-evaluator-program.duty-separation.v1","media_type":"text/x-jq","sha256":"755b51ba0ed7d463309d9ab5d30243f60d2847f2370140c2bf3b3b45a63b2611"}},"fail_mode":"closed","policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"6a86ddbe4432dae9e6e3748295b4b1da7280aa7ca410515531d0059ba2e1d566"},"semantics":{"authority_effect":"none","input_contract":"control-policy-set+public-core-stage-run.v1","output_kind":"duty_separation_evaluation","output_schema_version":1,"reference_semantics":"identity-only","verdicts":["inconclusive","satisfied","violated"]}},"id":"control-decision.duty-separation","kind":"duty_separation_decision","schema_version":1} diff --git a/control/v1/duty-separation-policy.json b/control/v1/duty-separation-policy.json index a79d177..b649372 100644 --- a/control/v1/duty-separation-policy.json +++ b/control/v1/duty-separation-policy.json @@ -1 +1 @@ -{"body":{"activation_state":"inactive","core_contract":{"generation_id_sha256":"6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137","package_ref":{"content_id":"core-contract-package.v2","media_type":"application/vnd.ystack.core-contract+json","sha256":"005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716"},"semantic_identity":"core.contracts.v2"},"dormant_roles":["ci","execution","identity","publisher"],"evaluation_mode":"observation-only","fail_mode":"closed","identity_dimensions":["adapter_instance_id","execution_boundary_id","principal_id"],"operation_ceilings":[{"capabilities":["core.forge.materialize-candidate.v2"],"execution_kind":"deterministic","permissions":["core.perm.candidate-repository.write.v2","core.perm.evidence.write.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"role":"forge"},{"capabilities":["core.harness.produce.v1"],"execution_kind":"deterministic","permissions":["core.perm.evidence.write.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"role":"producer"},{"capabilities":["core.harness.produce.v1"],"execution_kind":"model","permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"role":"producer"},{"capabilities":["core.review.change.v1"],"execution_kind":"deterministic","permissions":["core.perm.evidence.write.v1","core.perm.target.read.v1"],"role":"reviewer"},{"capabilities":["core.review.change.v1"],"execution_kind":"model","permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.target.read.v1"],"role":"reviewer"},{"capabilities":["core.verify.run.v1"],"execution_kind":"deterministic","permissions":["core.perm.candidate.execute.v1","core.perm.evidence.write.v1","core.perm.target.read.v1"],"role":"verifier"}],"policy_version":"v1","protected_roles":["forge","producer","publisher","reviewer","verifier"],"reporter_relation":"performer-else-selected","requester_roles":["manager","operator","orchestrator"]},"id":"control-policy.duty-separation","kind":"duty_separation_policy","schema_version":1} +{"body":{"activation_state":"inactive","core_contract":{"generation_id_sha256":"6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137","package_ref":{"content_id":"core-contract-package.v2","media_type":"application/vnd.ystack.core-contract+json","sha256":"2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c"},"semantic_identity":"core.contracts.v2"},"dormant_roles":["ci","execution","identity","publisher"],"evaluation_mode":"observation-only","fail_mode":"closed","identity_dimensions":["adapter_instance_id","execution_boundary_id","principal_id"],"operation_ceilings":[{"capabilities":["core.forge.materialize-candidate.v2"],"execution_kind":"deterministic","permissions":["core.perm.candidate-repository.write.v2","core.perm.evidence.write.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"role":"forge"},{"capabilities":["core.harness.produce.v1"],"execution_kind":"deterministic","permissions":["core.perm.evidence.write.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"role":"producer"},{"capabilities":["core.harness.produce.v1"],"execution_kind":"model","permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"],"role":"producer"},{"capabilities":["core.review.change.v1"],"execution_kind":"deterministic","permissions":["core.perm.evidence.write.v1","core.perm.target.read.v1"],"role":"reviewer"},{"capabilities":["core.review.change.v1"],"execution_kind":"model","permissions":["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.target.read.v1"],"role":"reviewer"},{"capabilities":["core.verify.run.v1"],"execution_kind":"deterministic","permissions":["core.perm.candidate.execute.v1","core.perm.evidence.write.v1","core.perm.target.read.v1"],"role":"verifier"}],"policy_version":"v1","protected_roles":["forge","producer","publisher","reviewer","verifier"],"reporter_relation":"performer-else-selected","requester_roles":["manager","operator","orchestrator"]},"id":"control-policy.duty-separation","kind":"duty_separation_policy","schema_version":1} diff --git a/control/v1/duty-separation.jq b/control/v1/duty-separation.jq index 56540f8..5467976 100644 --- a/control/v1/duty-separation.jq +++ b/control/v1/duty-separation.jq @@ -48,7 +48,7 @@ def policy_ok: generation_id_sha256:"6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137", package_ref:{content_id:"core-contract-package.v2", media_type:"application/vnd.ystack.core-contract+json", - sha256:"005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716"} + sha256:"2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c"} } and .protected_roles == expected_roles and .dormant_roles == expected_dormant and .identity_dimensions == expected_dimensions and diff --git a/control/v1/evidence-integrity-decision.json b/control/v1/evidence-integrity-decision.json index 526d9bb..70f4929 100644 --- a/control/v1/evidence-integrity-decision.json +++ b/control/v1/evidence-integrity-decision.json @@ -1 +1 @@ -{"body":{"activation_state":"inactive","decision":"allow-observation-only-evaluation","evaluator":{"evaluation_payload_ref":{"content_id":"control-evaluator-payload.evidence-integrity.v1","media_type":"text/x-shellscript-fragment","sha256":"79e2a3c8817e19f1e3fc9d5571b68cb1eb15d55b69eb10f5090bb943220d1afc"},"policy_set_validator":{"driver_ref":{"content_id":"control-policy-set-validator-driver.v1","media_type":"text/x-shellscript","sha256":"cf173ad0eaa08244bf636e3937845e894b21f14291fc5e66753e8673bdd2bd2a"},"program_ref":{"content_id":"control-policy-set-validator-program.v1","media_type":"text/x-jq","sha256":"2be97550574ee4522fc0bd14780c92dee3c1b455f2c04b7763b0e437665a8d58"}},"program_ref":{"content_id":"control-evaluator-program.evidence-integrity.v1","media_type":"text/x-jq","sha256":"5b61b900b71e9485072a2d65fe52a221c25d9e270c942d8d3b00ef53aedf117f"},"trusted_launcher_ref":{"content_id":"control-evaluator-launcher.evidence-integrity.v1","media_type":"text/x-shellscript","sha256":"f0ecbe036601102db082d0a94c860ea868614ff79d06f2b37ec8dcd672c367a2"}},"fail_mode":"closed","policy_ref":{"content_id":"control-policy.evidence-integrity","media_type":"application/vnd.ystack.control-policy+json","sha256":"171b89c49c7dd6a58e4c5aa6ca13e8c95d109acf7f67429ecb33fcf1dae7582a"},"semantics":{"authority_effect":"none","candidate_execution":"none","credential_access":"none","input_contract":"control-policy-set+public-core-stage-run+evidence-integrity-presentation.v1","launcher_attestation":"trusted-boundary-not-self-attested","network_access":"none","output_kind":"evidence_integrity_evaluation","output_schema_version":1,"qualification_effect":"none","reference_semantics":"identity-only","storage_effect":"none","verdicts":["satisfied","violated"]}},"id":"control-decision.evidence-integrity","kind":"evidence_integrity_decision","schema_version":1} +{"body":{"activation_state":"inactive","decision":"allow-observation-only-evaluation","evaluator":{"evaluation_payload_ref":{"content_id":"control-evaluator-payload.evidence-integrity.v1","media_type":"text/x-shellscript-fragment","sha256":"79e2a3c8817e19f1e3fc9d5571b68cb1eb15d55b69eb10f5090bb943220d1afc"},"policy_set_validator":{"driver_ref":{"content_id":"control-policy-set-validator-driver.v1","media_type":"text/x-shellscript","sha256":"cf173ad0eaa08244bf636e3937845e894b21f14291fc5e66753e8673bdd2bd2a"},"program_ref":{"content_id":"control-policy-set-validator-program.v1","media_type":"text/x-jq","sha256":"2be97550574ee4522fc0bd14780c92dee3c1b455f2c04b7763b0e437665a8d58"}},"program_ref":{"content_id":"control-evaluator-program.evidence-integrity.v1","media_type":"text/x-jq","sha256":"4280ecc9410b17b898a773aedb7ac7d955ca3b9c6ce8420f15ba255cb55f18df"},"trusted_launcher_ref":{"content_id":"control-evaluator-launcher.evidence-integrity.v1","media_type":"text/x-shellscript","sha256":"f0ecbe036601102db082d0a94c860ea868614ff79d06f2b37ec8dcd672c367a2"}},"fail_mode":"closed","policy_ref":{"content_id":"control-policy.evidence-integrity","media_type":"application/vnd.ystack.control-policy+json","sha256":"e14bf8ccc36d391d4ccab5b64b931cda02e3369cf0bda4e34a4cd4c3b19da662"},"semantics":{"authority_effect":"none","candidate_execution":"none","credential_access":"none","input_contract":"control-policy-set+public-core-stage-run+evidence-integrity-presentation.v1","launcher_attestation":"trusted-boundary-not-self-attested","network_access":"none","output_kind":"evidence_integrity_evaluation","output_schema_version":1,"qualification_effect":"none","reference_semantics":"identity-only","storage_effect":"none","verdicts":["satisfied","violated"]}},"id":"control-decision.evidence-integrity","kind":"evidence_integrity_decision","schema_version":1} diff --git a/control/v1/evidence-integrity-policy.json b/control/v1/evidence-integrity-policy.json index 0d448c0..de69e63 100644 --- a/control/v1/evidence-integrity-policy.json +++ b/control/v1/evidence-integrity-policy.json @@ -1 +1 @@ -{"body":{"activation_state":"inactive","core_contract":{"generation_id_sha256":"6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137","package_ref":{"content_id":"core-contract-package.v2","media_type":"application/vnd.ystack.core-contract+json","sha256":"005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716"},"semantic_identity":"core.contracts.v2"},"evaluation_mode":"observation-only","evidence_contract":{"current_result_binding":"exact-document-digest","presentation_kind":"evidence_integrity_presentation","prior_evidence_binding":"exact-stage-result-digest-and-evidence-id","proof_binding":"content-ref-sha256","qualification_binding":"exact-scope-ref-or-absent"},"fail_mode":"closed","policy_version":"v1","qualification_semantics":"identity-only-unqualified","storage_effect":"none"},"id":"control-policy.evidence-integrity","kind":"evidence_integrity_policy","schema_version":1} +{"body":{"activation_state":"inactive","core_contract":{"generation_id_sha256":"6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137","package_ref":{"content_id":"core-contract-package.v2","media_type":"application/vnd.ystack.core-contract+json","sha256":"2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c"},"semantic_identity":"core.contracts.v2"},"evaluation_mode":"observation-only","evidence_contract":{"current_result_binding":"exact-document-digest","presentation_kind":"evidence_integrity_presentation","prior_evidence_binding":"exact-stage-result-digest-and-evidence-id","proof_binding":"content-ref-sha256","qualification_binding":"exact-scope-ref-or-absent"},"fail_mode":"closed","policy_version":"v1","qualification_semantics":"identity-only-unqualified","storage_effect":"none"},"id":"control-policy.evidence-integrity","kind":"evidence_integrity_policy","schema_version":1} diff --git a/control/v1/evidence-integrity.jq b/control/v1/evidence-integrity.jq index 0acbd8b..bdd9818 100644 --- a/control/v1/evidence-integrity.jq +++ b/control/v1/evidence-integrity.jq @@ -99,7 +99,7 @@ def expected_core: "6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137", package_ref:{content_id:"core-contract-package.v2", media_type:"application/vnd.ystack.core-contract+json", - sha256:"005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716"}}; + sha256:"2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c"}}; def policy_ok: exact(["body","id","kind","schema_version"]) and .schema_version == 1 and diff --git a/control/v1/kill-switch-decision.json b/control/v1/kill-switch-decision.json index d7e3097..c8c445a 100644 --- a/control/v1/kill-switch-decision.json +++ b/control/v1/kill-switch-decision.json @@ -1 +1 @@ -{"body":{"activation_state":"inactive","decision":"allow-observation-only-evaluation","duty_decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"08f8b496a689ab6fefa976de495fa13e1f9d954cd2b33ee44acd3c70022b4697"},"evaluator":{"driver_ref":{"content_id":"control-evaluator-driver.kill-switch.v1","media_type":"text/x-shellscript","sha256":"ea1d40c50de706fa52198dc09e783ee613933aa0dbea72bfff8072becd79bb3b"},"policy_set_validator":{"driver_ref":{"content_id":"control-policy-set-validator-driver.v1","media_type":"text/x-shellscript","sha256":"cf173ad0eaa08244bf636e3937845e894b21f14291fc5e66753e8673bdd2bd2a"},"program_ref":{"content_id":"control-policy-set-validator-program.v1","media_type":"text/x-jq","sha256":"2be97550574ee4522fc0bd14780c92dee3c1b455f2c04b7763b0e437665a8d58"}},"program_ref":{"content_id":"control-evaluator-program.kill-switch.v1","media_type":"text/x-jq","sha256":"e660454c6addc426913b4dbc910c3c25a7333cbb84090d917ea65258ddd0968c"}},"fail_mode":"closed","policy_ref":{"content_id":"control-policy.kill-switch","media_type":"application/vnd.ystack.control-policy+json","sha256":"60a1171f13fa763076b31c0d65a3a54e70d2af28860e3a6da9ed6bb0038a15f5"},"semantics":{"authority_effect":"none","input_contract":"control-policy-set+kill-state+attempt+duty-evaluation.v1","output_kind":"kill_switch_evaluation","output_schema_version":1,"reference_semantics":"identity-only","verdicts":["inconclusive","satisfied","violated"]}},"id":"control-decision.kill-switch","kind":"kill_switch_decision","schema_version":1} +{"body":{"activation_state":"inactive","decision":"allow-observation-only-evaluation","duty_decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"25a513104dc08de8e22727901555d0a3fb6008dd8b222f7a604ed50734d4e23e"},"evaluator":{"driver_ref":{"content_id":"control-evaluator-driver.kill-switch.v1","media_type":"text/x-shellscript","sha256":"ea1d40c50de706fa52198dc09e783ee613933aa0dbea72bfff8072becd79bb3b"},"policy_set_validator":{"driver_ref":{"content_id":"control-policy-set-validator-driver.v1","media_type":"text/x-shellscript","sha256":"cf173ad0eaa08244bf636e3937845e894b21f14291fc5e66753e8673bdd2bd2a"},"program_ref":{"content_id":"control-policy-set-validator-program.v1","media_type":"text/x-jq","sha256":"2be97550574ee4522fc0bd14780c92dee3c1b455f2c04b7763b0e437665a8d58"}},"program_ref":{"content_id":"control-evaluator-program.kill-switch.v1","media_type":"text/x-jq","sha256":"e660454c6addc426913b4dbc910c3c25a7333cbb84090d917ea65258ddd0968c"}},"fail_mode":"closed","policy_ref":{"content_id":"control-policy.kill-switch","media_type":"application/vnd.ystack.control-policy+json","sha256":"6cc216935f62d1a705c8fa4d7ec6fc076d71313b24b2b0fce5ba63243f1ffad2"},"semantics":{"authority_effect":"none","input_contract":"control-policy-set+kill-state+attempt+duty-evaluation.v1","output_kind":"kill_switch_evaluation","output_schema_version":1,"reference_semantics":"identity-only","verdicts":["inconclusive","satisfied","violated"]}},"id":"control-decision.kill-switch","kind":"kill_switch_decision","schema_version":1} diff --git a/control/v1/kill-switch-policy.json b/control/v1/kill-switch-policy.json index 54a26d0..4446b88 100644 --- a/control/v1/kill-switch-policy.json +++ b/control/v1/kill-switch-policy.json @@ -1 +1 @@ -{"body":{"activation_state":"inactive","duty_decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"08f8b496a689ab6fefa976de495fa13e1f9d954cd2b33ee44acd3c70022b4697"},"evaluation_mode":"observation-only","fail_mode":"closed","policy_version":"v1","scope_order":["global","repository","workflow","stage","attempt"],"states":["cleared","stop"]},"id":"control-policy.kill-switch","kind":"kill_switch_policy","schema_version":1} +{"body":{"activation_state":"inactive","duty_decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"25a513104dc08de8e22727901555d0a3fb6008dd8b222f7a604ed50734d4e23e"},"evaluation_mode":"observation-only","fail_mode":"closed","policy_version":"v1","scope_order":["global","repository","workflow","stage","attempt"],"states":["cleared","stop"]},"id":"control-policy.kill-switch","kind":"kill_switch_policy","schema_version":1} diff --git a/control/v1/risk-gates-decision.json b/control/v1/risk-gates-decision.json index c00ebb6..a78e68d 100644 --- a/control/v1/risk-gates-decision.json +++ b/control/v1/risk-gates-decision.json @@ -1 +1 @@ -{"body":{"activation_state":"inactive","decision":"allow-observation-only-evaluation","dependencies":{"duty_separation":{"decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"08f8b496a689ab6fefa976de495fa13e1f9d954cd2b33ee44acd3c70022b4697"},"policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"b33a4022c74c8a1ccb06674c080adf2fc106561c426a7d1dd30fdb9865531dbb"}}},"evaluator":{"driver_ref":{"content_id":"control-evaluator-driver.risk-gates.v1","media_type":"text/x-shellscript","sha256":"0df2094a1a86901d5db8bd463cdeb295f455585b345096719bdc6dcd0b8852e8"},"program_ref":{"content_id":"control-evaluator-program.risk-gates.v1","media_type":"text/x-jq","sha256":"b6b31e39276e49b95f8a41c75364be1b0470db36bae9e26a40f67a9cf11828ff"}},"fail_mode":"closed","policy_ref":{"content_id":"control-policy.risk-gates","media_type":"application/vnd.ystack.control-policy+json","sha256":"0286be22ec3d3a31be8e2c00c5e57a5b674c3f6b0e6d03c87a670e51e3141bed"},"semantics":{"authority_effect":"none","decision_claim_semantics":"immutable-input-claim-only","decision_provenance":"unqualified-input-claim","input_contract":"control-policy-set+public-core-stage-run+duty-evaluation+risk-decision-claim.v1","output_kind":"risk_gate_evaluation","output_schema_version":1,"reference_semantics":"identity-only","verdicts":["inconclusive","violated"]}},"id":"control-decision.risk-gates","kind":"risk_gates_decision","schema_version":1} +{"body":{"activation_state":"inactive","decision":"allow-observation-only-evaluation","dependencies":{"duty_separation":{"decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"25a513104dc08de8e22727901555d0a3fb6008dd8b222f7a604ed50734d4e23e"},"policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"6a86ddbe4432dae9e6e3748295b4b1da7280aa7ca410515531d0059ba2e1d566"}}},"evaluator":{"driver_ref":{"content_id":"control-evaluator-driver.risk-gates.v1","media_type":"text/x-shellscript","sha256":"0df2094a1a86901d5db8bd463cdeb295f455585b345096719bdc6dcd0b8852e8"},"program_ref":{"content_id":"control-evaluator-program.risk-gates.v1","media_type":"text/x-jq","sha256":"bfc6d6d9c967bae8c55e006a3db62e6d7aabd6ca6274d69b6d3caf653f7a64bb"}},"fail_mode":"closed","policy_ref":{"content_id":"control-policy.risk-gates","media_type":"application/vnd.ystack.control-policy+json","sha256":"130c4fc32ddabbddc25b12df7c03ec1ad5bb4925915b4bd90375a0a573c7ef0b"},"semantics":{"authority_effect":"none","decision_claim_semantics":"immutable-input-claim-only","decision_provenance":"unqualified-input-claim","input_contract":"control-policy-set+public-core-stage-run+duty-evaluation+risk-decision-claim.v1","output_kind":"risk_gate_evaluation","output_schema_version":1,"reference_semantics":"identity-only","verdicts":["inconclusive","violated"]}},"id":"control-decision.risk-gates","kind":"risk_gates_decision","schema_version":1} diff --git a/control/v1/risk-gates-policy.json b/control/v1/risk-gates-policy.json index f7d8563..cf030ba 100644 --- a/control/v1/risk-gates-policy.json +++ b/control/v1/risk-gates-policy.json @@ -1 +1 @@ -{"body":{"activation_state":"inactive","core_contract":{"generation_id_sha256":"6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137","package_ref":{"content_id":"core-contract-package.v2","media_type":"application/vnd.ystack.core-contract+json","sha256":"005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716"},"semantic_identity":"core.contracts.v2"},"decision_claim_semantics":"immutable-input-claim-only","decision_provenance":"unqualified-input-claim","duty_separation":{"decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"08f8b496a689ab6fefa976de495fa13e1f9d954cd2b33ee44acd3c70022b4697"},"evaluation_kind":"duty_separation_evaluation","policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"b33a4022c74c8a1ccb06674c080adf2fc106561c426a7d1dd30fdb9865531dbb"},"required_verdict":"satisfied"},"evaluation_mode":"observation-only","fail_mode":"closed","forced_high_reason_ids":["risk.broad-architecture","risk.constitution","risk.deployment","risk.identity-auth","risk.migration","risk.production-infrastructure","risk.security-control","risk.workflow"],"policy_version":"v1","tier_rules":[{"classification":"bootstrap","decision_kind":"operator-bootstrap-approval","decision_role":"operator","declared_tier":"bootstrap"},{"classification":"high","decision_kind":"operator-plan-approval","decision_role":"operator","declared_tier":"high"},{"classification":"routine","decision_kind":"operator-plan-approval","decision_role":"operator","declared_tier":"high"},{"classification":"routine","decision_kind":"independent-plan-check","decision_role":"reviewer","declared_tier":"routine"}]},"id":"control-policy.risk-gates","kind":"risk_gates_policy","schema_version":1} +{"body":{"activation_state":"inactive","core_contract":{"generation_id_sha256":"6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137","package_ref":{"content_id":"core-contract-package.v2","media_type":"application/vnd.ystack.core-contract+json","sha256":"2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c"},"semantic_identity":"core.contracts.v2"},"decision_claim_semantics":"immutable-input-claim-only","decision_provenance":"unqualified-input-claim","duty_separation":{"decision_ref":{"content_id":"control-decision.duty-separation","media_type":"application/vnd.ystack.control-decision+json","sha256":"25a513104dc08de8e22727901555d0a3fb6008dd8b222f7a604ed50734d4e23e"},"evaluation_kind":"duty_separation_evaluation","policy_ref":{"content_id":"control-policy.duty-separation","media_type":"application/vnd.ystack.control-policy+json","sha256":"6a86ddbe4432dae9e6e3748295b4b1da7280aa7ca410515531d0059ba2e1d566"},"required_verdict":"satisfied"},"evaluation_mode":"observation-only","fail_mode":"closed","forced_high_reason_ids":["risk.broad-architecture","risk.constitution","risk.deployment","risk.identity-auth","risk.migration","risk.production-infrastructure","risk.security-control","risk.workflow"],"policy_version":"v1","tier_rules":[{"classification":"bootstrap","decision_kind":"operator-bootstrap-approval","decision_role":"operator","declared_tier":"bootstrap"},{"classification":"high","decision_kind":"operator-plan-approval","decision_role":"operator","declared_tier":"high"},{"classification":"routine","decision_kind":"operator-plan-approval","decision_role":"operator","declared_tier":"high"},{"classification":"routine","decision_kind":"independent-plan-check","decision_role":"reviewer","declared_tier":"routine"}]},"id":"control-policy.risk-gates","kind":"risk_gates_policy","schema_version":1} diff --git a/control/v1/risk-gates.jq b/control/v1/risk-gates.jq index 5568eca..b51a87d 100644 --- a/control/v1/risk-gates.jq +++ b/control/v1/risk-gates.jq @@ -65,7 +65,7 @@ def expected_core: "6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137", package_ref:{content_id:"core-contract-package.v2", media_type:"application/vnd.ystack.core-contract+json", - sha256:"005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716"}}; + sha256:"2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c"}}; def expected_tier_rules: [ @@ -101,11 +101,11 @@ def policy_ok: .duty_separation == { decision_ref:{content_id:"control-decision.duty-separation", media_type:"application/vnd.ystack.control-decision+json", - sha256:"08f8b496a689ab6fefa976de495fa13e1f9d954cd2b33ee44acd3c70022b4697"}, + sha256:"25a513104dc08de8e22727901555d0a3fb6008dd8b222f7a604ed50734d4e23e"}, evaluation_kind:"duty_separation_evaluation", policy_ref:{content_id:"control-policy.duty-separation", media_type:"application/vnd.ystack.control-policy+json", - sha256:"b33a4022c74c8a1ccb06674c080adf2fc106561c426a7d1dd30fdb9865531dbb"}, + sha256:"6a86ddbe4432dae9e6e3748295b4b1da7280aa7ca410515531d0059ba2e1d566"}, required_verdict:"satisfied"}); def claim_shape_ok: diff --git a/core/v2/generation-registry.json b/core/v2/generation-registry.json index 5607140..0bc09fa 100644 --- a/core/v2/generation-registry.json +++ b/core/v2/generation-registry.json @@ -1 +1 @@ -[{"authorization_comment_id":5476938197,"concern":"fake-forge-materialization-contract","generation_id":"g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e","parent_generation_id":"g-71433a31f52f37041a41b5a8812f79c4c0f5f26c79265788c8d625a9c6f9686b","semantic_identity":"core.contracts.v2"}] +[{"authorization_comment_id":5476938197,"concern":"fake-forge-materialization-contract","generation_id":"g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e","parent_generation_id":"g-71433a31f52f37041a41b5a8812f79c4c0f5f26c79265788c8d625a9c6f9686b","semantic_identity":"core.contracts.v2"},{"authorization_comment_id":5517944082,"concern":"incident-mismatch-nonpassing-evidence","generation_id":"g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43","parent_generation_id":"g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e","semantic_identity":"core.contracts.v2"}] diff --git a/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/contracts.jq b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/contracts.jq new file mode 100644 index 0000000..8efe758 --- /dev/null +++ b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/contracts.jq @@ -0,0 +1,85 @@ +import "schema" as schema; +import "profile_graph" as profile_graph; +import "stage_request" as stage_request; +import "result_facts" as result_facts; +import "result_truth" as result_truth; + +def pair_shape_ok: + schema::exact_fields(["content","sha256"];[]) and + (.content | type == "object") and + (.sha256 | schema::sha256_ok); + +def route_shape_ok: + schema::exact_fields(["mode","docs"];[]) and + (.docs | type == "array") and + all(.docs[]; pair_shape_ok) and + (if .mode == "document" then + (.docs | length) == 1 + elif .mode == "profile-set" then + (.docs | length) >= 3 and (.docs | length) <= 10 + elif .mode == "stage-run" then + (.docs | length) == 3 + else false + end); + +def document_shape_ok: + if .kind == "adapter_manifest" or .kind == "profile" or + .kind == "resolved_profile" then + profile_graph::document_shape_ok + elif .kind == "stage_request" then + stage_request::document_shape_ok + elif .kind == "stage_result" then + result_truth::document_shape_ok + else false + end; + +def document_self_ok: + if .kind == "adapter_manifest" or .kind == "profile" or + .kind == "resolved_profile" then + profile_graph::document_self_ok + elif .kind == "stage_request" then + stage_request::document_self_ok + elif .kind == "stage_result" then + result_facts::document_shape_ok and result_truth::document_self_ok + else false + end; + +def parsed_limits_ok: + all(.docs[].content; schema::parsed_limits_ok); + +def shapes_ok: + route_shape_ok and all(.docs[].content; document_shape_ok); + +def refs_ok: + .docs as $docs | + if .mode == "document" then true + elif .mode == "profile-set" then + profile_graph::profile_set_refs_ok($docs[0];$docs[1];$docs[2:]) + elif .mode == "stage-run" then + stage_request::stage_request_resolved_ref_ok($docs[0];$docs[1]) and + result_truth::refs_relation_ok($docs[0];$docs[1];$docs[2].content.body) + else false + end; + +def relations_ok: + .docs as $docs | + if .mode == "document" then + ($docs[0].content | document_self_ok) + elif .mode == "profile-set" then + all($docs[].content; document_self_ok) and + profile_graph::profile_set_graph_ok($docs[0];$docs[1];$docs[2:]) + elif .mode == "stage-run" then + all($docs[].content; document_self_ok) and + stage_request::stage_request_resolved_relation_ok( + $docs[0].content.body;$docs[1].content.body) and + result_truth::stage_result_relation_ok( + $docs[0];$docs[1];$docs[2].content.body) + else false + end; + +if (parsed_limits_ok | not) then "E_LIMIT" +elif (shapes_ok | not) then "E_SHAPE" +elif (refs_ok | not) then "E_REF" +elif (relations_ok | not) then "E_RELATION" +else empty +end diff --git a/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/core-ingress.sh b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/core-ingress.sh new file mode 100644 index 0000000..973f5c3 --- /dev/null +++ b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/core-ingress.sh @@ -0,0 +1,1709 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2016,SC2034 + +portable_core_ingress_error() { + local error_token + case "${1:-}" in + E_RUNTIME|E_PARSE|E_CANONICAL|E_LIMIT|E_SHAPE|E_REF|E_RELATION) + error_token="$1" + ;; + *) + error_token=E_RUNTIME + ;; + esac + if [ "${PORTABLE_CORE_INGRESS_BUFFER_ERRORS:-false}" = true ]; then + if [ -z "${PORTABLE_CORE_INGRESS_PENDING_ERROR:-}" ]; then + PORTABLE_CORE_INGRESS_PENDING_ERROR="$error_token" + fi + else + printf '%s\n' "$error_token" >&2 + fi + return 1 +} + +portable_core_ingress_regular_file() { + [ -f "$1" ] && [ ! -L "$1" ] +} + +portable_core_ingress_real_directory() { + [ -d "$1" ] && [ ! -L "$1" ] +} + +portable_core_ingress_physical_file_path() { + local candidate_path="$1" + local current_path='' + local component + local remaining_path + + case "$candidate_path" in /*) ;; *) return 1 ;; esac + case "$candidate_path" in *$'\n'*|*$'\r'*) return 1 ;; esac + remaining_path="${candidate_path#/}" + [ -n "$remaining_path" ] || return 1 + while [ -n "$remaining_path" ]; do + case "$remaining_path" in + */*) + component="${remaining_path%%/*}" + remaining_path="${remaining_path#*/}" + ;; + *) + component="$remaining_path" + remaining_path='' + ;; + esac + case "$component" in ''|.|..) return 1 ;; esac + current_path="$current_path/$component" + [ ! -L "$current_path" ] || return 1 + if [ -n "$remaining_path" ]; then + [ -d "$current_path" ] || return 1 + else + [ -f "$current_path" ] || return 1 + fi + done +} + +portable_core_ingress_physical_directory_path() { + local candidate_path="$1" + local current_path='' + local component + local remaining_path + + case "$candidate_path" in /*) ;; *) return 1 ;; esac + case "$candidate_path" in *$'\n'*|*$'\r'*) return 1 ;; esac + remaining_path="${candidate_path#/}" + [ -n "$remaining_path" ] || return 1 + while [ -n "$remaining_path" ]; do + case "$remaining_path" in + */*) + component="${remaining_path%%/*}" + remaining_path="${remaining_path#*/}" + ;; + *) + component="$remaining_path" + remaining_path='' + ;; + esac + case "$component" in ''|.|..) return 1 ;; esac + current_path="$current_path/$component" + [ ! -L "$current_path" ] && [ -d "$current_path" ] || return 1 + done +} + +portable_core_ingress_decimal() { + [[ "$1" =~ ^(0|[1-9][0-9]*)$ ]] +} + +portable_core_ingress_file_size() { + local measured_path="$1" + local measured_size + + measured_size="$("$PORTABLE_CORE_INGRESS_WC" -c 2>/dev/null < "$measured_path")" || + return 1 + measured_size="${measured_size//[[:space:]]/}" + portable_core_ingress_decimal "$measured_size" || return 1 + PORTABLE_CORE_INGRESS_MEASURED_SIZE="$measured_size" +} + +portable_core_ingress_account_reserve() { + local expected_bytes="$1" + + [ "${PORTABLE_CORE_INGRESS_ACCOUNTED:-false}" = true ] || return 0 + portable_core_ingress_decimal "$expected_bytes" && + [ -z "${PORTABLE_CORE_INGRESS_RESERVED_BYTES:-}" ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + if [ "$expected_bytes" -gt "$PORTABLE_CORE_INGRESS_REMAINING_BYTES" ]; then + portable_core_ingress_error E_LIMIT + return 1 + fi + PORTABLE_CORE_INGRESS_RESERVED_BYTES="$expected_bytes" +} + +portable_core_ingress_account_commit() { + local actual_bytes="$1" + local reserved_bytes + + [ "${PORTABLE_CORE_INGRESS_ACCOUNTED:-false}" = true ] || return 0 + portable_core_ingress_decimal "$actual_bytes" && + [ -n "${PORTABLE_CORE_INGRESS_RESERVED_BYTES:-}" ] || { + PORTABLE_CORE_INGRESS_RESERVED_BYTES='' + portable_core_ingress_error E_RUNTIME + return 1 + } + reserved_bytes="$PORTABLE_CORE_INGRESS_RESERVED_BYTES" + [ "$actual_bytes" -le "$reserved_bytes" ] || { + PORTABLE_CORE_INGRESS_RESERVED_BYTES='' + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_REMAINING_BYTES=$(( + PORTABLE_CORE_INGRESS_REMAINING_BYTES - actual_bytes + )) + PORTABLE_CORE_INGRESS_WRITTEN_BYTES=$(( + PORTABLE_CORE_INGRESS_WRITTEN_BYTES + actual_bytes + )) + PORTABLE_CORE_INGRESS_RESERVED_BYTES='' + [ "$actual_bytes" -eq "$reserved_bytes" ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + if [ -n "${PORTABLE_CORE_INGRESS_DEFERRED_SIGNAL:-}" ]; then + portable_core_ingress_error E_RUNTIME + return 1 + fi +} + +portable_core_ingress_account_files() { + local expected_bytes="$1" + local measured_path + local measured_total=0 + local invalid_path=false + shift + + [ "${PORTABLE_CORE_INGRESS_ACCOUNTED:-false}" = true ] || return 0 + for measured_path in "$@"; do + if ! portable_core_ingress_regular_file "$measured_path" || + ! portable_core_ingress_file_size "$measured_path"; then + invalid_path=true + continue + fi + measured_total=$((measured_total + PORTABLE_CORE_INGRESS_MEASURED_SIZE)) + done + portable_core_ingress_account_commit "$measured_total" || return 1 + if [ "$invalid_path" = true ] || + [ "$measured_total" -ne "$expected_bytes" ]; then + portable_core_ingress_error E_RUNTIME + return 1 + fi +} + +portable_core_ingress_account_append() { + local expected_bytes="$1" + local prior_bytes="$2" + local measured_path="$3" + local appended_bytes + + [ "${PORTABLE_CORE_INGRESS_ACCOUNTED:-false}" = true ] || return 0 + portable_core_ingress_file_size "$measured_path" || { + PORTABLE_CORE_INGRESS_RESERVED_BYTES='' + portable_core_ingress_error E_RUNTIME + return 1 + } + [ "$PORTABLE_CORE_INGRESS_MEASURED_SIZE" -ge "$prior_bytes" ] || { + PORTABLE_CORE_INGRESS_RESERVED_BYTES='' + portable_core_ingress_error E_RUNTIME + return 1 + } + appended_bytes=$((PORTABLE_CORE_INGRESS_MEASURED_SIZE - prior_bytes)) + portable_core_ingress_account_commit "$appended_bytes" && + [ "$appended_bytes" -eq "$expected_bytes" ] +} + +portable_core_ingress_open() { + local accounted=false + local accounted_root='' + local accounted_budget=0 + local source_path + local source_cwd + local source_dir + local source_parent + local repo_root + local expected_dir + local jq_path + local jq_version + local schema_identity + local sha_path + local temp_path + local required_dir + local scratch_mode + local mkdir_status=0 + local owner_pid + + case "$#" in + 0) ;; + 2) + accounted=true + accounted_root="$1" + accounted_budget="$2" + portable_core_ingress_decimal "$accounted_budget" && + [ "$accounted_budget" -le 536870912 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + + PORTABLE_CORE_INGRESS_BUFFER_ERRORS="$accounted" + PORTABLE_CORE_INGRESS_PENDING_ERROR='' + + PORTABLE_CORE_INGRESS_GENERATION='g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43' + case "${BASH_SOURCE[0]}" in + /*) source_path="${BASH_SOURCE[0]}" ;; + *) + source_cwd="$(pwd -L 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + source_path="$source_cwd/${BASH_SOURCE[0]}" + ;; + esac + portable_core_ingress_physical_file_path "$source_path" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + source_dir="$( + { + source_parent="$(dirname -- "$source_path")" && + CDPATH='' cd -P -- "$source_parent" && pwd -P + } 2>/dev/null + )" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + repo_root="$( + { + CDPATH='' cd -P -- "$source_dir/../../../.." && pwd -P + } 2>/dev/null + )" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + expected_dir="$repo_root/core/v2/generations/$PORTABLE_CORE_INGRESS_GENERATION" + [ "$source_dir" = "$expected_dir" ] && + [ "$source_path" = "$expected_dir/core-ingress.sh" ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + for required_dir in \ + "$repo_root" \ + "$repo_root/core" \ + "$repo_root/core/v2" \ + "$repo_root/core/v2/generations" \ + "$expected_dir" \ + "$expected_dir/modules"; do + portable_core_ingress_real_directory "$required_dir" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + done + + PORTABLE_CORE_INGRESS_REPO_ROOT="$repo_root" + PORTABLE_CORE_INGRESS_MODULE_DIR="$expected_dir/modules" + PORTABLE_CORE_INGRESS_SCHEMA="$PORTABLE_CORE_INGRESS_MODULE_DIR/schema.jq" + PORTABLE_CORE_INGRESS_ROOT="$expected_dir/contracts.jq" + portable_core_ingress_regular_file "$expected_dir/core-ingress.sh" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + portable_core_ingress_regular_file "$PORTABLE_CORE_INGRESS_SCHEMA" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + + jq_path="$(command -v jq 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + case "$jq_path" in + /*) ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + jq_version="$("$jq_path" --version 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + [ "$jq_version" = jq-1.6 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + schema_identity="$( + CDPATH='' cd -P -- "$PORTABLE_CORE_INGRESS_MODULE_DIR" 2>/dev/null && + HOME=/nonexistent JQ_LIBRARY_PATH=/nonexistent \ + "$jq_path" -L "$PORTABLE_CORE_INGRESS_MODULE_DIR" -nr \ + 'import "schema" as schema; schema::semantic_identity' 2>/dev/null + )" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + [ "$schema_identity" = core.contracts.v2 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_JQ="$jq_path" + + if sha_path="$(command -v sha256sum 2>/dev/null)"; then + PORTABLE_CORE_INGRESS_SHA_BACKEND=sha256sum + elif sha_path="$(command -v shasum 2>/dev/null)"; then + PORTABLE_CORE_INGRESS_SHA_BACKEND=shasum + else + portable_core_ingress_error E_RUNTIME + return 1 + fi + case "$sha_path" in + /*) PORTABLE_CORE_INGRESS_SHA="$sha_path" ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + + PORTABLE_CORE_INGRESS_HEAD="$(command -v head 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_WC="$(command -v wc 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_CMP="$(command -v cmp 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_CAT="$(command -v cat 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_RM="$(command -v rm 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_OD="$(command -v od 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_AWK="$(command -v awk 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + case "$PORTABLE_CORE_INGRESS_OD:$PORTABLE_CORE_INGRESS_AWK" in + /*:/*) ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + + PORTABLE_CORE_INGRESS_ACCOUNTED="$accounted" + PORTABLE_CORE_INGRESS_SCRATCH_ROOT='' + PORTABLE_CORE_INGRESS_INITIAL_BYTES="$accounted_budget" + PORTABLE_CORE_INGRESS_REMAINING_BYTES="$accounted_budget" + PORTABLE_CORE_INGRESS_WRITTEN_BYTES=0 + PORTABLE_CORE_INGRESS_RESERVED_BYTES='' + PORTABLE_CORE_INGRESS_DEFERRED_SIGNAL='' + PORTABLE_CORE_INGRESS_CREATING_TEMP=false + PORTABLE_CORE_INGRESS_OWNS_TEMP=false + if [ "$accounted" = true ]; then + PORTABLE_CORE_INGRESS_STAT="$(command -v stat 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_MKDIR="$(command -v mkdir 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + case "$PORTABLE_CORE_INGRESS_STAT:$PORTABLE_CORE_INGRESS_MKDIR" in + /*:/*) ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + portable_core_ingress_physical_directory_path "$accounted_root" && + [ -O "$accounted_root" ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + if scratch_mode="$("$PORTABLE_CORE_INGRESS_STAT" -c %a -- \ + "$accounted_root" 2>/dev/null)"; then + : + elif scratch_mode="$("$PORTABLE_CORE_INGRESS_STAT" -f %Lp \ + "$accounted_root" 2>/dev/null)"; then + : + else + portable_core_ingress_error E_RUNTIME + return 1 + fi + [ "$scratch_mode" = 700 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_SCRATCH_ROOT="$accounted_root" + owner_pid="$$" + [[ "$owner_pid" =~ ^[1-9][0-9]*$ ]] && [ "${#owner_pid}" -le 20 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_OWNER_PID="$owner_pid" + temp_path="$accounted_root/portable-core-accounted-v2.$owner_pid" + if [ -e "$temp_path" ] || [ -L "$temp_path" ]; then + portable_core_ingress_error E_RUNTIME + return 1 + fi + PORTABLE_CORE_INGRESS_TEMP="$temp_path" + PORTABLE_CORE_INGRESS_CREATING_TEMP=true + "$PORTABLE_CORE_INGRESS_MKDIR" -m 700 -- "$temp_path" 2>/dev/null || + mkdir_status=$? + if [ "$mkdir_status" -eq 0 ]; then + PORTABLE_CORE_INGRESS_OWNS_TEMP=true + elif portable_core_ingress_physical_directory_path "$temp_path" && + [ -O "$temp_path" ]; then + if scratch_mode="$("$PORTABLE_CORE_INGRESS_STAT" -c %a -- \ + "$temp_path" 2>/dev/null)"; then + : + elif scratch_mode="$("$PORTABLE_CORE_INGRESS_STAT" -f %Lp \ + "$temp_path" 2>/dev/null)"; then + : + else + scratch_mode='' + fi + [ "$scratch_mode" = 700 ] && PORTABLE_CORE_INGRESS_OWNS_TEMP=true + fi + PORTABLE_CORE_INGRESS_CREATING_TEMP=false + if [ -n "$PORTABLE_CORE_INGRESS_DEFERRED_SIGNAL" ] || + [ "$mkdir_status" -ne 0 ]; then + portable_core_ingress_error E_RUNTIME + return 1 + fi + else + temp_path="$(mktemp -d /tmp/ystack-portable-core-ingress.XXXXXXXX 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + case "$temp_path" in + /tmp/ystack-portable-core-ingress.*) ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + fi + portable_core_ingress_real_directory "$temp_path" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_TEMP="$temp_path" + PORTABLE_CORE_INGRESS_MODE='' + PORTABLE_CORE_INGRESS_CONTENTS='' + PORTABLE_CORE_INGRESS_HASHES='' + PORTABLE_CORE_INGRESS_DRIVER='' + PORTABLE_CORE_INGRESS_OUTPUT='' + PORTABLE_CORE_INGRESS_SNAPSHOT='' + PORTABLE_CORE_INGRESS_SHA256='' + PORTABLE_CORE_INGRESS_COUNT=0 + PORTABLE_CORE_INGRESS_RAW_PATHS=() + PORTABLE_CORE_INGRESS_RAW_SIZES=() + PORTABLE_CORE_INGRESS_CANONICAL_PATHS=() + PORTABLE_CORE_INGRESS_DEPTH_OVER=() +} + +portable_core_ingress_begin() { + [ "$#" -eq 1 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + case "$1" in + document|profile-set|stage-run) ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + portable_core_ingress_real_directory "${PORTABLE_CORE_INGRESS_TEMP:-}" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + PORTABLE_CORE_INGRESS_MODE="$1" + PORTABLE_CORE_INGRESS_CONTENTS="$PORTABLE_CORE_INGRESS_TEMP/contents.ndjson" + PORTABLE_CORE_INGRESS_HASHES="$PORTABLE_CORE_INGRESS_TEMP/hashes.ndjson" + portable_core_ingress_account_reserve 0 || return 1 + if : 2>/dev/null > "$PORTABLE_CORE_INGRESS_CONTENTS"; then + portable_core_ingress_account_files 0 \ + "$PORTABLE_CORE_INGRESS_CONTENTS" || return 1 + else + portable_core_ingress_account_files 0 \ + "$PORTABLE_CORE_INGRESS_CONTENTS" >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + portable_core_ingress_account_reserve 0 || return 1 + if : 2>/dev/null > "$PORTABLE_CORE_INGRESS_HASHES"; then + portable_core_ingress_account_files 0 \ + "$PORTABLE_CORE_INGRESS_HASHES" || return 1 + else + portable_core_ingress_account_files 0 \ + "$PORTABLE_CORE_INGRESS_HASHES" >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + PORTABLE_CORE_INGRESS_COUNT=0 + PORTABLE_CORE_INGRESS_RAW_PATHS=() + PORTABLE_CORE_INGRESS_RAW_SIZES=() + PORTABLE_CORE_INGRESS_CANONICAL_PATHS=() + PORTABLE_CORE_INGRESS_DEPTH_OVER=() +} + +portable_core_ingress_digest() { + local input_path="$1" + local digest_output + local digest + + case "$PORTABLE_CORE_INGRESS_SHA_BACKEND" in + sha256sum) + digest_output="$("$PORTABLE_CORE_INGRESS_SHA" -- "$input_path" 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + ;; + shasum) + digest_output="$("$PORTABLE_CORE_INGRESS_SHA" -a 256 -- "$input_path" 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + case "$digest_output" in *$'\n'*|*$'\r'*) + portable_core_ingress_error E_RUNTIME + return 1 + esac + [[ "$digest_output" =~ ^([0-9a-f]{64})([[:space:]].*)?$ ]] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + digest="${BASH_REMATCH[1]}" + PORTABLE_CORE_INGRESS_SHA256="$digest" +} + +portable_core_ingress_snapshot() { + local input_path + local snapshot_number + local raw_path + local encoded_bytes + local byte_count + local -a pipeline_status + + [ "$#" -eq 1 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + input_path="$1" + [ -n "${PORTABLE_CORE_INGRESS_MODE:-}" ] && + portable_core_ingress_real_directory "${PORTABLE_CORE_INGRESS_TEMP:-}" && + [ -r "$input_path" ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + + snapshot_number=$((PORTABLE_CORE_INGRESS_COUNT + 1)) + raw_path="$PORTABLE_CORE_INGRESS_TEMP/raw.$snapshot_number" + encoded_bytes="$( + "$PORTABLE_CORE_INGRESS_HEAD" -c 1048577 -- "$input_path" 2>/dev/null | + "$PORTABLE_CORE_INGRESS_OD" -An -v -t u1 2>/dev/null + )" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + byte_count="$( + printf '%s\n' "$encoded_bytes" | + "$PORTABLE_CORE_INGRESS_AWK" ' + { + for (i = 1; i <= NF; i++) { + if ($i !~ /^[0-9]+$/ || ($i + 0) < 0 || ($i + 0) > 255) { + invalid = 1 + exit 42 + } + count++ + } + } + END { if (!invalid) print count + 0 } + ' 2>/dev/null + )" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + byte_count="${byte_count//[[:space:]]/}" + portable_core_ingress_decimal "$byte_count" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + portable_core_ingress_account_reserve "$byte_count" || return 1 + if printf '%s\n' "$encoded_bytes" | + "$PORTABLE_CORE_INGRESS_AWK" ' + { for (i = 1; i <= NF; i++) printf "%c", ($i + 0) } + ' 2>/dev/null > "$raw_path"; then + pipeline_status=("${PIPESTATUS[@]}") + else + pipeline_status=("${PIPESTATUS[@]}") + fi + if [ "${#pipeline_status[@]}" -eq 2 ] && + [ "${pipeline_status[0]}" -eq 0 ] && + [ "${pipeline_status[1]}" -eq 0 ]; then + portable_core_ingress_account_files "$byte_count" "$raw_path" || return 1 + else + portable_core_ingress_account_files "$byte_count" "$raw_path" \ + >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + PORTABLE_CORE_INGRESS_RAW_PATHS[PORTABLE_CORE_INGRESS_COUNT]="$raw_path" + PORTABLE_CORE_INGRESS_RAW_SIZES[PORTABLE_CORE_INGRESS_COUNT]="$byte_count" + PORTABLE_CORE_INGRESS_SNAPSHOT="$raw_path" + PORTABLE_CORE_INGRESS_COUNT="$snapshot_number" +} + +portable_core_ingress_analyze() { + local raw_path="$1" + local canonical_path="$2" + local scalar_path="$PORTABLE_CORE_INGRESS_TEMP/deep-scalars.ndjson" + local scalar_canonical_path="$PORTABLE_CORE_INGRESS_TEMP/deep-scalars-canonical.ndjson" + local key_path="$PORTABLE_CORE_INGRESS_TEMP/deep-keys.ndjson" + local key_pair_path="$PORTABLE_CORE_INGRESS_TEMP/deep-key-pairs.ndjson" + local key_order_path="$PORTABLE_CORE_INGRESS_TEMP/deep-key-order" + local meta_path="$PORTABLE_CORE_INGRESS_TEMP/deep-meta" + local scalar_marker_path="$PORTABLE_CORE_INGRESS_TEMP/deep-scalar-marker" + local scratch_path + local compare_status + local meta_size + local meta_lines + local meta_kind + local structural_canonical + local max_depth + local extra_meta + local marker_size + local marker_lines + local marker_kind + local scalar_program + local scalar_canonical_size + local key_order_output + local key_order_size + local canonical_size + local scan_program + local scan_sizes + local scalar_size + local key_size + local key_pair_size + local expected_scan_bytes + local canonical_ok=true + local -a pipeline_status + + for scratch_path in "$scalar_path" "$scalar_canonical_path" \ + "$key_path" "$key_pair_path" "$key_order_path" "$meta_path" \ + "$scalar_marker_path"; do + portable_core_ingress_account_reserve 0 || return 1 + if : 2>/dev/null > "$scratch_path"; then + portable_core_ingress_account_files 0 "$scratch_path" || return 1 + else + portable_core_ingress_account_files 0 "$scratch_path" \ + >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + done + + scan_program=' function fail_parse() { parse_bad = 1 } + function byte_char(byte) { return sprintf("%c", byte) } + function is_hex(byte) { + return (byte >= 48 && byte <= 57) || + (byte >= 65 && byte <= 70) || + (byte >= 97 && byte <= 102) + } + function value_expected() { + if (depth == 0) return root_state == 1 + return frame[depth] == 1 || frame[depth] == 2 || frame[depth] == 7 + } + function key_expected() { + return depth > 0 && (frame[depth] == 4 || frame[depth] == 5) + } + function record_value_depth() { + if (depth > max_depth) max_depth = depth + } + function complete_value() { + if (depth == 0) { + if (root_state != 1) { fail_parse(); return } + root_state = 2 + } else if (frame[depth] == 1 || frame[depth] == 2) { + frame[depth] = 3 + } else if (frame[depth] == 7) { + frame[depth] = 8 + } else { + fail_parse() + } + } + function flush_token_chunk() { + if (token_chunk == "") return + scalar_size += length(token_chunk) + if (!measure_only) printf "%s", token_chunk >> scalar_file + if (token_role == "key") { + key_size += length(token_chunk) + if (!measure_only) printf "%s", token_chunk >> key_file + } + token_chunk = "" + } + function begin_token(role, first_byte) { + token_active = 1 + token_role = role + token_chunk = "" + if (role == "key") { + current_key_index = key_count + key_count++ + } + append_token(first_byte) + } + function append_token(byte) { + token_chunk = token_chunk byte_char(byte) + if (length(token_chunk) >= 4096) flush_token_chunk() + } + function finish_scalar() { + flush_token_chunk() + scalar_size++ + if (!measure_only) printf "\n" >> scalar_file + if (token_role == "key") { + if (!key_expected()) { fail_parse(); return } + key_size++ + if (!measure_only) printf "\n" >> key_file + if (depth in previous_key_index) { + pair_text = sprintf("[%d,%d]\n", previous_key_index[depth], + current_key_index) + key_pair_size += length(pair_text) + if (!measure_only) printf "%s", pair_text >> key_pair_file + } + previous_key_index[depth] = current_key_index + frame[depth] = 6 + } else { + complete_value() + } + token_chunk = "" + token_role = "" + token_active = 0 + token_state = "" + } + function token_terminal() { + if (token_state == "literal") return literal_pos == literal_len + return token_state == "zero" || token_state == "integer" || + token_state == "fraction" || token_state == "exponent" + } + function literal_byte(kind, position) { + if (kind == 1) { + if (position == 2) return 114 + if (position == 3) return 117 + if (position == 4) return 101 + } else if (kind == 2) { + if (position == 2) return 97 + if (position == 3) return 108 + if (position == 4) return 115 + if (position == 5) return 101 + } else { + if (position == 2) return 117 + if (position == 3) return 108 + if (position == 4) return 108 + } + return -1 + } + function start_atom(byte) { + if (!value_expected()) { fail_parse(); return } + record_value_depth() + begin_token("value", byte) + if (byte == 116) { + token_state = "literal"; literal_kind = 1; literal_pos = 1; + literal_len = 4 + } else if (byte == 102) { + token_state = "literal"; literal_kind = 2; literal_pos = 1; + literal_len = 5 + } else if (byte == 110) { + token_state = "literal"; literal_kind = 3; literal_pos = 1; + literal_len = 4 + } else if (byte == 45) { + token_state = "sign" + } else if (byte == 48) { + token_state = "zero" + } else if (byte >= 49 && byte <= 57) { + token_state = "integer" + } else { + fail_parse() + } + } + function atom_byte(byte) { + if (token_state == "literal") { + if (literal_pos < literal_len) { + if (byte != literal_byte(literal_kind, literal_pos + 1)) return -1 + literal_pos++ + append_token(byte) + return 1 + } + return 0 + } + if (token_state == "sign") { + if (byte == 48) token_state = "zero" + else if (byte >= 49 && byte <= 57) token_state = "integer" + else return -1 + } else if (token_state == "zero") { + if (byte == 46) token_state = "decimal-mark" + else if (byte == 101 || byte == 69) token_state = "exponent-mark" + else if (byte >= 48 && byte <= 57) return -1 + else return 0 + } else if (token_state == "integer") { + if (byte >= 48 && byte <= 57) token_state = "integer" + else if (byte == 46) token_state = "decimal-mark" + else if (byte == 101 || byte == 69) token_state = "exponent-mark" + else return 0 + } else if (token_state == "decimal-mark") { + if (byte >= 48 && byte <= 57) token_state = "fraction" + else return -1 + } else if (token_state == "fraction") { + if (byte >= 48 && byte <= 57) token_state = "fraction" + else if (byte == 101 || byte == 69) token_state = "exponent-mark" + else return 0 + } else if (token_state == "exponent-mark") { + if (byte == 43 || byte == 45) token_state = "exponent-sign" + else if (byte >= 48 && byte <= 57) token_state = "exponent" + else return -1 + } else if (token_state == "exponent-sign") { + if (byte >= 48 && byte <= 57) token_state = "exponent" + else return -1 + } else if (token_state == "exponent") { + if (byte >= 48 && byte <= 57) token_state = "exponent" + else return 0 + } else { + return -1 + } + append_token(byte) + return 1 + } + function push_container(byte) { + if (!value_expected()) { fail_parse(); return } + record_value_depth() + depth++ + if (byte == 91) frame[depth] = 1 + else { + frame[depth] = 4 + } + } + function close_container(byte, state) { + if (depth == 0) { fail_parse(); return } + state = frame[depth] + if (byte == 93) { + if (!(state == 1 || state == 3)) { fail_parse(); return } + } else { + if (!(state == 4 || state == 8)) { fail_parse(); return } + } + if (byte == 125) { + delete previous_key_index[depth] + } + delete frame[depth] + depth-- + complete_value() + } + function structural_ascii(byte) { + if (byte == 32 || byte == 9 || byte == 10 || byte == 13) { + if (depth == 0 && root_state == 2) { + trailing_count++ + if (trailing_count == 1) trailing_byte = byte + } else { + internal_space = 1 + } + return + } + if (depth == 0 && root_state == 2) { fail_parse(); return } + if (byte == 34) { + if (key_expected()) begin_token("key", byte) + else if (value_expected()) { + record_value_depth() + begin_token("value", byte) + } + else { fail_parse(); return } + in_string = 1 + escape_state = 0 + return + } + if (byte == 91 || byte == 123) { push_container(byte); return } + if (byte == 93 || byte == 125) { + if ((byte == 93 && frame[depth] != 1 && frame[depth] != 3) || + (byte == 125 && frame[depth] != 4 && frame[depth] != 8)) { + fail_parse(); return + } + close_container(byte) + return + } + if (byte == 44) { + if (depth == 0) { fail_parse(); return } + if (frame[depth] == 3) frame[depth] = 2 + else if (frame[depth] == 8) frame[depth] = 5 + else fail_parse() + return + } + if (byte == 58) { + if (depth > 0 && frame[depth] == 6) frame[depth] = 7 + else fail_parse() + return + } + if (byte < 32 || byte > 127) { fail_parse(); return } + start_atom(byte) + } + function string_ascii(byte) { + append_token(byte) + if (escape_state == 2) { + if (!is_hex(byte)) { fail_parse(); return } + unicode_left-- + if (unicode_left == 0) escape_state = 0 + return + } + if (escape_state == 1) { + if (byte == 117) { escape_state = 2; unicode_left = 4; return } + if (byte == 34 || byte == 92 || byte == 47 || byte == 98 || + byte == 102 || byte == 110 || byte == 114 || byte == 116) { + escape_state = 0 + return + } + fail_parse(); return + } + if (byte == 34) { + in_string = 0 + finish_scalar() + } else if (byte == 92) { + escape_state = 1 + } else if (byte < 32) { + fail_parse() + } + } + function consume_byte(byte, used) { + if (parse_bad || runtime_bad) return + byte_position++ + if (bom_state == 1) { + if (byte != 187) { fail_parse(); return } + bom_state = 2 + return + } + if (bom_state == 2) { + if (byte != 191) { fail_parse(); return } + bom_state = 0 + return + } + if (byte_position == 1 && byte == 239) { + bom_present = 1 + bom_state = 1 + return + } + if (utf_need > 0) { + if (byte < utf_min || byte > utf_max) { fail_parse(); return } + if (!in_string) { fail_parse(); return } + append_token(byte) + utf_need-- + utf_min = 128 + utf_max = 191 + return + } + if (byte > 127) { + if (!in_string) { fail_parse(); return } + append_token(byte) + if (byte >= 194 && byte <= 223) { + utf_need = 1; utf_min = 128; utf_max = 191 + } else if (byte == 224) { + utf_need = 2; utf_min = 160; utf_max = 191 + } else if ((byte >= 225 && byte <= 236) || + (byte >= 238 && byte <= 239)) { + utf_need = 2; utf_min = 128; utf_max = 191 + } else if (byte == 237) { + utf_need = 2; utf_min = 128; utf_max = 159 + } else if (byte == 240) { + utf_need = 3; utf_min = 144; utf_max = 191 + } else if (byte >= 241 && byte <= 243) { + utf_need = 3; utf_min = 128; utf_max = 191 + } else if (byte == 244) { + utf_need = 3; utf_min = 128; utf_max = 143 + } else { + fail_parse() + } + return + } + if (in_string) { string_ascii(byte); return } + if (token_active) { + used = atom_byte(byte) + if (used == 1) return + if (used < 0 || !token_terminal()) { fail_parse(); return } + finish_scalar() + if (parse_bad) return + } + structural_ascii(byte) + } + BEGIN { + depth = 0 + max_depth = 0 + root_state = 1 + parse_bad = 0 + runtime_bad = 0 + token_active = 0 + in_string = 0 + utf_need = 0 + internal_space = 0 + trailing_count = 0 + byte_position = 0 + bom_state = 0 + bom_present = 0 + key_count = 0 + } + { + for (i = 1; i <= NF; i++) { + if ($i !~ /^[0-9]+$/ || ($i + 0) < 0 || ($i + 0) > 255) { + runtime_bad = 1 + next + } + consume_byte($i + 0) + } + } + END { + meta_text = "" + if (!parse_bad && token_active) { + if (!token_terminal()) fail_parse() + else finish_scalar() + } + if (in_string || utf_need != 0 || bom_state != 0 || + depth != 0 || root_state != 2) fail_parse() + if (runtime_bad) { + meta_text = "R\n" + } else if (parse_bad) { + meta_text = "P\n" + } else { + structurally_canonical = !bom_present && !internal_space && + trailing_count == 1 && trailing_byte == 10 + meta_text = sprintf("S %d %d\n", structurally_canonical, max_depth) + } + if (measure_only) { + printf "%d %d %d %d\n", scalar_size, key_size, key_pair_size, + length(meta_text) + } else { + printf "%s", meta_text + } + } +' + if [ "${PORTABLE_CORE_INGRESS_ACCOUNTED:-false}" = true ]; then + scan_sizes="$( + "$PORTABLE_CORE_INGRESS_OD" -An -v -t u1 "$raw_path" 2>/dev/null | + LC_ALL=C "$PORTABLE_CORE_INGRESS_AWK" \ + -v measure_only=1 \ + -v scalar_file="$scalar_path" \ + -v key_file="$key_path" \ + -v key_pair_file="$key_pair_path" "$scan_program" + )" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + case "$scan_sizes" in *$'\n'*|*$'\r'*) + portable_core_ingress_error E_RUNTIME + return 1 + esac + [[ "$scan_sizes" =~ ^([0-9]+)[[:space:]]+([0-9]+)[[:space:]]+([0-9]+)[[:space:]]+([0-9]+)$ ]] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + scalar_size="${BASH_REMATCH[1]}" + key_size="${BASH_REMATCH[2]}" + key_pair_size="${BASH_REMATCH[3]}" + meta_size="${BASH_REMATCH[4]}" + expected_scan_bytes=$((scalar_size + key_size + key_pair_size + meta_size)) + portable_core_ingress_account_reserve "$expected_scan_bytes" || return 1 + else + expected_scan_bytes=0 + fi + if "$PORTABLE_CORE_INGRESS_OD" -An -v -t u1 "$raw_path" 2>/dev/null | + LC_ALL=C "$PORTABLE_CORE_INGRESS_AWK" \ + -v measure_only=0 \ + -v scalar_file="$scalar_path" \ + -v key_file="$key_path" \ + -v key_pair_file="$key_pair_path" "$scan_program" \ + 2>/dev/null > "$meta_path"; then + pipeline_status=("${PIPESTATUS[@]}") + else + pipeline_status=("${PIPESTATUS[@]}") + fi + portable_core_ingress_account_files "$expected_scan_bytes" \ + "$scalar_path" "$key_path" "$key_pair_path" "$meta_path" || return 1 + [ "${#pipeline_status[@]}" -eq 2 ] && + [ "${pipeline_status[0]}" -eq 0 ] && + [ "${pipeline_status[1]}" -eq 0 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + + meta_size="$("$PORTABLE_CORE_INGRESS_WC" -c 2>/dev/null < "$meta_path")" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + meta_lines="$("$PORTABLE_CORE_INGRESS_WC" -l 2>/dev/null < "$meta_path")" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + meta_size="${meta_size//[[:space:]]/}" + meta_lines="${meta_lines//[[:space:]]/}" + [[ "$meta_size" =~ ^[0-9]+$ ]] && [[ "$meta_lines" =~ ^[0-9]+$ ]] && + [ "$meta_size" -ge 2 ] && [ "$meta_lines" -eq 1 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + IFS=' ' read -r meta_kind structural_canonical max_depth extra_meta \ + 2>/dev/null < "$meta_path" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + case "$meta_kind" in + P) + [ "$meta_size" -eq 2 ] && [ -z "${structural_canonical:-}" ] && + [ -z "${max_depth:-}" ] && [ -z "${extra_meta:-}" ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + portable_core_ingress_error E_PARSE + return 1 + ;; + R) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + S) ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + case "$structural_canonical" in 0|1) ;; *) + portable_core_ingress_error E_RUNTIME + return 1 + esac + [[ "$max_depth" =~ ^[0-9]+$ ]] && [ -z "${extra_meta:-}" ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + if [ "$max_depth" -gt 32 ]; then + PORTABLE_CORE_INGRESS_ANALYZE_DEPTH_OVER=true + else + PORTABLE_CORE_INGRESS_ANALYZE_DEPTH_OVER=false + fi + + scalar_program=' foreach (inputs, {end:true}) as $event + ({emit:"", parse:true, runtime:true}; + if ($event | type) == "object" then + if (.runtime | not) then halt_error(42) + elif (.parse | not) then .emit = "\u0000" + else .emit = "" + end + elif (.parse | not) then .emit = "" + elif (($event | type) != "array") or (($event | length) == 0) then + .runtime = false | .emit = "" + elif ($event[0] | type) == "string" then + .parse = false | .emit = "" + elif (($event | length) == 2) and ($event[0] == []) then + .emit = ($event[1] | tojson) + "\n" + else .runtime = false | .emit = "" + end; + .emit) +' + if [ "${PORTABLE_CORE_INGRESS_ACCOUNTED:-false}" = true ]; then + scalar_canonical_size="$( + "$PORTABLE_CORE_INGRESS_JQ" -n --stream --stream-errors -j \ + "$scalar_program" "$scalar_path" 2>/dev/null | + "$PORTABLE_CORE_INGRESS_WC" -c 2>/dev/null + )" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + scalar_canonical_size="${scalar_canonical_size//[[:space:]]/}" + portable_core_ingress_decimal "$scalar_canonical_size" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + portable_core_ingress_account_reserve "$scalar_canonical_size" || return 1 + else + scalar_canonical_size=0 + fi + if "$PORTABLE_CORE_INGRESS_JQ" -n --stream --stream-errors -j \ + "$scalar_program" "$scalar_path" 2>/dev/null > "$scalar_canonical_path"; then + portable_core_ingress_account_files "$scalar_canonical_size" \ + "$scalar_canonical_path" || return 1 + else + portable_core_ingress_account_files "$scalar_canonical_size" \ + "$scalar_canonical_path" >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + marker_kind="$( + "$PORTABLE_CORE_INGRESS_OD" -An -v -t u1 \ + "$scalar_canonical_path" 2>/dev/null | + "$PORTABLE_CORE_INGRESS_AWK" ' + { + for (i = 1; i <= NF; i++) if (($i + 0) == 0) found = 1 + } + END { print found ? "P" : "C" } + ' 2>/dev/null + )" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + marker_size=$((${#marker_kind} + 1)) + portable_core_ingress_account_reserve "$marker_size" || return 1 + if printf '%s\n' "$marker_kind" 2>/dev/null > "$scalar_marker_path"; then + portable_core_ingress_account_files "$marker_size" \ + "$scalar_marker_path" || return 1 + else + portable_core_ingress_account_files "$marker_size" \ + "$scalar_marker_path" >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + marker_size="$("$PORTABLE_CORE_INGRESS_WC" -c \ + 2>/dev/null < "$scalar_marker_path")" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + marker_lines="$("$PORTABLE_CORE_INGRESS_WC" -l \ + 2>/dev/null < "$scalar_marker_path")" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + marker_size="${marker_size//[[:space:]]/}" + marker_lines="${marker_lines//[[:space:]]/}" + [[ "$marker_size" =~ ^[0-9]+$ ]] && [[ "$marker_lines" =~ ^[0-9]+$ ]] && + [ "$marker_size" -eq 2 ] && [ "$marker_lines" -eq 1 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + IFS= read -r marker_kind 2>/dev/null < "$scalar_marker_path" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + case "$marker_kind" in + C) ;; + P) + portable_core_ingress_error E_PARSE + return 1 + ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + if "$PORTABLE_CORE_INGRESS_CMP" -s -- "$scalar_path" \ + "$scalar_canonical_path" 2>/dev/null; then + : + else + compare_status=$? + if [ "$compare_status" -eq 1 ]; then + canonical_ok=false + else + portable_core_ingress_error E_RUNTIME + return 1 + fi + fi + + if [ -s "$key_pair_path" ]; then + key_order_output="$("$PORTABLE_CORE_INGRESS_JQ" -n -j \ + --slurpfile keys "$key_path" ' + reduce inputs as $pair + (false; + if (($pair | type) != "array") or (($pair | length) != 2) or + (all($pair[]; + (type == "number") and (. >= 0) and (floor == .)) | not) or + ($pair[0] >= ($keys | length)) or + ($pair[1] >= ($keys | length)) then + halt_error(43) + else . or (($keys[$pair[0]] < $keys[$pair[1]]) | not) + end) + | if . then "x" else empty end + ' "$key_pair_path" 2>/dev/null)" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + key_order_size="${#key_order_output}" + portable_core_ingress_account_reserve "$key_order_size" || return 1 + if printf '%s' "$key_order_output" 2>/dev/null > "$key_order_path"; then + portable_core_ingress_account_files "$key_order_size" \ + "$key_order_path" || return 1 + else + portable_core_ingress_account_files "$key_order_size" \ + "$key_order_path" >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + fi + if [ -s "$key_order_path" ]; then + if "$PORTABLE_CORE_INGRESS_OD" -An -v -t u1 "$key_order_path" 2>/dev/null | + "$PORTABLE_CORE_INGRESS_AWK" ' + { + for (i = 1; i <= NF; i++) { + count++ + if (($i + 0) != 120) invalid = 1 + } + } + END { if (invalid || count != 1) exit 42 } + ' >/dev/null 2>/dev/null; then + pipeline_status=("${PIPESTATUS[@]}") + else + pipeline_status=("${PIPESTATUS[@]}") + fi + [ "${#pipeline_status[@]}" -eq 2 ] && + [ "${pipeline_status[0]}" -eq 0 ] && + [ "${pipeline_status[1]}" -eq 0 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + canonical_ok=false + fi + if [ "$structural_canonical" != 1 ]; then + canonical_ok=false + fi + + if [ "$canonical_ok" = true ]; then + portable_core_ingress_file_size "$raw_path" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + canonical_size="$PORTABLE_CORE_INGRESS_MEASURED_SIZE" + portable_core_ingress_account_reserve "$canonical_size" || return 1 + if ! "$PORTABLE_CORE_INGRESS_CAT" -- "$raw_path" \ + 2>/dev/null > "$canonical_path"; then + portable_core_ingress_account_files "$canonical_size" "$canonical_path" \ + >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + portable_core_ingress_account_files "$canonical_size" \ + "$canonical_path" || return 1 + else + canonical_size=2 + portable_core_ingress_account_reserve "$canonical_size" || return 1 + if ! printf '!\n' 2>/dev/null > "$canonical_path"; then + portable_core_ingress_account_files "$canonical_size" "$canonical_path" \ + >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + portable_core_ingress_account_files "$canonical_size" \ + "$canonical_path" || return 1 + fi +} + +portable_core_ingress_finish_driver() { + local input_index + local raw_path + local canonical_path + local compare_status + local contents_before + local hashes_before + local driver_program + local driver_size + + [ "$#" -eq 0 ] && [ "${PORTABLE_CORE_INGRESS_COUNT:-0}" -gt 0 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + + for ((input_index = 0; input_index < PORTABLE_CORE_INGRESS_COUNT; input_index++)); do + if [ "${PORTABLE_CORE_INGRESS_RAW_SIZES[$input_index]}" -gt 1048576 ]; then + portable_core_ingress_error E_LIMIT + return 1 + fi + done + for ((input_index = 0; input_index < PORTABLE_CORE_INGRESS_COUNT; input_index++)); do + raw_path="${PORTABLE_CORE_INGRESS_RAW_PATHS[$input_index]}" + canonical_path="$PORTABLE_CORE_INGRESS_TEMP/canonical.$((input_index + 1))" + portable_core_ingress_analyze "$raw_path" "$canonical_path" || return 1 + PORTABLE_CORE_INGRESS_DEPTH_OVER[input_index]="$PORTABLE_CORE_INGRESS_ANALYZE_DEPTH_OVER" + PORTABLE_CORE_INGRESS_CANONICAL_PATHS[input_index]="$canonical_path" + done + for ((input_index = 0; input_index < PORTABLE_CORE_INGRESS_COUNT; input_index++)); do + raw_path="${PORTABLE_CORE_INGRESS_RAW_PATHS[$input_index]}" + canonical_path="${PORTABLE_CORE_INGRESS_CANONICAL_PATHS[$input_index]}" + if "$PORTABLE_CORE_INGRESS_CMP" -s -- "$raw_path" "$canonical_path" 2>/dev/null; then + : + else + compare_status=$? + if [ "$compare_status" -eq 1 ]; then + portable_core_ingress_error E_CANONICAL + else + portable_core_ingress_error E_RUNTIME + fi + return 1 + fi + done + for ((input_index = 0; input_index < PORTABLE_CORE_INGRESS_COUNT; input_index++)); do + if [ "${PORTABLE_CORE_INGRESS_DEPTH_OVER[$input_index]}" = true ]; then + portable_core_ingress_error E_LIMIT + return 1 + fi + done + for ((input_index = 0; input_index < PORTABLE_CORE_INGRESS_COUNT; input_index++)); do + raw_path="${PORTABLE_CORE_INGRESS_RAW_PATHS[$input_index]}" + portable_core_ingress_digest "$raw_path" || return 1 + if [ "${PORTABLE_CORE_INGRESS_ACCOUNTED:-false}" = true ]; then + portable_core_ingress_file_size "$PORTABLE_CORE_INGRESS_CONTENTS" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + contents_before="$PORTABLE_CORE_INGRESS_MEASURED_SIZE" + else + contents_before=0 + fi + portable_core_ingress_account_reserve \ + "${PORTABLE_CORE_INGRESS_RAW_SIZES[$input_index]}" || return 1 + if "$PORTABLE_CORE_INGRESS_CAT" -- "$raw_path" \ + 2>/dev/null >> "$PORTABLE_CORE_INGRESS_CONTENTS"; then + portable_core_ingress_account_append \ + "${PORTABLE_CORE_INGRESS_RAW_SIZES[$input_index]}" \ + "$contents_before" "$PORTABLE_CORE_INGRESS_CONTENTS" || return 1 + else + portable_core_ingress_account_append \ + "${PORTABLE_CORE_INGRESS_RAW_SIZES[$input_index]}" \ + "$contents_before" "$PORTABLE_CORE_INGRESS_CONTENTS" \ + >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + if [ "${PORTABLE_CORE_INGRESS_ACCOUNTED:-false}" = true ]; then + portable_core_ingress_file_size "$PORTABLE_CORE_INGRESS_HASHES" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + hashes_before="$PORTABLE_CORE_INGRESS_MEASURED_SIZE" + else + hashes_before=0 + fi + portable_core_ingress_account_reserve 67 || return 1 + if printf '"%s"\n' "$PORTABLE_CORE_INGRESS_SHA256" \ + 2>/dev/null >> "$PORTABLE_CORE_INGRESS_HASHES"; then + portable_core_ingress_account_append 67 "$hashes_before" \ + "$PORTABLE_CORE_INGRESS_HASHES" || return 1 + else + portable_core_ingress_account_append 67 "$hashes_before" \ + "$PORTABLE_CORE_INGRESS_HASHES" >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + done + PORTABLE_CORE_INGRESS_DRIVER="$PORTABLE_CORE_INGRESS_TEMP/driver.json" + driver_program=' {mode:$mode, + docs:([range(0;($contents|length))] | + map({content:$contents[.],sha256:$hashes[.]}))} +' + if [ "${PORTABLE_CORE_INGRESS_ACCOUNTED:-false}" = true ]; then + driver_size="$( + "$PORTABLE_CORE_INGRESS_JQ" -n -S -c \ + --arg mode "$PORTABLE_CORE_INGRESS_MODE" \ + --slurpfile contents "$PORTABLE_CORE_INGRESS_CONTENTS" \ + --slurpfile hashes "$PORTABLE_CORE_INGRESS_HASHES" \ + "$driver_program" 2>/dev/null | + "$PORTABLE_CORE_INGRESS_WC" -c 2>/dev/null + )" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + driver_size="${driver_size//[[:space:]]/}" + portable_core_ingress_decimal "$driver_size" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + portable_core_ingress_account_reserve "$driver_size" || return 1 + else + driver_size=0 + fi + if ! "$PORTABLE_CORE_INGRESS_JQ" -n -S -c \ + --arg mode "$PORTABLE_CORE_INGRESS_MODE" \ + --slurpfile contents "$PORTABLE_CORE_INGRESS_CONTENTS" \ + --slurpfile hashes "$PORTABLE_CORE_INGRESS_HASHES" \ + "$driver_program" \ + 2>/dev/null > "$PORTABLE_CORE_INGRESS_DRIVER"; then + portable_core_ingress_account_files "$driver_size" \ + "$PORTABLE_CORE_INGRESS_DRIVER" >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + portable_core_ingress_account_files "$driver_size" \ + "$PORTABLE_CORE_INGRESS_DRIVER" || return 1 + if ! "$PORTABLE_CORE_INGRESS_JQ" -e \ + '(.docs|length) > 0 and (.docs|length) == ([.docs[].sha256]|length)' \ + "$PORTABLE_CORE_INGRESS_DRIVER" >/dev/null 2>/dev/null; then + portable_core_ingress_error E_RUNTIME + return 1 + fi +} + +portable_core_ingress_validate() { + local output_size + local token + local validator_capture + local validator_encoded + local validator_status_record + local validator_jq_status + local validator_od_status + local -a pipeline_status + + if [ "$#" -ne 0 ] || + ! portable_core_ingress_regular_file "${PORTABLE_CORE_INGRESS_DRIVER:-}" || + ! portable_core_ingress_regular_file "${PORTABLE_CORE_INGRESS_ROOT:-}"; then + portable_core_ingress_error E_RUNTIME + return 1 + fi + PORTABLE_CORE_INGRESS_OUTPUT="$PORTABLE_CORE_INGRESS_TEMP/validator.out" + validator_capture="$( + if ( + CDPATH='' cd -P -- "$PORTABLE_CORE_INGRESS_MODULE_DIR" && + HOME=/nonexistent JQ_LIBRARY_PATH=/nonexistent \ + "$PORTABLE_CORE_INGRESS_JQ" -L "$PORTABLE_CORE_INGRESS_MODULE_DIR" -r \ + -f "$PORTABLE_CORE_INGRESS_ROOT" "$PORTABLE_CORE_INGRESS_DRIVER" + ) 2>/dev/null | "$PORTABLE_CORE_INGRESS_OD" -An -v -t u1 2>/dev/null; then + pipeline_status=("${PIPESTATUS[@]}") + else + pipeline_status=("${PIPESTATUS[@]}") + fi + printf 'S %s %s\n' "${pipeline_status[0]}" "${pipeline_status[1]}" + )" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + case "$validator_capture" in + *$'\n'*) + validator_encoded="${validator_capture%$'\n'*}" + validator_status_record="${validator_capture##*$'\n'}" + ;; + *) + validator_encoded='' + validator_status_record="$validator_capture" + ;; + esac + [[ "$validator_status_record" =~ ^S[[:space:]]([0-9]+)[[:space:]]([0-9]+)$ ]] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + validator_jq_status="${BASH_REMATCH[1]}" + validator_od_status="${BASH_REMATCH[2]}" + [ "$validator_jq_status" -eq 0 ] && [ "$validator_od_status" -eq 0 ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + output_size="$( + printf '%s\n' "$validator_encoded" | + "$PORTABLE_CORE_INGRESS_AWK" ' + { + for (i = 1; i <= NF; i++) { + if ($i !~ /^[0-9]+$/ || ($i + 0) < 0 || ($i + 0) > 255) { + invalid = 1 + exit 42 + } + count++ + } + } + END { if (!invalid) print count + 0 } + ' 2>/dev/null + )" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + output_size="${output_size//[[:space:]]/}" + portable_core_ingress_decimal "$output_size" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + portable_core_ingress_account_reserve "$output_size" || return 1 + if printf '%s\n' "$validator_encoded" | + "$PORTABLE_CORE_INGRESS_AWK" ' + { for (i = 1; i <= NF; i++) printf "%c", ($i + 0) } + ' 2>/dev/null > "$PORTABLE_CORE_INGRESS_OUTPUT"; then + pipeline_status=("${PIPESTATUS[@]}") + else + pipeline_status=("${PIPESTATUS[@]}") + fi + if [ "${#pipeline_status[@]}" -ne 2 ] || + [ "${pipeline_status[0]}" -ne 0 ] || + [ "${pipeline_status[1]}" -ne 0 ]; then + portable_core_ingress_account_files "$output_size" \ + "$PORTABLE_CORE_INGRESS_OUTPUT" >/dev/null 2>&1 || : + portable_core_ingress_error E_RUNTIME + return 1 + fi + portable_core_ingress_account_files "$output_size" \ + "$PORTABLE_CORE_INGRESS_OUTPUT" || return 1 + if [ ! -s "$PORTABLE_CORE_INGRESS_OUTPUT" ]; then + return 0 + fi + output_size="$("$PORTABLE_CORE_INGRESS_WC" -c \ + 2>/dev/null < "$PORTABLE_CORE_INGRESS_OUTPUT")" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + output_size="${output_size//[[:space:]]/}" + [[ "$output_size" =~ ^[0-9]+$ ]] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + IFS= read -r token 2>/dev/null < "$PORTABLE_CORE_INGRESS_OUTPUT" || { + portable_core_ingress_error E_RUNTIME + return 1 + } + case "$token" in + E_LIMIT|E_SHAPE|E_REF|E_RELATION) ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + if [ "$output_size" -ne $((${#token} + 1)) ]; then + portable_core_ingress_error E_RUNTIME + return 1 + fi + portable_core_ingress_error "$token" +} + +portable_core_ingress_close() { + local temp_path="${PORTABLE_CORE_INGRESS_TEMP:-}" + if [ "${PORTABLE_CORE_INGRESS_ACCOUNTED:-false}" = true ]; then + if [ "$temp_path" = \ + "${PORTABLE_CORE_INGRESS_SCRATCH_ROOT:-}/portable-core-accounted-v2.${PORTABLE_CORE_INGRESS_OWNER_PID:-}" ] && + [[ "${PORTABLE_CORE_INGRESS_OWNER_PID:-}" =~ ^[1-9][0-9]*$ ]]; then + if [ "${PORTABLE_CORE_INGRESS_OWNS_TEMP:-false}" = true ]; then + if [ -d "$temp_path" ] && [ ! -L "$temp_path" ]; then + if ! "$PORTABLE_CORE_INGRESS_RM" -rf -- "$temp_path" \ + >/dev/null 2>&1; then + portable_core_ingress_error E_RUNTIME + return 1 + fi + elif [ -e "$temp_path" ] || [ -L "$temp_path" ]; then + portable_core_ingress_error E_RUNTIME + return 1 + fi + fi + PORTABLE_CORE_INGRESS_CREATING_TEMP=false + PORTABLE_CORE_INGRESS_OWNS_TEMP=false + PORTABLE_CORE_INGRESS_OWNER_PID='' + PORTABLE_CORE_INGRESS_TEMP='' + return 0 + fi + [ -z "$temp_path" ] || { + portable_core_ingress_error E_RUNTIME + return 1 + } + return 0 + fi + case "$temp_path" in + /tmp/ystack-portable-core-ingress.*) + if [ -d "$temp_path" ] && [ ! -L "$temp_path" ]; then + if ! "$PORTABLE_CORE_INGRESS_RM" -rf -- "$temp_path" >/dev/null 2>&1; then + portable_core_ingress_error E_RUNTIME + return 1 + fi + fi + ;; + '') ;; + *) + portable_core_ingress_error E_RUNTIME + return 1 + ;; + esac + PORTABLE_CORE_INGRESS_TEMP='' +} diff --git a/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/profile_graph.jq b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/profile_graph.jq new file mode 100644 index 0000000..e3633b2 --- /dev/null +++ b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/profile_graph.jq @@ -0,0 +1,315 @@ +import "schema" as schema; + +def optional_ok($name; value_ok): + (has($name) | not) or (.[$name] | value_ok); + +def model_request_ok: + schema::exact_fields(["provider_id","model_id","effort_id"];[]) and + (.provider_id | schema::id_ok) and + (.model_id | schema::id_ok) and + (.effort_id | schema::id_ok); + +def adapter_manifest_body_ok: + schema::exact_fields( + ["adapter_version","package_ref","offered_roles","offered_execution_kinds", + "offered_capabilities","offered_permissions","offered_tools"]; + ["config_contract_ref"]) and + (.adapter_version | schema::version_ok) and + (.package_ref | schema::git_object_ref_ok) and + (.offered_roles | schema::enum_set_ok(1;8;schema::adapter_roles)) and + (.offered_execution_kinds | schema::enum_set_ok(1;2;schema::execution_kinds)) and + (.offered_capabilities | schema::enum_set_ok(0;3;schema::capability_ids)) and + (.offered_permissions | schema::enum_set_ok(0;5;schema::permission_ids)) and + (.offered_tools | schema::bounded_set(0;32;schema::tool_ref_ok;.tool_id)) and + optional_ok("config_contract_ref";schema::scope_ref_purpose_ok("config-contract")); + +def adapter_manifest_shape_ok: + schema::envelope_ok("adapter_manifest") and + (.body | adapter_manifest_body_ok); + +def adapter_manifest_self_ok: adapter_manifest_shape_ok; + +def binding_capability_ok: + . as $binding | + (schema::capabilities_for_role($binding.role)) as $capabilities | + if ($capabilities | length) == 1 then + $binding.requested_capabilities == $capabilities and + $binding.requested_permissions == + schema::permissions_for_capability($capabilities[0];$binding.execution_kind) + else + $binding.requested_capabilities == [] and + $binding.requested_permissions == [] + end; + +def profile_binding_shape_ok: + schema::exact_fields( + ["binding_id","role","manifest_ref","execution_kind","adapter_instance_id", + "principal_id","execution_boundary_id","package_ref","skill_refs", + "requested_tools","requested_capabilities","requested_permissions"]; + ["authority_ref","config_ref","prompt_ref","model_request"]) and + (.binding_id | schema::id_ok) and + (.role | schema::adapter_role_ok) and + (.manifest_ref | schema::document_ref_kind_ok("adapter_manifest")) and + (.execution_kind | schema::execution_kind_ok) and + (.execution_kind as $kind | + .role as $role | + schema::execution_kinds_for_role($role) | index($kind) != null) and + (.adapter_instance_id | schema::id_ok) and + (.principal_id | schema::id_ok) and + (.execution_boundary_id | schema::id_ok) and + optional_ok("authority_ref";schema::scope_ref_purpose_ok("authority")) and + (.package_ref | schema::git_object_ref_ok) and + optional_ok("config_ref";schema::git_object_ref_ok) and + optional_ok("prompt_ref";schema::git_object_ref_ok) and + (.skill_refs | schema::bounded_set(0;32;schema::git_object_ref_ok;schema::git_key)) and + (.requested_tools | schema::bounded_set(0;32;schema::tool_ref_ok;.tool_id)) and + optional_ok("model_request";model_request_ok) and + (.requested_capabilities | + schema::enum_set_ok(0;1;schema::capability_ids)) and + (.requested_permissions | + schema::enum_set_ok(0;5;schema::permission_ids)) and + (if .execution_kind == "model" then + has("model_request") and has("prompt_ref") + else + (has("model_request") | not) and + (has("prompt_ref") | not) and + .skill_refs == [] + end); + +def profile_binding_ok: + profile_binding_shape_ok and binding_capability_ok; + +def profile_body_shape_ok: + schema::exact_fields(["profile_version","bindings"];[]) and + (.profile_version | schema::version_ok) and + (.bindings | + schema::bounded_set(4;8;profile_binding_ok;.binding_id)); + +def profile_body_ok: profile_body_shape_ok; + +def protected_role_separation_ok($bindings): + [$bindings[] | + select(.role as $role | schema::protected_roles | index($role) != null)] as $protected | + [$bindings[] | + select(.role as $role | schema::protected_roles | index($role) == null)] as $other | + all(schema::protected_roles[]; . as $role | + [$protected[] | select(.role == $role)] | length == 1) and + all($protected[]; has("authority_ref")) and + (($protected | map(.binding_id) | unique | length) == ($protected | length)) and + (($protected | map(.adapter_instance_id) | unique | length) == ($protected | length)) and + (($protected | map(.principal_id) | unique | length) == ($protected | length)) and + (($protected | map(.execution_boundary_id) | unique | length) == ($protected | length)) and + (($protected | map(.authority_ref.scope_sha256) | unique | length) == + ($protected | length)) and + (($other | map(.role) | unique | length) == ($other | length)); + +def profile_shape_ok: + schema::envelope_ok("profile") and + (.body | profile_body_shape_ok); + +def profile_relations_ok: + .body.bindings as $bindings | + protected_role_separation_ok($bindings); + +def profile_self_ok: + profile_shape_ok and profile_relations_ok; + +def tool_source_ok: + schema::exact_fields(["tool_id","package_source","config_source"];[]) and + (.tool_id | schema::id_ok) and + (.package_source | schema::source_value_ref_ok) and + (.config_source | schema::present_ok(schema::source_value_ref_ok)); + +def resolved_binding_ok: + schema::exact_fields( + ["binding","adapter_implementation","manifest_source","package_source", + "config_source","prompt_source","skill_sources","tool_sources"]; + []) and + (.binding | profile_binding_shape_ok) and + (.adapter_implementation | + schema::exact_fields(["id","version"];[]) and + (.id | schema::id_ok) and + (.version | schema::version_ok)) and + (.manifest_source | + schema::source_value_ref_ok and .value_format == "canonical-json") and + (.package_source | schema::source_value_ref_ok) and + (.config_source | schema::present_ok(schema::source_value_ref_ok)) and + (.prompt_source | schema::present_ok(schema::source_value_ref_ok)) and + (.skill_sources | + schema::bounded_set(0;32;schema::source_value_ref_ok;schema::source_git_key)) and + (.tool_sources | schema::bounded_set(0;32;tool_source_ok;.tool_id)); + +def resolved_profile_body_shape_ok: + schema::exact_fields( + ["profile_ref","profile_source","selection_ref","repository_context_ref", + "bindings"]; + []) and + (.profile_ref | schema::document_ref_kind_ok("profile")) and + (.profile_source | + schema::source_value_ref_ok and .value_format == "canonical-json") and + (.selection_ref | schema::scope_ref_purpose_ok("selection")) and + (.repository_context_ref | + schema::scope_ref_purpose_ok("repository-context")) and + (.bindings | + schema::bounded_set(4;8;resolved_binding_ok;.binding.binding_id)); + +def resolved_profile_body_ok: resolved_profile_body_shape_ok; + +def resolved_profile_shape_ok: + schema::envelope_ok("resolved_profile") and + (.body | resolved_profile_body_shape_ok); + +def present_source_values($present): + if $present.state == "present" then [$present.value] else [] end; + +def resolved_binding_source_claims($resolved_binding): + [$resolved_binding.manifest_source,$resolved_binding.package_source] + + present_source_values($resolved_binding.config_source) + + present_source_values($resolved_binding.prompt_source) + + $resolved_binding.skill_sources + + ($resolved_binding.tool_sources | + map([.package_source] + present_source_values(.config_source)) | + add // []); + +def resolved_profile_source_claims($body): + [$body.profile_source] + + ($body.bindings | map(resolved_binding_source_claims(.)) | add // []); + +def source_claims_agree($body): + resolved_profile_source_claims($body) | + group_by(schema::source_git_key) | + all(.[]; + (map(.value_format) | unique | length) == 1 and + (map(.value_sha256) | unique | length) == 1); + +def present_source_matches_optional_ref($source; $binding; $name): + ($source.state == "present") == ($binding | has($name)) and + (if $binding | has($name) then + $source.value.source == $binding[$name] + else true end); + +def tool_sources_match($binding; $resolved_binding): + ($resolved_binding.tool_sources | map(.tool_id)) == + ($binding.requested_tools | map(.tool_id)) and + all($resolved_binding.tool_sources[]; + . as $source | + [$binding.requested_tools[] | + select(.tool_id == $source.tool_id)] as $requested | + ($requested | length) == 1 and + $source.package_source.source == $requested[0].package_ref and + ($source.config_source.state == "present") == + ($requested[0].config_ref.state == "present") and + (if $source.config_source.state == "present" then + $source.config_source.value.source == $requested[0].config_ref.value + else true end)); + +def resolved_binding_projection_ok: + . as $resolved | + $resolved.binding as $binding | + $resolved.adapter_implementation.id == $binding.manifest_ref.id and + $resolved.manifest_source.value_sha256 == $binding.manifest_ref.sha256 and + $resolved.package_source.source == $binding.package_ref and + present_source_matches_optional_ref($resolved.config_source;$binding;"config_ref") and + present_source_matches_optional_ref($resolved.prompt_source;$binding;"prompt_ref") and + ($resolved.skill_sources | map(schema::source_git_key)) == + ($binding.skill_refs | map(schema::git_key)) and + tool_sources_match($binding;$resolved); + +def resolved_profile_relations_ok: + .body as $body | + ($body.bindings | map(.binding)) as $bindings | + $body.profile_source.value_sha256 == $body.profile_ref.sha256 and + protected_role_separation_ok($bindings) and + all($bindings[]; binding_capability_ok) and + all($body.bindings[]; resolved_binding_projection_ok) and + source_claims_agree($body); + +def resolved_profile_self_ok: + resolved_profile_shape_ok and resolved_profile_relations_ok; + +def document_pair_ok($kind): + schema::exact_fields(["content","sha256"];[]) and + (.content | schema::envelope_ok($kind)) and + (.sha256 | schema::sha256_ok); + +def document_ref_for_pair($pair): + { + schema_version:2, + kind:$pair.content.kind, + id:$pair.content.id, + sha256:$pair.sha256 + }; + +def profile_set_refs_ok($profile; $resolved; $manifests): + ($profile | document_pair_ok("profile")) and + ($resolved | document_pair_ok("resolved_profile")) and + ($manifests | type == "array") and + ($manifests | length) >= 1 and + ($manifests | length) <= 8 and + all($manifests[]; document_pair_ok("adapter_manifest")) and + (($manifests | map(.content.id) | unique | length) == ($manifests | length)) and + $resolved.content.body.profile_ref == document_ref_for_pair($profile); + +def manifest_for_ref($manifests; $ref): + [$manifests[] | select(document_ref_for_pair(.) == $ref)]; + +def offered_tool_ok($manifest; $tool): + $manifest.content.body.offered_tools | any(.[]; . == $tool); + +def binding_manifest_graph_ok($binding; $resolved_binding; $manifest): + ($resolved_binding.binding == $binding) and + ($manifest.content.body.offered_roles | index($binding.role) != null) and + ($manifest.content.body.offered_execution_kinds | + index($binding.execution_kind) != null) and + all($binding.requested_capabilities[]; . as $capability | + $manifest.content.body.offered_capabilities | index($capability) != null) and + all($binding.requested_permissions[]; . as $permission | + $manifest.content.body.offered_permissions | index($permission) != null) and + all($binding.requested_tools[]; . as $tool | + offered_tool_ok($manifest;$tool)) and + ($binding.package_ref == $manifest.content.body.package_ref) and + (if $binding | has("config_ref") then + $manifest.content.body | has("config_contract_ref") + else true end) and + ($resolved_binding.adapter_implementation.id == $manifest.content.id) and + ($resolved_binding.adapter_implementation.version == + $manifest.content.body.adapter_version) and + ($resolved_binding.manifest_source.value_sha256 == $manifest.sha256); + +def profile_set_graph_ok($profile; $resolved; $manifests): + $profile.content.body.bindings as $bindings | + $resolved.content.body.bindings as $resolved_bindings | + ($bindings | map(.binding_id)) == + ($resolved_bindings | map(.binding.binding_id)) and + ($resolved.content.body.profile_source.value_sha256 == $profile.sha256) and + ([ $bindings[].manifest_ref ] | unique) == + ([$manifests[] | document_ref_for_pair(.)] | unique) and + all($bindings[]; + . as $binding | + manifest_for_ref($manifests;$binding.manifest_ref) as $matches | + [$resolved_bindings[] | + select(.binding.binding_id == $binding.binding_id)] as $resolved_matches | + ($matches | length) == 1 and + ($resolved_matches | length) == 1 and + binding_manifest_graph_ok($binding;$resolved_matches[0];$matches[0])); + +def profile_set_ok($profile; $resolved; $manifests): + profile_set_refs_ok($profile;$resolved;$manifests) and + ($profile.content | profile_self_ok) and + ($resolved.content | resolved_profile_self_ok) and + all($manifests[].content; adapter_manifest_self_ok) and + profile_set_graph_ok($profile;$resolved;$manifests); + +def document_shape_ok: + if .kind == "adapter_manifest" then adapter_manifest_shape_ok + elif .kind == "profile" then profile_shape_ok + elif .kind == "resolved_profile" then resolved_profile_shape_ok + else false + end; + +def document_self_ok: + if .kind == "adapter_manifest" then adapter_manifest_self_ok + elif .kind == "profile" then profile_self_ok + elif .kind == "resolved_profile" then resolved_profile_self_ok + else false + end; diff --git a/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/result_facts.jq b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/result_facts.jq new file mode 100644 index 0000000..cfc3ed3 --- /dev/null +++ b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/result_facts.jq @@ -0,0 +1,151 @@ +import "schema" as schema; +import "profile_graph" as profile_graph; +import "stage_request" as stage_request; + +def optional_ok($name; value_ok): + (has($name) | not) or (.[$name] | value_ok); + +def actual_binding_shape_ok: + schema::exact_fields( + ["binding_id","role","adapter_implementation","manifest_ref","package_ref", + "config_ref","execution_kind","adapter_instance_id","principal_id", + "execution_boundary_id"]; + ["authority_ref"]) and + (.binding_id | schema::id_ok) and + (.role | schema::adapter_role_ok) and + (.adapter_implementation | + schema::exact_fields(["id","version"];[]) and + (.id | schema::id_ok) and + (.version | schema::version_ok)) and + (.manifest_ref | schema::document_ref_kind_ok("adapter_manifest")) and + (.package_ref | schema::git_object_ref_ok) and + (.config_ref | schema::present_ok(schema::git_object_ref_ok)) and + (.execution_kind | schema::execution_kind_ok) and + (.adapter_instance_id | schema::id_ok) and + (.principal_id | schema::id_ok) and + (.execution_boundary_id | schema::id_ok) and + optional_ok("authority_ref";schema::scope_ref_purpose_ok("authority")); + +def observed_capability_shape_ok: + schema::exact_fields(["kind","id"];[]) and + (if .kind == "registered" then + (.id | schema::capability_id_ok) + elif .kind == "unclassified" then + (.id | schema::id_ok) and + (.id as $id | schema::capability_ids | index($id) == null) + else false + end); + +def fact_shape_ok(value_ok): + type == "object" and + (if .state == "recorded" or .state == "computed" then + schema::exact_fields(["state","value","source_ref"];[]) and + (.value | value_ok) and + (.source_ref | schema::content_ref_ok) + elif .state == "unavailable" then + schema::exact_fields(["state","reason_id"];[]) and + (.reason_id | schema::id_ok) + elif .state == "not-applicable" then + schema::exact_fields(["state"];[]) + else false + end); + +def factual_or_unavailable: + type == "object" and + (.state == "recorded" or .state == "computed" or .state == "unavailable"); + +def execution_metadata_shape_ok: + schema::exact_fields( + ["kind","provider","model","snapshot","effort","prompt","skills","tools"]; + []) and + (.kind | schema::execution_kind_ok) and + (.provider | fact_shape_ok(schema::id_ok)) and + (.model | fact_shape_ok(schema::id_ok)) and + (.snapshot | fact_shape_ok(schema::id_ok)) and + (.effort | fact_shape_ok(schema::id_ok)) and + (.prompt | fact_shape_ok(schema::git_object_ref_ok)) and + (.skills | + fact_shape_ok(schema::bounded_set(0;32;schema::git_object_ref_ok;schema::git_key))) and + (.tools | + fact_shape_ok(schema::bounded_set(0;32;schema::tool_ref_ok;.tool_id))) and + .tools.state != "not-applicable" and + (if .kind == "deterministic" then + [.provider,.model,.snapshot,.effort,.prompt,.skills] | + all(.[];.state == "not-applicable") + else + [.provider,.model,.snapshot,.effort,.prompt,.skills] | + all(.[];factual_or_unavailable) + end); + +def execution_shape_ok: + schema::exact_fields( + ["performer","actual_binding","environment","used_capability","metadata"]; + []) and + (.performer | schema::actor_ref_ok) and + (.actual_binding | actual_binding_shape_ok) and + (.environment | schema::environment_ref_ok) and + (.used_capability | observed_capability_shape_ok) and + (.metadata | execution_metadata_shape_ok) and + .metadata.kind == .actual_binding.execution_kind and + .performer.role == .actual_binding.role; + +def stage_result_facts_shape_ok: + type == "object" and + (if has("execution") then (.execution | execution_shape_ok) else true end); + +def fact_matches($fact; $expected): + if $fact.state == "recorded" or $fact.state == "computed" then + $fact.value == $expected + else $fact.state == "unavailable" + end; + +def used_tools_match($fact; $allowed): + if $fact.state == "recorded" or $fact.state == "computed" then + all($fact.value[];. as $tool | $allowed | index($tool) != null) + else $fact.state == "unavailable" + end; + +def metadata_matches_projection($metadata; $projection): + $metadata.kind == $projection.execution_kind and + used_tools_match($metadata.tools;$projection.metadata_expectation.allowed_tools) and + (if $projection.execution_kind == "model" then + $projection.metadata_expectation.model_request.value as $model_request | + fact_matches($metadata.provider;$model_request.provider_id) and + fact_matches($metadata.model;$model_request.model_id) and + fact_matches($metadata.effort;$model_request.effort_id) and + fact_matches($metadata.prompt;$projection.metadata_expectation.prompt_ref.value) and + fact_matches($metadata.skills;$projection.metadata_expectation.skill_refs) + else true + end); + +def execution_matches_projection($execution; $projection): + $projection != null and + $execution.actual_binding == $projection.actual_binding and + $execution.performer == $projection.performer and + $execution.environment == $projection.environment and + $execution.used_capability == $projection.used_capability and + metadata_matches_projection($execution.metadata;$projection); + +def incident_execution_allowed($result_body): + $result_body.status == "failed" or + $result_body.status == "cancelled" or + ($result_body.status == "completed" and + ($result_body | has("outcome")) and + $result_body.outcome.value == "inconclusive"); + +def stage_result_execution_relation_ok($request_body; $resolved_body; $result_body): + if ($result_body | has("execution") | not) then true + elif ($result_body.execution | execution_shape_ok | not) then false + else + stage_request::expected_execution_projection($request_body;$resolved_body) as $projection | + $projection != null and + (if $result_body.execution.used_capability.kind == "unclassified" then + incident_execution_allowed($result_body) + elif incident_execution_allowed($result_body) then true + else execution_matches_projection($result_body.execution;$projection) + end) + end; + +def document_shape_ok: + .kind == "stage_result" and + (.body | stage_result_facts_shape_ok); diff --git a/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/result_truth.jq b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/result_truth.jq new file mode 100644 index 0000000..6af6f42 --- /dev/null +++ b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/result_truth.jq @@ -0,0 +1,376 @@ +import "schema" as schema; +import "profile_graph" as profile_graph; +import "stage_request" as stage_request; +import "result_facts" as result_facts; + +def optional_ok($name; value_ok): + (has($name) | not) or (.[$name] | value_ok); + +def outcome_shape_ok: + schema::exact_fields(["family","value"];[]) and + (if .family == "change" then + .value == "changed" or .value == "no-change" or .value == "inconclusive" + elif .family == "check" then + .value == "passed" or .value == "failed" or .value == "inconclusive" + else false + end); + +def reason_shape_ok: + schema::exact_fields(["reason_id"];["summary"]) and + (.reason_id | schema::id_ok) and + optional_ok("summary";schema::short_text_ok); + +def output_shape_ok: + schema::exact_fields(["output_id","ref"];[]) and + (.output_id | schema::id_ok) and + (.ref | schema::content_ref_ok); + +def evidence_shape_ok: + schema::exact_fields(["evidence_id","kind","verdict","proof_ref"];[]) and + (.evidence_id | schema::id_ok) and + (.kind | schema::evidence_kind_ok) and + (.verdict as $verdict | schema::evidence_verdicts | index($verdict) != null) and + (.proof_ref | schema::content_ref_ok); + +def stale_selector_shape_ok: + type == "object" and + (if .kind == "target" or .kind == "source" or .kind == "base" or + .kind == "resolved-profile" or .kind == "qualification" or + .kind == "environment" then + schema::exact_fields(["kind"];[]) + elif .kind == "input" then + schema::exact_fields(["kind","input_id"];[]) and + (.input_id | schema::id_ok) + elif .kind == "gate-decision" then + schema::exact_fields(["kind","scope_sha256"];[]) and + (.scope_sha256 | schema::sha256_ok) + else false + end); + +def stale_observed_shape_ok($kind): + if $kind == "target" or $kind == "base" then + schema::present_ok(schema::git_revision_ref_ok) + elif $kind == "source" then + schema::present_ok(schema::artifact_ref_ok) + elif $kind == "resolved-profile" then + schema::present_ok(schema::document_ref_kind_ok("resolved_profile")) + elif $kind == "qualification" then + schema::present_ok(schema::scope_ref_purpose_ok("qualification")) + elif $kind == "environment" then + schema::present_ok(schema::environment_ref_ok) + elif $kind == "input" then + schema::present_ok(schema::input_ref_ok) + elif $kind == "gate-decision" then + schema::present_ok(schema::scope_ref_purpose_ok("gate-decision")) + else false + end; + +def stale_observation_shape_ok: + schema::exact_fields(["selector","observed"];[]) and + (.selector | stale_selector_shape_ok) and + (.selector.kind as $kind | .observed | stale_observed_shape_ok($kind)); + +def stale_selector_key: + [.selector.kind, + (.selector.input_id // .selector.scope_sha256 // "")]; + +def stage_result_body_shape_ok: + schema::exact_fields( + ["request_ref","resolved_profile_ref","attempt_id","attempt_number", + "reported_by","status","outputs","diagnostics","evidence","recorded_at"]; + ["outcome","reason","stale_observations","delta_ref","execution", + "started_at","finished_at"]) and + (.request_ref | schema::document_ref_kind_ok("stage_request")) and + (.resolved_profile_ref | + schema::document_ref_kind_ok("resolved_profile")) and + (.attempt_id | schema::id_ok) and + (.attempt_number | schema::int_ok) and + .attempt_number >= 1 and + (.reported_by | schema::actor_ref_ok) and + (.status == "completed" or .status == "skipped" or .status == "stale" or + .status == "blocked" or .status == "failed" or .status == "cancelled") and + optional_ok("outcome";outcome_shape_ok) and + optional_ok("reason";reason_shape_ok) and + optional_ok("stale_observations"; + schema::bounded_set(1;256;stale_observation_shape_ok;stale_selector_key)) and + (.outputs | schema::bounded_set(0;256;output_shape_ok;.output_id)) and + optional_ok("delta_ref";schema::git_patch_ref_ok) and + (.diagnostics | + schema::bounded_set(0;256;schema::content_ref_ok;.content_id)) and + (.evidence | + schema::bounded_set(0;256;evidence_shape_ok;.evidence_id)) and + ((.evidence | map(.kind) | unique | length) == (.evidence | length)) and + optional_ok("started_at";schema::time_ok) and + optional_ok("finished_at";schema::time_ok) and + (.recorded_at | schema::time_ok) and + result_facts::stage_result_facts_shape_ok; + +def status_presence_ok: + .status as $status | + if $status == "completed" then + has("execution") and has("outcome") and has("started_at") and + has("finished_at") and .diagnostics == [] and + (has("stale_observations") | not) and + ((.outcome.value == "inconclusive") == has("reason")) + elif $status == "skipped" then + has("reason") and .outputs == [] and .diagnostics == [] and .evidence == [] and + (has("outcome") | not) and (has("stale_observations") | not) and + (has("delta_ref") | not) and (has("execution") | not) and + (has("started_at") | not) and (has("finished_at") | not) + elif $status == "stale" then + has("reason") and has("stale_observations") and .outputs == [] and + .diagnostics == [] and .evidence == [] and (has("outcome") | not) and + (has("delta_ref") | not) and (has("execution") | not) and + (has("started_at") | not) and (has("finished_at") | not) + elif $status == "blocked" then + has("reason") and .outputs == [] and .evidence == [] and + (has("outcome") | not) and (has("stale_observations") | not) and + (has("delta_ref") | not) and (has("execution") | not) and + (has("started_at") | not) and (has("finished_at") | not) + elif $status == "failed" or $status == "cancelled" then + has("reason") and .outputs == [] and (has("delta_ref") | not) and + (has("stale_observations") | not) and + (if $status == "failed" then (.diagnostics | length) > 0 else true end) and + (if has("execution") then + has("outcome") and .outcome.value == "inconclusive" and + has("started_at") and has("finished_at") and + (.evidence | length) > 0 and + all(.evidence[];.verdict == "failed" or .verdict == "inconclusive") + else + (has("outcome") | not) and .evidence == [] and + (has("started_at") | not) and (has("finished_at") | not) + end) + else false + end; + +def local_time_order_ok: + if has("execution") then + .started_at <= .finished_at and .finished_at <= .recorded_at + else true + end; + +def stage_result_self_ok: + stage_result_body_shape_ok and status_presence_ok and local_time_order_ok; + +def expected_stale_value($request; $observation): + $observation.selector as $selector | + if $selector.kind == "target" then $request.target_revision + elif $selector.kind == "source" then $request.source + elif $selector.kind == "base" then $request.base + elif $selector.kind == "resolved-profile" then + {state:"present",value:$request.resolved_profile_ref} + elif $selector.kind == "qualification" then + if $request | has("qualification_ref") + then {state:"present",value:$request.qualification_ref} + else {state:"absent"} + end + elif $selector.kind == "environment" then + {state:"present",value:$request.environment_ref} + elif $selector.kind == "input" then + [$request.inputs[] | select(.input_id == $selector.input_id)] as $matches | + if ($matches | length) == 1 + then {state:"present",value:$matches[0].value} + else null + end + elif $selector.kind == "gate-decision" then + [$request.gate_decision_refs[] | + select(.scope_sha256 == $selector.scope_sha256)] as $matches | + if ($matches | length) == 1 + then {state:"present",value:$matches[0]} + else null + end + else null + end; + +def observed_repository_ok($request; $observation; $expected): + $observation.selector.kind as $kind | + $observation.observed as $observed | + if $observed.state == "absent" then true + elif $kind == "target" then + $observed.value.repository_id == $request.target_repository_id + elif $kind == "base" then + $observed.value.repository_id == $request.target_repository_id and + (if $expected.state == "present" then + $observed.value.hash_algorithm == $expected.value.hash_algorithm + else true + end) + elif $kind == "source" and $observed.value.type == "git-object" then + $observed.value.value.revision.repository_id == $request.target_repository_id + else true + end; + +def observed_identity_ok($request; $observation): + $observation.selector.kind as $kind | + $observation.observed as $observed | + if $observed.state == "absent" then true + elif $kind == "resolved-profile" then + $observed.value.kind == "resolved_profile" and + $observed.value.id == $request.resolved_profile_ref.id + elif $kind == "environment" then + $observed.value.environment_id == $request.environment_ref.environment_id + else true + end; + +def stale_observation_relation_ok($request; $observation): + expected_stale_value($request;$observation) as $expected | + $expected != null and $observation.observed != $expected and + observed_repository_ok($request;$observation;$expected) and + observed_identity_ok($request;$observation); + +def refs_relation_ok($request_pair; $resolved_pair; $result): + $result.request_ref == profile_graph::document_ref_for_pair($request_pair) and + $result.resolved_profile_ref == + profile_graph::document_ref_for_pair($resolved_pair) and + $request_pair.content.body.resolved_profile_ref == + profile_graph::document_ref_for_pair($resolved_pair); + +def requested_time_floor_ok($request; $result): + if $result | has("execution") then + $request.requested_at <= $result.started_at + else $request.requested_at <= $result.recorded_at + end; + +def evidence_kinds_allowed($request; $result): + ($request.required_evidence_kinds) as $requested | + all($result.evidence[];.kind as $kind | $requested | index($kind) != null); + +def completed_evidence_exact($request; $result): + ($result.evidence | map(.kind) | sort) == + ($request.required_evidence_kinds | sort); + +def requested_fact_gap($result): + if $result | has("execution") then + $result.execution.metadata as $metadata | + [$metadata.provider,$metadata.model,$metadata.effort,$metadata.prompt, + $metadata.skills,$metadata.tools] | + any(.[];.state == "unavailable") + else false + end; + +def producer_outcome_ok($operation; $result): + ($result.evidence | any(.[];.verdict != "passed")) as $nonpassing | + requested_fact_gap($result) as $fact_gap | + ($result.outputs | length) as $output_count | + if $nonpassing or $fact_gap then + $result.outcome == {family:"change",value:"inconclusive"} and + $result.outputs == [] and ($result | has("delta_ref") | not) + elif $output_count == 0 then + $result.outcome == {family:"change",value:"no-change"} and + ($result | has("delta_ref") | not) + elif $output_count == 1 then + $result.outcome == {family:"change",value:"changed"} and + (if $operation.arguments | has("allowed_delta") then + ($result | has("delta_ref")) and + $result.delta_ref == $result.outputs[0].ref + else ($result | has("delta_ref") | not) + end) + else false + end; + +def forge_outcome_ok($operation; $result): + ($result.evidence | any(.[];.verdict != "passed")) as $nonpassing | + requested_fact_gap($result) as $fact_gap | + ($result.outputs | length) as $output_count | + if $nonpassing or $fact_gap then + $result.outcome == {family:"change",value:"inconclusive"} and + $result.outputs == [] and ($result | has("delta_ref") | not) + elif $output_count == 0 then + $result.outcome == {family:"change",value:"no-change"} and + ($result | has("delta_ref") | not) + elif $output_count == 1 then + $result.outcome == {family:"change",value:"changed"} and + $result.outputs[0].output_id == + $operation.arguments.candidate_output_id and + $result.outputs[0].ref.media_type == "application/json" and + ($result | has("delta_ref") | not) + else false + end; + +def check_outcome_ok($result): + ($result.evidence | any(.[];.verdict == "failed")) as $failed | + ($result.evidence | any(.[];.verdict == "inconclusive")) as $inconclusive | + requested_fact_gap($result) as $fact_gap | + $result.outputs == [] and ($result | has("delta_ref") | not) and + (if $failed then + $result.outcome == {family:"check",value:"failed"} + elif $inconclusive or $fact_gap then + $result.outcome == {family:"check",value:"inconclusive"} + else $result.outcome == {family:"check",value:"passed"} + end); + +def completed_outcome_ok($request; $result): + if $request.operation.capability_id == + "core.forge.materialize-candidate.v2" then + forge_outcome_ok($request.operation;$result) + elif $request.operation.role == "producer" then + producer_outcome_ok($request.operation;$result) + elif $request.operation.role == "verifier" or + $request.operation.role == "reviewer" then + check_outcome_ok($result) + else false + end; + +def passing_review_identity_ok($request; $result): + all($result.evidence[]; + if .kind == "independent-review" and .verdict == "passed" then + $result.execution.performer.role == "reviewer" and + $result.execution.used_capability == + {kind:"registered",id:"core.review.change.v1"} and + $request.operation.role == "reviewer" + else true + end); + +def passing_evidence_execution_ok($request; $resolved; $result): + if any($result.evidence[];.verdict == "passed") then + ($result | has("execution")) and + stage_request::expected_execution_projection($request;$resolved) as $projection | + result_facts::execution_matches_projection($result.execution;$projection) + else true + end; + +def status_external_relation_ok($request; $result): + schema::outcome_family_for_capability( + $request.operation.capability_id) as $outcome_family | + if $result.status == "completed" then + completed_evidence_exact($request;$result) and + completed_outcome_ok($request;$result) and + passing_review_identity_ok($request;$result) + elif ($result.status == "failed" or $result.status == "cancelled") and + ($result | has("execution")) then + $result.outcome == { + family:$outcome_family, + value:"inconclusive" + } + else true + end; + +def stage_result_relation_ok($request_pair; $resolved_pair; $result): + refs_relation_ok($request_pair;$resolved_pair;$result) and + requested_time_floor_ok($request_pair.content.body;$result) and + evidence_kinds_allowed($request_pair.content.body;$result) and + (if $result.status == "stale" then + all($result.stale_observations[]; + stale_observation_relation_ok($request_pair.content.body;.)) + else true + end) and + status_external_relation_ok($request_pair.content.body;$result) and + passing_evidence_execution_ok( + $request_pair.content.body;$resolved_pair.content.body;$result) and + result_facts::stage_result_execution_relation_ok( + $request_pair.content.body;$resolved_pair.content.body;$result); + +def document_shape_ok: + .kind == "stage_result" and schema::envelope_ok("stage_result") and + (.body | stage_result_body_shape_ok); + +def document_self_ok: + document_shape_ok and (.body | stage_result_self_ok); + +def stage_run_ok($request_pair; $resolved_pair; $result_pair): + ($request_pair | profile_graph::document_pair_ok("stage_request")) and + ($resolved_pair | profile_graph::document_pair_ok("resolved_profile")) and + ($result_pair | profile_graph::document_pair_ok("stage_result")) and + ($request_pair.content | stage_request::document_self_ok) and + ($result_pair.content | document_self_ok) and + stage_result_relation_ok( + $request_pair;$resolved_pair;$result_pair.content.body); diff --git a/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/schema.jq b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/schema.jq new file mode 100644 index 0000000..e2bc03a --- /dev/null +++ b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/schema.jq @@ -0,0 +1,395 @@ +def policy_table: + { + roles: [ + {id:"ci", class:"dormant", execution_kinds:["deterministic"], capabilities:[]}, + {id:"execution", class:"dormant", execution_kinds:["deterministic"], capabilities:[]}, + {id:"forge", class:"protected", execution_kinds:["deterministic"], capabilities:["core.forge.materialize-candidate.v2"]}, + {id:"identity", class:"dormant", execution_kinds:["deterministic"], capabilities:[]}, + {id:"producer", class:"protected", execution_kinds:["deterministic","model"], capabilities:["core.harness.produce.v1"]}, + {id:"publisher", class:"protected-dormant", execution_kinds:["deterministic"], capabilities:[]}, + {id:"reviewer", class:"protected", execution_kinds:["deterministic","model"], capabilities:["core.review.change.v1"]}, + {id:"verifier", class:"protected", execution_kinds:["deterministic"], capabilities:["core.verify.run.v1"]} + ], + actor_only_roles: ["manager","observer","operator","orchestrator"], + capabilities: [ + { + id:"core.forge.materialize-candidate.v2", + role:"forge", + argument_shape:"materialize-candidate", + outcome_family:"change", + permissions_by_execution:{ + deterministic:["core.perm.candidate-repository.write.v2","core.perm.evidence.write.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"] + }, + allowed_evidence:["deterministic"], + required_evidence:["deterministic"] + }, + { + id:"core.harness.produce.v1", + role:"producer", + argument_shape:"produce", + outcome_family:"change", + permissions_by_execution:{ + deterministic:["core.perm.evidence.write.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"], + model:["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.scratch.write.v1","core.perm.target.read.v1"] + }, + allowed_evidence:["deterministic"], + required_evidence:["deterministic"] + }, + { + id:"core.review.change.v1", + role:"reviewer", + argument_shape:"review", + outcome_family:"check", + permissions_by_execution:{ + deterministic:["core.perm.evidence.write.v1","core.perm.target.read.v1"], + model:["core.perm.evidence.write.v1","core.perm.model.invoke.v1","core.perm.target.read.v1"] + }, + allowed_evidence:["independent-review"], + required_evidence:["independent-review"] + }, + { + id:"core.verify.run.v1", + role:"verifier", + argument_shape:"verify", + outcome_family:"check", + permissions_by_execution:{ + deterministic:["core.perm.candidate.execute.v1","core.perm.evidence.write.v1","core.perm.target.read.v1"] + }, + allowed_evidence:["architecture","behavioral","deterministic"], + required_evidence:["deterministic"] + } + ], + permissions: [ + {id:"core.perm.candidate.execute.v1",resource:"exact-candidate",actions:["execute"]}, + {id:"core.perm.candidate-repository.write.v2",resource:"caller-disposable-candidate-repository",actions:["write"]}, + {id:"core.perm.evidence.write.v1",resource:"current-attempt-evidence",actions:["append"]}, + {id:"core.perm.model.invoke.v1",resource:"exact-resolved-model-binding",actions:["invoke"]}, + {id:"core.perm.scratch.write.v1",resource:"caller-disposable-scratch",actions:["write"]}, + {id:"core.perm.target.read.v1",resource:"exact-target-git",actions:["read"]} + ], + evidence: [ + {id:"architecture",verdicts:["failed","inconclusive","passed"]}, + {id:"behavioral",verdicts:["failed","inconclusive","passed"]}, + {id:"deterministic",verdicts:["failed","inconclusive","passed"]}, + {id:"independent-review",verdicts:["failed","inconclusive","passed"]} + ] + }; + +def document_kinds: + ["adapter_manifest","profile","resolved_profile","stage_request","stage_result"]; + +def semantic_identity: "core.contracts.v2"; +def adapter_roles: policy_table.roles | map(.id); +def actor_roles: (adapter_roles + policy_table.actor_only_roles) | sort; +def protected_roles: + policy_table.roles | + map(select(.class == "protected" or .class == "protected-dormant") | .id); +def capability_ids: policy_table.capabilities | map(.id); +def permission_ids: policy_table.permissions | map(.id); +def evidence_kinds: policy_table.evidence | map(.id); +def execution_kinds: ["deterministic","model"]; +def scope_purposes: + ["allowed-delta","authority","config-contract","finish-condition","gate-decision", + "gate-requirement","grant","output-contract","policy","qualification", + "repository-context","review-policy","selection","verification-instructions", + "verification-plan"]; + +def capabilities_for_role($role): + [policy_table.roles[] | select(.id == $role) | .capabilities] | + if length == 1 then .[0] else [] end; +def execution_kinds_for_role($role): + [policy_table.roles[] | select(.id == $role) | .execution_kinds] | + if length == 1 then .[0] else [] end; +def capability_execution_kinds($capability): + [policy_table.capabilities[] | + select(.id == $capability) | + (.permissions_by_execution | keys)] | + if length == 1 then .[0] else [] end; +def permissions_for_capability($capability; $execution_kind): + [policy_table.capabilities[] | + select(.id == $capability) | + .permissions_by_execution[$execution_kind] | + select(. != null)] | + if length == 1 then .[0] else [] end; +def allowed_evidence_kinds_for_capability($capability): + [policy_table.capabilities[] | select(.id == $capability) | .allowed_evidence] | + if length == 1 then .[0] else [] end; +def required_evidence_kinds_for_capability($capability): + [policy_table.capabilities[] | select(.id == $capability) | .required_evidence] | + if length == 1 then .[0] else [] end; +def argument_shape_for_capability($capability): + [policy_table.capabilities[] | select(.id == $capability) | .argument_shape] | + if length == 1 then .[0] else null end; +def outcome_family_for_capability($capability): + [policy_table.capabilities[] | select(.id == $capability) | .outcome_family] | + if length == 1 then .[0] else null end; +def evidence_verdicts: + policy_table.evidence | map(.verdicts) | unique | + if length == 1 then .[0] else [] end; + +def exact_fields($required; $optional): + . as $value | + ($value | type) == "object" and + (($value | keys_unsorted) - ($required + $optional) | length) == 0 and + all($required[]; . as $key | $value | has($key)); + +def bounded_set($minimum; $maximum; item_ok; key): + . as $items | + ($items | type) == "array" and + ($items | length) >= $minimum and + ($items | length) <= $maximum and + all($items[]; item_ok) and + (($items | map(key)) as $keys | + ($keys | length) == ($keys | unique | length) and + $keys == ($keys | sort)); + +def enum_set_ok($minimum; $maximum; $allowed): + . as $items | + ($items | type) == "array" and + ($items | length) >= $minimum and + ($items | length) <= $maximum and + all($items[]; . as $item | $allowed | index($item) != null) and + ($items | length) == ($items | unique | length) and + $items == ($items | sort); + +def present_ok(value_ok): + (exact_fields(["state"];[]) and .state == "absent") or + (exact_fields(["state","value"];[]) and + .state == "present" and + (.value | value_ok)); + +def id_ok: type == "string" and test("\\A[a-z0-9][a-z0-9._:-]{0,127}\\z"); +# Schema receives only values accepted by the raw canonical-byte gate; jq 1.6 preserves -0 here. +def int_ok: + type == "number" and + . == floor and + . >= 0 and + . <= 2147483647 and + tostring != "-0"; +def sha256_ok: type == "string" and test("\\A[0-9a-f]{64}\\z"); +def version_ok: id_ok; +def short_text_ok: type == "string" and utf8bytelength >= 1 and utf8bytelength <= 1024; +def media_type_ok: + type == "string" and + length <= 127 and + test("\\A[a-z0-9][a-z0-9!#$&^_.+-]*/[a-z0-9][a-z0-9!#$&^_.+-]*\\z"); +def patch_media_type_ok: . == "text/x-diff"; +def git_oid_ok: + type == "string" and + (test("\\A[0-9a-f]{40}\\z") or test("\\A[0-9a-f]{64}\\z")); +def reverse_dns_ok: + type == "string" and + (split(".") as $labels | + ($labels | length) >= 2 and + all($labels[]; test("\\A[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\z"))); + +def time_ok: + type == "string" and + test("\\A[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z\\z") and + (capture("\\A(?[0-9]{4})-(?[0-9]{2})-(?[0-9]{2})T(?[0-9]{2}):(?[0-9]{2}):(?[0-9]{2})Z\\z") as $parts | + ($parts.year | tonumber) as $year | + ($parts.month | tonumber) as $month | + ($parts.day | tonumber) as $day | + ($parts.hour | tonumber) as $hour | + ($parts.minute | tonumber) as $minute | + ($parts.second | tonumber) as $second | + ($year % 4 == 0 and ($year % 100 != 0 or $year % 400 == 0)) as $leap | + [31,(if $leap then 29 else 28 end),31,30,31,30,31,31,30,31,30,31] as $days | + $month >= 1 and $month <= 12 and + $day >= 1 and $day <= $days[$month - 1] and + $hour >= 0 and $hour <= 23 and + $minute >= 0 and $minute <= 59 and + $second >= 0 and $second <= 59); + +# Oniguruma's bare byte escapes do not match multibyte C1 code points in UTF-8 mode. +def repo_path_ok: + type == "string" and + length > 0 and + (test("[\\x{0000}-\\x{001f}\\x{007f}-\\x{009f}]") | not) and + (contains("\\") | not) and + (split("/") | all(.[]; . != "" and . != "." and . != "..")); + +def parsed_limits_ok: + def within($depth): + if $depth > 32 then false + elif type == "object" then + length <= 256 and + all(keys_unsorted[]; utf8bytelength <= 8192) and + all(.[]; within($depth + 1)) + elif type == "array" then + length <= 256 and all(.[]; within($depth + 1)) + elif type == "string" then utf8bytelength <= 8192 + elif type == "number" then int_ok + else true + end; + within(0); + +def document_kind_ok: + type == "string" and (. as $kind | document_kinds | index($kind) != null); +def adapter_role_ok: + type == "string" and (. as $role | adapter_roles | index($role) != null); +def actor_role_ok: + type == "string" and (. as $role | actor_roles | index($role) != null); +def capability_id_ok: + type == "string" and (. as $id | capability_ids | index($id) != null); +def permission_id_ok: + type == "string" and (. as $id | permission_ids | index($id) != null); +def evidence_kind_ok: + type == "string" and (. as $kind | evidence_kinds | index($kind) != null); +def execution_kind_ok: + type == "string" and (. as $kind | execution_kinds | index($kind) != null); +def scope_purpose_ok: + type == "string" and (. as $purpose | scope_purposes | index($purpose) != null); + +def envelope_ok($kind): + exact_fields(["schema_version","kind","id","body"];[]) and + .schema_version == 2 and + .kind == $kind and + (.kind | document_kind_ok) and + (.id | id_ok) and + (.body | type == "object"); + +def document_envelope_ok: + (.kind? // "") as $kind | + ($kind | document_kind_ok) and envelope_ok($kind); + +def schema_layer_ok: parsed_limits_ok and document_envelope_ok; + +def document_ref_ok: + exact_fields(["schema_version","kind","id","sha256"];[]) and + .schema_version == 2 and + (.kind | document_kind_ok) and + (.id | id_ok) and + (.sha256 | sha256_ok); +def document_ref_kind_ok($kind): document_ref_ok and .kind == $kind; + +def git_revision_ref_ok: + exact_fields(["repository_id","hash_algorithm","commit_id"];[]) and + (.repository_id | id_ok) and + (.hash_algorithm == "sha1" or .hash_algorithm == "sha256") and + (if .hash_algorithm == "sha1" + then (.commit_id | type == "string" and test("\\A[0-9a-f]{40}\\z")) + else (.commit_id | type == "string" and test("\\A[0-9a-f]{64}\\z")) + end); + +def git_location_ok: + (exact_fields(["kind"];[]) and .kind == "root") or + (exact_fields(["kind","value"];[]) and + .kind == "path" and + (.value | repo_path_ok)); + +def git_object_ref_ok: + exact_fields(["revision","location","object_type","object_id","mode"];[]) and + (.revision | git_revision_ref_ok) and + (.location | git_location_ok) and + (.object_type == "blob" or .object_type == "tree") and + (if .revision.hash_algorithm == "sha1" + then (.object_id | type == "string" and test("\\A[0-9a-f]{40}\\z")) + else (.object_id | type == "string" and test("\\A[0-9a-f]{64}\\z")) + end) and + (if .location.kind == "root" then .object_type == "tree" else true end) and + (if .object_type == "tree" + then .mode == "040000" + else (.mode == "100644" or .mode == "100755") + end); + +def content_ref_ok: + exact_fields(["content_id","media_type","sha256"];[]) and + (.content_id | id_ok) and + (.content_id | contains(":") | not) and + (.content_id | contains("/") | not) and + (.media_type | media_type_ok) and + (.sha256 | sha256_ok); + +def artifact_ref_ok: + exact_fields(["type","value"];[]) and + ((.type == "git-object" and (.value | git_object_ref_ok)) or + (.type == "content" and (.value | content_ref_ok))); + +def input_ref_ok: + exact_fields(["type","value"];[]) and + ((.type == "artifact" and (.value | artifact_ref_ok)) or + (.type == "document" and (.value | document_ref_ok))); + +def evidence_ref_ok: + exact_fields(["stage_result_ref","evidence_id"];[]) and + (.stage_result_ref | document_ref_kind_ok("stage_result")) and + (.evidence_id | id_ok); + +def scope_subject_ok: + exact_fields(["type","value"];[]) and + ((.type == "artifact" and (.value | artifact_ref_ok)) or + (.type == "document" and (.value | document_ref_ok))); + +def scope_ref_ok: + exact_fields(["purpose","decision_record_ref","subject_ref","scope_sha256"];[]) and + (.purpose | scope_purpose_ok) and + (.decision_record_ref | content_ref_ok) and + (.subject_ref | scope_subject_ok) and + (.scope_sha256 | sha256_ok); +def scope_ref_purpose_ok($purpose): scope_ref_ok and .purpose == $purpose; + +def actor_ref_ok: + exact_fields( + ["role","implementation_id","implementation_version","adapter_instance_id", + "principal_id","execution_boundary_id"]; + ["authority_ref"]) and + (.role | actor_role_ok) and + (.implementation_id | id_ok) and + (.implementation_version | version_ok) and + (.adapter_instance_id | id_ok) and + (.principal_id | id_ok) and + (.execution_boundary_id | id_ok) and + ((has("authority_ref") | not) or (.authority_ref | scope_ref_purpose_ok("authority"))); + +def environment_ref_ok: + exact_fields(["environment_id","fingerprint_sha256"];[]) and + (.environment_id | id_ok) and + (.fingerprint_sha256 | sha256_ok); + +def tool_ref_ok: + exact_fields(["tool_id","tool_version","package_ref","config_ref"];[]) and + (.tool_id | id_ok) and + (.tool_version | version_ok) and + (.package_ref | git_object_ref_ok) and + (.config_ref | present_ok(git_object_ref_ok)); + +def git_patch_ref_ok: content_ref_ok and .media_type == "text/x-diff"; + +def change_ref_ok: + exact_fields(["repository_id","base","head","delta_ref"];[]) and + (.repository_id | id_ok) and + (.base | present_ok(git_revision_ref_ok)) and + (.head | git_revision_ref_ok) and + (.delta_ref | git_patch_ref_ok) and + .head.repository_id == .repository_id and + (if .base.state == "present" then .base.value.repository_id == .repository_id else true end); + +def source_value_ref_ok: + exact_fields(["source","value_format","value_sha256"];[]) and + (.source | git_object_ref_ok) and + (.value_format == "raw-bytes" or .value_format == "canonical-json") and + (.value_sha256 | sha256_ok) and + (if .value_format == "canonical-json" then .source.object_type == "blob" else true end); + +def delivered_scope_ok($purpose): + exact_fields(["ref","input_id"];[]) and + (.ref | scope_ref_purpose_ok($purpose)) and + (.input_id | id_ok) and + .ref.subject_ref.type == "artifact" and + .ref.subject_ref.value.type == "content"; + +def fact_ok(value_ok): + (exact_fields(["state","value","source_ref"];[]) and + (.state == "recorded" or .state == "computed") and + (.value | value_ok) and + (.source_ref | content_ref_ok)) or + (exact_fields(["state","reason_id"];[]) and + .state == "unavailable" and + (.reason_id | id_ok)) or + (exact_fields(["state"];[]) and .state == "not-applicable"); + +def git_key: + [.revision.repository_id,.revision.hash_algorithm,.revision.commit_id, + .location.kind,(.location.value // ""),.object_type,.object_id,.mode]; +def source_git_key: .source | git_key; diff --git a/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/stage_request.jq b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/stage_request.jq new file mode 100644 index 0000000..aff5cf1 --- /dev/null +++ b/core/v2/generations/g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43/modules/stage_request.jq @@ -0,0 +1,374 @@ +import "schema" as schema; +import "profile_graph" as profile_graph; + +def optional_ok($name; value_ok): + (has($name) | not) or (.[$name] | value_ok); + +def present($value): {state:"present",value:$value}; +def absent: {state:"absent"}; + +def named_input_shape_ok: + schema::exact_fields(["input_id","value"];[]) and + (.input_id | schema::id_ok) and + (.value | schema::input_ref_ok); + +def risk_tier_shape_ok: + schema::exact_fields(["namespace","name"];[]) and + ((.namespace == "core" and + (.name == "routine" or .name == "high" or .name == "bootstrap")) or + ((.namespace | schema::reverse_dns_ok) and (.name | schema::id_ok))); + +def risk_claim_shape_ok: + schema::exact_fields( + ["tier","reason_ids","policy_ref","required_gate_refs"]; + []) and + (.tier | risk_tier_shape_ok) and + (.reason_ids | schema::bounded_set(1;256;schema::id_ok;.)) and + (.policy_ref | schema::scope_ref_purpose_ok("policy")) and + (.required_gate_refs | + schema::bounded_set( + 0;256;schema::scope_ref_purpose_ok("gate-requirement");.scope_sha256)); + +def instruction_media_type_ok: + . == "text/plain" or . == "application/json"; + +def capability_arguments_shape_ok($capability): + schema::argument_shape_for_capability($capability) as $shape | + if $shape == "materialize-candidate" then + schema::exact_fields( + ["source_tree_input_id","candidate_output_id", + "materialization_contract","network_mode"]; + []) and + (.source_tree_input_id | schema::id_ok) and + (.candidate_output_id | schema::id_ok) and + (.materialization_contract | + schema::delivered_scope_ok("output-contract")) and + .network_mode == "deny" + elif $shape == "produce" then + (schema::exact_fields(["artifact_kind","output_contract"];[]) and + (.artifact_kind == "plan" or .artifact_kind == "structured-artifact") and + (.output_contract | schema::delivered_scope_ok("output-contract"))) or + (schema::exact_fields(["artifact_kind","allowed_delta"];[]) and + .artifact_kind == "git-patch" and + (.allowed_delta | schema::delivered_scope_ok("allowed-delta"))) + elif $shape == "verify" then + schema::exact_fields( + ["candidate_input_id","verification_plan","network_mode"]; + []) and + (.candidate_input_id | schema::id_ok) and + (.verification_plan | schema::delivered_scope_ok("verification-plan")) and + .network_mode == "deny" + elif $shape == "review" then + schema::exact_fields(["change_ref","review_policy"];[]) and + (.change_ref | schema::change_ref_ok) and + (.review_policy | schema::delivered_scope_ok("review-policy")) + else false + end; + +def operation_shape_ok: + schema::exact_fields( + ["role","binding_id","capability_id","permissions","arguments"]; + []) and + (.role | schema::adapter_role_ok) and + (.binding_id | schema::id_ok) and + (.capability_id | schema::capability_id_ok) and + (.permissions | schema::enum_set_ok(1;5;schema::permission_ids)) and + (.capability_id as $capability | + .arguments | capability_arguments_shape_ok($capability)); + +def stage_request_body_shape_ok: + schema::exact_fields( + ["initiative_id","workflow_id","stage_id","task_class_id","requested_by", + "target_repository_id","target_revision","source","base","inputs", + "prior_evidence_refs","risk","resolved_profile_ref","selection_ref", + "repository_context_ref","gate_decision_refs","environment_ref","operation", + "finish_condition","verification_instruction","required_evidence_kinds", + "requested_at"]; + ["qualification_ref","grant_ref"]) and + (.initiative_id | schema::id_ok) and + (.workflow_id | schema::id_ok) and + (.stage_id | schema::id_ok) and + (.task_class_id | schema::id_ok) and + (.requested_by | schema::actor_ref_ok) and + (.target_repository_id | schema::id_ok) and + (.target_revision | schema::present_ok(schema::git_revision_ref_ok)) and + (.source | schema::present_ok(schema::artifact_ref_ok)) and + (.base | schema::present_ok(schema::git_revision_ref_ok)) and + (.inputs | schema::bounded_set(0;256;named_input_shape_ok;.input_id)) and + (.prior_evidence_refs | + schema::bounded_set( + 0;256;schema::evidence_ref_ok; + [.stage_result_ref.sha256,.evidence_id])) and + (.risk | risk_claim_shape_ok) and + (.resolved_profile_ref | schema::document_ref_kind_ok("resolved_profile")) and + (.selection_ref | schema::scope_ref_purpose_ok("selection")) and + (.repository_context_ref | + schema::scope_ref_purpose_ok("repository-context")) and + optional_ok("qualification_ref"; + schema::scope_ref_purpose_ok("qualification")) and + optional_ok("grant_ref";schema::scope_ref_purpose_ok("grant")) and + (.gate_decision_refs | + schema::bounded_set( + 0;256;schema::scope_ref_purpose_ok("gate-decision");.scope_sha256)) and + (.environment_ref | schema::environment_ref_ok) and + (.operation | operation_shape_ok) and + (.finish_condition | schema::delivered_scope_ok("finish-condition")) and + (.verification_instruction | + schema::delivered_scope_ok("verification-instructions")) and + (.required_evidence_kinds | + schema::enum_set_ok(1;3;schema::evidence_kinds)) and + (.requested_at | schema::time_ok); + +def stage_request_shape_ok: + schema::envelope_ok("stage_request") and + (.body | stage_request_body_shape_ok); + +def operation_capability_scope($operation): + if $operation.arguments | has("output_contract") then + $operation.arguments.output_contract + elif $operation.arguments | has("allowed_delta") then + $operation.arguments.allowed_delta + elif $operation.arguments | has("verification_plan") then + $operation.arguments.verification_plan + elif $operation.arguments | has("review_policy") then + $operation.arguments.review_policy + elif $operation.arguments | has("materialization_contract") then + $operation.arguments.materialization_contract + else null + end; + +def delivered_scope_input_relation_ok($delivered; $inputs): + [$inputs[] | select(.input_id == $delivered.input_id)] as $matches | + ($matches | length) == 1 and + $matches[0].value == $delivered.ref.subject_ref and + ($delivered.ref.subject_ref.value.value.media_type | + instruction_media_type_ok); + +def instruction_relations_ok($body): + operation_capability_scope($body.operation) as $capability_scope | + if $capability_scope == null then false + else + [$body.finish_condition,$body.verification_instruction,$capability_scope] as $scopes | + ($scopes | map(.input_id)) as $instruction_ids | + ($instruction_ids | unique | length) == 3 and + all($scopes[]; . as $scope | + delivered_scope_input_relation_ok($scope;$body.inputs)) and + (if $body.operation.capability_id == "core.verify.run.v1" then + ($instruction_ids | + index($body.operation.arguments.candidate_input_id) == null) + elif $body.operation.capability_id == + "core.forge.materialize-candidate.v2" then + ($instruction_ids | + index($body.operation.arguments.source_tree_input_id) == null) + else true end) + end; + +def capability_role_relation_ok($operation): + schema::capabilities_for_role($operation.role) == + [$operation.capability_id]; + +def permissions_match_a_role_execution_kind($operation): + schema::execution_kinds_for_role($operation.role) as $role_kinds | + schema::capability_execution_kinds($operation.capability_id) as $capability_kinds | + any($role_kinds[]; . as $execution_kind | + ($capability_kinds | index($execution_kind) != null) and + $operation.permissions == + schema::permissions_for_capability( + $operation.capability_id;$execution_kind)); + +def evidence_relation_ok($operation; $required): + if $operation.capability_id == "core.verify.run.v1" then + ($required | index("deterministic") != null) and + all($required[]; + . == "deterministic" or . == "behavioral" or . == "architecture") + else + $required == + schema::required_evidence_kinds_for_capability( + $operation.capability_id) + end; + +def artifact_repository_ok($artifact; $repository_id): + if $artifact.type == "git-object" then + $artifact.value.revision.repository_id == $repository_id + else true + end; + +def input_repository_ok($input; $repository_id): + if $input.value.type == "artifact" then + artifact_repository_ok($input.value.value;$repository_id) + else true + end; + +def request_repository_relations_ok($body): + $body.target_repository_id as $repository_id | + (if $body.target_revision.state == "present" then + $body.target_revision.value.repository_id == $repository_id + else true end) and + (if $body.source.state == "present" then + artifact_repository_ok($body.source.value;$repository_id) + else true end) and + (if $body.base.state == "present" then + $body.base.value.repository_id == $repository_id + else true end) and + all($body.inputs[]; . as $input | + input_repository_ok($input;$repository_id)) and + (if $body.operation.capability_id == "core.review.change.v1" then + $body.operation.arguments.change_ref.repository_id == $repository_id + else true end); + +def verifier_candidate_relation_ok($body): + if $body.operation.capability_id == "core.verify.run.v1" then + $body.operation.arguments.candidate_input_id as $candidate_id | + [$body.inputs[] | select(.input_id == $candidate_id)] as $matches | + $body.target_revision.state == "present" and + ($matches | length) == 1 and + $matches[0].value.type == "artifact" and + $matches[0].value.value.type == "git-object" and + $matches[0].value.value.value.object_type == "tree" and + $matches[0].value.value.value.revision == $body.target_revision.value + else true + end; + +def reviewer_change_relation_ok($body): + if $body.operation.capability_id == "core.review.change.v1" then + $body.target_revision.state == "present" and + $body.operation.arguments.change_ref.head == $body.target_revision.value and + $body.operation.arguments.change_ref.base == $body.base + else true + end; + +def forge_materialization_relation_ok($body): + if $body.operation.capability_id == + "core.forge.materialize-candidate.v2" then + $body.operation.arguments.source_tree_input_id as $source_id | + [$body.inputs[] | select(.input_id == $source_id)] as $matches | + $body.target_revision.state == "present" and + ($matches | length) == 1 and + $matches[0].value.type == "artifact" and + $matches[0].value.value.type == "git-object" and + $matches[0].value.value.value.object_type == "tree" and + $matches[0].value.value.value.revision == $body.target_revision.value and + all($body.inputs[]; + .input_id != $body.operation.arguments.candidate_output_id) + else true + end; + +def absent_target_relation_ok($body): + if $body.target_revision.state == "absent" then + $body.operation.role == "producer" and + $body.risk.tier == {namespace:"core",name:"bootstrap"} + else true + end; + +def stage_request_self_relations_ok: + . as $body | + capability_role_relation_ok($body.operation) and + permissions_match_a_role_execution_kind($body.operation) and + evidence_relation_ok($body.operation;$body.required_evidence_kinds) and + instruction_relations_ok($body) and + request_repository_relations_ok($body) and + verifier_candidate_relation_ok($body) and + reviewer_change_relation_ok($body) and + forge_materialization_relation_ok($body) and + absent_target_relation_ok($body); + +def stage_request_self_ok: + stage_request_shape_ok and + (.body | stage_request_self_relations_ok); + +def stage_request_resolved_ref_ok($request_pair; $resolved_pair): + $request_pair.content.body.resolved_profile_ref == + profile_graph::document_ref_for_pair($resolved_pair); + +def selected_resolved_binding($request_body; $resolved_body): + [$resolved_body.bindings[] | + select(.binding.binding_id == $request_body.operation.binding_id)]; + +def selected_binding_relation_ok($operation; $resolved_binding): + $resolved_binding.binding as $binding | + $binding.role == $operation.role and + $binding.requested_capabilities == [$operation.capability_id] and + $binding.requested_permissions == $operation.permissions and + $operation.permissions == + schema::permissions_for_capability( + $operation.capability_id;$binding.execution_kind); + +def stage_request_resolved_relation_ok($request_body; $resolved_body): + selected_resolved_binding($request_body;$resolved_body) as $matches | + $request_body.selection_ref == $resolved_body.selection_ref and + $request_body.repository_context_ref == $resolved_body.repository_context_ref and + ($matches | length) == 1 and + selected_binding_relation_ok($request_body.operation;$matches[0]); + +def projected_actual_binding($resolved_binding): + $resolved_binding.binding as $binding | + { + binding_id:$binding.binding_id, + role:$binding.role, + adapter_implementation:$resolved_binding.adapter_implementation, + manifest_ref:$binding.manifest_ref, + package_ref:$binding.package_ref, + config_ref:(if $binding | has("config_ref") + then present($binding.config_ref) + else absent end), + execution_kind:$binding.execution_kind, + adapter_instance_id:$binding.adapter_instance_id, + principal_id:$binding.principal_id, + execution_boundary_id:$binding.execution_boundary_id + } + + (if $binding | has("authority_ref") + then {authority_ref:$binding.authority_ref} + else {} end); + +def projected_performer($resolved_binding): + $resolved_binding.binding as $binding | + { + role:$binding.role, + implementation_id:$resolved_binding.adapter_implementation.id, + implementation_version:$resolved_binding.adapter_implementation.version, + adapter_instance_id:$binding.adapter_instance_id, + principal_id:$binding.principal_id, + execution_boundary_id:$binding.execution_boundary_id + } + + (if $binding | has("authority_ref") + then {authority_ref:$binding.authority_ref} + else {} end); + +def metadata_expectation($binding): + { + kind:$binding.execution_kind, + model_request:(if $binding | has("model_request") + then present($binding.model_request) + else absent end), + prompt_ref:(if $binding | has("prompt_ref") + then present($binding.prompt_ref) + else absent end), + skill_refs:$binding.skill_refs, + allowed_tools:$binding.requested_tools + }; + +def expected_execution_projection($request_body; $resolved_body): + selected_resolved_binding($request_body;$resolved_body) as $matches | + if (($matches | length) == 1 and + selected_binding_relation_ok($request_body.operation;$matches[0])) then + $matches[0] as $resolved_binding | + { + actual_binding:projected_actual_binding($resolved_binding), + performer:projected_performer($resolved_binding), + environment:$request_body.environment_ref, + used_capability:{kind:"registered",id:$request_body.operation.capability_id}, + execution_kind:$resolved_binding.binding.execution_kind, + metadata_expectation:metadata_expectation($resolved_binding.binding) + } + else null + end; + +def document_shape_ok: + if .kind == "stage_request" then stage_request_shape_ok + else false + end; + +def document_self_ok: + if .kind == "stage_request" then stage_request_self_ok + else false + end; diff --git a/orchestrator/v1/state-scanner-driver.sh b/orchestrator/v1/state-scanner-driver.sh index 86a486d..5680749 100755 --- a/orchestrator/v1/state-scanner-driver.sh +++ b/orchestrator/v1/state-scanner-driver.sh @@ -54,9 +54,9 @@ program="$runtime/program.jq" jq_bin="$runtime/jq" work="$runtime_parent/work" verify_runtime() { - verify_hash 8838c85aae5a2ed9ada659ae1a13c5cf8f561463789d1d5d9f28370d479f6c80 \ + verify_hash 43f6e3fabe1bec7025fb6068ccbe3b034d3c16a0ac33d1a9d7de5757e1b92fa7 \ "$program" && - verify_hash f55b697716dc13a6d2c71bde7769493b3f4b091fd7a94d3280c5d417974df3a1 \ + verify_hash 3950ce43c3073b97759db23fb7e4ce533cbc1d8a8fe4917db6ee1ee0a8e78f94 \ "$runtime/core/v2/generation-registry.json" && verify_hash 65eb40b9afb9b4f1d809ed66d0f2ca625f656c34e856cedcde9cbbde857f0f0a \ "$runtime/core/v2/generations/$generation/contracts.jq" && diff --git a/orchestrator/v1/state-scanner-launcher.sh b/orchestrator/v1/state-scanner-launcher.sh index 5a7f351..523901c 100755 --- a/orchestrator/v1/state-scanner-launcher.sh +++ b/orchestrator/v1/state-scanner-launcher.sh @@ -129,12 +129,12 @@ snapshot_file "$source_dir/scan-state.sh" "$runtime/bootstrap.sh" 1048576 0400 | bootstrap_sha=$(sha256_path "$runtime/bootstrap.sh") || emit_error E_RUNTIME snapshot_file "$self" "$runtime/launcher.sh" 1048576 0400 || emit_error E_RUNTIME launcher_sha=$(sha256_path "$runtime/launcher.sh") || emit_error E_RUNTIME -snapshot_expected 3f0b14cddd27ef7638b3227159af686defa5f5662c893096cc6711a692d57d1a \ +snapshot_expected 10d3ad263f5757fc403ae6eb758fef630570e594b029cf2e314cda08dfb37de3 \ "$source_dir/state-scanner-driver.sh" "$runtime/driver.sh" 0400 || emit_error E_STALE -snapshot_expected 8838c85aae5a2ed9ada659ae1a13c5cf8f561463789d1d5d9f28370d479f6c80 \ +snapshot_expected 43f6e3fabe1bec7025fb6068ccbe3b034d3c16a0ac33d1a9d7de5757e1b92fa7 \ "$source_dir/state-scanner.jq" "$runtime/program.jq" 0400 || emit_error E_STALE -snapshot_expected f55b697716dc13a6d2c71bde7769493b3f4b091fd7a94d3280c5d417974df3a1 \ +snapshot_expected 3950ce43c3073b97759db23fb7e4ce533cbc1d8a8fe4917db6ee1ee0a8e78f94 \ "$repo/core/v2/generation-registry.json" \ "$runtime/core/v2/generation-registry.json" 0400 || emit_error E_STALE snapshot_expected 65eb40b9afb9b4f1d809ed66d0f2ca625f656c34e856cedcde9cbbde857f0f0a \ @@ -168,8 +168,8 @@ snapshot_sha=$(sha256_path "$scratch/input.json") || emit_error E_RUNTIME "$runtime/jq" -S -c -n \ --arg bootstrap_sha "$bootstrap_sha" --arg launcher_sha "$launcher_sha" \ - --arg driver_sha 3f0b14cddd27ef7638b3227159af686defa5f5662c893096cc6711a692d57d1a \ - --arg program_sha 8838c85aae5a2ed9ada659ae1a13c5cf8f561463789d1d5d9f28370d479f6c80 \ + --arg driver_sha 10d3ad263f5757fc403ae6eb758fef630570e594b029cf2e314cda08dfb37de3 \ + --arg program_sha 43f6e3fabe1bec7025fb6068ccbe3b034d3c16a0ac33d1a9d7de5757e1b92fa7 \ --arg jq_sha "$jq_sha" --arg bash_sha "$bash_sha" \ --arg host_os "$host_os" --arg host_arch "$host_arch" \ --arg jq_arch "$jq_arch" --arg execution_mode "$execution_mode" ' @@ -182,11 +182,11 @@ snapshot_sha=$(sha256_path "$scratch/input.json") || emit_error E_RUNTIME generation_id_sha256:"6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137", package_ref:ref("core-contract-package.v2"; "application/vnd.ystack.core-contract+json"; - "005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716"), + "2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c"), semantic_identity:"core.contracts.v2" }, core_closure:[ - {path:"core/v2/generation-registry.json",sha256:"f55b697716dc13a6d2c71bde7769493b3f4b091fd7a94d3280c5d417974df3a1"}, + {path:"core/v2/generation-registry.json",sha256:"3950ce43c3073b97759db23fb7e4ce533cbc1d8a8fe4917db6ee1ee0a8e78f94"}, {path:"core/v2/generations/g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e/contracts.jq",sha256:"65eb40b9afb9b4f1d809ed66d0f2ca625f656c34e856cedcde9cbbde857f0f0a"}, {path:"core/v2/generations/g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e/core-ingress.sh",sha256:"db87c6e97e93dc2a6eebd83087878c04f5528badc620d57fc9d883694e2ac28b"}, {path:"core/v2/generations/g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e/modules/profile_graph.jq",sha256:"c00f9cfbe88df5cb1dbcfbead61288ff7d68684d43d095e74f26e7820f0d7207"}, @@ -213,7 +213,7 @@ evaluator_sha=$(sha256_path "$runtime/evaluator.json") || emit_error E_RUNTIME verify_private_core() { [ "$(sha256_path "$runtime/core/v2/generation-registry.json")" = \ - f55b697716dc13a6d2c71bde7769493b3f4b091fd7a94d3280c5d417974df3a1 ] && + 3950ce43c3073b97759db23fb7e4ce533cbc1d8a8fe4917db6ee1ee0a8e78f94 ] && [ "$(sha256_path "$generation_runtime/contracts.jq")" = \ 65eb40b9afb9b4f1d809ed66d0f2ca625f656c34e856cedcde9cbbde857f0f0a ] && [ "$(sha256_path "$generation_runtime/core-ingress.sh")" = \ @@ -280,9 +280,9 @@ verify_private_core || emit_error E_STALE [ "$(sha256_path "$runtime/bootstrap.sh")" = "$bootstrap_sha" ] && [ "$(sha256_path "$runtime/launcher.sh")" = "$launcher_sha" ] && [ "$(sha256_path "$runtime/driver.sh")" = \ - 3f0b14cddd27ef7638b3227159af686defa5f5662c893096cc6711a692d57d1a ] && + 10d3ad263f5757fc403ae6eb758fef630570e594b029cf2e314cda08dfb37de3 ] && [ "$(sha256_path "$runtime/program.jq")" = \ - 8838c85aae5a2ed9ada659ae1a13c5cf8f561463789d1d5d9f28370d479f6c80 ] && + 43f6e3fabe1bec7025fb6068ccbe3b034d3c16a0ac33d1a9d7de5757e1b92fa7 ] && [ "$(sha256_path "$runtime/jq")" = "$jq_sha" ] && [ "$(sha256_path /bin/bash)" = "$bash_sha" ] && [ "$(sha256_path "$scratch/input.json")" = "$snapshot_sha" ] && diff --git a/orchestrator/v1/state-scanner.jq b/orchestrator/v1/state-scanner.jq index 6ccbc1c..22772e5 100644 --- a/orchestrator/v1/state-scanner.jq +++ b/orchestrator/v1/state-scanner.jq @@ -20,7 +20,7 @@ def expected_core: package_ref:{ content_id:"core-contract-package.v2", media_type:"application/vnd.ystack.core-contract+json", - sha256:"005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716" + sha256:"2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c" }, semantic_identity:"core.contracts.v2" }; @@ -28,7 +28,7 @@ def expected_core: def expected_core_closure: [ {path:"core/v2/generation-registry.json", - sha256:"f55b697716dc13a6d2c71bde7769493b3f4b091fd7a94d3280c5d417974df3a1"}, + sha256:"3950ce43c3073b97759db23fb7e4ce533cbc1d8a8fe4917db6ee1ee0a8e78f94"}, {path:"core/v2/generations/g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e/contracts.jq", sha256:"65eb40b9afb9b4f1d809ed66d0f2ca625f656c34e856cedcde9cbbde857f0f0a"}, {path:"core/v2/generations/g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e/core-ingress.sh", diff --git a/scripts/lib/profile-resolution.sh b/scripts/lib/profile-resolution.sh index d252c0b..8154f06 100755 --- a/scripts/lib/profile-resolution.sh +++ b/scripts/lib/profile-resolution.sh @@ -6,7 +6,7 @@ PROFILE_RESOLUTION_CORE_GENERATION='g-392d20099dfa99872764009b268c8871914b4dbc0d PROFILE_RESOLUTION_CORE_PUBLISHER_RECEIPT_SHA256='25772b9054b433a2c2a5e689aa2364700e2872f514d1e4319aa26c9bb1803d47' PROFILE_RESOLUTION_CONTRACTS_BLOB='8efe7582480d179463e0e88aac9a7874689786d1' PROFILE_RESOLUTION_WRAPPER_BLOB='dcb0e8500e52dd129c6aae9451049d563720b2ee' -PROFILE_RESOLUTION_REGISTRY_BLOB='56071404b150b8187f8c10fd036385aad7b9a86c' +PROFILE_RESOLUTION_REGISTRY_BLOB='0bc09fa56047b2e3fdecf22559f68468f0528797' PROFILE_RESOLUTION_INGRESS_BLOB='9ddaf700594266d67aeb17c881dea04236d5015f' PROFILE_RESOLUTION_SCHEMA_MAJOR='2' PROFILE_RESOLUTION_GLOBAL_LIMIT=536870912 diff --git a/scripts/test/default-claude-code-producer-adapter.test.sh b/scripts/test/default-claude-code-producer-adapter.test.sh index 989579e..0541679 100755 --- a/scripts/test/default-claude-code-producer-adapter.test.sh +++ b/scripts/test/default-claude-code-producer-adapter.test.sh @@ -26,7 +26,13 @@ jq_bin="${TMPDIR:-/tmp}/ystack-portable-core-jq16/$asset" jq_cmd=("$jq_bin") [ "$platform" != Darwin:arm64 ] || jq_cmd=(/usr/bin/arch -x86_64 "$jq_bin") [ "$("${jq_cmd[@]}" --version)" = jq-1.6 ] || exit 1 -generation=$("${jq_cmd[@]}" -r '.[-1].generation_id' "$root/core/v2/generation-registry.json") +generation=$(/usr/bin/sed -n \ + "s/^PORTABLE_CORE_GENERATION='\(g-[0-9a-f]\\{64\\}\)'$/\\1/p" \ + "$root/scripts/core-contract.sh") +[ -n "$generation" ] && + [ "$("${jq_cmd[@]}" -r --arg generation "$generation" \ + '[.[] | select(.generation_id==$generation)] | length' \ + "$root/core/v2/generation-registry.json")" -eq 1 ] || exit 1 modules="$root/core/v2/generations/$generation/modules" [ -d "$modules" ] || exit 1 diff --git a/scripts/test/default-codex-native-reviewer-adapter.test.sh b/scripts/test/default-codex-native-reviewer-adapter.test.sh index ac9a387..54fa5e3 100755 --- a/scripts/test/default-codex-native-reviewer-adapter.test.sh +++ b/scripts/test/default-codex-native-reviewer-adapter.test.sh @@ -28,9 +28,13 @@ if [ "$platform" = Darwin:arm64 ]; then jq_command=(/usr/bin/arch -x86_64 "$jq_b runtime_bin="$tmp/bin" /bin/mkdir -m 700 "$runtime_bin" /bin/ln -s "$jq_bin" "$runtime_bin/jq" -generation=$("${jq_command[@]}" -er \ - 'select(type=="array" and length==1) | .[0].generation_id' \ - "$root/core/v2/generation-registry.json") +generation=$(/usr/bin/sed -n \ + "s/^PORTABLE_CORE_GENERATION='\(g-[0-9a-f]\\{64\\}\)'$/\\1/p" \ + "$root/scripts/core-contract.sh") +[ -n "$generation" ] && + [ "$("${jq_command[@]}" -r --arg generation "$generation" \ + '[.[] | select(.generation_id==$generation)] | length' \ + "$root/core/v2/generation-registry.json")" -eq 1 ] || fail 'selected generation' modules="$root/core/v2/generations/$generation/modules" check() { diff --git a/scripts/test/default-github-forge-adapter.test.sh b/scripts/test/default-github-forge-adapter.test.sh index 3c95137..05a421b 100755 --- a/scripts/test/default-github-forge-adapter.test.sh +++ b/scripts/test/default-github-forge-adapter.test.sh @@ -110,9 +110,13 @@ expect_reject() { } ' >"$tmp/baseline.json" -generation=$("${jq_command[@]}" -er \ - 'select(type=="array" and length==1) | .[0].generation_id' \ - "$root/core/v2/generation-registry.json") +generation=$(/usr/bin/sed -n \ + "s/^PORTABLE_CORE_GENERATION='\(g-[0-9a-f]\\{64\\}\)'$/\\1/p" \ + "$root/scripts/core-contract.sh") +[ -n "$generation" ] && + [ "$("${jq_command[@]}" -r --arg generation "$generation" \ + '[.[] | select(.generation_id==$generation)] | length' \ + "$root/core/v2/generation-registry.json")" -eq 1 ] || fail 'selected generation' modules="$root/core/v2/generations/$generation/modules" expect_state open-ready '.' open-ready diff --git a/scripts/test/orchestrator-reconciliation-plan.test.sh b/scripts/test/orchestrator-reconciliation-plan.test.sh index 8724b27..11522aa 100755 --- a/scripts/test/orchestrator-reconciliation-plan.test.sh +++ b/scripts/test/orchestrator-reconciliation-plan.test.sh @@ -42,7 +42,14 @@ fi /bin/chmod 0555 "$tmp/bin/jq" jq_bin="$tmp/bin/jq" [ "$("$jq_bin" --version)" = jq-1.6 ] || fail 'jq identity' -generation=$("$jq_bin" -er '.[0].generation_id' "$root/core/v2/generation-registry.json") +generation=$(/usr/bin/sed -n \ + "s/^PORTABLE_CORE_GENERATION='\(g-[0-9a-f]\\{64\\}\)'$/\\1/p" \ + "$root/scripts/core-contract.sh") +[ -n "$generation" ] && + [ "$("$jq_bin" -r --arg generation "$generation" \ + '[.[] | select(.generation_id==$generation)] | length' \ + "$root/core/v2/generation-registry.json")" -eq 1 ] || + fail 'selected generation' schema_dir="$root/core/v2/generations/$generation/modules" [ -f "$schema_dir/schema.jq" ] && [ ! -L "$schema_dir/schema.jq" ] || fail 'selected schema module' diff --git a/scripts/test/orchestrator-state-scanner.test.sh b/scripts/test/orchestrator-state-scanner.test.sh index 3d0869f..3d4a1f9 100755 --- a/scripts/test/orchestrator-state-scanner.test.sh +++ b/scripts/test/orchestrator-state-scanner.test.sh @@ -92,9 +92,9 @@ expect_class() { (.body.evaluator.content.body.bootstrap_ref.sha256 | test("^[0-9a-f]{64}$")) and .body.evaluator.content.body.program_ref.sha256 == - "8838c85aae5a2ed9ada659ae1a13c5cf8f561463789d1d5d9f28370d479f6c80" and + "43f6e3fabe1bec7025fb6068ccbe3b034d3c16a0ac33d1a9d7de5757e1b92fa7" and .body.evaluator.content.body.driver_ref.sha256 == - "3f0b14cddd27ef7638b3227159af686defa5f5662c893096cc6711a692d57d1a" and + "10d3ad263f5757fc403ae6eb758fef630570e594b029cf2e314cda08dfb37de3" and .body.evaluator.content.body.runtime.host_architecture == $host_arch and .body.evaluator.content.body.runtime.execution_mode == $execution_mode and (.body.evaluator.content.body.core_closure | length) == 9 and @@ -232,7 +232,7 @@ make_snapshot() { generation_id_sha256:"6f6acbbd0cf40ab3c913328d6c0070635424ffe920bcdb900fbd0718345d7137", package_ref:{content_id:"core-contract-package.v2", media_type:"application/vnd.ystack.core-contract+json", - sha256:"005431c5c7e3a39dc3ab75dfcafd0f09359331667fdcacb140514a4384592716"}, + sha256:"2742f9c097943bb140cc0f19feda1e3b653ce95e699c570f9e9fc48825137c6c"}, semantic_identity:"core.contracts.v2" }, items:[{ diff --git a/scripts/test/portable-core-schema.test.sh b/scripts/test/portable-core-schema.test.sh index 0f3c892..8e39cc6 100755 --- a/scripts/test/portable-core-schema.test.sh +++ b/scripts/test/portable-core-schema.test.sh @@ -6,13 +6,17 @@ schema_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)" schema_generation="g-14b7ad8ce54c3b8c585ff92063d71551ffc7394cc2294d0297bc7d2b8da2c386" schema_selected_generation="g-71433a31f52f37041a41b5a8812f79c4c0f5f26c79265788c8d625a9c6f9686b" schema_v2_generation="g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e" +schema_v2_corrective_generation="g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43" schema_base="38a26f5f046897c0455fef24874c5dbb40c20926" schema_module_dir="$schema_root/core/v1/generations/$schema_generation/modules" schema_module="$schema_module_dir/schema.jq" schema_registry="$schema_root/core/v1/generation-registry.json" schema_v2_registry="$schema_root/core/v2/generation-registry.json" schema_v2_root="$schema_root/core/v2/generations/$schema_v2_generation" +schema_v2_corrective_root="$schema_root/core/v2/generations/$schema_v2_corrective_generation" schema_v2_test="$schema_root/scripts/test/portable-core-v2-fake-forge.test.sh" +schema_v2_corrective_test="$schema_root/scripts/test/portable-core-v2-evidence-identity.test.sh" +schema_v2_corrective_ledger="$schema_root/scripts/test/portable-core-v2-evidence-identity-ledger.tsv" schema_fixture="$schema_root/scripts/test/portable-core-schema-fixtures.json" schema_ledger="$schema_root/scripts/test/portable-core-schema-ledger.tsv" schema_manifest="$schema_root/ci/required-files.txt" @@ -574,7 +578,14 @@ v2_generation_path_ok() { "core/v2/generations/$schema_v2_generation/modules/profile_graph.jq"|\ "core/v2/generations/$schema_v2_generation/modules/stage_request.jq"|\ "core/v2/generations/$schema_v2_generation/modules/result_facts.jq"|\ - "core/v2/generations/$schema_v2_generation/modules/result_truth.jq") return 0 ;; + "core/v2/generations/$schema_v2_generation/modules/result_truth.jq"|\ + "core/v2/generations/$schema_v2_corrective_generation/core-ingress.sh"|\ + "core/v2/generations/$schema_v2_corrective_generation/contracts.jq"|\ + "core/v2/generations/$schema_v2_corrective_generation/modules/schema.jq"|\ + "core/v2/generations/$schema_v2_corrective_generation/modules/profile_graph.jq"|\ + "core/v2/generations/$schema_v2_corrective_generation/modules/stage_request.jq"|\ + "core/v2/generations/$schema_v2_corrective_generation/modules/result_facts.jq"|\ + "core/v2/generations/$schema_v2_corrective_generation/modules/result_truth.jq") return 0 ;; *) return 1 ;; esac } @@ -635,7 +646,7 @@ schema_activation_state_ok() { [ -z "$(find "$selected_root" -type l -print -quit)" ] } -schema_guard_total=39 +schema_guard_total=41 schema_generation_files="$schema_test_tmp/generation-files" find "$schema_root/core/v1/generations/$schema_generation" -type f -print | \ sed "s#^$schema_root/##" | LC_ALL=C sort > "$schema_generation_files" @@ -670,6 +681,26 @@ if v2_generation_paths_ok "$schema_v2_generation_files" && else fail_case "core v2 generation has an unknown, missing, or symlink member" fi +schema_v2_corrective_files="$schema_test_tmp/v2-corrective-files" +schema_v2_corrective_expected="$schema_test_tmp/v2-corrective-expected" +find "$schema_v2_corrective_root" -type f -print | + sed "s#^$schema_root/##" | LC_ALL=C sort > "$schema_v2_corrective_files" +printf '%s\n' \ + "core/v2/generations/$schema_v2_corrective_generation/contracts.jq" \ + "core/v2/generations/$schema_v2_corrective_generation/core-ingress.sh" \ + "core/v2/generations/$schema_v2_corrective_generation/modules/profile_graph.jq" \ + "core/v2/generations/$schema_v2_corrective_generation/modules/result_facts.jq" \ + "core/v2/generations/$schema_v2_corrective_generation/modules/result_truth.jq" \ + "core/v2/generations/$schema_v2_corrective_generation/modules/schema.jq" \ + "core/v2/generations/$schema_v2_corrective_generation/modules/stage_request.jq" > \ + "$schema_v2_corrective_expected" +if v2_generation_paths_ok "$schema_v2_corrective_files" && + cmp -s "$schema_v2_corrective_files" "$schema_v2_corrective_expected" && + [ -z "$(find "$schema_v2_corrective_root" -type l -print -quit)" ]; then + schema_guard_passed=$((schema_guard_passed + 1)) +else + fail_case "corrective core v2 generation has an unknown, missing, or symlink member" +fi schema_v2_manifest_paths="core/v2/generation-registry.json core/v2/generations/$schema_v2_generation/contracts.jq core/v2/generations/$schema_v2_generation/core-ingress.sh @@ -678,7 +709,16 @@ core/v2/generations/$schema_v2_generation/modules/result_facts.jq core/v2/generations/$schema_v2_generation/modules/result_truth.jq core/v2/generations/$schema_v2_generation/modules/schema.jq core/v2/generations/$schema_v2_generation/modules/stage_request.jq -scripts/test/portable-core-v2-fake-forge.test.sh" +scripts/test/portable-core-v2-fake-forge.test.sh +core/v2/generations/$schema_v2_corrective_generation/contracts.jq +core/v2/generations/$schema_v2_corrective_generation/core-ingress.sh +core/v2/generations/$schema_v2_corrective_generation/modules/profile_graph.jq +core/v2/generations/$schema_v2_corrective_generation/modules/result_facts.jq +core/v2/generations/$schema_v2_corrective_generation/modules/result_truth.jq +core/v2/generations/$schema_v2_corrective_generation/modules/schema.jq +core/v2/generations/$schema_v2_corrective_generation/modules/stage_request.jq +scripts/test/portable-core-v2-evidence-identity-ledger.tsv +scripts/test/portable-core-v2-evidence-identity.test.sh" schema_v2_manifest_ok=true while IFS= read -r schema_v2_required_path; do [ "$(grep -Fxc "$schema_v2_required_path" "$schema_manifest" || true)" -eq 1 ] && @@ -693,17 +733,25 @@ if "$schema_jq" -s -S -c \ "$schema_jq" -e \ --arg generation "$schema_v2_generation" \ --arg parent "$schema_selected_generation" ' - length == 1 and + length == 2 and .[0] == { authorization_comment_id:5476938197, concern:"fake-forge-materialization-contract", generation_id:$generation, parent_generation_id:$parent, semantic_identity:"core.contracts.v2" + } and + .[1] == { + authorization_comment_id:5517944082, + concern:"incident-mismatch-nonpassing-evidence", + generation_id:"g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43", + parent_generation_id:$generation, + semantic_identity:"core.contracts.v2" } ' "$schema_v2_registry" >/dev/null && [ "$schema_v2_manifest_ok" = true ] && - [ -x "$schema_v2_test" ]; then + [ -x "$schema_v2_test" ] && [ -x "$schema_v2_corrective_test" ] && + [ -f "$schema_v2_corrective_ledger" ] && [ ! -L "$schema_v2_corrective_ledger" ]; then schema_guard_passed=$((schema_guard_passed + 1)) else fail_case "core v2 registry, restore manifest, or focused runner is incomplete" @@ -767,6 +815,7 @@ v2_activation_path_ok() { scripts/core-contract.sh|scripts/lib/profile-resolution.sh|\ scripts/test/orchestrator-state-scanner.test.sh|\ scripts/test/portable-core-schema.test.sh|\ + scripts/test/portable-core-v2-evidence-identity.test.sh|\ scripts/test/portable-core-v2-fake-forge.test.sh) ;; *) v2_generation_path_ok "$1" || return 1 ;; esac @@ -856,6 +905,7 @@ printf '%s\n' \ scripts/lib/profile-resolution.sh \ scripts/test/orchestrator-state-scanner.test.sh \ scripts/test/portable-core-schema.test.sh \ + scripts/test/portable-core-v2-evidence-identity.test.sh \ scripts/test/portable-core-v2-fake-forge.test.sh > \ "$schema_v2_expected_live_hits" if cmp -s "$schema_v2_live_hits" "$schema_v2_expected_live_hits" && @@ -864,6 +914,27 @@ if cmp -s "$schema_v2_live_hits" "$schema_v2_expected_live_hits" && else fail_case "v2 generation ID appears outside its closed tracked-path allowlist" fi +schema_v2_corrective_live_hits="$schema_test_tmp/v2-corrective-live-hits" +: > "$schema_v2_corrective_live_hits" +while IFS= read -r -d '' schema_tracked_path; do + if git -C "$schema_root" show ":$schema_tracked_path" 2>/dev/null | + /usr/bin/grep -F "$schema_v2_corrective_generation" >/dev/null; then + printf '%s\n' "$schema_tracked_path" >> "$schema_v2_corrective_live_hits" + fi +done < <(git -C "$schema_root" ls-files -z) +schema_v2_corrective_expected_hits="$schema_test_tmp/v2-corrective-expected-hits" +printf '%s\n' \ + ci/required-files.txt \ + core/v2/generation-registry.json \ + "core/v2/generations/$schema_v2_corrective_generation/core-ingress.sh" \ + scripts/test/portable-core-schema.test.sh \ + scripts/test/portable-core-v2-evidence-identity.test.sh > \ + "$schema_v2_corrective_expected_hits" +if cmp -s "$schema_v2_corrective_live_hits" "$schema_v2_corrective_expected_hits"; then + schema_guard_passed=$((schema_guard_passed + 1)) +else + fail_case "corrective v2 generation ID appears outside its closed tracked-path allowlist" +fi if activation_paths_ok "$schema_import_hits" schema_import_path_ok; then schema_guard_passed=$((schema_guard_passed + 1)) else @@ -901,6 +972,13 @@ printf '%s\n' \ "core/v2/generations/$schema_v2_generation/modules/result_truth.jq" \ "core/v2/generations/$schema_v2_generation/modules/schema.jq" \ "core/v2/generations/$schema_v2_generation/modules/stage_request.jq" \ + "core/v2/generations/$schema_v2_corrective_generation/contracts.jq" \ + "core/v2/generations/$schema_v2_corrective_generation/core-ingress.sh" \ + "core/v2/generations/$schema_v2_corrective_generation/modules/profile_graph.jq" \ + "core/v2/generations/$schema_v2_corrective_generation/modules/result_facts.jq" \ + "core/v2/generations/$schema_v2_corrective_generation/modules/result_truth.jq" \ + "core/v2/generations/$schema_v2_corrective_generation/modules/schema.jq" \ + "core/v2/generations/$schema_v2_corrective_generation/modules/stage_request.jq" \ orchestrator/v1/state-scanner-driver.sh \ orchestrator/v1/state-scanner-launcher.sh \ orchestrator/v1/state-scanner.jq \ @@ -908,6 +986,7 @@ printf '%s\n' \ scripts/lib/profile-resolution.sh \ scripts/test/orchestrator-state-scanner.test.sh \ scripts/test/portable-core-schema.test.sh \ + scripts/test/portable-core-v2-evidence-identity.test.sh \ scripts/test/portable-core-v2-fake-forge.test.sh > "$schema_v2_allowed_paths" schema_v2_injected_source="$schema_test_tmp/v2-injected-source" schema_v2_injected_hits="$schema_test_tmp/v2-injected-hits" diff --git a/scripts/test/portable-core-v2-evidence-identity-ledger.tsv b/scripts/test/portable-core-v2-evidence-identity-ledger.tsv new file mode 100644 index 0000000..3beb522 --- /dev/null +++ b/scripts/test/portable-core-v2-evidence-identity-ledger.tsv @@ -0,0 +1,2 @@ +source row_id disposition rule_id test_id +review pr-222-important-1 ported portable-core-v2-evidence-identity.passing-evidence-execution portable-core-v2-evidence-identity.test.incident-mismatch-passed-rejected diff --git a/scripts/test/portable-core-v2-evidence-identity.test.sh b/scripts/test/portable-core-v2-evidence-identity.test.sh new file mode 100755 index 0000000..89a0ada --- /dev/null +++ b/scripts/test/portable-core-v2-evidence-identity.test.sh @@ -0,0 +1,249 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2016 +set -euo pipefail +export LC_ALL=C + +root=$(CDPATH='' cd -P -- "${BASH_SOURCE[0]%/*}/../.." && pwd -P) +fixtures="$root/scripts/test" +generation=g-c83c940afd16550a4f8a4dbee2b9a6f37e429063d277962ba81c141ba5303b43 +parent=g-392d20099dfa99872764009b268c8871914b4dbc0da467ec346baa921818ae3e +generation_root="$root/core/v2/generations/$generation" +parent_root="$root/core/v2/generations/$parent" +registry="$root/core/v2/generation-registry.json" +ledger="$root/scripts/test/portable-core-v2-evidence-identity-ledger.tsv" +tmp=$(/usr/bin/mktemp -d "${TMPDIR:-/tmp}/ystack-core-v2-evidence.XXXXXX") +trap '/bin/rm -rf -- "$tmp"' EXIT + +sha_file() { /usr/bin/shasum -a 256 "$1" | /usr/bin/awk '{print $1}'; } +sha_text() { /usr/bin/printf '%s' "$1" | /usr/bin/shasum -a 256 | /usr/bin/awk '{print $1}'; } +fail() { /usr/bin/printf 'FAIL: %s\n' "$1" >&2; exit 1; } +passed=0 +pass() { passed=$((passed + 1)); /usr/bin/printf 'ok %s - %s\n' "$passed" "$1"; } +check() { local name=$1; shift; "$@" >/dev/null 2>&1 || fail "$name"; pass "$name"; } + +platform=$(/usr/bin/uname -s):$(/usr/bin/uname -m) +case "$platform" in + Darwin:*) asset=jq-osx-amd64; digest=5c0a0a3ea600f302ee458b30317425dd9632d1ad8882259fcaf4e9b868b2b1ef ;; + Linux:x86_64) asset=jq-linux64; digest=af986793a515d500ab2d35f8d2aecd656e764504b789b66d7e1a0b727a124c44 ;; + *) fail "unsupported jq 1.6 proof platform: $platform" ;; +esac +jq_bin="${TMPDIR:-/tmp}/ystack-portable-core-jq16/$asset" +[ -f "$jq_bin" ] && [ ! -L "$jq_bin" ] && [ "$(sha_file "$jq_bin")" = "$digest" ] || + fail 'verified jq 1.6 cache is required' +jq_cmd=("$jq_bin") +[ "$platform" != Darwin:arm64 ] || jq_cmd=(/usr/bin/arch -x86_64 "$jq_bin") +[ "$("${jq_cmd[@]}" --version)" = jq-1.6 ] || fail 'jq version' +runtime_bin="$tmp/runtime-bin" +/bin/mkdir -m 0700 "$runtime_bin" +/bin/ln -s "$jq_bin" "$runtime_bin/jq" +export PATH="$runtime_bin:/usr/bin:/bin" + +run_generation() ( + local mode=$1 input + shift + set -uo pipefail + # shellcheck source=/dev/null + source "$generation_root/core-ingress.sh" 2>/dev/null || exit 1 + trap 'portable_core_ingress_close >/dev/null 2>&1 || :' EXIT + portable_core_ingress_open || exit 1 + portable_core_ingress_begin "$mode" || exit 1 + for input in "$@"; do portable_core_ingress_snapshot "$input" || exit 1; done + portable_core_ingress_finish_driver || exit 1 + portable_core_ingress_validate || exit 1 + portable_core_ingress_close || exit 1 + trap - EXIT +) + +expect_pass() { + local name=$1 mode=$2 + shift 2 + if run_generation "$mode" "$@" >"$tmp/$name.out" 2>"$tmp/$name.err" && + [ ! -s "$tmp/$name.out" ] && [ ! -s "$tmp/$name.err" ]; then pass "$name" + else /bin/cat "$tmp/$name.err" >&2; fail "$name"; fi +} +expect_relation() { + local name=$1 expected=$2 request=$3 result=$4 + local output="$tmp/$name.out" error="$tmp/$name.err" status=0 + run_generation stage-run "$request" "$resolved" "$result" >"$output" 2>"$error" || status=$? + if [ "$expected" = pass ]; then + [ "$status" -eq 0 ] && [ ! -s "$output" ] && [ ! -s "$error" ] || fail "$name" + else + if [ "$status" -eq 0 ] || [ -s "$output" ] || + [ "$(/bin/cat "$error")" != E_RELATION ]; then + /bin/cat "$error" >&2 + fail "$name" + fi + fi + pass "$name" +} +mutate() { "${jq_cmd[@]}" -S -c "$3" "$1" >"$2"; } + +preimage="portable-core-v2|selected-generation=$parent|authorization-comment=5517944082|concern=incident-mismatch-nonpassing-evidence" +check generation-derived test "g-$(sha_text "$preimage")" = "$generation" +check registry-entry "${jq_cmd[@]}" -e --arg generation "$generation" --arg parent "$parent" ' + length==2 and .[1]=={authorization_comment_id:5517944082, + concern:"incident-mismatch-nonpassing-evidence",generation_id:$generation, + parent_generation_id:$parent,semantic_identity:"core.contracts.v2"} and + .[0].generation_id==$parent and + ([.[].generation_id] | length)==([.[].generation_id] | unique | length) +' "$registry" +check ledger-exact /usr/bin/awk -F '\t' ' + NR==1 {ok=($0=="source\trow_id\tdisposition\trule_id\ttest_id"); next} + NR==2 {ok=ok && $1=="review" && $2=="pr-222-important-1" && $3=="ported" && + $4=="portable-core-v2-evidence-identity.passing-evidence-execution" && + $5=="portable-core-v2-evidence-identity.test.incident-mismatch-passed-rejected"; next} + {ok=0} END {exit !(ok && NR==2)} +' "$ledger" + +for path in contracts.jq modules/schema.jq modules/profile_graph.jq \ + modules/stage_request.jq modules/result_facts.jq; do + /usr/bin/cmp -s "$parent_root/$path" "$generation_root/$path" || fail "copied-$path" +done +pass copied-exports-byte-identical + +roles=(producer publisher reviewer verifier) +manifest_files=() +for role in "${roles[@]}"; do + file="$tmp/manifest-$role.json" + "${jq_cmd[@]}" -L "$fixtures" -S -c -n --arg role "$role" ' + import "portable-core-profile-graph-fixtures" as f; + def v2: walk(if type=="object" and has("schema_version") then .schema_version=2 else . end); + f::manifest($role) | v2 + ' >"$file" + manifest_files+=("$file") +done +forge_manifest="$tmp/manifest-forge.json" +"${jq_cmd[@]}" -L "$fixtures" -S -c -n ' + import "portable-core-profile-graph-fixtures" as f; + {schema_version:2,kind:"adapter_manifest",id:"manifest.forge",body:{ + adapter_version:"v2",package_ref:f::blob("packages/forge.bin";"6"), + offered_roles:["forge"],offered_execution_kinds:["deterministic"], + offered_capabilities:["core.forge.materialize-candidate.v2"], + offered_permissions:["core.perm.candidate-repository.write.v2", + "core.perm.evidence.write.v1","core.perm.scratch.write.v1", + "core.perm.target.read.v1"],offered_tools:[]}} +' >"$forge_manifest" +manifest_files=("$forge_manifest" "${manifest_files[@]}") +manifest_shas=$( + "${jq_cmd[@]}" -S -c -n \ + --arg forge "$(sha_file "$forge_manifest")" \ + --arg producer "$(sha_file "$tmp/manifest-producer.json")" \ + --arg publisher "$(sha_file "$tmp/manifest-publisher.json")" \ + --arg reviewer "$(sha_file "$tmp/manifest-reviewer.json")" \ + --arg verifier "$(sha_file "$tmp/manifest-verifier.json")" \ + '{forge:$forge,producer:$producer,publisher:$publisher,reviewer:$reviewer,verifier:$verifier}' +) +profile="$tmp/profile.json" +"${jq_cmd[@]}" -L "$fixtures" -S -c -n --argjson shas "$manifest_shas" ' + import "portable-core-profile-graph-fixtures" as f; + def v2: walk(if type=="object" and has("schema_version") then .schema_version=2 else . end); + def forge_binding:{binding_id:"binding.forge",role:"forge", + manifest_ref:{schema_version:2,kind:"adapter_manifest",id:"manifest.forge",sha256:$shas.forge}, + execution_kind:"deterministic",adapter_instance_id:"instance.forge",principal_id:"principal.forge", + execution_boundary_id:"boundary.forge",authority_ref:f::scope("authority";"authority-forge";f::sha("5")), + package_ref:f::blob("packages/forge.bin";"6"),skill_refs:[],requested_tools:[], + requested_capabilities:["core.forge.materialize-candidate.v2"], + requested_permissions:["core.perm.candidate-repository.write.v2","core.perm.evidence.write.v1", + "core.perm.scratch.write.v1","core.perm.target.read.v1"]}; + f::profile_doc($shas) | v2 | .body.profile_version="v2" | + .body.bindings += [forge_binding] | .body.bindings |= sort_by(.binding_id) +' >"$profile" +profile_sha=$(sha_file "$profile") +resolved="$tmp/resolved.json" +"${jq_cmd[@]}" -L "$fixtures" -S -c -n --slurpfile profile "$profile" \ + --arg profile_sha "$profile_sha" --argjson shas "$manifest_shas" ' + import "portable-core-profile-graph-fixtures" as f; + def v2: walk(if type=="object" and has("schema_version") then .schema_version=2 else . end); + f::resolved_profile_doc($profile[0];$profile_sha;$shas) | v2 | + .body.bindings |= map(if .binding.role=="forge" then + .adapter_implementation.version="v2" | + .manifest_source=f::source_value(f::blob("manifests/forge.json";"a");"canonical-json";$shas.forge) + else . end) +' >"$resolved" +resolved_sha=$(sha_file "$resolved") +expect_pass profile-set profile-set "$profile" "$resolved" "${manifest_files[@]}" + +for role in producer reviewer verifier; do + request="$tmp/request-$role.json" + "${jq_cmd[@]}" -L "$fixtures" -S -c -n --arg role "$role" --arg sha "$resolved_sha" ' + import "portable-core-stage-request-fixtures" as f; + def v2: walk(if type=="object" and has("schema_version") then .schema_version=2 else . end); + f::request_doc($role;$sha) | v2 + ' >"$request" + request_sha=$(sha_file "$request") + base="$tmp/base-$role.json" + "${jq_cmd[@]}" -L "$fixtures" -S -c -n --slurpfile request "$request" \ + --slurpfile resolved "$resolved" --arg request_sha "$request_sha" --arg resolved_sha "$resolved_sha" ' + import "portable-core-result-truth-fixtures" as f; + def v2: walk(if type=="object" and has("schema_version") then .schema_version=2 else . end); + f::completed_result_doc($request[0];$request_sha;$resolved[0];$resolved_sha) | v2 | + .body.execution.metadata.tools={state:"unavailable",reason_id:"provider.tools-unavailable"} | + .body.outcome.value="inconclusive" | .body.reason={reason_id:"evidence.identity-check"} + ' >"$base" + expect_relation "$role-correct-fact-gap-passed" pass "$request" "$base" + + wrong="$tmp/$role-wrong-principal.json" + mutate "$base" "$wrong" '.body.execution.actual_binding.principal_id="principal.other" | + .body.execution.performer.principal_id="principal.other" | + .body.reported_by.principal_id="principal.other"' + expect_relation "$role-wrong-principal-passed" reject "$request" "$wrong" + + nonpassing="$tmp/$role-wrong-principal-nonpassing.json" + mutate "$wrong" "$nonpassing" '.body.evidence |= map(.verdict="inconclusive")' + expect_relation "$role-wrong-principal-nonpassing" pass "$request" "$nonpassing" +done + +request="$tmp/request-verifier.json" +base="$tmp/base-verifier.json" +for field in binding_id adapter_instance_id execution_boundary_id; do + candidate="$tmp/verifier-wrong-$field.json" + mutate "$base" "$candidate" ".body.execution.actual_binding.$field=\"other.$field\"" + expect_relation "verifier-wrong-$field-passed" reject "$request" "$candidate" +done +candidate="$tmp/verifier-wrong-implementation.json" +mutate "$base" "$candidate" '.body.execution.actual_binding.adapter_implementation.id="adapter.other" | + .body.execution.performer.implementation_id="adapter.other" | .body.reported_by.implementation_id="adapter.other"' +expect_relation verifier-wrong-implementation-passed reject "$request" "$candidate" +candidate="$tmp/verifier-wrong-environment.json" +mutate "$base" "$candidate" '.body.execution.environment.environment_id="environment.other"' +expect_relation verifier-wrong-environment-passed reject "$request" "$candidate" +candidate="$tmp/verifier-wrong-registered-capability.json" +mutate "$base" "$candidate" '.body.execution.used_capability={kind:"registered",id:"core.review.change.v1"}' +expect_relation verifier-wrong-registered-capability-passed reject "$request" "$candidate" +candidate="$tmp/verifier-ci-unclassified.json" +mutate "$base" "$candidate" ' + .body.execution.actual_binding |= (.binding_id="binding.ci" | .role="ci" | + .adapter_implementation={id:"adapter.github-actions-ci.v1",version:"v1"} | + .adapter_instance_id="instance.ci" | .principal_id="principal.ci" | + .execution_boundary_id="boundary.ci" | del(.authority_ref)) | + .body.execution.performer={role:"ci",implementation_id:"adapter.github-actions-ci.v1", + implementation_version:"v1",adapter_instance_id:"instance.ci",principal_id:"principal.ci", + execution_boundary_id:"boundary.ci"} | .body.reported_by=.body.execution.performer | + .body.execution.used_capability={kind:"unclassified",id:"github.actions.observe.v1"} +' +expect_relation verifier-ci-unclassified-passed reject "$request" "$candidate" +nonpassing="$tmp/verifier-ci-unclassified-nonpassing.json" +mutate "$candidate" "$nonpassing" '.body.evidence |= map(.verdict="inconclusive")' +expect_relation verifier-ci-unclassified-nonpassing pass "$request" "$nonpassing" +mixed="$tmp/verifier-mixed.json" +mutate "$tmp/verifier-wrong-principal.json" "$mixed" \ + '.body.evidence[0].verdict="inconclusive"' +expect_relation verifier-mismatch-mixed-passed reject "$request" "$mixed" + +for status in failed cancelled; do + candidate="$tmp/verifier-$status-passed.json" + mutate "$tmp/verifier-ci-unclassified.json" "$candidate" ".body.status=\"$status\" | + .body.reason={reason_id:\"stage.$status\"} | .body.outcome={family:\"check\",value:\"inconclusive\"} | + .body.outputs=[] | .body.diagnostics=(if \"$status\"==\"failed\" then + [{content_id:\"diagnostic.failed\",media_type:\"text/plain\",sha256:(\"d\"*64)}] else [] end)" + expect_relation "verifier-$status-mismatch-passed" reject "$request" "$candidate" + nonpassing="$tmp/verifier-$status-nonpassing.json" + mutate "$candidate" "$nonpassing" '.body.evidence |= map(.verdict="inconclusive")' + expect_relation "verifier-$status-mismatch-nonpassing" pass "$request" "$nonpassing" +done + +check result-truth-diff /usr/bin/grep -Fq 'passing_evidence_execution_ok' \ + "$generation_root/modules/result_truth.jq" +check new-ingress-id /usr/bin/grep -Fq "$generation" "$generation_root/core-ingress.sh" + +/usr/bin/printf 'portable core v2 evidence identity: %s/%s checks passed\n' "$passed" "$passed" diff --git a/scripts/test/portable-core-v2-fake-forge.test.sh b/scripts/test/portable-core-v2-fake-forge.test.sh index 1085781..3760758 100755 --- a/scripts/test/portable-core-v2-fake-forge.test.sh +++ b/scripts/test/portable-core-v2-fake-forge.test.sh @@ -436,10 +436,11 @@ check protected-profile-separation expect_v2_error protected-profile-separation check registry-canonical cmp -s "$registry" \ <("${jq_command[@]}" -S -c . "$registry") -check registry-single-unique "${jq_command[@]}" -e --arg generation "$generation_id" \ - 'type == "array" and length == 1 and +check registry-prefix-unique "${jq_command[@]}" -e --arg generation "$generation_id" \ + 'type == "array" and length == 2 and (map(.generation_id) | length == (unique | length)) and .[0].generation_id == $generation and + .[1].parent_generation_id == $generation and .[0].semantic_identity == "core.contracts.v2"' "$registry" registered_generations="$("${jq_command[@]}" -r \ '.[].generation_id' "$registry" | LC_ALL=C sort)"