security(reputation): prevent source-generation ABA replay - #191
Draft
seonghobae wants to merge 8 commits into
Draft
Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Refs #190 and #192. Draft child of #189.
Exact parent/current base remains
#189@7f715a843236bcb79452fc1b3c84d50f34da9981.Original RED and bounded lifecycle implementation
The first production-unchanged hostile fixture was established at
ce56ee0645c046a4572e97cf9cc4889945205b59. Hosted CI34165964131, job101876937399, completed checkout, Rust setup, and formatting, then failed becauseSourceGenerationLifecycleCursorV1,SourceGenerationLifecycleErrorV1, andEvidenceSnapshotV1::replace_source_with_lifecycledid not yet exist.1504a1424f737016461dc0f84db2659c027649a9added a bounded pure-Rust current-generation lifecycle cursor and atomic immutable snapshot+cursor return value. CI then exposed a dead-module integration defect;f9b00db81790b335f9f06ce4d48770ff8630f0c2declared/re-exported the module.3aac5304773652096a5895ec95b60fcf858005afadded stale ordinal, collision, schema/text/time, invalid retained-cursor, and missing/spurious cursor-membership cases. Formatting-onlyc30a9028c69011b6884825841f761f12916f5bfcand9d42b7da750570a970785242b7f26072e89a558eapplied hosted rustfmt output. Exact9d42...then passed CI34168771438and Fuzz34168771365.That GREEN proved only single-hop/current-cursor invariants. Fresh exact-source review found that it did not satisfy the issue-level historical ABA claim.
Multi-hop ABA RED — current exact state
Current exact source head is
ed6ba763b7feeb9a4ac67653776619c34783023e. It is a non-force, test-only child of9d42...; comparison is ahead 1 / behind 0 and changes onlycrates/wardnet-reputation-core/tests/source_generation_lifecycle.rs(+38/-0). Production source is unchanged.The added hostile sequence is:
generation-8 @ ordinal 8;generation-9 @ ordinal 9;generation-8at authenticated ordinal 10;ReusedSourceGeneration.Hosted CI
34172081051, rust job101894179030, acquired GitHub-hosted runner1001761240. Checkout/toolchain andcargo fmt --checksucceeded.cargo test --locked --workspacethen failed exactly insource_generation_lifecycle_rejects_aba_token_rebinding_at_a_newer_ordinal: the implementation returnedOk(SourceReplacementTransitionV1 { ... source_generation: "generation-8", source_generation_ordinal: 10 ... })while the test requiresErr(ReusedSourceGeneration). Nine other lifecycle tests passed. Clippy was skipped after the semantic test failure.Exact Fuzz
34172081085, job101894179222, is terminal SUCCESS on the same unchangeded6ba763b7feeb9a4ac67653776619c34783023e. GitHub-hosted runner1001761232completed checkout/toolchain/cargo-fuzz setup and every bounded fuzz target; no crash artifact was produced. This does not convert the semantic CI RED into GREEN.This is the current authoritative RED. The predecessor
9d42...successes must not be represented as exact-current GREEN.Root cause and causal successor
SourceGenerationLifecycleCursorV1retains only the currently represented generation token/ordinal. After8@8 -> 9@9, historical binding8@8is forgotten, so a current-only cursor cannot prove that8@10is a replay. A fixed-size recent-token cache would merely postpone ABA acceptance or impose an arbitrary source lifetime and is not an acceptable commercial security invariant.#192 now owns the durable causal repair under #80: tenant-scoped PostgreSQL uniqueness must bind both
(source_id, source_generation)and(source_id, source_generation_ordinal)and commit those bindings atomically with producer lifecycle state, evidence snapshot, completeness/pagination proof, and last-known-good publication. Real PostgreSQL tests must cover multi-hop ABA, concurrent writers, crash/retry/idempotency, RLS/pool context, migrations, and restore. #140 Runtime Configuration is the prerequisite foundation before reconstructing #80; stale mixed #95 is evidence only and must not be imported wholesale.This PR deliberately remains Draft/RED until that durable history authority exists or another bounded implementation can prove the full invariant without weakening it. Do not delete the hostile test, cap history to manufacture GREEN, or claim a current-only cursor is global replay authority.
Boundary
The contract remains Wardnet security-evidence admission only. It performs no feed fetching, HTTP/304 interpretation, destination URL/DNS/peer/redirect/proxy/TLS/resource authorization, Context Graph/EA mutation, quarantine execution, LLM/provider routing, or AppGuardrail analysis. Authenticated normalized ordinal derivation remains source-adapter authority. Durable reputation history remains Wardnet-owned state under #80/#192.
No predecessor-result transfer, self/model approval, routine administrator bypass, force push/destructive rebase, mutable foreign dependency, source copy, cross-service SQL, or gate weakening.