Repository navigation
feat(verifier): admin console package (search, reschedule, recovery, action log) - #1500
Conversation
|
👋 tt-cll, thanks for creating this pull request! To help reviewers, please consider creating future PRs as drafts first. This allows you to self-review and make any final changes before notifying the team. Once you're ready, you can mark it as "Ready for review" to request feedback. Thanks! |
There was a problem hiding this comment.
🟡 Changes recommended
Missing proxy identities are accepted, and recovery, rescheduling, and audit paths have correctness gaps.
10 open findings
Correlate audit intent and outcome rows · New Reject missing identity headers on privileged routes · New Add audit log pagination beyond 100 rows · New Persist idempotency keys before submission · New Render full search page for non-HTMX validation errors · New Condense protobuf boundary comment · New Condense shared database and secrets comment · New Condense flow description comment · New Condense ownership and migration comment · New Condense unavailable-versus-empty comment · New
What changed in this PR
Adds the currently unwired verifier admin-console package for searching failures, rescheduling jobs, managing recovery operations, and auditing mutations.
Changes:
- Adds the Gin/templ console, authentication, CSRF protection, views, and assets.
- Implements attestation-gated rescheduling, durable recovery controls, and action logging.
- Adds storage clients, migration, secrets schema, documentation, and tests.
| File | Description |
|---|---|
verifier/pkg/admin/actionlog.go |
Persists and lists audit actions. |
verifier/pkg/admin/actionlog_test.go |
Tests action-log persistence. |
verifier/pkg/admin/attestation.go |
Checks aggregator attestation state. |
verifier/pkg/admin/attestation_test.go |
Tests freshness outcomes. |
verifier/pkg/admin/auth.go |
Defines access-policy and basic-auth handling. |
verifier/pkg/admin/auth_test.go |
Tests authentication rules. |
verifier/pkg/admin/config.go |
Defines console configuration. |
verifier/pkg/admin/config_test.go |
Tests configuration validation. |
verifier/pkg/admin/detail.go |
Builds message-detail data. |
verifier/pkg/admin/detail_test.go |
Tests message details. |
verifier/pkg/admin/handlers.go |
Provides shared handlers and core routes. |
verifier/pkg/admin/recoveryops.go |
Implements recovery operations and evidence. |
verifier/pkg/admin/recoveryops_test.go |
Tests recovery workflows. |
verifier/pkg/admin/reschedule.go |
Implements guarded rescheduling. |
verifier/pkg/admin/reschedule_test.go |
Tests rescheduling safety. |
verifier/pkg/admin/search.go |
Implements archived-job search. |
verifier/pkg/admin/server.go |
Builds and runs the HTTP server. |
verifier/pkg/admin/server_test.go |
Tests routing and CSRF. |
verifier/pkg/admin/stores.go |
Adapts verifier database stores. |
verifier/pkg/admin/views/actions.templ |
Defines the action-log page. |
verifier/pkg/admin/views/actions_templ.go |
Generated action-log view. |
verifier/pkg/admin/views/detail.templ |
Defines the detail page. |
verifier/pkg/admin/views/detail_templ.go |
Generated detail view. |
verifier/pkg/admin/views/layout.templ |
Defines the shared layout. |
verifier/pkg/admin/views/layout_templ.go |
Generated layout view. |
verifier/pkg/admin/views/recovery.templ |
Defines recovery UI. |
verifier/pkg/admin/views/recovery_templ.go |
Generated recovery view. |
verifier/pkg/admin/views/reschedule.templ |
Defines rescheduling UI. |
verifier/pkg/admin/views/reschedule_templ.go |
Generated rescheduling view. |
verifier/pkg/admin/views/search.templ |
Defines search UI. |
verifier/pkg/admin/views/search_templ.go |
Generated search view. |
verifier/pkg/admin/views/static.go |
Embeds browser assets. |
verifier/pkg/admin/views/static/admin.css |
Styles the console. |
verifier/pkg/admin/views/static/favicon.svg |
Adds the console icon. |
verifier/pkg/admin/views/static/htmx.min.js |
Vendors htmx. |
verifier/pkg/vsecrets/vsecrets.go |
Adds admin UI credentials. |
verifier/pkg/vsecrets/doccomments_gen.go |
Documents the new secret fields. |
verifier/migrations/postgres/00010_admin_actions.sql |
Creates the audit table. |
integration/storageaccess/aggregator_results_client.go |
Adds the aggregator results client. |
integration/storageaccess/aggregator_results_client_test.go |
Tests protobuf translation. |
tools/configdoc/registry/registry.go |
Registers example admin credentials. |
docs/config/verifier/secrets.documented.toml |
Documents [admin_ui]. |
go.mod |
Adds templ. |
go.sum |
Records templ checksums. |
Files not reviewed (2)
- verifier/pkg/admin/views/actions_templ.go: Generated file
- verifier/pkg/admin/views/detail_templ.go: Generated file
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| // One target at a time: the gate, the intent row, the mutation, then the | ||
| // outcome row — so the audit log reads as adjacent intent/outcome pairs. |
There was a problem hiding this comment.
Done — each reschedule target now generates a correlation UUID, written into operation_id on both the intent and the outcome row, so concurrent requests can no longer break the pairing (rows also keep actor/action/target).\n\nThis also answers the operation_id empty note: it is never empty for reschedule rows now, and the Action.OperationID doc comment states the correlation semantics.
4e233e0 to
96e2f75
Compare
makramkd
left a comment
There was a problem hiding this comment.
Awesome stuff! I have some more simplification suggestions below, let me know what you think.
| -- Admin console action log. The console runs in the verifier process and audits its | ||
| -- mutations here, in the verifier's own application database. | ||
| CREATE TABLE IF NOT EXISTS ccv_admin_actions ( |
There was a problem hiding this comment.
Just sanity-checking: migrations added here are typically added to the CL migrations as well. But since this feature will probably never be enabled in CL mode, I guess its safe to skip this one?
There was a problem hiding this comment.
And I guess this is basically an audit trail for the admin of what they ended up doing in the admin mode right?
We don't have this kind of thing in the chainlink operator UI AFAIK, so I think its OK to axe and keep things in-mem. We could create a follow-up ticket to persist it if its something that we think is useful.
| // Access configures how the console identifies who is acting. | ||
| Access AccessConfig `toml:"access"` |
There was a problem hiding this comment.
I think we can remove this, seems like too much knobs. Looking at the docstring from the AccessConfig struct, it might be a relic of the previous admin UI that we were thinking could potentially connect to multiple verifier nodes. But since that isn't the case, we can remove it.
| type AccessConfig struct { | ||
| // ActorHeader names the HTTP header carrying an authenticated identity from a | ||
| // fronting proxy (shared hosting). Empty means self-hosted loopback: actor "local". | ||
| // Non-loopback serving requires this header or [admin_ui] basic auth, and a | ||
| // configured-but-absent header rejects the request (validated at startup). | ||
| ActorHeader string `toml:"actor_header"` | ||
| } |
There was a problem hiding this comment.
Can remove, like I mentioned above.
| // AggregatorAddress (optional, host:port) overrides the aggregator used for | ||
| // attestation freshness checks via the unauthenticated GetVerifierResultsForMessage. | ||
| // Empty uses the verifier's own first configured aggregator. | ||
| AggregatorAddress string `toml:"aggregator_address"` |
There was a problem hiding this comment.
Also curious about this - we typically configure multiple aggregators, and it seems like we have access to that since the docstring here says "Empty uses the verifier's own first configured aggregator".
Can we just use that for now, and maybe in a followup, we can check the attestation reached all aggregators, if that's not too complex a lift? That way operators would not have to reconfigure same info in multiple places.
Concretely that means we can get rid of this config and just use the first configured aggregator for now, and in the future, we automatically check in all configured aggregators (or a subset, maybe from some UI toggle/checklist/dropdown).
|
One more question, since I probably missed it from the diff view: how is the frontend built? Wondering if we need some extra CI checks to validate freshness (if we commit the fully compiled frontend). |
|
Code coverage report:
Files added (in
|



Summary
Bottom of a 3-PR stack splitting #1471, reworked per review: the console is scoped to the single verifier it runs beside — no multi-node
[[nodes]]config, no separate console database, no read-only mode.This PR adds the self-contained console package plus its direct dependencies:
verifier/pkg/admin— server-rendered UI (templ/htmx, Gin) over the verifier's own application DB: message search, message detail, gated reschedule (archive + attestation freshness re-checked on every execution), source-range recovery (replay / reset-reader with durable operations), and a fail-closed action log (intent row before every mutation).verifier/migrations/postgres/00010_admin_actions.sql— the action log lives in the verifier's own migrations, not a separate goose table/DB.verifier/pkg/vsecrets— optional[admin_ui]basic-auth credential in the verifier secrets file.integration/storageaccess— unauthenticated aggregator results read client used for attestation freshness checks (aggregator-only; the indexer path was dropped per review).Nothing serves the console yet — that wiring is #1501.
Note:
admin.Deps.ResultsDialeris an optional injection seam for the attestation read path; production wiring leaves it nil (real aggregator dial), tests and the demo harness (#1502) substitute a canned client.Stack: this PR → #1501 → #1502. Supersedes the package portion of #1471.