Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 28 additions & 0 deletions artifacts/cybersecurity/goals-and-requirements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1318,3 +1318,31 @@ artifacts:
links:
- type: verifies
target: CD-18

- id: CD-19
type: cybersecurity-design
title: BuildEnvironment capture and SLSA embedding
status: draft
description: >
BuildEnvironment struct auto-detecting rustc, cargo, Bazel, wasm-tools
versions, Nix flake lock hash, and host platform. Embeds as SLSA
provenance internalParameters. Supports both auto-detection and
CI environment variable configuration via WSC_* prefix.
links:
- type: refines
target: CR-4

- id: CV-27
type: cybersecurity-verification
title: Build environment capture and serialization tests
status: draft
description: >
Test that BuildEnvironment::capture() detects available tools,
from_env_vars() reads WSC_* variables, to_slsa_internal_params()
produces valid JSON, and serialization roundtrips correctly.
fields:
method: test
tool: cargo-test
links:
- type: verifies
target: CD-19
16 changes: 16 additions & 0 deletions artifacts/dev/features.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,19 @@ artifacts:
links:
- type: satisfies
target: FEAT-3

- id: REQ-13
type: requirement
title: Build environment metadata in SLSA provenance
status: approved
description: >
Attestation chain must capture build environment metadata including
Rust compiler version, Bazel version, Nix flake lock hash, and
host platform as SLSA provenance internal parameters. Addresses
Ferrocene RUSTC_CSTR_0030 for tool version verification.
fields:
priority: must
category: non-functional
links:
- type: satisfies
target: FEAT-4
65 changes: 65 additions & 0 deletions src/cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,22 @@ fn start() -> Result<(), WSError> {
.help("Type of transformation"),
),
)
.subcommand(
Command::new("build-env")
.about("Capture and display build environment attestation")
.arg(
Arg::new("json")
.long("json")
.action(ArgAction::SetTrue)
.help("Output as JSON (for embedding in SLSA provenance)"),
)
.arg(
Arg::new("from-env")
.long("from-env")
.action(ArgAction::SetTrue)
.help("Read versions from WSC_* environment variables"),
),
)
.get_matches();

let verbose = matches.get_flag("verbose");
Expand Down Expand Up @@ -997,6 +1013,55 @@ fn start() -> Result<(), WSError> {
handle_verify_chain_command(matches)?;
} else if let Some(matches) = matches.subcommand_matches("attest") {
handle_attest_command(matches)?;
} else if let Some(matches) = matches.subcommand_matches("build-env") {
let json_output = matches.get_flag("json");
let from_env = matches.get_flag("from-env");

let env = if from_env {
wsc::build_env::BuildEnvironment::from_env_vars()
} else {
wsc::build_env::BuildEnvironment::capture()
};

if json_output {
let json = serde_json::to_string_pretty(&env)
.map_err(|e| WSError::InternalError(format!("JSON serialization failed: {}", e)))?;
println!("{}", json);
} else {
println!("Build Environment Attestation");
println!("=============================");
if let Some(ref v) = env.rustc_version {
println!(" rustc: {}", v);
}
if let Some(ref v) = env.cargo_version {
println!(" cargo: {}", v);
}
if let Some(ref v) = env.bazel_version {
println!(" bazel: {}", v);
}
if let Some(ref v) = env.wasm_tools_version {
println!(" wasm-tools: {}", v);
}
if let Some(ref v) = env.nix_flake_lock_hash {
println!(" nix lock: {}", v);
}
if let Some(nix) = env.nix_build {
println!(" nix shell: {}", nix);
}
if let Some(ref v) = env.host_platform {
println!(" platform: {}", v);
}
if let Some(ref v) = env.os_version {
println!(" os: {}", v);
}
for (tool, version) in &env.additional_tools {
let pad = " ".repeat(11usize.saturating_sub(tool.len()));
println!(" {}:{}{}", tool, pad, version);
}
if env.is_reproducible() {
println!("\n [reproducible: nix flake lock pinned]");
}
}
} else {
return Err(WSError::UsageError("No subcommand specified"));
}
Expand Down
Loading
Loading