Skip to content

Prepare the v1.0.0 release: versioned builds, clean config, public image - #761

Merged
aditya1702 merged 17 commits into
mainfrom
release-prep-v1
Oct 9, 2026
Merged

aditya1702 merged 17 commits into
mainfrom
release-prep-v1

Conversation

@aditya1702

@aditya1702 aditya1702 commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Gets the repo ready to cut v1.0.0 and publish it to public ECR, with Docker Hub kept for existing users. No ingestion or API behavior changes. The docs that describe all of this are in #762, stacked on this PR.

TL;DR

  • The binary knows its version. wallet-backend version prints it, and every service logs it at startup.
  • Config is cleaned up before semver freezes it: 6 flags removed, 3 defaults changed, 2 validations added. See the tables below for what you may need to change in your env.
  • The Docker image is production-shaped: static binary, slim base, non-root, 172 MB.
  • Promoting a release also publishes public.ecr.aws/stellar/wallet-backend:<version> and :latest (primary; the repository is declared in stellar/terraform) and the same digest to Docker Hub stellar/wallet-backend, which stays until it is deprecated.
  • docker compose up is now a testnet quickstart on the published image.

If you deploy this: what to change in your env

You set What happens now Do
NETWORK Ignored. The ingest lock key comes from NETWORK_PASSPHRASE. Remove at leisure
TRACKER_DSN, STELLAR_ENVIRONMENT Ignored. Sentry is gone; errors are logged. Remove at leisure
SERVER_BASE_URL, SUPPORTED_ASSETS, LATEST_LEDGER_CURSOR_NAME Ignored. They were never read. Remove at leisure
START_LEDGER or END_LEDGER on a live ingester, any value including 0 Startup fails with a clear error. Unset them on live; keep them on backfill
Nothing for LEDGER_BACKEND_TYPE Default is now rpc, not datastore. Set LEDGER_BACKEND_TYPE=datastore explicitly if you rely on it
Nothing for DATASTORE_BUCKET_PATH with datastore Startup fails; there is no default bucket any more. Set it to your network's bucket
Nothing for DB_MAX_CONNS on a live ingester Default is now 12 (from main), and live mode refuses to start below 9: the persist pipeline holds 7 sibling transactions, a coordinator and the lock session. Nothing, unless you pinned a value below 9
Nothing for LOG_LEVEL INFO, and it is actually applied. Before, the default never reached the logger and services ran at TRACE. Nothing, unless you want DEBUG

Our dev, staging, and prod manifests already set the backend type, bucket path, and log level explicitly, so nothing breaks there. The ingest lock key changes once; ingest uses a Recreate strategy, so no two ingesters overlap during the rollout.

Version

Where Shows
wallet-backend version wallet-backend v1.2.3 (commit abc1234, go1.25.9)
Service startup log wallet-backend v1.2.3 (commit abc1234)
Image labels org.opencontainers.image.version, .revision, .source, .licenses
A build with no ldflags dev, commit unknown

A promoted image reports the rc it was built as (for example v1.2.0-rc.2), because promotion copies the soaked digest instead of rebuilding. The release and the image tags carry the final version.

Config cleanup, in full

Change Why
Removed --network Only fed the advisory-lock ID; derived from the passphrase now
Removed --server-base-url, --supported-assets Parsed and never read
Removed --latest-ledger-cursor-name Deprecated no-op
Removed --tracker-dsn, --stellar-environment, the Sentry client, the AppTracker plumbing, the sentry-go dependency Not used. The 500/503 paths and panic recovery still log the error
--ledger-backend-type defaults to rpc on ingest and protocol-migrate One story for every command: RPC works out of the box, datastore is explicit
--datastore-bucket-path has no default; required only with datastore The old default pointed at pubnet while the passphrase and archive defaulted to testnet
Live mode rejects an explicitly set --start-ledger / --end-ledger, even 0; backfill validates the range, stays below the uint32 ceiling, and splits batches without overflow Live mode silently ignored them
--log-level defaults to INFO and the default is applied The setter only applied the level when the flag was set explicitly
--compression-max-chunks and RETENTION_PERIOD help text match the code 0 leaves the compression job unchanged; an empty retention period removes the policy
.env.example lists every variable with a one-line comment; values with spaces are quoted Works with source .env and with Compose

Image

Before After
Build -gcflags=all=-N -l, Delve installed CGO_ENABLED=0 -trimpath -ldflags "-s -w"; BUILD_MODE=debug opts into Delve
Base ubuntu:jammy + curl, wget, gnupg, Stellar apt repos debian:bookworm-slim + ca-certificates
User root UID 10001
Ports 8001, 40000 8001
Extras /app/config copied in Nothing; .dockerignore added

Release flow

Unchanged shape: dispatch publish-prerelease with vX.Y.Z-rc.N, soak on staging, dispatch promote-release. What is new:

  • promote-release logs into public ECR through the shared sdf-ecr-login action (login-public-ecr: true, the same path friendbot uses) and copies the production digest to public.ecr.aws/stellar/wallet-backend:<version> and :latest. It then copies the same digest to Docker Hub using the existing DOCKERHUB_* secrets. All three tag checks run before any tag is created. Each proceeds on an explicit not-found or on a tag that already holds the staging digest, so a promotion that failed partway can be re-run, and a tag with any other digest stops it. Each copy is digest-verified. Promotions run one at a time, and latest moves only when the release is the highest version released so far (every release is checked, and a failed lookup stops the run), so a patch for an older line never moves it backwards. Docker Hub is kept for existing users until it is deprecated; public ECR is primary.
  • The GitHub release starts with an Images and Tested with block, then the generated notes. Fill the two <fill in> lines (stellar-rpc, protocol) after promotion.
  • .github/release.yml groups notes by label: breaking, feature, fix, docs, dependencies, ci. Dependabot PRs get dependencies. The PR template asks for a label.
  • CodeQL stops scanning develop.

Compose

  • docker-compose.yaml: db, stellar-rpc (testnet), migrate, ingest, api from public.ecr.aws/stellar/wallet-backend:${WALLET_BACKEND_VERSION:-latest}.
  • docker-compose.dev.yaml: local debug build and the Delve port.

How to review

Each commit is one concern and reads on its own, in this order:

  1. Version injection and the version command
  2. Config cleanup
  3. Dockerfile and Makefile
  4. Workflows and release notes
  5. Compose
  6. Help-text fixes for the compression and retention knobs
  7. Log-level default fix
  8. Copilot review fixes (fail-closed publish guard, quoted env template, uint32 bound)
  9. Sentry removal
  10. Public ECR as the primary registry
  11. Docker Hub kept alongside it for existing users
  12. Second Copilot round: fail-closed AWS checks, check-before-create ordering, explicit-zero rejection, overflow-safe batches
  13. Third Copilot round: latest follows the highest release, batch loop ends at the ceiling
  14. Rebased onto main after the live-persist pipeline merged; .env.example gains LIVE_PERSIST_MAX_BATCH_SIZE and the pool minimum
  15. Fourth Copilot round: re-runnable promotion, paginated release lookup that fails on gh errors, no such manifest counts as not found
  16. Test for the version command output and its unknown commit fallback

Verification

  • make check, make unit-test with race detection, CI integration suite: green.
  • docker build then wallet-backend version prints the injected version; id -u is 10001.
  • ingest --ingestion-mode=live --start-ledger=5 exits 1 with a single Error: line after the startup line.
  • .env.example parses under source and as a Compose env file.

Tracked internally.

🤖 Generated with Claude Code

@aditya1702 aditya1702 added the enhancement New feature or request label Oct 1, 2026
Copilot AI lite review requested due to automatic review settings October 1, 2026 20:34

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

The release-tag verification has a critical fail-open path, with additional unresolved build, configuration, Compose, and documentation issues.

Review effort: Lite
Findings: 1 High severity · 3 Medium severity · 1 Low severity

Open (5)
What changed in this PR

Prepares the v1.0.0 release with injected build metadata, cleaned configuration, production Docker images, Compose support, and publishing automation.

Changes:

  • Adds version and commit reporting across builds and commands.
  • Simplifies configuration and updates ingestion validation.
  • Adds optimized non-root images and Docker Hub promotion workflows.
File Summary
Makefile Adds versioned builds and Docker arguments.
main.go Defines injectable build metadata.
internal/​services/​ingest.go Derives locks from network passphrases.
internal/​services/​ingest_test.go Updates ingest test configuration.
internal/​services/​ingest_live_test.go Updates lock test configuration.
internal/​serve/​serve.go Removes obsolete settings.
internal/​integrationtests/​infrastructure/​run_command.go Uses the installed binary.
internal/​integrationtests/​infrastructure/​containers.go Updates container commands and configuration.
internal/​ingest/​ingest.go Removes network configuration and updates defaults.
internal/​entities/​asset.go Removes the obsolete asset type.
Dockerfile Adds release/debug multi-stage images.
docker-compose.yaml Defines the published-image testnet quickstart.
docker-compose.dev.yaml Adds local debug overrides.
cmd/​version.go Adds the version command.
cmd/​utils/​global_options.go Updates defaults and removes obsolete options.
cmd/​utils/​custom_set_value.go Removes asset parsing.
cmd/​utils/​custom_set_value_test.go Removes obsolete parser tests.
cmd/​serve.go Removes obsolete serve flags.
cmd/​root.go Adds startup identity logging and concise errors.
cmd/​protocol_migrate.go Updates backend defaults and validation.
cmd/​ingest.go Adds backend and ledger-range validation.
.github/​workflows/​publish-prerelease.yml Injects prerelease version metadata.
.github/​workflows/​promote-release.yml Publishes promoted images.
.github/​workflows/​codeql.yml Restricts CodeQL scanning.
.github/​workflows/​build.yml Injects development versions.
.github/​release.yml Configures categorized release notes.
.github/​pull_request_template.md Adds release-label guidance.
.github/​dependabot.yml Labels dependency updates.
.env.example Expands environment configuration documentation.
.dockerignore Reduces Docker build context.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .github/workflows/promote-release.yml Outdated
Comment thread .env.example Outdated
Comment thread Dockerfile
Comment thread docker-compose.dev.yaml Outdated
Comment thread docker-compose.yaml
Copilot AI lite review requested due to automatic review settings October 1, 2026 20:45

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Critical configuration-template and ledger-range issues remain, along with additional workflow and default-configuration problems.

Review effort: Lite
Findings: 4 High severity · 3 Medium severity · 1 Low severity

Open (8)
Previously missed (4)

In code that hasn't changed since last review

Medium severity Reject explicitly supplied zero ledger flags in live mode

cmd/​ingest.go:164

This checks only the resulting integer values, so an explicitly supplied --start-ledger=0 or --end-ledger=0 is silently accepted in live mode even though the new contract says live mode rejects these flags. Check the Cobra flag's Changed state in addition to the non-zero values.

Medium severity RPC migration lacks a default RPC URL

cmd/​protocol_migrate.go:93

With this default, protocol-migrate selects the RPC backend but rpc-url still defaults to an empty string (line 85), and the pre-run validation rejects that at line 129. A flag-less RPC migration therefore fails instead of working out of the box as this change intends; give rpc-url the same localhost default as the other RPC commands (or reuse RPCURLOption).

Medium severity Apply INFO logger default when LOG_LEVEL is unset

cmd/​utils/​global_options.go:53

Changing the config default to INFO does not change the process logger's default: preConfigureLogger still sets it to TRACE, and SetConfigOptionLogLevel only calls SetLevel when the option is explicitly set. Consequently, a normal serve/ingest launch with no LOG_LEVEL still emits TRACE-level logs, contrary to this new default; apply the parsed default level as well.

Low severity Use consistent fallback for empty Git commit

cmd/​root.go:57

For an un-injected build, cfg.GitCommit is empty, so service startup logs wallet-backend dev (commit ), while wallet-backend version normalizes the same value to unknown. This makes the advertised build identity inconsistent and leaves an unhelpful blank field; use the same fallback here.

Comment thread .env.example Outdated
Comment thread .env.example Outdated
Comment thread cmd/ingest.go
Copilot AI lite review requested due to automatic review settings October 1, 2026 20:51

Copilot AI 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.

Copilot review overview

🔵 Needs a closer look

Unresolved configuration, validation, Docker/Compose, documentation, and release-workflow findings block approval.

Review effort: Lite
Findings: 4 High severity · 3 Medium severity · 1 Low severity

Open (8)
Previously missed (1)

In code that hasn't changed since last review

Low severity Avoid startup identity log before validation

cmd/​root.go:57

Because this root hook runs before each command's PersistentPreRunE, an invalid service configuration logs the build-identity INFO line here and then Execute prints Error: .... That makes cases such as ingest --ingestion-mode=live --start-ledger=5 produce two lines, contradicting the promised one-line config error; move this log after command-specific validation (or otherwise suppress it when validation fails).

@aditya1702
aditya1702 added this pull request to stack #763 October 1, 2026 21:00
Copilot AI lite review requested due to automatic review settings October 1, 2026 21:07
@aditya1702

Copy link
Copy Markdown
Contributor Author

On the overview-only findings Copilot listed without a thread:

  • Apply INFO logger default: already fixed in 31ca373; the setter now applies the parsed level whether or not the flag was set.
  • Use a consistent fallback for an empty commit: done in ad155a0; the startup line prints unknown like the version command.
  • Reject an explicit --start-ledger=0 in live mode: not changing. Zero is the documented "unset" value for both flags and the env-var path cannot distinguish explicit zero from absent.
  • Default rpc-url on protocol-migrate: not changing. An empty rpc-url is what tells a datastore run to skip RPC metadata and the tip gauge; a localhost default would make those runs call an RPC that is not there. The rpc backend fails fast with a clear message instead.
  • Identity log before validation: keeping it. Knowing which build rejected a config is useful on the failure path; the description now says "a single Error: line" follows the startup line.

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Unresolved critical ledger-range overflow and additional workflow and validation issues remain.

Review effort: Lite
Findings: 1 High severity

Open (1)
Resolved since last review (8)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Include Go version in service startup logs

cmd/​root.go:61

The service startup log here omits the Go toolchain version, while wallet-backend version includes it and the PR description says every service logs the same build-identity line. As written, serve, ingest, and the migration commands do not expose the complete identity; include runtime.Version() in this log as well.

Comment thread cmd/ingest.go Outdated
Copilot AI lite review requested due to automatic review settings October 5, 2026 15:17

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Unresolved workflow, ledger validation, RPC default, and debug-container issues remain.

Review effort: Lite
Findings: 2 High severity

Open (2)

Comment thread .github/workflows/promote-release.yml
Copilot AI lite review requested due to automatic review settings October 5, 2026 15:35
@aditya1702 aditya1702 changed the title Release prep for v1.0.0: version injection, config cleanup, production image, Docker Hub publishing Prepare the v1.0.0 release: versioned builds, clean config, public image Oct 5, 2026

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Unresolved release workflow, ledger-boundary, and Docker registry issues must be addressed.

Review effort: Lite
Findings: 2 High severity · 2 Medium severity

Open (4)

Comment thread .github/workflows/promote-release.yml
Comment thread docker-compose.yaml
@aristidesstaffieri

Copy link
Copy Markdown
Contributor

@aditya1702 the readme quickstart still references deleted modules and env vars

@aristidesstaffieri

Copy link
Copy Markdown
Contributor

we still have leftovers references to the old binary path in the docs and a few other spots

Copilot AI lite review requested due to automatic review settings October 5, 2026 17:29

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Unresolved critical release-promotion safeguards and additional validation and test issues block approval.

Review effort: Lite
Findings: 5 High severity · 1 Medium severity

Open (6)
Resolved since last review (2)

Comment thread .github/workflows/promote-release.yml Outdated
Comment thread .github/workflows/promote-release.yml Outdated
Comment thread .github/workflows/publish-prerelease.yml
Comment thread cmd/ingest.go Outdated
Copilot AI lite review requested due to automatic review settings October 5, 2026 17:35
Copilot AI lite review requested due to automatic review settings October 6, 2026 14:22

Copilot AI 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.

Copilot review overview

🔵 Needs a closer look

Moderate unresolved findings affect release promotion safeguards and MaxUint32 backfill regression coverage.

Review effort: Lite
Findings: 3 High severity

Open (3)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Cross-registry promotion cannot safely resume after partial failure

.github/​workflows/​promote-release.yml:249

A failure after the production/public copy but during Docker Hub publication leaves a partially promoted release, and a retry is then blocked because the existing production and public tags fail the preflight checks. Make the cross-registry steps resumable by accepting an existing destination tag only when its digest matches the source (and skipping that copy), or provide an equivalent recovery path.

main.Version and main.GitCommit are both set through ldflags; a build
without them reports "dev". `wallet-backend version` prints the version,
commit, and Go toolchain. Service commands log the same identity on
startup. A config error now prints one line to stderr and exits 1
instead of panicking with a stack trace.
…face freezes

Removed: --network (the advisory-lock ID now derives from the network
passphrase), --server-base-url and --supported-assets (parsed, never
read), --latest-ledger-cursor-name (deprecated no-op).

Changed: --ledger-backend-type defaults to rpc for ingest and
protocol-migrate; --datastore-bucket-path has no default and is required
only with the datastore backend; live mode rejects --start-ledger and
--end-ledger instead of ignoring them; backfill validates its range;
--stellar-environment is optional; --log-level defaults to INFO.

.env.example lists every variable with a one-line comment.
Release builds use CGO_ENABLED=0, -trimpath and -s -w. BUILD_MODE=debug
adds Delve and disables optimizations for docker-compose.dev.yaml. The
runtime image is debian:bookworm-slim with ca-certificates only, runs as
UID 10001, exposes 8001, and carries OCI labels. The Makefile passes
VERSION and BUILD_MODE through and drops the unused STELLAR_CORE_VERSION.
promote-release copies the production digest to
docker.io/stellar/wallet-backend:<version> and :latest, refuses to
overwrite an existing tag, and verifies the digest. The GitHub release
starts with an Images and Tested-with block. .github/release.yml groups
notes by label; Dependabot PRs get the dependencies label. CodeQL no
longer scans the develop branch.
docker-compose.yaml runs db, stellar-rpc, migrate, ingest and api from
stellar/wallet-backend:${WALLET_BACKEND_VERSION:-latest}.
docker-compose.dev.yaml overrides it with a local debug build and the
Delve port.
COMPRESSION_MAX_CHUNKS=0 leaves the job's setting unchanged rather than
meaning unlimited, and an empty RETENTION_PERIOD removes the retention
policy rather than keeping the current one.
SetConfigOptionLogLevel only called SetLevel when the option was set
explicitly, so serve and ingest ignored the INFO default and logged at
TRACE unless LOG_LEVEL was given.
…nt32 range check

The Docker Hub existence check proceeds only on an explicit not-found
answer and fails on any other inspect error. The CI integration image
gets VERSION=integration-test. The documented Delve invocation overrides
the entrypoint, since the image's entrypoint is wallet-backend. Values
with spaces in .env.example are quoted so the file works with source
and with Compose. Backfill rejects an end ledger above uint32. The
startup identity line prints "unknown" for an empty commit, matching
the version command.
… flags

The AppTracker interface existed only to forward errors to Sentry.
Removing it drops the two flags, the sentry-go dependency, the
internal/apptracker package, and the tracker parameter threaded through
the HTTP error helpers, middleware, health handler, and ingest config.
Errors are still logged where they were captured before.
promote-release logs into public ECR through the shared sdf-ecr-login
action and copies the production digest to
public.ecr.aws/stellar/wallet-backend:<version> and :latest. That
repository is managed in stellar/terraform. The compose quickstart and
the release notes pull from it.
Public ECR stays the primary registry. promote-release also copies the
same production digest to docker.io/stellar/wallet-backend:<version>
and :latest with the same fail-closed existence check, until Docker Hub
is deprecated. The release notes list both pull commands.
…ring, overflow-safe backfill ranges

Every image-existence check in publish-prerelease and promote-release
now proceeds only on an explicit not-found answer and fails on any
other error. promote-release runs all three existence checks before it
creates any tag, so a failed check leaves nothing half-promoted, and it
uses one global concurrency group so :latest cannot move backwards.

Live ingest rejects an explicitly supplied --start-ledger or
--end-ledger, including 0, via flag or env var. Backfill rejects an end
ledger at the uint32 ceiling and splits batches without overflow.
…op at the ceiling

promote-release compares the release version with the highest existing
non-prerelease and moves :latest only when this release is the newest,
so promoting a patch for an older line publishes its tag without moving
:latest. The per-ledger loop in backfill stops after EndLedger instead
of relying on a uint32 counter that wraps at the ceiling.
A zero --backfill-batch-size would make the batch splitter loop
forever; a zero insert batch size would never flush. Both must be
between 1 and MaxUint32, and --backfill-workers must not be negative.
Copilot AI lite review requested due to automatic review settings October 8, 2026 14:59

Copilot AI 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.

🟡 Changes recommended

Release promotion has unresolved partial-publication and latest version-selection risks.

5 open findings

🧠 Review effort: Lite


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

Comment thread .github/workflows/promote-release.yml
Comment thread cmd/version.go

@aristidesstaffieri aristidesstaffieri 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.

other than the open copilot comments this lgtm, acknowledging that the docs are outdated but will be updated in the stacked PR.

…fails on gh errors

The :latest check pages through every release and stops on a gh failure
instead of reading it as no releases. The tag guards accept a tag that
already holds the staging digest, so a run that failed after a partial
publish can be re-run, and treat 'no such manifest' as not found.
Copilot AI lite review requested due to automatic review settings October 9, 2026 18:04

Copilot AI 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.

🔵 Needs a closer look

Add command-level and maximum-ledger boundary tests for the new ingestion safeguards.

0 open findings

5 resolved since last review

🧠 Review effort: Lite

@aditya1702
aditya1702 merged commit 1dad992 into main Oct 9, 2026
10 checks passed
@aditya1702
aditya1702 deleted the release-prep-v1 branch October 9, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants