Repository navigation
fix: enforce the table quota, the provisioned-capacity maxima and max_policy_document_bytes - #831
Open
LeeroyHannigan wants to merge 5 commits into
Open
LeeroyHannigan wants to merge 5 commits into
LeeroyHannigan wants to merge 5 commits into
Conversation
Pure checks for max_tables_per_account, per_table_max_rcu/wcu and per_account_max_rcu/wcu, with the LimitExceededException sentences the service returns for a provisioned value over a maximum.
CreateTable counts the account's tables and refuses one over max_tables_per_account, and CreateTable and UpdateTable refuse a provisioned throughput over the per-table or account maximum with LimitExceededException. A name the account already holds is still refused as taken first.
The size limit of a policy document was the literal 6,144 in PolicyDocument::from_json, so the max_policy_document_bytes key changed nothing. The key is now the limit on both paths. - Write: from_json_for_write now takes the limit as an argument. The management API's policy and permissions boundary handlers and the console's policy page pass the key to it. - Read: the authorization cache parses a stored identity policy, permissions boundary or session policy with the key. A stored policy over it does not parse, and authorization answers AccessDenied. from_json keeps the default of 6,144 bytes, now the named constant DEFAULT_MAX_POLICY_DOCUMENT_BYTES. The security model manual names the key.
LeeroyHannigan
requested review from
amrith,
c33howard,
eliseong,
hitesh96db,
jcshepherd,
navareamol,
pdf-amzn and
robinnsc
as code owners
November 4, 2026 23:34
from_json_for_write now takes the limit as a second argument, and the fuzz target called it with one. The target now drives from_json_with_size_limit and from_json_for_write with DEFAULT_MAX_POLICY_DOCUMENT_BYTES, the two calls the server makes, and its header names them.
This branch has not been deployed
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.
What
Six
[limits]keys that the server accepted and did not act on now take effect.max_tables_per_account:CreateTablecounts the account's tables. When the account already holds the quota, it refuses the new table withLimitExceededException:There is a soft account quota of {n} tables.per_table_max_rcu,per_table_max_wcu,per_account_max_rcuandper_account_max_wcu:CreateTableandUpdateTablerefuse a provisioned throughput over a maximum withLimitExceededException. The checks are incrates/core/src/validation/provisioned_limits.rs.crates/engine/src/table_limits.rsreads what the account holds.CreateTablechecks the account maximum first. Then it checks the per-table maximum, which bounds the table and its global secondary indexes together.UpdateTablefirst checks the table's ownProvisionedThroughputagainst the per-table maximum. Then it checks the account maximum against what the table and its indexes hold after the change.max_policy_document_bytes: the policy size limit was the literal 6,144 inPolicyDocument::from_json. The management API's policy and permissions boundary handlers and the console's policy page now pass the key tofrom_json_for_write. The authorization cache parses a stored identity policy, permissions boundary or session policy with the same key. The security model manual names the key.On
CreateTablethe order is the measured one: the definition checks, then a taken name (ResourceInUseException), then the capacity limits. The table quota comes last.Other effects:
CreateTablelists the account's table names. ACreateTableorUpdateTablewith a provisioned throughput also describes every table in the account to sum what the account holds.max_policy_document_bytesbelow the size of a stored policy, the policy no longer parses. Requests of its principal then getAccessDeniedException.max_tables_per_account, the per-table maxima andmax_policy_document_bytesas not enforced. Whichever of the two merges second must update those descriptions.Why
The issue lists the keys and the code that ignored them. The comment on the issue has the answers of Amazon DynamoDB, measured on 2026-10-31. This change uses those sentences where a measurement exists. These answers are not in the measurements:
LimitExceededExceptionAPI reference.CreateTableover the per-table maximum while the account stays under its maximum. It uses theUpdateTablesentence.UpdateTablethat raises the table's own throughput over the account maximum but not over the per-table maximum. It uses the account sentence that the measured GSI case returned.UpdateTableon a table that is notACTIVEgetsLimitExceededException. Under the maxima, it getsResourceInUseException.Closes #538
Testing done
cargo +1.97.0 fmt --all -- --checkandcargo +1.97.0 clippy --locked --all-targets -- -D warnings: clean. Pedantic lints flag no line that this change adds.cargo +1.88.0 test --locked -p extenddb-core -p extenddb-auth -p extenddb-engine -p extenddb-server: all pass, with 775 unit tests in core, 372 in auth, 230 in engine and 295 in server.provisioned_limits_tests.rsuse the maxima and the reserved units of the measured account. They check the measured sentences, and each maximum at its value and one unit above. They also cover a table above a lowered maximum, the table quota and the sum of a request's capacity.the_size_limit_is_the_one_the_caller_passeschecks both parse paths at the limit and one byte over it.a_stored_policy_over_the_configured_size_does_not_loadchecks that the authorization cache refuses a stored policy one byte over the configured limit. It fails on a mutant that ignores the limit on the read path.max_tables_per_account = 3, both per-table maxima at 100 and both account maxima at 150. Each answer below is the expected one:DescribeLimitsreports 150, 150, 100 and 100.CreateTablewith an undefined key and 101 RCU: theValidationExceptionfor the undefined key.CreateTableat 101 RCU, and at 101 WCU: the per-table sentence for each unit. At 100 RCU: created.CreateTableat 51 RCU with 100 reserved: the account sentence,reserved by the account: 100. Limit: 150. Requested: 51.At 50 RCU: created.UpdateTableof that table to 101 RCU: the per-table sentence. To 60 RCU: the account sentence withprovisioned for the table and indexes: 50andRequested: 60. Down to 40 RCU: accepted.UpdateTablewith a GSI create of 11 RCU on that table: the account sentence withreserved by the account: 140,provisioned for the table and indexes: 40andRequested: 51.CreateTableof a fourth:There is a soft account quota of 3 tables.Of a taken name:ResourceInUseException.max_policy_document_bytes = 400:Invalid policy document: policy parse error: policy document exceeds maximum size (400 bytes). It stores a 94-byte one.ListTablesby that user getsAccessDeniedException. After a restart at 400 bytes, it succeeds.Checklist
cargo test --workspace)cargo fmt --check)cargo clippy -- -W clippy::pedantic)Storagetrait, auth model, on-diskformat, 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
Breaking changes
The server now refuses requests that it accepted before. With the defaults, it refuses a table over 40,000 RCU or WCU and an account over 80,000 RCU or WCU. It also refuses a 2,501st table. A deployment that relies on more must raise the keys.
PolicyDocument::from_json_for_writenow takes the size limit as a second argument.By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache License 2.0 and I agree to the Developer Certificate of
Origin (DCO). See CONTRIBUTING.md for details.