Skip to content

Add on_trap callback hook for observability and custom handling - #6

Merged
cedric merged 4 commits into
mainfrom
copilot/add-on-trap-callback-hook
Jul 8, 2026
Merged

cedric merged 4 commits into
mainfrom
copilot/add-on-trap-callback-hook

Conversation

Copilot AI commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor

No first-class way existed to hook into a trap event — consuming applications had to detect the implicit head 200 indirectly, which is fragile and ambiguous. This adds a configurable on_trap callback invoked on every trap (honeypot or nonce), at both global and per-declaration scope.

Changes

lib/spamtrap.rb

  • Added attr_accessor :on_trap to module config

lib/spamtrap/controller.rb

  • Extracts on_trap: per-declaration option using the same :global sentinel pattern as nonce: and mutate:
  • Calls spamtrap_invoke_on_trap(reason, on_trap_opt) before head 200 in both honeypot and nonce trap paths
  • Adds private spamtrap_invoke_on_trap — resolves global vs per-declaration callback, invokes it with reason: (:honeypot or :nonce) and request: kwargs, and wraps in rescue StandardError so a broken callback never prevents the silent discard

test/

  • Added routes and test controllers for the new code paths
  • Tests cover: global callback on honeypot, global callback on nonce, no-op when nil, per-declaration precedence over global, and error resilience

API

# Global (initializer)
Spamtrap.on_trap = ->(reason:, request:) {
  Rails.logger.warn "[Spamtrap] #{reason} from #{request.remote_ip}"
  StatsD.increment('spamtrap.triggered', tags: ["reason:#{reason}"])
}

# Per-declaration override (takes precedence over global)
spamtrap :comment, only: :create, on_trap: ->(reason:, request:) {
  Honeybadger.notify("Spamtrap fired", context: { reason: reason, ip: request.remote_ip })
}

Backwards compatible — no behaviour change when on_trap is not set.

Copilot AI changed the title [WIP] Add on_trap callback hook for observability and custom handling Add on_trap callback hook for observability and custom handling Jul 8, 2026
Copilot finished work on behalf of cedric July 8, 2026 17:26
Copilot AI requested a review from cedric July 8, 2026 17:26
@cedric

cedric commented Jul 8, 2026

Copy link
Copy Markdown
Owner

@copilot please update README. bump version to 0.3.2 and update the CHANGELOG.

Copilot AI commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please update README. bump version to 0.3.2 and update the CHANGELOG.

Done in commit Bump version to 0.3.2, add CHANGELOG, update README with on_trap docs:

  • lib/spamtrap/version.rb → 0.3.2
  • CHANGELOG.md created with entries for 0.3.2 (new on_trap callback) and 0.3.1
  • README.rdoc updated: added Spamtrap.on_trap to the global configuration block and a new Trap callback subsection under Configuration documenting the global and per-declaration APIs, callback arguments, and error resilience behaviour

@cedric
cedric marked this pull request as ready for review July 8, 2026 17:32
Copilot AI review requested due to automatic review settings July 8, 2026 17:32
Copilot finished work on behalf of cedric July 8, 2026 17:32
@cedric
cedric merged commit 6f6359a into main Jul 8, 2026
1 check passed
@cedric
cedric deleted the copilot/add-on-trap-callback-hook branch July 8, 2026 17:32

Copilot AI 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.

Pull request overview

Adds a first-class on_trap callback hook to the Spamtrap controller integration so consuming apps can reliably observe and handle trap events (honeypot and nonce) without inferring behavior from the implicit head 200.

Changes:

  • Introduces global Spamtrap.on_trap configuration and a per-declaration on_trap: override option.
  • Invokes the callback on both honeypot and nonce trap paths with reason: and request: keyword args, rescuing callback errors to preserve the silent discard behavior.
  • Adds tests, routes, and documentation (README + CHANGELOG) and bumps the gem version.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/test_helper.rb Adds routes for the new on_trap test controllers.
test/controller_test.rb Adds controller fixtures and test coverage for global/per-declaration callbacks and error resilience.
README.rdoc Documents the on_trap API and usage patterns.
lib/spamtrap/version.rb Bumps version to 0.3.2.
lib/spamtrap/controller.rb Extracts on_trap: option and invokes the callback for honeypot/nonce traps via a helper method.
lib/spamtrap.rb Adds global on_trap configuration accessor.
CHANGELOG.md Adds a new 0.3.2 changelog entry describing the feature.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return unless callback.respond_to?(:call)
callback.call(reason: reason, request: request)
rescue StandardError => e
Rails.logger.error "Spamtrap on_trap callback raised: #{e.class}: #{e.message}"
cedric pushed a commit that referenced this pull request Jul 8, 2026
* Initial plan

* Add on_trap callback hook for observability and custom handling

* Use thread-local variable instead of global in on_trap test

* Bump version to 0.3.2, add CHANGELOG, update README with on_trap docs

---------
cedric added a commit that referenced this pull request Jul 8, 2026
* Initial plan

* Add on_trap callback hook for observability and custom handling

* Use thread-local variable instead of global in on_trap test

* Bump version to 0.3.2, add CHANGELOG, update README with on_trap docs

---------
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.

Add on_trap callback hook for observability and custom handling

3 participants