Skip to content

✨ EMS-AUDIT: imports' checksums, deleted events in account exports, admin keys after commit, new tenants' realms (part 2) - #3929

Merged
ereslibre merged 11 commits into
ovcsfrom
feat/meta-13781-audit-completion/ovcs
Oct 17, 2026
Merged

ereslibre merged 11 commits into
ovcsfrom
feat/meta-13781-audit-completion/ovcs

Conversation

@ereslibre

@ereslibre ereslibre commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Parent issue: https://github.com/sequentech/meta/issues/13781

Design package EMS-AUDIT, second part. #3902 gave each tenant a signed tenant log; this pull request closes the gaps it listed or left open, apart from the route-by-route entries (see "Split with #3928" below).

What changes

Area Change
Imports Importing an election event or a tenant configuration records the file's SHA-256, computed by the task from the file it read, and compares it with the checksum the admin declared (undeclared, matches or mismatch). The entry also counts what the file held: elections, contests, candidates, areas and areas per contest, or configuration sections. A failed commit of a tenant configuration import no longer records the import.
Entry popup A new The imported file section shows the checksum verdict, the SHA-256, the counts and the document, instead of raw extra details. The deleted election event section names The log's system key. Translated into the portal's 8 languages.
Deleted events in exports One account's export with "every election event" now also reads the logs of deleted events from their retired databases, merged by time; their rows name retired event <ID>. Each retired database is checked against the catalog, opened read-only under the event database lock, and closed to connections again, including when the read fails. The deletion entry keeps the retired log's system public key, since the event's keys are deleted with it.
Admin public keys AdminPublicKey is posted to the tenant log only once the transaction that saved the key commits. A rollback leaves nothing behind (before, it could leave a public key in the log whose key was then lost). The delivery id is per account and key, so the key is posted once. The tenant log migration backfills keys created before keys went to the tenant log, and running it again does nothing. The outbox can't carry this statement (it only posts Audit bodies), so a small post-commit task does it instead.
New tenants Creating a tenant prepares its Keycloak realm for the tenant log whatever the realm template: custom-event-listener, admin events with details, and the tenant-logs-read / tenant-logs-export roles granted to the admin group.
Monitoring Every audit outbox worker pass writes {"target":"audit_log_outbox","pending_entries":N,"oldest_pending_seconds":S}, zeros included, so security monitoring can alert on entries waiting more than 5 minutes. This replaces the waiting/oldest_seconds names. It is documented in the developer page.
Permissions /export-tenant-logs needs tenant-logs-read as well as tenant-logs-export (403 otherwise). The portal shows the tenant log's Export only to people who have both.
Fix Tenant log exports could not be downloaded: fetch-document built a private document's S3 key from the event the caller named. The tenant log asks with an empty event, so the link pointed at tenant-…/event-/document-… (NoSuchKey). The key now comes from the document's own event.
Docs Settings > Logs reference: the popup's new sections, deleted events in account exports, the export permissions. Developer page: the backlog line and its alert threshold. Auditor tutorial: retired logs, which have no system key in the manifest.

Split with #3928

#3928 (VOTE-AUDIT, meta#14259) closes the "routes write no AdminChange" gap from #3902 for every Harvest route, including messaging accounts, certificate authorities, countries and deleting a tenant. It does this by letting the audit_change() trigger see Step's own writes. To avoid logging each change twice, this pull request adds no per-route entries. The two pull requests touch different files.

Acceptance (meta#13781)

Ticked where #3902 (merged) and this pull request together meet the criterion. Items 2, 3 and 5 also need #3928.

Not in this pull request

  • EMS-SBEI-QUORUM's signing entries still use their own signing_log_outbox.
  • Tenant log checkpoints and an audit task for the tenant log (VOTE-AUDIT).
  • Erasing or reopening a retired event database (OPS-RETENTION).
  • Beyond's client-setup chart still configures only jboss-logging for the tenant realm. Existing realms are set up by the one-off task, and new tenants by this pull request.

Upgrade notes

  • Monitoring that parsed the outbox line's waiting/oldest_seconds must read pending_entries/oldest_pending_seconds.
  • Roles that exported the tenant log with only tenant-logs-export need tenant-logs-read too.

Tests

  • electoral-log: 124 tests with the database tests (--include-ignored), including reading a retired database and closing it again.
  • windmill: 1705 lib tests pass. decrypted_archives_use_private_owned_files_and_leave_no_plaintext needs an openssl binary on the host, and passes with one. postgres_audit_log_outbox (8, including the post-commit key announcement, the backfill and retired events in exports) and postgres_audit_change (18) pass.
  • harvest: 561 pass, including the new 403 for an export without read permission.
  • admin-portal: 2233 jest tests, LogEntryDialog stories (17, with a new import story), story inventory, typecheck:stories, and the journeys settings/logs, settings/access and events/operations (29).
  • End to end on a local stack built from this branch (Keycloak, Hasura, Harvest, Windmill, PostgreSQL, MinIO, production portals), using the backend E2E bootstrap. All 11 UI journeys pass. The stack also checked, by hand: the import entry's checksum and counts; retired databases read and closed again; the account export's download and its retired rows; a new tenant's realm settings and roles; the backlog line. That run found the export download bug fixed here.

Not measured locally: the per-package coverage gates.

Demo

Video with voiceover, to upload to meta#13781: import, then an event edit, deletion, the account export with the retired log, a new tenant's realm, and the backlog line.

🤖 Generated with Claude Code

ereslibre and others added 9 commits October 16, 2026 21:49
… backlog line, admin keys after commit, retired events in account exports

- Election event and tenant configuration imports record the file's computed
  SHA-256, the declared checksum and whether they match, and counts.
- New tenants' realms get the tenant log listener, admin events and roles.
- Every outbox worker pass writes pending_entries and oldest_pending_seconds.
- AdminPublicKey is posted after the key's transaction commits, under a
  delivery id per account and key; the tenant log migration backfills keys
  the tenant log does not announce.
- ACCOUNT_WITH_EVENTS exports read deleted events' retired databases, opened
  read-only for the read under the event database lock and closed again; the
  deletion entry keeps the retired log's system public key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An export holds what the log holds: `/export-tenant-logs` now refuses
with 403 a caller with `tenant-logs-export` but without
`tenant-logs-read`, as the design asks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… counts

An import's entry now shows the file's SHA-256, whether it matches the
checksum the admin declared, and what the file held, instead of raw
extra details. The tenant log's Export shows only to those who can also
read it, as Harvest requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fetch-document built a private document's S3 key from the election event
the caller named. The tenant log's Export asks with an empty event, so
its link pointed at tenant-…/event-/document-…, which does not exist:
every tenant log export failed to download with NoSuchKey. The key now
comes from the document's own election event.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The deletion entry now keeps the retired log's system public key, since the
event's keys are deleted with it. The popup shows it in the deleted event's
section instead of as a raw detail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d export permissions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ereslibre ereslibre self-assigned this Oct 16, 2026
@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review: 2
  • release/10.0
  • feat/meta-12767/.*

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: sequentech/step/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 64c98b26-f591-46a1-b041-41658ce459e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-17 00:30 UTC

@ereslibre
ereslibre marked this pull request as ready for review October 16, 2026 22:21
ereslibre and others added 2 commits October 17, 2026 00:26
…s without a server

The coverage profile skips the database tests, so the new read of a
retired event database lowered electoral-log-native's ratios. Check the
retired database's IDs before the server is asked, and test that read,
the read-only store, log queries and board names without a server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only a route test whose realm keys can't be fetched reached the
reason of KEYS_UNAVAILABLE, and not on every run, so harvest's
coverage changed between runs of the same code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ereslibre
ereslibre merged commit 43b0a55 into ovcs Oct 17, 2026
77 checks passed
@ereslibre
ereslibre deleted the feat/meta-13781-audit-completion/ovcs branch October 17, 2026 00:25
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.

1 participant