Skip to content

Add: per-site enforcement denylist authored from the popup (ADR-0018)#235

Merged
twschiller merged 2 commits into
mainfrom
per-site-denylist
Jun 9, 2026
Merged

Add: per-site enforcement denylist authored from the popup (ADR-0018)#235
twschiller merged 2 commits into
mainfrom
per-site-denylist

Conversation

@twschiller

Copy link
Copy Markdown
Contributor

Summary

  • Adds a one-click Disable on this site / Re-enable on this site toggle to the toolbar popup and an audit-and-edit Sites with enforcement disabled section to the Options page.
  • Storage is string[] of URL Pattern strings under agent-browser-shield.site-denylist; the popup writes `${scheme}//${host}/*` for the active tab; Re-enable removes every entry matching the active URL.
  • Effective enforcement = globalEnforcement && !matchesAnyDenylistPattern(topFrameUrl). Subframes inherit by asking the background once for the tab's top-frame URL (new get-tab-url message); pure-top-frame computation uses globalThis.location.href so SPA route changes re-evaluate on the next storage event.
  • New siteDenylist reserved key on the build-time overrides file (spec 0011 / ADR-0018), validated via zod + new URLPattern(entry). Round-trips through the Options-page Export configuration / Apply configuration surface.

ADR: decisions/0018-per-site-enforcement-denylist.md

Spec updates: specs/0010-extension-ui-and-controls.md FR-7a–FR-7d, FR-10a, FR-10b, FR-15; specs/0011-build-time-customization.md FR-3 (siteDenylist), FR-4 (loud failure on bad pattern).

What's NOT in scope

  • Per-rule per-host control. v1 scopes the whole rule set off on a host; the per-rule axis remains future work in spec 0010 §"Future work".
  • Per-host enable overrides (the user explicitly chose denylist-only).

Test plan

  • extension/src/lib/__tests__/site-denylist.test.ts — unit coverage for hostPatternFor, matchesDenylist, findMatchingPatterns, addHostPattern, removeMatchingPatterns, isContentSchemeUrl, isValidPattern.
  • extension/src/lib/__tests__/site-denylist.property.test.tsfast-check round-trip invariants: pattern from addHostPattern always matches the URL; removeMatchingPatterns leaves no matching pattern.
  • extension/src/options/__tests__/parse-config.test.tssiteDenylist round-trip + bad-shape rejections through the Options-page Apply configuration surface.
  • extension/scripts/__tests__/load-default-overrides.test.ts — build-time siteDenylist validation (valid list, empty list, non-array, non-string entry, invalid URL Pattern).
  • extension/src/lib/__tests__/rule-engine.test.ts — mock swapped from enforcement.ts to effective-enforcement.ts; all 12 existing reconciliation cases pass.
  • Full suite: 2001 / 2001 pass.
  • bun run check (biome + eslint): clean.
  • pre-commit run --all-files: clean (after bun install in demo-site/).
  • bun run build --defaults <file> with a valid siteDenylist injects the pattern into dist/content.js; with an invalid pattern, build fails loudly with a path-qualified zod message.
  • Manual verification needed (no headed browser in this environment): load the unpacked build, click "Disable on this site" on a few URLs, confirm the rule engine pauses on that tab and re-enables on click. Spot-check that subframes inherit by visiting a page with a cross-origin iframe.

🤖 Generated with Claude Code

Adds a one-click "Disable on this site" / "Re-enable on this site" toggle
to the toolbar popup and an audit-and-edit "Sites with enforcement
disabled" section to the Options page. Storage is an array of URL Pattern
strings under `agent-browser-shield.site-denylist`; the popup writes
`${scheme}//${host}/*` for the active tab and "Re-enable" removes every
entry matching the active URL. Effective enforcement is composed from
`global enforcement && !matchesAnyDenylistPattern(topFrameUrl)` —
subframes inherit by asking the background for the tab's top-frame URL.

The same `siteDenylist` key is a new reserved key on the build-time
overrides file (spec 0011) and round-trips through the Options-page
*Export configuration* / *Apply configuration* surface, so a tuned
extension's exported JSON can be fed back into the next build. Bad
patterns fail the build loudly via the existing zod loader.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
agent-browser-shield-demo-site Ready Ready Preview, Comment Jun 9, 2026 5:47pm

Request Review

knip flagged the speculative `getEffectiveEnforcement` accessor as
unused. The rule engine consumes `initEffectiveEnforcement` +
`subscribeEffectiveEnforcement` only; the snapshot accessor was
defensive surface with no caller.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@twschiller twschiller merged commit 885e49e into main Jun 9, 2026
7 checks passed
@twschiller twschiller deleted the per-site-denylist branch June 9, 2026 17:57
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