Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Adds SEP-58 reproducible contract builds and source archive generation.
Changes:
- Adds
--verifiablebuild flags and provenance metadata. - Adds deterministic source archiving and
contract archive. - Extends container execution, artifact handling, tests, and documentation.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
FULL_HELP_DOCS.md |
Documents new commands and flags. |
cmd/soroban-cli/src/config/locator.rs |
Adds recursive permission hardening. |
cmd/soroban-cli/src/config/data.rs |
Adds managed archive storage. |
cmd/soroban-cli/src/commands/mod.rs |
Adds verifiable help heading. |
cmd/soroban-cli/src/commands/contract/mod.rs |
Registers archive command. |
cmd/soroban-cli/src/commands/contract/build/verifiable.rs |
Implements verifiable builds. |
cmd/soroban-cli/src/commands/contract/build/source_archive.rs |
Implements reproducible archives. |
cmd/soroban-cli/src/commands/contract/build/container.rs |
Shares container and artifact logic. |
cmd/soroban-cli/src/commands/contract/build.rs |
Adds flags and dispatch. |
cmd/soroban-cli/src/commands/contract/archive.rs |
Implements archive CLI. |
cmd/soroban-cli/src/commands/container/shared.rs |
Adds streamed image pulling. |
cmd/soroban-cli/Cargo.toml |
Adds archive dependencies. |
cmd/crates/soroban-test/tests/it/build.rs |
Adds integration coverage. |
Cargo.lock |
Locks dependency updates. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
d58a8a7 to
fce6107
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 14 changed files in this pull request and generated 1 comment.
Suppressed comments (6)
cmd/soroban-cli/src/commands/contract/build/container.rs:304
- Metadata keys are accepted as arbitrary strings by
parse_meta_arg, but this records the key unescaped. A key containing whitespace makes the stampedbldoptsplit into multiple shell words, and shell metacharacters such as;can execute commands when a verifier replays the joined options. Escape the key portion as well as the value (or reject non-shell-safe metadata keys).
bldopts.push(format!("{key}={}", shell_escape::escape(v.into())));
cmd/soroban-cli/src/commands/contract/build/container.rs:760
- The container is explicitly forced to write to
/source/targetviaCARGO_TARGET_DIR, so using the host metadata target here breaks collection whenever the host hasCARGO_TARGET_DIRor a configuredtarget-dir. Plain builds then return a missing/stale path; for verifiable builds an absolute metadata path also causesjointo discard the extracted root and can select an old host WASM instead of the newly built artifact. Collect from the forcedtargetdirectory.
let host_target = md.target_directory.as_std_path();
cmd/soroban-cli/src/commands/contract/build/source_archive.rs:207
- This filter silently omits every symlink, including Git-tracked symlinked files and directories. Such links are part of the source tree and may be required by path dependencies or build scripts, so the archived source can fail to build or differ from the committed source. Preserve safe symlink entries deterministically, or reject them explicitly instead of dropping them.
if entry.file_type().is_some_and(|t| t.is_file()) {
files.push(entry.path().to_path_buf());
}
cmd/soroban-cli/src/commands/contract/build/verifiable.rs:309
- Hardening the extracted tree through this helper changes every file to mode
0600, removing executable bits from Git-tracked helper scripts. A contract whose build script invokes an executable from the repository will build normally but fail only in verifiable mode. Use source-specific hardening that preserves the owner execute bit while removing group/other access; keep config files at0600.
enforce_hardened_tree(tmp.path()).map_err(source_archive::Error::ArchiveExtract)?;
cmd/soroban-cli/src/commands/contract/build/source_archive.rs:129
- Every nonzero
git statusresult is treated as “not a repository.” Failures in a real repository (for example corrupt metadata, ownership checks, or configuration errors) therefore bypass the clean-tree requirement and allow an unverified working tree to be archived. First determine whether this is a work tree, and propagate status failures for repositories; only the explicit non-repository case should proceed.
// Not a git repo (or git refused): can't verify cleanliness, proceed.
if !status.status.success() {
return Ok(false);
}
cmd/soroban-cli/src/commands/contract/build/verifiable.rs:147
- The documented contract says
--verifiableimplies--locked, but this branch knowingly performs an unlocked build. That can update dependency resolution relative to the archived lockfile, so the stamped source/image inputs no longer guarantee the advertised reproducibility. Reject images older than the--lockedminimum for verifiable builds instead of degrading to an unlocked build.
} else {
print.warnln(
"The build image's `contract build` does not support --locked; \
building without it. Dependency drift may affect reproducibility.",
);
}
fce6107 to
4988080
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 14 changed files in this pull request and generated 3 comments.
Suppressed comments (2)
cmd/soroban-cli/src/commands/contract/build/container.rs:304
- Only escaping
vdoes not make every recorded option valid shell syntax becauseparse_meta_argallows metadata keys containing spaces or shell metacharacters. For example,--meta 'my key=value'is forwarded as one argv item but recorded as--meta=my key=value, which splits into two arguments during replay. Escape the key segment as well so the recorded bldopt round-trips.
bldopts.push(format!("{key}={}", shell_escape::escape(v.into())));
cmd/soroban-cli/src/commands/contract/build/verifiable.rs:149
- A verifiable build is documented to imply
--locked, but an older pinned image reaches this branch and the build continues without it. That permits dependency resolution to drift between the original build and a verifier's replay, defeating the reproducibility guarantee. Please reject images whose CLI does not support--lockedinstead of producing a “verifiable” artifact without it.
} else {
print.warnln(
"The build image's `contract build` does not support --locked; \
building without it. Dependency drift may affect reproducibility.",
);
4988080 to
f1ab06b
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 14 changed files in this pull request and generated 3 comments.
Suppressed comments (1)
cmd/soroban-cli/src/commands/contract/build/container.rs:304
- SEP-58 defines each
bldoptas one value passed verbatim as an argv argument (“as if single-quoted”), not as shell source to evaluate. Escaping onlyvstores literal quote characters: an original--meta=note=added on buildis recorded as--meta=note='added on build', so a conforming verifier passes the apostrophes into the metadata value and cannot reproduce the WASM. Record the raw{key}={v}argument instead, and update the shell-roundtrip test/documentation accordingly.
bldopts.push(format!("{key}={}", shell_escape::escape(v.into())));
f1ab06b to
42db3e5
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 14 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
cmd/soroban-cli/src/commands/contract/build/source_archive.rs:127
git status --porcelainhides files ignored by global excludes,.git/info/exclude, and parent ignore files. The archive walker explicitly disables those sources, so a machine-local file such as a globally ignored.envcan pass this “clean tree” gate and then be included and persisted in the archive. Validate cleanliness against the actual selected archive entries (for example, reject selected files that are not tracked) so local ignored files cannot leak or makesource_sha256machine-specific.
.arg("status")
.arg("--porcelain")
42db3e5 to
434b938
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Recorded build options and failure reproduction commands currently cannot reliably reproduce the original build.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 9/9 changed files
- Comments generated: 2
- Review effort level: Balanced
| if let Some(v) = value { | ||
| args.push(format!("{key}={v}")); | ||
| if record_bldopts { | ||
| bldopts.push(format!("{key}={}", shell_escape::escape(v.into()))); |
| container::run_in_container( | ||
| &image_ref, | ||
| &resolved.mount_root, | ||
| &container_cmds, | ||
| &env, |
What
Adds a
--verifiableflag tostellar contract buildthat performs a reproducible build inside a digest-pinned Docker container and stamps SEP-58 metadata (bldimg,source_uri,source_sha256,bldopt) into the resulting WASM so third parties can re-run the build and verify the output byte-for-byte. The container connection/resource flags are the existing container-build arguments, reused here.A
--verifiablebuild always generates the reproducible source archive (the same generator #2731 exposes asstellar contract archive), records its SHA-256 assource_sha256, writes a content-addressed copy to the data dir'sarchives/<sha256>.tar.gz, and builds from the extracted (permission-hardened) copy so the WASM comes from exactly the bytes that were hashed. Each contract is built with its own--package, forwarded to the build and recorded as abldopt, so every WASM is independently reproducible; multi-contract workspaces build in a single container to share the crates download andtarget/. Everybldoptis recorded as valid shell syntax so a verifier can replay the exact invocation.Why
SEP-58 defines how to verify that a deployed contract WASM came from a specific source built with a specific toolchain image. Until now the CLI had no built-in way to produce such a build — users had to assemble the docker invocation, run cargo inside it, and stamp the custom sections by hand. This makes it a first-class option on
stellar contract build, building on the reproducible source archive from #2731.