Skip to content

fix(pii): bound custom-pattern matching time per request - #9584

Merged
waleedlatif1 merged 1 commit into
stagingfrom
fix/pii-request-bounds
Nov 2, 2026
Merged

waleedlatif1 merged 1 commit into
stagingfrom
fix/pii-request-bounds

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Presidio's REGEX_TIMEOUT_SECONDS (2s) bounds one custom pattern on one text, so a single batch request could cost texts x patterns x 2s (2,000 texts x 20 patterns = ~22h on one handler thread). A pathological pattern like (a|aa)+$ hits the per-match cap on every text, and the sync handler thread keeps running after the client gives up, so each retry ties up another thread
  • Custom-pattern recognizers now charge their matching time to a shared per-request 60s budget and reject the request with a 400 once it's spent. The cost of one request is now at most budget + one match
  • The budget counts only custom-pattern time, not spaCy NER or built-in recognizers, so slow legitimate batches can't trip it. Benign patterns use well under 1s per 256 KB chunk, and a single text with 20 timed-out patterns stays under the budget, so single-text behavior is unchanged
  • A 400 maps to PiiServiceRejectedError → route 422 → no retry in mask-client, and it isn't treated as an outage, so the chunk fails closed without retry amplification
  • Updated the validate-regex.ts TSDoc that named Presidio's timeout as the only bound

Type of Change

  • Bug fix

Testing

Drove apps/pii/server.py with the pinned Presidio 2.2.362 / spaCy 3.8.14 / FastAPI stack through FastAPI TestClient (en_core_web_sm in place of the 5 large models), pre-fix vs post-fix:

  • Report shape (2,000 texts x 20 (a|aa)+$ patterns, timeout 2s): post-fix /redact_batch (regex-only and full NLP paths) and /analyze_batch all return 400 in 60.4-63.0s
  • Across the budget line (120 texts x 1 pattern, timeout 1s): pre-fix 200 after 121-165s, post-fix 400 after 60.2-60.3s
  • Single text with a pathological pattern: /redact and /analyze still return 200 after one ~2s timeout, same as before
  • Benign regression (2,000 realistic texts x 20 benign patterns + built-ins, all 6 endpoints incl. invalid-regex 400): pre vs post outputs are identical under a pinned PYTHONHASHSEED on 6 seeds. The only run-to-run variation is the winner of exact equal-score span ties, which varies by seed on the unmodified server too (Presidio dedups via set())
  • biome check on the TS file; JS gates otherwise left to CI (the diff is Python + one TSDoc sentence)

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing (new tests pass the test-audit authoring gate)
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Presidio's REGEX_TIMEOUT_SECONDS bounds one custom pattern on one text, so a
batch request could cost texts x patterns x that timeout (2,000 texts x 20
patterns x 2s) on a single handler thread. Charge every custom-pattern match to
a per-request 60s budget and reject the request with a 400 once it is spent.
@vercel

vercel Bot commented Nov 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Nov 2, 2026 8:48pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable issues were found.

Summary

Adds a shared 60-second budget for custom-pattern matching within each PII request.

  • Custom patterns share a 60-second matching budget for each request.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[PII request] --> B[Create shared matching budget]
  B --> C[Run custom recognizer]
  C --> D[Subtract elapsed matching time]
  D --> E{Budget exceeded?}
  E -->|No| F[Continue analysis]
  E -->|Yes| G[Return HTTP 400]
  G --> H[App returns HTTP 422]
  H --> I[Client fails chunk without retry]
Loading

Reviews (1) · Last reviewed commit: "fix(pii): bound custom-pattern matching ..." · Reviewed by Greptile

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Turn on auto-fix | Re-trigger cubic

@waleedlatif1
waleedlatif1 merged commit 70be4b7 into staging Nov 2, 2026
72 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/pii-request-bounds branch November 2, 2026 23:26

This branch was previously deployed

1 inactive deployment
Preview — 58ba01c3 Deployed Nov 2, 2026 by vercel[bot]
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.

1 participant