Skip to content

chore(hooks): log claude_prompt_denied on UserPromptSubmit block#2888

Open
mfbx9da4 wants to merge 3 commits into
mainfrom
da/hooks-observability-prompt-deny-log
Open

chore(hooks): log claude_prompt_denied on UserPromptSubmit block#2888
mfbx9da4 wants to merge 3 commits into
mainfrom
da/hooks-observability-prompt-deny-log

Conversation

@mfbx9da4
Copy link
Copy Markdown
Contributor

@mfbx9da4 mfbx9da4 commented May 17, 2026

Why

When investigating a production policy block on a Claude Code UserPromptSubmit hook, the only signal in Datadog was @http.response.status_code:403. There was no structured log event recording that the synchronous risk scan ran and matched a policy on a given session, and no easy join key from a chat row in Postgres back to server log lines. Several adjacent gaps also made it hard to debug: there was no log when the scan ran and found nothing, no log when the scan was silently skipped because the project could not be resolved, the top-level "claude hook received" log fired before plugin auth so it never carried gram.auth.user_email, and the asynchronous persistHook goroutine continued the synchronous request's OTel trace so APM showed the /rpc/hooks.claude trace polluted with detached DB writes and Temporal kickoffs.

What changed (Before/After)

Before:

  • handleUserPromptSubmit wrote a ClickHouse block row and returned a 403, with no info-level log identifying the policy, session, or reason.
  • scanClaudeForEnforcement emitted nothing on the success path (match or no-match).
  • resolveClaudeScanProjectID returned (uuid.Nil, false) silently when there was no cached session metadata and no auth context, so failed scans were invisible.
  • The "claude hook received" log fired before withAuthContext enriched the logger, so it never carried gram.auth.user_email even on plugin-authenticated requests.
  • recordHook kicked off persistHook in a goroutine using context.WithoutCancel(ctx), which preserved the OTel span context so the async DB writes and Temporal kickoffs hung off the synchronous request trace.

After:

  • handleUserPromptSubmit logs claude_prompt_denied with hook source/event, session id, block reason, and matching policy id/name just before returning the 403. HTTP response shape and status are unchanged.
  • scanClaudeForEnforcement always logs claude_hook_scan_decision after a successful scan with gram.risk.matched, plus policy id/name when matched.
  • Both (uuid.Nil, false) paths in resolveClaudeScanProjectID now log a warn claude_scan_no_project with gram.session.has_cached_metadata and gram.session.has_auth_ctx so silent skips are visible.
  • The top-level "claude hook received" info log moved to after the plugin-auth block so it carries the enriched logger (including gram.auth.user_email) when plugin auth succeeded.
  • The async persistHook goroutine starts from a context with a cleared OTel span context, so APM no longer attributes its work to the synchronous handler trace.

Adds an info log on the deny path of handleUserPromptSubmit mirroring
the existing claude_hook_denied log shape used by PreToolUse, so a 403
on a claude prompt can be joined to a session in Datadog without
inferring from response status alone.
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 17, 2026

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

Project Deployment Actions Updated (UTC)
gram-docs-redirect Ready Ready Preview, Comment May 18, 2026 2:59pm

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 17, 2026

⚠️ No Changeset found

Latest commit: a57617f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions github-actions Bot added the preview Spawn a preview environment label May 17, 2026
@speakeasybot
Copy link
Copy Markdown
Collaborator

speakeasybot commented May 17, 2026

🚀 Preview Environment (PR #2888)

Preview URL: https://pr-2888.dev.getgram.ai

Component Status Details Updated (UTC)
✅ Database Ready Existing database reused 2026-05-21 08:12:14.
✅ Images Available Container images ready 2026-05-21 08:11:49.

Gram Preview Bot

…y-prompt-deny-log

# Conflicts:
#	server/internal/attr/conventions.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview Spawn a preview environment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants