test(contract): cover the Verified attestation path cross-contract in sandbox - #4085
test(contract): cover the Verified attestation path cross-contract in sandbox#4085pbeza wants to merge 7 commits into
Conversation
|
PR title type suggestion: This PR modifies source code files in Suggested title: |
There was a problem hiding this comment.
Pull request overview
Adds end-to-end, gas-metered sandbox coverage for the async attestation flow reaching a Verified verdict through the real tee-verifier contract (including cross-contract callback propagation), using a cfg-gated hook to pin verifier time for fixture validity. Also updates E2E cluster startup to deploy and vote in tee-verifier for topology parity with production, and refreshes docs/build plumbing accordingly.
Changes:
- Introduce
tee-verifiersandbox-test-hooksfeature to optionally read a pinned “now” timestamp from storage in sandbox-only builds. - Add sandbox (near-workspaces) tests that deploy/vote in the real verifier, whitelist fixture measurements, and assert Verified verdict propagation + gas budgeting (with store-path tests
#[ignore]pending fixture secret key). - Update E2E cluster startup, CI, build tasks, and docs to consistently build/deploy/vote in the verifier.
Reviewed changes
Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| Makefile.toml | Ensures tee-verifier WASM is built for E2E runs and exported via env var. |
| .github/workflows/ci.yml | Adds an explicit CI step to build the tee-verifier WASM. |
| crates/tee-verifier/Cargo.toml | Adds sandbox-test-hooks feature flag. |
| crates/tee-verifier/src/lib.rs | Implements pinned-time hook (feature-gated) and routes verify_quote timestamp via helper. |
| crates/tee-verifier-interface/src/lib.rs | Exposes the shared storage key constant used to pin verifier time in sandbox tests. |
| crates/contract/tests/sandbox/utils/contract_build.rs | Adds a builder path for verifier WASM with sandbox test hooks enabled. |
| crates/contract/tests/sandbox/utils/mpc_contract.rs | Adds typed get_verified_attestation and a vote helper for OS measurements. |
| crates/contract/tests/sandbox/tee_verifier.rs | Adds Verified cross-contract sandbox tests and related setup utilities (with store-path tests ignored pending fixture key). |
| crates/test-utils/src/attestation.rs | Adds runtime-loaded fixture account secret key accessor for sandbox signing (pending asset). |
| crates/test-utils/assets/README.md | Documents adding the fixture account secret key asset and how it’s used by sandbox tests. |
| crates/test-utils/assets/create-assets.sh | Warns when the secret-key asset is missing during asset extraction. |
| crates/e2e-tests/src/cluster.rs | Deploys and votes in tee-verifier at cluster startup; adds verifier WASM loading helper. |
| crates/e2e-tests/README.md | Documents new cluster startup step and config field. |
| crates/e2e-tests/Cargo.toml | Adds sha2 dependency for verifier code-hash computation. |
| Cargo.lock | Records the new sha2 dependency resolution. |
| docs/localnet/localnet.md | Updates verifier docs to reference new cross-contract sandbox coverage. |
| docs/deploy-tee-verifier.md | Updates verifier deploy docs to reference cross-contract sandbox coverage. |
| docs/design/attestation-verifier-contract.md | Updates design doc to reflect the shipped approach (real verifier + sandbox hook), not a stub verifier. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for &i in participant_indices { | ||
| let account = format!("node{i}.{SANDBOX_ROOT_ACCOUNT}"); | ||
| let client = blockchain.client_for(&account, &operator_keys[i])?; | ||
| let outcome = contract |
There was a problem hiding this comment.
Fixed at the root instead: MpcClusterConfig::validate() now bounds-checks initial_participant_indices, mirroring the existing migration_targets check. That also covers the same indexing in init_contract and add_initial_domains, which predate this PR.
|
PR title type suggestion: This PR adds new source code modules (tee-verifier-interface, tee-verifier). Since non-test source code files are changed, the type prefix should be |
Pull request overviewCloses the last gap in cross-contract attestation coverage: the Changes:
Reviewed changesPer-file summary
FindingsBlocking (must fix before merge):
Non-blocking (nits, follow-ups, suggestions):
|
03a9d59 to
63e2f8f
Compare
|
PR title type suggestion: This PR modifies source code files across multiple crates (tee-verifier-interface, tee-verifier, test-utils, e2e-tests), so the type prefix should be Suggested title: |
…tion The MPC node generates its NEAR signer key inside the enclave and writes it only to the CVM's encrypted disk. Collecting test assets needs that key alongside the quote it is bound to, and an app-compose pre-launch script is the only way in: the dev image ships no sshd and the guest agent serves only node info and container logs. vmm-cli already supports --prelaunch-script; this just plumbs an optional PRELAUNCH_SCRIPT through. Attestation verification rejects any app-compose carrying a script, so a CVM deployed this way cannot join a network - the deploy guide, default.env and the script itself now say so loudly.
Collecting the attestation fixtures requires a pre-launch script to export the node's in-enclave signer key, which makes the resulting app-compose one that production verification rejects as arbitrary root code. The new allow-pre-launch-script feature relaxes exactly that field for test builds; init_script and bash_script stay rejected, and the production wasm never enables it. The check takes the policy as an argument so the strict behaviour keeps its unit test in test builds too, and a further test pins the compiled-in policy at the call site.
…ner key Regenerated from a fresh localnet CVM on a TDX host, keeping the node's NEAR signer key this time so tests can sign submit_participant_info as the fixture node. The quote's report_data binds that key and the contract reads it from the transaction signer, so without it the Verified store path is unreachable (#3787). create-assets.sh had been producing collateral our own parser cannot read since the tee-verifier-interface refactor: nodes serialize the DER and signature fields as JSON byte arrays while collateral_from_json expects hex strings. It now hex-encodes those fields, and strips the NUL that terminates the PEM chains so the fixture stays valid PEM. The regeneration reminder is unconditional, since the committed key is normally present but stale. .editorconfig no longer asserts the borsh fixture's final byte: it is whatever the encoded collateral ends with.
…ation time Sandbox chain time is wall-clock and forward-only, so it can never fall inside the validity window of a checked-in collateral fixture. Under the new test-only feature, verify_quote prefers a pinned timestamp read from a well-known storage key that tests write via state patching; the production build reads no storage at all. The key constant lives in tee-verifier-interface so caller test suites can share it without depending on the contract crate.
… sandbox Drives the async submit_participant_info flow against the real deployed tee-verifier for every verdict: Rejected with a malformed quote, no-verdict with an undeployed verifier account, and Verified with the fixture quote against a verifier built with sandbox-test-hooks, whose clock the test pins to the fixture's validity window. Covers what the Verified path unlocks: the attestation stores with storage charged to the contract, the TlsKeyOwnedByOtherAccount guard rejects a second account claiming the same TLS key, and real dcap-qvl runs within the production verifier_tera_gas budget with headroom to spare (measured at 175.7 of 200 Tgas). The budget is read from the contract's config view so it cannot drift from DEFAULT_VERIFIER_TERA_GAS. Storing a first attestation for a TLS key consumes a prepaid storage grant, so the tests fund one from a separate payer, leaving the submitter's balance clean for the only-gas-spent assertions. Closes #3787
Mirrors the production topology (cf. scripts/launch-localnet.sh). Nodes in e2e clusters submit mock attestations, which the MPC contract verifies without calling the verifier, so the verifier stays idle; the cross-contract flow is covered at the sandbox layer. The vote-resolution check polls because views can briefly lag final votes, and MpcClusterConfig::validate now bounds-checks initial_participant_indices, which also covers the pre-existing indexing in init_contract and add_initial_domains.
The design doc's Testing section described a stub verifier that was built and then dropped during implementation; it now states the shipped approach, with a status note recording the supersession. The two verifier runbooks gain a pointer to the cross-contract sandbox coverage alongside the existing unit test.
63e2f8f to
48b09eb
Compare
|
PR title type suggestion: This PR changes core library source files in addition to tests (attestation, tee-verifier, etc.), so the type prefix should probably be Suggested title: |
|
Superseded by #4109 (fixtures, to main) and #4110 (cross-contract sandbox tests, stacked on it). Re-sliced so the fixture regeneration lands first. That removes the awkward step this PR had: it landed three Same content otherwise, rebased onto current main and re-verified. Review comments here remain readable; the code they point at moved to #4109 or #4110. |
Closes #4084