Skip to content

Replace RegexPiiGuard with RedactWire; clear PII messaging; 0.4.0#39

Merged
adamy merged 6 commits into
mainfrom
feature/redactwire-pii-guard
Jun 26, 2026
Merged

Replace RegexPiiGuard with RedactWire; clear PII messaging; 0.4.0#39
adamy merged 6 commits into
mainfrom
feature/redactwire-pii-guard

Conversation

@adamy

@adamy adamy commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Summary

Replaces the built-in 4-pattern RegexPiiGuard with RedactWire (sister project), and makes a blocked message tell the user why it was refused instead of a generic error. Bumps BotWire to 0.4.0.

PII detection (RedactWire)

  • BotWire.Core now backs PII detection with RedactWire 0.4.0: invariant rules (email, credit card, IP, IBAN) + secret/credential detection, against the default culture.
  • PiiGuardOptions keeps Enabled + RejectionMessage, keeps AdditionalPatterns (no breaking change) — bridged to RedactWire custom rules via a TimeoutRegexRule that compiles each user regex with a 100ms match timeout to bound ReDoS — and adds ConfigureDetector (Action<PiiDetectorBuilder>) for full RedactWire customization (cultures, custom rules, overlap strategy).
  • RedactWire 0.4.0's base package no longer pulls System.Text.Json (structured scanning moved to an add-on), so no net-new transitive dep on BotWire.Core.

Clear PII messaging

A blocked message previously showed the widget's generic "Something went wrong" and dropped the configured PII rejection. Now legible end to end:

  • Server returns a distinct PiiBlocked status carrying the configurable RejectionMessage.
  • Prompt-injection blocks no longer reuse the PII copy — own neutral PromptInjectionOptions.RejectionMessage.
  • Embedded widget + RedisShop sample surface the server's message for guard rejections (PiiBlocked/Blocked/RateLimited).
  • widget.js endpoint now uses no-cache + content-hash ETag instead of a one-hour max-age — a rebuilt widget reaches browsers immediately (was masking the fix).

Release / versioning

  • Release workflow is manual-only (workflow_dispatch with a tag input); no longer fires on tag push.
  • Bumped to 0.4.0: VersionPrefix (all .NET packages) and botwire-js.

Note (public API)

PiiGuardOptions.ConfigureDetector exposes RedactWire's PiiDetectorBuilder, so RedactWire is a deliberate public dependency of BotWire.Core.

Tests

All green: Core 255, AspNetCore 27, Integration 9, Redis 19, Email 22, npm 30. Added coverage for the RedactWire guard, ReDoS timeout, PiiBlocked rendering, and widget.js ETag revalidation.

🤖 Generated with Claude Code

adamy and others added 6 commits June 24, 2026 20:55
Swap the built-in 4-pattern RegexPiiGuard for RedactWire (sister project):
invariant rules (email, credit card, IP, IBAN) + secret/credential detection,
running against the default culture (CultureInfo.CurrentCulture).

- Add RedactWire 0.3.0 PackageReference to BotWire.Core.
- PiiGuardOptions gains ConfigureDetector (Action<PiiDetectorBuilder>) for full
  RedactWire customization (cultures, custom IPiiRule, overlap strategy).
- AdditionalPatterns retained (no breaking change), bridged to RedactWire custom
  rules via TimeoutRegexRule, which compiles each user regex with a 100ms match
  timeout to bound ReDoS; on timeout it logs and degrades to no-match.
- Check() reports the earliest in-text match and short-circuits blank input.

Note: PiiGuardOptions now exposes RedactWire's PiiDetectorBuilder, so RedactWire
(and System.Text.Json transitively) is a public dependency of BotWire.Core.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0.4.0 moves JSON/XML/object scanning into the RedactWire.Structured add-on, so the
base package no longer pulls System.Text.Json. BotWire.Core uses only string
detection, so no code change is needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A blocked message used to surface the widget's generic "Something went wrong"
instead of the configured PII rejection, so users had no idea why their message
was refused. Make the PII rejection legible end to end:

- Server: PII blocks return a distinct "PiiBlocked" status (carrying the
  configurable PiiGuardOptions.RejectionMessage), so clients can tell a PII
  refusal apart from a generic failure.
- Prompt-injection blocks no longer reuse the PII copy; they get their own
  neutral PromptInjectionOptions.RejectionMessage.
- Widget + RedisShop sample: surface the server's message for guard rejections
  (PiiBlocked / Blocked / RateLimited) instead of the generic error. The sample
  duck-types on status so it holds across botwire-js versions.
- Widget.js endpoint: serve with no-cache + a content-hash ETag instead of a
  one-hour max-age, so a rebuilt widget reaches browsers immediately (304 when
  unchanged). This long cache was why the fix appeared not to take effect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release no longer fires on tag push; it runs solely via workflow_dispatch with a
required `tag` input. Every job resolves REF_NAME from that input, checks out the
tag, and the GitHub Release step is re-run-safe (upload --clobber if it exists).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
VersionPrefix (all .NET packages) and botwire-js package.json to 0.4.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@adamy adamy merged commit fe2326f into main Jun 26, 2026
5 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.

1 participant