Skip to content

build(semgrep): add no-streamable-http-headers rule for Goose recipes#1141

Merged
jomcgi merged 5 commits intomainfrom
build/semgrep-no-streamable-http-headers
Mar 14, 2026
Merged

build(semgrep): add no-streamable-http-headers rule for Goose recipes#1141
jomcgi merged 5 commits intomainfrom
build/semgrep-no-streamable-http-headers

Conversation

@jomcgi
Copy link
Owner

@jomcgi jomcgi commented Mar 14, 2026

Summary

  • Add semgrep rule no-streamable-http-headers to catch unsupported headers: fields in Goose recipe streamable_http extensions
  • Add yaml_rules filegroup to bazel/semgrep/rules/BUILD for YAML-language semgrep rules
  • Add test fixture documenting bad/good patterns in bazel/semgrep/tests/fixtures/
  • Add recipes_semgrep_test to goose_agent/image/BUILD to enforce the rule in CI against all recipe YAML and config.yaml

Motivation

The headers: field is not part of the Goose recipe schema for streamable_http extensions. Goose's strict serde_yaml deserialization rejects unknown fields at runtime with:

Invalid recipe: did not find expected key

This pattern was introduced twice in recent PRs (#1094, #1122) while configuring MCP gateway auth — both times it had to be reverted. The correct approach is to omit headers: entirely since the MCP gateway runs with MCP_REQUIRE_AUTH=false for in-cluster access.

Rule details

  • ID: no-streamable-http-headers
  • Language: yaml
  • Severity: ERROR
  • Pattern: detects headers: inside any streamable_http extension block
  • Fix: remove headers:, use env_keys for secrets or omit auth entirely for in-cluster access

Test plan

  • bazel/semgrep/tests/fixtures/no-streamable-http-headers.yaml documents # ruleid: / # ok: cases
  • recipes_semgrep_test enforces the rule against current recipe files (all pass — no violations present)
  • CI green (semgrep scan, bazel test //...)

🤖 Generated with Claude Code

@jomcgi jomcgi enabled auto-merge (rebase) March 14, 2026 05:20
The `headers:` field is not part of the Goose recipe schema for
`streamable_http` extensions. Goose uses strict serde_yaml deserialization
and rejects unknown fields with "Invalid recipe: did not find expected key",
causing agent job failures at runtime.

This pattern was introduced twice (PRs 1094, 1122) when configuring
in-cluster MCP gateway auth. Both times the `headers: Authorization`
approach had to be reverted. Auth is not needed when MCP_REQUIRE_AUTH=false;
the correct pattern is to simply omit headers.

Changes:
- Add bazel/semgrep/rules/yaml/no-streamable-http-headers.yaml rule
- Add bazel/semgrep/rules/BUILD yaml_rules filegroup and yaml_rules_test
- Add bazel/semgrep/tests/fixtures/no-streamable-http-headers.yaml test case
- Add recipes_semgrep_test to goose_agent/image/BUILD for CI enforcement
  against all recipe YAML files and config.yaml
- Fix Bazel label: //bazel/semgrep/tests:yaml_fixtures (not tests/fixtures:)
- Use mapping-level pattern (without list-item prefix) for broader matching

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jomcgi jomcgi force-pushed the build/semgrep-no-streamable-http-headers branch from 6594452 to c395b5a Compare March 14, 2026 05:31
chart-version-bot and others added 4 commits March 14, 2026 05:31
Remove blank lines before --- document separators in the
no-streamable-http-headers fixture file. Prettier normalizes this
format; the CI format check auto-detects and rejects unformatted files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The semgrep gazelle plugin marks manually-added semgrep_test rules as
stale when a package has no .py files or configured target kinds
(py_venv_binary, go_binary). The goose_agent image package has only
Go and YAML files, so the plugin's staleRules() deletes the
recipes_semgrep_test target on every `gazelle` run, causing the
format check to fail (git diff --exit-code detects the deletion).

Add `# gazelle:semgrep disabled` to prevent the plugin from processing
this package. The recipes_semgrep_test enforces that recipe YAML files
never include `headers:` in streamable_http extensions — an anti-pattern
that caused two separate runtime failures (PRs 1094, 1122).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jomcgi jomcgi merged commit 01a7d4b into main Mar 14, 2026
6 checks passed
@jomcgi jomcgi deleted the build/semgrep-no-streamable-http-headers branch March 14, 2026 06:35
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.

1 participant