feat(exit-certificate-claimer): prepare exit_certificate_claimer for deployment#1690
Merged
joanestebanr merged 11 commits intoJul 10, 2026
Conversation
The build stage already compiles every tool, but the final runtime image only copied aggkit and aggsender_find_imported_bridge. Add the exit_certificate generator and the exit_certificate_claimer HTTP service so they ship in the image. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…vice Add a docker-compose.yml (and .env.example) that runs the exit_certificate_claimer over the exit_certificate working directory. - Builds the aggkit image and overrides the entrypoint with the claimer binary (exec form; the production image has no shell). - Mounts the exit_certificate run dir (parameters.toml + output/) at /data read-write, and derives the claimer config via --exit-certificate-config, which enables L1 sync. - All parameters configurable via env vars: EXIT_TOOL_DIR, EXIT_CERT_CONFIG, CLAIMER_ADDRESS, CLAIMER_PORT, AGGKIT_IMAGE. - Wires host.docker.internal so an l1RpcUrl pointing at the host is reachable from the container on Linux. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rk type could not be determined" Right after the network starts, the agglayer node has not yet classified the network and GetNetworkInfo fails with: Code: NotFound, Message: Network type could not be determined, Reason: GET_NETWORK_INFO_ERROR_KIND_UNKNOWN_NETWORK_TYPE waitForSettled aborted on any GetNetworkInfo error, so the e2e prepare_network.sh step (agglayer_certificate_status.sh --wait) failed intermittently. Treat this specific error as transient and keep polling, respecting the configured interval and timeout. Other errors still abort. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…cker/ Relocate docker-compose.yml and .env.example under tools/exit_certificate_claimer/docker/ and fix the relative paths that shift one level deeper: build context ../.. -> ../../.. and the default EXIT_TOOL_DIR ../exit_certificate -> ../../exit_certificate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a --version flag (via cli.VersionPrinter) and include the aggkit build traceability (version, git rev/branch, build date, Go version, OS/arch) in the GET /health response through the new HealthResponse / VersionInfo types. Build the binary with ldflags in the Makefile so the values are populated. Docs updated in README and SPEC. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
61f9dca to
ae3b1a1
Compare
…se healthcheck The production image ships without a shell or curl, so the claimer binary itself performs the HTTP probe: `exit_certificate_claimer healthcheck` GETs /claimer/v1/health and exits 0 (healthy) or 1. Wired as the docker-compose healthcheck; also documented volume-permission expectations (container runs as appuser) addressing the PR review suggestions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…laim step 60-claim_exit_certificate_funds.sh now supports CLAIMER_MODE=docker to run the claimer through tools/exit_certificate_claimer/docker/docker-compose.yml instead of a host background binary (default CLAIMER_MODE=binary, unchanged behavior). Docker mode writes a sibling copy of the exit_certificate config with 127.0.0.1/localhost rewritten to host.docker.internal so the container reaches the Kurtosis-published L1 RPC, mounts the config dir at /data (relative outputDir keeps resolving), and tears the stack down on exit. AGGKIT_IMAGE and CLAIMER_DOCKER_BUILD=0 allow reusing a prebuilt image. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ompose The exit-certificate E2E workflow now sets CLAIMER_MODE=docker so the claim step exercises the claimer via its docker-compose deployment (the artifact users actually deploy) instead of a host binary, and also triggers on tools/exit_certificate_claimer/** and Dockerfile changes. The compose service user is now parameterizable (CLAIMER_USER, default the image's appuser): the e2e passes the host uid:gid so L1 sync can write its SQLite DBs inside the mounted config dir regardless of the runner's uid. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Collaborator
Author
|
@codex review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Adds a --log-json boolean flag that switches the logger to aggkit's production environment (zap JSON encoder); the default stays the human-readable console format. Exposed in docker-compose via CLAIMER_LOG_JSON (default false). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…json Startup errors (config load, missing data files, ...) were returned to main and printed as a plain "Error: ..." line, escaping the JSON log stream. With --log-json they now go through the configured logger and the process exits 1 via cli.Exit; without the flag the plain error line is preserved. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gger unconditionally Fatal startup errors now always go through the configured logger (console format by default, JSON under --log-json) instead of urfave/cli's plain "Error: ..." line, matching how aggkit's cmd handles them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
3e2c1b4
into
feature/exit-certificate-tool
23 of 24 checks passed
joanestebanr
added a commit
that referenced
this pull request
Jul 10, 2026
…deployment (#1690) ## 🔄 Changes Summary Packaging and deployment preparation for the exit_certificate_claimer service. - 🐳 **Dockerfile**: ship the `exit_certificate` (generator) and `exit_certificate_claimer` (HTTP service) binaries in the aggkit image under `/usr/local/bin`, so the tools travel alongside `aggkit` and the same image can be used to deploy the exit_certificate_claimer. - 📦 **docker-compose**: add `tools/exit_certificate_claimer/docker/docker-compose.yml` to run the exit_certificate_claimer as a read-only HTTP service. It builds from the repo-root Dockerfile, overrides the entrypoint with the exit_certificate_claimer binary, and derives its whole config from the exit_certificate `parameters.toml` via `--exit-certificate-config`. Mounts the exit_certificate working dir at `/data` (read-write, since L1 sync keeps its SQLite DBs updated) and wires `host.docker.internal` so a host-pointing `l1RpcUrl` is reachable on Linux. Defines a `healthcheck:` and documents the volume-permission expectations (the container runs as `appuser`, uid 1000). - 🩺 **healthcheck subcommand**: `exit_certificate_claimer healthcheck` probes `GET /claimer/v1/health` of a running claimer and exits 0 (healthy) or 1. The production image ships without a shell or curl, so the binary itself performs the HTTP probe; the docker-compose healthcheck is backed by it. - 📜 **JSON logs**: new `--log-json` flag switches the claimer logs to JSON format (aggkit's `production` log environment, zap JSON encoder); the default remains the human-readable console format. Fatal startup errors are emitted through the configured logger too (JSON or console), instead of urfave/cli's plain `Error: ...` line. Exposed in docker-compose via `CLAIMER_LOG_JSON` (default `false`). - 🧪 **e2e docker mode**: `60-claim_exit_certificate_funds.sh` gains `CLAIMER_MODE=docker` to run the claimer through the docker-compose deployment instead of a host binary (a sibling config copy rewrites `127.0.0.1`/`localhost` to `host.docker.internal` so the container reaches the Kurtosis-published L1 RPC). The CI workflow sets it, so the e2e exercises the same artifact users deploy — image build from the repo-root Dockerfile included — and now also triggers on `tools/exit_certificate_claimer/**` and `Dockerfile` changes. The compose service user is parameterizable (`CLAIMER_USER`, default `appuser`) so L1 sync can write its SQLite DBs whatever the host uid. - ⚙️ **.env.example**: documented env vars (`EXIT_TOOL_DIR`, `EXIT_CERT_CONFIG`, `CLAIMER_ADDRESS`, `CLAIMER_PORT`, `CLAIMER_LOG_JSON`, `AGGKIT_IMAGE`) consumed by compose. - 🩹 **e2e fix**: `agglayer_status` (`agglayer_certificate_status.sh --wait`) now retries on the transient agglayer error raised right after the network starts, before the node has classified the network: ``` ERROR: get network info: failed to get network info: Code: NotFound, Message: Network type could not be determined, Details: [Reason: GET_NETWORK_INFO_ERROR_KIND_UNKNOWN_NETWORK_TYPE, Domain: agglayer-node.grpc-api.v1.node-state-service.get_network_info. ] ``` `waitForSettled` previously aborted on any `GetNetworkInfo` error, making the e2e `prepare_network.sh` step fail intermittently. This specific error is now treated as transient and polling continues (respecting the configured interval and timeout); other errors still abort. ##⚠️ Breaking Changes - None. ## 📋 Config Updates - New env-var driven setup for the exit_certificate_claimer (see `.env.example`). No changes to the existing TOML config. - New optional `--log-json` CLI flag (`CLAIMER_LOG_JSON` in compose) to emit JSON-formatted logs; defaults to the previous console format. ## ✅ Testing - 🖱️ **Manual**: - `make build-tools` / `go build ./tools/exit_certificate/... ./tools/exit_certificate_claimer/...` build cleanly. - From `tools/exit_certificate_claimer/docker/`: `cp .env.example .env` then `docker compose up --build` starts the exit_certificate_claimer serving on `CLAIMER_PORT`. - `exit_certificate_claimer healthcheck` verified against a live health endpoint (exit 0) and a closed port (exit 1). - Ran the claimer with and without `--log-json` and verified the log output switches between the zap JSON encoder and the console format, including fatal startup errors (logged as an error line in the active format, exit code 1). - 🧪 **Unit**: `go test ./tools/exit_certificate/scripts/agglayer_status/` covers the new retry-on-undetermined-network-type path; `go test ./tools/exit_certificate_claimer/...` covers the healthcheck probe (URL building, 200/non-200/unreachable, end-to-end against the real router). - 🚀 **E2E**: the exit-certificate tool E2E (CI) runs the claim step with `CLAIMER_MODE=docker`, validating the full docker deployment end to end: compose build of the aggkit image, container startup deriving the config, in-container L1 sync, `/claimer/v1/health` readiness and claiming every bridge exit against the containerized service. ## 📝 Notes - The exit_certificate_claimer runs from the same working directory the exit_certificate tool used (config + `output/`), so no separate config file is needed. - PR base: `feature/exit-certificate-tool` (packaging/deployment work only). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <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.



🔄 Changes Summary
Packaging and deployment preparation for the exit_certificate_claimer service.
🐳 Dockerfile: ship the
exit_certificate(generator) andexit_certificate_claimer(HTTP service) binaries in the aggkit image under/usr/local/bin, so the tools travel alongsideaggkitand the same image canbe used to deploy the exit_certificate_claimer.
📦 docker-compose: add
tools/exit_certificate_claimer/docker/docker-compose.ymlto run the exit_certificate_claimer as a read-only HTTP service. It builds from
the repo-root Dockerfile, overrides the entrypoint with the
exit_certificate_claimer binary, and derives its whole config from the
exit_certificate
parameters.tomlvia--exit-certificate-config. Mounts theexit_certificate working dir at
/data(read-write, since L1 sync keeps itsSQLite DBs updated) and wires
host.docker.internalso a host-pointingl1RpcUrlis reachable on Linux. Defines ahealthcheck:and documents thevolume-permission expectations (the container runs as
appuser, uid 1000).🩺 healthcheck subcommand:
exit_certificate_claimer healthcheckprobesGET /claimer/v1/healthof a running claimer and exits 0 (healthy) or 1.The production image ships without a shell or curl, so the binary itself
performs the HTTP probe; the docker-compose healthcheck is backed by it.
📜 JSON logs: new
--log-jsonflag switches the claimer logs to JSONformat (aggkit's
productionlog environment, zap JSON encoder); the defaultremains the human-readable console format. Fatal startup errors are emitted
through the configured logger too (JSON or console), instead of urfave/cli's
plain
Error: ...line. Exposed in docker-compose viaCLAIMER_LOG_JSON(default
false).🧪 e2e docker mode:
60-claim_exit_certificate_funds.shgainsCLAIMER_MODE=dockerto run the claimer through the docker-compose deploymentinstead of a host binary (a sibling config copy rewrites
127.0.0.1/localhostto
host.docker.internalso the container reaches the Kurtosis-published L1RPC). The CI workflow sets it, so the e2e exercises the same artifact users
deploy — image build from the repo-root Dockerfile included — and now also
triggers on
tools/exit_certificate_claimer/**andDockerfilechanges. Thecompose service user is parameterizable (
CLAIMER_USER, defaultappuser) soL1 sync can write its SQLite DBs whatever the host uid.
⚙️ .env.example: documented env vars (
EXIT_TOOL_DIR,EXIT_CERT_CONFIG,CLAIMER_ADDRESS,CLAIMER_PORT,CLAIMER_LOG_JSON,AGGKIT_IMAGE) consumedby compose.
🩹 e2e fix:
agglayer_status(agglayer_certificate_status.sh --wait) nowretries on the transient agglayer error raised right after the network starts,
before the node has classified the network:
waitForSettledpreviously aborted on anyGetNetworkInfoerror, making thee2e
prepare_network.shstep fail intermittently. This specific error is nowtreated as transient and polling continues (respecting the configured interval
and timeout); other errors still abort.
📋 Config Updates
.env.example).No changes to the existing TOML config.
--log-jsonCLI flag (CLAIMER_LOG_JSONin compose) to emitJSON-formatted logs; defaults to the previous console format.
✅ Testing
make build-tools/go build ./tools/exit_certificate/... ./tools/exit_certificate_claimer/...build cleanly.tools/exit_certificate_claimer/docker/:cp .env.example .envthendocker compose up --buildstarts the exit_certificate_claimer serving onCLAIMER_PORT.exit_certificate_claimer healthcheckverified against a live health endpoint(exit 0) and a closed port (exit 1).
--log-jsonand verified the log outputswitches between the zap JSON encoder and the console format, including
fatal startup errors (logged as an error line in the active format, exit code 1).
go test ./tools/exit_certificate/scripts/agglayer_status/covers thenew retry-on-undetermined-network-type path;
go test ./tools/exit_certificate_claimer/...covers the healthcheck probe(URL building, 200/non-200/unreachable, end-to-end against the real router).
CLAIMER_MODE=docker, validating the full docker deployment end to end:compose build of the aggkit image, container startup deriving the config,
in-container L1 sync,
/claimer/v1/healthreadiness and claiming every bridgeexit against the containerized service.
📝 Notes
exit_certificate tool used (config +
output/), so no separate config file is needed.feature/exit-certificate-tool(packaging/deployment work only).🤖 Generated with Claude Code