From c4141e0dee68251299e575512657204440b00aef Mon Sep 17 00:00:00 2001 From: Michel Paulissen <862400+MichelPaulissen@users.noreply.github.com> Date: Sat, 4 Jul 2026 10:22:53 +0200 Subject: [PATCH] Update public bundle metadata contract --- DISASMER_PUBLIC_TREE.json | 4 +- crates/disasmer-cli/src/main.rs | 93 ++++++++++++++++++++++++++++- crates/disasmer-core/src/bundle.rs | 80 ++++++++++++++++++++++++- crates/disasmer-core/src/lib.rs | 5 +- scripts/cli-first-contract-smoke.js | 15 +++++ scripts/cli-output-mode-smoke.js | 12 ++++ 6 files changed, 204 insertions(+), 5 deletions(-) diff --git a/DISASMER_PUBLIC_TREE.json b/DISASMER_PUBLIC_TREE.json index 783ca77..3d8d6ca 100644 --- a/DISASMER_PUBLIC_TREE.json +++ b/DISASMER_PUBLIC_TREE.json @@ -1,7 +1,7 @@ { "kind": "disasmer-filtered-public-tree", - "source_commit": "3313653a3d00fcd3fa5613e12cde2f76ae9a8ad0", - "release_name": "dryrun-3313653a3d00", + "source_commit": "b2b2e4a1b7c94ccc39c4d8cdfca6e98928fe2185", + "release_name": "dryrun-b2b2e4a1b7c9", "filtered_out": [ "private/**", "experiments/**", diff --git a/crates/disasmer-cli/src/main.rs b/crates/disasmer-cli/src/main.rs index d02c072..aceaf6c 100644 --- a/crates/disasmer-cli/src/main.rs +++ b/crates/disasmer-cli/src/main.rs @@ -4316,8 +4316,11 @@ fn bundle_inspection(args: BundleInspectArgs, cwd: PathBuf) -> Result, + pub default_entrypoint: String, pub environments: Vec, pub source_provider_manifest: Digest, + pub source_transfer_policy: SourceTransferPolicy, pub selected_inputs: Vec, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct BundleMetadata { pub identity: Digest, + pub wasm_code: Digest, + pub task_metadata: BundleTaskMetadata, + pub source_metadata: BundleSourceMetadata, + pub debug_metadata: BundleDebugMetadata, pub environments: Vec, pub selected_inputs: Vec, pub embeds_full_container_images: bool, } +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct BundleTaskMetadata { + pub task_abi: Digest, + pub entrypoints: Vec, + pub default_entrypoint: String, + pub boundary: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct BundleSourceMetadata { + pub source_provider_manifest: Digest, + pub transfer_policy: SourceTransferPolicy, + pub selected_inputs: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct BundleDebugMetadata { + pub available: bool, + pub source_level_breakpoints: bool, + pub dap_virtual_process: bool, + pub variables_pane_supported: bool, +} + impl BundleIdentityInputs { pub fn identity(&self) -> Digest { let mut parts = vec![ @@ -32,8 +62,16 @@ impl BundleIdentityInputs { self.wasm_code.as_str().as_bytes().to_vec(), self.task_abi.as_str().as_bytes().to_vec(), self.source_provider_manifest.as_str().as_bytes().to_vec(), + self.default_entrypoint.as_bytes().to_vec(), + format!("{:?}", self.source_transfer_policy).into_bytes(), ]; + let mut entrypoints = self.entrypoints.clone(); + entrypoints.sort(); + for entrypoint in entrypoints { + parts.push(entrypoint.into_bytes()); + } + let mut environments = self.environments.clone(); environments.sort_by(|left, right| left.name.cmp(&right.name)); for environment in environments { @@ -53,8 +91,29 @@ impl BundleIdentityInputs { } pub fn inspectable_metadata(&self) -> BundleMetadata { + let mut entrypoints = self.entrypoints.clone(); + entrypoints.sort(); + BundleMetadata { identity: self.identity(), + wasm_code: self.wasm_code.clone(), + task_metadata: BundleTaskMetadata { + task_abi: self.task_abi.clone(), + entrypoints, + default_entrypoint: self.default_entrypoint.clone(), + boundary: "disasmer_task_exports".to_owned(), + }, + source_metadata: BundleSourceMetadata { + source_provider_manifest: self.source_provider_manifest.clone(), + transfer_policy: self.source_transfer_policy.clone(), + selected_inputs: self.selected_inputs.clone(), + }, + debug_metadata: BundleDebugMetadata { + available: true, + source_level_breakpoints: true, + dap_virtual_process: true, + variables_pane_supported: true, + }, environments: self.environments.clone(), selected_inputs: self.selected_inputs.clone(), embeds_full_container_images: false, @@ -86,8 +145,11 @@ mod tests { let base = BundleIdentityInputs { wasm_code: Digest::sha256("wasm"), task_abi: Digest::sha256("abi"), + entrypoints: vec!["build".to_owned()], + default_entrypoint: "build".to_owned(), environments: vec![env("recipe-a")], source_provider_manifest: Digest::sha256("source"), + source_transfer_policy: SourceTransferPolicy::local_first_snapshot_chunks(), selected_inputs: vec![], }; let mut changed = base.clone(); @@ -101,8 +163,11 @@ mod tests { let inputs = BundleIdentityInputs { wasm_code: Digest::sha256("wasm"), task_abi: Digest::sha256("abi"), + entrypoints: vec!["build".to_owned(), "test".to_owned()], + default_entrypoint: "build".to_owned(), environments: vec![env("recipe")], source_provider_manifest: Digest::sha256("source"), + source_transfer_policy: SourceTransferPolicy::local_first_snapshot_chunks(), selected_inputs: vec![SelectedInput { path: "inputs/config.json".to_owned(), digest: Digest::sha256("config"), @@ -111,6 +176,19 @@ mod tests { let metadata = inputs.inspectable_metadata(); + assert!(metadata.wasm_code.as_str().starts_with("sha256:")); + assert_eq!(metadata.task_metadata.default_entrypoint, "build"); + assert!(metadata + .task_metadata + .entrypoints + .contains(&"test".to_owned())); + assert!(metadata.debug_metadata.dap_virtual_process); + assert!( + metadata + .source_metadata + .transfer_policy + .local_source_bytes_remain_node_local + ); assert_eq!(metadata.environments.len(), 1); assert!(!metadata.embeds_full_container_images); } diff --git a/crates/disasmer-core/src/lib.rs b/crates/disasmer-core/src/lib.rs index ece5b8c..36f213d 100644 --- a/crates/disasmer-core/src/lib.rs +++ b/crates/disasmer-core/src/lib.rs @@ -26,7 +26,10 @@ pub use auth::{ CliLoginFlow, CredentialKind, EnrollmentError, EnrollmentGrant, IdentityKind, NodeCredential, PublicKeyIdentity, Scope, }; -pub use bundle::{BundleIdentityInputs, BundleMetadata, SelectedInput}; +pub use bundle::{ + BundleDebugMetadata, BundleIdentityInputs, BundleMetadata, BundleSourceMetadata, + BundleTaskMetadata, SelectedInput, +}; pub use capability::{Capability, CapabilityReportError, EnvironmentBackend, NodeCapabilities, Os}; pub use checkpoint::{ CheckpointBoundary, CompatibilityFailure, RestartDecision, RestartPolicy, RestartRequest, diff --git a/scripts/cli-first-contract-smoke.js b/scripts/cli-first-contract-smoke.js index 9f4acfa..a019de4 100644 --- a/scripts/cli-first-contract-smoke.js +++ b/scripts/cli-first-contract-smoke.js @@ -376,6 +376,21 @@ expect( "CLI exposes environment pre-schedule diagnostics", /environment_diagnostics_for_inputs[\s\S]*diagnose_environment_references[\s\S]*missing_environment/ ); +expect( + cli, + "CLI bundle metadata exposes MVP build facets", + /BundleIdentityInputs[\s\S]*entrypoints[\s\S]*default_entrypoint[\s\S]*source_transfer_policy[\s\S]*wasm_source_proxy_digest[\s\S]*task_abi_digest/ +); +expect( + cli, + "CLI bundle coverage verifies Dockerfile and debug metadata", + /fn bundle_inspect_discovers_environments_selected_inputs_and_source_providers\(\)[\s\S]*envs\/docker\/Dockerfile[\s\S]*task_metadata[\s\S]*source_metadata[\s\S]*debug_metadata/ +); +expect( + cli, + "CLI build coverage verifies inspectable metadata", + /fn build_command_reuses_bundle_inspection_without_full_repo_upload\(\)[\s\S]*wasm_code[\s\S]*task_metadata[\s\S]*source_metadata[\s\S]*debug_metadata/ +); expect( cli, "CLI blocks build before scheduling unsafe inputs", diff --git a/scripts/cli-output-mode-smoke.js b/scripts/cli-output-mode-smoke.js index 0027dce..a73879b 100644 --- a/scripts/cli-output-mode-smoke.js +++ b/scripts/cli-output-mode-smoke.js @@ -89,5 +89,17 @@ assertHuman("bundle inspect", inspectHuman, [ const inspectJson = json(["bundle", "inspect", "--project", project, "--json"]); assert.strictEqual(inspectJson.project, project); assert.match(inspectJson.metadata.identity, /^sha256:/); +assert.match(inspectJson.metadata.wasm_code, /^sha256:/); +assert.strictEqual(inspectJson.metadata.task_metadata.default_entrypoint, "build"); +assert(inspectJson.metadata.task_metadata.entrypoints.includes("release")); +assert.strictEqual( + inspectJson.metadata.source_metadata.transfer_policy.coordinator_receives_source_bytes_by_default, + false +); +assert.strictEqual( + inspectJson.metadata.source_metadata.transfer_policy.default_full_repo_tarball, + false +); +assert.strictEqual(inspectJson.metadata.debug_metadata.dap_virtual_process, true); console.log("CLI output mode smoke passed");