Skip to content

feat(release): automate per-crate releases and version contract artifacts (ENG-522)#528

Open
peer2f00l wants to merge 6 commits into
devfrom
feature/eng-522-standardize-the-release-cycle-cratesio-publishing-per-crate
Open

feat(release): automate per-crate releases and version contract artifacts (ENG-522)#528
peer2f00l wants to merge 6 commits into
devfrom
feature/eng-522-standardize-the-release-cycle-cratesio-publishing-per-crate

Conversation

@peer2f00l

@peer2f00l peer2f00l commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Closes ENG-522. Folds in ENG-362 (GPLv3 relicense).

Nothing in this workspace was released anywhere. templar-backend/services/blockchain-gateway pins seven crates to a raw dev commit because no release tag contains gateway/; tags used three naming schemes; the only GitHub Release was a draft. contract/artifacts stored one WASM blob per contract, overwritten in place — so gateway/testing/src/wasm.rs hand-hoarded five historical blobs as ad-hoc include_bytes! consts, outside the catalog and outside any drift check.

What this adds

Per-crate releases via release-plz. Every crate versions itself from its own commit history. Merging the standing "chore: release" PR is the trigger; an ordinary merge to dev ships nothing. Three tiers: published (the 17-crate closure consumers import), tagged-only (contracts, services, tools), internal (mocks, fuzz, scaffolding).

Immutable versioned WASM. res/near/<target>/<version>/. Releases are added, never rewritten — historical blobs are what the migration tests deploy. Drift checking goes from 2 checks to 5, and a tag workflow rebuilds each release reproducibly and requires a byte-for-byte match.

Commit conventions, documented in AGENTS.md and enforced by a PR-title lint, since squash-merge makes the PR title the commit that drives version inference.

Things worth knowing

crates.io publishing is configured but deferred. templar-common depends on the RedStone SDK as a git dependency, and Cargo refuses to publish any crate with one — on crates.io or a private registry. Every Tier A crate reaches templar-common. Consumers pin per-crate git tags meanwhile; unblocking is a config flip, no code changes. See RELEASING.md.

Two blobs both claimed one version. proxy-oracle 0.3.0 and governance 0.1.0 each had two distinct binaries — a stale local rebuild and the bytes actually deployed on mainnet — with current source matching neither. The on-chain bytes are recorded as canonical; source is bumped to 0.4.0/0.2.0 with freshly cut reproducible blobs.

Reproducibility is verified at the recorded source_commit, not the tag. cargo near build reproducible-wasm embeds the source commit per NEP-330, so identical source at two commits yields different bytes (measured: f03b159e vs b0a6ff7c). A blob is always committed before its tag exists, so verifying at the tag would fail every release.

Before merging

Verification

cargo fmt · CI's clippy command clean · artifact drift 25/25 · just test-fast 4997 passed · just test-sandbox 275 passed, including the migration/upgrade tests repointed at the catalog (migrate_mainnet, migrate_v0, upgrade_ordering, uac migration from real 0.2.0/0.4.0 bytes).

🤖 Generated with Claude Code


This change is Reviewable

peer2f00l and others added 6 commits July 24, 2026 00:03
…acts

Nothing in this workspace was released anywhere: templar-backend pinned seven
crates to a raw dev commit because no release tag contained `gateway/`, tags
used three naming schemes, and the only GitHub Release was a draft.

Add a release cycle built on release-plz. Every crate versions itself from its
own commit history; merging the standing "chore: release" PR is the trigger.
Crates fall into three tiers: published (the 17-crate closure external
consumers import), tagged-only (contracts, services, tools), and internal
(mocks, fuzz, test scaffolding).

Publishing to crates.io is configured but deferred: `templar-common` depends on
the RedStone SDK as a git dependency, and Cargo refuses to publish any crate
with one — on crates.io or a private registry. Tier A is therefore `git_only`
for now, so consumers pin per-crate tags instead of a commit hash. Unblocking is
a config flip, no code changes. See RELEASING.md.

Contract WASM blobs become immutable per-version releases under
res/near/<target>/<version>/. This replaces a single overwritten blob per
contract, and folds in the five historical blobs that were hand-maintained as
include_bytes! consts in gateway/testing — outside the catalog and outside any
drift check. Two of those exposed a real conflict: proxy-oracle 0.3.0 and
proxy-governance 0.1.0 each had two distinct binaries claiming the version (a
local rebuild and the bytes actually deployed on mainnet), with current source
matching neither. The on-chain bytes are recorded as canonical; the stale
rebuilds are dropped.

Drift checking grows from two checks to five, and a tag workflow rebuilds each
released contract reproducibly and requires a byte-for-byte match.

Also folds in ENG-362: the workspace relicenses from MIT to GPL-3.0-only, with
the twelve vault crates that already declared GPL now inheriting it, so there is
a single source of truth.

ENG-522, ENG-362

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The bytes deployed on mainnet are now recorded as the canonical 0.3.0 (oracle)
and 0.1.0 (governance) releases. Source has moved past both since ENG-481
changed the contracts without a version bump, so the current source is a new
release rather than a rewrite of a shipped one.

Blobs are cut in the following commit; the artifact drift check is red until
then, which is the intended tripwire.

ENG-522

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Reproducibly built from the previous commit via `just artifact-release
proxy-oracle`. First release cut through the new flow.

ENG-522

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Reproducibly built via `just artifact-release proxy-governance`. Completes the
version bump: source, crate version, and released bytes now agree for both
contracts, and the artifact drift check is green again.

ENG-522

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The tag workflow as first written could never have passed. `cargo near build
reproducible-wasm` embeds the source commit into the WASM per NEP-330, so
identical source built at two different commits yields different bytes —
measured here as f03b159e at the build commit versus b0a6ff7c one commit later.
Since a blob is necessarily committed *before* the tag that releases it exists,
rebuilding at the tag would have mismatched on every release.

Record the build commit on each release and rebuild there instead. Verified
end-to-end: rebuilding proxy-oracle 0.4.0 at its recorded commit reproduces the
committed blob byte-for-byte.

Legacy releases — bytes recovered from deployed mainnet contracts, whose
provenance predates this field — carry an empty commit. Their hash pin is still
enforced, but the workflow reports that they cannot be rebuilt rather than
pretending to verify them.

ENG-522

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Review pass over the first iteration. Net -216 lines, and two real defects.

Keep test-only bytes out of production. `embedded_bytes` routed through
`embedded_bytes_for_version`, whose runtime `&str` match made every historical
blob reachable, so ~2 MB of migration-test fixtures landed in the shipped
gateway binary. It is a direct match on the newest release again; the linked
dispatch binary drops from 19 embedded modules to 15. A new
`embedded_bytes_matches_current_release` test keeps the two lists agreeing,
replacing an `expect` and its clippy allow.

Drop the dead `workflow_dispatch` path in release-artifacts.yml: it wrote
`outputs.artifact`, which nothing read, while the consumers read `package` and
`version`, which it never set. Also skip cleanly when a tagged `*-contract`
crate has no catalogued WASM (the Soroban ones do not) rather than failing a
legitimate release.

`source_commit` becomes `Option` instead of `""`. The sentinel dodged the
invariant layer — release well-formedness checked the sha256 length but could
not check an empty string — and made "skip verification" the same value a typo
produces. `Some` arms are now asserted to be full 40-char shas.

Delete 17 inert release-plz `[[package]]` blocks that restated the workspace
default and would have rotted unnoticed; the Tier C blocks stay, since `release`
defaults to true. Collapse the `include_bytes!` arms from nine lines of
`concat!` to one literal each. Fold the crate version into `--print-metadata` so
`artifact-release.sh` drops its inline Python. Delete the unused `release_dir`,
the README table duplicating `ArtifactId::ALL`, and `synchronize` from the
PR-title trigger, which cannot change a title.

ENG-522

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary

  • Added release-plz automation for version bumps, changelogs, tags, and GitHub Releases, with publishing deferred while git dependencies remain.
  • Added conventional PR-title validation and documented commit/release conventions.
  • Reworked contract WASM artifacts into immutable, versioned releases with catalogued hashes and source commits.
  • Added reproducible artifact release, drift-check, and release-tag verification workflows.
  • Recorded mainnet proxy-oracle 0.3.0 and proxy-governance 0.1.0 artifacts, while bumping current versions to 0.4.0 and 0.2.0.
  • Updated migration and sandbox tests to use versioned artifacts instead of legacy constants.
  • Standardized crate metadata, explicit dependency versions, publication settings, and GPL-3.0-only licensing.

Verification

Formatting, clippy, artifact drift checks, fast tests, sandbox tests, and reproducible artifact validation were run.

Review focus

  • Confirm release-tag verification checks out the recorded source_commit and cannot accidentally validate artifacts against the moving branch.
  • Audit artifact catalog completeness, hashes, version mappings, and historical immutability.
  • Verify release-plz package classification and deferred crates.io publishing behavior.
  • Review smart-contract version bumps and migration fixtures for compatibility with the intended deployed artifact history.

Walkthrough

The pull request adds versioned, reproducibly verified contract artifacts; release-plz and GitHub Release automation; conventional PR-title validation; workspace license and package metadata updates; and migration tests that consume catalogued historical WASM releases.

Changes

Versioned artifact catalog and release tooling

Layer / File(s) Summary
Artifact release model and verification
contract/artifacts/*, script/*, justfile
Artifact metadata now contains ordered releases with pinned hashes and optional source commits. Version-specific embedded WASM lookup, release creation, reproducible builds, and full catalog drift checks are implemented.
Historical fixture migration
gateway/testing/*, contract/*/tests/*, service/relayer/tests/*, gateway/artifacts-spec/*, gateway/artifacts-dispatch/*
Tests replace hardcoded historical WASM constants with wasm::released(ArtifactId, version) lookups and use accessor-based artifact versions.

Release automation and repository guidance

Layer / File(s) Summary
Release workflows and configuration
.github/workflows/release-*.yml, .github/workflows/publish-soroban-vault-cli.yml, release-plz.toml
Release-plz creates release PRs and releases from dev; contract tags verify and upload reproducible artifacts; the Soroban CLI workflow supports release-tag triggers and derived image tags.
Contributor and release documentation
AGENTS.md, README.md, RELEASING.md
Documentation describes PR title rules, release tiers, immutable artifact handling, release-plz operation, and the GPL license.

Workspace and package metadata

Layer / File(s) Summary
Workspace metadata and licensing
Cargo.toml, LICENSE, README.md
The workspace license changes to GPL-3.0-only, Rust 1.86 is declared, internal dependency versions are made explicit, and the license documentation and badge are updated.
Crate publication and descriptions
**/Cargo.toml
Package descriptions are added, workspace license and repository fields are adopted where applicable, and numerous internal, contract, service, tool, mock, and client crates are marked publish = false.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Developer
  participant ReleasePlz
  participant GitHubActions
  participant ArtifactCatalog
  participant GitHubRelease
  Developer->>ReleasePlz: merge release PR on dev
  ReleasePlz->>GitHubActions: create package and contract tags
  GitHubActions->>ArtifactCatalog: resolve release metadata and source_commit
  GitHubActions->>ArtifactCatalog: rebuild and compare committed WASM
  GitHubActions->>GitHubRelease: upload verified WASM and checksums
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/eng-522-standardize-the-release-cycle-cratesio-publishing-per-crate

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • LINEAR integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0241c8422c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +397 to +399
"0.4.0",
"f03b159e9132a59ab929463866c672b734a5950fb41520ec33ad7a97030d5770",
Some("ea0a6357c89748e64b43036b776cd9459078af00")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep recorded source commits reachable after squash merge

These new reproducible releases record source_commit values that are not ancestors of the reviewed commit (I checked ea0a6357... and 9d447741... with git merge-base --is-ancestor). Because PRs are squash-merged, those intermediate commit objects can disappear once the branch is deleted, and .github/workflows/release-artifacts.yml later does git worktree add ../verify "$source_commit" from a tag checkout; the proxy-oracle/proxy-governance release verification will then fail before it can rebuild the blob. Record a commit that will be reachable from the release tag, or otherwise retain/fetch the exact source commits.

AGENTS.md reference: AGENTS.md:L76-L76

Useful? React with 👍 / 👎.

Comment on lines +117 to +118
git worktree add ../verify "$source_commit"
(cd ../verify && cargo near build reproducible-wasm --manifest-path "${source_path}/Cargo.toml")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Install cargo-near before invoking cargo near

On the release-tag runner this job only installs the Rust toolchain with dtolnay/rust-toolchain; unlike the existing node test workflow, it never installs the cargo-near subcommand before calling cargo near build reproducible-wasm. Any catalogued release with a source_commit will therefore fail with Cargo's “no such command: near” instead of verifying or uploading the artifact.

Useful? React with 👍 / 👎.

Comment on lines +133 to +137
- name: Attach artifacts to the release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REF_NAME: ${{ github.ref_name }}
run: gh release upload "$REF_NAME" dist/* --clobber

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip uploads when no artifact was produced

For tags that match this workflow but are not NEAR artifacts in ArtifactId::ALL—for example the Soroban contract packages that release-plz will tag by default—the metadata step exits successfully before creating dist/, but this unconditional upload still runs and fails on dist/*. Either narrow the tag trigger or gate the upload step on an output that says a blob was actually copied.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release-artifacts.yml:
- Around line 86-89: Update the release workflow’s verification step to create
and set a step output only when dist/ is created and artifact verification
should proceed; leave it unset on the intentional early-exit paths for Soroban
contracts and legacy blobs. Add an if condition to the upload step so it runs
only when that output indicates verification produced dist/ contents, preventing
unconditional dist/* uploads.

In @.github/workflows/release-plz.yml:
- Around line 15-20: Update the RELEASE_PLZ_TOKEN configuration documentation
and usage in the release workflow to require the PAT explicitly, removing the
fallback to GITHUB_TOKEN. Ensure the workflow fails clearly when
RELEASE_PLZ_TOKEN is unset rather than proceeding unattended with reduced
release validation.

In `@contract/artifacts/src/embedded.rs`:
- Around line 183-204: Update the assertion in
embedded_bytes_matches_current_release to compare the byte-slice contents
returned by embedded_bytes() and embedded_bytes_for_version() using equality,
replacing the pointer-identity check while preserving the existing failure
message and validation flow.

In `@contract/artifacts/src/prebuild.rs`:
- Around line 47-58: Add mutual conflicts_with configuration to the
print_metadata and print_release CLI arguments so they cannot be supplied
together. Preserve each flag’s existing output behavior when used independently,
ensuring conflicting invocations are rejected instead of selecting the metadata
branch.

In `@README.md`:
- Around line 43-46: Update the release PR title reference in the Contributing
section to use a title that satisfies the documented type(scope): summary
format, such as chore(release): release, while preserving the existing release
workflow description.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 29945415-c1f1-493f-bcde-b88d2346adae

📥 Commits

Reviewing files that changed from the base of the PR and between 92d0c33 and 0241c84.

⛔ Files ignored due to path filters (22)
  • Cargo.lock is excluded by !**/*.lock
  • contract/artifacts/res/near/mock_ft/0.0.0/mock_ft.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/mock_mt/0.0.0/mock_mt.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/mock_oracle/0.0.0/mock_oracle.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/mock_receiver/1.2.1/mock_receiver.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/mock_ref/1.2.1/mock_ref.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_lst_oracle_contract/1.2.1/templar_lst_oracle_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_market_contract/1.4.0/templar_market_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_proxy_oracle_near_contract/0.1.0/templar_proxy_oracle_near_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_proxy_oracle_near_contract/0.3.0/templar_proxy_oracle_near_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_proxy_oracle_near_contract/0.4.0/templar_proxy_oracle_near_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_proxy_oracle_near_contract/templar_proxy_oracle_near_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_proxy_oracle_near_governance_contract/0.1.0/templar_proxy_oracle_near_governance_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_proxy_oracle_near_governance_contract/0.2.0/templar_proxy_oracle_near_governance_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_proxy_oracle_near_governance_contract/templar_proxy_oracle_near_governance_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_pyth_lazer_adapter_contract/0.1.0/templar_pyth_lazer_adapter_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_redstone_adapter_contract/0.2.0/templar_redstone_adapter_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_registry_contract/1.2.1/templar_registry_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_universal_account_contract/0.2.0/templar_universal_account_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_universal_account_contract/0.4.0/templar_universal_account_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_universal_account_contract/0.5.0/templar_universal_account_contract.wasm is excluded by !**/*.wasm
  • contract/artifacts/res/near/templar_vault_contract/1.2.1/templar_vault_contract.wasm is excluded by !**/*.wasm
📒 Files selected for processing (91)
  • .github/workflows/pr-title.yml
  • .github/workflows/publish-soroban-vault-cli.yml
  • .github/workflows/release-artifacts.yml
  • .github/workflows/release-plz.yml
  • AGENTS.md
  • Cargo.toml
  • LICENSE
  • README.md
  • RELEASING.md
  • client/vault/Cargo.toml
  • common/Cargo.toml
  • contract/artifacts/README.md
  • contract/artifacts/src/embedded.rs
  • contract/artifacts/src/ids.rs
  • contract/artifacts/src/lib.rs
  • contract/artifacts/src/prebuild.rs
  • contract/market/Cargo.toml
  • contract/proxy-oracle/governance-kernel/Cargo.toml
  • contract/proxy-oracle/kernel/Cargo.toml
  • contract/proxy-oracle/near/common/Cargo.toml
  • contract/proxy-oracle/near/contract/Cargo.toml
  • contract/proxy-oracle/near/contract/tests/common/mod.rs
  • contract/proxy-oracle/near/contract/tests/migrate_mainnet.rs
  • contract/proxy-oracle/near/governance-common/Cargo.toml
  • contract/proxy-oracle/near/governance-contract/Cargo.toml
  • contract/proxy-oracle/near/governance-contract/tests/upgrade_ordering.rs
  • contract/proxy-oracle/near/lst-contract/Cargo.toml
  • contract/proxy-oracle/soroban/common/Cargo.toml
  • contract/proxy-oracle/soroban/contract/Cargo.toml
  • contract/proxy-oracle/soroban/governance-common/Cargo.toml
  • contract/proxy-oracle/soroban/governance-contract/Cargo.toml
  • contract/proxy-oracle/soroban/sep40-adapter-contract/Cargo.toml
  • contract/pyth-lazer/contract/Cargo.toml
  • contract/pyth-lazer/verifier/Cargo.toml
  • contract/redstone-adapter/Cargo.toml
  • contract/registry/Cargo.toml
  • contract/universal-account/Cargo.toml
  • contract/universal-account/tests/migration.rs
  • contract/vault/curator-primitives/Cargo.toml
  • contract/vault/kernel/Cargo.toml
  • contract/vault/macros/Cargo.toml
  • contract/vault/near/Cargo.toml
  • contract/vault/soroban/Cargo.toml
  • contract/vault/soroban/blend-adapter/Cargo.toml
  • contract/vault/soroban/curator-proxy/Cargo.toml
  • contract/vault/soroban/custodial-adapter/Cargo.toml
  • contract/vault/soroban/governance/Cargo.toml
  • contract/vault/soroban/proxy-4626/Cargo.toml
  • contract/vault/soroban/share-token/Cargo.toml
  • contract/vault/soroban/shared-types/Cargo.toml
  • gateway/artifacts-dispatch/Cargo.toml
  • gateway/artifacts-dispatch/src/lib.rs
  • gateway/artifacts-spec/Cargo.toml
  • gateway/artifacts-spec/src/artifact.rs
  • gateway/catalog/Cargo.toml
  • gateway/client/Cargo.toml
  • gateway/core/Cargo.toml
  • gateway/macros/Cargo.toml
  • gateway/methods-dispatch/Cargo.toml
  • gateway/methods-spec/Cargo.toml
  • gateway/oracle-updates-dispatch/Cargo.toml
  • gateway/oracle-updates-spec/Cargo.toml
  • gateway/runtime/Cargo.toml
  • gateway/store/Cargo.toml
  • gateway/testing/Cargo.toml
  • gateway/testing/src/lib.rs
  • gateway/testing/src/sandbox.rs
  • gateway/testing/src/wasm.rs
  • gateway/types/Cargo.toml
  • justfile
  • mock/receiver/Cargo.toml
  • mock/ref/Cargo.toml
  • primitives/Cargo.toml
  • release-plz.toml
  • script/artifact-release.sh
  • script/check-artifact-drift.sh
  • service/accumulator/Cargo.toml
  • service/funding-bridge/Cargo.toml
  • service/gateway/Cargo.toml
  • service/gateway/src/rpc/tests/artifact_tests.rs
  • service/liquidator/Cargo.toml
  • service/market-monitor/Cargo.toml
  • service/redstone-bridge/Cargo.toml
  • service/relayer/Cargo.toml
  • service/relayer/tests/relayer.rs
  • tools/harvest-static-yield/Cargo.toml
  • tools/manager/Cargo.toml
  • tools/market-config-cli/Cargo.toml
  • tools/soroban-vault-cli/Cargo.toml
  • tools/tools-common/Cargo.toml
  • universal-account/Cargo.toml

Comment on lines +86 to +89
--print-metadata --artifact "$PACKAGE" 2>/dev/null); then
echo "::notice::${PACKAGE} has no catalogued WASM artifact (e.g. a" \
"Soroban contract); nothing to verify."
exit 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Skip the upload when verification is intentionally skipped.

Both supported early-exit paths leave no dist/ directory, but the next step unconditionally uploads dist/*. Soroban package tags and legacy blobs therefore fail after reporting that they were intentionally skipped. Set a step output only after creating dist/, and gate the upload step on it.

Also applies to: 108-112, 133-137

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-artifacts.yml around lines 86 - 89, Update the
release workflow’s verification step to create and set a step output only when
dist/ is created and artifact verification should proceed; leave it unset on the
intentional early-exit paths for Soroban contracts and legacy blobs. Add an if
condition to the upload step so it runs only when that output indicates
verification produced dist/ contents, preventing unconditional dist/* uploads.

Comment on lines +15 to +20
# RELEASE_PLZ_TOKEN optional PAT. A PR opened with the default
# GITHUB_TOKEN does NOT trigger other workflows, so
# without this the Release PR never runs `test.yml` and
# you would be merging an unverified release. Falls back
# to GITHUB_TOKEN so the workflow still works unattended.
# CARGO_REGISTRY_TOKEN only consulted once crates leave `git_only` mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## release-plz.yml\n'
cat -n .github/workflows/release-plz.yml | sed -n '1,220p'

printf '\n## release-artifacts.yml\n'
cat -n .github/workflows/release-artifacts.yml | sed -n '1,220p'

printf '\n## release workflow refs\n'
rg -n "RELEASE_PLZ_TOKEN|GITHUB_TOKEN|workflow_run|release-artifacts|release-plz|release tags|tag" .github/workflows -S

Repository: Templar-Protocol/contracts

Length of output: 17001


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for any documentation or comments that state how release-plz tokens are expected to behave.
rg -n "RELEASE_PLZ_TOKEN|release-plz|release artifacts|GITHUB_TOKEN.*trigger|does NOT trigger|workflow_run|tag-triggered" -S .

Repository: Templar-Protocol/contracts

Length of output: 2836


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cat -n RELEASING.md | sed -n '88,108p'

Repository: Templar-Protocol/contracts

Length of output: 1242


Require RELEASE_PLZ_TOKEN here. The GITHUB_TOKEN fallback suppresses the release PR’s downstream test.yml run and the tag-triggered release-artifacts.yml check, so a release can ship without those gates. Make the PAT mandatory instead of falling back silently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-plz.yml around lines 15 - 20, Update the
RELEASE_PLZ_TOKEN configuration documentation and usage in the release workflow
to require the PAT explicitly, removing the fallback to GITHUB_TOKEN. Ensure the
workflow fails clearly when RELEASE_PLZ_TOKEN is unset rather than proceeding
unattended with reduced release validation.

Comment on lines +183 to +204
#[test]
fn embedded_bytes_matches_current_release() {
for artifact in ArtifactId::ALL.iter().map(|id| id.metadata()) {
let via_version = artifact
.id
.embedded_bytes_for_version(artifact.version())
.unwrap_or_else(|| {
panic!(
"{} has no blob for its current version {}",
artifact.package_name,
artifact.version(),
)
});
assert!(
std::ptr::eq(artifact.id.embedded_bytes(), via_version),
"{}: `embedded_bytes` does not point at the current release ({}). \
Update its arm in `ArtifactId::embedded_bytes`.",
artifact.package_name,
artifact.version(),
);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does LLVM's ConstantMerge pass run at opt-level 0 (rustc dev/debug profile)?

💡 Result:

No, LLVM's ConstantMerge pass does not run at opt-level 0 [1][2]. In the context of both LLVM's internal optimization pipelines and rustc's compilation profiles, opt-level 0 is designed to minimize optimizations to improve compilation speed and debuggability [3][4][5]. Technical documentation and discussions within the LLVM project confirm that ConstantMerge is applied at optimization levels O1 and higher, but it is explicitly excluded from the O0 pipeline [1][2]. Consequently, when compiling Rust code with the default dev profile (which uses opt-level 0), the ConstantMerge pass is not executed [3][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant file and nearby symbols.
file='contract/artifacts/src/embedded.rs'
wc -l "$file"
sed -n '1,260p' "$file"

Repository: Templar-Protocol/contracts

Length of output: 10886


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file='contract/artifacts/src/embedded.rs'

# Map the relevant functions first, then inspect only the implementation slices.
ast-grep outline "$file" --view expanded || true

printf '\n--- embedded_bytes implementations ---\n'
rg -n "fn embedded_bytes|fn embedded_bytes_for_version|include_bytes!" "$file" -n -A8 -B4

printf '\n--- ArtifactId metadata/current definitions ---\n'
rg -n "current\\(|embedded_bytes\\(|embedded_bytes_for_version\\(" contract/artifacts/src -n -A6 -B3

Repository: Templar-Protocol/contracts

Length of output: 14338


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the artifact ID definitions if they live in a different file.
rg -n "enum ArtifactId|impl ArtifactId|embedded_bytes_for_version|embedded_bytes\\(" contract/artifacts/src -g '!contract/artifacts/src/embedded.rs' -A8 -B4

Repository: Templar-Protocol/contracts

Length of output: 5757


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the implementation of the pointer-checked functions and the ArtifactId definition.
file='contract/artifacts/src/embedded.rs'
rg -n "fn embedded_bytes|fn embedded_bytes_for_version|include_bytes!|enum ArtifactId|impl ArtifactId|current\\(" "$file" contract/artifacts/src -A8 -B4

Repository: Templar-Protocol/contracts

Length of output: 20370


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the ArtifactId implementation file if it is separate.
fd -a -t f 'ids.rs' contract/artifacts/src

Repository: Templar-Protocol/contracts

Length of output: 213


Compare slice contents instead of pointer identity. This test depends on two separate include_bytes! sites being merged into the same allocation, so a correct catalog entry can still fail here. Use artifact.id.embedded_bytes() == via_version instead.

Suggested fix
-                std::ptr::eq(artifact.id.embedded_bytes(), via_version),
+                artifact.id.embedded_bytes() == via_version,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[test]
fn embedded_bytes_matches_current_release() {
for artifact in ArtifactId::ALL.iter().map(|id| id.metadata()) {
let via_version = artifact
.id
.embedded_bytes_for_version(artifact.version())
.unwrap_or_else(|| {
panic!(
"{} has no blob for its current version {}",
artifact.package_name,
artifact.version(),
)
});
assert!(
std::ptr::eq(artifact.id.embedded_bytes(), via_version),
"{}: `embedded_bytes` does not point at the current release ({}). \
Update its arm in `ArtifactId::embedded_bytes`.",
artifact.package_name,
artifact.version(),
);
}
}
#[test]
fn embedded_bytes_matches_current_release() {
for artifact in ArtifactId::ALL.iter().map(|id| id.metadata()) {
let via_version = artifact
.id
.embedded_bytes_for_version(artifact.version())
.unwrap_or_else(|| {
panic!(
"{} has no blob for its current version {}",
artifact.package_name,
artifact.version(),
)
});
assert!(
artifact.id.embedded_bytes() == via_version,
"{}: `embedded_bytes` does not point at the current release ({}). \
Update its arm in `ArtifactId::embedded_bytes`.",
artifact.package_name,
artifact.version(),
);
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contract/artifacts/src/embedded.rs` around lines 183 - 204, Update the
assertion in embedded_bytes_matches_current_release to compare the byte-slice
contents returned by embedded_bytes() and embedded_bytes_for_version() using
equality, replacing the pointer-identity check while preserving the existing
failure message and validation flow.

Comment on lines +47 to +58
/// Print `<source_path> <cargo_target_name> <version>` for each selected
/// artifact and exit, without building. Lets shell tooling
/// (`script/artifact-release.sh`, `release-artifacts.yml`) read the catalog
/// instead of re-deriving paths and drifting from it.
#[arg(long)]
print_metadata: bool,

/// Print the `source_commit` of the given released version of the single
/// selected artifact and exit, or an empty line for a legacy blob that
/// cannot be reproducibly rebuilt.
#[arg(long, value_name = "VERSION")]
print_release: Option<String>,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant file and inspect the surrounding argument handling.
git ls-files contract/artifacts/src/prebuild.rs
wc -l contract/artifacts/src/prebuild.rs
cat -n contract/artifacts/src/prebuild.rs | sed -n '1,220p'

Repository: Templar-Protocol/contracts

Length of output: 7102


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n --hidden --glob '!target' --glob '!dist' --glob '!build' --glob '!node_modules' \
  'print_metadata|print_release|check_all|artifact-release|release-artifacts' \
  contract README.md .github script || true

Repository: Templar-Protocol/contracts

Length of output: 891


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n --hidden --glob '!target' --glob '!dist' --glob '!build' --glob '!node_modules' \
  'print_metadata|print_release|artifact-release|release-artifacts|--print-metadata|--print-release' \
  contract README.md .github script || true

Repository: Templar-Protocol/contracts

Length of output: 995


Reject conflicting output modes.

--print-metadata and --print-release <version> should conflict; today the metadata branch wins silently, so a caller can ask for release output and get the catalog instead. Add conflicts_with on both flags.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@contract/artifacts/src/prebuild.rs` around lines 47 - 58, Add mutual
conflicts_with configuration to the print_metadata and print_release CLI
arguments so they cannot be supplied together. Preserve each flag’s existing
output behavior when used independently, ensuring conflicting invocations are
rejected instead of selecting the metadata branch.

Source: Path instructions

Comment thread README.md
Comment on lines +43 to +46
## Contributing

PRs are squash-merged, so the PR title becomes the commit message and drives automated versioning. Titles must follow `type(scope): summary` — see [Commit And PR Titles](AGENTS.md#commit-and-pr-titles). Releases are cut by merging the standing "chore: release" PR; see [RELEASING.md](RELEASING.md).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use a release PR title that passes validation.

The documentation requires type(scope): summary but names the standing release PR chore: release, which omits the scope. Document a compliant title such as chore(release): release, or explicitly support the exception in the title workflow.

As per path instructions, PR titles must use type(scope): summary; the documented release title does not satisfy that format.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 43 - 46, Update the release PR title reference in the
Contributing section to use a title that satisfies the documented type(scope):
summary format, such as chore(release): release, while preserving the existing
release workflow description.

Source: Path instructions

@carrion256 carrion256 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love release-plz, but why do we checkin the wasm rather than release into GH releases? Editors & AI will actually index these blobs and it adds unnecessary slop to the git index.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants