From 8389d2d2950673042a9b5db16d73ce7daeff73a1 Mon Sep 17 00:00:00 2001 From: Midia Kiasat Date: Thu, 19 Mar 2026 09:39:44 +0100 Subject: [PATCH 1/2] Align CORPIFORM runtime authority enforcement and ledger fixtures --- bodies/deploy/promote/execute.sh | 0 bodies/mail/send/adapters/api.sh | 0 bodies/mail/send/adapters/smtp.sh | 0 bodies/mail/send/execute.sh | 0 bodies/payment/transfer/execute.sh | 0 bodies/publish/release/execute.sh | 0 denials/emit.sh | 0 execution/emit_denial.sh | 0 execution/emit_receipt.sh | 0 execution/gate.sh | 25 ++++++----- execution/refuse_on_ambiguity.sh | 0 execution/refuse_without_seal.sh | 0 execution/state_lock/acquire_lock.sh | 0 execution/state_lock/release_lock.sh | 0 execution/validate_authority.sh | 0 fixtures/expired_authority/command.json | 13 ++++++ fixtures/expired_authority/seal.json | 14 +++++++ fixtures/invalid_authority/command.json | 13 ++++++ fixtures/invalid_authority/seal.json | 13 ++++++ fixtures/keys/denial.key | 27 ++++++++++++ fixtures/keys/receipt.key | 27 ++++++++++++ fixtures/replay_attempt/command.json | 13 ++++++ fixtures/replay_attempt/seal.json | 14 +++++++ fixtures/revoked_authority/command.json | 13 ++++++ .../revoked_authority/revocation.record.json | 2 +- fixtures/revoked_authority/seal.json | 14 +++++++ fixtures/time_violation/command.json | 13 ++++++ fixtures/time_violation/seal.json | 14 +++++++ fixtures/valid_authority/command.json | 13 ++++++ fixtures/valid_authority/seal.json | 14 +++++++ revocation/apply.sh | 0 revocation/verify.sh | 0 runtime/runner/run.sh | 41 ++++++++++++++----- seals/reject_invalid.sh | 0 seals/require_auctoriseal.sh | 0 seals/verify_custody.sh | 0 seals/verify_revocation.sh | 27 ++++++++++++ seals/verify_scope.sh | 37 ++++++++++++++--- seals/verify_seal.sh | 0 seals/verify_time_window.sh | 40 ++++++++++-------- tests/must_execute_once.test | 6 ++- tests/must_honor_revocation.test | 16 ++++---- tests/must_record_ledger.test | 1 + 43 files changed, 354 insertions(+), 56 deletions(-) mode change 100644 => 100755 bodies/deploy/promote/execute.sh mode change 100644 => 100755 bodies/mail/send/adapters/api.sh mode change 100644 => 100755 bodies/mail/send/adapters/smtp.sh mode change 100644 => 100755 bodies/mail/send/execute.sh mode change 100644 => 100755 bodies/payment/transfer/execute.sh mode change 100644 => 100755 bodies/publish/release/execute.sh mode change 100644 => 100755 denials/emit.sh mode change 100644 => 100755 execution/emit_denial.sh mode change 100644 => 100755 execution/emit_receipt.sh mode change 100644 => 100755 execution/gate.sh mode change 100644 => 100755 execution/refuse_on_ambiguity.sh mode change 100644 => 100755 execution/refuse_without_seal.sh mode change 100644 => 100755 execution/state_lock/acquire_lock.sh mode change 100644 => 100755 execution/state_lock/release_lock.sh mode change 100644 => 100755 execution/validate_authority.sh create mode 100644 fixtures/expired_authority/command.json create mode 100644 fixtures/expired_authority/seal.json create mode 100644 fixtures/invalid_authority/command.json create mode 100644 fixtures/invalid_authority/seal.json create mode 100644 fixtures/keys/denial.key create mode 100644 fixtures/keys/receipt.key create mode 100644 fixtures/replay_attempt/command.json create mode 100644 fixtures/replay_attempt/seal.json create mode 100644 fixtures/revoked_authority/command.json create mode 100644 fixtures/revoked_authority/seal.json create mode 100644 fixtures/time_violation/command.json create mode 100644 fixtures/time_violation/seal.json create mode 100644 fixtures/valid_authority/command.json create mode 100644 fixtures/valid_authority/seal.json mode change 100644 => 100755 revocation/apply.sh mode change 100644 => 100755 revocation/verify.sh mode change 100644 => 100755 seals/reject_invalid.sh mode change 100644 => 100755 seals/require_auctoriseal.sh mode change 100644 => 100755 seals/verify_custody.sh create mode 100755 seals/verify_revocation.sh mode change 100644 => 100755 seals/verify_scope.sh mode change 100644 => 100755 seals/verify_seal.sh mode change 100644 => 100755 seals/verify_time_window.sh mode change 100644 => 100755 tests/must_execute_once.test mode change 100644 => 100755 tests/must_honor_revocation.test mode change 100644 => 100755 tests/must_record_ledger.test diff --git a/bodies/deploy/promote/execute.sh b/bodies/deploy/promote/execute.sh old mode 100644 new mode 100755 diff --git a/bodies/mail/send/adapters/api.sh b/bodies/mail/send/adapters/api.sh old mode 100644 new mode 100755 diff --git a/bodies/mail/send/adapters/smtp.sh b/bodies/mail/send/adapters/smtp.sh old mode 100644 new mode 100755 diff --git a/bodies/mail/send/execute.sh b/bodies/mail/send/execute.sh old mode 100644 new mode 100755 diff --git a/bodies/payment/transfer/execute.sh b/bodies/payment/transfer/execute.sh old mode 100644 new mode 100755 diff --git a/bodies/publish/release/execute.sh b/bodies/publish/release/execute.sh old mode 100644 new mode 100755 diff --git a/denials/emit.sh b/denials/emit.sh old mode 100644 new mode 100755 diff --git a/execution/emit_denial.sh b/execution/emit_denial.sh old mode 100644 new mode 100755 diff --git a/execution/emit_receipt.sh b/execution/emit_receipt.sh old mode 100644 new mode 100755 diff --git a/execution/gate.sh b/execution/gate.sh old mode 100644 new mode 100755 index 4291866..c1ede1c --- a/execution/gate.sh +++ b/execution/gate.sh @@ -5,24 +5,27 @@ set -euo pipefail # Central enforcement gate. No execution may proceed past this point # without satisfying all authority and policy checks. -# Required environment variables : "${AUTHORITY_SEAL_PATH:?REFUSE: AUTHORITY_SEAL_PATH not set}" : "${EXECUTION_COMMAND_PATH:?REFUSE: EXECUTION_COMMAND_PATH not set}" : "${EXECUTION_CUSTODIAN:?REFUSE: EXECUTION_CUSTODIAN not set}" -# Authority presence -seals/require_auctoriseal.sh +run_or_reject() { + local script="$1" + local reason="$2" -# Authority verification -seals/verify_seal.sh -seals/verify_scope.sh -seals/verify_time_window.sh -seals/verify_custody.sh + if ! "$script"; then + seals/reject_invalid.sh "$reason" + fi +} + +run_or_reject seals/require_auctoriseal.sh MISSING_AUTHORITY_SEAL +run_or_reject seals/verify_seal.sh INVALID_AUTHORITY_SEAL +run_or_reject seals/verify_scope.sh AUTHORITY_SCOPE_VIOLATION +run_or_reject seals/verify_time_window.sh AUTHORITY_TIME_WINDOW_VIOLATION +run_or_reject seals/verify_custody.sh AUTHORITY_CUSTODY_VIOLATION +run_or_reject seals/verify_revocation.sh AUTHORITY_REVOKED -# Acquire execute-once lock execution/state_lock/acquire_lock.sh -# Execution permitted beyond this point echo "EXECUTION GATE PASSED" - exit 0 diff --git a/execution/refuse_on_ambiguity.sh b/execution/refuse_on_ambiguity.sh old mode 100644 new mode 100755 diff --git a/execution/refuse_without_seal.sh b/execution/refuse_without_seal.sh old mode 100644 new mode 100755 diff --git a/execution/state_lock/acquire_lock.sh b/execution/state_lock/acquire_lock.sh old mode 100644 new mode 100755 diff --git a/execution/state_lock/release_lock.sh b/execution/state_lock/release_lock.sh old mode 100644 new mode 100755 diff --git a/execution/validate_authority.sh b/execution/validate_authority.sh old mode 100644 new mode 100755 diff --git a/fixtures/expired_authority/command.json b/fixtures/expired_authority/command.json new file mode 100644 index 0000000..a583037 --- /dev/null +++ b/fixtures/expired_authority/command.json @@ -0,0 +1,13 @@ +{ + "command_id": "cmd-expired-001", + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp", + "parameters": { + "to": "recipient@example.test", + "from": "sender@example.test", + "subject": "Expired Authority Test", + "body": "This execution must be refused because the authority is expired." + }, + "authority_seal_id": "seal-expired-001" +} diff --git a/fixtures/expired_authority/seal.json b/fixtures/expired_authority/seal.json new file mode 100644 index 0000000..5045306 --- /dev/null +++ b/fixtures/expired_authority/seal.json @@ -0,0 +1,14 @@ +{ + "issuer": "root.primary", + "authority_seal_id": "seal-expired-001", + "custodian": "test-custodian", + "scope": { + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp" + }, + "valid_from": "2015-01-01T00:00:00Z", + "valid_until": "2020-01-01T00:00:00Z", + "single_use": true, + "signature": "TEST_SIGNATURE_EXPIRED_AUTHORITY" +} diff --git a/fixtures/invalid_authority/command.json b/fixtures/invalid_authority/command.json new file mode 100644 index 0000000..e6382ed --- /dev/null +++ b/fixtures/invalid_authority/command.json @@ -0,0 +1,13 @@ +{ + "command_id": "cmd-invalid-001", + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp", + "parameters": { + "to": "recipient@example.test", + "from": "sender@example.test", + "subject": "Invalid Authority Test", + "body": "This execution must be refused due to invalid authority." + }, + "authority_seal_id": "seal-invalid-missing-signature" +} diff --git a/fixtures/invalid_authority/seal.json b/fixtures/invalid_authority/seal.json new file mode 100644 index 0000000..331a851 --- /dev/null +++ b/fixtures/invalid_authority/seal.json @@ -0,0 +1,13 @@ +{ + "issuer": "root.primary", + "authority_seal_id": "seal-invalid-missing-signature", + "custodian": "test-custodian", + "scope": { + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp" + }, + "valid_from": "2025-01-01T00:00:00Z", + "valid_until": "2030-01-01T00:00:00Z", + "single_use": true +} diff --git a/fixtures/keys/denial.key b/fixtures/keys/denial.key new file mode 100644 index 0000000..d1f3c6d --- /dev/null +++ b/fixtures/keys/denial.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAreBOCtBzzkl6y0C41lURMsOjXiZSpWPaJYpPj4O4Cb/GrvJe +LUdj6yrd+NYz76W8Qhfluj5Yw5X9qMKye6gWP/l924kgSdF2AN3NpUPmThsj2RIv +UNHarT/aSrwTpHWfpNc16swFMVm6xviNYx0aFQHGNkkC3cGNjlvw01izpIoQuBav +Wwcuz42RB0VmjqTjutTukxUCAKqaWjeAahwlAy9KhdieLQe3tROkRaqzunnVrIAP +IN/wmzw88AUrUVyeLwwWtmaU738UwMAmuvXZgqer4K/OX5Eg4xAqUEHg53dyLYlE +xiCAYzN5Yf/h6ocmr3qwIQtwuVITGQyFfFOIRwIDAQABAoIBAAUL03gA4LuF6mhn +snWV9m/QubcLya4/HZ+lSfXSTs8Jn8yIAC+0OLQkhFiqbstvtez9II+tK4pRmhEB +xYhNMogcx4hNjIBX8eLIjSVUuSRfKUUtf+4KiRwqFD3DA5bsSvvPuyLbVPM/tWn8 +4K2VtKITcRs2Nz0UVvVgubaIhn4p711xJHxIV/opWrSaMWduYyBm375vasmwhf3/ +z09rjrTIyAAQL3IRKQSj2INv9cCcdUr2N1za3iv08Ev2/nge1YVB5NWiLun56MNM +df9eZ3B6gmK4eyQipMElMk+2oL1zK7M75hR6ea0wqZQ5drfOxrbAWGmYuiQC9mX1 +U/BGxPECgYEA2koUb3hveDff9A9xTFVjxb7S8309YIuSzXIkpra3f6Vc+iW3P2Wj +6BAvSgIF5UmW+cuaf6etMGAwI+5CyV/lq4pVMOneGVKMrbbt59JGkJ0IEACTkWi1 +sVo2zbGLLxbk6VyJpTkTn7yGd7vHxogTQRc4LLGxq06p0X8K1WwYpGsCgYEAy+oJ +hwdcL+3ot+SYV2FkTlUcEpkNCPJb8srCL60VwZXh0kfg1KZ3lcuKBMIZeZGy9Lja +et7r0M84v8iEaQ+1LdpctN6zesi2z9wp08tJ9d4X0hYZ1YMiYdWTLR64yX42UQoe +8RCcEOGVNtRhKo6rArscq41YutGb0X6WBobZApUCgYBdYpXNfmOJtbWsjrK0qk8t +uM48dpa8Z9mc5LkDTWXBSPg2183GZHAzhkEE00q8ZbgeE1l8RTqVWIEfzf1qcwkp +UtvROivW/3bJllm+9DlWAqgBWI3JBle8kNCjPNJDifLSVtFYCsv3aUrJjF8R8wLx +tMJGdJqCo/uIcWYsGbuNEwKBgFuluVh931oPVGvqCuoi9KEcMXzOWwRtYRQTOwmQ +glm6Un9fHNaWZuLlUwfmcOqpqEPDHTbiIBx+NiREK/bIP4b3QHluKj6CHV/4tLfj +Az/E7PHYSw4iXP6Zrgc2apjs596ubM+txmbz7EtzUqR88LFOhYk5AuscMCsM+MLA +MqKtAoGATeFtkKz/sBI9D5hP44hVVBKGjihcfdNID/SisHgKXu/RT0ksgMuvADUP +L6ueP4to7ToxijAs66YymgI/yDC0scEjdCwQcueCPhKobWWTga8qwvtWNp0U80RZ +SdRfSrjp5fhpGfRb6jJlciuJPictJ9hZwQU+7PPNikWAxLVK9yM= +-----END RSA PRIVATE KEY----- diff --git a/fixtures/keys/receipt.key b/fixtures/keys/receipt.key new file mode 100644 index 0000000..388db48 --- /dev/null +++ b/fixtures/keys/receipt.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA1FShs0OaJRZIzzjrytumnEFaqIf/SPYMThlpwJpDvF/nVxlZ +46Yl9GnKvgU4brllPkwjM1HFMosyVzWEchQPqCXLptIIDoGE9VWsMcRikDwzl5cy +LoTB5gj6WKex/9vRt8nNk4+yPJ3oRSz4URfbFS0SKotM9l6/ctyLYugUl0qx6hP3 +JMU0zYCel1p2uGhoIJwkJahtPD8DCkL6JdaR62dUK0392yKzM2b8zv69PvjFqCvb +azaRgMOLauQER0zmnR75fzgwO83mfWTnf/0DRcRC8PJCgklI5b1VM8hnbzA/+4f/ +9R8oIK6AlAY2kj7T+oIW7w/56Vl0POKluRO49wIDAQABAoIBAQCXkSo0Sud33eZv +ddRrZEwUclqCv0GuFWVHQsDIqdX8XAFJnWEbLfkd9X6yEgvsjg8FX1gpRA+eOtre +gedff46FmyU6mecCY9ZDQrq+c89f4nl5loZNypqW2IXMTziyyXl01msXEJZMyvOI +ncdMK9lJzniPQgzYOV40YdZl7gD01SDYlqZO9dYcadP9Lb+II002qd2GsLB4JyEx +1CATTC4iy0DEdclyKfkN2J+7ihuXFnDcYlDjEMOLkByiMDgXSV4rN0JUI6RJoJPV +JwRxMwBqMxU+pUbzJlpvcfqROF+v5OxsIq01SBPfQ6RDc80R/y8ZvuxS0hkilzLY +a1PSqwmxAoGBAP9yzTc3fuHaFO++ofVo4e92H8pJ5W/xGF4g75cWZQ/ur2wByiz+ +Fq+7P5F0y8ZZ1QffALKHit+39L+XGJ7IZG76SXDnNO7XVWRZKPLxkq85hsH4KO4+ +Py0tiyXvC1XaHlSf6U7Y106qZNhhr5SFtp/d5tXoOya7s8UMrIGV36BLAoGBANTJ +/ysmrVwIiF2zDTXywZMV/Iqfoc+HzpFABRdk37LqB1rDKPeS8hn+bq417iajjL30 +11c4ZJ5KabwWcO2+ukvEjo/PN2GVeZV4he46saIQUHZmqkg8Tj1D4HwaObWSSWql +bDsbv5BQPJ0ooWFYzVJ/y5WB/HRrCEvZKLBu/RaFAoGAYh5hjuUFGpFe21u47/+y +UP1pZpUNyPqtZnJ2NO2IMh93SCBD3RZX9nYRC7j2EKEuv5A7v1dq01Xgb7sE3PCS +C0Kd9P0KCvexOBM7NF3v/tg018qPRjuonpzQxuhTzU0zu0OVJRELWo7+n1KeU4ks +xalBYkaKee09NuIQXNIJjJMCgYEAkhAeIcao1TXeNUNE3DVIfuhms9kjv0rfloC1 +fft2Ol++sKSqKFcr7H/kBZ1rXgaCA5pffrVtC+LUdZGJ7wgu5PeFTF3XDBsInHtg +o8iSSkaclMmgNXl/0zoWi9mMp4BE+PmYM3K2qh8JnG9ZZ3MHbYvfeT8Cxf76cOYd +sg5dl+kCgYB0Tso0i4uTBDzn617dEmXGoJSc4pCaq0r504U05/b5tPIu6wlYn9m5 +ZS1027NENgKChXFTcmPwAbGF5o9xaSqpnJbybJf1vPQAlgoBBPGGgvXrTDKVj6U6 +ourNqwRRA47juGeutLuElZ6TrOAVPlUO1pfyxQ8dtLjqU4pFqTGMiw== +-----END RSA PRIVATE KEY----- diff --git a/fixtures/replay_attempt/command.json b/fixtures/replay_attempt/command.json new file mode 100644 index 0000000..4b27a3d --- /dev/null +++ b/fixtures/replay_attempt/command.json @@ -0,0 +1,13 @@ +{ + "command_id": "cmd-replay-001", + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp", + "parameters": { + "to": "recipient@example.test", + "from": "sender@example.test", + "subject": "Replay Attempt Test", + "body": "This command must execute once and be refused on replay." + }, + "authority_seal_id": "seal-replay-001" +} diff --git a/fixtures/replay_attempt/seal.json b/fixtures/replay_attempt/seal.json new file mode 100644 index 0000000..93d663f --- /dev/null +++ b/fixtures/replay_attempt/seal.json @@ -0,0 +1,14 @@ +{ + "issuer": "root.primary", + "authority_seal_id": "seal-replay-001", + "custodian": "test-custodian", + "scope": { + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp" + }, + "valid_from": "2025-01-01T00:00:00Z", + "valid_until": "2030-01-01T00:00:00Z", + "single_use": true, + "signature": "TEST_SIGNATURE_SINGLE_USE" +} diff --git a/fixtures/revoked_authority/command.json b/fixtures/revoked_authority/command.json new file mode 100644 index 0000000..7452c70 --- /dev/null +++ b/fixtures/revoked_authority/command.json @@ -0,0 +1,13 @@ +{ + "command_id": "cmd-revoked-001", + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp", + "parameters": { + "to": "recipient@example.test", + "from": "sender@example.test", + "subject": "Revoked Authority Test", + "body": "This execution must be refused because the authority is revoked." + }, + "authority_seal_id": "seal-revoked-001" +} diff --git a/fixtures/revoked_authority/revocation.record.json b/fixtures/revoked_authority/revocation.record.json index 4977f21..34e7ec0 100644 --- a/fixtures/revoked_authority/revocation.record.json +++ b/fixtures/revoked_authority/revocation.record.json @@ -1,5 +1,5 @@ { - "issuer": "auctoriseal:test-root", + "issuer": "root.primary", "revocation_id": "revocation-001", "authority_seal_id": "seal-revoked-001", "reason": "TEST_REVOCATION", diff --git a/fixtures/revoked_authority/seal.json b/fixtures/revoked_authority/seal.json new file mode 100644 index 0000000..c362921 --- /dev/null +++ b/fixtures/revoked_authority/seal.json @@ -0,0 +1,14 @@ +{ + "issuer": "root.primary", + "authority_seal_id": "seal-revoked-001", + "custodian": "test-custodian", + "scope": { + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp" + }, + "valid_from": "2024-01-01T00:00:00Z", + "valid_until": "2030-01-01T00:00:00Z", + "single_use": true, + "signature": "TEST_SIGNATURE_REVOKED_AUTHORITY" +} diff --git a/fixtures/time_violation/command.json b/fixtures/time_violation/command.json new file mode 100644 index 0000000..a104214 --- /dev/null +++ b/fixtures/time_violation/command.json @@ -0,0 +1,13 @@ +{ + "command_id": "cmd-time-violation-001", + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp", + "parameters": { + "to": "recipient@example.test", + "from": "sender@example.test", + "subject": "Time Violation Test", + "body": "This execution must be refused because authority time window is invalid." + }, + "authority_seal_id": "seal-time-past-001" +} diff --git a/fixtures/time_violation/seal.json b/fixtures/time_violation/seal.json new file mode 100644 index 0000000..a800b48 --- /dev/null +++ b/fixtures/time_violation/seal.json @@ -0,0 +1,14 @@ +{ + "issuer": "root.primary", + "authority_seal_id": "seal-time-past-001", + "custodian": "test-custodian", + "scope": { + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp" + }, + "valid_from": "2010-01-01T00:00:00Z", + "valid_until": "2015-01-01T00:00:00Z", + "single_use": true, + "signature": "TEST_SIGNATURE_PAST_VALID_UNTIL" +} diff --git a/fixtures/valid_authority/command.json b/fixtures/valid_authority/command.json new file mode 100644 index 0000000..cd87ac8 --- /dev/null +++ b/fixtures/valid_authority/command.json @@ -0,0 +1,13 @@ +{ + "command_id": "cmd-valid-001", + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp", + "parameters": { + "to": "recipient@example.test", + "from": "sender@example.test", + "subject": "Test Message", + "body": "This is a test email dispatched under valid authority." + }, + "authority_seal_id": "seal-valid-001" +} diff --git a/fixtures/valid_authority/seal.json b/fixtures/valid_authority/seal.json new file mode 100644 index 0000000..e7a237e --- /dev/null +++ b/fixtures/valid_authority/seal.json @@ -0,0 +1,14 @@ +{ + "issuer": "root.primary", + "authority_seal_id": "seal-valid-001", + "custodian": "test-custodian", + "scope": { + "body": "mail", + "action": "MAIL_DISPATCH", + "adapter": "smtp" + }, + "valid_from": "2025-01-01T00:00:00Z", + "valid_until": "2030-01-01T00:00:00Z", + "single_use": true, + "signature": "TEST_SIGNATURE_NOT_CRYPTOGRAPHICALLY_VALID" +} diff --git a/revocation/apply.sh b/revocation/apply.sh old mode 100644 new mode 100755 diff --git a/revocation/verify.sh b/revocation/verify.sh old mode 100644 new mode 100755 diff --git a/runtime/runner/run.sh b/runtime/runner/run.sh index 4f78449..dee65a9 100755 --- a/runtime/runner/run.sh +++ b/runtime/runner/run.sh @@ -15,23 +15,42 @@ set -euo pipefail # Canonical denial emission hook export DENIAL_EMIT_SCRIPT="${DENIAL_EMIT_SCRIPT:-denials/emit.sh}" -# Ensure system is not dead or frozen -if grep -q "DEAD" STATUS.md; then - echo "REFUSE: system is dead" - if [[ -x "$DENIAL_EMIT_SCRIPT" ]]; then - "$DENIAL_EMIT_SCRIPT" "SYSTEM_DEAD" || true - fi - exit 1 -fi +CURRENT_STATE="$( + python3 - <<'PY' +from pathlib import Path + +for line in Path("STATUS.md").read_text().splitlines(): + if line.startswith("**CURRENT STATE:**"): + print(line.split(":", 1)[1].replace(chr(96), "").strip()) + break +PY +)" -if grep -q "FROZEN" STATUS.md; then - echo "REFUSE: system is frozen" +if [[ -z "${CURRENT_STATE:-}" ]]; then + echo "REFUSE: current state unresolved" if [[ -x "$DENIAL_EMIT_SCRIPT" ]]; then - "$DENIAL_EMIT_SCRIPT" "SYSTEM_FROZEN" || true + "$DENIAL_EMIT_SCRIPT" "STATUS_STATE_UNRESOLVED" || true fi exit 1 fi +case "$CURRENT_STATE" in + DEAD) + echo "REFUSE: system is dead" + if [[ -x "$DENIAL_EMIT_SCRIPT" ]]; then + "$DENIAL_EMIT_SCRIPT" "SYSTEM_DEAD" || true + fi + exit 1 + ;; + FROZEN) + echo "REFUSE: system is frozen" + if [[ -x "$DENIAL_EMIT_SCRIPT" ]]; then + "$DENIAL_EMIT_SCRIPT" "SYSTEM_FROZEN" || true + fi + exit 1 + ;; +esac + # Authority + policy gate execution/gate.sh diff --git a/seals/reject_invalid.sh b/seals/reject_invalid.sh old mode 100644 new mode 100755 diff --git a/seals/require_auctoriseal.sh b/seals/require_auctoriseal.sh old mode 100644 new mode 100755 diff --git a/seals/verify_custody.sh b/seals/verify_custody.sh old mode 100644 new mode 100755 diff --git a/seals/verify_revocation.sh b/seals/verify_revocation.sh new file mode 100755 index 0000000..99a5111 --- /dev/null +++ b/seals/verify_revocation.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail + +# VERIFY REVOCATION +# Refuses execution if authority seal is revoked. + +SEAL_FILE="${AUTHORITY_SEAL_PATH:-}" + +if [[ -z "$SEAL_FILE" ]]; then + echo "REFUSE: no authority seal path provided" + exit 1 +fi + +if [[ ! -f "$SEAL_FILE" ]]; then + echo "REFUSE: authority seal file not found" + exit 1 +fi + +REVOKED=$(jq -r ".revoked // false" "$SEAL_FILE") + +if [[ "$REVOKED" == "true" ]]; then + echo "REFUSE: authority revoked" + exit 1 +fi + +echo "AUTHORITY NOT REVOKED" +exit 0 diff --git a/seals/verify_scope.sh b/seals/verify_scope.sh old mode 100644 new mode 100755 index 1943d3e..27d9d9a --- a/seals/verify_scope.sh +++ b/seals/verify_scope.sh @@ -17,16 +17,41 @@ if [[ ! -f "$SEAL_FILE" || ! -f "$COMMAND_FILE" ]]; then exit 1 fi -SEAL_RESOURCES=$(jq -r '.scope.resources[]' "$SEAL_FILE" | sort) -CMD_RESOURCES=$(jq -r '.parameters.resources[]?' "$COMMAND_FILE" | sort) +SEAL_BODY=$(jq -r ".scope.body" "$SEAL_FILE") +SEAL_ACTION=$(jq -r ".scope.action" "$SEAL_FILE") +SEAL_ADAPTER=$(jq -r ".scope.adapter" "$SEAL_FILE") -if [[ -z "$SEAL_RESOURCES" ]]; then - echo "REFUSE: empty authority scope" +CMD_BODY=$(jq -r ".body" "$COMMAND_FILE") +CMD_ACTION=$(jq -r ".action" "$COMMAND_FILE") +CMD_ADAPTER=$(jq -r ".adapter" "$COMMAND_FILE") + +if [[ -z "$SEAL_BODY" || "$SEAL_BODY" == "null" ]]; then + echo "REFUSE: missing scope body" + exit 1 +fi + +if [[ -z "$SEAL_ACTION" || "$SEAL_ACTION" == "null" ]]; then + echo "REFUSE: missing scope action" + exit 1 +fi + +if [[ -z "$SEAL_ADAPTER" || "$SEAL_ADAPTER" == "null" ]]; then + echo "REFUSE: missing scope adapter" + exit 1 +fi + +if [[ "$SEAL_BODY" != "$CMD_BODY" ]]; then + echo "REFUSE: scope body mismatch" + exit 1 +fi + +if [[ "$SEAL_ACTION" != "$CMD_ACTION" ]]; then + echo "REFUSE: scope action mismatch" exit 1 fi -if [[ "$SEAL_RESOURCES" != "$CMD_RESOURCES" ]]; then - echo "REFUSE: scope mismatch" +if [[ "$SEAL_ADAPTER" != "$CMD_ADAPTER" ]]; then + echo "REFUSE: scope adapter mismatch" exit 1 fi diff --git a/seals/verify_seal.sh b/seals/verify_seal.sh old mode 100644 new mode 100755 diff --git a/seals/verify_time_window.sh b/seals/verify_time_window.sh old mode 100644 new mode 100755 index d0541bb..917ee10 --- a/seals/verify_time_window.sh +++ b/seals/verify_time_window.sh @@ -16,29 +16,37 @@ if [[ ! -f "$SEAL_FILE" ]]; then exit 1 fi -VALID_FROM=$(jq -r '.time_window.valid_from' "$SEAL_FILE") -VALID_UNTIL=$(jq -r '.time_window.valid_until' "$SEAL_FILE") +VALID_FROM=$(jq -r ".valid_from" "$SEAL_FILE") +VALID_UNTIL=$(jq -r ".valid_until" "$SEAL_FILE") -if [[ -z "$VALID_FROM" || -z "$VALID_UNTIL" || "$VALID_FROM" == "null" || "$VALID_UNTIL" == "null" ]]; then +if [[ -z "$VALID_FROM" || "$VALID_FROM" == "null" || -z "$VALID_UNTIL" || "$VALID_UNTIL" == "null" ]]; then echo "REFUSE: invalid time window in authority seal" exit 1 fi -NOW_UTC=$(date -u +"%Y-%m-%dT%H:%M:%SZ") +python3 - "$VALID_FROM" "$VALID_UNTIL" <<'PY' +import sys +from datetime import datetime, timezone -FROM_EPOCH=$(date -u -d "$VALID_FROM" +"%s") -UNTIL_EPOCH=$(date -u -d "$VALID_UNTIL" +"%s") -NOW_EPOCH=$(date -u -d "$NOW_UTC" +"%s") +valid_from = sys.argv[1] +valid_until = sys.argv[2] -if (( NOW_EPOCH < FROM_EPOCH )); then - echo "REFUSE: authority not yet valid" - exit 1 -fi +def parse_iso_z(value: str) -> datetime: + return datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc) -if (( NOW_EPOCH > UNTIL_EPOCH )); then - echo "REFUSE: authority expired" - exit 1 -fi +now = datetime.now(timezone.utc) +from_dt = parse_iso_z(valid_from) +until_dt = parse_iso_z(valid_until) + +if now < from_dt: + print("REFUSE: authority not yet valid") + raise SystemExit(1) + +if now > until_dt: + print("REFUSE: authority expired") + raise SystemExit(1) + +print("AUTHORITY TIME WINDOW VERIFIED") +PY -echo "AUTHORITY TIME WINDOW VERIFIED" exit 0 diff --git a/tests/must_execute_once.test b/tests/must_execute_once.test old mode 100644 new mode 100755 index 1d94bda..7c456fd --- a/tests/must_execute_once.test +++ b/tests/must_execute_once.test @@ -4,8 +4,8 @@ set -euo pipefail # TEST: MUST EXECUTE ONCE # Verifies that a command cannot be executed more than once. -export EXECUTION_COMMAND_PATH="fixtures/valid_authority/command.json" -export AUTHORITY_SEAL_PATH="fixtures/valid_authority/seal.json" +export EXECUTION_COMMAND_PATH="fixtures/replay_attempt/command.json" +export AUTHORITY_SEAL_PATH="fixtures/replay_attempt/seal.json" export EXECUTION_CUSTODIAN="test-custodian" export SYSTEM_FINGERPRINT="test-fingerprint" export BUILD_HASH="test-build-hash" @@ -13,6 +13,8 @@ export CORPIFORM_VERSION="v0.test" export RECEIPT_SIGNING_KEY="fixtures/keys/receipt.key" export DENIAL_SIGNING_KEY="fixtures/keys/denial.key" +rm -f ledger/locks/cmd-replay-001.lock 2>/dev/null || true + # First execution should succeed if ! runtime/runner/run.sh >/dev/null 2>&1; then echo "FAIL: first execution did not succeed" diff --git a/tests/must_honor_revocation.test b/tests/must_honor_revocation.test old mode 100644 new mode 100755 index 5ee5a43..aa37366 --- a/tests/must_honor_revocation.test +++ b/tests/must_honor_revocation.test @@ -10,13 +10,13 @@ export CORPIFORM_VERSION="v0.test" export DENIAL_SIGNING_KEY="fixtures/keys/denial.key" export EXECUTION_CUSTODIAN="test-custodian" -export EXECUTION_COMMAND_PATH="fixtures/valid_authority/command.json" -export AUTHORITY_SEAL_PATH="fixtures/valid_authority/seal.json" -export REVOCATION_PATH="fixtures/revocations/revocation.json" +export EXECUTION_COMMAND_PATH="fixtures/revoked_authority/command.json" +export AUTHORITY_SEAL_PATH="fixtures/revoked_authority/seal.json" +export REVOCATION_PATH="fixtures/revoked_authority/revocation.record.json" mkdir -p ledger/revocations ledger/denials ledger/locks +rm -f ledger/locks/cmd-revoked-001.lock 2>/dev/null || true -# Apply revocation (idempotent for test) if ! revocation/verify.sh >/dev/null 2>&1; then echo "FAIL: revocation fixture did not verify" exit 1 @@ -27,19 +27,17 @@ if ! revocation/apply.sh >/dev/null 2>&1; then exit 1 fi -# Ensure seal_id is present in revocation ledger -SEAL_ID=$(jq -r '.seal_id' "$AUTHORITY_SEAL_PATH") +SEAL_ID=$(jq -r .authority_seal_id "$AUTHORITY_SEAL_PATH") if [[ -z "$SEAL_ID" || "$SEAL_ID" == "null" ]]; then - echo "FAIL: fixture seal_id missing" + echo "FAIL: fixture authority_seal_id missing" exit 1 fi if ! grep -R "\"authority_seal_id\"[[:space:]]*:[[:space:]]*\"${SEAL_ID}\"" ledger/revocations >/dev/null 2>&1; then - echo "FAIL: revocation ledger does not reference seal_id" + echo "FAIL: revocation ledger does not reference authority_seal_id" exit 1 fi -# Attempt execution: MUST be refused if runtime/runner/run.sh >/dev/null 2>&1; then echo "FAIL: execution succeeded with revoked authority" exit 1 diff --git a/tests/must_record_ledger.test b/tests/must_record_ledger.test old mode 100644 new mode 100755 index c9ecae0..5732395 --- a/tests/must_record_ledger.test +++ b/tests/must_record_ledger.test @@ -13,6 +13,7 @@ export DENIAL_SIGNING_KEY="fixtures/keys/denial.key" export EXECUTION_CUSTODIAN="test-custodian" mkdir -p ledger/receipts ledger/denials ledger/locks +rm -f ledger/locks/cmd-valid-001.lock 2>/dev/null || true receipts_before=$(find ledger/receipts -type f -name '*.json' 2>/dev/null | wc -l | tr -d ' ') denials_before=$(find ledger/denials -type f -name '*.json' 2>/dev/null | wc -l | tr -d ' ') From c0d0c2b324671753cdaa457cd98c2954d81c318d Mon Sep 17 00:00:00 2001 From: Midia Kiasat Date: Thu, 19 Mar 2026 09:47:49 +0100 Subject: [PATCH 2/2] Finalize receipt emission consistency after ledger isolation --- receipts/emit.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 receipts/emit.sh diff --git a/receipts/emit.sh b/receipts/emit.sh old mode 100644 new mode 100755