diff --git a/CAPABILITIES.md b/CAPABILITIES.md index 0e77798dd..7c131360a 100644 --- a/CAPABILITIES.md +++ b/CAPABILITIES.md @@ -256,7 +256,7 @@ improvising or retrying when something is off. | Encrypt PHI at rest: every bundle file that can hold patient data under one sealed index (unknown files refused), web recordings from the first frame, and the run directories of sealed bundles; compile, induce, scaffold-verifier, qualify, admit, run, resume and undo read them in memory and refuse without the key | On main | Synthetic (no-plaintext audit-hook test over record, compile and a VERIFIED run; per-frame cost measured) | `openadapt-flow seal`, `record`; [phi_at_rest.md](packages/flow/docs/phi_at_rest.md) | | Signed receipts (Seals), countersigned and timestamped, offline by default | Released | Unit tests, real TSA tokens | `openadapt-flow seal`, `countersign`, `local-seal` | | Offline Seals signed with a key the customer holds: a key file, the OS keychain, or a PKCS#11 token or HSM; pinned keys with rotation and revocation; no fallback to a generated key | On main ([#1392](https://github.com/OpenAdaptAI/OpenAdapt/pull/1392)) | Unit tests with synthetic data (keychain and PKCS#11 through stand-ins) | `openadapt-flow local-seal --key`, `local-seal key create`, `pin`, `revoke`; `openadapt seal verify FOLDER` checks every sealed run in a folder; [OFFLINE_SEALS.md](packages/flow/docs/OFFLINE_SEALS.md#customer-held-keys) | -| Anchor an offline Seal in the public Sigstore Rekor transparency log (opt-in; sends one digest and the public key), and verify the anchor offline from the stored inclusion proof | On main ([#1394](https://github.com/OpenAdaptAI/OpenAdapt/pull/1394)) | Unit tests against a simulated Rekor log; Ed25519ph matches the RFC 8032 test vector | `openadapt-flow local-seal anchor`, `local-seal verify --require-anchor`; [OFFLINE_SEALS.md](packages/flow/docs/OFFLINE_SEALS.md#optional-anchor-a-seal-in-a-public-transparency-log) | +| Anchor an offline Seal in the public Sigstore Rekor transparency log (opt-in; sends one digest and the public key), and verify the anchor offline from the stored inclusion proof | On main ([#1394](https://github.com/OpenAdaptAI/OpenAdapt/pull/1394)) | Unit tests against a simulated Rekor log; real public Rekor entries and Sigstore TSA tokens for the landing demo's referral runs, verified offline in tests; Ed25519ph matches the RFC 8032 test vector | `openadapt-flow local-seal anchor`, `local-seal verify --require-anchor`; [OFFLINE_SEALS.md](packages/flow/docs/OFFLINE_SEALS.md#optional-anchor-a-seal-in-a-public-transparency-log) | | Run authorizations signed with the authorizer's GitHub SSH key (`ssh-keygen -Y sign`, after a summary of what it allows), naming the signing key and bound to the bundle digest, items, profile and Seal keys, and referenced by each Seal; the identity checked against github.com (`--live`) or pinned allowed signers; a pseudonymous operator profile counted from anchored Seals only | On main ([#1401](https://github.com/OpenAdaptAI/OpenAdapt/pull/1401)) | Unit tests with synthetic data; signatures checked against OpenSSH's `ssh-keygen` both ways | `openadapt-flow local-seal authorize`, `local-seal run --authorization`, `local-seal profile`; [OFFLINE_SEALS.md](packages/flow/docs/OFFLINE_SEALS.md#run-authorizations-who-authorized-the-runs) | | Run reports redacted before they are sealed: session and CSRF tokens, OAuth grants and credential headers become `` and are listed in `redactions`; a Seal refuses a report that still holds one; per-app policy | On main ([#1407](https://github.com/OpenAdaptAI/OpenAdapt/pull/1407)) | Unit tests with generated tokens; 7,773 local reports scanned, only OpenEMR `token_main` matched | `openadapt-flow redact-report`, `local-seal run --allow-unredacted`; [REPORT_REDACTION.md](packages/flow/docs/REPORT_REDACTION.md) | | Strict no-outbound mode and an unattended on-prem service | Released | Synthetic | `openadapt-flow no-outbound`, `service`; [ON_PREM.md](packages/flow/docs/ON_PREM.md) | diff --git a/llms-full.txt b/llms-full.txt index 4b77cf131..ec0ceb271 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -653,7 +653,7 @@ improvising or retrying when something is off. | Encrypt PHI at rest: every bundle file that can hold patient data under one sealed index (unknown files refused), web recordings from the first frame, and the run directories of sealed bundles; compile, induce, scaffold-verifier, qualify, admit, run, resume and undo read them in memory and refuse without the key | On main | Synthetic (no-plaintext audit-hook test over record, compile and a VERIFIED run; per-frame cost measured) | `openadapt-flow seal`, `record`; [phi_at_rest.md](https://github.com/OpenAdaptAI/OpenAdapt/blob/main/packages/flow/docs/phi_at_rest.md) | | Signed receipts (Seals), countersigned and timestamped, offline by default | Released | Unit tests, real TSA tokens | `openadapt-flow seal`, `countersign`, `local-seal` | | Offline Seals signed with a key the customer holds: a key file, the OS keychain, or a PKCS#11 token or HSM; pinned keys with rotation and revocation; no fallback to a generated key | On main ([#1392](https://github.com/OpenAdaptAI/OpenAdapt/pull/1392)) | Unit tests with synthetic data (keychain and PKCS#11 through stand-ins) | `openadapt-flow local-seal --key`, `local-seal key create`, `pin`, `revoke`; `openadapt seal verify FOLDER` checks every sealed run in a folder; [OFFLINE_SEALS.md](https://github.com/OpenAdaptAI/OpenAdapt/blob/main/packages/flow/docs/OFFLINE_SEALS.md#customer-held-keys) | -| Anchor an offline Seal in the public Sigstore Rekor transparency log (opt-in; sends one digest and the public key), and verify the anchor offline from the stored inclusion proof | On main ([#1394](https://github.com/OpenAdaptAI/OpenAdapt/pull/1394)) | Unit tests against a simulated Rekor log; Ed25519ph matches the RFC 8032 test vector | `openadapt-flow local-seal anchor`, `local-seal verify --require-anchor`; [OFFLINE_SEALS.md](https://github.com/OpenAdaptAI/OpenAdapt/blob/main/packages/flow/docs/OFFLINE_SEALS.md#optional-anchor-a-seal-in-a-public-transparency-log) | +| Anchor an offline Seal in the public Sigstore Rekor transparency log (opt-in; sends one digest and the public key), and verify the anchor offline from the stored inclusion proof | On main ([#1394](https://github.com/OpenAdaptAI/OpenAdapt/pull/1394)) | Unit tests against a simulated Rekor log; real public Rekor entries and Sigstore TSA tokens for the landing demo's referral runs, verified offline in tests; Ed25519ph matches the RFC 8032 test vector | `openadapt-flow local-seal anchor`, `local-seal verify --require-anchor`; [OFFLINE_SEALS.md](https://github.com/OpenAdaptAI/OpenAdapt/blob/main/packages/flow/docs/OFFLINE_SEALS.md#optional-anchor-a-seal-in-a-public-transparency-log) | | Run authorizations signed with the authorizer's GitHub SSH key (`ssh-keygen -Y sign`, after a summary of what it allows), naming the signing key and bound to the bundle digest, items, profile and Seal keys, and referenced by each Seal; the identity checked against github.com (`--live`) or pinned allowed signers; a pseudonymous operator profile counted from anchored Seals only | On main ([#1401](https://github.com/OpenAdaptAI/OpenAdapt/pull/1401)) | Unit tests with synthetic data; signatures checked against OpenSSH's `ssh-keygen` both ways | `openadapt-flow local-seal authorize`, `local-seal run --authorization`, `local-seal profile`; [OFFLINE_SEALS.md](https://github.com/OpenAdaptAI/OpenAdapt/blob/main/packages/flow/docs/OFFLINE_SEALS.md#run-authorizations-who-authorized-the-runs) | | Run reports redacted before they are sealed: session and CSRF tokens, OAuth grants and credential headers become `` and are listed in `redactions`; a Seal refuses a report that still holds one; per-app policy | On main ([#1407](https://github.com/OpenAdaptAI/OpenAdapt/pull/1407)) | Unit tests with generated tokens; 7,773 local reports scanned, only OpenEMR `token_main` matched | `openadapt-flow redact-report`, `local-seal run --allow-unredacted`; [REPORT_REDACTION.md](https://github.com/OpenAdaptAI/OpenAdapt/blob/main/packages/flow/docs/REPORT_REDACTION.md) | | Strict no-outbound mode and an unattended on-prem service | Released | Synthetic | `openadapt-flow no-outbound`, `service`; [ON_PREM.md](https://github.com/OpenAdaptAI/OpenAdapt/blob/main/packages/flow/docs/ON_PREM.md) | diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.anchor.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.anchor.json new file mode 100644 index 000000000..f001f9a49 --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.anchor.json @@ -0,0 +1,51 @@ +{ + "entry": { + "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhNTEyIiwidmFsdWUiOiI1NmIyMzhjNDgzZWEzZTgyZTAyN2NkMTAwNDMwN2UzMzljN2Q0YjAxNmFmZjIxN2Y3YjUwNDViMThhMTZhNzVhMWMzODk5NjY4YzA4MGY1M2MyNTg3ZWNjYjk3NjFjOGE3OGM0MzhmZGE4YjJlNTcxMzJlODdmYjNiYTM4MWM3NyJ9fSwic2lnbmF0dXJlIjp7ImNvbnRlbnQiOiJtZ1RWbmFnWGJNUlY2cisvTDI3bHQvWWFUSElmSHFDb04yRUU2bFpzY2s2Y1VVRkd0SzhRK3pqeUM4elhKeTZLVTgxVXZhQ2NkbGRJZ0I3Q2pMRTdDQT09IiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVU52ZDBKUldVUkxNbFozUVhsRlFWVlJUMU5zYWpOcFEzbHdVMlJUZDNKVldWbFBZMHhpVXpaNWVUSTFlVTAyYzNscVNGWnVjV05JUW1jOUNpMHRMUzB0UlU1RUlGQlZRa3hKUXlCTFJWa3RMUzB0TFFvPSJ9fX19", + "integratedTime": 1792511616, + "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d", + "logIndex": 3339635766, + "uuid": "108e9186e8c5677aa7543418cff84038fcf0b8503bf878af6bf8d4f906821840f5ac10e710b45fd0", + "verification": { + "inclusionProof": { + "checkpoint": "rekor.sigstore.dev - 1193050959916656506\n3217731569\nbiQKRWlqyS4H1E+XQ5PFa5baE9Kd1lW7p8G+lIfSeqU=\n\n\u2014 rekor.sigstore.dev wNI9ajBGAiEA20ISQsSDn7Nuey0fi3E2Lex7RYGBhxb/A64t5gN7ZfoCIQC5wdcDm1qDThGpZ0iSqL1PTXg+ijgnmRQ2zcQWqHT3rw==\n", + "hashes": [ + "10dbbfb55020f1d64f0b225023fb50941b60f127291f28e95eba9f587e3337f4", + "47ad4a16cdd51b56416df9342d93f2214e44f417a6a3bbcc7a6023df5546d7d6", + "6eb11ff37c55975e524689fe07aa0916720bfa71277fc93f4b87100ba4c4ff97", + "42ddaaa8c42f56f6d7b3f161b22f4b15dd776ed047619513613a7e4dca557311", + "a8c8d03e3b329a6cf131ab27b827e3be2e848f7e6cca5aa855a2ee0626816c36", + "3c5163882115b80260634e9e2d5d879afda6fb1cb5663e9e14fed33b99a9fdcb", + "dc1086cf79fe48992da87c2a10bb624a47caa43460224453e9090366159f72ce", + "e239ff0ee76a53932dbf944e2425ea1157bde41af58206da2526e71d6750268b", + "e2b57796cc1375a4c7dfec20fa74b010f649efda4a0f6e0507bb2c2fb8f9583c", + "d85ef1b75a8ce7965b02d1b8a2405371366c3cc89b0bbd04d220c9dbd623228c", + "db8524b1f6610642730eacb0471a0aeca405ba750bfbc099f6c48a0d03b11392", + "1dae9e1aae4a6299c11ec217c1bb739017aee8cb939df21d5bd07fd98f9bf75c", + "0484fc459183f5191a1f5f4eff5954c5d06af4285a6f5fe8593937bd78547475", + "d7b421e7c5b37697a2e76feacad4ebab65bc2767c0e85fa12e9e296333847051", + "0ccdecead5a695d8d359e61502b86785401c1cfb4746f46480699137a76bb2da", + "ed916d87334cd633f90b1eccc9f011c0da8163146fc375559f75c06dd1bc31fb", + "5eaa5e4bf0471ce13153de87be0e4bf9d1f0ab444f2431c298a4f1fe35c0839d", + "e916fbb8e824dafe5829c1526c03cea4b9560083757220cf765a7827f094bb99", + "1e8bd33c15b3a04aef520d6ee6c222df1d59a2767bc897a456c06b9a9a260880", + "1be9e4ee6804e61e9d526bf6518ecd0c9ad8dd6beb658df5ada68ed40113b7ea", + "aa54d6343cc44674c14157071d75d53e38943f44ac8a41b17dcc55960a95143a", + "820f46340a4d91edfeccd865e2db16b6623270216b38c081de5cace97b9240d4", + "36539c96576628f035b4c288b24a87030b900d81e9df5630a4af8e38cacc71c7", + "ab1cc76a7033cf9ed20dd9897b407b6c92bbd8d4c805bc043060412af0ce44ec", + "c47fc30ac78b1ebf5e2a8613f2ab0e4592bbcd5744198587b95b6c56b0fde706" + ], + "logIndex": 3217731504, + "rootHash": "6e240a45696ac92e07d44f974393c56b96da13d29dd655bba7c1be9487d27aa5", + "treeSize": 3217731569 + }, + "signedEntryTimestamp": "MEUCIQCsYGXQN3fzdGPh/hzhpx6JO9KtPH2/XtmLHULOTGDheAIgPdBIipG0R7oJsx4gIF5Cs5NeFOjWXAtl7N1gKsET7yw=" + } + }, + "key_id": "seal-ed25519-ca08dd7f42a4be01", + "log_url": "https://rekor.sigstore.dev", + "nonce": "66d6dfeaca36c609b0e1c250317137f0934e230c69a32116ea717f95ea4ed35b", + "schema": "openadapt.local-seal-anchor/v1", + "seal_sha256": "548ba574914dffee8443b54d33a340ee106923e0fe672b41d7756621124d9a4d", + "statement_sha512": "56b238c483ea3e82e027cd1004307e339c7d4b016aff217f7b5045b18a16a75a1c3899668c080f53c2587eccb9761c8a78c438fda8b2e57132e87fb3ba381c77" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.json index 8acb4bebc..2ba10a6f4 100644 --- a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.json +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.json @@ -1,13 +1,15 @@ { "algorithm": "ed25519", - "issued_at": "2026-10-20T04:19:56Z", + "authorization_sha256": "bdfda160138f89a708caa122904af6fec66b29ad41c2d8cb25e458e2da5104d3", + "issued_at": "2026-10-20T15:53:26Z", "issuer": "local", "key_id": "seal-ed25519-ca08dd7f42a4be01", "outcome": "VERIFIED", "public_key": "UQOSlj3iCypSdSwrUYYOcLbS6yy25yM6syjHVnqcHBg=", "run_id": "engine", "schema": "openadapt.local-seal/v1", - "signature": "pjzps9rNTF3yA57NEd71nTCD1OLcRQh4UdVwGUvklRqXXuLlIyK6ZeIPFQDWZV+9N8b/h3WKUNWP43aTlJJABg==", + "scope_item": "r3", + "signature": "2+zCKP4B8srkGvTaKNwisg8g45hGNugy75QoCZg33xycVCU4T/H9RFwhWcXJz1S6osmU0mseO8DiDIwBVDzEAg==", "subject_kind": "run-report", "subject_sha256": "ad349a68cc2d60b7c4f36ac1558f6cc39439f69b952c883bd5a4cd14d229a2b1" } diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.tsa.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.tsa.json new file mode 100644 index 000000000..bb3d86da1 --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.tsa.json @@ -0,0 +1,9 @@ +{ + "gen_time": "2026-10-20T15:53:35Z", + "imprint_sha256": "548ba574914dffee8443b54d33a340ee106923e0fe672b41d7756621124d9a4d", + "schema": "openadapt.record-timestamp/v1", + "seal_sha256": "548ba574914dffee8443b54d33a340ee106923e0fe672b41d7756621124d9a4d", + "tsa": "https://timestamp.sigstore.dev/api/v1/timestamp", + "tsr_file": "seal.tsr", + "tsr_sha256": "edf5322f93f772e9de3ba2667e41daeb27584f5e104b5df07661af3633228792" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.tsr b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.tsr new file mode 100644 index 000000000..289fc2d9c Binary files /dev/null and b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.tsr differ diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.anchor.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.anchor.json new file mode 100644 index 000000000..fd125d159 --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.anchor.json @@ -0,0 +1,49 @@ +{ + "entry": { + "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhNTEyIiwidmFsdWUiOiI1YzVhYjQ1ZWY4M2U4MzA4M2JmODc1MDE5N2FiZmRkZDBiZTNjYzFhMGZkZDU1YjZkMzY2MjNjN2NhY2FhMTdjNjYzZmM0NjI2MWM5YjJlMzM3Zjg0MWQ3YWQ3MGM0Y2MwNDY0OGJjMGQ0MjQxNjI4NTI2YjI2MWNlMGI0OWUxZiJ9fSwic2lnbmF0dXJlIjp7ImNvbnRlbnQiOiJMM1Vhb29HRTlwOEhuMEpLZjRKdDkvbWtCSGx4NVVSWHkyeWVRSFBJQzI1cm1yT1Q5QllvdXZZZ2xjNk83cW04alkyMEhKZVlwYU9OOUc1bzY4cENCZz09IiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVU52ZDBKUldVUkxNbFozUVhsRlFWVlJUMU5zYWpOcFEzbHdVMlJUZDNKVldWbFBZMHhpVXpaNWVUSTFlVTAyYzNscVNGWnVjV05JUW1jOUNpMHRMUzB0UlU1RUlGQlZRa3hKUXlCTFJWa3RMUzB0TFFvPSJ9fX19", + "integratedTime": 1792511619, + "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d", + "logIndex": 3339636256, + "uuid": "108e9186e8c5677a034e57e78270445688b507e30b2098787ccfa9e37edd267f473f4439dc1da50f", + "verification": { + "inclusionProof": { + "checkpoint": "rekor.sigstore.dev - 1193050959916656506\n3217732093\nUR+J0hDfIJUEP7k6+HS3fu9V4Pbafy5w3tNqwDHFWhw=\n\n\u2014 rekor.sigstore.dev wNI9ajBFAiEA0wflszFams4IIUJUAO76hkqfKaU0eQA3RntL9vr/iHwCIGSmqMoIM1qdccDU3ywrX+jBHnV3VIdfpNuSFSxqUc41\n", + "hashes": [ + "bef2c04bb1df02d4a705a5173da6f8166aafead681338555237f447b192cd067", + "8eebe59571e836d1c936458558b9af3c23d23de349d7b2ada82c26080edf55d0", + "8867f51a9f490c2aeee5b0f22b9a05206fd69c7b19012daff4e5ad2f254ef41b", + "f8ad2ab87a173b526aaa96d7adbbad9ba3eb35dc9a921906432b83ed65edf7f4", + "d98b96f73065dc9c848e123666481b9830bdbbfb45fc915e8368f1a61c5ab810", + "5eebbb3d30942aad7ad5288e396a2a884d0b54b167d8ae349199380275e3b91a", + "33e1d7e51e2df5ba981d11adced4955443d233895615585a49751dea9a8de6c9", + "dcedddd7bcc80aff404d785f8a68966d8198d904747927cfdfa2c4e9671fadc2", + "1b6eb37d7763b4aedb58c24c0e0ae55444fc52c7bebbbfea5e844d874840a1e1", + "ca010f0e78c08f47679d2372d5a10a9878a2015c3b4b67753fb289674679d573", + "0484fc459183f5191a1f5f4eff5954c5d06af4285a6f5fe8593937bd78547475", + "d7b421e7c5b37697a2e76feacad4ebab65bc2767c0e85fa12e9e296333847051", + "0ccdecead5a695d8d359e61502b86785401c1cfb4746f46480699137a76bb2da", + "ed916d87334cd633f90b1eccc9f011c0da8163146fc375559f75c06dd1bc31fb", + "5eaa5e4bf0471ce13153de87be0e4bf9d1f0ab444f2431c298a4f1fe35c0839d", + "e916fbb8e824dafe5829c1526c03cea4b9560083757220cf765a7827f094bb99", + "1e8bd33c15b3a04aef520d6ee6c222df1d59a2767bc897a456c06b9a9a260880", + "1be9e4ee6804e61e9d526bf6518ecd0c9ad8dd6beb658df5ada68ed40113b7ea", + "aa54d6343cc44674c14157071d75d53e38943f44ac8a41b17dcc55960a95143a", + "820f46340a4d91edfeccd865e2db16b6623270216b38c081de5cace97b9240d4", + "36539c96576628f035b4c288b24a87030b900d81e9df5630a4af8e38cacc71c7", + "ab1cc76a7033cf9ed20dd9897b407b6c92bbd8d4c805bc043060412af0ce44ec", + "c47fc30ac78b1ebf5e2a8613f2ab0e4592bbcd5744198587b95b6c56b0fde706" + ], + "logIndex": 3217731994, + "rootHash": "511f89d210df2095043fb93af874b77eef55e0f6da7f2e70ded36ac031c55a1c", + "treeSize": 3217732093 + }, + "signedEntryTimestamp": "MEUCIAbIIcdtYSmjN+zICFw3tcmPVibBXTVKWvYmak8qLpVCAiEAosiPiiiiHKlqPVfDcCrb5rI9zMrC0RaM0yQERS1bPiw=" + } + }, + "key_id": "seal-ed25519-ca08dd7f42a4be01", + "log_url": "https://rekor.sigstore.dev", + "nonce": "c0504e5d2d2f9a9b02d1d75ca557acdf6016c3d450d479a6b62bdfb0ac9132a9", + "schema": "openadapt.local-seal-anchor/v1", + "seal_sha256": "e27585b3f86dd9b79ef3fc368ffca13cd34824e03352987697ae1e33f228808e", + "statement_sha512": "5c5ab45ef83e83083bf8750197abfddd0be3cc1a0fdd55b6d36623c7cacaa17c663fc46261c9b2e337f841d7ad70c4cc04648bc0d4241628526b261ce0b49e1f" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.json index 90530a89b..5866e46ba 100644 --- a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.json +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.json @@ -1,13 +1,15 @@ { "algorithm": "ed25519", - "issued_at": "2026-10-20T04:20:00Z", + "authorization_sha256": "bdfda160138f89a708caa122904af6fec66b29ad41c2d8cb25e458e2da5104d3", + "issued_at": "2026-10-20T15:53:27Z", "issuer": "local", "key_id": "seal-ed25519-ca08dd7f42a4be01", "outcome": "VERIFIED", "public_key": "UQOSlj3iCypSdSwrUYYOcLbS6yy25yM6syjHVnqcHBg=", "run_id": "engine", "schema": "openadapt.local-seal/v1", - "signature": "/gLYzwGDUfDut9K8Zee5KPJbVuvraXMvb5CYP5wSJpU0oR0+n1uMjIEl2XnbRwLoc/WC8NvW0883r/L4tywiCQ==", + "scope_item": "r4", + "signature": "2komh9VDPGkipxXmF1js2OXYEtmdVVo6IXn6yfkgQDztthCsh4jSZqrjN608pDgdk6IyQ1wImczXPdCr5rL3BA==", "subject_kind": "run-report", "subject_sha256": "391522a4414eb9db29a0f9e5d06746ea02d7ba71d9dcd8685c2f2066aa7b384a" } diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.tsa.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.tsa.json new file mode 100644 index 000000000..86ee50afd --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.tsa.json @@ -0,0 +1,9 @@ +{ + "gen_time": "2026-10-20T15:53:38Z", + "imprint_sha256": "e27585b3f86dd9b79ef3fc368ffca13cd34824e03352987697ae1e33f228808e", + "schema": "openadapt.record-timestamp/v1", + "seal_sha256": "e27585b3f86dd9b79ef3fc368ffca13cd34824e03352987697ae1e33f228808e", + "tsa": "https://timestamp.sigstore.dev/api/v1/timestamp", + "tsr_file": "seal.tsr", + "tsr_sha256": "d0ebda4a0eb90d824340f93b467f8ac1a28ff2b794827d3783d11e059a25df65" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.tsr b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.tsr new file mode 100644 index 000000000..ae3acad9d Binary files /dev/null and b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.tsr differ diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.anchor.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.anchor.json new file mode 100644 index 000000000..a86e7b8ae --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.anchor.json @@ -0,0 +1,49 @@ +{ + "entry": { + "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhNTEyIiwidmFsdWUiOiI0NGIyYzgzMTVmM2ZiODQ1MzliYWVmMmM5NTcyOTNmZjk0OGQ5OGExZTA4NDk5Y2JkNjNmMjRmZDlkODg2MDhiMTU3YTRhODI1MzdlM2EzYjFiNzBkZmE0OWU2OGQxNzFhYjg3ODM4M2JlMjI4N2M4OTE2MGQwMWExOTcyZDg2NiJ9fSwic2lnbmF0dXJlIjp7ImNvbnRlbnQiOiJXeENLRThvNWJTSmFJRlRHVndCN01adkNCUXQ4dCtXNUZTMDhYQzdIZndRWlZFMEROU0xKRHZvYms1STUyVjdNVTdLdFlsRE81U2VURUFWTFk1YitBQT09IiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVU52ZDBKUldVUkxNbFozUVhsRlFWVlJUMU5zYWpOcFEzbHdVMlJUZDNKVldWbFBZMHhpVXpaNWVUSTFlVTAyYzNscVNGWnVjV05JUW1jOUNpMHRMUzB0UlU1RUlGQlZRa3hKUXlCTFJWa3RMUzB0TFFvPSJ9fX19", + "integratedTime": 1792511622, + "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d", + "logIndex": 3339636914, + "uuid": "108e9186e8c5677abddac2ca5a6ab882f1fef08af621e0f2315a15000099f51bd60cfda82ba445f1", + "verification": { + "inclusionProof": { + "checkpoint": "rekor.sigstore.dev - 1193050959916656506\n3217732815\niYQpIB+hwfj911TZ3jx27pAmu+auUU4/7hX1UgjW1Xk=\n\n\u2014 rekor.sigstore.dev wNI9ajBFAiEAs37nFb7MChqq2Ewx25XD4+GGZi4JtYSC/+VUWSlZmuwCIGpenAIeEpO16eW4coKD7yfderHSNjD3ne8bNLM3BfSO\n", + "hashes": [ + "01639633f22a3ec47997c42986c1f4e51bfda3e1ee746c8890720b83ac4376b4", + "0775d6a94ea0f9fd24ac2f40b0d5ae7ea5c5a4db39721be9fb30b074dbce0056", + "fcb569765bd7657dfdf0e06b93755fcb3bf36f1dadc14fead7aaf264195540e5", + "44ae8f9bab336a5c173cd8c7334a256c5570cb72e2a43478471eec643abdb1bc", + "2e7164efc66f696b08b1c6a48419f98ede80c930dbfd8a8b5045bfe0e54930c0", + "69645c32dcc24e821fd0cf98797f42a983460e2eccf0a86c8b9cef4f5e516826", + "d08f1e4a4618a859b4c19e41ee0d94dc92f258b22ed35c18a8345370f1f44cdd", + "fdcd3f8737e4720a7e78c0249b6174439089604e71546e62c92e05f778ca39f8", + "9ffeab3d5ef363c5573880102f1d415f5b53df2e910900a2aaea4d5e8b72720c", + "ca010f0e78c08f47679d2372d5a10a9878a2015c3b4b67753fb289674679d573", + "0484fc459183f5191a1f5f4eff5954c5d06af4285a6f5fe8593937bd78547475", + "d7b421e7c5b37697a2e76feacad4ebab65bc2767c0e85fa12e9e296333847051", + "0ccdecead5a695d8d359e61502b86785401c1cfb4746f46480699137a76bb2da", + "ed916d87334cd633f90b1eccc9f011c0da8163146fc375559f75c06dd1bc31fb", + "5eaa5e4bf0471ce13153de87be0e4bf9d1f0ab444f2431c298a4f1fe35c0839d", + "e916fbb8e824dafe5829c1526c03cea4b9560083757220cf765a7827f094bb99", + "1e8bd33c15b3a04aef520d6ee6c222df1d59a2767bc897a456c06b9a9a260880", + "1be9e4ee6804e61e9d526bf6518ecd0c9ad8dd6beb658df5ada68ed40113b7ea", + "aa54d6343cc44674c14157071d75d53e38943f44ac8a41b17dcc55960a95143a", + "820f46340a4d91edfeccd865e2db16b6623270216b38c081de5cace97b9240d4", + "36539c96576628f035b4c288b24a87030b900d81e9df5630a4af8e38cacc71c7", + "ab1cc76a7033cf9ed20dd9897b407b6c92bbd8d4c805bc043060412af0ce44ec", + "c47fc30ac78b1ebf5e2a8613f2ab0e4592bbcd5744198587b95b6c56b0fde706" + ], + "logIndex": 3217732652, + "rootHash": "898429201fa1c1f8fdd754d9de3c76ee9026bbe6ae514e3fee15f55208d6d579", + "treeSize": 3217732815 + }, + "signedEntryTimestamp": "MEQCIBQie2v0MK8+nMAuOpmNf18S3gcXzePB7a0SNUCVQCPHAiBkz5hwCo0w5pT5qKugXQJ8JW4QwQbEYh1FW+ENvjhEmg==" + } + }, + "key_id": "seal-ed25519-ca08dd7f42a4be01", + "log_url": "https://rekor.sigstore.dev", + "nonce": "e2bcbb246607209324676336ac195b9020f1f6191b84261e4b40d2f69d0cf466", + "schema": "openadapt.local-seal-anchor/v1", + "seal_sha256": "65d6dea5a3d696215e1de1da9621f6ce345e5523fee32b7c02abb60fdd755f12", + "statement_sha512": "44b2c8315f3fb84539baef2c957293ff948d98a1e08499cbd63f24fd9d88608b157a4a82537e3a3b1b70dfa49e68d171ab878383be2287c89160d01a1972d866" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.json index d48340ee9..18522f1d0 100644 --- a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.json +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.json @@ -1,13 +1,15 @@ { "algorithm": "ed25519", - "issued_at": "2026-10-20T04:20:06Z", + "authorization_sha256": "bdfda160138f89a708caa122904af6fec66b29ad41c2d8cb25e458e2da5104d3", + "issued_at": "2026-10-20T15:53:27Z", "issuer": "local", "key_id": "seal-ed25519-ca08dd7f42a4be01", "outcome": "VERIFIED", "public_key": "UQOSlj3iCypSdSwrUYYOcLbS6yy25yM6syjHVnqcHBg=", "run_id": "engine", "schema": "openadapt.local-seal/v1", - "signature": "2bOwc2FEywo0QaCr7T/IXc7osuTOOFIDA/I6lKFOjbsb10mOaJOFPl3in1wnItqRXPQWGigLbYKgTadO4k7xAA==", + "scope_item": "r5", + "signature": "lLxvy+9N5iJfKfu0hIVTWr2hu1z+vFUFdZB6M9bluu0uTRRabWby+m1TbYw1XtTpbXIkMY6RVqbyI7eAWrbTBw==", "subject_kind": "run-report", "subject_sha256": "c77e8d47fab15a16286f7c06b05e3c29353e853448695bb68c8d9bd5031dfaa0" } diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.tsa.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.tsa.json new file mode 100644 index 000000000..6bea245e9 --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.tsa.json @@ -0,0 +1,9 @@ +{ + "gen_time": "2026-10-20T15:53:41Z", + "imprint_sha256": "65d6dea5a3d696215e1de1da9621f6ce345e5523fee32b7c02abb60fdd755f12", + "schema": "openadapt.record-timestamp/v1", + "seal_sha256": "65d6dea5a3d696215e1de1da9621f6ce345e5523fee32b7c02abb60fdd755f12", + "tsa": "https://timestamp.sigstore.dev/api/v1/timestamp", + "tsr_file": "seal.tsr", + "tsr_sha256": "7b40480b5dcac43c9b37a1db0b0fa083b55d8d87b9341f950a89601c3c49c139" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.tsr b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.tsr new file mode 100644 index 000000000..a0f7ea199 Binary files /dev/null and b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.tsr differ diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.anchor.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.anchor.json new file mode 100644 index 000000000..22dfbfbe7 --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.anchor.json @@ -0,0 +1,49 @@ +{ + "entry": { + "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhNTEyIiwidmFsdWUiOiI0ZThkMWJhYzkyOWVkOWU0NmU4ODYzMzIwNWE5MDczY2I1NDYyMDQ0Njk4ZDQwNGNjNDVhODlkY2U4MTVjYzU4MzI4NGFmYTU0YzNkYjFjMGRmMDFmOTIyYWJlYjRkZDYxNTc0OTQxODdjZjQ5OTNhYmIwNTJmNDRlZWMzOWEwMiJ9fSwic2lnbmF0dXJlIjp7ImNvbnRlbnQiOiJTb2FiaHU5bmw4dzFySmtiVmFmdzYrZGJ5eVNiREE5dGNRSlhnYUdzTmk3M3FKL29Wbmg2cER2UVVjTG0wWnE2alFmQzdTSlJqWEQycFZrdC9zUWhBQT09IiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVU52ZDBKUldVUkxNbFozUVhsRlFWVlJUMU5zYWpOcFEzbHdVMlJUZDNKVldWbFBZMHhpVXpaNWVUSTFlVTAyYzNscVNGWnVjV05JUW1jOUNpMHRMUzB0UlU1RUlGQlZRa3hKUXlCTFJWa3RMUzB0TFFvPSJ9fX19", + "integratedTime": 1792511625, + "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d", + "logIndex": 3339637492, + "uuid": "108e9186e8c5677ae048d92273984a18a560bc8237b32a5924424c1367a2aa9a6200b3dc196c3491", + "verification": { + "inclusionProof": { + "checkpoint": "rekor.sigstore.dev - 1193050959916656506\n3217733234\n0TLv/X08+2ltbBIfioJAobc1ClPY9fS4aS3QCUKA2ug=\n\n\u2014 rekor.sigstore.dev wNI9ajBFAiA90RuG5P4l/tt5Wn/0KOJpg2ZV2xyzDYNFbF7c93ddDwIhAOkcLJg4KvLRYoPDAh3BROQIANv6TSIykU6SGAegnH0p\n", + "hashes": [ + "6c4d78db1062105b4c9010019dd1f8412da7d083a5d5f8d3a578e8560bc83753", + "4e9d46d71cd391aeb6136f9890ee3be425fe7f9e91d617549d19659ad58eff0f", + "8b7e48fb1fd624d82028264b44b33bf7e342023c4b01d34b7ecaf282d9876043", + "ab26b95b98b7b4334c9fd1b0060b214906ca0ad5d3e343dc1e12909798414857", + "f14007fe302a2a9ec7b5c942cea1b1ee515c7e7dfe54a55bf9273a6c79d07056", + "e77e493a3728d79812d04512a1530ccdb701369454933f0e76e6b49dbaf19f09", + "f2f6be98b42c39f2b8749c8ff3206272b047df7c40d497a5dd1f7c10aa4230e3", + "23ee394392344b0d066f6e8a4fbd092ed13404027734b7f662a83aa943c0c8ce", + "9ffeab3d5ef363c5573880102f1d415f5b53df2e910900a2aaea4d5e8b72720c", + "ca010f0e78c08f47679d2372d5a10a9878a2015c3b4b67753fb289674679d573", + "0484fc459183f5191a1f5f4eff5954c5d06af4285a6f5fe8593937bd78547475", + "d7b421e7c5b37697a2e76feacad4ebab65bc2767c0e85fa12e9e296333847051", + "0ccdecead5a695d8d359e61502b86785401c1cfb4746f46480699137a76bb2da", + "ed916d87334cd633f90b1eccc9f011c0da8163146fc375559f75c06dd1bc31fb", + "5eaa5e4bf0471ce13153de87be0e4bf9d1f0ab444f2431c298a4f1fe35c0839d", + "e916fbb8e824dafe5829c1526c03cea4b9560083757220cf765a7827f094bb99", + "1e8bd33c15b3a04aef520d6ee6c222df1d59a2767bc897a456c06b9a9a260880", + "1be9e4ee6804e61e9d526bf6518ecd0c9ad8dd6beb658df5ada68ed40113b7ea", + "aa54d6343cc44674c14157071d75d53e38943f44ac8a41b17dcc55960a95143a", + "820f46340a4d91edfeccd865e2db16b6623270216b38c081de5cace97b9240d4", + "36539c96576628f035b4c288b24a87030b900d81e9df5630a4af8e38cacc71c7", + "ab1cc76a7033cf9ed20dd9897b407b6c92bbd8d4c805bc043060412af0ce44ec", + "c47fc30ac78b1ebf5e2a8613f2ab0e4592bbcd5744198587b95b6c56b0fde706" + ], + "logIndex": 3217733230, + "rootHash": "d132effd7d3cfb696d6c121f8a8240a1b7350a53d8f5f4b8692dd0094280dae8", + "treeSize": 3217733234 + }, + "signedEntryTimestamp": "MEUCIF3W5xHxCAXpR0AnUFBJUMATwDOryWjOp+P9yTm1XHYnAiEAg0m5Etgf/BRmbIBOKXEiYZjiXp/79WgQ5UWlS08ZWw4=" + } + }, + "key_id": "seal-ed25519-ca08dd7f42a4be01", + "log_url": "https://rekor.sigstore.dev", + "nonce": "eda5ce03996da7fe7736b597cee9901e22e8801fe0709f61c453b2dfcc49ed93", + "schema": "openadapt.local-seal-anchor/v1", + "seal_sha256": "04d05033f9e0c2d39759a2f9ca44845d5c21b3e7b37f8be4601b25bfd971c826", + "statement_sha512": "4e8d1bac929ed9e46e88633205a9073cb5462044698d404cc45a89dce815cc583284afa54c3db1c0df01f922abeb4dd6157494187cf4993abb052f44eec39a02" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.json index bcd3a193c..efdb61af6 100644 --- a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.json +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.json @@ -1,13 +1,15 @@ { "algorithm": "ed25519", - "issued_at": "2026-10-20T04:20:09Z", + "authorization_sha256": "bdfda160138f89a708caa122904af6fec66b29ad41c2d8cb25e458e2da5104d3", + "issued_at": "2026-10-20T15:53:28Z", "issuer": "local", "key_id": "seal-ed25519-ca08dd7f42a4be01", "outcome": "HALTED", "public_key": "UQOSlj3iCypSdSwrUYYOcLbS6yy25yM6syjHVnqcHBg=", "run_id": "engine", "schema": "openadapt.local-seal/v1", - "signature": "O/o+bIrQAB8Ln+idkRtT8e0nf0wI4AfjnkJx2vUEeQWxFG7a1EJmYdKpHE6yWQ3Hcix2k5nJMnMfFDVfJ8q+AA==", + "scope_item": "r6", + "signature": "10CU+nicG4SE7mdPu1RtlmlJvDSwBCdzUBF0sgQHjUxfkW9kW9zwBYlLIgKYfI3SoaIpGQpmCGBv2Rt2oL3GCg==", "subject_kind": "run-report", "subject_sha256": "3a1e2eecbf3a2af4628524c206db469de4d20bf310cae93dc79307f7b3d861a4" } diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.tsa.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.tsa.json new file mode 100644 index 000000000..05ca6793b --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.tsa.json @@ -0,0 +1,9 @@ +{ + "gen_time": "2026-10-20T15:53:44Z", + "imprint_sha256": "04d05033f9e0c2d39759a2f9ca44845d5c21b3e7b37f8be4601b25bfd971c826", + "schema": "openadapt.record-timestamp/v1", + "seal_sha256": "04d05033f9e0c2d39759a2f9ca44845d5c21b3e7b37f8be4601b25bfd971c826", + "tsa": "https://timestamp.sigstore.dev/api/v1/timestamp", + "tsr_file": "seal.tsr", + "tsr_sha256": "40bc950b9a0c0a32c18dd23fdb5fd3573783b6f3a1708cc915463046596879c5" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.tsr b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.tsr new file mode 100644 index 000000000..a09604fb8 Binary files /dev/null and b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.tsr differ diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/README.md b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/README.md index 502f6a0e8..98b483cee 100644 --- a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/README.md +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/README.md @@ -30,11 +30,43 @@ Before each run the fixture was reset and the existing chart Rosa Delgado (born Each `engine/report.json` is signed with an offline Seal (`openadapt.local-seal/v1`), key `seal-ed25519-ca08dd7f42a4be01`. The public key is in `seal-key.json`; the private key was never in this repository. +Each Seal names the run authorization in `run-authorization/` and its item (`r3` to `r6`). Each Seal and the authorization are also anchored in Sigstore Rekor and timestamped by the Sigstore timestamp authority: + +| Record | Rekor log index | Rekor time (UTC) | Sigstore TSA time (UTC) | +|---|---|---|---| +| `run-authorization/` | 3339630782 | 2026-10-20 15:53:13 | 2026-10-20 15:53:12 | +| `1-r3-ines-carvalho` | 3339635766 | 2026-10-20 15:53:36 | 2026-10-20 15:53:35 | +| `2-r4-theo-lindqvist` | 3339636256 | 2026-10-20 15:53:39 | 2026-10-20 15:53:38 | +| `3-r5-grace-adeyemi` | 3339636914 | 2026-10-20 15:53:42 | 2026-10-20 15:53:41 | +| `4-r6-rosa-delgado` | 3339637492 | 2026-10-20 15:53:45 | 2026-10-20 15:53:44 | + +Look up any entry at `https://search.sigstore.dev/?logIndex=`. Only a digest and the Seal key's public key were sent to Rekor and the TSA, never report content. + ```bash -openadapt-flow local-seal verify 1-r3-ines-carvalho/engine --keys seal-key.json +openadapt-flow local-seal verify 1-r3-ines-carvalho/engine 2-r4-theo-lindqvist/engine \ + 3-r5-grace-adeyemi/engine 4-r6-rosa-delgado/engine --keys seal-key.json \ + --strict --require-anchor --require-timestamp --authorization run-authorization --live ``` -These Seals are not anchored in a transparency log. +Without `--live` this runs offline, from the stored inclusion proofs and tokens. `--live` also fetches each Rekor entry, and checks the signer's key against https://github.com/abrichr.keys. + +### The run authorization + +`run-authorization/run-authorization.json` (`openadapt.run-authorization/v1`) names: + +- the bundle `ec096afa…60b6`; +- the items `r3` to `r6`, one run each; +- the `standard` profile; +- the Seal key above; +- the signer's key, `SHA256:x+1MwCSAsNNHpc+UcIdbktY/Z+/FByyqfhuwiRzeO9A`. + +The founder signed it with the SSH key published at https://github.com/abrichr.keys (`ssh-keygen -Y sign -n openadapt-run-authorization`). `run-authorization.allowed_signers` is a copy of that key list, for `ssh-keygen -Y verify`. It isn't proof of identity on its own; `--live` checks the key against GitHub itself. + +The founder signed after the runs: they ran at about 03:03 UTC, and the authorization was logged at 15:53 UTC. The verifier therefore reports `after_run`, and the card reads "Authorization signed by @abrichr on 2026-10-20, after this run". The four Seals were re-signed under the authorization after it was signed, over the same redacted report bytes. That re-signing doesn't change the order. + +`operator-profile.json` counts these four anchored Seals for the Seal key: 3 verified, 1 stopped before effect, 0 completed-unverified, 0 failed. Its linked identity, `github:abrichr`, was checked live against GitHub. + +`authorization.json` in each run directory is a different record: the engine's governed authorization for that run. OpenEMR puts its per-session CSRF token in the entry URL (`main.php?token_main=...`). Each report here was run through `openadapt-flow redact-report` before it was sealed, so `execution_entry_url` reads `token_main=`, and the report's `redactions` field names that one change. The duplicate-check reports in `qualification/duplicate-check/` were redacted the same way. The unredacted originals stay on the machine that ran the work. See `packages/flow/docs/REPORT_REDACTION.md`. diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/operator-profile.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/operator-profile.json new file mode 100644 index 000000000..70d1e1054 --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/operator-profile.json @@ -0,0 +1,111 @@ +{ + "counted": "Seals that verify against the pinned keys and have a valid transparency-log anchor", + "excluded": { + "duplicate": 0, + "item_reused": 0, + "not_valid": 0, + "unanchored": 0 + }, + "generated_at": "2026-10-20T15:54:05Z", + "operators": { + "seal-ed25519-ca08dd7f42a4be01": { + "apps": [ + "openemr" + ], + "first_anchored_at": "2026-10-20T15:53:36Z", + "last_anchored_at": "2026-10-20T15:53:45Z", + "linked_identity": [ + { + "checked_against": "https://github.com/abrichr.keys now", + "handle": "github:abrichr", + "provider": "ssh-github", + "run_authorization_sha256": "bdfda160138f89a708caa122904af6fec66b29ad41c2d8cb25e458e2da5104d3", + "ssh_key_fingerprint": "SHA256:x+1MwCSAsNNHpc+UcIdbktY/Z+/FByyqfhuwiRzeO9A" + } + ], + "other_outcomes": {}, + "outcomes": { + "completed_unverified": 0, + "failed": 0, + "stopped_before_effect": 1, + "verified": 3 + }, + "programs": [ + "openemr-create-synthetic-patient" + ], + "public_key": "UQOSlj3iCypSdSwrUYYOcLbS6yy25yM6syjHVnqcHBg=", + "public_key_sha256": "ca08dd7f42a4be017301c3f6e7dab39ff0671fab22a16ec6d8ad8353d165c2ad", + "rekor_log_indexes": [ + 3339635766, + 3339636256, + 3339636914, + 3339637492 + ], + "run_list": [ + { + "anchor": { + "integrated_time": 1792511616, + "log_index": 3339635766, + "uuid": "108e9186e8c5677aa7543418cff84038fcf0b8503bf878af6bf8d4f906821840f5ac10e710b45fd0" + }, + "app": "openemr", + "execution_outcome": "VERIFIED", + "issued_at": "2026-10-20T15:53:26Z", + "outcome": "verified", + "program": "openemr-create-synthetic-patient", + "scope_item": "r3", + "seal_sha256": "548ba574914dffee8443b54d33a340ee106923e0fe672b41d7756621124d9a4d", + "transaction_outcome": "VERIFIED" + }, + { + "anchor": { + "integrated_time": 1792511619, + "log_index": 3339636256, + "uuid": "108e9186e8c5677a034e57e78270445688b507e30b2098787ccfa9e37edd267f473f4439dc1da50f" + }, + "app": "openemr", + "execution_outcome": "VERIFIED", + "issued_at": "2026-10-20T15:53:27Z", + "outcome": "verified", + "program": "openemr-create-synthetic-patient", + "scope_item": "r4", + "seal_sha256": "e27585b3f86dd9b79ef3fc368ffca13cd34824e03352987697ae1e33f228808e", + "transaction_outcome": "VERIFIED" + }, + { + "anchor": { + "integrated_time": 1792511622, + "log_index": 3339636914, + "uuid": "108e9186e8c5677abddac2ca5a6ab882f1fef08af621e0f2315a15000099f51bd60cfda82ba445f1" + }, + "app": "openemr", + "execution_outcome": "VERIFIED", + "issued_at": "2026-10-20T15:53:27Z", + "outcome": "verified", + "program": "openemr-create-synthetic-patient", + "scope_item": "r5", + "seal_sha256": "65d6dea5a3d696215e1de1da9621f6ce345e5523fee32b7c02abb60fdd755f12", + "transaction_outcome": "VERIFIED" + }, + { + "anchor": { + "integrated_time": 1792511625, + "log_index": 3339637492, + "uuid": "108e9186e8c5677ae048d92273984a18a560bc8237b32a5924424c1367a2aa9a6200b3dc196c3491" + }, + "app": "openemr", + "execution_outcome": "HALTED", + "issued_at": "2026-10-20T15:53:28Z", + "outcome": "stopped_before_effect", + "program": "openemr-create-synthetic-patient", + "scope_item": "r6", + "seal_sha256": "04d05033f9e0c2d39759a2f9ca44845d5c21b3e7b37f8be4601b25bfd971c826", + "transaction_outcome": "HALTED_BEFORE_EFFECT" + } + ], + "runs": 4, + "seal_key_id": "seal-ed25519-ca08dd7f42a4be01" + } + }, + "schema": "openadapt.operator-profile/v1" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.allowed_signers b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.allowed_signers new file mode 100644 index 000000000..939aa6c53 --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.allowed_signers @@ -0,0 +1,2 @@ +# github:abrichr: snapshot of https://github.com/abrichr.keys at 2026-10-20T05:51:31Z +github:abrichr namespaces="openadapt-run-authorization" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEqSb2q1hQenZ7L7Ae78iAbYWEU4xmIrj3wuvNwasrgv diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.anchor.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.anchor.json new file mode 100644 index 000000000..2700b6d40 --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.anchor.json @@ -0,0 +1,50 @@ +{ + "entry": { + "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhNTEyIiwidmFsdWUiOiJjOGQyMjQ3NjNlNGNkYTVhZjZmZTU2NDk2ZjRkY2ZhZTgzMTg1ZDNjYWNjOGZmOGExNWY1ZDAzOThlYmRmNzJkNDdkZTc1ZTkwNzEzOTYwZjk4NzE1YzI1ZGJjYzk0OWQyZDhmZjVlZTk2MDA5YjY5OWQ3MTIyOTQ2Y2JhN2IyNCJ9fSwic2lnbmF0dXJlIjp7ImNvbnRlbnQiOiJpcTFpc0YrRTFTdDBUaVpESUlBME1SUkdrak5SbTlUdzlsRlRCYzJUcTR4Z3h6UlZxTEhpRHczRjlSR056OGFFVnRKUnJqejlYR3N1ZW9FN3hjTllDQT09IiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVU52ZDBKUldVUkxNbFozUVhsRlFWVlJUMU5zYWpOcFEzbHdVMlJUZDNKVldWbFBZMHhpVXpaNWVUSTFlVTAyYzNscVNGWnVjV05JUW1jOUNpMHRMUzB0UlU1RUlGQlZRa3hKUXlCTFJWa3RMUzB0TFFvPSJ9fX19", + "integratedTime": 1792511593, + "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d", + "logIndex": 3339630782, + "uuid": "108e9186e8c5677a001396813afed609baaef0283598e838b9ed0afa5564fa988f89c2031f45000a", + "verification": { + "inclusionProof": { + "checkpoint": "rekor.sigstore.dev - 1193050959916656506\n3217726668\nluSaeekqWadIGV8Md+b7NeRumngUsUkPwPj/RlYXj5I=\n\n\u2014 rekor.sigstore.dev wNI9ajBFAiBS3eZTgFE7tlspKZWLbgIEfenJgueQxMaMZM/99vaCSwIhANtpKOQVrhzuAH76cisPhwRfqln+xcBfom5j6WWYYARZ\n", + "hashes": [ + "9cdcd033510e9b1f6196f9488aeadb8ea12837188291f4dcb17a841cfdac9cfe", + "333d3c99f6ebeccb9b891c328c1742737e9f87033ced6e08a71b999d5faa6ea3", + "3d67ee4e7f48a45184d7f67fa29f2a5ab63b2e561a3ece7ad8a8f30d34c2740a", + "6628d72c0d30a95189f8e7452f82c384b5fcb036ddc8cd8248fe0db041cd6a82", + "14a1c1853ee29a313e92ec6979ed6e201d0fc9d7340f1d4b618185fd99c8899a", + "03841902fadcd0a7caa1e0a28c24c8c09d6fcb5656d6d3ceb4ba37b012543ff5", + "9c0fb3154b844b0e073ea23feec7810e2e4da534e2fced0191f8a3e22e58db4b", + "17424224392abf9226909473db61f46d3d9e3cfcf4011cb9b6eb5d2976ea7f4f", + "7b7f2f6ab907f81f88229cd6b13d91d76eef66073ad7723dd4c667aaa0476320", + "e28712ec0baf11f68477008e0f8f06c7e301f81124b630b0a3ed9451692a8149", + "c7d458c7b211585467fb12d9712dbaaf137f4947235eece15f3c81494bcc6193", + "d7b421e7c5b37697a2e76feacad4ebab65bc2767c0e85fa12e9e296333847051", + "0ccdecead5a695d8d359e61502b86785401c1cfb4746f46480699137a76bb2da", + "ed916d87334cd633f90b1eccc9f011c0da8163146fc375559f75c06dd1bc31fb", + "5eaa5e4bf0471ce13153de87be0e4bf9d1f0ab444f2431c298a4f1fe35c0839d", + "e916fbb8e824dafe5829c1526c03cea4b9560083757220cf765a7827f094bb99", + "1e8bd33c15b3a04aef520d6ee6c222df1d59a2767bc897a456c06b9a9a260880", + "1be9e4ee6804e61e9d526bf6518ecd0c9ad8dd6beb658df5ada68ed40113b7ea", + "aa54d6343cc44674c14157071d75d53e38943f44ac8a41b17dcc55960a95143a", + "820f46340a4d91edfeccd865e2db16b6623270216b38c081de5cace97b9240d4", + "36539c96576628f035b4c288b24a87030b900d81e9df5630a4af8e38cacc71c7", + "ab1cc76a7033cf9ed20dd9897b407b6c92bbd8d4c805bc043060412af0ce44ec", + "c47fc30ac78b1ebf5e2a8613f2ab0e4592bbcd5744198587b95b6c56b0fde706" + ], + "logIndex": 3217726520, + "rootHash": "96e49a79e92a59a748195f0c77e6fb35e46e9a7814b1490fc0f8ff4656178f92", + "treeSize": 3217726668 + }, + "signedEntryTimestamp": "MEUCIQD0lsvspsL4nZBA/HD2Zvd1ZZlMK3SKx4Jk2kHmV86w3QIgFEZrkE1ogGn5tsknK5MSn0jGklECkwtrvwxHK4ItjYA=" + } + }, + "key_id": "seal-ed25519-ca08dd7f42a4be01", + "log_url": "https://rekor.sigstore.dev", + "nonce": "89988bfd536c6beb4bd96160e3e3058419777721ed5c41646aea7e36800d9c9f", + "run_authorization_sha256": "bdfda160138f89a708caa122904af6fec66b29ad41c2d8cb25e458e2da5104d3", + "schema": "openadapt.local-seal-anchor/v1", + "signature_sha256": "69a122f802945951a93984831248d4429caa617b4edba5eb2fe3b4e0756da214", + "statement_sha512": "c8d224763e4cda5af6fe56496f4dcfae83185d3cacc8ff8a15f5d0398ebdf72d47de75e90713960f98715c25dbcc949d2d8ff5ee96009b699d7122946cba7b24" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.json new file mode 100644 index 000000000..f989607c7 --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.json @@ -0,0 +1,21 @@ +{ + "authorizer": "github:abrichr", + "bundle_content_digest": "ec096afa2b614326b00ec3155f256041c19d86f3998761ce9d772cfd911460b6", + "issued_at": "2026-10-20T05:51:31Z", + "nonce": "8691f588a507ca4882bc0cabe9371a706d0c33bf740137f303a80958101ffbc9", + "schema": "openadapt.run-authorization/v1", + "scope": { + "items": [ + "r3", + "r4", + "r5", + "r6" + ], + "profile": "standard", + "reusable": false, + "seal_key_ids": [ + "seal-ed25519-ca08dd7f42a4be01" + ] + }, + "signer_fingerprint": "SHA256:x+1MwCSAsNNHpc+UcIdbktY/Z+/FByyqfhuwiRzeO9A" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.json.sig b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.json.sig new file mode 100644 index 000000000..e020a22c4 --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.json.sig @@ -0,0 +1,6 @@ +-----BEGIN SSH SIGNATURE----- +U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgSpJvarWFB6dnsvsB7vyIBthYRT +jGYiuPfC683BqyuC8AAAAbb3BlbmFkYXB0LXJ1bi1hdXRob3JpemF0aW9uAAAAAAAAAAZz +aGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5AAAAQESj95I/VGv80qYZLHYlK1xC47I053k5t7 +9reegcHJ2UnJ+poC8QbjywpC56ZyY+w3Xw3AJ7rAE9BEtRx8GwFg4= +-----END SSH SIGNATURE----- diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.tsa.json b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.tsa.json new file mode 100644 index 000000000..a692a4fd3 --- /dev/null +++ b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.tsa.json @@ -0,0 +1,10 @@ +{ + "gen_time": "2026-10-20T15:53:12Z", + "imprint_sha256": "a364a2c9b2540aa20dfa12c83142e6818fe7a640a1f34d2436f3cf5a4aa03f3a", + "run_authorization_sha256": "bdfda160138f89a708caa122904af6fec66b29ad41c2d8cb25e458e2da5104d3", + "schema": "openadapt.record-timestamp/v1", + "signature_sha256": "69a122f802945951a93984831248d4429caa617b4edba5eb2fe3b4e0756da214", + "tsa": "https://timestamp.sigstore.dev/api/v1/timestamp", + "tsr_file": "run-authorization.tsr", + "tsr_sha256": "6c1e0c998efa8690d1f1342031c24ce94a7ebf88cc0365e2e97cd908458a4a06" +} diff --git a/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.tsr b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.tsr new file mode 100644 index 000000000..581794ac0 Binary files /dev/null and b/packages/flow/benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.tsr differ diff --git a/packages/flow/docs/OFFLINE_SEALS.md b/packages/flow/docs/OFFLINE_SEALS.md index e8f1b9730..2bc6f11d6 100644 --- a/packages/flow/docs/OFFLINE_SEALS.md +++ b/packages/flow/docs/OFFLINE_SEALS.md @@ -444,8 +444,8 @@ from a timestamp authority is a second, independent time, signed by the TSA's certificate. Sigstore's TSA (`timestamp.sigstore.dev`) is the default. ```bash -openadapt-flow local-seal timestamp runs/job-0007 # writes runs/job-0007/seal.tsa.json -openadapt-flow local-seal timestamp auth/ # writes auth/run-authorization.tsa.json +openadapt-flow local-seal timestamp runs/job-0007 # writes seal.tsr and seal.tsa.json +openadapt-flow local-seal timestamp auth/ # writes run-authorization.tsr and .tsa.json openadapt-flow local-seal verify runs/job-0007 --keys site-keys.json --require-timestamp ``` @@ -456,9 +456,17 @@ Each request sends only a 32-byte SHA-256 imprint and a random nonce: `canonical_json({"run_authorization_sha256", "signature_sha256"})`, which covers the statement and the signature together. -The token file (`openadapt.record-timestamp/v1`) holds the record's digest -fields, `imprint_sha256`, `tsa`, `token` (base64 DER TimeStampToken) and -`gen_time`. `timestamp` checks the token offline before writing it. +The token is stored in its standard binary form: DER, as returned by the +TSA, in `seal.tsr` next to `seal.json` (`run-authorization.tsr` for an +authorization). `openssl ts -reply -in seal.tsr -token_in -text` reads it. +A small JSON file beside it, `seal.tsa.json` (`openadapt.record-timestamp/v1`), +holds: + +- the record's digest fields and `imprint_sha256`; +- `tsa`, the authority's URL; +- `tsr_file`, a bare file name beside the JSON; +- `tsr_sha256`, the SHA-256 of the `.tsr` bytes; +- `gen_time`. `timestamp` checks the token offline before writing it. `--require-timestamp` checks it again, against the Sigstore TSA root shipped with OpenAdapt, or the certificates you pass with `--tsa-cert`. Strict no-outbound mode refuses to send. To cover many Seals with one token instead, diff --git a/packages/flow/openadapt_flow/seal_timestamp.py b/packages/flow/openadapt_flow/seal_timestamp.py index ef3ba61fd..216a7fe81 100644 --- a/packages/flow/openadapt_flow/seal_timestamp.py +++ b/packages/flow/openadapt_flow/seal_timestamp.py @@ -16,17 +16,17 @@ ``canonical_json({"run_authorization_sha256": ..., "signature_sha256": ...})``, which covers the statement and the person's signature together. -The token is stored as ``seal.tsa.json`` next to ``seal.json`` -(``NAME.seal.tsa.json`` next to ``NAME.seal.json``), or -``run-authorization.tsa.json`` next to the statement -(``openadapt.record-timestamp/v1``). Before it is written, the token is +The token is stored in its standard binary form, DER, as ``seal.tsr`` next +to ``seal.json`` (``run-authorization.tsr`` next to the statement). A small +JSON file beside it, ``seal.tsa.json`` / ``run-authorization.tsa.json`` +(``openadapt.record-timestamp/v1``), names the record's digests, the imprint, +the TSA, the token file and the token's SHA-256. Before it is written, the token is checked offline against the pinned TSA certificate: the Sigstore TSA root shipped with OpenAdapt, unless the caller pins another. """ from __future__ import annotations -import base64 import hashlib import json import os @@ -73,6 +73,28 @@ def default_trusted() -> list[Any]: return load_pem_certificates(sigstore_tsa_root_pem()) +def token_path(timestamp_file: Path) -> Path: + """``seal.tsa.json`` -> ``seal.tsr``: the DER TimeStampToken stored beside it.""" + timestamp_file = Path(timestamp_file) + name = timestamp_file.name + stem = name[: -len(".tsa.json")] if name.endswith(".tsa.json") else name + return timestamp_file.with_name(stem + ".tsr") + + +def _token_file(data: Mapping[str, Any], path: Path) -> Path: + """The token file the JSON names: a bare file name beside it, nothing else.""" + name = str(data["tsr_file"]) + if ( + not name + or "/" in name + or "\\" in name + or name in (".", "..") + or not name.endswith(".tsr") + ): + raise ValueError("tsr_file must be a .tsr file name beside the JSON") + return Path(path).with_name(name) + + def verify_record_timestamp( fields: Mapping[str, str], path: Path, trusted: Optional[Sequence[Any]] = None ) -> Any: @@ -97,13 +119,29 @@ def verify_record_timestamp( expected = imprint(fields) if data.get("imprint_sha256") != expected.hex(): return TimestampVerification(False, "timestamp_mismatch") - token = base64.b64decode(str(data["token"]), validate=True) + token_file = _token_file(data, Path(path)) + want_sha = str(data["tsr_sha256"]) except (KeyError, TypeError, ValueError, AttributeError, RecordTimestampError): return TimestampVerification(False, "timestamp_malformed") + try: + token = token_file.read_bytes() + except FileNotFoundError: + return TimestampVerification(False, "timestamp_token_missing") + except OSError: + return TimestampVerification(False, "timestamp_malformed") + if hashlib.sha256(token).hexdigest() != want_sha: + return TimestampVerification(False, "timestamp_token_mismatch") pinned = list(trusted) if trusted is not None else default_trusted() return verify_timestamp_token(token, expected, pinned) +def _write_atomic(path: Path, data: bytes, mode: int = 0o644) -> None: + tmp = path.with_name(path.name + ".tmp") + tmp.write_bytes(data) + os.chmod(tmp, mode) + os.replace(tmp, path) + + def timestamp_record( fields: Mapping[str, str], out: Path, @@ -112,10 +150,15 @@ def timestamp_record( trusted: Optional[Sequence[Any]] = None, env: Optional[Mapping[str, str]] = None, ) -> dict[str, Any]: - """Get one token for ``fields`` from ``authority`` and write ``out``. Idempotent.""" + """Get one token for ``fields`` from ``authority``; write ``out`` and its ``.tsr``. + + The token is stored as-is (DER CMS ``TimeStampToken``) in ``.tsr``; + the JSON names that file and its SHA-256. Idempotent. + """ from openadapt_flow import no_outbound out = Path(out) + tsr = token_path(out) if out.exists(): existing = verify_record_timestamp(fields, out, trusted) if existing.ok: @@ -130,26 +173,25 @@ def timestamp_record( token = bytes(authority.timestamp(digest)) except Exception as exc: # unreachable TSA, bad answer: a closed reason raise RecordTimestampError("timestamp_failed", str(exc)) from exc + pinned = list(trusted) if trusted is not None else default_trusted() + from openadapt_flow.countersign.tsa import verify_timestamp_token + + result = verify_timestamp_token(token, digest, pinned) + if not result.ok: + raise RecordTimestampError("timestamp_invalid", str(result.reason)) record = { "schema": SCHEMA, **fields, "imprint_sha256": digest.hex(), "tsa": str(getattr(authority, "name", "unknown")), - "token": base64.b64encode(token).decode("ascii"), + "tsr_file": tsr.name, + "tsr_sha256": hashlib.sha256(token).hexdigest(), + "gen_time": result.gen_time, } - tmp = out.with_name(out.name + ".tmp") - tmp.write_text( - json.dumps(record, indent=2, sort_keys=True) + "\n", encoding="utf-8" - ) - result = verify_record_timestamp(fields, tmp, trusted) - if not result.ok: - tmp.unlink() - raise RecordTimestampError("timestamp_invalid", str(result.reason)) - record["gen_time"] = result.gen_time - tmp.write_text( - json.dumps(record, indent=2, sort_keys=True) + "\n", encoding="utf-8" + _write_atomic(tsr, token) + _write_atomic( + out, (json.dumps(record, indent=2, sort_keys=True) + "\n").encode("utf-8") ) - os.replace(tmp, out) return record diff --git a/packages/flow/public-artifacts.json b/packages/flow/public-artifacts.json index 2c6262d4c..12c4af6ef 100644 --- a/packages/flow/public-artifacts.json +++ b/packages/flow/public-artifacts.json @@ -551,7 +551,9 @@ "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/checkpoints/step_0027_step_039.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/checkpoints/step_0028_step_040.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/report.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.anchor.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/engine/seal.tsa.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/result.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/run-gate.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/1-r3-ines-carvalho/sql-readback.json", @@ -587,7 +589,9 @@ "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/checkpoints/step_0027_step_039.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/checkpoints/step_0028_step_040.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/report.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.anchor.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/engine/seal.tsa.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/result.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/run-gate.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/2-r4-theo-lindqvist/sql-readback.json", @@ -623,7 +627,9 @@ "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/checkpoints/step_0027_step_039.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/checkpoints/step_0028_step_040.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/report.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.anchor.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/engine/seal.tsa.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/result.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/run-gate.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/3-r5-grace-adeyemi/sql-readback.json", @@ -659,10 +665,13 @@ "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/checkpoints/step_0026_step_037.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/pending_escalation.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/report.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.anchor.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/engine/seal.tsa.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/result.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/run-gate.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/4-r6-rosa-delgado/sql-readback.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/operator-profile.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/qualification/campaign-summary.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/qualification/certified-run/oracle.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/qualification/certified-run/run-gate.json", @@ -687,6 +696,9 @@ "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/qualification/qualification/report.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/qualification/qualification/result.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/qualification/timing.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.anchor.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.json", + "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/run-authorization/run-authorization.tsa.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/seal-key.json", "benchmark/scoreboard/raw/openemr_referral/certified/2026-10-20/summary.json", "benchmark/scoreboard/raw/openemr_referral/claims/2026-10-19-a/hand_check.json", @@ -2518,6 +2530,13 @@ "tests/fixtures/jit/playwright_mcp_add_note.json", "tests/fixtures/jit/playwright_mcp_snapshot_refs.json", "tests/fixtures/match_ridge/openemr_accordion_rdp.png", + "tests/fixtures/rekor_real/run-authorization/run-authorization.anchor.json", + "tests/fixtures/rekor_real/run-authorization/run-authorization.json", + "tests/fixtures/rekor_real/run-authorization/run-authorization.tsa.json", + "tests/fixtures/rekor_real/seal-key.json", + "tests/fixtures/rekor_real/seal.anchor.json", + "tests/fixtures/rekor_real/seal.json", + "tests/fixtures/rekor_real/seal.tsa.json", "tests/fixtures/remote-safe-synthetic-flow-release-verification.json", "tests/fixtures/runtime-validation-canonical-vector.json", "tests/fixtures/shadow/invoice_exact.episodes.json", diff --git a/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.anchor.json b/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.anchor.json new file mode 100644 index 000000000..2700b6d40 --- /dev/null +++ b/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.anchor.json @@ -0,0 +1,50 @@ +{ + "entry": { + "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhNTEyIiwidmFsdWUiOiJjOGQyMjQ3NjNlNGNkYTVhZjZmZTU2NDk2ZjRkY2ZhZTgzMTg1ZDNjYWNjOGZmOGExNWY1ZDAzOThlYmRmNzJkNDdkZTc1ZTkwNzEzOTYwZjk4NzE1YzI1ZGJjYzk0OWQyZDhmZjVlZTk2MDA5YjY5OWQ3MTIyOTQ2Y2JhN2IyNCJ9fSwic2lnbmF0dXJlIjp7ImNvbnRlbnQiOiJpcTFpc0YrRTFTdDBUaVpESUlBME1SUkdrak5SbTlUdzlsRlRCYzJUcTR4Z3h6UlZxTEhpRHczRjlSR056OGFFVnRKUnJqejlYR3N1ZW9FN3hjTllDQT09IiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVU52ZDBKUldVUkxNbFozUVhsRlFWVlJUMU5zYWpOcFEzbHdVMlJUZDNKVldWbFBZMHhpVXpaNWVUSTFlVTAyYzNscVNGWnVjV05JUW1jOUNpMHRMUzB0UlU1RUlGQlZRa3hKUXlCTFJWa3RMUzB0TFFvPSJ9fX19", + "integratedTime": 1792511593, + "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d", + "logIndex": 3339630782, + "uuid": "108e9186e8c5677a001396813afed609baaef0283598e838b9ed0afa5564fa988f89c2031f45000a", + "verification": { + "inclusionProof": { + "checkpoint": "rekor.sigstore.dev - 1193050959916656506\n3217726668\nluSaeekqWadIGV8Md+b7NeRumngUsUkPwPj/RlYXj5I=\n\n\u2014 rekor.sigstore.dev wNI9ajBFAiBS3eZTgFE7tlspKZWLbgIEfenJgueQxMaMZM/99vaCSwIhANtpKOQVrhzuAH76cisPhwRfqln+xcBfom5j6WWYYARZ\n", + "hashes": [ + "9cdcd033510e9b1f6196f9488aeadb8ea12837188291f4dcb17a841cfdac9cfe", + "333d3c99f6ebeccb9b891c328c1742737e9f87033ced6e08a71b999d5faa6ea3", + "3d67ee4e7f48a45184d7f67fa29f2a5ab63b2e561a3ece7ad8a8f30d34c2740a", + "6628d72c0d30a95189f8e7452f82c384b5fcb036ddc8cd8248fe0db041cd6a82", + "14a1c1853ee29a313e92ec6979ed6e201d0fc9d7340f1d4b618185fd99c8899a", + "03841902fadcd0a7caa1e0a28c24c8c09d6fcb5656d6d3ceb4ba37b012543ff5", + "9c0fb3154b844b0e073ea23feec7810e2e4da534e2fced0191f8a3e22e58db4b", + "17424224392abf9226909473db61f46d3d9e3cfcf4011cb9b6eb5d2976ea7f4f", + "7b7f2f6ab907f81f88229cd6b13d91d76eef66073ad7723dd4c667aaa0476320", + "e28712ec0baf11f68477008e0f8f06c7e301f81124b630b0a3ed9451692a8149", + "c7d458c7b211585467fb12d9712dbaaf137f4947235eece15f3c81494bcc6193", + "d7b421e7c5b37697a2e76feacad4ebab65bc2767c0e85fa12e9e296333847051", + "0ccdecead5a695d8d359e61502b86785401c1cfb4746f46480699137a76bb2da", + "ed916d87334cd633f90b1eccc9f011c0da8163146fc375559f75c06dd1bc31fb", + "5eaa5e4bf0471ce13153de87be0e4bf9d1f0ab444f2431c298a4f1fe35c0839d", + "e916fbb8e824dafe5829c1526c03cea4b9560083757220cf765a7827f094bb99", + "1e8bd33c15b3a04aef520d6ee6c222df1d59a2767bc897a456c06b9a9a260880", + "1be9e4ee6804e61e9d526bf6518ecd0c9ad8dd6beb658df5ada68ed40113b7ea", + "aa54d6343cc44674c14157071d75d53e38943f44ac8a41b17dcc55960a95143a", + "820f46340a4d91edfeccd865e2db16b6623270216b38c081de5cace97b9240d4", + "36539c96576628f035b4c288b24a87030b900d81e9df5630a4af8e38cacc71c7", + "ab1cc76a7033cf9ed20dd9897b407b6c92bbd8d4c805bc043060412af0ce44ec", + "c47fc30ac78b1ebf5e2a8613f2ab0e4592bbcd5744198587b95b6c56b0fde706" + ], + "logIndex": 3217726520, + "rootHash": "96e49a79e92a59a748195f0c77e6fb35e46e9a7814b1490fc0f8ff4656178f92", + "treeSize": 3217726668 + }, + "signedEntryTimestamp": "MEUCIQD0lsvspsL4nZBA/HD2Zvd1ZZlMK3SKx4Jk2kHmV86w3QIgFEZrkE1ogGn5tsknK5MSn0jGklECkwtrvwxHK4ItjYA=" + } + }, + "key_id": "seal-ed25519-ca08dd7f42a4be01", + "log_url": "https://rekor.sigstore.dev", + "nonce": "89988bfd536c6beb4bd96160e3e3058419777721ed5c41646aea7e36800d9c9f", + "run_authorization_sha256": "bdfda160138f89a708caa122904af6fec66b29ad41c2d8cb25e458e2da5104d3", + "schema": "openadapt.local-seal-anchor/v1", + "signature_sha256": "69a122f802945951a93984831248d4429caa617b4edba5eb2fe3b4e0756da214", + "statement_sha512": "c8d224763e4cda5af6fe56496f4dcfae83185d3cacc8ff8a15f5d0398ebdf72d47de75e90713960f98715c25dbcc949d2d8ff5ee96009b699d7122946cba7b24" +} diff --git a/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.json b/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.json new file mode 100644 index 000000000..f989607c7 --- /dev/null +++ b/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.json @@ -0,0 +1,21 @@ +{ + "authorizer": "github:abrichr", + "bundle_content_digest": "ec096afa2b614326b00ec3155f256041c19d86f3998761ce9d772cfd911460b6", + "issued_at": "2026-10-20T05:51:31Z", + "nonce": "8691f588a507ca4882bc0cabe9371a706d0c33bf740137f303a80958101ffbc9", + "schema": "openadapt.run-authorization/v1", + "scope": { + "items": [ + "r3", + "r4", + "r5", + "r6" + ], + "profile": "standard", + "reusable": false, + "seal_key_ids": [ + "seal-ed25519-ca08dd7f42a4be01" + ] + }, + "signer_fingerprint": "SHA256:x+1MwCSAsNNHpc+UcIdbktY/Z+/FByyqfhuwiRzeO9A" +} diff --git a/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.json.sig b/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.json.sig new file mode 100644 index 000000000..e020a22c4 --- /dev/null +++ b/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.json.sig @@ -0,0 +1,6 @@ +-----BEGIN SSH SIGNATURE----- +U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgSpJvarWFB6dnsvsB7vyIBthYRT +jGYiuPfC683BqyuC8AAAAbb3BlbmFkYXB0LXJ1bi1hdXRob3JpemF0aW9uAAAAAAAAAAZz +aGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5AAAAQESj95I/VGv80qYZLHYlK1xC47I053k5t7 +9reegcHJ2UnJ+poC8QbjywpC56ZyY+w3Xw3AJ7rAE9BEtRx8GwFg4= +-----END SSH SIGNATURE----- diff --git a/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.tsa.json b/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.tsa.json new file mode 100644 index 000000000..a692a4fd3 --- /dev/null +++ b/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.tsa.json @@ -0,0 +1,10 @@ +{ + "gen_time": "2026-10-20T15:53:12Z", + "imprint_sha256": "a364a2c9b2540aa20dfa12c83142e6818fe7a640a1f34d2436f3cf5a4aa03f3a", + "run_authorization_sha256": "bdfda160138f89a708caa122904af6fec66b29ad41c2d8cb25e458e2da5104d3", + "schema": "openadapt.record-timestamp/v1", + "signature_sha256": "69a122f802945951a93984831248d4429caa617b4edba5eb2fe3b4e0756da214", + "tsa": "https://timestamp.sigstore.dev/api/v1/timestamp", + "tsr_file": "run-authorization.tsr", + "tsr_sha256": "6c1e0c998efa8690d1f1342031c24ce94a7ebf88cc0365e2e97cd908458a4a06" +} diff --git a/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.tsr b/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.tsr new file mode 100644 index 000000000..581794ac0 Binary files /dev/null and b/packages/flow/tests/fixtures/rekor_real/run-authorization/run-authorization.tsr differ diff --git a/packages/flow/tests/fixtures/rekor_real/seal-key.json b/packages/flow/tests/fixtures/rekor_real/seal-key.json new file mode 100644 index 000000000..e0ca6a367 --- /dev/null +++ b/packages/flow/tests/fixtures/rekor_real/seal-key.json @@ -0,0 +1,7 @@ +[ + { + "key_id": "seal-ed25519-ca08dd7f42a4be01", + "public_key": "UQOSlj3iCypSdSwrUYYOcLbS6yy25yM6syjHVnqcHBg=", + "status": "active" + } +] diff --git a/packages/flow/tests/fixtures/rekor_real/seal.anchor.json b/packages/flow/tests/fixtures/rekor_real/seal.anchor.json new file mode 100644 index 000000000..f001f9a49 --- /dev/null +++ b/packages/flow/tests/fixtures/rekor_real/seal.anchor.json @@ -0,0 +1,51 @@ +{ + "entry": { + "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhNTEyIiwidmFsdWUiOiI1NmIyMzhjNDgzZWEzZTgyZTAyN2NkMTAwNDMwN2UzMzljN2Q0YjAxNmFmZjIxN2Y3YjUwNDViMThhMTZhNzVhMWMzODk5NjY4YzA4MGY1M2MyNTg3ZWNjYjk3NjFjOGE3OGM0MzhmZGE4YjJlNTcxMzJlODdmYjNiYTM4MWM3NyJ9fSwic2lnbmF0dXJlIjp7ImNvbnRlbnQiOiJtZ1RWbmFnWGJNUlY2cisvTDI3bHQvWWFUSElmSHFDb04yRUU2bFpzY2s2Y1VVRkd0SzhRK3pqeUM4elhKeTZLVTgxVXZhQ2NkbGRJZ0I3Q2pMRTdDQT09IiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVU52ZDBKUldVUkxNbFozUVhsRlFWVlJUMU5zYWpOcFEzbHdVMlJUZDNKVldWbFBZMHhpVXpaNWVUSTFlVTAyYzNscVNGWnVjV05JUW1jOUNpMHRMUzB0UlU1RUlGQlZRa3hKUXlCTFJWa3RMUzB0TFFvPSJ9fX19", + "integratedTime": 1792511616, + "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d", + "logIndex": 3339635766, + "uuid": "108e9186e8c5677aa7543418cff84038fcf0b8503bf878af6bf8d4f906821840f5ac10e710b45fd0", + "verification": { + "inclusionProof": { + "checkpoint": "rekor.sigstore.dev - 1193050959916656506\n3217731569\nbiQKRWlqyS4H1E+XQ5PFa5baE9Kd1lW7p8G+lIfSeqU=\n\n\u2014 rekor.sigstore.dev wNI9ajBGAiEA20ISQsSDn7Nuey0fi3E2Lex7RYGBhxb/A64t5gN7ZfoCIQC5wdcDm1qDThGpZ0iSqL1PTXg+ijgnmRQ2zcQWqHT3rw==\n", + "hashes": [ + "10dbbfb55020f1d64f0b225023fb50941b60f127291f28e95eba9f587e3337f4", + "47ad4a16cdd51b56416df9342d93f2214e44f417a6a3bbcc7a6023df5546d7d6", + "6eb11ff37c55975e524689fe07aa0916720bfa71277fc93f4b87100ba4c4ff97", + "42ddaaa8c42f56f6d7b3f161b22f4b15dd776ed047619513613a7e4dca557311", + "a8c8d03e3b329a6cf131ab27b827e3be2e848f7e6cca5aa855a2ee0626816c36", + "3c5163882115b80260634e9e2d5d879afda6fb1cb5663e9e14fed33b99a9fdcb", + "dc1086cf79fe48992da87c2a10bb624a47caa43460224453e9090366159f72ce", + "e239ff0ee76a53932dbf944e2425ea1157bde41af58206da2526e71d6750268b", + "e2b57796cc1375a4c7dfec20fa74b010f649efda4a0f6e0507bb2c2fb8f9583c", + "d85ef1b75a8ce7965b02d1b8a2405371366c3cc89b0bbd04d220c9dbd623228c", + "db8524b1f6610642730eacb0471a0aeca405ba750bfbc099f6c48a0d03b11392", + "1dae9e1aae4a6299c11ec217c1bb739017aee8cb939df21d5bd07fd98f9bf75c", + "0484fc459183f5191a1f5f4eff5954c5d06af4285a6f5fe8593937bd78547475", + "d7b421e7c5b37697a2e76feacad4ebab65bc2767c0e85fa12e9e296333847051", + "0ccdecead5a695d8d359e61502b86785401c1cfb4746f46480699137a76bb2da", + "ed916d87334cd633f90b1eccc9f011c0da8163146fc375559f75c06dd1bc31fb", + "5eaa5e4bf0471ce13153de87be0e4bf9d1f0ab444f2431c298a4f1fe35c0839d", + "e916fbb8e824dafe5829c1526c03cea4b9560083757220cf765a7827f094bb99", + "1e8bd33c15b3a04aef520d6ee6c222df1d59a2767bc897a456c06b9a9a260880", + "1be9e4ee6804e61e9d526bf6518ecd0c9ad8dd6beb658df5ada68ed40113b7ea", + "aa54d6343cc44674c14157071d75d53e38943f44ac8a41b17dcc55960a95143a", + "820f46340a4d91edfeccd865e2db16b6623270216b38c081de5cace97b9240d4", + "36539c96576628f035b4c288b24a87030b900d81e9df5630a4af8e38cacc71c7", + "ab1cc76a7033cf9ed20dd9897b407b6c92bbd8d4c805bc043060412af0ce44ec", + "c47fc30ac78b1ebf5e2a8613f2ab0e4592bbcd5744198587b95b6c56b0fde706" + ], + "logIndex": 3217731504, + "rootHash": "6e240a45696ac92e07d44f974393c56b96da13d29dd655bba7c1be9487d27aa5", + "treeSize": 3217731569 + }, + "signedEntryTimestamp": "MEUCIQCsYGXQN3fzdGPh/hzhpx6JO9KtPH2/XtmLHULOTGDheAIgPdBIipG0R7oJsx4gIF5Cs5NeFOjWXAtl7N1gKsET7yw=" + } + }, + "key_id": "seal-ed25519-ca08dd7f42a4be01", + "log_url": "https://rekor.sigstore.dev", + "nonce": "66d6dfeaca36c609b0e1c250317137f0934e230c69a32116ea717f95ea4ed35b", + "schema": "openadapt.local-seal-anchor/v1", + "seal_sha256": "548ba574914dffee8443b54d33a340ee106923e0fe672b41d7756621124d9a4d", + "statement_sha512": "56b238c483ea3e82e027cd1004307e339c7d4b016aff217f7b5045b18a16a75a1c3899668c080f53c2587eccb9761c8a78c438fda8b2e57132e87fb3ba381c77" +} diff --git a/packages/flow/tests/fixtures/rekor_real/seal.json b/packages/flow/tests/fixtures/rekor_real/seal.json new file mode 100644 index 000000000..2ba10a6f4 --- /dev/null +++ b/packages/flow/tests/fixtures/rekor_real/seal.json @@ -0,0 +1,15 @@ +{ + "algorithm": "ed25519", + "authorization_sha256": "bdfda160138f89a708caa122904af6fec66b29ad41c2d8cb25e458e2da5104d3", + "issued_at": "2026-10-20T15:53:26Z", + "issuer": "local", + "key_id": "seal-ed25519-ca08dd7f42a4be01", + "outcome": "VERIFIED", + "public_key": "UQOSlj3iCypSdSwrUYYOcLbS6yy25yM6syjHVnqcHBg=", + "run_id": "engine", + "schema": "openadapt.local-seal/v1", + "scope_item": "r3", + "signature": "2+zCKP4B8srkGvTaKNwisg8g45hGNugy75QoCZg33xycVCU4T/H9RFwhWcXJz1S6osmU0mseO8DiDIwBVDzEAg==", + "subject_kind": "run-report", + "subject_sha256": "ad349a68cc2d60b7c4f36ac1558f6cc39439f69b952c883bd5a4cd14d229a2b1" +} diff --git a/packages/flow/tests/fixtures/rekor_real/seal.tsa.json b/packages/flow/tests/fixtures/rekor_real/seal.tsa.json new file mode 100644 index 000000000..bb3d86da1 --- /dev/null +++ b/packages/flow/tests/fixtures/rekor_real/seal.tsa.json @@ -0,0 +1,9 @@ +{ + "gen_time": "2026-10-20T15:53:35Z", + "imprint_sha256": "548ba574914dffee8443b54d33a340ee106923e0fe672b41d7756621124d9a4d", + "schema": "openadapt.record-timestamp/v1", + "seal_sha256": "548ba574914dffee8443b54d33a340ee106923e0fe672b41d7756621124d9a4d", + "tsa": "https://timestamp.sigstore.dev/api/v1/timestamp", + "tsr_file": "seal.tsr", + "tsr_sha256": "edf5322f93f772e9de3ba2667e41daeb27584f5e104b5df07661af3633228792" +} diff --git a/packages/flow/tests/fixtures/rekor_real/seal.tsr b/packages/flow/tests/fixtures/rekor_real/seal.tsr new file mode 100644 index 000000000..289fc2d9c Binary files /dev/null and b/packages/flow/tests/fixtures/rekor_real/seal.tsr differ diff --git a/packages/flow/tests/test_rekor_real_fixture.py b/packages/flow/tests/test_rekor_real_fixture.py new file mode 100644 index 000000000..ffc35d308 --- /dev/null +++ b/packages/flow/tests/test_rekor_real_fixture.py @@ -0,0 +1,132 @@ +"""Real public Sigstore records, verified offline with the shipped trust roots. + +``tests/fixtures/rekor_real`` holds the landing demo's referral r3 Seal +(synthetic patient, redacted report) and the run authorization it was +sealed under, as anchored in the public Rekor log (rekor.sigstore.dev) and +timestamped by the Sigstore TSA on 2026-10-20. Rekor log indexes: Seal +3339635766, authorization 3339630782. + +Nothing here touches the network: these tests check that real Rekor entries +(Ed25519ph ``hashedrekord``) and real Sigstore TSA tokens verify against the +Rekor key and TSA root built into OpenAdapt, and that a change to any of +them is refused. +""" + +from __future__ import annotations + +import copy +import json +import urllib.request +from pathlib import Path + +import pytest +from openadapt_types.seal import parse_key_registry + +from openadapt_flow import ssh_sig +from openadapt_flow.offline_seal import LocalSealV1, seal_sha256, verify_local_seal +from openadapt_flow.run_authorization import NAMESPACE, verify, verify_anchor +from openadapt_flow.seal_anchor import verify_anchor as verify_seal_anchor + +FIXTURES = Path(__file__).parent / "fixtures" / "rekor_real" +AUTH = FIXTURES / "run-authorization" +# The founder's key as github.com/abrichr.keys listed it when the fixture was made. +FOUNDER = ( + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEqSb2q1hQenZ7L7Ae78iAbYWEU4xmIrj3wuvNwasrgv" +) + + +@pytest.fixture(autouse=True) +def offline(monkeypatch): + def refuse(*args, **kwargs): + raise AssertionError("these checks must not touch the network") + + monkeypatch.setattr(urllib.request, "urlopen", refuse) + + +def _json(path: Path): + return json.loads(path.read_text(encoding="utf-8")) + + +def _registry(): + return parse_key_registry(_json(FIXTURES / "seal-key.json")) + + +def test_the_real_seal_and_its_rekor_entry_verify_offline(): + seal = LocalSealV1.model_validate(_json(FIXTURES / "seal.json")).wire() + registry = _registry() + assert verify_local_seal(seal, seal["subject_sha256"], registry).ok + anchor = _json(FIXTURES / "seal.anchor.json") + assert anchor["entry"]["logIndex"] == 3339635766 + raw = __import__("base64").b64decode(registry[0].public_key) + result = verify_seal_anchor(seal, anchor, raw) # the built-in public Rekor key + assert result.ok, result.reason + assert result.log_index == 3339635766 + + +@pytest.mark.parametrize( + "edit", + [ + lambda a: a["entry"]["verification"]["inclusionProof"]["hashes"].__setitem__( + 0, "00" * 32 + ), + lambda a: a["entry"].__setitem__( + "integratedTime", a["entry"]["integratedTime"] + 1 + ), + lambda a: a.__setitem__("nonce", "00" * 32), + ], +) +def test_a_changed_real_entry_is_refused(edit): + seal = LocalSealV1.model_validate(_json(FIXTURES / "seal.json")).wire() + raw = __import__("base64").b64decode(_registry()[0].public_key) + anchor = copy.deepcopy(_json(FIXTURES / "seal.anchor.json")) + edit(anchor) + assert not verify_seal_anchor(seal, anchor, raw).ok + + +def test_the_real_tsa_tokens_verify_against_the_shipped_sigstore_root(): + pytest.importorskip("asn1crypto") + from openadapt_flow.seal_timestamp import ( + authorization_fields, + seal_fields, + verify_record_timestamp, + ) + + stamp = verify_record_timestamp( + seal_fields(FIXTURES / "seal.json"), FIXTURES / "seal.tsa.json" + ) + assert stamp.ok, stamp.reason + assert stamp.imprint_sha256 == seal_sha256(_json(FIXTURES / "seal.json")) + auth_stamp = verify_record_timestamp( + authorization_fields(AUTH / "run-authorization.json"), + AUTH / "run-authorization.tsa.json", + ) + assert auth_stamp.ok, auth_stamp.reason + + +def test_the_real_authorization_and_its_anchor_verify_offline(tmp_path): + pinned = tmp_path / "allowed_signers" + founder_raw = ssh_sig.parse_key_line(FOUNDER) + pinned.write_text( + ssh_sig.allowed_signers_line("github:abrichr", NAMESPACE, founder_raw) + "\n" + ) + result = verify( + AUTH, allowed_signers=pinned, registry=_registry(), require_anchor=True + ) + assert result.ok, (result.reason, result.detail) + assert result.identity_verified + assert ( + result.signer_fingerprint + == "SHA256:x+1MwCSAsNNHpc+UcIdbktY/Z+/FByyqfhuwiRzeO9A" + ) + assert result.anchor.log_index == 3339630782 + # The Seal references exactly this authorization. + assert _json(FIXTURES / "seal.json")["authorization_sha256"] == result.sha256 + # Without a pinned key the same files verify, but the identity is self-asserted. + offline = verify(AUTH) + assert offline.ok and not offline.identity_verified + + +def test_the_real_authorization_anchor_is_refused_for_another_record(): + anchor_file = AUTH / "run-authorization.anchor.json" + result = verify_anchor("ab" * 32, "cd" * 32, anchor_file, _registry()) + assert result.reason == "anchor_mismatch" diff --git a/packages/flow/tests/test_seal_timestamp.py b/packages/flow/tests/test_seal_timestamp.py index 10db77398..e1e04c75f 100644 --- a/packages/flow/tests/test_seal_timestamp.py +++ b/packages/flow/tests/test_seal_timestamp.py @@ -6,7 +6,6 @@ from __future__ import annotations -import base64 import hashlib import json from pathlib import Path @@ -51,6 +50,12 @@ def test_a_seal_gets_its_own_token_next_to_it(tmp_path, tsa): assert record["schema"] == "openadapt.record-timestamp/v1" assert record["imprint_sha256"] == fields["seal_sha256"] # only this was sent assert record["gen_time"] + # The token is stored in its standard binary form beside the JSON. + tsr = seal.with_name("seal.tsr") + assert record["tsr_file"] == "seal.tsr" and tsr.is_file() + assert record["tsr_sha256"] == hashlib.sha256(tsr.read_bytes()).hexdigest() + assert "token" not in record + assert tsr.read_bytes()[:1] == b"\x30" # DER SEQUENCE result = verify_record_timestamp(fields, out, [tsa.certificate]) assert result.ok and result.imprint_sha256 == fields["seal_sha256"] # Idempotent: a second call returns the stored token without asking again. @@ -62,7 +67,7 @@ def timestamp(self, digest): raise AssertionError("must not be called") again = timestamp_record(fields, out, Refuses(), trusted=[tsa.certificate], env={}) - assert again["token"] == record["token"] + assert again["tsr_sha256"] == record["tsr_sha256"] def test_the_default_pin_is_sigstore_so_a_local_token_is_refused(tmp_path, tsa): @@ -87,12 +92,34 @@ def test_changed_seal_tampered_token_and_wrong_pin_are_refused(tmp_path, tsa): assert not verify_record_timestamp( fields, out, [LocalTsa.generate().certificate] ).ok - data = json.loads(out.read_text()) - token = bytearray(base64.b64decode(data["token"])) + tsr = seal.with_name("seal.tsr") + original = tsr.read_bytes() + token = bytearray(original) token[-5] ^= 0xFF - data["token"] = base64.b64encode(bytes(token)).decode() + tsr.write_bytes(bytes(token)) + # Changed bytes no longer match the SHA-256 the JSON names. + assert ( + verify_record_timestamp(fields, out, [tsa.certificate]).reason + == "timestamp_token_mismatch" + ) + # And a JSON rewritten to match a tampered token fails the signature check. + data = json.loads(out.read_text()) + data["tsr_sha256"] = hashlib.sha256(bytes(token)).hexdigest() out.write_text(json.dumps(data)) assert not verify_record_timestamp(fields, out, [tsa.certificate]).ok + tsr.write_bytes(original) + for bad in ("../seal.tsr", "/etc/passwd", "seal.json", ""): + out.write_text(json.dumps(dict(data, tsr_file=bad))) + assert ( + verify_record_timestamp(fields, out, [tsa.certificate]).reason + == "timestamp_malformed" + ), bad + tsr.unlink() + out.write_text(json.dumps(dict(data, tsr_file="seal.tsr"))) + assert ( + verify_record_timestamp(fields, out, [tsa.certificate]).reason + == "timestamp_token_missing" + ) out.write_text('{"schema": "openadapt.record-timestamp/v1", "schema": "x"}') assert ( verify_record_timestamp(fields, out, [tsa.certificate]).reason