Repository navigation
Reconcile main with production and add main-only release automation - #5
Merged
Merged
Conversation
…and durable delivery
The mainnet release crosschain-20261021 was built from 39e4ae3 plus uncommitted changes (release-info.json: "dirty": true). This commit records that exact source so production code is in git: all 79 files match the release's backend-manifest.json SHA-256 hashes and the archive matches its recorded sha256 (1fe2763a…6cbe). Adds NEAR 1Click cross-chain payments, the email module, the scanner API and related billing/invoice/scanner changes. Credentials are read from the environment; no secrets are included. 121 tests pass with --locked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reconciles main with the production snapshot so nothing deployed is lost. Production's stricter audit workflow (cargo test plus check-dependency-exposure.py) is kept. - actix-web: production's feature set minus compress-* (no Compress middleware; the features auto-decoded zstd/brotli/gzip request bodies through zstd-safe 7.3.0) - rustls 0.23.44 -> 0.23.46, rustls-webpki 0.103.15 -> 0.103.16 (emSign distrust), tokio 1.53.1 -> 1.54.1 121 tests pass with --locked; cargo audit with the CI flags passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Production drifted from main because releases were built from working trees (crosschain-20261021 was 39e4ae3 plus uncommitted changes, while main lacked the September payment fixes). Make that impossible: - release-build.yml: on every push to main, test, build on ubuntu-24.04 (matches the hosts) and publish a build-<sha> prerelease with the binary, source archive, build-info.json and SHA256SUMS. The 1 vCPU / 1 GB host no longer compiles. - scripts/release/stage.sh: refuse commits not on main, verify checksums, validate migrations on a private DB copy (validate-database.py, generalized from the crosschain release), write release-info.json. - scripts/release/activate.sh: generalized activate-production.sh with backup, live --check-database, zz-release.conf drop-in, health check and automatic rollback. - scripts/release/status.sh: report the serving commit and fail when it is dirty or not on main. - docs/RELEASING.md documents the flow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/referrals.rs and src/referrals/guardrails.rs ran in production (crosschain-20261021) but were never committed: a global *REFERRAL* exclude hid them, so main could not build the deployed code. Commit them from the release source (guardrails.rs matches the release manifest hash; referrals.rs differs only by the gate in apply() below) and re-include them in the repo .gitignore. The referral program is not meant to be live yet, but production exposed POST /merchants/me/referral and minted codes in the billing summary. Add REFERRALS_ENABLED (default off): applying a code returns 404 and the billing summary returns "referrals": null without creating a code. Fee-policy tables, migrations, service_bps and reconcile are unchanged, since every invoice's fee snapshot depends on them. Production has 0 applied referrals and 0 earnings, so nothing in flight is affected. 122 tests pass on rustc 1.99.1 (CI stable). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Production and
mainhad diverged.crosschain-20261021. It was built from39e4ae3plus uncommitted changes (release-info.json:"dirty": true).mainwas missing six commits that production has. These are the September payment isolation, replay protection, confirmation accounting and delivery fixes (bb06438…107ed00) and the subscription renewal fix (39e4ae3).mainwould have reverted all of them. It would also have dropped the NEAR cross-chain, email and scanner-API code that existed only on the server.After this PR merges,
mainequals production plus the security fix, and releases can only be built frommain.Commits
c39affdProduction snapshot. Records the exact source ofcrosschain-20261021. All 79 files match the release'sbackend-manifest.jsonSHA-256 hashes, and the archive matches its recorded sha256. I scanned it for secrets: credentials are read from environment variables only, and there are no keys or addresses in the code.a3dc2d8Merge ofmain, which includes Fix lockfile drift and clear cargo audit (rustls, h2, zstd, tokio) #4. This brings the security fix onto the production line:check-dependency-exposure.py).compress-*. The API used noCompressmiddleware, but those features auto-decoded zstd, brotli and gzip request bodies throughzstd-safe7.3.0 (RUSTSEC-2026-0391..0410).rustls0.23.44 → 0.23.46,rustls-webpki0.103.15 → 0.103.16 (emSign distrust),tokio1.53.1 → 1.54.1.51c8d38Release automation, so production can't drift from main again:release-build.ymlruns on every push tomain. It runs the tests, builds on ubuntu-24.04 (matching the hosts) and publishes abuild-<sha>prerelease containing the binary, source archive,build-info.jsonandSHA256SUMS.scripts/release/stage.sh <sha>refuses commits that aren't onmainand verifies the checksums. It then validates the migrations on a private copy of the database, proving every existing row is unchanged.scripts/release/activate.shgeneralizesactivate-production.sh. It takes a backup, runs--check-databaseon the live database, writes azz-release.confdrop-in and checks health, rolling back automatically if any step fails.scripts/release/status.shreports the serving commit and exits non-zero when it is dirty or not onmain. Run against mainnet today, it reportsDIRTY, as expected.docs/RELEASING.mddocuments the flow.9d95a23Referral source tracked, program off by default.src/referrals.rsandsrc/referrals/guardrails.rsran in production but were never committed. A global*REFERRAL*exclude hid them, and that is why CI failed. They are now committed, and the repo.gitignoreexplicitly re-includes them.REFERRALS_ENABLED, off by default. While it's off,POST /merchants/me/referralreturns 404, and the billing summary returns"referrals": nullwithout creating a code.service_bpsandreconcilestill run, because every invoice's fee snapshot depends on them.Testing
cargo test --lockedon rustc 1.99.1 (CI stable): 122 passed, 3 ignored.cargo audit --deny unmaintained --deny unsoundwith the CI ignores exits 0.check-dependency-exposure.pypasses.bash -nand shellcheck, andstatus.shwas run read-only against mainnet.Behaviour changes
REFERRALS_ENABLED=true.Content-Encoding: gzip/br/zstdis no longer decompressed. None of our clients send compressed requests, and responses are unchanged.Not covered
Testnet (
/root/cipherpay-api-testnet) runs April code from a source checkout and isn't covered by these scripts yet.🤖 Generated with Claude Code