diff --git a/evals/scenarios/smart-contracts/04-build-verification.json b/evals/scenarios/smart-contracts/04-build-verification.json new file mode 100644 index 0000000..3b80d76 --- /dev/null +++ b/evals/scenarios/smart-contracts/04-build-verification.json @@ -0,0 +1,15 @@ +{ + "skills": [ + "smart-contracts" + ], + "query": "I'm deploying my Soroban contract to mainnet next week. How do I make it so users can check that the deployed WASM really came from my GitHub repo?", + "expected_behavior": [ + "Points at SEP-55 build verification — source_repo metadata in the WASM plus a GitHub build attestation — rather than improvising a scheme like publishing the hash in the README", + "Names either stellar contract build --meta source_repo=github:/ or the soroban-build-workflow reusable workflow", + "If it reuses soroban-build-workflow, resolves the current release itself, reads release.yml at that commit rather than at the tag, and pins the full commit SHA rather than a version tag copied from documentation", + "Grants contents: write for publishing the release and id-token: write plus attestations: write for the attestation, without presenting all three as attestation requirements", + "Says to deploy the WASM attached to the release the workflow produced, because a local rebuild may not match the attested hash", + "States the limits: the source repo must be public to be checkable, and the attestation proves which workflow run and commit built the binary, not that the code is safe", + "Says the commit pin covers release.yml only, not the actions release.yml calls on mutable tags, rather than presenting the pin as closing the whole supply chain" + ] +} diff --git a/skills/smart-contracts/SKILL.md b/skills/smart-contracts/SKILL.md index 99903bd..f725145 100644 --- a/skills/smart-contracts/SKILL.md +++ b/skills/smart-contracts/SKILL.md @@ -186,6 +186,59 @@ stellar contract invoke \ To upload WASM without instantiating (e.g. for factories or upgrades), use `stellar contract upload` (the older `stellar contract install` is a deprecated alias). +## Verify your build + +Nothing on-chain ties a deployed WASM to its source. [SEP-0055](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0055.md) (Draft) closes that gap: build in GitHub Actions, stamp the source repository into the WASM's `contractmetav0` section, and publish a [GitHub build attestation](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations) over the binary — anyone can then walk from the on-chain WASM hash back to the commit and the workflow run that produced it. Verifiers read the attestation from `api.github.com/repos///attestations/sha256:` unauthenticated, so the source repository has to be public for that "anyone" to hold. On the Free, Pro, and Team plans a private or internal repo cannot publish an attestation at all. Enterprise Cloud can, but only accounts with repository access read it, so no user of your contract can. Make it a standard step before **any** mainnet deploy; it costs one workflow file, so there's no reason to reserve it for user-facing contracts. + +Two metadata entries carry it (`stellar contract build --meta key=value`, read back with `stellar contract info meta --wasm `): + +- `source_repo=github:/` — where the source lives +- `home_domain=` — domain serving your SEP-1 `stellar.toml`, for org/token lookup (optional; bare domain, no scheme or path) + +[soroban-build-workflow](https://github.com/stellar-expert/soroban-build-workflow) does the whole job — build with the metadata, optimize, attest, publish a release with the WASM attached, and register the build with stellar.expert's contract validation. + +Resolve its version yourself instead of copying a pin out of any documentation, this file included. Pins go stale, and the newest tag in that repo is not always a published release: + +```bash +REPO=stellar-expert/soroban-build-workflow +TAG=$(gh release view --repo "$REPO" --json tagName --jq .tagName) # latest release +SHA=$(gh api "repos/$REPO/commits/$TAG" --jq .sha) # its commit +gh api "repos/$REPO/contents/.github/workflows/release.yml?ref=$SHA" \ + -H "Accept: application/vnd.github.raw" # the file you will pin +``` + +Read `release.yml` at that SHA, never at the tag. A tag can move between the two steps, and then you review one commit and pin another. It should check out the tagged commit, build from source, and attest the same file it uploads. If it doesn't, stop and tell the user rather than pinning it anyway. Then pin that full SHA, because this workflow runs with your repository token, OIDC, and attestation permissions. + +Tell the user where that pin stops. It freezes `release.yml`, not the actions `release.yml` calls. Those sit on mutable tags of their own (`actions/checkout@v4`, the CLI, the attest action) and resolve at run time under the same permissions, and a caller cannot pin them. Fork the workflow if that residual risk is unacceptable. + +```yaml +# .github/workflows/release.yml — verified build on every version tag +name: Build and Release +on: + push: + tags: ["v*"] + +permissions: # inherited by the called workflow, which cannot elevate them + contents: write # create the release, attach the WASM + id-token: write # sign the attestation + attestations: write # publish it + +jobs: + release: + # the SHA you resolved and reviewed; keep the version in the comment + uses: stellar-expert/soroban-build-workflow/.github/workflows/release.yml@ # vX.Y.Z + with: + release_name: ${{ github.ref_name }} + home_domain: example.com # optional + package: my-contract # optional — omit to build the working directory + secrets: + release_token: ${{ secrets.GITHUB_TOKEN }} # created by GitHub, nothing to configure +``` + +Then deploy **the WASM attached to that release**, not a local rebuild — compilation environments vary, and a hash that differs by one byte matches no attestation. + +The result shows up in [Stellar Lab's contract explorer](https://developers.stellar.org/docs/tools/lab/smart-contracts/contract-explorer#build-info) and on stellar.expert. Be precise with users about what it proves: a specific workflow run built this binary from this commit. It says nothing about whether that code is safe or was ever reviewed. + ## Minimal test ```rust @@ -211,7 +264,7 @@ Auth mocking, event assertions, fuzzing, fork tests, and CI setup: [testing.md]( ## Before mainnet -Work through the checklists in [security.md](security.md) — authorization, reinitialization, arithmetic, storage TTLs, and cross-contract validation are the recurring failure modes. +Work through the checklists in [security.md](security.md) — authorization, reinitialization, arithmetic, storage TTLs, and cross-contract validation are the recurring failure modes. Ship the deploy through a [verified build](#verify-your-build) so the on-chain WASM hash traces back to a reviewable commit. ## Documentation diff --git a/skills/smart-contracts/security.md b/skills/smart-contracts/security.md index 75334df..aa56fe9 100644 --- a/skills/smart-contracts/security.md +++ b/skills/smart-contracts/security.md @@ -172,6 +172,7 @@ Any contract that takes a token address must assume it may be native XLM's SAC, - [ ] Events emitted for auditable state changes (and error codes never renumbered) - [ ] Upgrade path gated, tested (happy + failure), and replay-safe - [ ] Emergency controls (pause) and incident runbook defined for value-bearing contracts +- [ ] Deployed WASM traceable to its source — SEP-55 build metadata plus a GitHub attestation from a public repo, deployed from the release artifact ([SKILL.md](SKILL.md#verify-your-build)) ### Client-side diff --git a/skills/standards/SKILL.md b/skills/standards/SKILL.md index 9cae054..343b9ee 100644 --- a/skills/standards/SKILL.md +++ b/skills/standards/SKILL.md @@ -28,6 +28,7 @@ This file carries the SEP/CAP standards routing map. The other two live alongsid - Frontend SEP-7 / SEP-10 flows → `../dapp/SKILL.md` - CAPs for cryptography (BLS, BN254, Poseidon) → `../zk-proofs/SKILL.md` - x402/MPP protocol context → `../agentic-payments/SKILL.md` +- SEP-55 verified builds for mainnet contracts → `../smart-contracts/SKILL.md` ---