fix(api): address ZAP DAST scan findings#579
Conversation
…ware Cache-Control Add ZAP rules file (.github/zap-rules.tsv) to suppress validated false positives: unexpected content-type on /docs HTML endpoints, client error responses from literal path params, base64 patterns in public OpenAPI schema, and Sec-Fetch-* headers (JWT auth, no CSRF risk). Non-Storable Content kept as WARN for visibility. Make Cache-Control path-aware: /docs/* gets public, max-age=300 (public, unauthenticated content safe for brief caching), API endpoints keep no-store (sensitive dynamic data). Wire _API_CACHE_CONTROL constant into _SECURITY_HEADERS to prevent silent divergence. Fix pre-existing bare string event "asgi_missing_status" in middleware to use API_ASGI_MISSING_STATUS constant from observability events. Closes #441 Pre-reviewed by 11 agents, 5 findings addressed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
🧰 Additional context used🧠 Learnings (5)📚 Learning: 2026-03-15T11:48:14.867ZApplied to files:
📚 Learning: 2026-03-15T11:48:14.867ZApplied to files:
📚 Learning: 2026-03-15T11:48:14.867ZApplied to files:
📚 Learning: 2026-03-15T11:48:14.867ZApplied to files:
📚 Learning: 2026-03-15T11:48:14.867ZApplied to files:
🪛 LanguageToolCLAUDE.md[uncategorized] ~285-~285: The official name of this software platform is spelled with a capital “H”. (GITHUB) [uncategorized] ~285-~285: The official name of this software platform is spelled with a capital “H”. (GITHUB) docs/security.md[uncategorized] ~224-~224: The official name of this software platform is spelled with a capital “H”. (GITHUB) 🔇 Additional comments (4)
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds ZAP DAST tuning via Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
📝 Coding Plan
Comment |
Summary of ChangesHello, 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 significantly enhances the API's security posture and performance by refining its Dynamic Application Security Testing (DAST) process and optimizing HTTP caching. It addresses false positives in security scans, ensuring more accurate reporting, and intelligently manages Highlights
Ignored Files
Using Gemini Code AssistThe 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
Customization To customize 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 Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. 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
|
There was a problem hiding this comment.
Code Review
This pull request addresses ZAP DAST scan findings by introducing a rules file to suppress validated false positives and by implementing path-aware Cache-Control headers. The changes are well-implemented, with clear constants, updated documentation, and comprehensive tests. The logic for differentiating API and documentation paths for caching policies is correct. The use of constants for event names and cache control values improves maintainability. I have reviewed the changes and have no further recommendations.
- Add COOP row to security headers table in docs/security.md - Fix DAST schedule text (was "Weekly + on-demand", now "On push to main + weekly") - Reorder Cache-Control constants: default (_API) before override (_DOCS), matching CSP pair - Add Cache-Control to module-level docstring in middleware.py - Tighten COOP from unsafe-none to same-origin-allow-popups on /docs paths (prevents XS-Leak via window.opener while still allowing Scalar UI popups) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #579 +/- ##
=======================================
Coverage 92.66% 92.66%
=======================================
Files 545 545
Lines 27061 27065 +4
Branches 2603 2603
=======================================
+ Hits 25076 25080 +4
Misses 1568 1568
Partials 417 417 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tests/unit/api/test_middleware.py`:
- Around line 227-236: Rename the test function
test_docs_cache_does_not_suppress_coop_relaxation to a positive, clearer name
like test_docs_path_applies_cache_and_coop_relaxations; update any
references/imports if present so the test runner picks it up, leaving the body
unchanged (requests to "/docs/openapi.json", assertions against headers
"cache-control" == _DOCS_CACHE_CONTROL and "cross-origin-opener-policy" ==
"same-origin-allow-popups" should remain as-is) to preserve the original
assertions and intent.
🪄 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
Run ID: ea7e8efb-3590-4edb-980e-81d69ae5a200
📒 Files selected for processing (3)
docs/security.mdsrc/synthorg/api/middleware.pytests/unit/api/test_middleware.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Build Backend
- GitHub Check: Build Web
- GitHub Check: Build Sandbox
- GitHub Check: Test (Python 3.14)
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (4)
docs/**/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
Always read the relevant
docs/design/page before implementing any feature or planning any issue. The design spec is the starting point for architecture, data models, and behavior.
Files:
docs/security.md
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Usefrom synthorg.observability import get_loggerfollowed bylogger = get_logger(__name__)in every module with business logic. Never useimport logging,logging.getLogger(), orprint()in application code.
Use event name constants from domain-specific modules undersynthorg.observability.events(e.g.,API_REQUEST_STARTEDfromevents.api,TOOL_INVOKE_STARTfromevents.tool). Import directly:from synthorg.observability.events.<domain> import EVENT_CONSTANT.
Use structured logging with kwargs:logger.info(EVENT, key=value)— never use string formatting likelogger.info('msg %s', val).
Do not usefrom __future__ import annotations— Python 3.14 has native PEP 649 lazy annotations.
Useexcept A, B:syntax (no parentheses) for exception handling as per PEP 758 on Python 3.14, enforced by ruff.
All public functions and classes must have type hints. Use mypy strict mode for type checking.
Use Google-style docstrings required on all public classes and functions, enforced by ruff D rules.
Create new objects for immutability; never mutate existing ones. For non-Pydantic internal collections (registries,BaseTool), usecopy.deepcopy()at construction +MappingProxyTypewrapping for read-only enforcement.
Fordict/listfields in frozen Pydantic models, rely onfrozen=Truefor field reassignment prevention andcopy.deepcopy()at system boundaries (tool execution, LLM provider serialization, inter-agent delegation, serializing for persistence).
Use frozen Pydantic models for config/identity; use separate mutable-via-copy models (usingmodel_copy(update=...)) for runtime state that evolves (e.g. agent execution state, task progress). Never mix static config fields with mutable runtime fields in one model.
Use Pydantic v2 (BaseModel,model_validator,computed_field,ConfigDict). Use@computed_fieldfor derived values instead of storing + validating redundant fields.
UseNotBlankStr(fromcore.types) for all id...
Files:
src/synthorg/api/middleware.pytests/unit/api/test_middleware.py
src/synthorg/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Do not use vendor-specific names (Anthropic, OpenAI, Claude, GPT, etc.) in project-owned code, docstrings, comments, tests, or config examples. Use generic names:
example-provider,example-large-001,example-medium-001,example-small-001,large/medium/smallas aliases.
Files:
src/synthorg/api/middleware.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
tests/**/*.py: Use vendor-agnostic test names:test-provider,test-small-001, etc. Never use real vendor names (Anthropic, OpenAI, Claude, GPT, etc.) in tests.
Mark tests with@pytest.mark.unit,@pytest.mark.integration,@pytest.mark.e2e, or@pytest.mark.slow.
Maintain 80% minimum code coverage (enforced in CI). Usepytest-xdistwith-n auto— always include-n autowhen running pytest, never run tests sequentially.
Set test timeout to 30 seconds per test. Useasyncio_mode = 'auto'in pytest config — no manual@pytest.mark.asyncioneeded.
Prefer@pytest.mark.parametrizefor testing similar cases.
Use Hypothesis for property-based testing with@given+@settings. Profiles:ci(50 examples, default) anddev(1000 examples), controlled viaHYPOTHESIS_PROFILEenv var. Never skip, dismiss, or ignore flaky tests — always fix them fully and fundamentally. For timing-sensitive tests, mocktime.monotonic()andasyncio.sleep()to make them deterministic.
Files:
tests/unit/api/test_middleware.py
🧠 Learnings (11)
📚 Learning: 2026-03-19T09:01:47.243Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T09:01:47.243Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Applied to files:
docs/security.md
📚 Learning: 2026-03-19T09:01:47.243Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T09:01:47.243Z
Learning: Docker workflow (`.github/workflows/docker.yml`) builds backend + web + sandbox images, pushes to GHCR, signs with cosign, performs Trivy/Grype scans (CRITICAL = hard fail, HIGH = warn-only), and generates SLSA L3 provenance attestations. Images only pushed after scans pass.
Applied to files:
docs/security.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Applied to files:
docs/security.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Pre-commit hooks: trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint (Dockerfile linting).
Applied to files:
docs/security.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.
Applied to files:
docs/security.md
📚 Learning: 2026-03-19T09:01:47.243Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T09:01:47.243Z
Learning: PR Preview workflow (`.github/workflows/pages-preview.yml`) builds site on PRs and workflow_dispatch. Injects 'Development Preview' banner and deploys to Cloudflare Pages. Each PR gets unique preview URL at `pr-<number>.synthorg-pr-preview.pages.dev`. Cleanup job deletes preview on PR close.
Applied to files:
docs/security.md
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Pre-push hooks: mypy type-check + pytest unit tests + golangci-lint + go vet + go test (CLI, conditional on cli/**/*.go) (fast gate before push, skipped in pre-commit.ci — dedicated CI jobs already run these).
Applied to files:
docs/security.md
📚 Learning: 2026-03-19T09:01:47.243Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T09:01:47.243Z
Learning: Pages workflow (`.github/workflows/pages.yml`) exports OpenAPI schema via `scripts/export_openapi.py`, builds Astro landing + Zensical docs, copies CLI install scripts to `/get/`, merges, and deploys to GitHub Pages on push to main.
Applied to files:
docs/security.md
📚 Learning: 2026-03-19T09:01:47.243Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T09:01:47.243Z
Learning: Applies to .pre-commit-config.yaml : Configure hooks: trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint. Pre-push hooks: mypy + pytest unit + golangci-lint + go vet + go test (conditional on cli changes).
Applied to files:
docs/security.md
📚 Learning: 2026-03-19T09:01:47.243Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T09:01:47.243Z
Learning: Applies to **/*.py : Use event name constants from domain-specific modules under `synthorg.observability.events` (e.g., `API_REQUEST_STARTED` from `events.api`, `TOOL_INVOKE_START` from `events.tool`). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/api/middleware.py
📚 Learning: 2026-03-15T11:48:14.867Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to src/synthorg/**/*.py : Event names: always use constants from domain-specific modules under synthorg.observability.events (e.g., PROVIDER_CALL_START from events.provider, BUDGET_RECORD_ADDED from events.budget, etc.). Import directly: `from synthorg.observability.events.<domain> import EVENT_CONSTANT`.
Applied to files:
src/synthorg/api/middleware.py
🪛 LanguageTool
docs/security.md
[uncategorized] ~211-~211: The official name of this software platform is spelled with a capital “H”.
Context: ...he ZAP API scan runs with a rules file (.github/zap-rules.tsv) that suppresses validat...
(GITHUB)
🔇 Additional comments (11)
docs/security.md (3)
90-91: Path-aware header documentation is clear and aligned with the security behavior.Good update: the API/docs split for
Cross-Origin-Opener-PolicyandCache-Controlis explicit and easy to audit.
203-203: DAST schedule wording is precise and actionable.This cadence statement is clear for operators and reviewers.
209-225: DAST tuning documentation is well-structured and review-friendly.The rule table plus rationale makes suppressions auditable, and keeping
Non-Storable ContentatWarnpreserves useful scan signal.src/synthorg/api/middleware.py (5)
1-13: LGTM!Module docstring accurately documents the new Cache-Control path-awareness.
30-34: LGTM!Event constant imported correctly from the domain-specific module per coding guidelines.
66-88: LGTM!Well-designed constants with clear documentation. Wiring
_API_CACHE_CONTROLinto_SECURITY_HEADERSprevents silent divergence between the default and the named constant.
124-137: LGTM!Path-aware header logic is correctly implemented. The boundary conditions properly distinguish
/docsand/docs/*from similar-looking paths like/documentsand/docsearch.
206-211: LGTM!Event constant usage aligns with coding guidelines for observability events. Based on learnings: "Use event name constants from domain-specific modules under
synthorg.observability.events".tests/unit/api/test_middleware.py (3)
12-20: LGTM!Importing the private constants for testing ensures tests remain in sync with implementation and makes assertions more resilient to value changes.
140-184: LGTM!Excellent parametrized test coverage with explicit boundary condition tests for
/documentsand/docsearch. COOP assertions correctly verify the updatedsame-origin-allow-popupsfor docs paths.
190-225: LGTM!Well-structured parametrized tests with descriptive IDs. Coverage mirrors CSP tests, ensuring consistent boundary condition verification.
Rename test_docs_cache_does_not_suppress_coop_relaxation to test_docs_path_applies_cache_and_coop_relaxations -- clearer intent, body and assertions unchanged. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🤖 I have created a release *beep* *boop* --- ## [0.3.7](v0.3.6...v0.3.7) (2026-03-19) ### Features * **engine:** implement Hybrid Plan + ReAct execution loop ([#582](#582)) ([008147c](008147c)) * implement first-run setup wizard ([#584](#584)) ([dfed931](dfed931)) ### Bug Fixes * **api:** address ZAP DAST scan findings ([#579](#579)) ([ce9a3e0](ce9a3e0)) * **cli:** regenerate compose and re-exec binary on update ([#576](#576)) ([3f226eb](3f226eb)) ### CI/CD * add SBOM generation to Docker and CLI releases ([#580](#580)) ([db459cf](db459cf)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
🤖 I have created a release *beep* *boop* --- ## [0.3.7](v0.3.6...v0.3.7) (2026-03-19) ### Features * **engine:** implement Hybrid Plan + ReAct execution loop ([#582](#582)) ([008147c](008147c)) * implement first-run setup wizard ([#584](#584)) ([dfed931](dfed931)) ### Bug Fixes * **api:** address ZAP DAST scan findings ([#579](#579)) ([ce9a3e0](ce9a3e0)) * **cli:** auto-delete binary on Windows, prune images, fix GoReleaser ([#590](#590)) ([eb7c691](eb7c691)) * **cli:** regenerate compose and re-exec binary on update ([#576](#576)) ([3f226eb](3f226eb)) ### CI/CD * add SBOM generation to Docker and CLI releases ([#580](#580)) ([db459cf](db459cf)) ### Maintenance * **main:** release 0.3.7 ([#583](#583)) ([bf58779](bf58779)) * reset failed v0.3.7 release ([#591](#591)) ([b69000d](b69000d)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added engine Hybrid Plan + ReAct execution loop * Added first-run setup wizard * **Bug Fixes** * Addressed ZAP DAST scan issues * Fixed CLI Windows/image/update issues * **Maintenance** * Added SBOM generation for Docker/CLI releases * General maintenance updates <!-- end of auto-generated comment: release notes by coderabbit.ai -->
🤖 I have created a release *beep* *boop* --- ## [0.3.7](v0.3.6...v0.3.7) (2026-03-19) ### Features * **engine:** implement Hybrid Plan + ReAct execution loop ([#582](#582)) ([008147c](008147c)) * implement first-run setup wizard ([#584](#584)) ([dfed931](dfed931)) ### Bug Fixes * **api:** address ZAP DAST scan findings ([#579](#579)) ([ce9a3e0](ce9a3e0)) * **ci:** reset failed v0.3.7 release and fix syft SBOM scan ([#593](#593)) ([d1508c2](d1508c2)) * **cli:** auto-delete binary on Windows, prune images, fix GoReleaser ([#590](#590)) ([eb7c691](eb7c691)) * **cli:** regenerate compose and re-exec binary on update ([#576](#576)) ([3f226eb](3f226eb)) ### CI/CD * add SBOM generation to Docker and CLI releases ([#580](#580)) ([db459cf](db459cf)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
🤖 I have created a release *beep* *boop* --- ## [0.3.7](v0.3.6...v0.3.7) (2026-03-19) ### Features * **engine:** implement Hybrid Plan + ReAct execution loop ([#582](#582)) ([008147c](008147c)) * implement first-run setup wizard ([#584](#584)) ([dfed931](dfed931)) ### Bug Fixes * **api:** address ZAP DAST scan findings ([#579](#579)) ([ce9a3e0](ce9a3e0)) * **ci:** remove CLI SBOM generation, reset failed v0.3.7 ([#595](#595)) ([d0f4992](d0f4992)) * **ci:** reset failed v0.3.7 release and fix syft SBOM scan ([#593](#593)) ([d1508c2](d1508c2)) * **cli:** auto-delete binary on Windows, prune images, fix GoReleaser ([#590](#590)) ([eb7c691](eb7c691)) * **cli:** regenerate compose and re-exec binary on update ([#576](#576)) ([3f226eb](3f226eb)) ### CI/CD * add SBOM generation to Docker and CLI releases ([#580](#580)) ([db459cf](db459cf)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
Summary
.github/zap-rules.tsv) suppressing 4 validated false positives (unexpected content-type on/docsHTML, client error responses from literal path params, base64 patterns in public OpenAPI schema, Sec-Fetch-* headers with JWT auth) and keeping Non-Storable Content as WARNCache-Controlpath-aware in security headers middleware:/docs/*getspublic, max-age=300(public, unauthenticated content), API endpoints keepno-store_API_CACHE_CONTROLconstant into_SECURITY_HEADERSdict to prevent silent divergence"asgi_missing_status"to useAPI_ASGI_MISSING_STATUSconstantdocs/security.mdwith DAST Tuning section, updateCLAUDE.mdCI descriptionTest plan
TestCacheControlPathSelectionclass (7 parametrized + 1 cross-header assertion)/documents,/docsearchgetno-store;/docs,/docs/api,/docs/openapi.jsonget cached)/docspaths)cat -Afor tab charactersReview coverage
Pre-reviewed by 11 agents (docs-consistency, code-reviewer, python-reviewer, pr-test-analyzer, conventions-enforcer, logging-audit, resilience-audit, security-reviewer, infra-reviewer, test-quality-reviewer, issue-resolution-verifier). 5 findings addressed.
Closes #441
🤖 Generated with Claude Code