Skip to content

fix(pipes): escape non-scalar param values - #330

Merged
taitelee merged 10 commits into
mainfrom
non-scalar-pipe-injection
Jun 11, 2026
Merged

taitelee merged 10 commits into
mainfrom
non-scalar-pipe-injection

Conversation

@taitelee

@taitelee taitelee commented Jun 10, 2026 •

Copy link
Copy Markdown
Member

Summary

Pipe parameters are inlined into the SQL template as escaped literals, but formatParamValue's fallback branch emitted any non-scalar value via fmt.Sprintf("%v") — so a JSON array or object passed as a parameter reached ClickHouse raw and unescaped. An array element's inner ' could close a string literal and inject SQL (a UNION/boolean break-out past the per-column allowlist). Pipe execution is authorized only by the per-pipe allowed_roles (commonly [public]), so this was reachable unauthenticated.

formatParamValue is now recursive and fails closed:

  • a JSON array renders as a parenthesized (v1, v2, …) list with every element escaped — the same IN (…) shape the structured-query builder emits, so WHERE id IN {{ids}} pipes now work safely;
  • a value with no scalar SQL form (a JSON object, or an empty array → invalid IN ()) is rejected with a 400 instead of pasted raw;
  • a numeric-looking query-string value still renders bare (so ?limit=100 works) via a strict numeric-literal check; any other string is single-quote-escaped.

The declared parameter type stays advisory metadata documenting intent for callers and the SDK — binding keys off the runtime value, consistent with how the rest of WaveHouse leaves value typing to ClickHouse. (Stricter param typing can be its own PR if wanted.)

Related Issues

Closes #317

@taitelee
taitelee requested review from a team and EricAndrechek June 10, 2026 20:46
@github-actions github-actions Bot added documentation Improvements or additions to documentation go Pull requests that update go code area/api HTTP handlers, routing, middleware area/pipes Named query pipes area/sdk TypeScript SDK (clients/ts/) area/docs Documentation, site/, README labels Jun 10, 2026
@coderabbitai

coderabbitai Bot commented Jun 10, 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
📝 Walkthrough

Walkthrough

This PR hardens named pipe parameter binding: it enforces declared ParamDef.Type, rewrites formatParamValue to escape strings and render arrays as safe IN lists (rejecting objects and empty arrays), updates BindParams to validate and abort on errors, and adds unit, handler, E2E tests plus docs and changelog updates.

Changes

Pipe parameter security and type enforcement

Layer / File(s) Summary
SQL literal formatting and type validation
internal/pipes/pipes.go, internal/pipes/pipes_test.go
Rewrote formatParamValue to return (string, error), added strict isNumericLiteral, safe single-quote/backslash escaping for strings, and recursive parenthesized IN-list rendering for arrays (reject empty arrays). Added unit tests for accepted and rejected formats.
BindParams type enforcement and parameter binding
internal/pipes/pipes.go, internal/pipes/pipes_test.go
BindParams now enforces declared ParamDef.Type before formatting, aborts substitution with parameter-annotated errors on failure, and substitutes safely formatted inline literals. Tests cover declared-array substitution, undeclared-array handling, mixed element formatting, injection-regression, object rejection, and empty-array rejection.
Handler and integration tests
internal/api/pipes_test.go, tests/e2e/sdk/admin.test.ts
Added handler tests: successful array param binding and rejection (HTTP 400) for object/non-scalar inputs. E2E test creates a pipe with an IN-list param and executes it with a single-quote-containing value, asserting execution and returned rows.
User-facing and internal documentation
CHANGELOG.md, docs/src/content/docs/api.md, docs/src/content/docs/architecture.md, docs/src/content/docs/pipes.mdx
CHANGELOG records the security hardening. API and pipes docs add explicit 400 cases for unsupported non-scalar/empty-array inputs and enforced parameter type. Architecture docs describe placeholder forms, escaped inlining, and array IN rendering.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • Native SQL Templating #32: Implements ParamDef.Type validation and safer formatParamValue/BindParams behavior that address the SQL injection and unescaped non-scalar inlining described in #32.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR fully addresses all objectives from issue #317: preventing SQL injection via non-scalar params, enforcing declared types, escaping arrays as IN(...) lists, and rejecting objects/empty arrays with 400 responses.
Out of Scope Changes check ✅ Passed All changes are focused on fixing the SQL injection vulnerability in pipes: implementation changes to formatParamValue and BindParams, comprehensive test coverage, and aligned documentation updates with no unrelated modifications.
Title check ✅ Passed The title accurately reflects the main security fix in this changeset: hardening pipe parameter handling by escaping and rejecting non-scalar values to prevent SQL injection vulnerabilities.
Description check ✅ Passed The pull request description clearly details the SQL injection vulnerability being fixed, how non-scalar parameters are now handled safely, and references the related issue #317.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch non-scalar-pipe-injection
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch non-scalar-pipe-injection

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

github-actions Bot commented Jun 10, 2026 •

Copy link
Copy Markdown

📚 Docs preview is live → https://f9cefb02-wavehouse-docs.wave-rf.workers.dev

  • Commit — 9fe60c1: Merge remote-tracking branch 'origin/main' into non-scalar-pipe-injection
  • Author — @taitelee
  • Committed — 2026-06-11 13:27 (UTC-04:00)
  • Deployed — 2026-06-11 13:30 EDT

@taitelee taitelee assigned taitelee and unassigned taitelee Jun 10, 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: 4


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 95638e1b-fa68-45ef-a5f1-71e7be4cd78d

📥 Commits

Reviewing files that changed from the base of the PR and between 74b2c81 and 52c83bc.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • docs/src/content/docs/api.md
  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/pipes.md
  • internal/api/pipes_test.go
  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
  • tests/e2e/sdk/admin.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (go)
🧰 Additional context used
📓 Path-based instructions (9)
tests/e2e/sdk/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

tests/e2e/sdk/**/*.test.ts: E2E tests via SDK: The TypeScript SDK is the primary E2E test harness. Tests in tests/e2e/sdk/ exercise the full pipeline and validate backend + SDK correctness via make test-e2e
Per-suite table isolation in E2E: Each test file owns its own ClickHouse tables — <table>_<suite>, generated from tests/e2e/sdk/tables.ts. Get names via const T = suiteTables("<suite>")

Files:

  • tests/e2e/sdk/admin.test.ts
docs/src/content/**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

docs/src/content/**/*.{md,mdx}: Author Mermaid diagrams vertically so they fit the page at legible size; default to top-down (flowchart TB/TD); reserve LR/RL for short chains
Keep Mermaid node labels short; use <br/> for a second line; lean on semantic node classes (wh, win, pain, fail, infra, neutral, store, client) and CSS variables
Diagrams are click-to-zoom on the site; fine detail is recoverable, but ship legible inline diagrams
Never sit two large diagrams side-by-side; wrap comparisons in <div class="diagram-pair">…</div> for vertical stacking

Files:

  • docs/src/content/docs/api.md
  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/pipes.md
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Use Go 1.26 with strict formatting via gofumpt, enforced by CI
Use structured logging with log/slog (JSON handler)
Error handling: Return errors, don't panic. Wrap with fmt.Errorf("context: %w", err)
No global state: Dependencies are passed explicitly (constructor injection)

Files:

  • internal/api/pipes_test.go
  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
internal/api/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

internal/api/**/*.go: Use Chi v5 for HTTP routing
Handler error responses must stay in sync with docs (api.md error tables)

Files:

  • internal/api/pipes_test.go
internal/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Package naming: Lowercase, single word (or abbreviated). internal/ enforces module privacy

Files:

  • internal/api/pipes_test.go
  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Table-driven tests: Use tests := []struct{ name string; ... } with t.Run(tt.name, ...) for test cases
Shared mocks in internal/testutil/: Use MockPublisher, MockCache, MockDeduplicator, MockSubscriber instead of ad-hoc mocks
Schema helpers: Use testutil.NewTestSchemaRegistry(tables) or discovery.NewSchemaRegistryFromMap(tables) for schema-aware tests

Files:

  • internal/api/pipes_test.go
  • internal/pipes/pipes_test.go
internal/api/**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

Response assertions: Use testutil.AssertJSONResponse(t, rec, status, expected) and testutil.AssertJSONContains(t, rec, status, substring) for HTTP handlers

Files:

  • internal/api/pipes_test.go
internal/pipes/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Named query pipes: fail-closed (security). Per-pipe allowed_roles is the only execute-path gate via policy.RoleAllowed: exact allowlist (no "*"), admin always passes, empty role authorizes nobody, no allowed_roles → admin-only

Files:

  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
internal/pipes/**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

Pipes helpers: Use pipes.NewMemoryStore(queries...) for in-memory pipes testing without NATS

Files:

  • internal/pipes/pipes_test.go
🧠 Learnings (4)
📚 Learning: 2026-06-10T15:01:09.027Z
Learnt from: EricAndrechek
Repo: Wave-RF/WaveHouse PR: 312
File: docs/src/content/docs/development.md:0-0
Timestamp: 2026-06-10T15:01:09.027Z
Learning: In this repo’s Markdown review (all .md files), do not flag capitalization/style issues for literal paths starting with ".github/" (or any substring that is a path beginning with ".github/"). Treat ".github" as the correct lowercase dotfile directory name, even when it appears inside prose or code spans; automated checks such as LanguageTool’s "(GITHUB)" rule commonly produce false positives for this literal filesystem path.

Applied to files:

  • docs/src/content/docs/api.md
  • docs/src/content/docs/architecture.md
  • CHANGELOG.md
  • docs/src/content/docs/pipes.md
📚 Learning: 2026-05-20T01:02:00.784Z
Learnt from: EricAndrechek
Repo: Wave-RF/WaveHouse PR: 164
File: internal/api/router_test.go:289-350
Timestamp: 2026-05-20T01:02:00.784Z
Learning: In WaveHouse’s internal API tests (files matching internal/api/**/*_test.go), follow the existing separation-of-concerns convention for testing the RequireRole middleware: inject `ContextKeyRole` directly into the request `context.Context` instead of using `testutil.MakeJWT`/JWT-driven flows. Do not refactor role-gate tests to use JWT tokens—JWT parsing and token handling are covered separately in `middleware_test.go` (the dedicated JWT parsing tests), and mixing those concerns would expand the failure surface and reduce isolation.

Applied to files:

  • internal/api/pipes_test.go
📚 Learning: 2026-05-23T01:23:59.268Z
Learnt from: EricAndrechek
Repo: Wave-RF/WaveHouse PR: 174
File: internal/api/ingest_test.go:111-111
Timestamp: 2026-05-23T01:23:59.268Z
Learning: In WaveHouse Go tests in internal/api/**/*_test.go, use internal/testutil.AssertJSONErrorResponse(t, w) for HTTP error-path JSON assertions. Do not use (or reintroduce) package-local assertJSONErrorResponse helpers. AssertJSONErrorResponse verifies the response Content-Type is application/json, includes the X-Content-Type-Options: nosniff header, and that the JSON body contains an "error" field.

Applied to files:

  • internal/api/pipes_test.go
📚 Learning: 2026-05-20T20:30:15.808Z
Learnt from: taitelee
Repo: Wave-RF/WaveHouse PR: 172
File: internal/api/pipes_test.go:106-118
Timestamp: 2026-05-20T20:30:15.808Z
Learning: For WaveHouse pipes authorization allowlist checks, fix the empty-role fail-open behavior by (1) removing any outer guard that prevents allowlist evaluation when the incoming `role` is `""` (e.g., don’t short-circuit with `if role != "" { ... }`), and (2) during allowlist scanning, ensure only non-empty allowlist entries can match—e.g., require `ar != "" && ar == role` (so a malformed allowlist like `["" ]` cannot grant access to an empty incoming role via `"" == ""`).

Applied to files:

  • internal/api/pipes_test.go
🔇 Additional comments (3)
docs/src/content/docs/architecture.md (1)

138-138: LGTM!

docs/src/content/docs/pipes.md (2)

49-49: LGTM!


175-176: LGTM!

Comment thread docs/src/content/docs/api.md Resolved
Comment thread docs/src/content/docs/pipes.md Resolved
Comment thread internal/api/pipes_test.go Resolved
Comment thread internal/pipes/pipes.go Resolved
@github-project-automation github-project-automation Bot moved this from Backlog to In review in WaveHouse Task Board Jun 10, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 10, 2026
@github-code-quality

github-code-quality Bot commented Jun 10, 2026 •

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: Go

Go

The overall coverage in the non-scalar-pipe-inje... branch remains at 89%, unchanged from the main branch.

Show a code coverage summary of the most impacted files.
File main 9661c82 non-scalar-pipe-inje... 9fe60c1 +/-
internal/pipes/pipes.go 84% 83% -1%

Updated June 11, 2026 17:31 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
internal/pipes/pipes.go (1)

242-253: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Boolean query-string values are accepted but rendered with string quoting.

validateParamType accepts "true"/"false" spellings for declared booleans, but formatParamValue’s string branch only special-cases declared "string" and falls back to quoting for booleans ('true' / 'false'). This breaks the declared boolean contract for query-string inputs and can produce incorrect predicates.

Suggested fix
 case string:
+	if declaredType == "boolean" {
+		b, err := strconv.ParseBool(val)
+		if err != nil {
+			return "", fmt.Errorf("expected boolean, got string")
+		}
+		if b {
+			return "1", nil
+		}
+		return "0", nil
+	}
 	// A numeric-looking string renders bare (so `?limit=100` from a query
 	// string works as a number), unless the parameter is declared a string —
 	// then it is always quoted, honoring the declared type.
 	if declaredType != "string" {
 		if _, err := strconv.ParseFloat(val, 64); err == nil {
 			return val, nil
 		}
 	}
docs/src/content/docs/pipes.mdx (1)

179-180: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a separate row for the empty array error message.

The error table shows two rows, but line 180 conflates two distinct error cases in its description: "a JSON object, or an empty array." These produce different error messages:

  • Objects → {"error":"parameter \"x\": unsupported parameter type object"}
  • Empty arrays → {"error":"parameter \"x\": array parameter must not be empty"}

The api.md error table correctly separates these into three rows (lines 490–492). This table should match.

📝 Suggested addition
 | 400 | `{"error":"parameter \"x\": expected number, got array"}` | A value violates the parameter's declared `type` |
-| 400 | `{"error":"parameter \"x\": unsupported parameter type object"}` | A non-scalar with no SQL form (a JSON object, or an empty array) |
+| 400 | `{"error":"parameter \"x\": unsupported parameter type object"}` | A JSON object has no SQL literal form |
+| 400 | `{"error":"parameter \"x\": array parameter must not be empty"}` | An empty array — it would render as the invalid `IN ()` |

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9ce378aa-99f0-48bd-9b7f-b0684f65b2d8

📥 Commits

Reviewing files that changed from the base of the PR and between 52c83bc and ec94d25.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • docs/src/content/docs/api.md
  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/pipes.mdx
  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Docs preview
  • GitHub Check: E2E tests
  • GitHub Check: Coverage
🧰 Additional context used
📓 Path-based instructions (6)
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Markdown files must pass markdownlint style checks (enforce via make lint)

Files:

  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/api.md
  • CHANGELOG.md
**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

Markdown documentation files must pass docs-prose review (accuracy vs. code, examples, clarity, completeness); scope is canonical set from scripts/docs-prose.sh excluding .claude/**, .github/**, CHANGELOG.md, AGENTS.md, CLAUDE.md, *.draft.md, *.old.md

Files:

  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/api.md
  • CHANGELOG.md
  • docs/src/content/docs/pipes.mdx
docs/src/content/**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

When authoring Mermaid diagrams in Markdown: author vertically (top-down default, flowchart TB/TD) to fit page column (~46–58rem); keep node labels short with <br/> for multi-line; use semantic node classes (wh, win, pain, fail, infra, neutral, store, client); never sit two large diagrams side-by-side without <div class="diagram-pair"> wrapper

Files:

  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/api.md
  • docs/src/content/docs/pipes.mdx
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Go code must use strict formatting enforced by gofumpt
Use structured logging with log/slog (JSON handler) in Go code
Use Chi v5 for HTTP routing in Go code
Return errors from Go functions, never panic; wrap with fmt.Errorf("context: %w", err)
Pass dependencies explicitly via constructor injection in Go; no global state
Go code must pass go fmt (via gofumpt) and goimports (enforced by CI's make verify)
Go code must pass golangci-lint with v2.11.4 (auto-installed to .bin/ on first run; enforced by CI's make verify)
Go code must pass govulncheck ./... for vulnerability scanning (enforced by CI's make verify)
Go internal/ packages must not be imported outside cmd/ or other internal/ packages (module privacy enforced by the filesystem)

Files:

  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
internal/*/**.go

📄 CodeRabbit inference engine (AGENTS.md)

Use lowercase, single-word package names in Go; internal/ enforces module privacy

Files:

  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Use table-driven tests in Go with tests := []struct{ name string; ... } and t.Run(tt.name, ...) for multiple scenarios
Use shared mocks from internal/testutil/ (MockPublisher, MockCache, MockDeduplicator, MockSubscriber) instead of ad-hoc mocks in Go tests
Use testutil.MakeJWT(t, claims) and testutil.MakeExpiredJWT(t, claims) for auth tests in Go
Use testutil.NewTestSchemaRegistry(tables) or discovery.NewSchemaRegistryFromMap(tables) for schema-aware tests in Go
Use policy.NewMemoryStore(p) for in-memory policy testing without NATS in Go
Use pipes.NewMemoryStore(queries...) for in-memory pipes testing without NATS in Go
Use testutil.AssertJSONResponse(t, rec, status, expected) and testutil.AssertJSONContains(t, rec, status, substring) for HTTP response assertions in Go tests
Go test files must be named *_test.go and placed in the same package as the code under test

Files:

  • internal/pipes/pipes_test.go
🧠 Learnings (1)
📚 Learning: 2026-06-10T15:01:09.027Z
Learnt from: EricAndrechek
Repo: Wave-RF/WaveHouse PR: 312
File: docs/src/content/docs/development.md:0-0
Timestamp: 2026-06-10T15:01:09.027Z
Learning: In this repo’s Markdown review (all .md files), do not flag capitalization/style issues for literal paths starting with ".github/" (or any substring that is a path beginning with ".github/"). Treat ".github" as the correct lowercase dotfile directory name, even when it appears inside prose or code spans; automated checks such as LanguageTool’s "(GITHUB)" rule commonly produce false positives for this literal filesystem path.

Applied to files:

  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/api.md
  • CHANGELOG.md
🪛 LanguageTool
docs/src/content/docs/api.md

[style] ~362-~362: Consider using the typographical ellipsis character here instead.
Context: ...e upstream URL, and the request body is {"sql": "..."} with no escape hatch for query-strin...

(ELLIPSIS)

🔇 Additional comments (3)
docs/src/content/docs/api.md (1)

490-492: LGTM!

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

138-138: LGTM!

docs/src/content/docs/pipes.mdx (1)

8-9: LGTM!

Also applies to: 38-40, 53-53, 87-93, 110-110, 184-198, 205-207

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 10, 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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13432d47-a6a2-43d5-b986-05deccee080c

📥 Commits

Reviewing files that changed from the base of the PR and between ec94d25 and 672deaa.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • docs/src/content/docs/api.md
  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (go)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Markdown files must pass markdownlint style checks (enforce via make lint)

Files:

  • CHANGELOG.md
  • docs/src/content/docs/api.md
**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

Markdown documentation files must pass docs-prose review (accuracy vs. code, examples, clarity, completeness); scope is canonical set from scripts/docs-prose.sh excluding .claude/**, .github/**, CHANGELOG.md, AGENTS.md, CLAUDE.md, *.draft.md, *.old.md

Files:

  • CHANGELOG.md
  • docs/src/content/docs/api.md
docs/src/content/**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

When authoring Mermaid diagrams in Markdown: author vertically (top-down default, flowchart TB/TD) to fit page column (~46–58rem); keep node labels short with <br/> for multi-line; use semantic node classes (wh, win, pain, fail, infra, neutral, store, client); never sit two large diagrams side-by-side without <div class="diagram-pair"> wrapper

Files:

  • docs/src/content/docs/api.md
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Go code must use strict formatting enforced by gofumpt
Use structured logging with log/slog (JSON handler) in Go code
Use Chi v5 for HTTP routing in Go code
Return errors from Go functions, never panic; wrap with fmt.Errorf("context: %w", err)
Pass dependencies explicitly via constructor injection in Go; no global state
Go code must pass go fmt (via gofumpt) and goimports (enforced by CI's make verify)
Go code must pass golangci-lint with v2.11.4 (auto-installed to .bin/ on first run; enforced by CI's make verify)
Go code must pass govulncheck ./... for vulnerability scanning (enforced by CI's make verify)
Go internal/ packages must not be imported outside cmd/ or other internal/ packages (module privacy enforced by the filesystem)

Files:

  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
internal/*/**.go

📄 CodeRabbit inference engine (AGENTS.md)

Use lowercase, single-word package names in Go; internal/ enforces module privacy

Files:

  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Use table-driven tests in Go with tests := []struct{ name string; ... } and t.Run(tt.name, ...) for multiple scenarios
Use shared mocks from internal/testutil/ (MockPublisher, MockCache, MockDeduplicator, MockSubscriber) instead of ad-hoc mocks in Go tests
Use testutil.MakeJWT(t, claims) and testutil.MakeExpiredJWT(t, claims) for auth tests in Go
Use testutil.NewTestSchemaRegistry(tables) or discovery.NewSchemaRegistryFromMap(tables) for schema-aware tests in Go
Use policy.NewMemoryStore(p) for in-memory policy testing without NATS in Go
Use pipes.NewMemoryStore(queries...) for in-memory pipes testing without NATS in Go
Use testutil.AssertJSONResponse(t, rec, status, expected) and testutil.AssertJSONContains(t, rec, status, substring) for HTTP response assertions in Go tests
Go test files must be named *_test.go and placed in the same package as the code under test

Files:

  • internal/pipes/pipes_test.go
🧠 Learnings (1)
📚 Learning: 2026-06-10T15:01:09.027Z
Learnt from: EricAndrechek
Repo: Wave-RF/WaveHouse PR: 312
File: docs/src/content/docs/development.md:0-0
Timestamp: 2026-06-10T15:01:09.027Z
Learning: In this repo’s Markdown review (all .md files), do not flag capitalization/style issues for literal paths starting with ".github/" (or any substring that is a path beginning with ".github/"). Treat ".github" as the correct lowercase dotfile directory name, even when it appears inside prose or code spans; automated checks such as LanguageTool’s "(GITHUB)" rule commonly produce false positives for this literal filesystem path.

Applied to files:

  • CHANGELOG.md
  • docs/src/content/docs/api.md
🔇 Additional comments (3)
internal/pipes/pipes.go (1)

142-156: LGTM!

Also applies to: 206-227, 251-277, 343-344

internal/pipes/pipes_test.go (1)

292-296: LGTM!

Also applies to: 347-348, 396-405, 481-498

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

490-492: LGTM!

Comment thread CHANGELOG.md Resolved
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 11, 2026
coderabbitai[bot]
coderabbitai Bot previously requested changes Jun 11, 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

♻️ Duplicate comments (1)
internal/pipes/pipes.go (1)

33-35: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reinstate declared parameter-type enforcement before literal formatting.

At Line 33-35, ParamDef.Type is documented as advisory-only, and at Line 204 binding is driven only by runtime value formatting. This re-opens a contract gap where callers can supply broader shapes than the pipe definition declares (notably on publicly executable pipes), weakening the intended fail-closed behavior.

Suggested fix (shape)
 func BindParams(q *NamedQuery, supplied map[string]any) (string, []any, error) {
@@
-		lit, err := formatParamValue(val)
+		if p, ok := formal[name]; ok && p.Type != "" {
+			if err := validateParamType(p.Type, val); err != nil {
+				bindErr = fmt.Errorf("parameter %q: %w", name, err)
+				return match
+			}
+		}
+		lit, err := formatParamValue(val)
 		if err != nil {
 			bindErr = fmt.Errorf("parameter %q: %w", name, err)
 			return match
 		}
 		return lit
 	})

Also applies to: 204-207


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c1a9c2fd-f9e6-4f76-8374-2972c7dacebc

📥 Commits

Reviewing files that changed from the base of the PR and between 44dd4e3 and 7a2b6c7.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • docs/src/content/docs/api.md
  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/pipes.mdx
  • internal/api/pipes_test.go
  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
💤 Files with no reviewable changes (2)
  • docs/src/content/docs/api.md
  • internal/api/pipes_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 300000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Docs preview
  • GitHub Check: Coverage
  • GitHub Check: E2E tests
🧰 Additional context used
📓 Path-based instructions (4)
docs/src/content/docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (AGENTS.md)

docs/src/content/docs/**/*.{md,mdx}: Author Mermaid diagrams vertically (flowchart TB/TD) to fit page column width (~46–58rem); reserve LR for genuinely short chains (≤3–4 nodes)
Keep Mermaid node labels short; use
for a second line rather than one long line; lean on semantic node classes (wh, win, pain, fail, infra, neutral, store, client)
Never sit two large diagrams side-by-side; wrap comparisons in

…
to stack them vertically

Files:

  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/pipes.mdx
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Use Go 1.26 with strict formatting enforced by gofumpt
Use structured logging with log/slog (JSON handler)
Use Chi v5 for HTTP routing
Return errors, don't panic. Wrap with fmt.Errorf("context: %w", err)
Use package naming: lowercase, single word (or abbreviated). internal/ enforces module privacy
No global state: Dependencies are passed explicitly (constructor injection)
Comment the why, not the what. Add a comment only when the reason isn't obvious from the code; a line that matches the surrounding pattern needs none. Keep comments to 1–2 lines
DRY — one source of truth. Before adding logic, look for an existing helper, type, or constant to reuse; before duplicating a rule, factor it into one place every caller reads
Leave it neater than you found it — within reason. Fix small, safe things in passing: a stale comment, an obvious typo, a misnamed local, dead code on your path

Files:

  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
internal/pipes/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

Named query pipes: NamedQuery type + NATS KV store (WAVEHOUSE_PIPES) + .sql file bootstrap. Pre-defined SQL templates with param binding + caching; per-pipe allowed_roles is the only execute-path gate via policy.RoleAllowed

Files:

  • internal/pipes/pipes.go
  • internal/pipes/pipes_test.go
**/*_test.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*_test.go: Use table-driven tests with tests := []struct{ name string; ... } and t.Run(tt.name, ...)
Use shared mocks from internal/testutil/ (MockPublisher, MockCache, MockDeduplicator, MockSubscriber) instead of creating ad-hoc mocks
Use testutil.MakeJWT(t, claims) and testutil.MakeExpiredJWT(t, claims) for auth tests
Use testutil.NewTestSchemaRegistry(tables) or discovery.NewSchemaRegistryFromMap(tables) for schema-aware tests
Use policy.NewMemoryStore(p) for in-memory policy testing without NATS
Use pipes.NewMemoryStore(queries...) for in-memory pipes testing without NATS
Use testutil.AssertJSONResponse(t, rec, status, expected) and testutil.AssertJSONContains(t, rec, status, substring) for response assertions

Files:

  • internal/pipes/pipes_test.go
🧠 Learnings (1)
📚 Learning: 2026-06-10T15:01:09.027Z
Learnt from: EricAndrechek
Repo: Wave-RF/WaveHouse PR: 312
File: docs/src/content/docs/development.md:0-0
Timestamp: 2026-06-10T15:01:09.027Z
Learning: In this repo’s Markdown review (all .md files), do not flag capitalization/style issues for literal paths starting with ".github/" (or any substring that is a path beginning with ".github/"). Treat ".github" as the correct lowercase dotfile directory name, even when it appears inside prose or code spans; automated checks such as LanguageTool’s "(GITHUB)" rule commonly produce false positives for this literal filesystem path.

Applied to files:

  • docs/src/content/docs/architecture.md
  • CHANGELOG.md
🔇 Additional comments (3)
docs/src/content/docs/pipes.mdx (3)

84-93: LGTM!


95-110: LGTM!


179-179: LGTM!

Comment thread docs/src/content/docs/pipes.mdx Resolved
@taitelee taitelee changed the title fix(pipes): escape non-scalar param values and enforce declared type fix(pipes): escape non-scalar param values Jun 11, 2026
@taitelee
taitelee dismissed coderabbitai[bot]’s stale review June 11, 2026 19:21

type enforcement intentionally dropped

@taitelee
taitelee added this pull request to the merge queue Jun 11, 2026
Merged via the queue into main with commit d216c97 Jun 11, 2026
20 checks passed
@taitelee
taitelee deleted the non-scalar-pipe-injection branch June 11, 2026 19:26
@github-project-automation github-project-automation Bot moved this from In review to Done in WaveHouse Task Board Jun 11, 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/pipes Named query pipes 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.

security(pipes): non-scalar pipe param values inlined into SQL unescaped + declared type unchecked (SQL injection)

2 participants