Skip to content

fix: TWI API idempotency account scope - #208

Merged
pdf-amzn merged 4 commits into
ExtendDB:mainfrom
yesyayen:fix/idempotency-account-scope
Jul 15, 2026
Merged

fix: TWI API idempotency account scope#208
pdf-amzn merged 4 commits into
ExtendDB:mainfrom
yesyayen:fix/idempotency-account-scope

Conversation

@yesyayen

@yesyayen yesyayen commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

What

TransactWriteItems idempotency tokens were stored keyed on the token alone (PRIMARY KEY (token)). A ClientRequestToken is unique per account in Amazon DynamoDB, but the Postgres data database is shared, so tokens from different accounts collided.

Re-key idempotency_tokens on (account_id, token) (new data migration 003) and thread the caller's account from the TransactWriteItems handler into the token check.

Why

Two accounts sharing one token keyspace violates account isolation:

Two accounts, same token Before After (matches DynamoDB)
identical request account B's write silently dropped as a replay each account applies independently
different request account B rejected with IdempotentParameterMismatchException each account applies independently

Single-account behavior (replay-idempotent, mismatch, independence) is unchanged.

Closes # n/a.

Testing done

  • New tests/test_idempotency_account_scope.py: 3 single-account cases pass against Amazon DynamoDB and ExtendDB; 2 cross-account isolation cases (ExtendDB-only, two accounts) red before, green after.
  • cargo test --workspace, cargo fmt --check, cargo clippy --workspace -- -D warnings: clean. No regressions.

Checklist

  • I have read CONTRIBUTING.md
  • All tests pass (cargo test --workspace)
  • Code is formatted (cargo fmt --check)
  • Clippy is clean (cargo clippy -- -W clippy::pedantic)
  • I have added or updated tests for new functionality
  • I have updated documentation if behavior changed
  • Breaking changes are noted below (if any)
  • If this changes the wire protocol, Storage trait, auth model, on-disk
    format, or public CLI surface, an RFC has been accepted or is linked
    below. Otherwise, an ADR captures the decision (link below).

ADR / RFC: n/a. Refines the internal DataEngine::transact_write_items signature (see below).

Breaking changes

  • DataEngine::transact_write_items now takes Option<IdempotencyKey<'_>> instead of Option<(&str, &str)>. Backends must scope their idempotency store on (account_id, token). The SQLite backend (feat: SQLite storage backend (in-tree) with developer mode #182) has the same defect and is handled in that PR.
  • Migration 003 recreates idempotency_tokens. Apply during stop / migrate / restart; a client retry straddling the migration loses dedup for that short-lived cache.

yesyayen added 3 commits July 9, 2026 17:08
ClientRequestToken uniqueness is per account in Amazon DynamoDB, but the
Postgres idempotency_tokens table (a single shared data database) keyed on
token alone, so tokens from different accounts collided: an identical token
was treated as an idempotent replay (dropping another account's write) or a
parameter mismatch (rejecting it).

Re-key on (account_id, token) via a new data migration and thread the
account through the storage trait, matching every other account-scoped
table. Global TTL cleanup and the payload fingerprint are unchanged.
Single-account replay/mismatch/independence dual-targeted against Amazon
DynamoDB and ExtendDB; cross-account isolation (same token from two accounts)
asserted ExtendDB-only, since one AWS account cannot exercise a collision.
Backend-implementer contract now mandates keying idempotency tokens on
(account_id, token); storage design doc reflects the real account-scoped
schema and fingerprint flow.
@yesyayen yesyayen changed the title Fix/idempotency account scope fix: TWI API idempotency account scope Jul 9, 2026
@yesyayen yesyayen mentioned this pull request Jul 9, 2026
8 tasks
@pdf-amzn
pdf-amzn added this pull request to the merge queue Jul 15, 2026
Merged via the queue into ExtendDB:main with commit d508948 Jul 15, 2026
8 checks passed
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.

3 participants