Skip to content

test: add adversarial unit tests for hooks system#8

Merged
mattapperson merged 1 commit intofeat/hooks-managerfrom
adversarial-hooks-tests
Apr 3, 2026
Merged

test: add adversarial unit tests for hooks system#8
mattapperson merged 1 commit intofeat/hooks-managerfrom
adversarial-hooks-tests

Conversation

@mattapperson
Copy link
Copy Markdown
Collaborator

Summary

Findings surfaced

These tests document (not fix) real edge cases in the current implementation:

  1. matchesTool — no boolean coercion: Function matchers returning truthy non-booleans (e.g. 1, null) pass the raw value through instead of true/false. Works with truthiness checks but fails strict === true comparisons.

  2. matchesTool — global RegExp stateful .test(): Using a /g RegExp as a matcher causes alternating match/no-match results due to lastIndex state. The test documents this footgun.

  3. executeHandlerChain — filter throws bypass error handling: Throwing filters propagate unhandled (they execute outside the try block), unlike throwing handlers which are caught in non-strict mode.

  4. Re-entrant emit: A handler that registers a new handler mid-emit causes the new handler to execute in the same chain (since the for-loop reads entries.length dynamically).

  5. block: "" (empty string) triggers short-circuit: isBlockTriggered checks typeof value === 'string', so empty strings count as blocks — potentially surprising.

Test files

File Tests Covers
hooks-emit-adversarial.test.ts 21 Empty inputs, primitive results, block edge cases, mutation piping, filter throws, async+block overlap, matcher interactions, stress test
hooks-manager-adversarial.test.ts 17 Double unsubscribe, re-entrant emit, custom hook validation, drain safety, removeAll during emit, sessionId changes
hooks-matchers-adversarial.test.ts 12 Empty strings, global RegExp, non-boolean returns, throwing matchers, regex-special chars in string matchers
hooks-resolve-adversarial.test.ts 13 Falsy inputs, empty config, malformed values, prototype pollution, arbitrary hook names
hooks-types-adversarial.test.ts 18 Non-boolean async values, non-object inputs, Proxy objects, arrays with async property, Object.create(null)

Test plan

  • All 81 new adversarial tests pass
  • All existing 186 unit tests still pass
  • Build (pnpm build) passes

81 edge-case tests covering handler chain execution, manager lifecycle,
tool matchers, resolver normalization, and async output detection.
Surfaces real issues: filter throws bypass error handling, global RegExp
stateful .test(), and function matcher lacking boolean coercion.
@mattapperson mattapperson merged commit 35133a0 into feat/hooks-manager Apr 3, 2026
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