Skip to content

feat(api): structured WARN logging on authorization denials - #189

Merged
EricAndrechek merged 34 commits into
mainfrom
rbac-security-enforcement
Jun 2, 2026
Merged

feat(api): structured WARN logging on authorization denials#189
EricAndrechek merged 34 commits into
mainfrom
rbac-security-enforcement

Conversation

@taitelee

Copy link
Copy Markdown
Member

Summary

Every authorization denial now flows through one shared helper that emits a structured slog WARN, so a misconfigured role or policy is visible in logs without reproducing the request.

  • writeAuthzDenied (internal/api/errors.go) is the single denial path for all gates. It classifies the failure — a present-but-invalid/expired token fails loud as 401 with the sanitized token reason, everything else is a
    403 — and derives a greppable reason (role not in allowed roles, no role and no default_role configured, or the token error).
  • logAuthzDenied emits the "authorization denied" WARN with reason, role_observed (pre-default-resolution) vs role_resolved, roles_allowed, the chi route pattern (low-cardinality, no concrete path params), method, and status. slog escapes control chars, so the request-derived fields carry no log-injection risk.
  • forbiddenForRole returns the 403 body — verbose for the anonymous / no-default_role case, terse otherwise (doesn't enumerate roles).
  • All existing gates route denials through it: the /v1/admin/* gate (router.go), the pipe gate (pipes.go), and the policy-evaluator paths (ingest.go, structured_query.go). roles_allowed is populated only where a flat allowlist exists (a pipe's allowed_roles); the admin gate and evaluator paths pass nil.

Test plan

  • make ci (and go test ./internal/api/) passes locally
  • Admin-gate denial logs a WARN: reason role not in allowed roles, the role, route /v1/admin/query, status 403
  • Tokenless request under a default_role logs role_observed="" and role_resolved=<default>
  • Present-but-invalid token fails loud: status 401, reason carries the token error
  • Pipe denial logs roles_allowed equal to the pipe's allowed_roles
  • Denial routed through the real mux logs the chi route pattern, not the raw path

Related Issues

Part of #145: implements the "structured WARN on every denial" requirement from its Proposed Solution. Does not fully close #145; the broader role-gating enforcement is tracked there.

taitelee and others added 29 commits May 20, 2026 16:01
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…default role, other JWT enforcements, doc changes.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
wavehouse-docs 0cadcc6 May 27 2026, 06:07 PM

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Free

Run ID: c0db5f9c-b8d0-4e28-b52b-fb29e45bb619

📥 Commits

Reviewing files that changed from the base of the PR and between c3da09b and aeb50b6.

📒 Files selected for processing (2)
  • internal/api/router.go
  • tests/e2e/sdk/dlq.test.ts
💤 Files with no reviewable changes (1)
  • internal/api/router.go

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Authorization responses now use correct HTTP status: 401 for invalid authentication, 403 for insufficient permissions.
  • Chores

    • Authorization denials now emit structured WARN logs including reason, observed vs resolved role, allowed roles, route pattern, method, status, and gate tag.
    • API handlers and router now accept an injected request-scoped logger so logs inherit request/trace context.
  • Documentation

    • Changelog and docs updated to reflect authorization-logging changes and removal of the admin log-level endpoint.
  • Tests

    • Added/updated tests verifying structured denial logging, route-pattern reporting, handler logger wiring, and adjusted an e2e DLQ timing assertion.

Walkthrough

Authorization denials now use an injected request-context *slog.Logger and emit structured WARN logs with reason, observed/resolved roles, allowed roles, route (chi pattern preferred), method, and status; handlers, middleware, wiring, and tests updated.

Changes

Authorization Denial Logging & Structured Instrumentation

Layer / File(s) Summary
Authorization denial handler and structured logging
internal/api/errors.go, CHANGELOG.md
writeAuthzDenied now accepts *slog.Logger, resolvedRole, and allowedRoles; it derives 401 vs 403 from auth.AuthErrorFromContext and role presence, uses forbiddenForRole for 403 bodies, and calls logAuthzDenied. logAuthzDenied emits structured WARN fields including reason, role_observed, role_resolved, roles_allowed, route (chi route pattern preferred), method, and status.
Structured denial test coverage
internal/api/errors_test.go
Adds warnBufLogger helper and tests that capture WARN-level JSON logs asserting structured fields for admin-gate denials (non-admin, empty-role, invalid-token), pipe deny (roles_allowed/pipe), policy deny, and router integration (chi route pattern).
Ingest handler: injected logger & denial call-sites
internal/api/ingest.go, internal/api/ingest_test.go
IngestHandler now carries logger *slog.Logger; internal logs use h.logger.*Context. Insert-permission denied path calls writeAuthzDenied(h.logger, role, nil) and the ingest tests now pass a no-op logger.
Pipes handler: logger and allowed-roles
internal/api/pipes.go, internal/api/pipes_test.go
PipesHandler stores an injected *slog.Logger; NewPipesHandler signature updated. On Execute denial, call passes q.AllowedRoles, the handler logger, and attrs (gate=pipe, pipe=<name>). Tests updated to pass a test logger.
Router admin gate: logger wiring and middleware change
internal/api/router.go, internal/api/router_test.go
Dependencies adds Logger *slog.Logger; NewRouter passes it to RequireAdmin(store, logger). RequireAdmin normalizes via loggerOrDefault and routes denials through writeAuthzDenied(logger, role, nil, slog.String(\"gate\",\"admin\")). Admin /log-level endpoint removed from router/docs. Router tests updated to provide a test logger.
StructuredQuery handler: logger injection and denial call-site
internal/api/structured_query.go, internal/api/structured_query_test.go
StructuredQueryHandler now holds an injected *slog.Logger; permission denials call writeAuthzDenied with the handler logger and structured fields (gate, table, action). Tests updated to pass a test logger.
Wiring and integration tests
cmd/wavehouse/main.go, tests/integration/setup_test.go, docs/*, tests/e2e/sdk/dlq.test.ts
CLI and integration wiring updated to pass configured/test logger into NewIngestHandler, NewPipesHandler, and NewStructuredQueryHandler, and api.Dependencies now carries Logger. Documentation and changelog adjusted to reflect the admin /log-level removal and the new authz logging behavior. DLQ e2e test adds a short delay before baseline capture.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added go Pull requests that update go code area/api HTTP handlers, routing, middleware labels May 27, 2026
@github-actions
github-actions Bot requested a review from EricAndrechek May 27, 2026 18:13
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request centralizes authorization denial handling across the API to improve system observability. By routing all denials through a unified helper, the system now emits structured logs that capture essential context about why a request was rejected, such as role resolution details and route patterns. This change facilitates faster troubleshooting of policy misconfigurations without requiring request reproduction.

Highlights

  • Centralized Authorization Logging: Introduced a shared writeAuthzDenied helper that ensures all authorization denials are consistently logged with structured slog WARN messages.
  • Improved Observability: Logs now include context such as the observed vs. resolved role, allowed roles, request method, and the chi route pattern, making it easier to debug misconfigured policies.
  • Fail-Loud Authentication: Invalid tokens now result in a 401 status with the specific token error, providing better feedback than a generic 403 forbidden error.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request enhances authorization denial handling by emitting structured WARN logs containing detailed context (such as the observed and resolved roles, allowed roles, route template, and HTTP method) and adds comprehensive unit tests to verify these logs. However, a critical compilation error was identified in internal/api/errors.go where slog.LogAttrs is incorrectly called as a package-level function instead of a method on slog.Default().

Comment thread internal/api/errors.go Outdated
@taitelee taitelee moved this from Backlog to In review in WaveHouse Task Board May 27, 2026
@taitelee taitelee moved this from In review to Ready in WaveHouse Task Board May 27, 2026

@EricAndrechek EricAndrechek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I like the idea behind it, and you did a good job trying to keep it DRY, but I don't think that this implementation is complete, and honestly is doing more harm than good to logging details in its current form.

Comment thread internal/api/errors.go Outdated
Comment thread internal/api/errors_test.go Outdated
Comment thread internal/api/errors_test.go Outdated
Comment thread internal/api/ingest.go Outdated
Comment thread internal/api/router.go Outdated
Comment thread internal/api/structured_query.go Outdated
@github-project-automation github-project-automation Bot moved this from Ready to In review in WaveHouse Task Board May 27, 2026
@github-actions github-actions Bot added area/docs Documentation, site/, README area/infra CI, build, deploy, Docker, release labels May 28, 2026
Comment thread internal/api/router.go Outdated
Comment thread internal/api/router.go Outdated
Comment thread internal/api/errors.go
@github-actions github-actions Bot added documentation Improvements or additions to documentation area/sdk TypeScript SDK (clients/ts/) labels May 29, 2026
Comment thread internal/api/router.go Outdated
Comment thread tests/e2e/sdk/dlq.test.ts
@EricAndrechek
EricAndrechek enabled auto-merge (squash) June 2, 2026 10:21
@EricAndrechek
EricAndrechek merged commit 08fc38c into main Jun 2, 2026
8 checks passed
@EricAndrechek
EricAndrechek deleted the rbac-security-enforcement branch June 2, 2026 10:22
@github-project-automation github-project-automation Bot moved this from In review to Done in WaveHouse Task Board Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api HTTP handlers, routing, middleware area/docs Documentation, site/, README area/infra CI, build, deploy, Docker, release area/sdk TypeScript SDK (clients/ts/) documentation Improvements or additions to documentation go Pull requests that update go code

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

feat(auth): RequireRoles middleware — fail closed, no permissive fallback

2 participants