fix(api): make revision approval, signed action consumption and audit receipts transactional #40
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Scope and source
Priority: P0. Gap coverage: GAP-005, GAP-007, GAP-016, GAP-017, GAP-024, GAP-042. Derived from GAP_1791945837.md, reviewed code commit
f8dbe93df953a78b17cb3304b717dcf84c4cd517. Currente476a68da09645c2308cbf47b90211fcaffcb7afadds only the report, so implementation findings remain applicable. Report evidence is local reproduction/source inspection unless explicitly proposed; no production exploit or current live-readiness claim.Coverage and sequencing: gap backlog tracker. Workstream 05. Dependencies: 02, 03.
Current codebase
Amendment hash checks precede a DB update that predicates only on draft status; title-only changes do not change body hash. Opening and analysis validate outside their mutation transactions. Signatures always get new UUIDs and replay creates duplicate drafts/comments/analysis. Comment caps use separate COUNT checks and analysis has no wallet quota. Timestamp subtraction can overflow. Stored hashes omit original signed payload bytes and proposal/revision linkage.
Why this implementation is needed
Concurrent edits can open unreviewed content, replay can spam records, quotas can race, and persisted records cannot independently prove what was signed.
Relevant files
operator-voting/src/api.rsoperator-voting/src/db.rsoperator-voting/src/payload.rsoperator-voting/src/crypto/adr36.rsoperator-voting/src/crypto/eip191.rsledger/migrations/20260825000002_voting.sqlledger/migrations/20260830000002_draft_lifecycle.sqloperator-voting/tests/api_flow.rsdocs/OPERATOR_VOTING.mdRecommended solution
Introduce complete monotonic revisions covering title/sections and future schedule/editor metadata. Inside one transactional service, verify actor/role/blacklist, expected revision/state, independence, quota and unique nonce/action consumption, then mutate and persist a receipt. Opening verifies the signed complete revision and performs its existing one-time freeze in that transaction; analysis references the reviewed revision. Return prior receipts for safe response-loss retries. Require ordered timestamps, bounded issue time and positive checked TTL with injectable clock. Store exact signed bytes, scheme/domain, action/revision links, content hashes, actor/opening and freeze metadata; retain immutable history and export verifiable receipts. Define versioned payload migration and explicit legacy-receipt limits.
Constraints and guardrails
Preserve standalone offchain advisory voting, no new smart contracts or archive-node dependency, BSC as a core electorate, raw 18-decimal integer balances and separate Terra/BSC address identities. Keep Legal fail-closed transactional UI and the proven DEX Terra/Bridge EVM connectors; no browser BSC balance RPC, seed/key prompt or embedded admin/model credential. API must retain a restricted role separate from the ledger writer. Freeze at actual opening, never at draft creation or a client-supplied height. Agents own design, implementation, review and evidence under repository guidance; do not shift approvals/tests to the human or invent PASS evidence.
Acceptance criteria
One of concurrent stale revisions succeeds; title-only changes invalidate approval. No analysis is appended after opening and quota limits hold under concurrency. Replayed accepted actions cannot create extra state/signature rows. Timestamp extrema neither panic nor bypass TTL. Independent verification reconstructs accepted Terra/BSC actions from persisted data alone.
Test plan: supported paths, failure paths and concurrency
Full ADR-36 wallet-format and EIP-191 register→draft→amend→comment→analysis→open→vote lifecycles. Barrier-controlled amend/amend, amend/open, analyze/open, quota-at-cap and duplicate-open/action races. Wrong actor/revision/hash/status, author analysis, blacklisted actors, expired/skewed/reversed/extreme times, release arithmetic, lost responses, DB rollback and process restart. Verify original versus superseded revisions and immutable exported receipts.
Test plan: attack, hack and abuse vectors
Replay across purposes/chains/proposals; nonce reuse with altered bytes; forged signer/domain, cross-scheme blobs, extreme timestamps and signature malleability; parallel spam bypassing caps; receipt tampering, actor privilege changes at commit and opening unreviewed title/editor/schedule. Assert no partial mutation or unverifiable successful action.
Verification and completion criteria
Attach concurrency barriers/results and independent receipt-verifier output including tamper failures. Run Rust unit/debug and release timestamp regressions plus isolated DB integration tests for both signature schemes; document protocol/backfill compatibility without claiming old hash-only rows are fully verifiable.
Record commit and pinned toolchain, commands/results and sanitized artifacts. Relevant Rust changes require
cargo test --workspace --libplus isolated Postgres integration (explicit guarded LEDGER_TEST_DATABASE_URL); frontend changes requirenpm testand production build plus relevant browser cases. Run secret scanning for new fixtures/config. Exercise fresh/upgrade migrations when schema/grants change; report skipped/live-only checks explicitly.Implementation status after main merge PR #53, commit
cd07f00f32f04ad02f8b760ed34588fd9645919e:Services are paused while existing storage is audited and the corrected pinned release is prepared. No production wallet transaction or hardware-wallet/Legal QA is claimed. This is an interim report; the issue remains open and the final comment will map the original criteria to actual live results and any unverified cases.
Implemented transactional revision approval, replay-safe signed actions and independently verifiable receipts. Changes are in PR #53, #54, #55, #56, and the throughput/test followup #59. PR #59 is merged with passing CI. Ledger/API/frontend deployments finished and are running healthy at final code
5cd9363307dc1607de952ac3243193c1a16304c7. Final live evidence.Original acceptance and test-plan checklist:
verified wallet signature and signed action/content links. Genuine high-s, wrong network, cross-scheme, purpose and proposal-target attacks reject without records.CARGO_BUILD_JOBS=2 scripts/verify-release.shrelease13 passes 74 unit/supervisor tests, 121 integrations (66 ledger), 245 schema validations and 146 frontend tests, production build, both nginx checks and Gitleaks. Machine-readable results, combined report, and lifecycle evidence record commands, barriers, receipt/tamper and migration results. The late supervised database-recovery exit fixture is corrected: at most one nonzero restart, then fresh both-chain/intent progress and sustained readiness; four fresh repeats pass.5cd9363307dc1607de952ac3243193c1a16304c7. All three services are running healthy; smoke 13, four canonical fixtures and runtime configuration checks pass. Loki contains no post-activation ledger warnings; the direct Coolify rpc_missing_result warning at 13:56:21 precedes activation at 13:58:22. Final artifact.Operational observation: the first public window returned 44/45 successful checks, with one 503 at 14:00:58 followed by 200 on the next check. Its cause remains unexplained and is retained in the evidence. Subsequent accepted public/private windows pass with unchanged thresholds and actual observed tips; no unhealthy observation is represented as healthy.
Evidence limits: funded-holder/committee live proposal/vote, hardware/mobile wallet and live human Legal QA are unexecuted broader variants. Hash-only legacy receipts cannot recover original signed bytes; frozen heights/power remain operator ledger evidence. Future schedule/editor fields must join the complete signed revision if introduced. The signed lifecycle, concurrency, replay, timestamp and independent-verification criteria are satisfied by the evidence above. The recorded 503 shows no failure of a signed action or persisted-record invariant.
Final evidence is published through PR #60. All mandatory body/comment criteria are satisfied by the checklist above; closing this issue.