Skip to content

feat: configurable idempotency key validation (max length + pattern) - #6

Open
ashudhanda wants to merge 1 commit into
ravocode:mainfrom
ashudhanda:feat/key-validation
Open

feat: configurable idempotency key validation (max length + pattern)#6
ashudhanda wants to merge 1 commit into
ravocode:mainfrom
ashudhanda:feat/key-validation

Conversation

@ashudhanda

Copy link
Copy Markdown

Implements the key-validation half of #2 in the Spring Boot starter.

What changed

Two new configuration properties under avoonce.idempotency.* (IdempotencyProperties):

avoonce:
  idempotency:
    key-pattern: "^[a-fA-F0-9\\-]{36}$"  # optional; disabled by default
    max-key-length: 128                    # default 255
  • key-pattern — optional regex the key must fully match (e.g. UUID format, as suggested in the issue). null/blank (the default) disables it, so existing setups are unaffected. The pattern is compiled once in the IdempotencyFilter constructor, not per request.
  • max-key-length — keys longer than this are rejected with HTTP 400 before touching the store, preventing abuse via overly long keys. Default 255.
  • Blank/whitespace-only keys are now also rejected with 400 — previously an all-spaces header would flow into the state machine as a "real" key.

Validation runs in IdempotencyFilter after the existing null/enforce check and before the state machine is engaged, so an invalid key never acquires a lock or writes a record. The 400 body names the configured header and the specific violation.

Tests

Added to IdempotencyFilterTest:

  • blank key → 400, controller never executes
  • key over max-key-length → 400; key within the limit → 201 (normal flow)
  • key failing key-pattern → 400; UUID-shaped key → 201 (normal flow)

Not in this PR

The second part of the issue — sourcing the key from a query param or JSON-body field instead of a header — is a larger, separable change (it touches CachedBodyHttpServletRequest buffering order and the JAX-RS adapter for parity). Happy to follow up with it in a separate PR if the header-first shape here looks right to you; the same validation would then apply to whichever source is configured.

Refs #2

@raghavgopal

Copy link
Copy Markdown
Member

Implements the key-validation half of #2 in the Spring Boot starter.

What changed

Two new configuration properties under avoonce.idempotency.* (IdempotencyProperties):

avoonce:
  idempotency:
    key-pattern: "^[a-fA-F0-9\\-]{36}$"  # optional; disabled by default
    max-key-length: 128                    # default 255
  • key-pattern — optional regex the key must fully match (e.g. UUID format, as suggested in the issue). null/blank (the default) disables it, so existing setups are unaffected. The pattern is compiled once in the IdempotencyFilter constructor, not per request.
  • max-key-length — keys longer than this are rejected with HTTP 400 before touching the store, preventing abuse via overly long keys. Default 255.
  • Blank/whitespace-only keys are now also rejected with 400 — previously an all-spaces header would flow into the state machine as a "real" key.

Validation runs in IdempotencyFilter after the existing null/enforce check and before the state machine is engaged, so an invalid key never acquires a lock or writes a record. The 400 body names the configured header and the specific violation.

Tests

Added to IdempotencyFilterTest:

  • blank key → 400, controller never executes
  • key over max-key-length → 400; key within the limit → 201 (normal flow)
  • key failing key-pattern → 400; UUID-shaped key → 201 (normal flow)

Not in this PR

The second part of the issue — sourcing the key from a query param or JSON-body field instead of a header — is a larger, separable change (it touches CachedBodyHttpServletRequest buffering order and the JAX-RS adapter for parity). Happy to follow up with it in a separate PR if the header-first shape here looks right to you; the same validation would then apply to whichever source is configured.

Refs #2

Thanks for the PR, I will get back after reviewing.

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.

2 participants