Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
bdceeed
feat(cvm-deployment): optional PRELAUNCH_SCRIPT for test-asset collec…
pbeza Aug 10, 2026
a695d74
test(attestation): feature-gate the pre-launch-script rejection
pbeza Aug 10, 2026
782e500
test(test-utils): regenerate attestation fixtures with a retained sig…
pbeza Aug 10, 2026
6926a00
test(attestation): enable the script relaxation explicitly, and guard…
pbeza Aug 10, 2026
9373733
refactor(attestation): gate the pre-launch-script check on a named const
pbeza Aug 10, 2026
867dc5b
test(test-utils): simplify the collateral extraction in create-assets.sh
pbeza Aug 10, 2026
69c7f1a
chore(mpc-attestation): restore cargo sort formatting of the abi feat…
pbeza Aug 10, 2026
15850ee
test(attestation): address review on the fixture app-compose test
pbeza Aug 10, 2026
f70bbe7
chore(attestation): drop the feature-leak guard script
pbeza Aug 11, 2026
713691b
chore(editorconfig): drop the borsh final-newline comment
pbeza Aug 11, 2026
d456633
test(localnet): commit the key-export hook used to collect the fixtures
pbeza Aug 11, 2026
a7d0e11
test(test-utils): regenerate the fixtures with the simplified export …
pbeza Aug 11, 2026
cb66673
Merge remote-tracking branch 'origin/main' into 3787-regenerate-fixtures
pbeza Aug 11, 2026
cb51a9e
chore(localnet): pass `PRELAUNCH_SCRIPT` as an absolute path
pbeza Aug 11, 2026
5fa0480
test: note which tests require `allow-pre-launch-script`
pbeza Aug 11, 2026
e26eb67
chore: enable `allow-pre-launch-script` only for test builds
pbeza Aug 11, 2026
19c0f66
Merge remote-tracking branch 'origin/main' into 3787-regenerate-fixtures
pbeza Aug 13, 2026
7062936
refactor: export the fixture signer key through the launcher compose
pbeza Aug 13, 2026
2f71c86
test(test-utils): derive the fixture public key when checking the pair
pbeza Aug 13, 2026
46a1331
Merge remote-tracking branch 'origin/main' into 3787-regenerate-fixtures
pbeza Aug 13, 2026
9ace193
Merge remote-tracking branch 'origin/main' into 3787-regenerate-fixtures
pbeza Aug 13, 2026
246c1e6
docs: fix the fixture-collection hand-off and trim the asset docs
pbeza Aug 13, 2026
bf56c7e
Merge remote-tracking branch 'origin/main' into 3787-regenerate-fixtures
pbeza Aug 14, 2026
3118b2a
docs: address review wording on the asset and single-node readmes
pbeza Aug 14, 2026
d4c3017
feat(tee-verifier): add sandbox-test-hooks feature to pin the verific…
pbeza Aug 10, 2026
9ddafac
test(contract): cover the Verified attestation path cross-contract in…
pbeza Aug 10, 2026
c35887e
test(e2e): deploy and vote in the tee-verifier during cluster startup
pbeza Aug 10, 2026
3152d13
docs: align attestation testing docs with the shipped sandbox coverage
pbeza Aug 10, 2026
a43e53a
test(e2e): use call_from_with_deposit for the tee-verifier vote
pbeza Aug 10, 2026
f0a95b0
test(contract): whitelist the fixture compose hash from a sandbox-onl…
pbeza Aug 13, 2026
4e6f821
docs: correct the verifier storage claim and the E2E build inventory
pbeza Aug 13, 2026
7415a14
Merge remote-tracking branch 'origin/main' into 4084-verified-attesta…
pbeza Aug 14, 2026
432ae39
Merge remote-tracking branch 'origin/main' into 4084-verified-attesta…
pbeza Aug 14, 2026
fa72523
chore: make released wasm builds reject the sandbox test features
pbeza Aug 17, 2026
acaa563
docs: drop overclaimed invariants and refresh stale figures around th…
pbeza Aug 17, 2026
1f9153a
Merge remote-tracking branch 'origin/main' into 4084-verified-attesta…
pbeza Aug 17, 2026
5334692
refactor: keep the sandbox test switches out of released artifacts
pbeza Aug 17, 2026
0b79aff
Merge remote-tracking branch 'origin/main' into 4084-verified-attesta…
pbeza Aug 17, 2026
afce256
Merge remote-tracking branch 'origin/main' into 4084-verified-attesta…
pbeza Aug 17, 2026
a50819e
refactor(contract): move the state-patching helper into tee::test_utils
pbeza Aug 17, 2026
51fd510
refactor(test): shorten the verifier sandbox tests and their setup
pbeza Aug 17, 2026
6248374
Merge remote-tracking branch 'origin/main' into 4084-verified-attesta…
pbeza Aug 17, 2026
4c764ec
refactor(test): look up the fixture's stored attestation through one …
pbeza Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ jobs:
if: github.ref == 'refs/heads/main'
run: nix develop --command cargo near build reproducible-wasm --manifest-path crates/contract/Cargo.toml

- name: Build tee-verifier
run: nix develop --command cargo make build-tee-verifier-optimized

- name: Build test-parallel-contract
run: nix develop --command cargo make build-test-parallel-contract-optimized

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ time = "0.3.45"
[workspace.lints.rust]
unexpected_cfgs = { level = "allow", check-cfg = [
'cfg(feature, values("abi"))',
'cfg(mpc_sandbox_wasm)',
] }

[workspace.lints.clippy]
Expand Down
9 changes: 6 additions & 3 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ args = ["scripts/check-sandbox-image-version.sh"]

# These build tasks are the single source of truth for both local and CI builds.
# CI's `mpc-e2e-tests` job invokes them via `cargo make`.
# All three are skipped when `E2E_SKIP_BUILD` is set (used by `e2e-tests-skip-build`).
# Each is skipped when `E2E_SKIP_BUILD` is set (used by `e2e-tests-skip-build`).

[tasks.build-mpc-node-network-hardship-simulation]
description = "Build the mpc-node binary used by the E2E tests"
Expand Down Expand Up @@ -202,7 +202,8 @@ args = [
]

[tasks.build-tee-verifier-optimized]
description = "Build the tee-verifier WASM for localnet"
description = "Build the tee-verifier WASM for localnet and the E2E tests"
condition = { env_not_set = ["E2E_SKIP_BUILD"] }
command = "cargo"
args = [
"near",
Expand Down Expand Up @@ -252,6 +253,7 @@ private = true
dependencies = [
"build-mpc-node-network-hardship-simulation",
"build-mpc-contract-optimized",
"build-tee-verifier-optimized",
"build-test-parallel-contract-optimized",
"build-backup-cli",
]
Expand All @@ -272,8 +274,9 @@ args = [
[tasks._run-e2e-logic.env]
MPC_CONTRACT_WASM = "${CARGO_MAKE_WORKING_DIRECTORY}/target/near/mpc_contract/mpc_contract.wasm"
MPC_PARALLEL_CONTRACT_WASM = "${CARGO_MAKE_WORKING_DIRECTORY}/target/near/test_parallel_contract/test_parallel_contract.wasm"
MPC_TEE_VERIFIER_WASM = "${CARGO_MAKE_WORKING_DIRECTORY}/target/near/tee_verifier/tee_verifier.wasm"

# Build the mpc-node binary and both contract WASMs, then run the E2E tests.
# Build the mpc-node binary, the contract WASMs, and the backup CLI, then run the E2E tests.
[tasks.e2e-tests]
description = "Build required binaries and run the E2E tests"
run_task = "_run-e2e-logic"
Expand Down
2 changes: 1 addition & 1 deletion crates/contract/src/tee/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ impl AllowedLauncherImages {
/// Test-only: allows one more compose hash for an already-allowed launcher. The attestation
/// fixture is captured from a CVM whose launcher compose carries a key-export service, so
/// [`get_docker_compose_hash`] cannot derive its hash.
#[cfg(test)]
#[cfg(any(test, feature = "test-utils"))]
pub(crate) fn allow_compose_hash(
&mut self,
launcher_hash: &LauncherImageHash,
Expand Down
20 changes: 19 additions & 1 deletion crates/contract/src/tee/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
//! This module provides helper functions and types for testing TEE state,
//! attestation behavior, and general contract state management.

use crate::MpcContract;
use crate::primitives::test_utils::{gen_account_id, gen_seed};
use crate::tee::{measurements::ContractExpectedMeasurements, tee_state::TeeState};
use mpc_attestation::attestation::default_measurements;
use mpc_primitives::hash::{LauncherImageHash, NodeImageHash};
use mpc_primitives::hash::{LauncherDockerComposeHash, LauncherImageHash, NodeImageHash};
use near_account_id::AccountId;
use near_sdk::borsh::{self, BorshDeserialize};
use near_sdk::{BlockHeight, NearToken, PublicKey, test_utils::VMContextBuilder, testing_env};
use rand::Rng;
use std::time::Duration;
Expand Down Expand Up @@ -115,3 +117,19 @@ pub fn whitelist_dstack_measurements(
tee_state.add_measurement(ContractExpectedMeasurements::from(measurements));
}
}

/// Adds a [`LauncherDockerComposeHash`] to a [`LauncherImageHash`]'s allowlist entry in a
/// raw `STATE` blob, for sandbox tests to patch back in. The attestation fixture's compose
/// hash is not derivable from the compiled-in template, so no vote can allow it.
pub fn allow_launcher_compose_hash_in_state(
state: &[u8],
launcher_hash: &LauncherImageHash,
compose_hash: LauncherDockerComposeHash,
) -> Vec<u8> {
let mut contract = MpcContract::try_from_slice(state).expect("STATE deserializes");
contract
.tee_state
.allowed_launcher_images
.allow_compose_hash(launcher_hash, compose_hash);
borsh::to_vec(&contract).expect("STATE serializes")
}
48 changes: 23 additions & 25 deletions crates/contract/tests/sandbox/tee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::sandbox::{
consts::ALL_PROTOCOLS,
interface::IntoContractType,
mpc_contract::{
assert_running_return_participants, assert_running_return_threshold,
assert_running_return_participants, assert_running_return_threshold, get_config,
get_participant_attestation, get_state, get_tee_accounts,
prepay_and_submit_participant_info, prepay_attestation_grants, submit_participant_info,
vote_add_launcher_hash, vote_for_hash,
Expand All @@ -25,7 +25,7 @@ use mpc_primitives::hash::{LauncherDockerComposeHash, LauncherImageHash, NodeIma
use near_mpc_contract_interface::deposits::STORAGE_BYTE_COST_YOCTONEAR;
use near_mpc_contract_interface::method_names;
use near_mpc_contract_interface::types::{
self as dtos, Attestation, Config, MockAttestation, Protocol,
self as dtos, Attestation, MockAttestation, Protocol, VerifiedAttestation,
};
use near_workspaces::types::{KeyType, NearToken, SecretKey};
use near_workspaces::{AccessKey, Account, Contract};
Expand Down Expand Up @@ -595,10 +595,9 @@ async fn get_attestation_returns_none_when_tls_key_is_not_associated_with_an_att

assert!(validation_success);

let attestation_for_tls_key_2: Option<Attestation> =
get_participant_attestation(&contract, &tls_key_2)
.await
.unwrap();
let attestation_for_tls_key_2 = get_participant_attestation(&contract, &tls_key_2)
.await
.unwrap();

assert_eq!(attestation_for_tls_key_2, None);
}
Expand Down Expand Up @@ -637,12 +636,13 @@ async fn get_attestation_returns_some_when_tls_key_associated_with_an_attestatio
expected_measurements: None,
});

let participant_2_attestation = Attestation::Mock(MockAttestation::WithConstraints {
let participant_2_mock = MockAttestation::WithConstraints {
mpc_docker_image_hash: None,
launcher_docker_compose_hash: None,
expiry_timestamp_seconds: Some(now_seconds + 2_000),
expected_measurements: None,
});
};
let participant_2_attestation = Attestation::Mock(participant_2_mock.clone());

assert_ne!(
participant_1_attestation, participant_2_attestation,
Expand Down Expand Up @@ -671,12 +671,14 @@ async fn get_attestation_returns_some_when_tls_key_associated_with_an_attestatio
.is_success();
assert!(validation_success, "Submitting attestation failed.");

let attestation_for_tls_key_2: Option<Attestation> =
get_participant_attestation(&contract, &tls_key_2)
.await
.unwrap();
let attestation_for_tls_key_2 = get_participant_attestation(&contract, &tls_key_2)
.await
.unwrap();

assert_eq!(attestation_for_tls_key_2, Some(participant_2_attestation));
assert_eq!(
attestation_for_tls_key_2,
Some(VerifiedAttestation::Mock(participant_2_mock))
);
}

#[tokio::test]
Expand Down Expand Up @@ -705,12 +707,13 @@ async fn get_attestation_overwrites_when_same_tls_key_is_reused() {
expected_measurements: None,
});

let second_attestation = Attestation::Mock(MockAttestation::WithConstraints {
let second_mock = MockAttestation::WithConstraints {
mpc_docker_image_hash: None,
launcher_docker_compose_hash: None,
expiry_timestamp_seconds: Some(now_seconds + 2_000),
expected_measurements: None,
});
};
let second_attestation = Attestation::Mock(second_mock.clone());

assert_ne!(
first_attestation, second_attestation,
Expand Down Expand Up @@ -742,14 +745,13 @@ async fn get_attestation_overwrites_when_same_tls_key_is_reused() {
assert!(validation_success, "Second attestation submission failed");

// Now the latest attestation should be returned
let attestation_for_tls_key: Option<Attestation> =
get_participant_attestation(&contract, &tls_key)
.await
.unwrap();
let attestation_for_tls_key = get_participant_attestation(&contract, &tls_key)
.await
.unwrap();

assert_eq!(
attestation_for_tls_key,
Some(second_attestation),
Some(VerifiedAttestation::Mock(second_mock)),
"Expected the second attestation to overwrite the first for the same TLS key"
);
}
Expand Down Expand Up @@ -1088,11 +1090,7 @@ async fn prepay_and_submit_a_constrained_mock__should_use_at_most_half_a_grant_f
});
let node = worker.dev_create_account().await?;
let tls_key = bogus_ed25519_public_key();
let config: Config = contract
.view(method_names::CONFIG)
.args_json(serde_json::json!({}))
.await?
.json()?;
let config = get_config(&contract).await?;
let before = contract.as_account().view_account().await?;

// When
Expand Down
Loading