Skip to content

feat(rbac)!: fail-closed authorization + default_role public access - #172

Merged
EricAndrechek merged 31 commits into
mainfrom
rbac-security-enforcement
May 27, 2026
Merged

feat(rbac)!: fail-closed authorization + default_role public access#172
EricAndrechek merged 31 commits into
mainfrom
rbac-security-enforcement

Conversation

@taitelee

@taitelee taitelee commented May 20, 2026

Copy link
Copy Markdown
Member

Summary

Started as the #159 fail-open fix in pipe AllowedRoles and grew into a fail-closed pass over the whole RBAC surface, plus opt-in public access. Authorization is now uniformly allowlist membership: a caller's role (a tokenless/roleless request is first resolved to the policy default_role) must appear in the relevant allowlist, the built-in admin role is the only bypass, and the * any-role wildcard is gone.

Pipe authorization — internal/api/pipes.go (Closes #159)

The original bug: Execute enforced AllowedRoles only when the request carried a non-empty role, so an empty/absent role (a JWT missing auth.role_claim, or a tokenless request) skipped the gate and a restricted pipe was served — a fail-open authorization bug, and AllowedRoles is the only gate on the execute path.

Execute now runs one path for every request:

  1. Read the role; if empty, resolve it to the policy default_role (via PolicyStore/ResolveRole).
  2. The admin role (policy.AdminRole) always passes.
  3. Otherwise the role must be an exact match in allowed_roles; empty-string entries are skipped (a stray "" can't authorize a roleless caller).
  • BREAKING: a pipe with no allowed_roles now authorizes nobody but the admin role (previously it was open / "still required a token" under public access). Public reach is opt-in only by listing a role the default_role resolves to.
  • BREAKING: the admin role bypasses every pipe, including restricted ones, consistent with policy.Evaluate and the /v1/admin/* RequireAdmin gate.
  • Removed the now-unused PipesHandler.AllowAnonymous field/branch.

Policy engine — internal/policy/

  • Evaluate: an empty/absent role never matches a role key; the "*" any-role role wildcard is removed (column allow-lists, e.g. allow_columns: ["*"], are unaffected); the admin-role bypass is retained. Roleless access is granted only via default_role substitution. A nil policy (none configured yet, or deleted from KV) fails closed in Evaluate itself — only the admin role passes — so deleting the policy denies all non-admin traffic on its own.
  • Validate: rejects empty role keys, and a default_role equal to the admin role (it would hand every roleless request full admin).

Public / anonymous access via default_roleinternal/auth/auth.go, router.go, main.go, errors.go

  • No config flag, and no auth on/off switch: the auth middleware always runs, authenticates the Bearer token if present, and never rejects — authentication is decoupled from authorization (internal/auth). A no-token request, or one whose token lacks the role claim, carries an empty role that ResolveRole maps to the policy default_role before evaluation.
  • Public access is therefore driven entirely by the policy: define a usable (non-admin) default_role and anonymous callers reach whatever that role is authorized for; with no usable default_role, a roleless request has no role and is denied 403 ("forbidden: request has no role and no public default_role is configured") by whatever gate it hits. A policy PUT/delete flips this live (no restart).
  • A present-but-invalid/expired token still resolves to the empty role, but the auth middleware stashes the reason so a denying gate fails loud with 401 (token expired / invalid token) rather than a bare 403.
  • default_role is honored for authenticated-but-roleless requests too (valid token, no role claim).
  • The admin surface is gated by a single RequireAdmin middleware (router.go), driven by the live policy admin role (policy.AdminRole, configurable via admin_role, default admin): /v1/admin/* (raw-SQL /v1/admin/query, policy, pipe mutations, log-level), plus /v1/schema, /v1/schema/refresh, and /v1/dlq/stats — the infra endpoints that have no policy gate of their own.
  • forbiddenForRole returns a clearer 403 when the effective role is empty.

Divergence from #159's plan

#159 (and the original PR body) treated the "*" wildcard as kept ("wildcard intentionally permissive") and left "wildcard, no role" as a decision. We went further and removed the role wildcard entirely so authorization is pure allowlist membership with the admin role as the only bypass — no implicit "any role" grant. The role-matrix test cases were updated accordingly.

Tests & docs

  • internal/testutil/rolematrix.go: shared RunRoleMatrix/StandardRoleMatrix — the canonical (AllowedRoles, observed-role) matrix every allowlist gate must pass; a handler taking AllowedRoles without running it looks under-tested in review.
  • Expanded internal/api/pipes_test.go (no-allowlist deny/allow, default_role resolution, param paths), internal/policy/policy_test.go (empty-role guards, *-no-longer-grants regression, default_role substitution/escalation refusal), internal/api/router_test.go, internal/auth/auth_test.go, internal/policy/store_test.go, internal/config/config_test.go.
  • CHANGELOG.md, docs/api.md, docs/configuration.md, AGENTS.md updated to the fail-closed / no-wildcard public-access semantics.

Breaking changes

  • A pipe with no allowed_roles denies all callers except the admin role (was open).
  • The "*" any-role wildcard is removed from pipe allowed_roles and from policy.Evaluate role keys. Existing "*" role entries now match nothing (column allow_columns: ["*"] is unaffected).
  • The admin role bypasses every pipe.

Related issues

@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 addresses a security vulnerability where pipes with defined AllowedRoles were inadvertently accessible to requests lacking a role. By removing the conditional guard that skipped authorization checks for empty roles, the system now correctly evaluates these requests against the allowlist, defaulting to a 403 Forbidden response when no match is found.

Highlights

  • Security Fix: Updated PipesHandler.Execute to enforce AllowedRoles even when the request role is empty or absent, preventing unauthorized access to restricted pipes.
  • Test Coverage: Consolidated existing role authorization tests into a comprehensive table-driven test suite and added specific regression tests for empty/absent role scenarios.
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.

@github-actions github-actions Bot added go Pull requests that update go code area/api HTTP handlers, routing, middleware labels May 20, 2026
@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e3997bf3-5b38-47c9-b00a-de8de432a3c3

📥 Commits

Reviewing files that changed from the base of the PR and between e05bee3 and 59e0387.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • config.yaml
  • docs/src/content/docs/configuration.md
  • docs/src/content/docs/deployment.md
  • internal/config/config.go
  • internal/config/config_test.go
  • internal/policy/store.go
  • internal/policy/store_test.go
  • scripts/orchestrator/main.go
  • tests/e2e/fixtures/policy.yaml
💤 Files with no reviewable changes (1)
  • config.yaml
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use Go 1.26 with strict formatting via gofumpt

Use structured logging with log/slog and JSON handler for all logging

Return errors instead of panicking; wrap errors with fmt.Errorf for context

Avoid global state; pass dependencies explicitly using constructor injection

Use lowercase, single-word package names (or abbreviated); enforce module privacy via internal/

Files:

  • internal/config/config_test.go
  • internal/policy/store.go
  • internal/policy/store_test.go
  • scripts/orchestrator/main.go
  • internal/config/config.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

Use table-driven tests with t.Run(tt.name, ...) for multiple test scenarios

Use shared mocks from internal/testutil/ (MockPublisher, MockCache, MockDeduplicator, MockSubscriber) instead of ad-hoc mocks

Files:

  • internal/config/config_test.go
  • internal/policy/store_test.go
internal/policy/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Use Hasura-style access control: per-table, per-role column-level and row-level permissions with JWT claim templating ({{ jwt.path }}); policies stored in NATS KV with file-based bootstrap

Policy IsAdmin check is policy.IsAdmin (role == admin_role, configurable, exact case-sensitive match with no normalization); it is the single source of truth across Evaluate, ResolveRole, Validate, /v1/admin gate, and pipe authorization

Empty/absent role is fail-closed: never matches a role key, exact match only (no any-role wildcard), only admin role bypasses allowlist; Validate rejects empty role keys at write time, nil policy denies everyone including admin (total lockout)

Setting default_role equal to admin_role makes every roleless request admin; permitted but dev-only; store logs a loud warning on every node (policy.DefaultRoleGrantsAdmin condition); never use in production

Roles do not inherit default role permissions; default_role maps only empty/absent roles via ResolveRole before evaluation

When touching internal/policy package, preserve policy authorization invariants: exact admin check (policy.IsAdmin), fail-closed empty role, exact allowlist (no wildcard), default_role mapping, and test via shared testutil.RunRoleMatrix / StandardRoleMatrix

Files:

  • internal/policy/store.go
  • internal/policy/store_test.go
internal/policy/**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

Use policy.NewMemoryStore(p) for in-memory policy testing without NATS

Files:

  • internal/policy/store_test.go
internal/config/config.go

📄 CodeRabbit inference engine (AGENTS.md)

Config option changes require updates to docs/src/content/docs/configuration.md, config.yaml, deployments/compose/* env blocks, and docs/src/content/docs/deployment.md

Files:

  • internal/config/config.go
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Aim for 80%+ coverage on new code; project-wide minimum is 80% (merged unit + integration + e2e); per-suite minima: unit 70%, integration 12%, e2e 50%, sdk 50%
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Every new function should have corresponding test cases
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Run make lint and make test before considering work complete
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Architecture changes and new internal packages require updates to docs/src/content/docs/architecture.md and AGENTS.md
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Any notable code change should update CHANGELOG.md under [Unreleased] section
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Grep for config identifiers (field names, env var names, endpoint paths) across docs after touching config to catch staleness
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: TypeScript SDK updates needed when user-facing backend changes alter public API surface; SDK client methods, auth handling, EventMessage types, query AST, live-query aggregation, pipes, and policy endpoints must align with backend
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Validate locally before pushing via make ci (full parity with CI); do not use CI as first feedback loop — every push consumes shared CI capacity and AI-reviewer credits
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: make tools installs team-wide git hooks via git config core.hooksPath .githooks; .githooks/pre-commit runs make verify (~30s); .githooks/pre-push checks for tmp/ci-passed-<HEAD-sha> marker
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Bypass git hooks with git commit --no-verify / git push --no-verify only when explicitly intentional (WIP/draft); do not disable hooks globally
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Every review comment gets a substantive reply; every review thread gets resolved before merge (main branch protection enforces required_review_thread_resolution: true)
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: When replying to bot reviewers (Claude, Gemini), mention the bot on its own line in the reply; without mention, the bot never sees the reply and dialog silently terminates
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Fix in current PR if suggestion is in scope; out-of-scope but valid: link a tracking issue before resolving thread; re-request review from humans after substantive changes
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Do not argue in circles with reviewers; if repeated, escalate to maintainer; do not resolve thread with open child comment
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Syncing a PR branch with main: merge, don't rebase (git merge origin/main --no-edit); force-pushes blocked by deny rules and lose inline review-thread anchors; rebase changes SHAs requiring force-push
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: AI agents must create PRs with gh pr create --draft; only humans transition draft → ready-for-review; only humans approve or request changes
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: AI agents cannot add/remove human reviewers; only humans assign reviewers; agents can re-request bot reviewers via PR comments (claude, gemini-code-assist)
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: AI agents must invoke pre-push-reviewer subagent in fresh context before pushing to any branch with open PR; VERDICT: ship_it requires zero findings (including [MAY] sections); loop on iterate/block until ship_it
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: No agent bypass for git hooks; git push --no-verify and git commit --no-verify blocked for agents at .claude/hooks/agent-bash-gate.sh; marker files written exclusively by make ci (ci-passed) and pre-push-reviewer (review-passed)
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Gemini Code Assist silently ignores all .github/workflows/** files; for workflow-heavy PRs, Claude review is primary AI reviewer
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Issue triage (triage.yml): GitHub Models classifies new/edited issues and applies area/* + security + breaking-change labels; add matching area/<pkg> repo label for new internal packages so triage.yml routes issues (discovers via gh label list at runtime)
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: JWT secret (or JWKS endpoint) must be cryptographically strong in production; JWT middleware always runs (no enable flag), so token validation is sole gate on elevated access
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: govulncheck ./... runs in CI on every push/PR; Dependabot opens weekly grouped PRs for outdated Go modules and GitHub Actions
Learnt from: CR
Repo: Wave-RF/WaveHouse

Timestamp: 2026-05-27T13:34:54.460Z
Learning: Conventional Commits type list in CONTRIBUTING.md must stay in sync with regex in housekeeping.yml; title linter validates squash-merge commit messages
🧬 Code graph analysis (2)
internal/policy/store.go (1)
internal/policy/store_test.go (1)
  • NewStore (67-67)
internal/policy/store_test.go (1)
internal/policy/store.go (2)
  • Get (88-92)
  • Put (95-116)
🔇 Additional comments (8)
docs/src/content/docs/configuration.md (1)

109-109: LGTM!

Also applies to: 191-191

internal/config/config_test.go (1)

31-31: LGTM!

internal/policy/store.go (1)

6-6: LGTM!

Also applies to: 32-43, 55-58, 64-67, 69-83

CHANGELOG.md (1)

71-71: LGTM!

internal/policy/store_test.go (1)

31-47: LGTM!

Also applies to: 74-89, 108-187

scripts/orchestrator/main.go (1)

151-151: LGTM!

Also applies to: 186-186, 234-234, 258-334

internal/config/config.go (1)

129-141: Update review: companion artifacts for policy.file_path default removal

Docs are consistent with the explicit opt-in contract: docs/src/content/docs/configuration.md documents policy.file_path as empty-by-default (no implicit policy.yaml lookup; seed via PUT /v1/admin/policy), and docs/src/content/docs/deployment.md documents WH_POLICY_FILE_PATH=/etc/wavehouse/policy.yaml.

The shipped config samples don’t reintroduce that contract via env/config: ./config.yaml has no references to policy:, file_path, or WH_POLICY_FILE_PATH, and deployments/compose/**/*.yml(yaml) contains no WH_POLICY_FILE_PATH occurrences.

docs/src/content/docs/deployment.md (1)

131-134: docs contract: reconcile quick-start unauth behavior with opt-in fail-closed policy bootstrap

  • docs/src/content/docs/deployment.md (lines 131-134) says WH_POLICY_FILE_PATH bootstrap is opt-in and, when set, invalid/missing files must fail-boot (otherwise seed via PUT /v1/admin/policy).
  • In compose references, WH_POLICY_FILE_PATH is not set for deployments/compose/standalone.yaml (only commented guidance), while WH_AUTH_JWT_SECRET is set for tests/e2e/compose.yaml and clients/ts/playground/compose.yaml.
  • The search for default_role / admin_role mappings in tests/e2e/fixtures/policy.yaml and deployments/compose/config.yaml returned none, so it’s unclear what default_role-bearing policy would exist for any “no auth required by default” quick-start path.

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Policy-backed role resolution and a single admin gate; per-pipe allowlists now fail-closed with exact-match semantics, admin bypass preserved.
  • Security

    • JWT middleware always runs; invalid/expired tokens return 401, roleless requests evaluate via policy/default_role and are denied unless explicitly granted. Signing-algorithm handling tightened.
  • Behavior

    • Ingest is insert-only; non-insert mutations require the admin-only SQL path. Admin surfaces (/v1/admin/*, schema) require the configured admin role.
  • Documentation

    • Docs, guides, playground, and examples updated to reflect the new auth model, token semantics, and endpoint shapes.
  • Tests

    • Expanded auth/policy tests, new role-matrix helpers, and JWT middleware coverage.
  • Breaking Changes

    • Removed auth enable/dev-mode toggles; always-on JWT semantics; ingest envelopes are insert-only.

Walkthrough

Adds always-on JWT auth middleware and context helpers; centralizes policy role helpers and store warnings; replaces router role allowlist with policy-backed RequireAdmin; enforces fail-closed per-pipe allowed_roles in PipesHandler.Execute; updates handlers to use auth context and role-aware denials; broad test, config, manifest, and docs updates.

Changes

Auth middleware & context

Layer / File(s) Summary
JWT middleware and context helpers
internal/auth/*, internal/auth/auth_test.go
New auth.Config and auth.Middleware that extracts tokens (header/query), pins allowed alg family, records claims/role/auth errors in context, strips query tokens, and has tests covering header/query precedence, invalid/expired tokens, JWKS boot behavior, and claim extraction.

Policy & role helpers

Layer / File(s) Summary
Policy evaluation, validation, roles, and store
internal/policy/policy.go, internal/policy/roles.go, internal/policy/store.go, internal/policy/*_test.go
ResolveRole/Evaluate now fail-closed for nil/missing entries; wildcard role matching removed; validate rejects empty/whitespace role keys; added AdminRole/IsAdmin/DefaultRoleGrantsAdmin/RoleAllowed helpers; Store warns when default_role == admin_role, clears cache on KV delete, and NewStore bootstrapping is stricter with tests.

Router & admin gate

Layer / File(s) Summary
Router admin gate and wiring
internal/api/router.go, internal/api/router_test.go
Replace AuthEnabled + RequireRole with PolicyStore and RequireAdmin(store) middleware that checks policy.IsAdmin on auth.RoleFromContext; apply to /v1/admin/*, /schema, and DLQ; tests updated for admin-only behavior and 401 vs 403 token outcomes.

Pipes handler & tests

Layer / File(s) Summary
Pipes Execute authorization and tests
internal/api/pipes.go, internal/api/pipes_test.go, internal/testutil/rolematrix.go
PipesHandler holds a PolicyStore and enforces policy.RoleAllowed in Execute (deny when resolved role empty unless admin); constructor signature updated; tests refactored to use auth.WithRole/WithClaims and a role-matrix runner; explicit non-admin deny and admin allow cases added.

Handlers and error responses

Layer / File(s) Summary
Handlers use auth context + role-aware denials
internal/api/ingest.go, internal/api/structured_query.go, internal/api/stream_*.go, internal/api/errors.go
Handlers use auth.*FromContext and call writeAuthzDenied which maps token errors → 401 and role denials → 403 with JSON error body; updates to tests and wiring reflect auth context helpers.

Tests, integration, playground, and manifests

Layer / File(s) Summary
Test utilities, integration, and playground
internal/testutil/rolematrix.go, tests/integration/*, clients/ts/playground/*, tests/e2e/compose.yaml
Add RoleCase/RunRoleMatrix helpers; integration test server stamps admin role for test server; playground creates admin JWT and bootstraps policy before seeding; compose manifests remove auth.enabled/dev_mode toggles and document always-on behavior.

Docs & config

Layer / File(s) Summary
Docs, CHANGELOG, config and manifests
docs/src/content/docs/*, CHANGELOG.md, SECURITY.md, AGENTS.md, README.md, config.yaml, deployments/*
Document always-on JWT middleware, default_role fallback, admin-only /v1/admin/query, insert-only ingest shape, named-pipe allowed_roles fail-closed semantics, and remove auth enable/dev toggles from examples and manifests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

  • Wave-RF/WaveHouse#177: modifies PipesHandler/NewPipesHandler wiring and is closely related to the pipes authorization changes.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rbac-security-enforcement
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch rbac-security-enforcement

@github-actions
github-actions Bot requested a review from EricAndrechek May 20, 2026 20:15
@taitelee taitelee moved this from Backlog to In progress in WaveHouse Task Board May 20, 2026
@taitelee taitelee moved this from In progress to In review in WaveHouse Task Board May 20, 2026

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/api/pipes_test.go`:
- Around line 147-153: The test uses raw testify assertions
(assert.Equal/assert.NotEqual and assertJSONErrorResponse) for HTTP responses;
replace them with the repo testutil helpers: when expecting rejection replace
the pair assert.Equal(... http.StatusForbidden ...) and
assertJSONErrorResponse(t, w) with testutil.AssertJSONResponse(t, w,
http.StatusForbidden, /* expected JSON error or substring */) (keeping the same
context variables tc.allowedRoles, tc.role, tc.setRole and recorder w), and when
expecting success replace the assert.NotEqual checks with
testutil.AssertJSONContains(t, w, http.StatusOK, /* expected substring or key
present */) or testutil.AssertJSONResponse(t, w, expectedStatus, expectedBody)
as appropriate (use tc.allowedRoles/tc.role/tc.setRole to keep the test message
context and apply same change for the other occurrence around lines 176-178).
- Around line 106-118: Add a regression test row to verify that empty strings in
AllowedRoles are ignored: update the test cases table (the slice of test rows in
pipes_test.go) to include an entry with AllowedRoles set to []string{""} and the
request role empty (""), expecting the pipe to be restricted (i.e., require auth
-> expect 403/failure). Locate the table used by the test harness (the test-case
slice near the examples with descriptions like "wildcard, no role") and add a
case such as {"empty allowlist entry", []string{""}, "", false, true} to assert
a 403 response.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c52117c5-ce04-4a78-ad07-7f11a286a32a

📥 Commits

Reviewing files that changed from the base of the PR and between 4bd92a8 and e34a4a3.

📒 Files selected for processing (1)
  • internal/api/pipes_test.go

Comment thread internal/api/pipes_test.go Outdated
Comment thread internal/api/pipes_test.go Outdated

@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 refactors the authorization tests for the pipes handler into a comprehensive table-driven test suite, covering scenarios for open pipes, restricted pipes, wildcard roles, and missing context roles. The feedback suggests clarifying the documentation within the test struct to better distinguish between an empty role string and a missing role in the context.

Comment thread internal/api/pipes_test.go Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 20, 2026
@github-actions github-actions Bot added documentation Improvements or additions to documentation area/docs Documentation, site/, README labels May 20, 2026

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/src/content/docs/api.md`:
- Around line 325-326: Update the docs text that says auth.enabled=false leaves
all /v1/* open to include a brief exception: if a pipe defines allowed_roles
(the pipe-level `allowed_roles` setting), requests are still subject to
fail-closed checks even when `auth.enabled=false`—requests without a role (e.g.
auth disabled or JWT missing `auth.role_claim`) will be denied unless the pipe's
`allowed_roles` explicitly includes `"*"`. Reference the `auth.enabled` setting,
the `/v1/*` path, `allowed_roles`, and `auth.role_claim` so readers can locate
the relevant settings.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2368d45d-8309-4980-bfdf-159fd2cc84e3

📥 Commits

Reviewing files that changed from the base of the PR and between e34a4a3 and 732b11d.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • docs/src/content/docs/api.md
  • internal/api/pipes.go
  • internal/api/pipes_test.go

Comment thread docs/src/content/docs/api.md Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 21, 2026
@github-project-automation github-project-automation Bot moved this from In review to In progress in WaveHouse Task Board May 21, 2026
@github-actions github-actions Bot added the area/policy Access control policies (Hasura-style) label May 21, 2026

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/policy/policy_test.go`:
- Around line 327-346: Convert the new individual tests (e.g.,
TestValidate_RejectsEmptyRoleKey and the tests around lines 377-414) into a
single table-driven test using the repo convention: create tests :=
[]struct{name string; policy *Policy; wantErr bool; wantMsg string}{...} and
iterate with for _, tt := range tests { t.Run(tt.name, func(t *testing.T){ err
:= Validate(tt.policy); if tt.wantErr { require.Error(t, err);
assert.Contains(t, err.Error(), tt.wantMsg) } else { require.NoError(t, err)
}})}; reference the Policy, TablePolicy and Validate symbols to build the table
cases (include entries for empty role key, other edge-cases originally added,
and expected messages like "empty role").
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6763fc00-7703-47d1-84cb-767326ba5b2a

📥 Commits

Reviewing files that changed from the base of the PR and between 732b11d and c0e84f5.

📒 Files selected for processing (7)
  • AGENTS.md
  • CHANGELOG.md
  • docs/src/content/docs/api.md
  • internal/api/pipes_test.go
  • internal/policy/policy.go
  • internal/policy/policy_test.go
  • internal/testutil/rolematrix.go

Comment thread internal/policy/policy_test.go Outdated
@github-project-automation github-project-automation Bot moved this from In progress to In review in WaveHouse Task Board May 21, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 21, 2026
@github-project-automation github-project-automation Bot moved this from In review to In progress in WaveHouse Task Board May 21, 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/pipes Named query pipes area/policy Access control policies (Hasura-style) 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.

fix(pipes): per-pipe AllowedRoles fails open when context role is empty feat(auth): RequireRoles middleware — fail closed, no permissive fallback

2 participants