diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ecac147..71b28e66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ ### Added +- The checked Echo Edict provider conformance corpus now declares twelve + reviewed executable obligations: exactly six owned by the isolated host + executor and six by the package executor, with one accepted, nine rejected, + and two refused dispositions. Each declaration names its crossing, stimulus, + required disposition, and outcome contract, but embeds no pass flag, result, + evidence pointer, implementation command, or runtime authority. The two + exact-set executors separately produce provider-conformance evidence for + baseline package parity, admission and binding failures, typed semantic + refusals, and verifier disagreements. Corpus declarations and their executed + provider evidence remain distinct from Echo installation, execution, + observation, and runtime receipts. - `TrustedRuntimeHost` can now admit a witnessed installed-contract submission without accepting caller-manufactured ticket authority. Echo derives a domain-separated admission digest from its witnessed submission record and @@ -96,7 +107,7 @@ dependency source paths to `/cargo`, and atomically promotes only distinct candidates matching a reviewed repository digest. The promoted 189,668-byte component has SHA-256 - `9b5ecf1c87a4a98ad3d7381d85e3625649a4f9d62f80f74b2aca6ace26be14af`. + `f2063b66798fbb1c2b27c3af56e4b78184ffc22c9ed9c7a32c483d05b8c1d382`. Other-host builds are structural and semantic witnesses rather than cross-host compiler-identity claims. The publication-enabled, archive-self-contained `echo-edict-provider-lowerer` source crate carries @@ -152,7 +163,7 @@ separating malformed artifacts from well-formed unsupported semantics, and one admitted diagnostic-ABI identity now binds both the target profile and every emitted report. The 189,922-byte checked component has SHA-256 - `4f99c07f1c6d682405945fbb3e36e5537b94c4a01bd1a4ec7f02ef8e9911249a` + `632cc5134861c0b31ccc9ca77d4a09fe757094964369d057b62ca6ba6ad38ad7` and reproduces byte-for-byte across independently provisioned designated `linux/amd64` builders. The isolated pinned Edict host preflights the exact request artifacts and declared output schema, invokes that checked component, diff --git a/crates/echo-edict-provider-lowerer/README.md b/crates/echo-edict-provider-lowerer/README.md index f9a52a1d..4b831217 100644 --- a/crates/echo-edict-provider-lowerer/README.md +++ b/crates/echo-edict-provider-lowerer/README.md @@ -101,7 +101,7 @@ remain a separate bounded observer/optic path and must never be represented as synthetic mutations. The refreshed 189,668-byte checked lowerer component has SHA-256 -`9b5ecf1c87a4a98ad3d7381d85e3625649a4f9d62f80f74b2aca6ace26be14af` and has +`f2063b66798fbb1c2b27c3af56e4b78184ffc22c9ed9c7a32c483d05b8c1d382` and has crossed the reproducible promotion boundary. The pinned Edict host admits its generated envelope under the owning `generated-artifact` CDDL root, and the isolated host fixture exercises the exact helper binding, typed codecs, EINT diff --git a/crates/echo-edict-provider-lowerer/resources/authority-facts.echo-dpo.cbor b/crates/echo-edict-provider-lowerer/resources/authority-facts.echo-dpo.cbor index ef4787da..610eaf27 100644 --- a/crates/echo-edict-provider-lowerer/resources/authority-facts.echo-dpo.cbor +++ b/crates/echo-edict-provider-lowerer/resources/authority-facts.echo-dpo.cbor @@ -1 +1,2 @@ -¥fsource£dkindmtargetProfilefdigest‚fsha256X ­á„?K=,±iß?œ sˆ®&»6LÈqÍAžjcoordinatejecho.dpo@1gbudgets japiVersionxedict.authority-facts/v1qoperationProfiles¡kp.effectful¢dcorexcontinuum.profile.write/v1sallowedWriteClasses¡greplaceöreffectWriteClasses¡ntarget.replacegreplace \ No newline at end of file +¥fsource£dkindmtargetProfilefdigest‚fsha256X îß{ÛöþKj@6i_AÃÜ +\i-'âÉÔÀÅê´/cÉjcoordinatejecho.dpo@1gbudgets japiVersionxedict.authority-facts/v1qoperationProfiles¡kp.effectful¢dcorexcontinuum.profile.write/v1sallowedWriteClasses¡greplaceöreffectWriteClasses¡ntarget.replacegreplace \ No newline at end of file diff --git a/crates/echo-edict-provider-lowerer/resources/authority-facts.echo-lawpack.cbor b/crates/echo-edict-provider-lowerer/resources/authority-facts.echo-lawpack.cbor index bba8cf44..e91698fb 100644 Binary files a/crates/echo-edict-provider-lowerer/resources/authority-facts.echo-lawpack.cbor and b/crates/echo-edict-provider-lowerer/resources/authority-facts.echo-lawpack.cbor differ diff --git a/crates/echo-edict-provider-lowerer/resources/lawpack.echo-dpo.cbor b/crates/echo-edict-provider-lowerer/resources/lawpack.echo-dpo.cbor index af0722fb..879f21c2 100644 Binary files a/crates/echo-edict-provider-lowerer/resources/lawpack.echo-dpo.cbor and b/crates/echo-edict-provider-lowerer/resources/lawpack.echo-dpo.cbor differ diff --git a/crates/echo-edict-provider-lowerer/resources/target-profile.echo-dpo.cbor b/crates/echo-edict-provider-lowerer/resources/target-profile.echo-dpo.cbor index 28493267..e4b31526 100644 Binary files a/crates/echo-edict-provider-lowerer/resources/target-profile.echo-dpo.cbor and b/crates/echo-edict-provider-lowerer/resources/target-profile.echo-dpo.cbor differ diff --git a/crates/echo-edict-provider-lowerer/src/lib.rs b/crates/echo-edict-provider-lowerer/src/lib.rs index b64699c2..98de8dc0 100644 --- a/crates/echo-edict-provider-lowerer/src/lib.rs +++ b/crates/echo-edict-provider-lowerer/src/lib.rs @@ -824,7 +824,7 @@ pub mod echo_dpo { pub const PROVIDER_SCHEMA_COORDINATE: &str = "echo.provider-artifacts.cddl@1"; /// Raw SHA-256 of the exact self-contained provider CDDL bytes. pub const PROVIDER_SCHEMA_SHA256_HEX: &str = - "e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c"; + "faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde"; /// Exact generated-artifact profile coordinate owning operation schemas. pub const GENERATED_ARTIFACT_PROFILE: &str = "echo.dpo.registration/v1"; /// Digest-framing domain for the generated-artifact profile. @@ -861,7 +861,7 @@ pub mod echo_dpo { const MUTATION_RULE_NAME: &str = concat!( "cmd/contract/", - "e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c", + "faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde", "/3389142194/a.b@1.t" ); const PROVIDER_OPERATIONS: [ProviderOperationV1<'static>; 1] = [ProviderOperationV1 { diff --git a/crates/echo-edict-provider-lowerer/tests/fixtures/generated_echo_dpo.rs b/crates/echo-edict-provider-lowerer/tests/fixtures/generated_echo_dpo.rs index f4abc28c..a9a6b8f9 100644 --- a/crates/echo-edict-provider-lowerer/tests/fixtures/generated_echo_dpo.rs +++ b/crates/echo-edict-provider-lowerer/tests/fixtures/generated_echo_dpo.rs @@ -50,13 +50,13 @@ pub mod echo_dpo { /// Digest-framing domain for the complete Target IR artifact envelope. pub const TARGET_IR_DIGEST_DOMAIN: &str = "edict.target-ir.artifact/v1"; /// Exact domain-framed identity of the emitted Target IR artifact. - pub const TARGET_IR_DIGEST: &str = "sha256:2244345f046448c7b519ade05a167137659361ed144b46315ea32dabfbad85fc"; + pub const TARGET_IR_DIGEST: &str = "sha256:d4689abc5c2275ea9c7e1b743197a0d8b4625091632e8f5162eba9ff88d568ad"; /// Exact target-profile coordinate. pub const TARGET_PROFILE_COORDINATE: &str = "echo.dpo@1"; /// Digest-framing domain for the target-profile artifact. pub const TARGET_PROFILE_DIGEST_DOMAIN: &str = "edict.target-profile/v1"; /// Exact domain-framed identity of the target profile. - pub const TARGET_PROFILE_DIGEST: &str = "sha256:ad7f10e1843f4b3d2c08b11d69df103f9c0b1b7388ae26bb364cc87106cd419e"; + pub const TARGET_PROFILE_DIGEST: &str = "sha256:eedf7bdbf6fe4b6a4036695f41c3dc0a5c692d27e206c9d4c0c5eab41e2f63c9"; /// Semantic profile for Echo contract bundles; not a bundle occurrence. pub const TARGET_BUNDLE_PROFILE_COORDINATE: &str = "echo.dpo.bundle/v1"; /// Digest-framing domain for the target-bundle profile artifact. @@ -71,7 +71,7 @@ pub mod echo_dpo { pub const PROVIDER_SCHEMA_COORDINATE: &str = "echo.provider-artifacts.cddl@1"; /// Raw SHA-256 of the exact self-contained provider CDDL bytes. pub const PROVIDER_SCHEMA_SHA256_HEX: &str = - "e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c"; + "faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde"; /// Exact generated-artifact profile coordinate owning operation schemas. pub const GENERATED_ARTIFACT_PROFILE: &str = "echo.dpo.registration/v1"; /// Digest-framing domain for the generated-artifact profile. @@ -108,7 +108,7 @@ pub mod echo_dpo { const MUTATION_RULE_NAME: &str = concat!( "cmd/contract/", - "e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c", + "faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde", "/3389142194/a.b@1.t" ); const PROVIDER_OPERATIONS: [ProviderOperationV1<'static>; 1] = [ProviderOperationV1 { diff --git a/crates/echo-edict-provider-lowerer/tests/lowerer_contract.rs b/crates/echo-edict-provider-lowerer/tests/lowerer_contract.rs index 9a5b7999..824f5f7a 100644 --- a/crates/echo-edict-provider-lowerer/tests/lowerer_contract.rs +++ b/crates/echo-edict-provider-lowerer/tests/lowerer_contract.rs @@ -45,7 +45,7 @@ const REVIEW_MEDIA_TYPE: &str = "application/json"; const GENERATED_SOURCE_PATH: &str = "generated/echo_dpo.rs"; const REVIEW_PATH: &str = "review/echo_dpo.json"; const EXPECTED_PROVIDER_SCHEMA_SHA256_HEX: &str = - "e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c"; + "faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde"; const EXPECTED_OPERATION_ID_LAW: &str = "echo.semantic-operation-id.fnv1-32/v1"; const EXPECTED_OPERATION_ID: u32 = 3_389_142_194; @@ -678,7 +678,7 @@ fn reviewed_edict_fixture_has_exact_builtin_wrapper_parity() { assert_eq!( digest_canonical_value_v1(OUTER_TARGET_IR_DOMAIN, &output_value) .expect("oracle-parity output has a domain-framed digest"), - "sha256:2244345f046448c7b519ade05a167137659361ed144b46315ea32dabfbad85fc" + "sha256:d4689abc5c2275ea9c7e1b743197a0d8b4625091632e8f5162eba9ff88d568ad" ); } diff --git a/crates/echo-edict-provider-verifier/README.md b/crates/echo-edict-provider-verifier/README.md index 32e4199b..cd8c9f72 100644 --- a/crates/echo-edict-provider-verifier/README.md +++ b/crates/echo-edict-provider-verifier/README.md @@ -23,7 +23,7 @@ The `wasm32` guest adapter vendors Edict's exact frozen `edict:target-provider/verifier@1.0.0` WIT world and performs only exhaustive transport-to-model conversion. Its reproducibly built 189,922-byte checked component has SHA-256 -`4f99c07f1c6d682405945fbb3e36e5537b94c4a01bd1a4ec7f02ef8e9911249a`. +`632cc5134861c0b31ccc9ca77d4a09fe757094964369d057b62ca6ba6ad38ad7`. Component identity and admitted host replay remain separate propositions: the pinned Edict host preflights the request artifacts and declared output schema, invokes the checked component, then admits and manifests each returned accepted diff --git a/crates/echo-edict-provider-verifier/resources/authority-facts.echo-dpo.cbor b/crates/echo-edict-provider-verifier/resources/authority-facts.echo-dpo.cbor index ef4787da..610eaf27 100644 --- a/crates/echo-edict-provider-verifier/resources/authority-facts.echo-dpo.cbor +++ b/crates/echo-edict-provider-verifier/resources/authority-facts.echo-dpo.cbor @@ -1 +1,2 @@ -¥fsource£dkindmtargetProfilefdigest‚fsha256X ­á„?K=,±iß?œ sˆ®&»6LÈqÍAžjcoordinatejecho.dpo@1gbudgets japiVersionxedict.authority-facts/v1qoperationProfiles¡kp.effectful¢dcorexcontinuum.profile.write/v1sallowedWriteClasses¡greplaceöreffectWriteClasses¡ntarget.replacegreplace \ No newline at end of file +¥fsource£dkindmtargetProfilefdigest‚fsha256X îß{ÛöþKj@6i_AÃÜ +\i-'âÉÔÀÅê´/cÉjcoordinatejecho.dpo@1gbudgets japiVersionxedict.authority-facts/v1qoperationProfiles¡kp.effectful¢dcorexcontinuum.profile.write/v1sallowedWriteClasses¡greplaceöreffectWriteClasses¡ntarget.replacegreplace \ No newline at end of file diff --git a/crates/echo-edict-provider-verifier/resources/authority-facts.echo-lawpack.cbor b/crates/echo-edict-provider-verifier/resources/authority-facts.echo-lawpack.cbor index bba8cf44..e91698fb 100644 Binary files a/crates/echo-edict-provider-verifier/resources/authority-facts.echo-lawpack.cbor and b/crates/echo-edict-provider-verifier/resources/authority-facts.echo-lawpack.cbor differ diff --git a/crates/echo-edict-provider-verifier/resources/lawpack.echo-dpo.cbor b/crates/echo-edict-provider-verifier/resources/lawpack.echo-dpo.cbor index af0722fb..879f21c2 100644 Binary files a/crates/echo-edict-provider-verifier/resources/lawpack.echo-dpo.cbor and b/crates/echo-edict-provider-verifier/resources/lawpack.echo-dpo.cbor differ diff --git a/crates/echo-edict-provider-verifier/resources/target-profile.echo-dpo.cbor b/crates/echo-edict-provider-verifier/resources/target-profile.echo-dpo.cbor index 28493267..e4b31526 100644 Binary files a/crates/echo-edict-provider-verifier/resources/target-profile.echo-dpo.cbor and b/crates/echo-edict-provider-verifier/resources/target-profile.echo-dpo.cbor differ diff --git a/crates/echo-edict-provider-verifier/src/semantic_resources.rs b/crates/echo-edict-provider-verifier/src/semantic_resources.rs index 223a7e18..8a623803 100644 --- a/crates/echo-edict-provider-verifier/src/semantic_resources.rs +++ b/crates/echo-edict-provider-verifier/src/semantic_resources.rs @@ -13,13 +13,13 @@ const PROFILE: ResourceSpec = ResourceSpec { coordinate: "echo.dpo@1", domain: "edict.target-profile/v1", bytes: include_bytes!("../resources/target-profile.echo-dpo.cbor"), - framed_sha256: "ad7f10e1843f4b3d2c08b11d69df103f9c0b1b7388ae26bb364cc87106cd419e", + framed_sha256: "eedf7bdbf6fe4b6a4036695f41c3dc0a5c692d27e206c9d4c0c5eab41e2f63c9", }; const LAWPACK: ResourceSpec = ResourceSpec { coordinate: "echo.dpo-lawpack@1", domain: "edict.lawpack/v1", bytes: include_bytes!("../resources/lawpack.echo-dpo.cbor"), - framed_sha256: "2a1631ae5fe2e11d09ccdfb94e3498f3236a3d615ee217e6cd5843efcd284987", + framed_sha256: "b009609fa3fd0b12c53b3da22bc9d40839b253808aed0520d3b37a909ea73cfa", }; const GENERATED_PROFILE: ResourceSpec = ResourceSpec { coordinate: "echo.dpo.registration/v1", @@ -1583,11 +1583,11 @@ mod tests { let expected_raw = [ ( PROFILE, - "cb5104802031e06d2e2802efe14ad23877dba2756684a5509c06a8de7bb9ec85", + "a2ecfe500dcedb25b22129a412a7c83379fc265d9f04792355425ff80b52a2ba", ), ( LAWPACK, - "679b090774088b46413a4697a646f10c3627d9f7f698380237db72e0b11739a1", + "2539a9856295db8545db10d1001b6b1697e40bff0ea07b45afd33255d45d4269", ), ( GENERATED_PROFILE, diff --git a/crates/echo-edict-provider-verifier/tests/verifier_contract.rs b/crates/echo-edict-provider-verifier/tests/verifier_contract.rs index 45ec57e8..ef5b93d0 100644 --- a/crates/echo-edict-provider-verifier/tests/verifier_contract.rs +++ b/crates/echo-edict-provider-verifier/tests/verifier_contract.rs @@ -408,19 +408,19 @@ fn packaged_semantic_resource_bytes_are_pinned() { let resources = [ ( TARGET_PROFILE, - "cb5104802031e06d2e2802efe14ad23877dba2756684a5509c06a8de7bb9ec85", + "a2ecfe500dcedb25b22129a412a7c83379fc265d9f04792355425ff80b52a2ba", ), ( LAWPACK, - "679b090774088b46413a4697a646f10c3627d9f7f698380237db72e0b11739a1", + "2539a9856295db8545db10d1001b6b1697e40bff0ea07b45afd33255d45d4269", ), ( TARGET_AUTHORITY, - "e4984d3ce0d9195f23ee30c2d36b46814d0872e294266ac30959a5a95b1f5f7e", + "e4ecd21b5b4d7c97c66f9aa9ef55794fd8610f58a6ccb5e37f411576b8247ca9", ), ( LAWPACK_AUTHORITY, - "022658a64fa8f693388e3f21354ebe3125eba0ea1fedf140b7c87f0c76cf08dc", + "893af4f37e2821525cc609e5740e7e95ae0e1795ca2444d2267f438a69d2283f", ), ]; diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm index 5f536455..6ca75c9e 100644 Binary files a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm and b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm differ diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm index 5e1224f6..86b08807 100644 Binary files a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm and b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm differ diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json index 2c481917..38ed92e9 100644 --- a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4984d3ce0d9195f23ee30c2d36b46814d0872e294266ac30959a5a95b1f5f7e"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:022658a64fa8f693388e3f21354ebe3125eba0ea1fedf140b7c87f0c76cf08dc"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:679b090774088b46413a4697a646f10c3627d9f7f698380237db72e0b11739a1"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:cb5104802031e06d2e2802efe14ad23877dba2756684a5509c06a8de7bb9ec85"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4ecd21b5b4d7c97c66f9aa9ef55794fd8610f58a6ccb5e37f411576b8247ca9"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:893af4f37e2821525cc609e5740e7e95ae0e1795ca2444d2267f438a69d2283f"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:2539a9856295db8545db10d1001b6b1697e40bff0ea07b45afd33255d45d4269"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:a2ecfe500dcedb25b22129a412a7c83379fc265d9f04792355425ff80b52a2ba"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json index a298a191..9a6ef4ed 100644 --- a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/evidence/review.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4984d3ce0d9195f23ee30c2d36b46814d0872e294266ac30959a5a95b1f5f7e"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:022658a64fa8f693388e3f21354ebe3125eba0ea1fedf140b7c87f0c76cf08dc"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:679b090774088b46413a4697a646f10c3627d9f7f698380237db72e0b11739a1"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:cb5104802031e06d2e2802efe14ad23877dba2756684a5509c06a8de7bb9ec85"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:2874523930a963f81204df9c39aca6f9b62edbd45e5512ef6903346f7efa7c3e","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4ecd21b5b4d7c97c66f9aa9ef55794fd8610f58a6ccb5e37f411576b8247ca9"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:893af4f37e2821525cc609e5740e7e95ae0e1795ca2444d2267f438a69d2283f"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:2539a9856295db8545db10d1001b6b1697e40bff0ea07b45afd33255d45d4269"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:a2ecfe500dcedb25b22129a412a7c83379fc265d9f04792355425ff80b52a2ba"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:614ad15a761639f61f693ac1202d770abb3156c4961b47ca30d27a2441a87b0b","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor index ef4787da..610eaf27 100644 --- a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor @@ -1 +1,2 @@ -¥fsource£dkindmtargetProfilefdigest‚fsha256X ­á„?K=,±iß?œ sˆ®&»6LÈqÍAžjcoordinatejecho.dpo@1gbudgets japiVersionxedict.authority-facts/v1qoperationProfiles¡kp.effectful¢dcorexcontinuum.profile.write/v1sallowedWriteClasses¡greplaceöreffectWriteClasses¡ntarget.replacegreplace \ No newline at end of file +¥fsource£dkindmtargetProfilefdigest‚fsha256X îß{ÛöþKj@6i_AÃÜ +\i-'âÉÔÀÅê´/cÉjcoordinatejecho.dpo@1gbudgets japiVersionxedict.authority-facts/v1qoperationProfiles¡kp.effectful¢dcorexcontinuum.profile.write/v1sallowedWriteClasses¡greplaceöreffectWriteClasses¡ntarget.replacegreplace \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor index bba8cf44..e91698fb 100644 Binary files a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor and b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor differ diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor index af0722fb..879f21c2 100644 Binary files a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor and b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor differ diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl index 380abbe7..58e8577c 100644 --- a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl @@ -837,7 +837,35 @@ echo-provider-conformance-corpus = { operations: { * tstr => null }, capabilities: { * tstr => null }, semanticEffects: { * tstr => null }, - cases: [], + cases: { 1* tstr => echo-provider-conformance-case }, +} + +echo-provider-conformance-case = { + crossing: "pipeline" / "request-admission" / "component-preflight" / + "helper-binding" / + "host-output-admission" / "verification" / + "schema-admission" / "lowering", + stimulus: "baseline" / "ambient-capabilities-denied" / + "artifact-bytes-changed" / "component-bytes-changed" / + "bundle-identity-changed" / "noncanonical-cbor-output" / + "unsupported-output-role-requested" / "schema-bytes-changed" / + "exact-source-bytes-changed" / "unsupported-core-semantics" / + "obstruction-arm-removed" / "target-intrinsic-changed", + requiredOutcome: { + disposition: "accepted" / "rejected" / "refused", + contract: "completed-package-parity" / + "ambient-capability-preflight-denied" / + "noncanonical-target-ir-output-denied" / + "unsupported-core-semantics-refused" / + "unsupported-verifier-output-role-refused" / + "target-intrinsic-mismatch-rejected" / + "obstruction-relation-mismatch-rejected" / + "artifact-digest-mismatch-rejected" / + "schema-artifact-digest-mismatch-rejected" / + "component-digest-mismatch-rejected" / + "target-ir-helper-binding-mismatch-rejected" / + "baseline-release-binding-mismatch-rejected", + }, } echo-provider-lawpack-compatibility = { diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor index 28493267..e4b31526 100644 Binary files a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor and b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor differ diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor index 4464f53c..c1e919e1 100644 --- a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor @@ -1 +1 @@ -¦ecases€eclasskdeclarativejapiVersionx)echo.edict-provider.conformance-corpus/v1joperations¡ga.b@1.tölcapabilities¡recho.dpo@1.replaceöosemanticEffects¡ntarget.replaceö \ No newline at end of file +¦ecases¬mschema-tamper£hcrossingpschema-admissionhstimulustschema-bytes-changedorequiredOutcome¢hcontractx(schema-artifact-digest-mismatch-rejectedkdispositionhrejectednpackage-parity£hcrossinghpipelinehstimulushbaselineorequiredOutcome¢hcontractxcompleted-package-paritykdispositionhacceptedoartifact-tamper£hcrossingqrequest-admissionhstimulusvartifact-bytes-changedorequiredOutcome¢hcontractx!artifact-digest-mismatch-rejectedkdispositionhrejectedowrong-intrinsic£hcrossinglverificationhstimulusxtarget-intrinsic-changedorequiredOutcome¢hcontractx"target-intrinsic-mismatch-rejectedkdispositionhrejectedpcomponent-tamper£hcrossingscomponent-preflighthstimuluswcomponent-bytes-changedorequiredOutcome¢hcontractx"component-digest-mismatch-rejectedkdispositionhrejectedpoutput-overclaim£hcrossinglverificationhstimulusx!unsupported-output-role-requestedorequiredOutcome¢hcontractx(unsupported-verifier-output-role-refusedkdispositiongrefusedsdropped-obstruction£hcrossinglverificationhstimuluswobstruction-arm-removedorequiredOutcome¢hcontractx&obstruction-relation-mismatch-rejectedkdispositionhrejectedsnoncanonical-output£hcrossinguhost-output-admissionhstimulusxnoncanonical-cbor-outputorequiredOutcome¢hcontractx$noncanonical-target-ir-output-deniedkdispositionhrejecteduunsupported-semantics£hcrossinghloweringhstimulusxunsupported-core-semanticsorequiredOutcome¢hcontractx"unsupported-core-semantics-refusedkdispositiongrefusedxhelper-identity-mismatch£hcrossingnhelper-bindinghstimuluswbundle-identity-changedorequiredOutcome¢hcontractx*target-ir-helper-binding-mismatch-rejectedkdispositionhrejectedxsource-occurrence-change£hcrossingnhelper-bindinghstimulusxexact-source-bytes-changedorequiredOutcome¢hcontractx*baseline-release-binding-mismatch-rejectedkdispositionhrejectedxambient-capability-denial£hcrossingscomponent-preflighthstimulusxambient-capabilities-deniedorequiredOutcome¢hcontractx#ambient-capability-preflight-deniedkdispositionhrejectedeclasskdeclarativejapiVersionx)echo.edict-provider.conformance-corpus/v1joperations¡ga.b@1.tölcapabilities¡recho.dpo@1.replaceöosemanticEffects¡ntarget.replaceö \ No newline at end of file diff --git a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json index 8782587e..23a5510d 100644 --- a/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json +++ b/crates/echo-wesley-gen/assets/v1/edict-provider/package/v1/provider-manifest.echo.json @@ -3,7 +3,7 @@ "providerAbi": "edict:target-provider@1.0.0", "provider": { "coordinate": "echo.edict-provider@1", - "digest": "sha256:6d99fc4b4a56268b053226f17dfaa946bec6a3328219393c21fdb3398db6a925" + "digest": "sha256:fc00dd73a26bbd6699668ddb3ba1e3db9beb9bd7655e270824019d1e6e33f712" }, "artifacts": [ { @@ -11,7 +11,7 @@ "artifactKind": "authorityFacts", "resource": { "coordinate": "echo.dpo-authority-facts@1", - "digest": "sha256:724d9f0cf79d2f3815902b1aba8d811add4c00f45c93a7c8c6b05ff2f7ed4c29" + "digest": "sha256:e1fa56a4d476d80ec3260792e9a85f13f92f7c73aef2a18c3cda9cdd4d901527" }, "source": { "kind": "generated", @@ -21,7 +21,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -30,7 +30,7 @@ "artifactKind": "authorityFacts", "resource": { "coordinate": "echo.dpo-lawpack-authority-facts@1", - "digest": "sha256:147a07c38d257f6c949ad3890f3071049b79771b268d2e0d0fb1ad846e235209" + "digest": "sha256:a7e3cc3e2a088b613640ebd76694cd9c4ff5125a6ad7fa6574abe55caf38401b" }, "source": { "kind": "generated", @@ -40,7 +40,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -59,7 +59,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -68,7 +68,7 @@ "artifactKind": "lawpack", "resource": { "coordinate": "echo.dpo-lawpack@1", - "digest": "sha256:2a1631ae5fe2e11d09ccdfb94e3498f3236a3d615ee217e6cd5843efcd284987" + "digest": "sha256:b009609fa3fd0b12c53b3da22bc9d40839b253808aed0520d3b37a909ea73cfa" }, "source": { "kind": "generated", @@ -78,7 +78,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -87,13 +87,13 @@ "artifactKind": "lowerer", "resource": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:9b5ecf1c87a4a98ad3d7381d85e3625649a4f9d62f80f74b2aca6ace26be14af" + "digest": "sha256:f2063b66798fbb1c2b27c3af56e4b78184ffc22c9ed9c7a32c483d05b8c1d382" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:9b5ecf1c87a4a98ad3d7381d85e3625649a4f9d62f80f74b2aca6ace26be14af" + "digest": "sha256:f2063b66798fbb1c2b27c3af56e4b78184ffc22c9ed9c7a32c483d05b8c1d382" } } }, @@ -102,7 +102,7 @@ "artifactKind": "generationProvenance", "resource": { "coordinate": "echo.edict-provider-generation-provenance@1", - "digest": "sha256:830978048785a7b59ab5ebc65ab10a09211c43394bd3e970534f2dc4d6c25982" + "digest": "sha256:9042d8f1b0db93e306c59edb9b586f5ffd06f2f3db713cb2934058c61365f05c" }, "source": { "kind": "generated", @@ -112,7 +112,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -121,7 +121,7 @@ "artifactKind": "reviewArtifact", "resource": { "coordinate": "echo.edict-provider-generation-review@1", - "digest": "sha256:c5092ee28a0fe0df0265e5f0313e72212b96578c069276ecbd534a6bc3fc9017" + "digest": "sha256:bdfeefd350a61fe5a09bb3eb81f43a9b120fe9ba470fe6682520460d10c3e342" }, "source": { "kind": "generated", @@ -131,7 +131,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -140,7 +140,7 @@ "artifactKind": "artifactSchema", "resource": { "coordinate": "echo.provider-artifacts.cddl@1", - "digest": "sha256:e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c" + "digest": "sha256:faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde" }, "source": { "kind": "generated", @@ -150,7 +150,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -159,7 +159,7 @@ "artifactKind": "targetProfile", "resource": { "coordinate": "echo.dpo@1", - "digest": "sha256:ad7f10e1843f4b3d2c08b11d69df103f9c0b1b7388ae26bb364cc87106cd419e" + "digest": "sha256:eedf7bdbf6fe4b6a4036695f41c3dc0a5c692d27e206c9d4c0c5eab41e2f63c9" }, "source": { "kind": "generated", @@ -169,7 +169,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -178,13 +178,13 @@ "artifactKind": "verifier", "resource": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:4f99c07f1c6d682405945fbb3e36e5537b94c4a01bd1a4ec7f02ef8e9911249a" + "digest": "sha256:632cc5134861c0b31ccc9ca77d4a09fe757094964369d057b62ca6ba6ad38ad7" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:4f99c07f1c6d682405945fbb3e36e5537b94c4a01bd1a4ec7f02ef8e9911249a" + "digest": "sha256:632cc5134861c0b31ccc9ca77d4a09fe757094964369d057b62ca6ba6ad38ad7" } } } diff --git a/crates/echo-wesley-gen/src/provider_artifacts.rs b/crates/echo-wesley-gen/src/provider_artifacts.rs index bc397d7b..b215d9c5 100644 --- a/crates/echo-wesley-gen/src/provider_artifacts.rs +++ b/crates/echo-wesley-gen/src/provider_artifacts.rs @@ -91,7 +91,35 @@ echo-provider-conformance-corpus = { operations: { * tstr => null }, capabilities: { * tstr => null }, semanticEffects: { * tstr => null }, - cases: [], + cases: { 1* tstr => echo-provider-conformance-case }, +} + +echo-provider-conformance-case = { + crossing: "pipeline" / "request-admission" / "component-preflight" / + "helper-binding" / + "host-output-admission" / "verification" / + "schema-admission" / "lowering", + stimulus: "baseline" / "ambient-capabilities-denied" / + "artifact-bytes-changed" / "component-bytes-changed" / + "bundle-identity-changed" / "noncanonical-cbor-output" / + "unsupported-output-role-requested" / "schema-bytes-changed" / + "exact-source-bytes-changed" / "unsupported-core-semantics" / + "obstruction-arm-removed" / "target-intrinsic-changed", + requiredOutcome: { + disposition: "accepted" / "rejected" / "refused", + contract: "completed-package-parity" / + "ambient-capability-preflight-denied" / + "noncanonical-target-ir-output-denied" / + "unsupported-core-semantics-refused" / + "unsupported-verifier-output-role-refused" / + "target-intrinsic-mismatch-rejected" / + "obstruction-relation-mismatch-rejected" / + "artifact-digest-mismatch-rejected" / + "schema-artifact-digest-mismatch-rejected" / + "component-digest-mismatch-rejected" / + "target-ir-helper-binding-mismatch-rejected" / + "baseline-release-binding-mismatch-rejected", + }, } echo-provider-lawpack-compatibility = { @@ -1462,6 +1490,99 @@ fn typed_digest(digest: &str) -> Result JsonValue { + json!({ + "crossing": crossing, + "stimulus": stimulus, + "requiredOutcome": { + "disposition": disposition, + "contract": contract, + }, + }) +} + +fn conformance_cases() -> JsonValue { + json!({ + "package-parity": conformance_case( + "pipeline", + "baseline", + "accepted", + "completed-package-parity", + ), + "ambient-capability-denial": conformance_case( + "component-preflight", + "ambient-capabilities-denied", + "rejected", + "ambient-capability-preflight-denied", + ), + "noncanonical-output": conformance_case( + "host-output-admission", + "noncanonical-cbor-output", + "rejected", + "noncanonical-target-ir-output-denied", + ), + "unsupported-semantics": conformance_case( + "lowering", + "unsupported-core-semantics", + "refused", + "unsupported-core-semantics-refused", + ), + "output-overclaim": conformance_case( + "verification", + "unsupported-output-role-requested", + "refused", + "unsupported-verifier-output-role-refused", + ), + "wrong-intrinsic": conformance_case( + "verification", + "target-intrinsic-changed", + "rejected", + "target-intrinsic-mismatch-rejected", + ), + "dropped-obstruction": conformance_case( + "verification", + "obstruction-arm-removed", + "rejected", + "obstruction-relation-mismatch-rejected", + ), + "artifact-tamper": conformance_case( + "request-admission", + "artifact-bytes-changed", + "rejected", + "artifact-digest-mismatch-rejected", + ), + "schema-tamper": conformance_case( + "schema-admission", + "schema-bytes-changed", + "rejected", + "schema-artifact-digest-mismatch-rejected", + ), + "component-tamper": conformance_case( + "component-preflight", + "component-bytes-changed", + "rejected", + "component-digest-mismatch-rejected", + ), + "helper-identity-mismatch": conformance_case( + "helper-binding", + "bundle-identity-changed", + "rejected", + "target-ir-helper-binding-mismatch-rejected", + ), + "source-occurrence-change": conformance_case( + "helper-binding", + "exact-source-bytes-changed", + "rejected", + "baseline-release-binding-mismatch-rejected", + ), + }) +} + fn build_resource_value( source: &ProviderSemanticSourceV1, declaration: &ArtifactResourceDeclaration, @@ -1473,7 +1594,7 @@ fn build_resource_value( "operations": coordinate_set(source.operations.iter().map(|item| &item.identity.coordinate)), "capabilities": coordinate_set(source.capabilities.iter().map(|item| &item.identity.coordinate)), "semanticEffects": coordinate_set(source.effects.iter().map(|item| &item.identity.coordinate)), - "cases": [], + "cases": conformance_cases(), })), "resource.lawpack-compatibility" => Ok(json!({ "apiVersion": "echo.edict-provider.lawpack-compatibility/v1", diff --git a/crates/echo-wesley-gen/tests/provider_package_corpus.rs b/crates/echo-wesley-gen/tests/provider_package_corpus.rs index 25aa5115..e45f32ba 100644 --- a/crates/echo-wesley-gen/tests/provider_package_corpus.rs +++ b/crates/echo-wesley-gen/tests/provider_package_corpus.rs @@ -11,9 +11,9 @@ use std::sync::atomic::{AtomicU64, Ordering}; use sha2::{Digest as _, Sha256}; const EXPECTED_PROVIDER_DIGEST: &str = - "sha256:6d99fc4b4a56268b053226f17dfaa946bec6a3328219393c21fdb3398db6a925"; + "sha256:fc00dd73a26bbd6699668ddb3ba1e3db9beb9bd7655e270824019d1e6e33f712"; const EXPECTED_MANIFEST_RAW_SHA256: &str = - "0256679771de98841e1594a4133b24a328a9924c765fe2545e182565494ea6c0"; + "f45d5ea0f504045a4fa8ac4d8f1dcb5e7d6b4c5fca1b3ddd54dca994532ea7c8"; const PACKAGE_PATHS: [&str; 25] = [ "components/lowerer.echo-dpo.component.wasm", diff --git a/crates/echo-wesley-gen/tests/provider_primary_artifacts.rs b/crates/echo-wesley-gen/tests/provider_primary_artifacts.rs index e344f532..e3c84a82 100644 --- a/crates/echo-wesley-gen/tests/provider_primary_artifacts.rs +++ b/crates/echo-wesley-gen/tests/provider_primary_artifacts.rs @@ -754,30 +754,213 @@ fn echo_owned_outputs_emit_their_declared_schema_api() { } #[test] -fn declarative_conformance_resource_cannot_claim_unproven_cases() { +fn declarative_conformance_resource_requires_at_least_one_case_contract() { let pack = admitted_pack(); let (_, generated) = generate(SOURCE, &pack); let corpus = generated .resource("resource.conformance-corpus") .expect("conformance resource exists"); - let mut fabricated = corpus.canonical_value().clone(); - *map_field_mut(&mut fabricated, "cases") = - CanonicalValueV1::Array(vec![CanonicalValueV1::Null]); - let fabricated_bytes = - encode_canonical_cbor_v1(&fabricated).expect("fabricated value remains canonical CBOR"); + let assert_root_rejected = |value: &CanonicalValueV1, reason: &str| { + let bytes = encode_canonical_cbor_v1(value).expect("mutated value remains canonical CBOR"); + let error = generated + .schema() + .validate_root_bytes(corpus.owning_root(), &bytes) + .expect_err(reason); + assert_eq!( + (error.kind(), error.subject(), error.reference()), + ( + ProviderArtifactGenerationErrorKind::OwningRootRejected, + "echo-provider-conformance-corpus", + "generated-provider-schema" + ) + ); + }; + + let mut empty = corpus.canonical_value().clone(); + *map_field_mut(&mut empty, "cases") = CanonicalValueV1::Map(Vec::new()); + assert_root_rejected( + &empty, + "the declarative corpus cannot omit every required case contract", + ); + + let mut malformed_outcome = corpus.canonical_value().clone(); + *map_field_mut( + map_field_mut( + map_field_mut( + map_field_mut(&mut malformed_outcome, "cases"), + "package-parity", + ), + "requiredOutcome", + ), + "disposition", + ) = CanonicalValueV1::Text("passed".to_owned()); + assert_root_rejected( + &malformed_outcome, + "a result-shaped disposition is not a declared conformance obligation", + ); + + let mut fabricated_evidence = corpus.canonical_value().clone(); + let CanonicalValueV1::Map(case_entries) = map_field_mut( + map_field_mut(&mut fabricated_evidence, "cases"), + "package-parity", + ) else { + panic!("package-parity case is a map"); + }; + case_entries.push(( + CanonicalValueV1::Text("evidence".to_owned()), + CanonicalValueV1::Null, + )); + assert_root_rejected( + &fabricated_evidence, + "the declarative resource cannot claim execution evidence", + ); + + let mut unknown_contract = corpus.canonical_value().clone(); + *map_field_mut( + map_field_mut( + map_field_mut( + map_field_mut(&mut unknown_contract, "cases"), + "package-parity", + ), + "requiredOutcome", + ), + "contract", + ) = CanonicalValueV1::Text("unreviewed-contract".to_owned()); + assert_root_rejected( + &unknown_contract, + "the declarative resource cannot name an unreviewed executable contract", + ); +} + +#[test] +fn declarative_conformance_resource_names_the_reviewed_case_contracts() { + let pack = admitted_pack(); + let (_, generated) = generate(SOURCE, &pack); + let corpus = generated + .resource("resource.conformance-corpus") + .expect("conformance resource exists"); + let cases = map_field(corpus.canonical_value(), "cases"); + let mut case_ids = map_keys(cases); + case_ids.sort_unstable(); - let error = generated - .schema() - .validate_root_bytes(corpus.owning_root(), &fabricated_bytes) - .expect_err("the empty corpus cannot fabricate executable parity evidence"); assert_eq!( - (error.kind(), error.subject(), error.reference()), - ( - ProviderArtifactGenerationErrorKind::OwningRootRejected, - "echo-provider-conformance-corpus", - "generated-provider-schema" - ) + case_ids, + [ + "ambient-capability-denial", + "artifact-tamper", + "component-tamper", + "dropped-obstruction", + "helper-identity-mismatch", + "noncanonical-output", + "output-overclaim", + "package-parity", + "schema-tamper", + "source-occurrence-change", + "unsupported-semantics", + "wrong-intrinsic", + ] ); + + for (id, crossing, stimulus, disposition, contract) in [ + ( + "package-parity", + "pipeline", + "baseline", + "accepted", + "completed-package-parity", + ), + ( + "ambient-capability-denial", + "component-preflight", + "ambient-capabilities-denied", + "rejected", + "ambient-capability-preflight-denied", + ), + ( + "noncanonical-output", + "host-output-admission", + "noncanonical-cbor-output", + "rejected", + "noncanonical-target-ir-output-denied", + ), + ( + "unsupported-semantics", + "lowering", + "unsupported-core-semantics", + "refused", + "unsupported-core-semantics-refused", + ), + ( + "output-overclaim", + "verification", + "unsupported-output-role-requested", + "refused", + "unsupported-verifier-output-role-refused", + ), + ( + "wrong-intrinsic", + "verification", + "target-intrinsic-changed", + "rejected", + "target-intrinsic-mismatch-rejected", + ), + ( + "dropped-obstruction", + "verification", + "obstruction-arm-removed", + "rejected", + "obstruction-relation-mismatch-rejected", + ), + ( + "artifact-tamper", + "request-admission", + "artifact-bytes-changed", + "rejected", + "artifact-digest-mismatch-rejected", + ), + ( + "schema-tamper", + "schema-admission", + "schema-bytes-changed", + "rejected", + "schema-artifact-digest-mismatch-rejected", + ), + ( + "component-tamper", + "component-preflight", + "component-bytes-changed", + "rejected", + "component-digest-mismatch-rejected", + ), + ( + "helper-identity-mismatch", + "helper-binding", + "bundle-identity-changed", + "rejected", + "target-ir-helper-binding-mismatch-rejected", + ), + ( + "source-occurrence-change", + "helper-binding", + "exact-source-bytes-changed", + "rejected", + "baseline-release-binding-mismatch-rejected", + ), + ] { + let case = map_field(cases, id); + assert_eq!(map_keys(case), ["crossing", "stimulus", "requiredOutcome"]); + assert_eq!(text_value(map_field(case, "crossing")), crossing); + assert_eq!(text_value(map_field(case, "stimulus")), stimulus); + let required_outcome = map_field(case, "requiredOutcome"); + assert_eq!( + text_value(map_field(required_outcome, "disposition")), + disposition + ); + assert_eq!( + text_value(map_field(required_outcome, "contract")), + contract + ); + } } #[test] diff --git a/docs/architecture/application-contract-hosting.md b/docs/architecture/application-contract-hosting.md index 7dbe8f0d..84ce22a0 100644 --- a/docs/architecture/application-contract-hosting.md +++ b/docs/architecture/application-contract-hosting.md @@ -349,15 +349,25 @@ crossing and may not be encoded as synthetic mutations. Both refreshed components have crossed reproducible checked promotion. The lowerer is 189,668 bytes with SHA-256 -`9b5ecf1c87a4a98ad3d7381d85e3625649a4f9d62f80f74b2aca6ace26be14af`; the +`f2063b66798fbb1c2b27c3af56e4b78184ffc22c9ed9c7a32c483d05b8c1d382`; the verifier is 189,922 bytes with SHA-256 -`4f99c07f1c6d682405945fbb3e36e5537b94c4a01bd1a4ec7f02ef8e9911249a`. +`632cc5134861c0b31ccc9ca77d4a09fe757094964369d057b62ca6ba6ad38ad7`. The generated envelope crosses pinned-host CDDL admission under its owning root, and the isolated host helper witness covers exact binding, codec refusal and round trips, EINT packing, the borrowed registry, and the non-installing proposal. Pinned-host admission of the review envelope remains a separate crossing. +The generated conformance corpus declares twelve reviewed obligations, divided +exactly six to the isolated host executor and six to the package executor. Its +closed vocabulary covers one accepted baseline, nine rejected admission, +binding, and verification negatives, and two typed refusals for unsupported +lowerer or verifier semantics. Each declaration names its crossing, stimulus, required +disposition, and outcome contract, but contains no claimed result or evidence +pointer. Each executor requires an exact one-to-one match with only its assigned +owner set. Corpus declaration, schema admission, executed provider evidence, +and later Echo runtime receipts remain distinct propositions. + The first executable verifier independently implements the frozen `edict:target-provider/verifier@1.0.0` world. It compares the exact Core and Target IR relation under the target profile and ordered semantic inputs rather diff --git a/schemas/edict-provider/README.md b/schemas/edict-provider/README.md index a4fe3d69..b7a16a26 100644 --- a/schemas/edict-provider/README.md +++ b/schemas/edict-provider/README.md @@ -129,13 +129,17 @@ model. Echo-owned resource documents use their declared schema API as their wire `apiVersion`; generated resource digests are framed by the resource coordinate. The lawpack and target-profile manifests bind those domain-framed identities, -while later Wesley provenance binds exact-byte content references. The empty -declarative conformance corpus cannot carry cases until executable parity -evidence exists. Direct-adapter routes bind the adapter and native capability, -and operation-local failure mappings are not collapsed merely because two -operations share one semantic effect. Read-class operations must use a -revelation/projection optic and generate observer metadata rather than mutation -metadata. +while later Wesley provenance binds exact-byte content references. The +declarative conformance corpus names twelve reviewed obligations: six consumed +by the isolated host executor and six by the package executor, spanning one +accepted, nine rejected, and two refused outcomes. It carries no pass flag, result, +evidence path, or runtime receipt; declarations are obligations rather than +evidence or runtime authority. Any future case must extend the owning closed +CDDL vocabulary together with a typed executable witness. Direct-adapter routes +bind the adapter and native capability, and operation-local failure mappings +are not collapsed merely because two operations share one semantic effect. +Read-class operations must use a revelation/projection optic and generate +observer metadata rather than mutation metadata. The two authority-facts outputs use Edict's `edict.authority-facts/v1` domain and bind their contract owner to @@ -165,9 +169,9 @@ reproduce all three completed outcomes identically. Both checked components remain uninstalled package material; neither they nor the generated authority-facts documents are runtime Echo authority. The promoted lowerer is 189,668 bytes with SHA-256 -`9b5ecf1c87a4a98ad3d7381d85e3625649a4f9d62f80f74b2aca6ace26be14af`; the +`f2063b66798fbb1c2b27c3af56e4b78184ffc22c9ed9c7a32c483d05b8c1d382`; the promoted verifier is 189,922 bytes with SHA-256 -`4f99c07f1c6d682405945fbb3e36e5537b94c4a01bd1a4ec7f02ef8e9911249a`. +`632cc5134861c0b31ccc9ca77d4a09fe757094964369d057b62ca6ba6ad38ad7`. External Edict contract inputs come from the checked [`contracts/v1/`](contracts/v1/README.md) publication merged in diff --git a/schemas/edict-provider/components/v1/README.md b/schemas/edict-provider/components/v1/README.md index 29d1ef32..7f87a576 100644 --- a/schemas/edict-provider/components/v1/README.md +++ b/schemas/edict-provider/components/v1/README.md @@ -24,7 +24,7 @@ The source WIT is the exact 7,392-byte Edict contract with SHA-256 `2971fe44def7e51d5271dfc0f04f3088aa58754cffdc847681a587605aac749e`. The checked component is 189,668 bytes with SHA-256 -`9b5ecf1c87a4a98ad3d7381d85e3625649a4f9d62f80f74b2aca6ace26be14af`. +`f2063b66798fbb1c2b27c3af56e4b78184ffc22c9ed9c7a32c483d05b8c1d382`. Its sole contract attestation is the top-level custom section `edict:target-provider-contract` containing `edict:target-provider/lowerer@1.0.0`. Its only imports are the frozen WIT's @@ -37,7 +37,7 @@ capability imports. authenticated Rust/Cargo identities, frozen WIT bytes, path-remapping law, and `wit-component` version recorded above. Its checked component is 189,922 bytes with SHA-256 -`4f99c07f1c6d682405945fbb3e36e5537b94c4a01bd1a4ec7f02ef8e9911249a`. +`632cc5134861c0b31ccc9ca77d4a09fe757094964369d057b62ca6ba6ad38ad7`. Its sole contract attestation is the top-level custom section `edict:target-provider-contract` containing `edict:target-provider/verifier@1.0.0`. Its only imports are the frozen WIT's diff --git a/schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm b/schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm index 5f536455..6ca75c9e 100644 Binary files a/schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm and b/schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm differ diff --git a/schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm b/schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm index 5e1224f6..86b08807 100644 Binary files a/schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm and b/schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm differ diff --git a/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json b/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json index 2c481917..38ed92e9 100644 --- a/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json +++ b/schemas/edict-provider/generated/v1/evidence/provenance.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4984d3ce0d9195f23ee30c2d36b46814d0872e294266ac30959a5a95b1f5f7e"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:022658a64fa8f693388e3f21354ebe3125eba0ea1fedf140b7c87f0c76cf08dc"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:679b090774088b46413a4697a646f10c3627d9f7f698380237db72e0b11739a1"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:cb5104802031e06d2e2802efe14ad23877dba2756684a5509c06a8de7bb9ec85"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4ecd21b5b4d7c97c66f9aa9ef55794fd8610f58a6ccb5e37f411576b8247ca9"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:893af4f37e2821525cc609e5740e7e95ae0e1795ca2444d2267f438a69d2283f"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:2539a9856295db8545db10d1001b6b1697e40bff0ea07b45afd33255d45d4269"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:a2ecfe500dcedb25b22129a412a7c83379fc265d9f04792355425ff80b52a2ba"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json b/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json index a298a191..9a6ef4ed 100644 --- a/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json +++ b/schemas/edict-provider/generated/v1/evidence/review.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4984d3ce0d9195f23ee30c2d36b46814d0872e294266ac30959a5a95b1f5f7e"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:022658a64fa8f693388e3f21354ebe3125eba0ea1fedf140b7c87f0c76cf08dc"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:679b090774088b46413a4697a646f10c3627d9f7f698380237db72e0b11739a1"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:cb5104802031e06d2e2802efe14ad23877dba2756684a5509c06a8de7bb9ec85"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:2874523930a963f81204df9c39aca6f9b62edbd45e5512ef6903346f7efa7c3e","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4ecd21b5b4d7c97c66f9aa9ef55794fd8610f58a6ccb5e37f411576b8247ca9"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:893af4f37e2821525cc609e5740e7e95ae0e1795ca2444d2267f438a69d2283f"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:2539a9856295db8545db10d1001b6b1697e40bff0ea07b45afd33255d45d4269"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:a2ecfe500dcedb25b22129a412a7c83379fc265d9f04792355425ff80b52a2ba"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:614ad15a761639f61f693ac1202d770abb3156c4961b47ca30d27a2441a87b0b","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/generated/v1/primary/authority-facts.echo-dpo.cbor b/schemas/edict-provider/generated/v1/primary/authority-facts.echo-dpo.cbor index ef4787da..610eaf27 100644 --- a/schemas/edict-provider/generated/v1/primary/authority-facts.echo-dpo.cbor +++ b/schemas/edict-provider/generated/v1/primary/authority-facts.echo-dpo.cbor @@ -1 +1,2 @@ -¥fsource£dkindmtargetProfilefdigest‚fsha256X ­á„?K=,±iß?œ sˆ®&»6LÈqÍAžjcoordinatejecho.dpo@1gbudgets japiVersionxedict.authority-facts/v1qoperationProfiles¡kp.effectful¢dcorexcontinuum.profile.write/v1sallowedWriteClasses¡greplaceöreffectWriteClasses¡ntarget.replacegreplace \ No newline at end of file +¥fsource£dkindmtargetProfilefdigest‚fsha256X îß{ÛöþKj@6i_AÃÜ +\i-'âÉÔÀÅê´/cÉjcoordinatejecho.dpo@1gbudgets japiVersionxedict.authority-facts/v1qoperationProfiles¡kp.effectful¢dcorexcontinuum.profile.write/v1sallowedWriteClasses¡greplaceöreffectWriteClasses¡ntarget.replacegreplace \ No newline at end of file diff --git a/schemas/edict-provider/generated/v1/primary/authority-facts.echo-lawpack.cbor b/schemas/edict-provider/generated/v1/primary/authority-facts.echo-lawpack.cbor index bba8cf44..e91698fb 100644 Binary files a/schemas/edict-provider/generated/v1/primary/authority-facts.echo-lawpack.cbor and b/schemas/edict-provider/generated/v1/primary/authority-facts.echo-lawpack.cbor differ diff --git a/schemas/edict-provider/generated/v1/primary/lawpack.echo-dpo.cbor b/schemas/edict-provider/generated/v1/primary/lawpack.echo-dpo.cbor index af0722fb..879f21c2 100644 Binary files a/schemas/edict-provider/generated/v1/primary/lawpack.echo-dpo.cbor and b/schemas/edict-provider/generated/v1/primary/lawpack.echo-dpo.cbor differ diff --git a/schemas/edict-provider/generated/v1/primary/schema.echo-provider-artifacts.cddl b/schemas/edict-provider/generated/v1/primary/schema.echo-provider-artifacts.cddl index 380abbe7..58e8577c 100644 --- a/schemas/edict-provider/generated/v1/primary/schema.echo-provider-artifacts.cddl +++ b/schemas/edict-provider/generated/v1/primary/schema.echo-provider-artifacts.cddl @@ -837,7 +837,35 @@ echo-provider-conformance-corpus = { operations: { * tstr => null }, capabilities: { * tstr => null }, semanticEffects: { * tstr => null }, - cases: [], + cases: { 1* tstr => echo-provider-conformance-case }, +} + +echo-provider-conformance-case = { + crossing: "pipeline" / "request-admission" / "component-preflight" / + "helper-binding" / + "host-output-admission" / "verification" / + "schema-admission" / "lowering", + stimulus: "baseline" / "ambient-capabilities-denied" / + "artifact-bytes-changed" / "component-bytes-changed" / + "bundle-identity-changed" / "noncanonical-cbor-output" / + "unsupported-output-role-requested" / "schema-bytes-changed" / + "exact-source-bytes-changed" / "unsupported-core-semantics" / + "obstruction-arm-removed" / "target-intrinsic-changed", + requiredOutcome: { + disposition: "accepted" / "rejected" / "refused", + contract: "completed-package-parity" / + "ambient-capability-preflight-denied" / + "noncanonical-target-ir-output-denied" / + "unsupported-core-semantics-refused" / + "unsupported-verifier-output-role-refused" / + "target-intrinsic-mismatch-rejected" / + "obstruction-relation-mismatch-rejected" / + "artifact-digest-mismatch-rejected" / + "schema-artifact-digest-mismatch-rejected" / + "component-digest-mismatch-rejected" / + "target-ir-helper-binding-mismatch-rejected" / + "baseline-release-binding-mismatch-rejected", + }, } echo-provider-lawpack-compatibility = { diff --git a/schemas/edict-provider/generated/v1/primary/target-profile.echo-dpo.cbor b/schemas/edict-provider/generated/v1/primary/target-profile.echo-dpo.cbor index 28493267..e4b31526 100644 Binary files a/schemas/edict-provider/generated/v1/primary/target-profile.echo-dpo.cbor and b/schemas/edict-provider/generated/v1/primary/target-profile.echo-dpo.cbor differ diff --git a/schemas/edict-provider/generated/v1/resources/resource.conformance-corpus.cbor b/schemas/edict-provider/generated/v1/resources/resource.conformance-corpus.cbor index 4464f53c..c1e919e1 100644 --- a/schemas/edict-provider/generated/v1/resources/resource.conformance-corpus.cbor +++ b/schemas/edict-provider/generated/v1/resources/resource.conformance-corpus.cbor @@ -1 +1 @@ -¦ecases€eclasskdeclarativejapiVersionx)echo.edict-provider.conformance-corpus/v1joperations¡ga.b@1.tölcapabilities¡recho.dpo@1.replaceöosemanticEffects¡ntarget.replaceö \ No newline at end of file +¦ecases¬mschema-tamper£hcrossingpschema-admissionhstimulustschema-bytes-changedorequiredOutcome¢hcontractx(schema-artifact-digest-mismatch-rejectedkdispositionhrejectednpackage-parity£hcrossinghpipelinehstimulushbaselineorequiredOutcome¢hcontractxcompleted-package-paritykdispositionhacceptedoartifact-tamper£hcrossingqrequest-admissionhstimulusvartifact-bytes-changedorequiredOutcome¢hcontractx!artifact-digest-mismatch-rejectedkdispositionhrejectedowrong-intrinsic£hcrossinglverificationhstimulusxtarget-intrinsic-changedorequiredOutcome¢hcontractx"target-intrinsic-mismatch-rejectedkdispositionhrejectedpcomponent-tamper£hcrossingscomponent-preflighthstimuluswcomponent-bytes-changedorequiredOutcome¢hcontractx"component-digest-mismatch-rejectedkdispositionhrejectedpoutput-overclaim£hcrossinglverificationhstimulusx!unsupported-output-role-requestedorequiredOutcome¢hcontractx(unsupported-verifier-output-role-refusedkdispositiongrefusedsdropped-obstruction£hcrossinglverificationhstimuluswobstruction-arm-removedorequiredOutcome¢hcontractx&obstruction-relation-mismatch-rejectedkdispositionhrejectedsnoncanonical-output£hcrossinguhost-output-admissionhstimulusxnoncanonical-cbor-outputorequiredOutcome¢hcontractx$noncanonical-target-ir-output-deniedkdispositionhrejecteduunsupported-semantics£hcrossinghloweringhstimulusxunsupported-core-semanticsorequiredOutcome¢hcontractx"unsupported-core-semantics-refusedkdispositiongrefusedxhelper-identity-mismatch£hcrossingnhelper-bindinghstimuluswbundle-identity-changedorequiredOutcome¢hcontractx*target-ir-helper-binding-mismatch-rejectedkdispositionhrejectedxsource-occurrence-change£hcrossingnhelper-bindinghstimulusxexact-source-bytes-changedorequiredOutcome¢hcontractx*baseline-release-binding-mismatch-rejectedkdispositionhrejectedxambient-capability-denial£hcrossingscomponent-preflighthstimulusxambient-capabilities-deniedorequiredOutcome¢hcontractx#ambient-capability-preflight-deniedkdispositionhrejectedeclasskdeclarativejapiVersionx)echo.edict-provider.conformance-corpus/v1joperations¡ga.b@1.tölcapabilities¡recho.dpo@1.replaceöosemanticEffects¡ntarget.replaceö \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm b/schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm index 5f536455..6ca75c9e 100644 Binary files a/schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm and b/schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm differ diff --git a/schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm b/schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm index 5e1224f6..86b08807 100644 Binary files a/schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm and b/schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm differ diff --git a/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json b/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json index 2c481917..38ed92e9 100644 --- a/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json +++ b/schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4984d3ce0d9195f23ee30c2d36b46814d0872e294266ac30959a5a95b1f5f7e"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:022658a64fa8f693388e3f21354ebe3125eba0ea1fedf140b7c87f0c76cf08dc"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:679b090774088b46413a4697a646f10c3627d9f7f698380237db72e0b11739a1"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:cb5104802031e06d2e2802efe14ad23877dba2756684a5509c06a8de7bb9ec85"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-provenance-manifest/v1","contractVersions":{"generatorAbi":"wesley.extension-generator/v1","inputSchema":"wesley.extension-generation-input/v1","provenanceSchema":"wesley.generation-provenance-manifest/v1"},"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4ecd21b5b4d7c97c66f9aa9ef55794fd8610f58a6ccb5e37f411576b8247ca9"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:893af4f37e2821525cc609e5740e7e95ae0e1795ca2444d2267f438a69d2283f"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:2539a9856295db8545db10d1001b6b1697e40bff0ea07b45afd33255d45d4269"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:a2ecfe500dcedb25b22129a412a7c83379fc265d9f04792355425ff80b52a2ba"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089","version":"0.1.0"},"settingsDigest":"sha256:0f708e76898de6fdb8186352e81d0f5c445adf94bb6c7de9204952d9fe913d4a","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json b/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json index a298a191..9a6ef4ed 100644 --- a/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json +++ b/schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json @@ -1 +1 @@ -{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4984d3ce0d9195f23ee30c2d36b46814d0872e294266ac30959a5a95b1f5f7e"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:022658a64fa8f693388e3f21354ebe3125eba0ea1fedf140b7c87f0c76cf08dc"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:679b090774088b46413a4697a646f10c3627d9f7f698380237db72e0b11739a1"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:cb5104802031e06d2e2802efe14ad23877dba2756684a5509c06a8de7bb9ec85"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:2874523930a963f81204df9c39aca6f9b62edbd45e5512ef6903346f7efa7c3e","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file +{"apiVersion":"wesley.generation-review/v1","authoritative":false,"emittedArtifacts":[{"coordinate":"echo.dpo-authority-facts@1","digest":"sha256:e4ecd21b5b4d7c97c66f9aa9ef55794fd8610f58a6ccb5e37f411576b8247ca9"},{"coordinate":"echo.dpo-lawpack-authority-facts@1","digest":"sha256:893af4f37e2821525cc609e5740e7e95ae0e1795ca2444d2267f438a69d2283f"},{"coordinate":"echo.dpo-lawpack@1","digest":"sha256:2539a9856295db8545db10d1001b6b1697e40bff0ea07b45afd33255d45d4269"},{"coordinate":"echo.dpo.registration/v1","digest":"sha256:4ef3aaad0d2131ba7129a3e2ae178d10c44f7e9b062af2c1fe211de781462f34"},{"coordinate":"echo.dpo@1","digest":"sha256:a2ecfe500dcedb25b22129a412a7c83379fc265d9f04792355425ff80b52a2ba"},{"coordinate":"echo.provider-artifacts.cddl@1","digest":"sha256:faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde"}],"generationInputDigest":"sha256:aff2b3737d635728190e6252515d03a1c3a9b58031c6a126a9cc9007f3998aa8","generator":{"coordinate":"echo-wesley-gen.provider-artifact-generator@1","digest":"sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089","version":"0.1.0"},"projectionRoles":["authority-facts.echo-dpo","authority-facts.echo-lawpack","generated-artifact-profile.echo-dpo-registration","lawpack.echo-dpo","schema.echo-provider-artifacts","target-profile.echo-dpo"],"provenanceManifestDigest":"sha256:614ad15a761639f61f693ac1202d770abb3156c4961b47ca30d27a2441a87b0b","sourceArtifacts":[{"coordinate":"echo.semantic-schema@1","digest":"sha256:09e621edf0ba0a21bb602d759d7c66a5db394065ab2bc3578a6b7c31bc1ab335"},{"coordinate":"edict.provider-contract-pack.cddl@1","digest":"sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74"},{"coordinate":"edict.provider-contract-pack.manifest@1","digest":"sha256:6902467149fec3e0338bb90e8cd7963ee21b8ce24f368f9b12e748343cbe0e4f"}]} \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor b/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor index ef4787da..610eaf27 100644 --- a/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor +++ b/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-dpo.cbor @@ -1 +1,2 @@ -¥fsource£dkindmtargetProfilefdigest‚fsha256X ­á„?K=,±iß?œ sˆ®&»6LÈqÍAžjcoordinatejecho.dpo@1gbudgets japiVersionxedict.authority-facts/v1qoperationProfiles¡kp.effectful¢dcorexcontinuum.profile.write/v1sallowedWriteClasses¡greplaceöreffectWriteClasses¡ntarget.replacegreplace \ No newline at end of file +¥fsource£dkindmtargetProfilefdigest‚fsha256X îß{ÛöþKj@6i_AÃÜ +\i-'âÉÔÀÅê´/cÉjcoordinatejecho.dpo@1gbudgets japiVersionxedict.authority-facts/v1qoperationProfiles¡kp.effectful¢dcorexcontinuum.profile.write/v1sallowedWriteClasses¡greplaceöreffectWriteClasses¡ntarget.replacegreplace \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor b/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor index bba8cf44..e91698fb 100644 Binary files a/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor and b/schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor differ diff --git a/schemas/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor b/schemas/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor index af0722fb..879f21c2 100644 Binary files a/schemas/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor and b/schemas/edict-provider/package/v1/generated/primary/lawpack.echo-dpo.cbor differ diff --git a/schemas/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl b/schemas/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl index 380abbe7..58e8577c 100644 --- a/schemas/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl +++ b/schemas/edict-provider/package/v1/generated/primary/schema.echo-provider-artifacts.cddl @@ -837,7 +837,35 @@ echo-provider-conformance-corpus = { operations: { * tstr => null }, capabilities: { * tstr => null }, semanticEffects: { * tstr => null }, - cases: [], + cases: { 1* tstr => echo-provider-conformance-case }, +} + +echo-provider-conformance-case = { + crossing: "pipeline" / "request-admission" / "component-preflight" / + "helper-binding" / + "host-output-admission" / "verification" / + "schema-admission" / "lowering", + stimulus: "baseline" / "ambient-capabilities-denied" / + "artifact-bytes-changed" / "component-bytes-changed" / + "bundle-identity-changed" / "noncanonical-cbor-output" / + "unsupported-output-role-requested" / "schema-bytes-changed" / + "exact-source-bytes-changed" / "unsupported-core-semantics" / + "obstruction-arm-removed" / "target-intrinsic-changed", + requiredOutcome: { + disposition: "accepted" / "rejected" / "refused", + contract: "completed-package-parity" / + "ambient-capability-preflight-denied" / + "noncanonical-target-ir-output-denied" / + "unsupported-core-semantics-refused" / + "unsupported-verifier-output-role-refused" / + "target-intrinsic-mismatch-rejected" / + "obstruction-relation-mismatch-rejected" / + "artifact-digest-mismatch-rejected" / + "schema-artifact-digest-mismatch-rejected" / + "component-digest-mismatch-rejected" / + "target-ir-helper-binding-mismatch-rejected" / + "baseline-release-binding-mismatch-rejected", + }, } echo-provider-lawpack-compatibility = { diff --git a/schemas/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor b/schemas/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor index 28493267..e4b31526 100644 Binary files a/schemas/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor and b/schemas/edict-provider/package/v1/generated/primary/target-profile.echo-dpo.cbor differ diff --git a/schemas/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor b/schemas/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor index 4464f53c..c1e919e1 100644 --- a/schemas/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor +++ b/schemas/edict-provider/package/v1/generated/resources/resource.conformance-corpus.cbor @@ -1 +1 @@ -¦ecases€eclasskdeclarativejapiVersionx)echo.edict-provider.conformance-corpus/v1joperations¡ga.b@1.tölcapabilities¡recho.dpo@1.replaceöosemanticEffects¡ntarget.replaceö \ No newline at end of file +¦ecases¬mschema-tamper£hcrossingpschema-admissionhstimulustschema-bytes-changedorequiredOutcome¢hcontractx(schema-artifact-digest-mismatch-rejectedkdispositionhrejectednpackage-parity£hcrossinghpipelinehstimulushbaselineorequiredOutcome¢hcontractxcompleted-package-paritykdispositionhacceptedoartifact-tamper£hcrossingqrequest-admissionhstimulusvartifact-bytes-changedorequiredOutcome¢hcontractx!artifact-digest-mismatch-rejectedkdispositionhrejectedowrong-intrinsic£hcrossinglverificationhstimulusxtarget-intrinsic-changedorequiredOutcome¢hcontractx"target-intrinsic-mismatch-rejectedkdispositionhrejectedpcomponent-tamper£hcrossingscomponent-preflighthstimuluswcomponent-bytes-changedorequiredOutcome¢hcontractx"component-digest-mismatch-rejectedkdispositionhrejectedpoutput-overclaim£hcrossinglverificationhstimulusx!unsupported-output-role-requestedorequiredOutcome¢hcontractx(unsupported-verifier-output-role-refusedkdispositiongrefusedsdropped-obstruction£hcrossinglverificationhstimuluswobstruction-arm-removedorequiredOutcome¢hcontractx&obstruction-relation-mismatch-rejectedkdispositionhrejectedsnoncanonical-output£hcrossinguhost-output-admissionhstimulusxnoncanonical-cbor-outputorequiredOutcome¢hcontractx$noncanonical-target-ir-output-deniedkdispositionhrejecteduunsupported-semantics£hcrossinghloweringhstimulusxunsupported-core-semanticsorequiredOutcome¢hcontractx"unsupported-core-semantics-refusedkdispositiongrefusedxhelper-identity-mismatch£hcrossingnhelper-bindinghstimuluswbundle-identity-changedorequiredOutcome¢hcontractx*target-ir-helper-binding-mismatch-rejectedkdispositionhrejectedxsource-occurrence-change£hcrossingnhelper-bindinghstimulusxexact-source-bytes-changedorequiredOutcome¢hcontractx*baseline-release-binding-mismatch-rejectedkdispositionhrejectedxambient-capability-denial£hcrossingscomponent-preflighthstimulusxambient-capabilities-deniedorequiredOutcome¢hcontractx#ambient-capability-preflight-deniedkdispositionhrejectedeclasskdeclarativejapiVersionx)echo.edict-provider.conformance-corpus/v1joperations¡ga.b@1.tölcapabilities¡recho.dpo@1.replaceöosemanticEffects¡ntarget.replaceö \ No newline at end of file diff --git a/schemas/edict-provider/package/v1/provider-manifest.echo.json b/schemas/edict-provider/package/v1/provider-manifest.echo.json index 8782587e..23a5510d 100644 --- a/schemas/edict-provider/package/v1/provider-manifest.echo.json +++ b/schemas/edict-provider/package/v1/provider-manifest.echo.json @@ -3,7 +3,7 @@ "providerAbi": "edict:target-provider@1.0.0", "provider": { "coordinate": "echo.edict-provider@1", - "digest": "sha256:6d99fc4b4a56268b053226f17dfaa946bec6a3328219393c21fdb3398db6a925" + "digest": "sha256:fc00dd73a26bbd6699668ddb3ba1e3db9beb9bd7655e270824019d1e6e33f712" }, "artifacts": [ { @@ -11,7 +11,7 @@ "artifactKind": "authorityFacts", "resource": { "coordinate": "echo.dpo-authority-facts@1", - "digest": "sha256:724d9f0cf79d2f3815902b1aba8d811add4c00f45c93a7c8c6b05ff2f7ed4c29" + "digest": "sha256:e1fa56a4d476d80ec3260792e9a85f13f92f7c73aef2a18c3cda9cdd4d901527" }, "source": { "kind": "generated", @@ -21,7 +21,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -30,7 +30,7 @@ "artifactKind": "authorityFacts", "resource": { "coordinate": "echo.dpo-lawpack-authority-facts@1", - "digest": "sha256:147a07c38d257f6c949ad3890f3071049b79771b268d2e0d0fb1ad846e235209" + "digest": "sha256:a7e3cc3e2a088b613640ebd76694cd9c4ff5125a6ad7fa6574abe55caf38401b" }, "source": { "kind": "generated", @@ -40,7 +40,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -59,7 +59,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -68,7 +68,7 @@ "artifactKind": "lawpack", "resource": { "coordinate": "echo.dpo-lawpack@1", - "digest": "sha256:2a1631ae5fe2e11d09ccdfb94e3498f3236a3d615ee217e6cd5843efcd284987" + "digest": "sha256:b009609fa3fd0b12c53b3da22bc9d40839b253808aed0520d3b37a909ea73cfa" }, "source": { "kind": "generated", @@ -78,7 +78,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -87,13 +87,13 @@ "artifactKind": "lowerer", "resource": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:9b5ecf1c87a4a98ad3d7381d85e3625649a4f9d62f80f74b2aca6ace26be14af" + "digest": "sha256:f2063b66798fbb1c2b27c3af56e4b78184ffc22c9ed9c7a32c483d05b8c1d382" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.lowerer/component@1", - "digest": "sha256:9b5ecf1c87a4a98ad3d7381d85e3625649a4f9d62f80f74b2aca6ace26be14af" + "digest": "sha256:f2063b66798fbb1c2b27c3af56e4b78184ffc22c9ed9c7a32c483d05b8c1d382" } } }, @@ -102,7 +102,7 @@ "artifactKind": "generationProvenance", "resource": { "coordinate": "echo.edict-provider-generation-provenance@1", - "digest": "sha256:830978048785a7b59ab5ebc65ab10a09211c43394bd3e970534f2dc4d6c25982" + "digest": "sha256:9042d8f1b0db93e306c59edb9b586f5ffd06f2f3db713cb2934058c61365f05c" }, "source": { "kind": "generated", @@ -112,7 +112,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -121,7 +121,7 @@ "artifactKind": "reviewArtifact", "resource": { "coordinate": "echo.edict-provider-generation-review@1", - "digest": "sha256:c5092ee28a0fe0df0265e5f0313e72212b96578c069276ecbd534a6bc3fc9017" + "digest": "sha256:bdfeefd350a61fe5a09bb3eb81f43a9b120fe9ba470fe6682520460d10c3e342" }, "source": { "kind": "generated", @@ -131,7 +131,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -140,7 +140,7 @@ "artifactKind": "artifactSchema", "resource": { "coordinate": "echo.provider-artifacts.cddl@1", - "digest": "sha256:e4d9239715011fb03891aaf710455ac6ef68d787fa1f27f7c3153df48337871c" + "digest": "sha256:faece52eaf8ec040c374e5fe2a5ea040b522b58f415973f481e9c836ecfc4cde" }, "source": { "kind": "generated", @@ -150,7 +150,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -159,7 +159,7 @@ "artifactKind": "targetProfile", "resource": { "coordinate": "echo.dpo@1", - "digest": "sha256:ad7f10e1843f4b3d2c08b11d69df103f9c0b1b7388ae26bb364cc87106cd419e" + "digest": "sha256:eedf7bdbf6fe4b6a4036695f41c3dc0a5c692d27e206c9d4c0c5eab41e2f63c9" }, "source": { "kind": "generated", @@ -169,7 +169,7 @@ }, "generator": { "coordinate": "echo-wesley-gen.provider-artifact-generator@1", - "digest": "sha256:4b38887f484e9de8cdffe89e87bd0edcad165122889a7761dfdae90c1af76af2" + "digest": "sha256:da25ad8f6b700d0f2b59021a7eaf04a8f28f834d828748a66adc7970d17e7089" } } }, @@ -178,13 +178,13 @@ "artifactKind": "verifier", "resource": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:4f99c07f1c6d682405945fbb3e36e5537b94c4a01bd1a4ec7f02ef8e9911249a" + "digest": "sha256:632cc5134861c0b31ccc9ca77d4a09fe757094964369d057b62ca6ba6ad38ad7" }, "source": { "kind": "component", "component": { "coordinate": "echo.dpo.verifier/component@1", - "digest": "sha256:4f99c07f1c6d682405945fbb3e36e5537b94c4a01bd1a4ec7f02ef8e9911249a" + "digest": "sha256:632cc5134861c0b31ccc9ca77d4a09fe757094964369d057b62ca6ba6ad38ad7" } } } diff --git a/scripts/verify-edict-provider-host-v1.sh b/scripts/verify-edict-provider-host-v1.sh index 56d6478f..e092238c 100755 --- a/scripts/verify-edict-provider-host-v1.sh +++ b/scripts/verify-edict-provider-host-v1.sh @@ -36,6 +36,12 @@ cargo +1.90.0 xtask provider-verifier-component audit \ cargo +1.94.0 fmt --manifest-path "$MANIFEST" --all -- --check +CARGO_TARGET_DIR="$HOST_TARGET_DIR" \ + cargo +1.94.0 test \ + --manifest-path "$MANIFEST" \ + --locked \ + --test conformance_contract + ECHO_PROVIDER_LOWERER_COMPONENT="$component" \ ECHO_PROVIDER_VERIFIER_COMPONENT="$verifier_component" \ CARGO_TARGET_DIR="$HOST_TARGET_DIR" \ diff --git a/tests/edict-provider-host-v1/Cargo.lock b/tests/edict-provider-host-v1/Cargo.lock index 9523ce42..02005372 100644 --- a/tests/edict-provider-host-v1/Cargo.lock +++ b/tests/edict-provider-host-v1/Cargo.lock @@ -433,6 +433,7 @@ dependencies = [ "serde_json", "sha2", "warp-core", + "wat", ] [[package]] @@ -1176,6 +1177,12 @@ version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -1451,6 +1458,28 @@ dependencies = [ "wit-parser", ] +[[package]] +name = "wast" +version = "251.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc7467dda0a96142eb2c980329dfb62480b1e1d3622fdeb1a44e2bca6ceed74" +dependencies = [ + "bumpalo", + "leb128fmt", + "memchr", + "unicode-width", + "wasm-encoder", +] + +[[package]] +name = "wat" +version = "1.251.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b1086c9e85b95bd6a229a928bc6c6d0662e42af0250c88d067b418831ea4d4" +dependencies = [ + "wast", +] + [[package]] name = "winapi-util" version = "0.1.11" diff --git a/tests/edict-provider-host-v1/Cargo.toml b/tests/edict-provider-host-v1/Cargo.toml index c923a1b4..82d4d761 100644 --- a/tests/edict-provider-host-v1/Cargo.toml +++ b/tests/edict-provider-host-v1/Cargo.toml @@ -22,6 +22,9 @@ warp-core = { path = "../../crates/warp-core" } serde_json = "=1.0.150" sha2 = "=0.10.9" +[dev-dependencies] +wat = "=1.251.0" + [lints.rust] missing_docs = "deny" unsafe_code = "deny" diff --git a/tests/edict-provider-host-v1/fixtures/provider-conformance-v1/ORIGIN.toml b/tests/edict-provider-host-v1/fixtures/provider-conformance-v1/ORIGIN.toml new file mode 100644 index 00000000..40cc41da --- /dev/null +++ b/tests/edict-provider-host-v1/fixtures/provider-conformance-v1/ORIGIN.toml @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 +# © James Ross Ω FLYING•ROBOTS + +repository = "https://github.com/flyingrobots/edict" +commit = "c75c3f550d049485ba00eae0dc272c6dd6aca11f" +source = "crates/edict-syntax/tests/provider_lowering.rs::EFFECTFUL_REPLACE" +license = "Apache-2.0" + +[fixture] +file = "source.edict" +coordinate = "echo.provider-conformance.source@1" +note = "Materialized reviewed source fixture; whitespace is part of this exact Echo-owned occurrence." + +[canonicalization_profile] +file = "canonicalization-profile.json" +coordinate = "edict.canonical-cbor/v1" +note = "Echo-owned descriptor binding the pinned Edict canonical ABI and admitted contract pack." diff --git a/tests/edict-provider-host-v1/fixtures/provider-conformance-v1/canonicalization-profile.json b/tests/edict-provider-host-v1/fixtures/provider-conformance-v1/canonicalization-profile.json new file mode 100644 index 00000000..050160e7 --- /dev/null +++ b/tests/edict-provider-host-v1/fixtures/provider-conformance-v1/canonicalization-profile.json @@ -0,0 +1,9 @@ +{ + "apiVersion": "echo.provider-conformance.canonicalization-profile/v1", + "canonicalAbi": "edict.canonical-cbor/v1", + "contractPack": { + "coordinate": "edict.provider-contract-pack.cddl@1", + "digest": "sha256:92697bc9a5262c68258be9ee451ee8c144aeb363b92142915b8224430b85cf74" + }, + "edictCommit": "c75c3f550d049485ba00eae0dc272c6dd6aca11f" +} diff --git a/tests/edict-provider-host-v1/fixtures/provider-conformance-v1/source.edict b/tests/edict-provider-host-v1/fixtures/provider-conformance-v1/source.edict new file mode 100644 index 00000000..95d639af --- /dev/null +++ b/tests/edict-provider-host-v1/fixtures/provider-conformance-v1/source.edict @@ -0,0 +1,16 @@ +package a.b@1; + +type Input = { id: String, }; + +type Receipt = { id: String, }; + +type Output = { id: String, }; + +intent t(input: Input) returns Output + profile p.effectful + basis none + budget <= p.tiny { + let receipt: Receipt = target.replace(input.id) + else { rejected(reason) => domain.WriteRejected }; + return { id: input.id }; +} diff --git a/tests/edict-provider-host-v1/tests/conformance_contract.rs b/tests/edict-provider-host-v1/tests/conformance_contract.rs new file mode 100644 index 00000000..798f8f3c --- /dev/null +++ b/tests/edict-provider-host-v1/tests/conformance_contract.rs @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS +#![allow(clippy::expect_used, clippy::panic)] +//! Shared declarative provider-conformance contract witnesses. + +mod support; + +use std::collections::BTreeSet; + +use edict_syntax::{decode_canonical_cbor, encode_canonical_cbor, CanonicalValue}; +use support::conformance::{ + decode_declared_cases, CorpusContractErrorKind, ExecutableContract, ExecutorOwner, + CONFORMANCE_CORPUS_BYTES, +}; + +fn text(value: &str) -> CanonicalValue { + CanonicalValue::Text(value.to_owned()) +} + +fn case_contract( + crossing: &str, + stimulus: &str, + disposition: &str, + contract: &str, +) -> CanonicalValue { + CanonicalValue::Map(vec![ + (text("crossing"), text(crossing)), + (text("stimulus"), text(stimulus)), + ( + text("requiredOutcome"), + CanonicalValue::Map(vec![ + (text("disposition"), text(disposition)), + (text("contract"), text(contract)), + ]), + ), + ]) +} + +fn map_field_mut<'a>(value: &'a mut CanonicalValue, field: &str) -> &'a mut CanonicalValue { + let CanonicalValue::Map(entries) = value else { + panic!("canonical value is not a map"); + }; + entries + .iter_mut() + .find_map(|(key, value)| (key == &text(field)).then_some(value)) + .unwrap_or_else(|| panic!("canonical map field `{field}` is absent")) +} + +fn checked_corpus_value() -> CanonicalValue { + decode_canonical_cbor(CONFORMANCE_CORPUS_BYTES) + .expect("checked conformance corpus is canonical CBOR") +} + +fn parse_mutation(value: &CanonicalValue) -> CorpusContractErrorKind { + let bytes = encode_canonical_cbor(value).expect("mutated corpus encodes canonically"); + decode_declared_cases(&bytes) + .expect_err("mutated declaration must fail the executable-law boundary") + .kind() +} + +#[test] +fn checked_declarations_have_exact_executable_owners() { + let cases = decode_declared_cases(CONFORMANCE_CORPUS_BYTES) + .expect("checked declarations satisfy the executable-law inventory"); + let expected_ids = BTreeSet::from([ + "ambient-capability-denial", + "artifact-tamper", + "component-tamper", + "dropped-obstruction", + "helper-identity-mismatch", + "noncanonical-output", + "output-overclaim", + "package-parity", + "schema-tamper", + "source-occurrence-change", + "unsupported-semantics", + "wrong-intrinsic", + ]); + let actual_ids = cases + .iter() + .map(support::conformance::DeclaredCase::id) + .collect::>(); + let contracts = cases + .iter() + .map(support::conformance::DeclaredCase::contract) + .collect::>(); + + assert_eq!(cases.len(), 12); + assert_eq!(actual_ids, expected_ids); + assert_eq!(contracts.len(), 12); + assert_eq!( + cases + .iter() + .filter(|case| case.owner() == ExecutorOwner::Package) + .count(), + 6 + ); + assert_eq!( + cases + .iter() + .filter(|case| case.owner() == ExecutorOwner::Host) + .count(), + 6 + ); +} + +#[test] +fn declaration_parser_rejects_unknown_or_mismatched_executable_laws() { + let mut unknown = checked_corpus_value(); + *map_field_mut( + map_field_mut( + map_field_mut(map_field_mut(&mut unknown, "cases"), "package-parity"), + "requiredOutcome", + ), + "contract", + ) = text("unreviewed-contract"); + assert_eq!( + parse_mutation(&unknown), + CorpusContractErrorKind::UnknownContract + ); + + let mut mismatch = checked_corpus_value(); + let case = map_field_mut(map_field_mut(&mut mismatch, "cases"), "package-parity"); + *map_field_mut(case, "stimulus") = text("component-bytes-changed"); + assert_eq!( + parse_mutation(&mismatch), + CorpusContractErrorKind::DeclarationMismatch + ); +} + +#[test] +fn declaration_parser_rejects_empty_duplicate_or_result_shaped_cases() { + let mut empty = checked_corpus_value(); + *map_field_mut(&mut empty, "cases") = CanonicalValue::Map(Vec::new()); + assert_eq!(parse_mutation(&empty), CorpusContractErrorKind::EmptyCases); + + let mut duplicate = checked_corpus_value(); + let cases = map_field_mut(&mut duplicate, "cases"); + let CanonicalValue::Map(entries) = cases else { + panic!("cases are a map"); + }; + let contract = entries[0].1.clone(); + entries.push((text("package-parity-copy"), contract)); + assert_eq!( + parse_mutation(&duplicate), + CorpusContractErrorKind::DuplicateContract + ); + + let mut result_shaped = checked_corpus_value(); + let case = map_field_mut(map_field_mut(&mut result_shaped, "cases"), "package-parity"); + let CanonicalValue::Map(fields) = case else { + panic!("case declaration is a map"); + }; + fields.push((text("passed"), CanonicalValue::Bool(true))); + assert_eq!( + parse_mutation(&result_shaped), + CorpusContractErrorKind::CaseClosureInvalid + ); +} + +#[test] +fn checked_corpus_matches_the_reviewed_executable_registry() { + let mut value = checked_corpus_value(); + let cases = map_field_mut(&mut value, "cases"); + let CanonicalValue::Map(entries) = cases else { + panic!("cases are a map"); + }; + entries.clear(); + entries.push(( + text("package-parity"), + case_contract( + "pipeline", + "baseline", + "accepted", + "completed-package-parity", + ), + )); + entries.push(( + text("ambient-capability-denial"), + case_contract( + "component-preflight", + "ambient-capabilities-denied", + "rejected", + "ambient-capability-preflight-denied", + ), + )); + entries.push(( + text("noncanonical-output"), + case_contract( + "host-output-admission", + "noncanonical-cbor-output", + "rejected", + "noncanonical-target-ir-output-denied", + ), + )); + entries.push(( + text("unsupported-semantics"), + case_contract( + "lowering", + "unsupported-core-semantics", + "refused", + "unsupported-core-semantics-refused", + ), + )); + entries.push(( + text("output-overclaim"), + case_contract( + "verification", + "unsupported-output-role-requested", + "refused", + "unsupported-verifier-output-role-refused", + ), + )); + entries.push(( + text("wrong-intrinsic"), + case_contract( + "verification", + "target-intrinsic-changed", + "rejected", + "target-intrinsic-mismatch-rejected", + ), + )); + entries.push(( + text("dropped-obstruction"), + case_contract( + "verification", + "obstruction-arm-removed", + "rejected", + "obstruction-relation-mismatch-rejected", + ), + )); + entries.push(( + text("artifact-tamper"), + case_contract( + "request-admission", + "artifact-bytes-changed", + "rejected", + "artifact-digest-mismatch-rejected", + ), + )); + entries.push(( + text("schema-tamper"), + case_contract( + "schema-admission", + "schema-bytes-changed", + "rejected", + "schema-artifact-digest-mismatch-rejected", + ), + )); + entries.push(( + text("component-tamper"), + case_contract( + "component-preflight", + "component-bytes-changed", + "rejected", + "component-digest-mismatch-rejected", + ), + )); + entries.push(( + text("helper-identity-mismatch"), + case_contract( + "helper-binding", + "bundle-identity-changed", + "rejected", + "target-ir-helper-binding-mismatch-rejected", + ), + )); + entries.push(( + text("source-occurrence-change"), + case_contract( + "helper-binding", + "exact-source-bytes-changed", + "rejected", + "baseline-release-binding-mismatch-rejected", + ), + )); + let bytes = encode_canonical_cbor(&value).expect("synthetic registry corpus is canonical"); + assert_eq!(bytes, CONFORMANCE_CORPUS_BYTES); + let cases = decode_declared_cases(&bytes).expect("reviewed executable laws have exact owners"); + + assert!(cases.iter().any(|case| { + case.contract() == ExecutableContract::AmbientCapabilityPreflightDenied + && case.owner() == ExecutorOwner::Host + })); + assert!(cases.iter().any(|case| { + case.contract() == ExecutableContract::NoncanonicalTargetIrOutputDenied + && case.owner() == ExecutorOwner::Host + })); + assert!(cases.iter().any(|case| { + case.contract() == ExecutableContract::UnsupportedCoreSemanticsRefused + && case.owner() == ExecutorOwner::Host + })); + assert!(cases.iter().any(|case| { + case.contract() == ExecutableContract::UnsupportedVerifierOutputRoleRefused + && case.owner() == ExecutorOwner::Host + })); + assert!(cases.iter().any(|case| { + case.contract() == ExecutableContract::TargetIntrinsicMismatchRejected + && case.owner() == ExecutorOwner::Host + })); + assert!(cases.iter().any(|case| { + case.contract() == ExecutableContract::ObstructionRelationMismatchRejected + && case.owner() == ExecutorOwner::Host + })); + assert!(cases.iter().any(|case| { + case.contract() == ExecutableContract::ArtifactDigestMismatchRejected + && case.owner() == ExecutorOwner::Package + })); + assert!(cases.iter().any(|case| { + case.contract() == ExecutableContract::SchemaArtifactDigestMismatchRejected + && case.owner() == ExecutorOwner::Package + })); + assert!(cases.iter().any(|case| { + case.contract() == ExecutableContract::ComponentDigestMismatchRejected + && case.owner() == ExecutorOwner::Package + })); + assert!(cases.iter().any(|case| { + case.contract() == ExecutableContract::TargetIrHelperBindingMismatchRejected + && case.owner() == ExecutorOwner::Package + })); + assert!(cases.iter().any(|case| { + case.contract() == ExecutableContract::BaselineReleaseBindingMismatchRejected + && case.owner() == ExecutorOwner::Package + })); +} + +#[test] +fn duplicate_case_ids_cannot_reach_executable_dispatch() { + let mut value = checked_corpus_value(); + let cases = map_field_mut(&mut value, "cases"); + let CanonicalValue::Map(entries) = cases else { + panic!("cases are a map"); + }; + entries.push(( + text("package-parity"), + case_contract( + "component-preflight", + "ambient-capabilities-denied", + "rejected", + "ambient-capability-preflight-denied", + ), + )); + + let Ok(bytes) = encode_canonical_cbor(&value) else { + return; + }; + let error = decode_declared_cases(&bytes) + .expect_err("the decoder or executable parser rejects duplicate case IDs"); + assert!(matches!( + error.kind(), + CorpusContractErrorKind::CanonicalCborInvalid | CorpusContractErrorKind::DuplicateCaseId + )); +} diff --git a/tests/edict-provider-host-v1/tests/host_contract.rs b/tests/edict-provider-host-v1/tests/host_contract.rs index 7940fac9..1fec2800 100644 --- a/tests/edict-provider-host-v1/tests/host_contract.rs +++ b/tests/edict-provider-host-v1/tests/host_contract.rs @@ -8,6 +8,9 @@ )] //! Standalone Rust 1.94 witness for the frozen Edict provider-host contract. +mod support; + +use std::collections::BTreeSet; use std::fmt::Write as _; use std::path::{Path, PathBuf}; use std::process::Command; @@ -28,9 +31,9 @@ use edict_syntax::{ ProviderBoundArtifact, ProviderDiagnosticSeverity, ProviderDigest, ProviderDigestAlgorithm, ProviderInvocationKind, ProviderInvocationValidationFailureKind, ProviderLoweringInvocationContract, ProviderLoweringOutputKind, ProviderLoweringOutputRequest, - ProviderLoweringRequest, ProviderOutputManifest, ProviderRefusalKind, ProviderResourceRef, - ProviderResponseLimits, ProviderSchemaBinding, ProviderSchemaFormat, ProviderSemanticInput, - ProviderSemanticInputBinding, ProviderSemanticInputKind, + ProviderLoweringRequest, ProviderOutputManifest, ProviderRefusal, ProviderRefusalKind, + ProviderResourceRef, ProviderResponseLimits, ProviderSchemaBinding, ProviderSchemaFormat, + ProviderSemanticInput, ProviderSemanticInputBinding, ProviderSemanticInputKind, ProviderVerificationInvocationContract, ProviderVerificationOutputKind, ProviderVerificationOutputRequest, ProviderVerificationRequest, ProviderVerificationSuccess, ResourceRef, TargetEffectLowering, TargetIrLoweringFacts, TargetProviderManifest, @@ -38,22 +41,15 @@ use edict_syntax::{ AUTHORITY_FACTS_API_VERSION, CORE_DIGEST_FRAME, CORE_MODULE_DIGEST_DOMAIN, ECHO_DPO_TARGET_PROFILE, ECHO_SPAN_IR_DOMAIN, MAX_CANONICAL_NESTING_DEPTH, PROVIDER_LAWPACK_ARTIFACT_DOMAIN, TARGET_IR_ARTIFACT_DIGEST_DOMAIN, TARGET_PROFILE_API_VERSION, - TARGET_PROVIDER_ABI, TARGET_PROVIDER_MANIFEST_API_VERSION, TARGET_PROVIDER_PROTOCOL_VERSION, + TARGET_PROVIDER_ABI, TARGET_PROVIDER_LOWERER_CONTRACT, TARGET_PROVIDER_MANIFEST_API_VERSION, + TARGET_PROVIDER_PROTOCOL_VERSION, }; use sha2::{Digest as _, Sha256}; +use support::conformance::{ + decode_declared_cases, ExecutableContract, ExecutorOwner, CONFORMANCE_CORPUS_BYTES, +}; -const ECHO_SOURCE: &str = "package a.b@1;\n\ - type Input = { id: String, };\n\ - type Receipt = { id: String, };\n\ - type Output = { id: String, };\n\ - intent t(input: Input) returns Output\n\ - profile p.effectful\n\ - basis none\n\ - budget <= p.tiny {\n\ - let receipt: Receipt = target.replace(input.id)\n\ - else { rejected(reason) => domain.WriteRejected };\n\ - return { id: input.id };\n\ - }"; +const ECHO_SOURCE: &str = include_str!("../fixtures/provider-conformance-v1/source.edict"); const LOWERABILITY_DOMAIN: &str = "edict.lowering-requirements/v1"; const TARGET_IR_ROLE: &str = "target-ir.echo-dpo"; @@ -67,13 +63,13 @@ const DIAGNOSTIC_ABI_DIGEST: &str = "28fd72a98223153982ca084c29dbb1b2d430623967ab3b6db9d7fee668e614b9"; const SCHEMA_ROLE: &str = "schema.echo-provider-artifacts"; const RAW_TARGET_IR_SHA256: &str = - "5922fe337e04d2df0b62f32b04b19409609dafbcc672d6e4ea593c83f4ffac53"; + "9cc5b163ae43116d561071f0b9a59f98d894d858f787ddedd8690ad1451f17d1"; const DOMAIN_TARGET_IR_SHA256: &str = - "2244345f046448c7b519ade05a167137659361ed144b46315ea32dabfbad85fc"; + "d4689abc5c2275ea9c7e1b743197a0d8b4625091632e8f5162eba9ff88d568ad"; const RAW_TARGET_PROFILE_SHA256: &str = - "cb5104802031e06d2e2802efe14ad23877dba2756684a5509c06a8de7bb9ec85"; + "a2ecfe500dcedb25b22129a412a7c83379fc265d9f04792355425ff80b52a2ba"; const DOMAIN_TARGET_PROFILE_SHA256: &str = - "ad7f10e1843f4b3d2c08b11d69df103f9c0b1b7388ae26bb364cc87106cd419e"; + "eedf7bdbf6fe4b6a4036695f41c3dc0a5c692d27e206c9d4c0c5eab41e2f63c9"; const OBSERVATION_MARKER: &str = "ECHO_EDICT_HOST_OBSERVATION="; const SCHEMA_BYTES: &[u8] = include_bytes!( @@ -737,6 +733,22 @@ fn target_ir_with_mismatched_intrinsic(core: &CoreModule) -> Vec { encode_canonical_cbor(&target_ir).expect("mismatched Target IR encodes canonically") } +fn target_ir_without_obstruction_arm(core: &CoreModule) -> Vec { + let (target_ir_bytes, _) = oracle_target_ir(core); + let mut target_ir = + decode_canonical_cbor(&target_ir_bytes).expect("oracle Target IR decodes canonically"); + let intent = canonical_map_field_mut(canonical_map_field_mut(&mut target_ir, "intents"), "t"); + let CanonicalValue::Array(steps) = canonical_map_field_mut(intent, "steps") else { + panic!("Target IR steps are not an array"); + }; + let step = steps + .first_mut() + .expect("reviewed Target IR has one effect step"); + *canonical_map_field_mut(step, "obstructionArms") = CanonicalValue::Map(Vec::new()); + encode_canonical_cbor(&target_ir) + .expect("Target IR without obstruction arm encodes canonically") +} + fn resource_ref_value(reference: &ProviderResourceRef) -> CanonicalValue { assert_eq!( reference.digest.algorithm, @@ -833,7 +845,14 @@ fn echo_harness_with_request( contract: ProviderLoweringInvocationContract, request: ProviderLoweringRequest, ) -> LowerHarness { - let component = echo_component_bytes(); + echo_harness_with_request_and_component(contract, request, echo_component_bytes()) +} + +fn echo_harness_with_request_and_component( + contract: ProviderLoweringInvocationContract, + request: ProviderLoweringRequest, + component: &'static [u8], +) -> LowerHarness { let manifest = echo_manifest(component); let manifest_proof = Box::leak(Box::new( bind_target_provider_manifest(manifest).expect("Echo provider manifest validates"), @@ -885,7 +904,7 @@ fn assert_echo_refusal( harness: &LowerHarness, expected_kind: ProviderRefusalKind, expected_subject: Option<&str>, -) { +) -> ProviderRefusal { let outcome = harness .host .invoke_lowerer( @@ -918,6 +937,7 @@ fn assert_echo_refusal( assert_eq!(replayed.refusal(), Some(refusal)); assert!(replayed.response().is_none()); assert!(replayed.manifest().is_none()); + refusal.clone() } fn fixture_manifest(component_bytes: &'static [u8]) -> &'static TargetProviderManifest { @@ -1409,20 +1429,34 @@ fn echo_component_refuses_an_unsupported_profile_through_the_actual_host() { ); } -#[test] -fn echo_component_refuses_unsupported_core_semantics_through_the_actual_host() { +fn assert_unsupported_core_semantics_contract() { let mut core = echo_core(); - core.coordinate = "x.y@1".to_owned(); + "x.y@1".clone_into(&mut core.coordinate); let (mut contract, mut request) = echo_request(&core, TARGET_IR_ROLE); request.core.reference.coordinate = core.coordinate; contract.core = artifact_binding(&request.core); let harness = echo_harness_with_request(contract, request); - assert_echo_refusal( + let refusal = assert_echo_refusal( &harness, ProviderRefusalKind::UnsupportedSemantics, Some("x.y@1"), ); + let [diagnostic] = refusal.diagnostics.as_slice() else { + panic!("unsupported semantics produces one provider diagnostic"); + }; + assert_eq!(diagnostic.code, "echo.provider.unsupported-semantics"); + assert_eq!(diagnostic.severity, ProviderDiagnosticSeverity::Error); + assert_eq!( + diagnostic.message, + "the supplied semantics are outside the exact first Echo lowering closure" + ); + assert_eq!(diagnostic.repair, None); +} + +#[test] +fn echo_component_refuses_unsupported_core_semantics_through_the_actual_host() { + assert_unsupported_core_semantics_contract(); } #[test] @@ -1601,6 +1635,119 @@ fn host_rejections_preserve_trap_lifting_and_envelope_identity() { .any(|item| { item.kind == ProviderInvocationValidationFailureKind::UndeclaredOutput })); } +fn assert_noncanonical_target_ir_output_contract() { + let core = echo_core(); + let (contract, request) = echo_request(&core, "fixture.noncanonical"); + let harness = echo_harness_with_request_and_component(contract, request, FIXTURE_LOWERER_BYTES); + + let requested = &harness.request.request().requested_outputs[0]; + assert_eq!(requested.kind, ProviderLoweringOutputKind::TargetIr); + assert_eq!(requested.domain, TARGET_IR_ARTIFACT_DIGEST_DOMAIN); + + let failure = harness + .host + .invoke_lowerer( + &harness.prepared, + &harness.request, + harness.schema, + host_limits(), + ) + .expect_err("noncanonical Target IR must not cross host admission"); + + assert_eq!( + failure.kind(), + ProviderHostFailureKind::ResponseEnvelopeInvalid + ); + assert_eq!(failure.phase(), ProviderHostPhase::ValidateResponse); + + let report = failure + .validation_report() + .expect("response rejection retains structured validation evidence"); + assert_eq!(report.failures.len(), 1); + let item = &report.failures[0]; + assert_eq!( + item.kind, + ProviderInvocationValidationFailureKind::NonCanonicalArtifact + ); + assert_eq!(item.field, "outputs.artifact"); + assert_eq!(item.role.as_deref(), Some("fixture.noncanonical")); + assert_eq!( + item.obligation, + "canonical artifact bytes within the deterministic nesting bound" + ); +} + +#[test] +fn host_rejects_noncanonical_target_ir_from_an_explicit_malicious_provider() { + assert_noncanonical_target_ir_output_contract(); +} + +fn assert_ambient_capability_preflight_contract() { + for capability in [ + "wasi:filesystem/types@0.2.0", + "wasi:sockets/tcp@0.2.0", + "wasi:cli/environment@0.2.0", + "wasi:clocks/wall-clock@0.2.0", + "wasi:random/random@0.2.0", + ] { + let component = wat::parse_str(format!( + r#"(component + (@custom + "edict:target-provider-contract" + "{TARGET_PROVIDER_LOWERER_CONTRACT}" + ) + (type $capability + (instance + (type $operation (func)) + (export "operation" (func (type $operation))) + ) + ) + (import "{capability}" (instance (type $capability))) + )"# + )) + .expect("ambient capability component parses"); + let component: &'static [u8] = Box::leak(component.into_boxed_slice()); + let manifest = echo_manifest(component); + let manifest_proof = Box::leak(Box::new( + bind_target_provider_manifest(manifest) + .expect("ambient capability manifest validates exact component bytes"), + )); + let selected = select_provider_component( + manifest_proof, + LOWERER_ROLE, + ProviderInvocationKind::Lowering, + ) + .expect("ambient capability component selects by exact digest"); + let resolved = ResolvedProviderComponent::new(selected, Arc::from(component)); + let host = ProviderComponentHost::new().expect("host configures"); + + let failure = host + .prepare(&resolved) + .expect_err("ambient capability import must reject before instantiation"); + assert_eq!( + failure.kind(), + ProviderHostFailureKind::ComponentContractMismatch, + "{capability}: {}", + failure.diagnostic() + ); + assert_eq!( + failure.phase(), + ProviderHostPhase::Preflight, + "{capability}" + ); + assert_eq!( + failure.diagnostic(), + "provider component imports callable or unknown host authority", + "{capability}" + ); + } +} + +#[test] +fn ambient_capability_imports_are_denied_during_preflight() { + assert_ambient_capability_preflight_contract(); +} + #[test] fn rejected_host_invocation_replays_with_the_same_typed_failure() { let harness = fixture_harness("fixture.trap"); @@ -1620,6 +1767,55 @@ fn rejected_host_invocation_replays_with_the_same_typed_failure() { assert_eq!(failure.phase(), ProviderHostPhase::Lower); } +#[test] +fn declared_host_cases_execute_their_exact_typed_contracts() { + let cases = decode_declared_cases(CONFORMANCE_CORPUS_BYTES) + .expect("every checked declaration has one exact executable owner"); + let declared: BTreeSet<_> = cases + .iter() + .filter(|case| case.owner() == ExecutorOwner::Host) + .map(support::conformance::DeclaredCase::contract) + .collect(); + let mut executed = BTreeSet::new(); + for case in &cases { + if case.owner() != ExecutorOwner::Host { + continue; + } + match case.contract() { + ExecutableContract::CompletedPackageParity => { + panic!("package parity cannot be owned by the host executor"); + } + ExecutableContract::AmbientCapabilityPreflightDenied => { + assert_ambient_capability_preflight_contract(); + } + ExecutableContract::NoncanonicalTargetIrOutputDenied => { + assert_noncanonical_target_ir_output_contract(); + } + ExecutableContract::UnsupportedCoreSemanticsRefused => { + assert_unsupported_core_semantics_contract(); + } + ExecutableContract::UnsupportedVerifierOutputRoleRefused => { + assert_unsupported_verifier_output_role_contract(); + } + ExecutableContract::TargetIntrinsicMismatchRejected => { + assert_target_intrinsic_mismatch_contract(); + } + ExecutableContract::ObstructionRelationMismatchRejected => { + assert_obstruction_relation_mismatch_contract(); + } + ExecutableContract::ArtifactDigestMismatchRejected + | ExecutableContract::SchemaArtifactDigestMismatchRejected + | ExecutableContract::ComponentDigestMismatchRejected + | ExecutableContract::TargetIrHelperBindingMismatchRejected + | ExecutableContract::BaselineReleaseBindingMismatchRejected => { + panic!("package-owned contract reached the host executor"); + } + } + assert!(executed.insert(case.contract())); + } + assert_eq!(executed, declared); +} + #[test] #[ignore = "child entrypoint exercised by the independent-process witness"] fn emit_echo_component_host_observation() { @@ -1682,8 +1878,7 @@ fn echo_verifier_component_admits_the_exact_relation_through_the_actual_host() { assert_admitted_verifier_success(&harness, response, manifest, "accepted"); } -#[test] -fn echo_verifier_component_admits_a_well_formed_semantic_rejection() { +fn assert_target_intrinsic_mismatch_contract() { let core = echo_core(); let target_ir_bytes = target_ir_with_mismatched_intrinsic(&core); let harness = echo_verifier_harness(&core, &target_ir_bytes); @@ -1716,7 +1911,49 @@ fn echo_verifier_component_admits_a_well_formed_semantic_rejection() { } #[test] -fn echo_verifier_component_preserves_a_typed_output_overclaim_refusal() { +fn echo_verifier_component_admits_a_well_formed_semantic_rejection() { + assert_target_intrinsic_mismatch_contract(); +} + +fn assert_obstruction_relation_mismatch_contract() { + let core = echo_core(); + let target_ir_bytes = target_ir_without_obstruction_arm(&core); + let harness = echo_verifier_harness(&core, &target_ir_bytes); + let outcome = harness + .host + .invoke_verifier( + &harness.prepared, + &harness.request, + harness.schema, + host_limits(), + ) + .expect("dropped obstruction remains a well-formed completed verification"); + assert!(outcome.refusal().is_none()); + let response = outcome + .response() + .expect("dropped obstruction returns a rejected verifier report"); + let [diagnostic] = response.diagnostics.as_slice() else { + panic!("dropped obstruction produces one verifier diagnostic"); + }; + assert_eq!(diagnostic.code, "echo.verifier.obstruction-mismatch"); + assert_eq!(diagnostic.severity, ProviderDiagnosticSeverity::Error); + assert_eq!( + diagnostic.message, + "Target IR does not preserve the exact Core obstruction relation" + ); + assert_eq!(diagnostic.repair, None); + let manifest = outcome + .manifest() + .expect("host authors the rejected verifier output manifest"); + assert_admitted_verifier_success(&harness, response, manifest, "rejected"); +} + +#[test] +fn echo_verifier_component_rejects_a_dropped_obstruction_arm() { + assert_obstruction_relation_mismatch_contract(); +} + +fn assert_unsupported_verifier_output_role_contract() { let core = echo_core(); let (target_ir_bytes, _) = oracle_target_ir(&core); let (contract, mut request) = echo_verification_request(&core, &target_ir_bytes); @@ -1758,6 +1995,11 @@ fn echo_verifier_component_preserves_a_typed_output_overclaim_refusal() { assert_eq!(diagnostic.repair, None); } +#[test] +fn echo_verifier_component_preserves_a_typed_output_overclaim_refusal() { + assert_unsupported_verifier_output_role_contract(); +} + #[test] fn echo_verifier_component_replays_all_completed_outcome_classes_identically() { let core = echo_core(); diff --git a/tests/edict-provider-host-v1/tests/package_contract.rs b/tests/edict-provider-host-v1/tests/package_contract.rs index 972c585d..1a7a779d 100644 --- a/tests/edict-provider-host-v1/tests/package_contract.rs +++ b/tests/edict-provider-host-v1/tests/package_contract.rs @@ -1,52 +1,62 @@ // SPDX-License-Identifier: Apache-2.0 // © James Ross Ω FLYING•ROBOTS -#![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)] +#![allow( + clippy::expect_used, + clippy::panic, + clippy::print_stdout, + clippy::unwrap_used +)] //! Edict-native pre-execution readiness witness for the checked Echo package. -use std::collections::BTreeMap; +mod support; + +#[rustfmt::skip] +#[allow(dead_code)] +#[path = "../../../crates/echo-edict-provider-lowerer/tests/fixtures/generated_echo_dpo.rs"] +mod checked_generated_helper; + +use std::collections::{BTreeMap, BTreeSet}; use std::fmt::Write as _; +use std::process::Command; use std::sync::Arc; use edict_provider_host_wasmtime::{ - ProviderComponentHost, ProviderHostFailureKind, ProviderHostPhase, ResolvedProviderComponent, + ProviderComponentHost, ProviderHostFailureKind, ProviderHostLimits, ProviderHostPhase, + ResolvedProviderComponent, }; use edict_provider_schema::{ ProviderArtifactSchemaRegistry, ProviderSchemaRegistryFailureKind, ResolvedProviderSchemaArtifact, }; use edict_syntax::{ - bind_target_provider_manifest, compile_to_core, decode_canonical_cbor, encode_canonical_cbor, - encode_core_module, encode_target_ir_artifact, lower_with_builtin_lowerer, parse_module, - select_provider_component, validate_provider_lowering_request, - validate_provider_verification_request, BuiltinLowererRequest, BuiltinTargetLowerer, - CanonicalValue, CompilerContext, CoreBudget, CoreModule, ProviderArtifact, - ProviderArtifactBinding, ProviderArtifactSchemaValidator, ProviderArtifactSource, - ProviderBoundArtifact, ProviderDigest, ProviderDigestAlgorithm, ProviderInvocationKind, - ProviderInvocationValidationFailureKind, ProviderLoweringInvocationContract, - ProviderLoweringOutputKind, ProviderLoweringOutputRequest, ProviderLoweringRequest, - ProviderResourceRef, ProviderResponseLimits, ProviderSchemaFormat, ProviderSemanticInput, - ProviderSemanticInputBinding, ProviderSemanticInputKind, + assemble_contract_bundle_from_target_ir, bind_target_provider_manifest, compile_to_core, + decode_canonical_cbor, encode_canonical_cbor, encode_core_module, encode_target_ir_artifact, + lower_with_builtin_lowerer, parse_module, select_provider_component, + validate_provider_lowering_request, validate_provider_verification_request, + BuiltinLowererRequest, BuiltinTargetLowerer, CanonicalValue, CompilerContext, + ContractBundleAssemblyFromTargetIrInput, ContractBundleManifest, ContractBundleSourceArtifact, + CoreBudget, CoreModule, DigestLockedResource, ProviderArtifact, ProviderArtifactBinding, + ProviderArtifactSchemaValidator, ProviderArtifactSource, ProviderBoundArtifact, ProviderDigest, + ProviderDigestAlgorithm, ProviderInvocationKind, ProviderInvocationValidationFailureKind, + ProviderLoweringInvocationContract, ProviderLoweringOutputKind, ProviderLoweringOutputRequest, + ProviderLoweringRequest, ProviderResourceRef, ProviderResponseLimits, ProviderSchemaFormat, + ProviderSemanticInput, ProviderSemanticInputBinding, ProviderSemanticInputKind, ProviderVerificationInvocationContract, ProviderVerificationOutputKind, ProviderVerificationOutputRequest, ProviderVerificationRequest, ResourceRef, - TargetEffectLowering, TargetIrLoweringFacts, TargetProviderManifest, WriteClass, - AUTHORITY_FACTS_API_VERSION, CORE_DIGEST_FRAME, CORE_MODULE_DIGEST_DOMAIN, - ECHO_DPO_TARGET_PROFILE, ECHO_SPAN_IR_DOMAIN, PROVIDER_LAWPACK_ARTIFACT_DOMAIN, - TARGET_IR_ARTIFACT_DIGEST_DOMAIN, TARGET_PROFILE_API_VERSION, TARGET_PROVIDER_PROTOCOL_VERSION, + TargetEffectLowering, TargetIrArtifact, TargetIrLoweringFacts, TargetProviderManifest, + WriteClass, AUTHORITY_FACTS_API_VERSION, CANONICAL_CBOR_ABI, CORE_DIGEST_FRAME, + CORE_MODULE_DIGEST_DOMAIN, ECHO_DPO_TARGET_PROFILE, ECHO_SPAN_IR_DOMAIN, + PROVIDER_LAWPACK_ARTIFACT_DOMAIN, TARGET_IR_ARTIFACT_DIGEST_DOMAIN, TARGET_PROFILE_API_VERSION, + TARGET_PROVIDER_PROTOCOL_VERSION, }; use sha2::{Digest as _, Sha256}; -const ECHO_SOURCE: &str = "package a.b@1;\n\ - type Input = { id: String, };\n\ - type Receipt = { id: String, };\n\ - type Output = { id: String, };\n\ - intent t(input: Input) returns Output\n\ - profile p.effectful\n\ - basis none\n\ - budget <= p.tiny {\n\ - let receipt: Receipt = target.replace(input.id)\n\ - else { rejected(reason) => domain.WriteRejected };\n\ - return { id: input.id };\n\ - }"; +use checked_generated_helper::echo_dpo as generated; +use support::conformance::{ + decode_declared_cases, ExecutableContract, ExecutorOwner, CONFORMANCE_CORPUS_BYTES, +}; + +const ECHO_SOURCE: &str = include_str!("../fixtures/provider-conformance-v1/source.edict"); const SCHEMA_ROLE: &str = "schema.echo-provider-artifacts"; const GENERATED_ARTIFACT_PROFILE_DOMAIN: &str = "echo.generated-artifact-profile/v1"; @@ -57,6 +67,7 @@ const TARGET_IR_ROLE: &str = "target-ir.echo-dpo"; const VERIFIER_ROLE: &str = "verifier.echo-dpo"; const VERIFIER_REPORT_DOMAIN: &str = "echo.verifier-report/v1"; const VERIFIER_REPORT_ROLE: &str = "verifier-report.echo-dpo"; +const PACKAGE_OBSERVATION_MARKER: &str = "ECHO_EDICT_PACKAGE_OBSERVATION="; const EXPECTED_SCHEMA_BINDING_COUNT: usize = 24; const MANIFEST_BYTES: &[u8] = @@ -79,12 +90,28 @@ const TARGET_AUTHORITY_BYTES: &[u8] = include_bytes!( const LAWPACK_AUTHORITY_BYTES: &[u8] = include_bytes!( "../../../schemas/edict-provider/package/v1/generated/primary/authority-facts.echo-lawpack.cbor" ); +const CANONICALIZATION_PROFILE_BYTES: &[u8] = + include_bytes!("../fixtures/provider-conformance-v1/canonicalization-profile.json"); +const GENERATION_SETTINGS_BYTES: &[u8] = + include_bytes!("../../../schemas/edict-provider/generation-settings-v1.json"); +const GENERATION_PROVENANCE_BYTES: &[u8] = include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/evidence/provenance.provider-generation.json" +); +const GENERATION_REVIEW_BYTES: &[u8] = include_bytes!( + "../../../schemas/edict-provider/package/v1/generated/evidence/review.provider-generation.json" +); const LOWERER_BYTES: &[u8] = include_bytes!( "../../../schemas/edict-provider/package/v1/components/lowerer.echo-dpo.component.wasm" ); const VERIFIER_BYTES: &[u8] = include_bytes!( "../../../schemas/edict-provider/package/v1/components/verifier.echo-dpo.component.wasm" ); +const EDICT_REVISION: &str = "c75c3f550d049485ba00eae0dc272c6dd6aca11f"; +const EDICT_COMPILER_DESCRIPTOR: &[u8] = + b"https://github.com/flyingrobots/edict\nc75c3f550d049485ba00eae0dc272c6dd6aca11f\nedict_syntax::compile_to_core\n"; +const BUILTIN_LOWERER_DESCRIPTOR: &[u8] = + b"https://github.com/flyingrobots/edict\nc75c3f550d049485ba00eae0dc272c6dd6aca11f\nedict_syntax::BuiltinTargetLowerer::EchoDpo\n"; +const NON_SEMANTIC_COMPILE_OPTIONS: &[u8] = b"{\"profile\":\"release\"}\n"; struct RoutedCanonicalArtifact { role: &'static str, @@ -347,6 +374,33 @@ fn rendered_provider_digest(digest: &ProviderDigest) -> String { format!("sha256:{}", hex(&digest.bytes)) } +fn raw_resource(coordinate: impl Into, bytes: &[u8]) -> DigestLockedResource { + DigestLockedResource::new(coordinate, raw_digest(bytes)).expect("resource digest is strict") +} + +fn routed_digest_locked_resource( + manifest: &TargetProviderManifest, + role: &str, +) -> DigestLockedResource { + let resource = routed_resource(manifest, role); + DigestLockedResource::new( + resource.coordinate.clone(), + resource + .digest + .clone() + .expect("every checked package route is digest locked"), + ) + .expect("the routed package resource has a strict digest") +} + +fn generated_digest_locked_resource(fixture: &GeneratedResourceFixture) -> DigestLockedResource { + DigestLockedResource::new( + fixture.domain, + rendered_provider_digest(&provider_digest(fixture.domain, fixture.bytes)), + ) + .expect("the generated package resource has a strict digest") +} + fn bound_artifact(coordinate: &str, domain: &str, bytes: &[u8]) -> ProviderBoundArtifact { ProviderBoundArtifact { reference: ProviderResourceRef { @@ -434,7 +488,7 @@ fn lowerability_bytes() -> Vec { .expect("lowerability facts encode canonically") } -fn echo_core() -> CoreModule { +fn echo_core_from(source: &str) -> CoreModule { let context = CompilerContext::new() .with_operation_profile("p.effectful", "continuum.profile.write/v1") .with_operation_profile_write_classes("p.effectful", [WriteClass::Replace]) @@ -447,10 +501,18 @@ fn echo_core() -> CoreModule { max_output_bytes: 256, }, ); - let module = parse_module(ECHO_SOURCE).expect("Echo source parses"); + let module = parse_module(source).expect("Echo source parses"); compile_to_core(&module, &context).expect("Echo source compiles to Core") } +fn echo_core() -> CoreModule { + echo_core_from(ECHO_SOURCE) +} + +fn whitespace_changed_echo_source() -> String { + format!("\n{ECHO_SOURCE}") +} + fn semantic_input( role: &str, kind: ProviderSemanticInputKind, @@ -537,7 +599,7 @@ fn lowering_request( (contract, request) } -fn oracle_target_ir(core: &CoreModule, target_profile: ResourceRef) -> Vec { +fn oracle_target_ir_artifact(core: &CoreModule, target_profile: ResourceRef) -> TargetIrArtifact { let facts = TargetIrLoweringFacts { target_profile, target_ir_domain: ECHO_SPAN_IR_DOMAIN.to_owned(), @@ -556,10 +618,14 @@ fn oracle_target_ir(core: &CoreModule, target_profile: ResourceRef) -> Vec { }, ) .expect("Edict's built-in Echo lowerer accepts the exact fixture"); - let artifact = report + report .artifact - .expect("the exact fixture lowers to Target IR"); - encode_target_ir_artifact(&artifact).expect("oracle Target IR encodes canonically") + .expect("the exact fixture lowers to Target IR") +} + +fn oracle_target_ir(core: &CoreModule, target_profile: ResourceRef) -> Vec { + encode_target_ir_artifact(&oracle_target_ir_artifact(core, target_profile)) + .expect("oracle Target IR encodes canonically") } fn verification_request( @@ -619,6 +685,696 @@ const fn response_limits() -> ProviderResponseLimits { } } +const fn host_limits() -> ProviderHostLimits { + ProviderHostLimits { + max_input_bytes: 1024 * 1024, + max_output_bytes: 3 * 1024 * 1024, + max_diagnostic_bytes: 3 * 1024 * 1024, + max_wasm_memory_bytes: 16 * 1024 * 1024, + max_table_elements: 10_000, + max_instances: 100, + max_memories: 8, + max_tables: 8, + max_wasm_fuel: 50_000_000, + max_hostcall_bytes: 4 * 1024 * 1024, + max_host_diagnostic_bytes: 512, + } +} + +struct PackageConformanceObservation { + target_ir_digest: String, + verifier_outcome: &'static str, + builtin_semantic_bundle_digest: String, + external_semantic_bundle_digest: String, + builtin_release_bundle_digest: String, + external_release_bundle_digest: String, + external_lowerer: ResourceRef, + external_verifier: ResourceRef, + generated_helper_bound: bool, +} + +struct PackageConformanceExecution { + observation: PackageConformanceObservation, + external_bundle: ContractBundleManifest, + source_occurrence_bundle: ContractBundleManifest, + baseline_core: CoreModule, + source_occurrence_core: CoreModule, + baseline_target_ir: TargetIrArtifact, + source_occurrence_target_ir: TargetIrArtifact, +} + +impl PackageConformanceObservation { + fn render(&self) -> String { + format!( + concat!( + "target-ir={};semantic-bundle={};builtin-release={};external-release={};", + "lowerer={}#{};verifier={}#{};verifier-outcome={};helper-bound={}" + ), + self.target_ir_digest, + self.external_semantic_bundle_digest, + self.builtin_release_bundle_digest, + self.external_release_bundle_digest, + self.external_lowerer.coordinate, + self.external_lowerer + .digest + .as_deref() + .expect("the external lowerer observation is digest locked"), + self.external_verifier.coordinate, + self.external_verifier + .digest + .as_deref() + .expect("the external verifier observation is digest locked"), + self.verifier_outcome, + self.generated_helper_bound, + ) + } +} + +fn package_conformance_child_observation() -> String { + let executable = std::env::current_exe().expect("current test executable is discoverable"); + let output = Command::new(executable) + .arg("emit_completed_package_conformance_observation") + .args(["--exact", "--ignored", "--nocapture", "--test-threads=1"]) + .output() + .expect("child conformance process launches"); + assert!( + output.status.success(), + "child conformance witness failed:\nstdout:\n{}\nstderr:\n{}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); + let stdout = String::from_utf8(output.stdout).expect("child output is UTF-8"); + stdout + .lines() + .find_map(|line| { + line.split_once(PACKAGE_OBSERVATION_MARKER) + .map(|(_, observation)| observation) + }) + .unwrap_or_else(|| panic!("child omitted stable package observation:\n{stdout}")) + .to_owned() +} + +fn contract_bundle_input( + manifest: &TargetProviderManifest, + core_module: CoreModule, + target_ir_artifact: TargetIrArtifact, + source_bytes: &[u8], + lowerer: DigestLockedResource, + verifier: DigestLockedResource, + verifier_report: DigestLockedResource, +) -> ContractBundleAssemblyFromTargetIrInput { + let mut generated_artifacts = [ + "authority-facts.echo-lawpack", + GENERATED_ARTIFACT_PROFILE_ROLE, + SCHEMA_ROLE, + ] + .into_iter() + .map(|role| routed_digest_locked_resource(manifest, role)) + .collect::>(); + generated_artifacts.extend( + GENERATED_RESOURCE_FIXTURES + .iter() + .filter(|fixture| fixture.path != "resource.conformance-corpus.cbor") + .map(generated_digest_locked_resource), + ); + let conformance_fixture = GENERATED_RESOURCE_FIXTURES + .iter() + .find(|fixture| fixture.path == "resource.conformance-corpus.cbor") + .map(generated_digest_locked_resource) + .expect("the checked package contains its conformance corpus"); + + ContractBundleAssemblyFromTargetIrInput { + core_module, + core_ir_coordinate: "a.b@1.core/v1".to_owned(), + source_artifacts: vec![ContractBundleSourceArtifact::new( + "tests/edict-provider-host-v1/fixtures/provider-conformance-v1/source.edict", + "echo.provider-conformance.source@1", + raw_digest(source_bytes), + ) + .expect("the reviewed Edict source has an exact occurrence identity")], + source_profile_semantic_facts: routed_digest_locked_resource( + manifest, + "authority-facts.echo-dpo", + ), + target_ir_artifact, + lawpacks: vec![routed_digest_locked_resource(manifest, "lawpack.echo-dpo")], + generated_artifacts, + compiler: raw_resource( + format!("edict.compiler@{EDICT_REVISION}"), + EDICT_COMPILER_DESCRIPTOR, + ), + lowerer, + verifier, + semantic_compile_options: raw_resource( + "echo.provider.generation-settings/v1", + GENERATION_SETTINGS_BYTES, + ), + non_semantic_compile_options: raw_resource( + "echo.provider.compile-options.non-semantic/v1", + NON_SEMANTIC_COMPILE_OPTIONS, + ), + build_provenance: raw_resource( + "wesley.generation-provenance-manifest/v1", + GENERATION_PROVENANCE_BYTES, + ), + canonicalization_profile: raw_resource(CANONICAL_CBOR_ABI, CANONICALIZATION_PROFILE_BYTES), + conformance_fixture_corpora: vec![conformance_fixture], + verifier_report, + compile_explanation: raw_resource( + "echo.provider.generation-review/v1", + GENERATION_REVIEW_BYTES, + ), + assurance_evidence: Vec::new(), + } +} + +fn generated_helper_expected( + bundle: &ContractBundleManifest, +) -> generated::ExpectedContractBundleIdentityV1<'_> { + generated::ExpectedContractBundleIdentityV1 { + semantic_digest_domain: generated::SEMANTIC_BUNDLE_DIGEST_DOMAIN, + semantic_digest: &bundle.semantic_bundle_digest, + release_digest_domain: generated::RELEASE_BUNDLE_DIGEST_DOMAIN, + release_digest: &bundle.release_bundle_digest, + } +} + +fn generated_helper_identity( + bundle: &ContractBundleManifest, +) -> generated::ContractBundleIdentityV1<'_> { + generated::ContractBundleIdentityV1 { + semantic_digest_domain: generated::SEMANTIC_BUNDLE_DIGEST_DOMAIN, + semantic_digest: &bundle.semantic_bundle_digest, + release_digest_domain: generated::RELEASE_BUNDLE_DIGEST_DOMAIN, + release_digest: &bundle.release_bundle_digest, + operation_coordinate: generated::OPERATION_COORDINATE, + operation_domain: generated::OPERATION_DOMAIN, + operation_id_law: generated::OPERATION_ID_LAW, + operation_id: generated::OPERATION_ID, + value_codec: generated::VALUE_CODEC_ID, + target_ir_coordinate: &bundle.target_ir.coordinate, + target_ir_digest_domain: generated::TARGET_IR_DIGEST_DOMAIN, + target_ir_digest: bundle + .target_ir + .digest + .as_deref() + .expect("the assembled Target IR is digest locked"), + target_profile_coordinate: &bundle.target_profile.coordinate, + target_profile_digest_domain: generated::TARGET_PROFILE_DIGEST_DOMAIN, + target_profile_digest: bundle + .target_profile + .digest + .as_deref() + .expect("the assembled target profile is digest locked"), + target_bundle_profile_coordinate: generated::TARGET_BUNDLE_PROFILE_COORDINATE, + target_bundle_profile_digest_domain: generated::TARGET_BUNDLE_PROFILE_DIGEST_DOMAIN, + target_bundle_profile_digest: generated::TARGET_BUNDLE_PROFILE_DIGEST, + echo_contract_abi_version: generated::ECHO_CONTRACT_ABI_VERSION, + helper_api_version: generated::CONTRACT_HOST_HELPER_API_VERSION, + provider_schema_coordinate: generated::PROVIDER_SCHEMA_COORDINATE, + provider_schema_sha256_hex: generated::PROVIDER_SCHEMA_SHA256_HEX, + input_schema: generated::INPUT_SCHEMA, + output_schema: generated::OUTPUT_SCHEMA, + type_schema_domain: generated::TYPE_SCHEMA_DOMAIN, + obstruction_coordinate: generated::OBSTRUCTION_COORDINATE, + obstruction_domain: generated::OBSTRUCTION_DOMAIN, + effect_failure_schema: generated::EFFECT_FAILURE_SCHEMA, + obstruction_payload_schema: generated::OBSTRUCTION_PAYLOAD_SCHEMA, + generated_artifact_profile: generated::GENERATED_ARTIFACT_PROFILE, + generated_artifact_profile_digest_domain: + generated::GENERATED_ARTIFACT_PROFILE_DIGEST_DOMAIN, + generated_artifact_profile_digest: generated::GENERATED_ARTIFACT_PROFILE_DIGEST, + operation_profile: generated::OPERATION_PROFILE, + operation_profile_domain: generated::OPERATION_PROFILE_DOMAIN, + operation_profiles_coordinate: generated::OPERATION_PROFILES_COORDINATE, + operation_profiles_digest_domain: generated::OPERATION_PROFILES_DIGEST_DOMAIN, + operation_profiles_digest: generated::OPERATION_PROFILES_DIGEST, + footprint_obligation: generated::FOOTPRINT_OBLIGATION, + footprint_algebra: generated::FOOTPRINT_ALGEBRA, + footprint_algebra_digest_domain: generated::FOOTPRINT_ALGEBRA_DIGEST_DOMAIN, + footprint_algebra_digest: generated::FOOTPRINT_ALGEBRA_DIGEST, + } +} + +fn bind_generated_helper_to_bundle(bundle: &ContractBundleManifest) -> bool { + assert_eq!(bundle.target_ir.coordinate, generated::TARGET_IR_COORDINATE); + assert_eq!( + bundle.target_ir.digest.as_deref(), + Some(generated::TARGET_IR_DIGEST) + ); + assert_eq!( + bundle.target_profile.coordinate, + generated::TARGET_PROFILE_COORDINATE + ); + assert_eq!( + bundle.target_profile.digest.as_deref(), + Some(generated::TARGET_PROFILE_DIGEST) + ); + + let expected = generated_helper_expected(bundle); + let identity = generated_helper_identity(bundle); + let descriptor = generated::bind_contract_bundle(expected, &identity) + .expect("the generated helper binds the real assembled external bundle"); + assert_eq!( + descriptor.contract_bundle().semantic_digest, + bundle.semantic_bundle_digest + ); + assert_eq!( + descriptor.contract_bundle().release_digest, + bundle.release_bundle_digest + ); + true +} + +fn complete_package_conformance_execution() -> PackageConformanceExecution { + let manifest = checked_manifest(); + let proof = bind_target_provider_manifest(&manifest) + .expect("the checked package manifest satisfies the Edict envelope"); + let registry = package_registry(&manifest); + let host = ProviderComponentHost::new().expect("the deterministic host configures"); + + let lowerer = select_provider_component(&proof, LOWERER_ROLE, ProviderInvocationKind::Lowering) + .expect("the checked package selects its lowerer"); + let lowerer = ResolvedProviderComponent::new(lowerer, Arc::<[u8]>::from(LOWERER_BYTES)); + let prepared_lowerer = host + .prepare(&lowerer) + .expect("the exact packaged lowerer passes Edict preflight"); + + let core = echo_core(); + let source_occurrence_bytes = whitespace_changed_echo_source(); + let source_occurrence_core = echo_core_from(&source_occurrence_bytes); + let (lowering_contract, lowering_request) = lowering_request(&core); + assert_request_semantics_are_package_routed( + &manifest, + &lowering_request.target_profile, + &lowering_request.semantic_inputs, + ); + let lowering_request = + validate_provider_lowering_request(®istry, &lowering_contract, &lowering_request) + .expect("the package-routed lowering request has an Edict validation proof"); + let lowering_outcome = host + .invoke_lowerer( + &prepared_lowerer, + &lowering_request, + ®istry, + host_limits(), + ) + .expect("the packaged lowerer completes through Edict's bounded host"); + assert!(lowering_outcome.refusal().is_none()); + let lowering_response = lowering_outcome + .response() + .expect("the packaged lowerer emits Target IR"); + assert!(lowering_response.diagnostics.is_empty()); + let [target_ir_output] = lowering_response.outputs.as_slice() else { + panic!("the packaged lowerer must emit exactly one Target IR output"); + }; + assert_eq!(target_ir_output.role, TARGET_IR_ROLE); + assert_eq!(target_ir_output.kind, ProviderLoweringOutputKind::TargetIr); + assert_eq!( + target_ir_output.artifact.domain, + TARGET_IR_ARTIFACT_DIGEST_DOMAIN + ); + assert_eq!(target_ir_output.logical_path, None); + + let builtin_target_ir_artifact = oracle_target_ir_artifact( + &core, + routed_resource(&manifest, "target-profile.echo-dpo").clone(), + ); + let source_occurrence_target_ir = oracle_target_ir_artifact( + &source_occurrence_core, + routed_resource(&manifest, "target-profile.echo-dpo").clone(), + ); + let builtin_target_ir = encode_target_ir_artifact(&builtin_target_ir_artifact) + .expect("the built-in compatibility Target IR encodes canonically"); + assert_eq!(target_ir_output.artifact.bytes, builtin_target_ir); + let builtin_target_ir_digest = + provider_digest(TARGET_IR_ARTIFACT_DIGEST_DOMAIN, &builtin_target_ir); + let lowering_manifest = lowering_outcome + .manifest() + .expect("the Edict host authors the external lowerer output manifest"); + let [target_ir_entry] = lowering_manifest.outputs() else { + panic!("the lowerer manifest must bind exactly one Target IR output"); + }; + assert_eq!(target_ir_entry.role, TARGET_IR_ROLE); + assert_eq!(target_ir_entry.kind, ProviderLoweringOutputKind::TargetIr); + assert_eq!(target_ir_entry.domain, TARGET_IR_ARTIFACT_DIGEST_DOMAIN); + assert_eq!(target_ir_entry.digest, builtin_target_ir_digest); + + let verifier = + select_provider_component(&proof, VERIFIER_ROLE, ProviderInvocationKind::Verification) + .expect("the checked package selects its verifier"); + let verifier = ResolvedProviderComponent::new(verifier, Arc::<[u8]>::from(VERIFIER_BYTES)); + let prepared_verifier = host + .prepare(&verifier) + .expect("the exact packaged verifier passes Edict preflight"); + let (verification_contract, verification_request) = + verification_request(&core, &target_ir_output.artifact.bytes); + assert_request_semantics_are_package_routed( + &manifest, + &verification_request.target_profile, + &verification_request.semantic_inputs, + ); + let verification_request = validate_provider_verification_request( + ®istry, + &verification_contract, + &verification_request, + ) + .expect("the package-routed verification request has an Edict validation proof"); + let verification_outcome = host + .invoke_verifier( + &prepared_verifier, + &verification_request, + ®istry, + host_limits(), + ) + .expect("the packaged verifier completes through Edict's bounded host"); + assert!( + verification_outcome.refusal().is_none(), + "packaged verifier unexpectedly refused: {:?}", + verification_outcome.refusal() + ); + let verification_response = verification_outcome + .response() + .expect("the packaged verifier emits a verifier report"); + assert!(verification_response.diagnostics.is_empty()); + let [verifier_report] = verification_response.outputs.as_slice() else { + panic!("the packaged verifier must emit exactly one verifier report"); + }; + assert_eq!(verifier_report.role, VERIFIER_REPORT_ROLE); + assert_eq!( + verifier_report.kind, + ProviderVerificationOutputKind::VerifierReport + ); + assert_eq!(verifier_report.artifact.domain, VERIFIER_REPORT_DOMAIN); + assert_eq!(verifier_report.logical_path, None); + let verifier_report_value = decode_canonical_cbor(&verifier_report.artifact.bytes) + .expect("the admitted verifier report is canonical CBOR"); + assert_eq!( + map_field(&verifier_report_value, "outcome"), + Some(&text("accepted")) + ); + let target_ir_reference = map_field(&verifier_report_value, "targetIr") + .expect("the verifier report binds its exact Target IR subject"); + let (target_ir_coordinate, target_ir_digest) = embedded_resource_ref(target_ir_reference) + .expect("the verifier report carries a strict Target IR reference"); + assert_eq!(target_ir_coordinate, "echo.target-ir@1"); + assert_eq!(target_ir_digest, builtin_target_ir_digest.bytes.as_slice()); + let verification_manifest = verification_outcome + .manifest() + .expect("the Edict host authors the verifier output manifest"); + let [verifier_entry] = verification_manifest.outputs() else { + panic!("the verifier manifest must bind exactly one report output"); + }; + assert_eq!(verifier_entry.role, VERIFIER_REPORT_ROLE); + assert_eq!( + verifier_entry.kind, + ProviderVerificationOutputKind::VerifierReport + ); + assert_eq!(verifier_entry.domain, VERIFIER_REPORT_DOMAIN); + assert_eq!( + verifier_entry.digest, + provider_digest(VERIFIER_REPORT_DOMAIN, &verifier_report.artifact.bytes) + ); + + let external_lowerer = routed_resource(&manifest, LOWERER_ROLE).clone(); + let external_verifier = routed_resource(&manifest, VERIFIER_ROLE).clone(); + let external_lowerer_resource = routed_digest_locked_resource(&manifest, LOWERER_ROLE); + let external_verifier_resource = routed_digest_locked_resource(&manifest, VERIFIER_ROLE); + let verifier_report_resource = DigestLockedResource::new( + VERIFIER_REPORT_DOMAIN, + rendered_provider_digest(&verifier_entry.digest), + ) + .expect("the admitted verifier report has a strict bundle identity"); + let builtin_bundle = assemble_contract_bundle_from_target_ir(contract_bundle_input( + &manifest, + core.clone(), + builtin_target_ir_artifact.clone(), + ECHO_SOURCE.as_bytes(), + raw_resource( + format!("edict.builtin.echo-dpo.lowerer@{EDICT_REVISION}"), + BUILTIN_LOWERER_DESCRIPTOR, + ), + external_verifier_resource.clone(), + verifier_report_resource.clone(), + )) + .expect("the built-in compatibility observation assembles a valid bundle"); + let external_bundle = assemble_contract_bundle_from_target_ir(contract_bundle_input( + &manifest, + core.clone(), + builtin_target_ir_artifact.clone(), + ECHO_SOURCE.as_bytes(), + external_lowerer_resource.clone(), + external_verifier_resource.clone(), + verifier_report_resource.clone(), + )) + .expect("the external provider observation assembles a valid bundle"); + let source_occurrence_bundle = assemble_contract_bundle_from_target_ir(contract_bundle_input( + &manifest, + source_occurrence_core.clone(), + source_occurrence_target_ir.clone(), + source_occurrence_bytes.as_bytes(), + external_lowerer_resource, + external_verifier_resource, + verifier_report_resource, + )) + .expect("the whitespace-only source occurrence assembles a valid bundle"); + assert_eq!(builtin_bundle.target_ir, external_bundle.target_ir); + assert_eq!( + builtin_bundle.semantic_bundle_digest, + external_bundle.semantic_bundle_digest + ); + assert_ne!( + builtin_bundle.release_bundle_digest, + external_bundle.release_bundle_digest + ); + assert_eq!(external_bundle.lowerer, external_lowerer); + assert_eq!(external_bundle.verifier, external_verifier); + let generated_helper_bound = bind_generated_helper_to_bundle(&external_bundle); + + let observation = PackageConformanceObservation { + target_ir_digest: rendered_provider_digest(&builtin_target_ir_digest), + verifier_outcome: "accepted", + builtin_semantic_bundle_digest: builtin_bundle.semantic_bundle_digest, + external_semantic_bundle_digest: external_bundle.semantic_bundle_digest.clone(), + builtin_release_bundle_digest: builtin_bundle.release_bundle_digest, + external_release_bundle_digest: external_bundle.release_bundle_digest.clone(), + external_lowerer, + external_verifier, + generated_helper_bound, + }; + PackageConformanceExecution { + observation, + external_bundle, + source_occurrence_bundle, + baseline_core: core, + source_occurrence_core, + baseline_target_ir: builtin_target_ir_artifact, + source_occurrence_target_ir, + } +} + +fn assert_completed_package_parity_contract(observation: &PackageConformanceObservation) { + assert_eq!(observation.verifier_outcome, "accepted"); + assert_eq!( + observation.builtin_semantic_bundle_digest, + observation.external_semantic_bundle_digest + ); + assert_ne!( + observation.builtin_release_bundle_digest, + observation.external_release_bundle_digest + ); + assert!(observation.generated_helper_bound); +} + +fn assert_target_ir_helper_binding_mismatch_contract(execution: &PackageConformanceExecution) { + const CHANGED_TARGET_IR_DIGEST: &str = + "sha256:0000000000000000000000000000000000000000000000000000000000000000"; + assert!(execution.observation.generated_helper_bound); + let expected = generated_helper_expected(&execution.external_bundle); + let mut identity = generated_helper_identity(&execution.external_bundle); + assert_ne!(identity.target_ir_digest, CHANGED_TARGET_IR_DIGEST); + identity.target_ir_digest = CHANGED_TARGET_IR_DIGEST; + + let Err(error) = generated::bind_contract_bundle(expected, &identity) else { + panic!("a changed Target IR identity cannot cross the checked bundle binding"); + }; + assert_eq!(error, generated::BindingMismatchKind::TargetIr); +} + +fn assert_baseline_release_binding_mismatch_contract(execution: &PackageConformanceExecution) { + let source_occurrence_bytes = whitespace_changed_echo_source(); + assert_eq!( + source_occurrence_bytes.strip_prefix('\n'), + Some(ECHO_SOURCE) + ); + assert_ne!(source_occurrence_bytes.as_bytes(), ECHO_SOURCE.as_bytes()); + let baseline_source_digest = raw_digest(ECHO_SOURCE.as_bytes()); + let source_occurrence_digest = raw_digest(source_occurrence_bytes.as_bytes()); + assert_ne!(baseline_source_digest, source_occurrence_digest); + + assert_eq!(execution.baseline_core, execution.source_occurrence_core); + assert_eq!( + encode_core_module(&execution.baseline_core) + .expect("the baseline Core encodes canonically"), + encode_core_module(&execution.source_occurrence_core) + .expect("the whitespace-only Core encodes canonically") + ); + assert_eq!( + execution.baseline_target_ir, + execution.source_occurrence_target_ir + ); + assert_eq!( + encode_target_ir_artifact(&execution.baseline_target_ir) + .expect("the baseline Target IR encodes canonically"), + encode_target_ir_artifact(&execution.source_occurrence_target_ir) + .expect("the whitespace-only Target IR encodes canonically") + ); + + let baseline = &execution.external_bundle; + let changed = &execution.source_occurrence_bundle; + let [baseline_source] = baseline.source_artifacts.as_slice() else { + panic!("the baseline release has one exact source occurrence"); + }; + let [changed_source] = changed.source_artifacts.as_slice() else { + panic!("the changed release has one exact source occurrence"); + }; + assert_eq!(baseline_source.logical_path, changed_source.logical_path); + assert_eq!( + baseline_source.artifact.coordinate, + changed_source.artifact.coordinate + ); + assert_eq!( + baseline_source.artifact.digest.as_deref(), + Some(baseline_source_digest.as_str()) + ); + assert_eq!( + changed_source.artifact.digest.as_deref(), + Some(source_occurrence_digest.as_str()) + ); + + assert_eq!(baseline.api_version, changed.api_version); + assert_eq!(baseline.core_ir, changed.core_ir); + assert_eq!(baseline.target_profile, changed.target_profile); + assert_eq!(baseline.target_ir, changed.target_ir); + assert_eq!(baseline.lawpacks, changed.lawpacks); + assert_eq!( + baseline.source_profile_semantic_facts, + changed.source_profile_semantic_facts + ); + assert_eq!(baseline.generated_artifacts, changed.generated_artifacts); + assert_eq!( + baseline.canonicalization_profile, + changed.canonicalization_profile + ); + assert_eq!( + baseline.semantic_compile_options, + changed.semantic_compile_options + ); + assert_eq!( + baseline.conformance_fixture_corpora, + changed.conformance_fixture_corpora + ); + assert_eq!(baseline.verifier_report, changed.verifier_report); + assert_eq!(baseline.compiler, changed.compiler); + assert_eq!(baseline.lowerer, changed.lowerer); + assert_eq!(baseline.verifier, changed.verifier); + assert_eq!( + baseline.non_semantic_compile_options, + changed.non_semantic_compile_options + ); + assert_eq!(baseline.build_provenance, changed.build_provenance); + assert_eq!(baseline.compile_explanation, changed.compile_explanation); + assert_eq!(baseline.assurance_evidence, changed.assurance_evidence); + assert_eq!(baseline.admission_artifacts, changed.admission_artifacts); + assert_eq!( + baseline.semantic_bundle_digest, + changed.semantic_bundle_digest + ); + assert_ne!( + baseline.release_bundle_digest, + changed.release_bundle_digest + ); + + let Err(error) = generated::bind_contract_bundle( + generated_helper_expected(baseline), + &generated_helper_identity(changed), + ) else { + panic!("a new release occurrence cannot cross the baseline host pin"); + }; + assert_eq!(error, generated::BindingMismatchKind::ReleaseBundleDigest); + generated::bind_contract_bundle( + generated_helper_expected(changed), + &generated_helper_identity(changed), + ) + .expect("the whitespace-only occurrence binds under its own release identity"); +} + +#[test] +fn checked_bundle_helper_refuses_a_changed_target_ir_identity() { + let execution = complete_package_conformance_execution(); + assert_target_ir_helper_binding_mismatch_contract(&execution); +} + +#[test] +fn whitespace_only_source_occurrence_preserves_semantics_and_moves_release_identity() { + let execution = complete_package_conformance_execution(); + assert_baseline_release_binding_mismatch_contract(&execution); +} + +fn execute_declared_package_cases(execution: &PackageConformanceExecution) { + let observation = &execution.observation; + let corpus = GENERATED_RESOURCE_FIXTURES + .iter() + .find(|fixture| fixture.path == "resource.conformance-corpus.cbor") + .expect("the checked package declares its conformance corpus"); + assert_eq!(corpus.bytes, CONFORMANCE_CORPUS_BYTES); + let cases = decode_declared_cases(corpus.bytes) + .expect("every checked declaration has one exact executable owner"); + let declared: BTreeSet<_> = cases + .iter() + .filter(|case| case.owner() == ExecutorOwner::Package) + .map(support::conformance::DeclaredCase::contract) + .collect(); + let mut executed = BTreeSet::new(); + for case in &cases { + match case.owner() { + ExecutorOwner::Package => { + match case.contract() { + ExecutableContract::CompletedPackageParity => { + assert_completed_package_parity_contract(observation); + } + ExecutableContract::ArtifactDigestMismatchRejected => { + assert_artifact_digest_mismatch_contract(); + } + ExecutableContract::SchemaArtifactDigestMismatchRejected => { + assert_schema_artifact_digest_mismatch_contract(); + } + ExecutableContract::ComponentDigestMismatchRejected => { + assert_component_digest_mismatch_contract(); + } + ExecutableContract::TargetIrHelperBindingMismatchRejected => { + assert_target_ir_helper_binding_mismatch_contract(execution); + } + ExecutableContract::BaselineReleaseBindingMismatchRejected => { + assert_baseline_release_binding_mismatch_contract(execution); + } + ExecutableContract::AmbientCapabilityPreflightDenied + | ExecutableContract::NoncanonicalTargetIrOutputDenied + | ExecutableContract::UnsupportedCoreSemanticsRefused + | ExecutableContract::UnsupportedVerifierOutputRoleRefused + | ExecutableContract::TargetIntrinsicMismatchRejected + | ExecutableContract::ObstructionRelationMismatchRejected => { + panic!("host-owned contract reached the package executor"); + } + } + assert!(executed.insert(case.contract())); + } + ExecutorOwner::Host => {} + } + } + assert_eq!(executed, declared); +} + fn routed_resource<'a>(manifest: &'a TargetProviderManifest, role: &str) -> &'a ResourceRef { &manifest .artifacts @@ -1206,6 +1962,100 @@ fn schema_valid_authority_source_mismatch_fails_primary_identity_closure() { assert_eq!(error, PackageIdentityFailure::AuthoritySourceMismatch); } +fn assert_artifact_digest_mismatch_contract() { + let manifest = checked_manifest(); + let registry = declared_package_registry(&manifest); + let core = echo_core(); + let (contract, mut request) = lowering_request(&core); + let mut changed_profile = + decode_canonical_cbor(TARGET_PROFILE_BYTES).expect("target profile is canonical"); + *map_field_mut(&mut changed_profile, "readConsistency") + .expect("target profile declares read consistency") = text("schema-valid-but-different"); + registry + .validate_canonical_value(TARGET_PROFILE_API_VERSION, &changed_profile) + .expect("changed target profile deliberately preserves its owning CDDL shape"); + request.target_profile.artifact.bytes = + encode_canonical_cbor(&changed_profile).expect("changed target profile is canonical"); + + let report = validate_provider_lowering_request(®istry, &contract, &request) + .expect_err("changed artifact bytes cannot cross an unchanged resource reference"); + let [failure] = report.failures.as_slice() else { + panic!("unchanged artifact pin produces one exact request-admission failure"); + }; + assert_eq!( + failure.kind, + ProviderInvocationValidationFailureKind::ArtifactDigestMismatch + ); + assert_eq!(failure.field, "target_profile.artifact.bytes"); + assert_eq!(failure.role, None); + assert_eq!( + failure.obligation, + "canonical bytes reproducing the bound sha256 digest" + ); +} + +#[test] +fn changed_artifact_bytes_fail_under_the_checked_reference() { + assert_artifact_digest_mismatch_contract(); +} + +fn assert_schema_artifact_digest_mismatch_contract() { + let manifest = checked_manifest(); + let proof = bind_target_provider_manifest(&manifest) + .expect("the checked package manifest satisfies the Edict envelope"); + let mut changed_schema = SCHEMA_BYTES.to_vec(); + changed_schema[0] ^= 1; + let error = ProviderArtifactSchemaRegistry::from_manifest( + &proof, + [ResolvedProviderSchemaArtifact { + role: SCHEMA_ROLE.to_owned(), + bytes: Arc::from(changed_schema), + }], + required_domains(&manifest), + ) + .expect_err("changed schema bytes cannot cross the checked schema reference"); + assert_eq!( + error.kind(), + ProviderSchemaRegistryFailureKind::SchemaArtifactDigestMismatch + ); + assert_eq!(error.schema_role(), Some(SCHEMA_ROLE)); +} + +#[test] +fn changed_schema_bytes_fail_under_the_checked_reference() { + assert_schema_artifact_digest_mismatch_contract(); +} + +fn assert_component_digest_mismatch_contract() { + let manifest = checked_manifest(); + let proof = bind_target_provider_manifest(&manifest) + .expect("the checked package manifest satisfies the Edict envelope"); + let selected = + select_provider_component(&proof, LOWERER_ROLE, ProviderInvocationKind::Lowering) + .expect("the checked lowerer selects"); + let mut changed_component = LOWERER_BYTES.to_vec(); + changed_component[0] ^= 1; + let resolved = ResolvedProviderComponent::new(selected, Arc::from(changed_component)); + let host = ProviderComponentHost::new().expect("the deterministic host configures"); + let error = host + .prepare(&resolved) + .expect_err("changed component bytes cannot cross the checked component reference"); + assert_eq!( + error.kind(), + ProviderHostFailureKind::ComponentDigestMismatch + ); + assert_eq!(error.phase(), ProviderHostPhase::Preflight); + assert_eq!( + error.diagnostic(), + "resolved component bytes do not reproduce the manifest digest" + ); +} + +#[test] +fn changed_component_bytes_fail_under_the_checked_reference() { + assert_component_digest_mismatch_contract(); +} + #[test] fn malformed_manifest_fails_before_component_selection() { let mut manifest = checked_manifest(); @@ -1310,3 +2160,53 @@ fn malformed_artifact_fails_before_component_execution() { failure.kind == ProviderInvocationValidationFailureKind::ArtifactSchemaMismatch })); } + +#[test] +fn declared_package_cases_execute_their_exact_typed_contracts() { + let execution = complete_package_conformance_execution(); + let observation = &execution.observation; + + execute_declared_package_cases(&execution); + + assert_eq!( + observation.target_ir_digest, + "sha256:d4689abc5c2275ea9c7e1b743197a0d8b4625091632e8f5162eba9ff88d568ad" + ); + assert_eq!(observation.verifier_outcome, "accepted"); + assert_eq!( + observation.builtin_semantic_bundle_digest, + observation.external_semantic_bundle_digest + ); + assert_ne!( + observation.builtin_release_bundle_digest, + observation.external_release_bundle_digest + ); + assert_eq!( + observation.external_lowerer, + routed_resource(&checked_manifest(), LOWERER_ROLE).clone() + ); + assert_eq!( + observation.external_verifier, + routed_resource(&checked_manifest(), VERIFIER_ROLE).clone() + ); + assert!(observation.generated_helper_bound); +} + +#[test] +#[ignore = "child entrypoint exercised by the independent-process package witness"] +fn emit_completed_package_conformance_observation() { + println!( + "{PACKAGE_OBSERVATION_MARKER}{}", + complete_package_conformance_execution() + .observation + .render() + ); +} + +#[test] +fn independent_processes_reproduce_the_completed_package_observation() { + let first = package_conformance_child_observation(); + let second = package_conformance_child_observation(); + + assert_eq!(first, second); +} diff --git a/tests/edict-provider-host-v1/tests/support/conformance.rs b/tests/edict-provider-host-v1/tests/support/conformance.rs new file mode 100644 index 00000000..62673bf5 --- /dev/null +++ b/tests/edict-provider-host-v1/tests/support/conformance.rs @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS +#![allow( + dead_code, + reason = "shared support is compiled into separate integration-test crates" +)] +//! Executable-law closure applied after owning-CDDL corpus admission. +//! +//! This parser does not replace schema admission. It binds each already +//! admitted declarative case to one reviewed tuple and executor owner without +//! treating the declaration itself as execution evidence. + +use std::collections::BTreeSet; + +use edict_syntax::{decode_canonical_cbor, CanonicalValue}; + +pub const CONFORMANCE_CORPUS_BYTES: &[u8] = include_bytes!( + "../../../../schemas/edict-provider/generated/v1/resources/resource.conformance-corpus.cbor" +); + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum ExecutableContract { + CompletedPackageParity, + AmbientCapabilityPreflightDenied, + NoncanonicalTargetIrOutputDenied, + UnsupportedCoreSemanticsRefused, + UnsupportedVerifierOutputRoleRefused, + TargetIntrinsicMismatchRejected, + ObstructionRelationMismatchRejected, + ArtifactDigestMismatchRejected, + SchemaArtifactDigestMismatchRejected, + ComponentDigestMismatchRejected, + TargetIrHelperBindingMismatchRejected, + BaselineReleaseBindingMismatchRejected, +} + +impl ExecutableContract { + fn parse(value: &str) -> Result { + match value { + "completed-package-parity" => Ok(Self::CompletedPackageParity), + "ambient-capability-preflight-denied" => Ok(Self::AmbientCapabilityPreflightDenied), + "noncanonical-target-ir-output-denied" => Ok(Self::NoncanonicalTargetIrOutputDenied), + "unsupported-core-semantics-refused" => Ok(Self::UnsupportedCoreSemanticsRefused), + "unsupported-verifier-output-role-refused" => { + Ok(Self::UnsupportedVerifierOutputRoleRefused) + } + "target-intrinsic-mismatch-rejected" => Ok(Self::TargetIntrinsicMismatchRejected), + "obstruction-relation-mismatch-rejected" => { + Ok(Self::ObstructionRelationMismatchRejected) + } + "artifact-digest-mismatch-rejected" => Ok(Self::ArtifactDigestMismatchRejected), + "schema-artifact-digest-mismatch-rejected" => { + Ok(Self::SchemaArtifactDigestMismatchRejected) + } + "component-digest-mismatch-rejected" => Ok(Self::ComponentDigestMismatchRejected), + "target-ir-helper-binding-mismatch-rejected" => { + Ok(Self::TargetIrHelperBindingMismatchRejected) + } + "baseline-release-binding-mismatch-rejected" => { + Ok(Self::BaselineReleaseBindingMismatchRejected) + } + _ => Err(CorpusContractError::new( + CorpusContractErrorKind::UnknownContract, + )), + } + } + + const fn expected(self) -> ExpectedDeclaration { + match self { + Self::CompletedPackageParity => ExpectedDeclaration { + id: "package-parity", + crossing: "pipeline", + stimulus: "baseline", + required_disposition: "accepted", + owner: ExecutorOwner::Package, + }, + Self::AmbientCapabilityPreflightDenied => ExpectedDeclaration { + id: "ambient-capability-denial", + crossing: "component-preflight", + stimulus: "ambient-capabilities-denied", + required_disposition: "rejected", + owner: ExecutorOwner::Host, + }, + Self::NoncanonicalTargetIrOutputDenied => ExpectedDeclaration { + id: "noncanonical-output", + crossing: "host-output-admission", + stimulus: "noncanonical-cbor-output", + required_disposition: "rejected", + owner: ExecutorOwner::Host, + }, + Self::UnsupportedCoreSemanticsRefused => ExpectedDeclaration { + id: "unsupported-semantics", + crossing: "lowering", + stimulus: "unsupported-core-semantics", + required_disposition: "refused", + owner: ExecutorOwner::Host, + }, + Self::UnsupportedVerifierOutputRoleRefused => ExpectedDeclaration { + id: "output-overclaim", + crossing: "verification", + stimulus: "unsupported-output-role-requested", + required_disposition: "refused", + owner: ExecutorOwner::Host, + }, + Self::TargetIntrinsicMismatchRejected => ExpectedDeclaration { + id: "wrong-intrinsic", + crossing: "verification", + stimulus: "target-intrinsic-changed", + required_disposition: "rejected", + owner: ExecutorOwner::Host, + }, + Self::ObstructionRelationMismatchRejected => ExpectedDeclaration { + id: "dropped-obstruction", + crossing: "verification", + stimulus: "obstruction-arm-removed", + required_disposition: "rejected", + owner: ExecutorOwner::Host, + }, + Self::ArtifactDigestMismatchRejected => ExpectedDeclaration { + id: "artifact-tamper", + crossing: "request-admission", + stimulus: "artifact-bytes-changed", + required_disposition: "rejected", + owner: ExecutorOwner::Package, + }, + Self::SchemaArtifactDigestMismatchRejected => ExpectedDeclaration { + id: "schema-tamper", + crossing: "schema-admission", + stimulus: "schema-bytes-changed", + required_disposition: "rejected", + owner: ExecutorOwner::Package, + }, + Self::ComponentDigestMismatchRejected => ExpectedDeclaration { + id: "component-tamper", + crossing: "component-preflight", + stimulus: "component-bytes-changed", + required_disposition: "rejected", + owner: ExecutorOwner::Package, + }, + Self::TargetIrHelperBindingMismatchRejected => ExpectedDeclaration { + id: "helper-identity-mismatch", + crossing: "helper-binding", + stimulus: "bundle-identity-changed", + required_disposition: "rejected", + owner: ExecutorOwner::Package, + }, + Self::BaselineReleaseBindingMismatchRejected => ExpectedDeclaration { + id: "source-occurrence-change", + crossing: "helper-binding", + stimulus: "exact-source-bytes-changed", + required_disposition: "rejected", + owner: ExecutorOwner::Package, + }, + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ExecutorOwner { + Package, + Host, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DeclaredCase { + id: String, + crossing: String, + stimulus: String, + required_disposition: String, + contract: ExecutableContract, +} + +impl DeclaredCase { + pub fn id(&self) -> &str { + &self.id + } + + pub fn crossing(&self) -> &str { + &self.crossing + } + + pub fn stimulus(&self) -> &str { + &self.stimulus + } + + pub fn required_disposition(&self) -> &str { + &self.required_disposition + } + + pub const fn contract(&self) -> ExecutableContract { + self.contract + } + + pub const fn owner(&self) -> ExecutorOwner { + self.contract.expected().owner + } + + fn matches_expected(&self) -> bool { + let expected = self.contract.expected(); + self.id == expected.id + && self.crossing == expected.crossing + && self.stimulus == expected.stimulus + && self.required_disposition == expected.required_disposition + } +} + +#[derive(Clone, Copy)] +struct ExpectedDeclaration { + id: &'static str, + crossing: &'static str, + stimulus: &'static str, + required_disposition: &'static str, + owner: ExecutorOwner, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum CorpusContractErrorKind { + CanonicalCborInvalid, + RootClosureInvalid, + EmptyCases, + CaseClosureInvalid, + OutcomeClosureInvalid, + FieldInvalid, + UnknownContract, + DeclarationMismatch, + DuplicateCaseId, + DuplicateContract, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct CorpusContractError { + kind: CorpusContractErrorKind, +} + +impl CorpusContractError { + const fn new(kind: CorpusContractErrorKind) -> Self { + Self { kind } + } + + pub const fn kind(self) -> CorpusContractErrorKind { + self.kind + } +} + +pub fn decode_declared_cases(bytes: &[u8]) -> Result, CorpusContractError> { + let root = decode_canonical_cbor(bytes) + .map_err(|_| CorpusContractError::new(CorpusContractErrorKind::CanonicalCborInvalid))?; + let root = map_entries(&root, CorpusContractErrorKind::RootClosureInvalid)?; + if root.len() != 6 + || required_text(root, "apiVersion")? != "echo.edict-provider.conformance-corpus/v1" + || required_text(root, "class")? != "declarative" + { + return Err(CorpusContractError::new( + CorpusContractErrorKind::RootClosureInvalid, + )); + } + for field in ["operations", "capabilities", "semanticEffects"] { + map_entries( + required_field(root, field)?, + CorpusContractErrorKind::RootClosureInvalid, + )?; + } + + let cases = map_entries( + required_field(root, "cases")?, + CorpusContractErrorKind::RootClosureInvalid, + )?; + if cases.is_empty() { + return Err(CorpusContractError::new( + CorpusContractErrorKind::EmptyCases, + )); + } + + let mut case_ids = BTreeSet::new(); + let mut contracts = BTreeSet::new(); + let mut declared = Vec::with_capacity(cases.len()); + for (case_id, value) in cases { + let CanonicalValue::Text(case_id) = case_id else { + return Err(CorpusContractError::new( + CorpusContractErrorKind::FieldInvalid, + )); + }; + if !case_ids.insert(case_id.clone()) { + return Err(CorpusContractError::new( + CorpusContractErrorKind::DuplicateCaseId, + )); + } + + let fields = map_entries(value, CorpusContractErrorKind::CaseClosureInvalid)?; + if fields.len() != 3 { + return Err(CorpusContractError::new( + CorpusContractErrorKind::CaseClosureInvalid, + )); + } + let outcome = map_entries( + required_field(fields, "requiredOutcome")?, + CorpusContractErrorKind::OutcomeClosureInvalid, + )?; + if outcome.len() != 2 { + return Err(CorpusContractError::new( + CorpusContractErrorKind::OutcomeClosureInvalid, + )); + } + + let contract = ExecutableContract::parse(required_text(outcome, "contract")?)?; + if !contracts.insert(contract) { + return Err(CorpusContractError::new( + CorpusContractErrorKind::DuplicateContract, + )); + } + let case = DeclaredCase { + id: case_id.clone(), + crossing: required_text(fields, "crossing")?.to_owned(), + stimulus: required_text(fields, "stimulus")?.to_owned(), + required_disposition: required_text(outcome, "disposition")?.to_owned(), + contract, + }; + if !case.matches_expected() { + return Err(CorpusContractError::new( + CorpusContractErrorKind::DeclarationMismatch, + )); + } + declared.push(case); + } + declared.sort_unstable_by(|left, right| left.id.cmp(&right.id)); + Ok(declared) +} + +fn map_entries( + value: &CanonicalValue, + kind: CorpusContractErrorKind, +) -> Result<&[(CanonicalValue, CanonicalValue)], CorpusContractError> { + let CanonicalValue::Map(entries) = value else { + return Err(CorpusContractError::new(kind)); + }; + Ok(entries) +} + +fn required_field<'a>( + entries: &'a [(CanonicalValue, CanonicalValue)], + field: &str, +) -> Result<&'a CanonicalValue, CorpusContractError> { + let mut matches = entries.iter().filter_map(|(key, value)| { + (key == &CanonicalValue::Text(field.to_owned())).then_some(value) + }); + let Some(value) = matches.next() else { + return Err(CorpusContractError::new( + CorpusContractErrorKind::FieldInvalid, + )); + }; + if matches.next().is_some() { + return Err(CorpusContractError::new( + CorpusContractErrorKind::FieldInvalid, + )); + } + Ok(value) +} + +fn required_text<'a>( + entries: &'a [(CanonicalValue, CanonicalValue)], + field: &str, +) -> Result<&'a str, CorpusContractError> { + let CanonicalValue::Text(value) = required_field(entries, field)? else { + return Err(CorpusContractError::new( + CorpusContractErrorKind::FieldInvalid, + )); + }; + Ok(value) +} diff --git a/tests/edict-provider-host-v1/tests/support/mod.rs b/tests/edict-provider-host-v1/tests/support/mod.rs new file mode 100644 index 00000000..f01c6508 --- /dev/null +++ b/tests/edict-provider-host-v1/tests/support/mod.rs @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 +// © James Ross Ω FLYING•ROBOTS + +pub mod conformance; diff --git a/xtask/src/provider_lowerer_component.rs b/xtask/src/provider_lowerer_component.rs index c567c794..6c8f2f3d 100644 --- a/xtask/src/provider_lowerer_component.rs +++ b/xtask/src/provider_lowerer_component.rs @@ -53,7 +53,7 @@ const PINNED_CARGO_COMMIT: &str = "840b83a10fb0e039a83f4d70ad032892c287570a"; /// Reviewed identity that the portable promotion command is permitted to install. pub(crate) const APPROVED_CHECKED_COMPONENT_SHA256: &str = - "9b5ecf1c87a4a98ad3d7381d85e3625649a4f9d62f80f74b2aca6ace26be14af"; + "f2063b66798fbb1c2b27c3af56e4b78184ffc22c9ed9c7a32c483d05b8c1d382"; pub(crate) const CHECKED_COMPONENT_REPOSITORY_PATH: &str = "schemas/edict-provider/components/v1/lowerer.echo-dpo.component.wasm"; @@ -62,7 +62,7 @@ pub(crate) const VERIFIER_CHECKED_COMPONENT_REPOSITORY_PATH: &str = "schemas/edict-provider/components/v1/verifier.echo-dpo.component.wasm"; /// Approved SHA-256 identity of the checked verifier component. pub(crate) const APPROVED_CHECKED_VERIFIER_COMPONENT_SHA256: &str = - "4f99c07f1c6d682405945fbb3e36e5537b94c4a01bd1a4ec7f02ef8e9911249a"; + "632cc5134861c0b31ccc9ca77d4a09fe757094964369d057b62ca6ba6ad38ad7"; #[derive(Clone, Copy, Debug, Eq, PartialEq)] struct ProviderComponentSpec {