Skip to content

Add --verifiable flag to stellar contract build#2585

Draft
fnando wants to merge 19 commits into
mainfrom
contract-build-verifiable
Draft

Add --verifiable flag to stellar contract build#2585
fnando wants to merge 19 commits into
mainfrom
contract-build-verifiable

Conversation

@fnando

@fnando fnando commented May 22, 2026

Copy link
Copy Markdown
Member

What

Adds a --verifiable flag to stellar contract build that 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.

New flags, all grouped under a Verifiable help section:

  • --verifiable — opt in to the reproducible build mode; implies --locked, infers --package (the default-member cdylib contracts) when omitted, and requires a clean git working tree.
  • --image — override the auto-selected container image. Must be digest-pinned (...@sha256:...); tag-only refs are rejected so bldimg stays content-addressed.
  • --source-sha256 — SEP-58 source identification: 64-char SHA-256 of the source. Optional — the archive is always generated and its SHA-256 computed for you. When supplied it acts as a pin: the build fails if it doesn't match the generated archive.
  • --source-uri — SEP-58 source identification: URI where the source can be obtained (any scheme, e.g. https://example.com/src.tar.gz). Optional.
  • -d/--docker-host (also reads DOCKER_HOST) — override the docker daemon endpoint.

A --verifiable build always generates the reproducible source archive, records its SHA-256 as source_sha256, writes a content-addressed copy to the data dir's archives/<sha256>.tar.gz, and builds from the extracted (permission-hardened) copy so the WASM comes from exactly the bytes that were hashed. In a git repo the archive is git archive HEAD; otherwise the working directory is archived, skipping common build/VCS/editor/AI/secret entries.

Each contract — explicit --package or inferred — is built with its own --package, which is forwarded to the build and recorded as a bldopt, so every WASM is independently reproducible and stable even if the workspace's default members change later. Multi-contract workspaces build every contract in a single container so the crates download, compiled dependencies, and target/ are shared.

Every bldopt is recorded as valid shell syntax: each build option is shell-escaped once at the source, quoting only the value side, so a verifier can join the recorded bldopts and replay the exact invocation through a shell. A flag like --env B='this is very nice' is stored as --env=B='this is very nice' (flag and key outside the quotes), which round-trips back to the original argument. Run with --verbose to print the full docker run … command the build executes (the same command surfaced in the error message if the container build fails).

--env NAME=VALUE

Some contracts read environment variables at build time (build scripts, proc-macros, env!). --env (repeatable) sets them for the build and lives on the shared build options, so contract build, deploy, and upload all accept it:

  • Without --verifiable it's set on the local build process.
  • With --verifiable it's passed to the container (docker -e) and recorded as its own bldopt (shell-escaped, e.g. --env=B='this is very nice') so a verifier replays the same build. Because it's embedded in the WASM meta, avoid secrets here.

Names are validated ([A-Za-z_][A-Za-z0-9_]*); values are kept verbatim.

stellar contract archive

A standalone command to generate — or inspect — the same reproducible archive a verifiable build uses, sharing the exact byte-generation logic so the output is identical:

  • -o/--out-file <PATH> — write the gzipped tarball. Must end in .tar.gz or .tgz. Required unless --dry-run.
  • --manifest-path — locate the source root (its enclosing git repo, or the working directory).
  • --dry-run — list the entries that would be archived plus the computed source_sha256, without writing anything. Handy for confirming contents before a verifiable build, or for producing the artifact to host at a --source-uri.

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, and the source archive (auto-generated on build, or produced/inspected via stellar contract archive) closes the loop by being the exact artifact that source_sha256 refers to.

Known limitations

  • The verify side (download source_uri, check source_sha256, rebuild, byte-compare) is not part of this PR.
  • A purely local docker image can't be used directly; reference it by digest (e.g. via a local registry).

@github-project-automation github-project-automation Bot moved this to Backlog (Not Ready) in DevX May 22, 2026
@fnando fnando moved this from Backlog (Not Ready) to In Progress in DevX May 22, 2026
@fnando fnando self-assigned this May 22, 2026
@fnando fnando force-pushed the contract-build-verifiable branch from bdca27b to 629046f Compare June 17, 2026 02:55
@socket-security

socket-security Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcargo/​tar@​0.4.4610010093100100

View full report

@fnando fnando force-pushed the contract-build-verifiable branch from 9765c11 to 557647b Compare June 17, 2026 19:26
@fnando fnando force-pushed the contract-build-verifiable branch from 557647b to 6e7c125 Compare June 17, 2026 19:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant