feat(review): add a security-focused review profile toggle - #2675
Merged
Conversation
review.profile's chill/balanced/assertive only tune how many findings surface, never what kind the reviewer prioritizes. Add an orthogonal review.security_focus boolean (mirroring the review.inline_comments toggle pattern) that appends an explicit system-prompt instruction to hunt injection, authn/authz bypass, secret handling, unsafe deserialization, SSRF, and path-traversal patterns with elevated scrutiny. It composes with (never replaces) the profile suffix and is threaded through the AI-review cache fingerprint so a toggle flip forces a fresh review. Off/unset by default, so existing repos see a byte-identical reviewer prompt. Closes #2566
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2675 +/- ##
=======================================
Coverage 96.10% 96.10%
=======================================
Files 237 237
Lines 26538 26542 +4
Branches 9624 9626 +2
=======================================
+ Hits 25505 25509 +4
Misses 424 424
Partials 609 609
🚀 New features to boost your workflow:
|
6 tasks
JSONbored
added a commit
that referenced
this pull request
Jul 3, 2026
…boot (#2686) * fix(review): add the missing securityFocus field to 5 AI-review-cache test fixtures #2675 (feat(review): add a security-focused review profile toggle) added securityFocus as a required AiReviewCacheInput field after these fixtures (from #2667) were written, breaking npm run typecheck on main for anyone branching fresh off it. * fix(selfhost): reject known-placeholder and weak critical secrets at boot .env.selfhost.example shipped ENABLED (not commented-out) placeholder values for GITHUB_WEBHOOK_SECRET, GITTENSORY_API_TOKEN, GITTENSORY_MCP_TOKEN, INTERNAL_JOB_TOKEN, and SELFHOST_SETUP_TOKEN. An operator who copies the starter to .env per the quickstart docs and misses "fill in the placeholders" runs an instance with a PUBLICLY KNOWN webhook HMAC secret (forgeable signatures) and PUBLICLY KNOWN static bearer tokens -- GITTENSORY_API_TOKEN authenticates as the server-to-server actor and bypasses per-repo write checks, INTERNAL_JOB_TOKEN gates internal routes -- silently, with no error at boot or runtime. - The boot-time preflight check (already gates server.ts's main(), throwing before the process starts serving) now rejects any of the five critical secrets that is set to the exact known-placeholder string, or that is merely too short to be a real generated secret, or that duplicates another critical secret's value. Presence is still each secret's own concern (most are feature-gating, not universally required) -- this only judges STRENGTH whenever one is actually set, so it can never be silently bypassed by leaving the file's placeholder in place. - .env.selfhost.example now ships these five lines commented out, with explicit per-secret generation guidance, instead of enabled placeholders. - The quickstart doc callout it directed users through now explicitly warns about generating distinct random values for each secret. Defense in depth: the docs + example file guide an operator toward doing the right thing, and the preflight check makes doing the wrong thing impossible rather than merely discouraged.
JSONbored
added a commit
that referenced
this pull request
Jul 3, 2026
countOpenItemsForAuthorAcrossRepos (merged via #2678, closing #2562) counted an author's open PRs/issues across the ENTIRE D1 database with no installation scoping at all -- on a database shared by multiple installations (the hosted product's normal shape, and possible on self-host too), a contributor's activity on one installation could wrongly trigger GLOBAL_CONTRIBUTOR_OPEN_ITEM_CAP closes on a completely unrelated installation that never gated them. Scope the query through repositories.installationId first (matching the existing markRepositoriesRemovedFromInstallation precedent), then inArray(...) against the resulting repoFullNames -- this codebase has no Drizzle joins to lean on instead. Also fixes 5 AiReviewCacheInput test fixtures in queue.test.ts left broken by an unrelated already-merged PR (#2675, security-focused review profile) that added a required securityFocus field without updating these fixtures -- main's typecheck was red without this, which this PR's own CI would otherwise have inherited.
JSONbored
added a commit
that referenced
this pull request
Jul 3, 2026
…ion (#2687) * fix(agent-actions): scope the global open-item cap query by installation countOpenItemsForAuthorAcrossRepos (merged via #2678, closing #2562) counted an author's open PRs/issues across the ENTIRE D1 database with no installation scoping at all -- on a database shared by multiple installations (the hosted product's normal shape, and possible on self-host too), a contributor's activity on one installation could wrongly trigger GLOBAL_CONTRIBUTOR_OPEN_ITEM_CAP closes on a completely unrelated installation that never gated them. Scope the query through repositories.installationId first (matching the existing markRepositoriesRemovedFromInstallation precedent), then inArray(...) against the resulting repoFullNames -- this codebase has no Drizzle joins to lean on instead. Also fixes 5 AiReviewCacheInput test fixtures in queue.test.ts left broken by an unrelated already-merged PR (#2675, security-focused review profile) that added a required securityFocus field without updating these fixtures -- main's typecheck was red without this, which this PR's own CI would otherwise have inherited. * fix(agent-actions): audit a truncated installation repo list, don't drop it silently listRepoFullNamesForInstallation's .limit(20_000) meant an installation with more tracked repos than that would silently undercount toward GLOBAL_CONTRIBUTOR_OPEN_ITEM_CAP with no signal anything was dropped. Records an audit event on the rare install where the limit is still hit, mirroring the same observability pattern already used for the per-author item-count truncation in this file. Addresses a gate review finding on #2687.
This was referenced Jul 3, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
review.profile(src/signals/focus-manifest.ts) only ever tuned HOW MANY findings the AI reviewer surfaces (chill suppresses nits, assertive raises them) — there was no way to tell the reviewer WHAT KIND of defect to prioritize. Adds a new, orthogonalreview.security_focus: booleantoggle (mirroring the existingreview.inline_commentsboolean pattern rather than extending thechill/balanced/assertiveunion, since this is a "what to hunt for" axis, not a fourth volume level).review.security_focusinparseReviewConfig, adds it toFocusManifestReviewConfig,reviewConfigToJson(cache round-trip), andresolveReviewPromptOverrides— the same manifest-only sitesreview.profileandreview.inline_commentsalready flow through (no DB column / OpenAPI field needed, confirmed vianpm run ui:openapi:settings-parity—review.profileitself isn't inRepositorySettingsSchemaeither, it's a.gittensory.yml-only field).src/services/ai-review.ts: a newSECURITY_FOCUS_SUFFIXconstant appended inbuildSystemPromptright after the existingREVIEW_PROFILE_SUFFIX, naming injection, authn/authz bypass, secret handling, unsafe deserialization, SSRF, and path traversal as elevated-scrutiny categories. It composes with (never replaces) the profile suffix.securityFocusthroughsrc/queue/processors.ts(resolveReviewPromptOverridesdestructure →runAiReviewForAdvisoryargs →runGittensoryAiReviewcall) and adds it tosrc/review/ai-review-cache-input.ts's fingerprint payload so flipping the toggle invalidates the AI-review cache instead of replaying a stale review.Scope
type(scope): short summaryConventional Commit format, for examplefix(api): restore profile access checks.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
git diff --checknpm run actionlint(vianpm run test:ci)npm run typechecknpm run test:coveragelocally;codecov/patchrequires ≥99% coverage of the lines AND branches you changed (aim for 100% on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate.npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderateAll run via the full local gate:
npm run test:ci(actionlint, migrations check, cf-typegen check, typecheck, unshardedtest:coverage,test:workers,build:mcp,test:mcp-pack,build:miner,rees:test,ui:openapi:check,ui:openapi:settings-parity,ui:version-audit,ui:lint,ui:typecheck,ui:test,ui:build) — all green, 6740+ tests passing — plusnpm audit --audit-level=moderatereporting 0 vulnerabilities. Added/updated tests:test/unit/focus-manifest.test.ts(parsing, round-trip,resolveReviewPromptOverridescomposition),test/unit/ai-review.test.ts(system-prompt composition with and withoutprofile),test/unit/ai-review-cache-input.test.ts(fingerprint changes when the toggle flips, independent ofprofile), plus fixture updates intest/unit/ai-review-cache.test.ts,test/unit/queue.test.ts, andtest/unit/signals-coverage.test.tsfor the new required field.Safety
UI Evidencesection below with JPG/JPEG or PNG screenshots arranged as organized, captioned, clickable thumbnails. SVG screenshots are not used as review evidence. Review-only screenshots or recordings are not committed to the repository.No auth/cookie/CORS/session/UI/docs changes in this PR — it's a backend prompt-composition + manifest-parsing change only, so those boxes don't apply.
UI Evidence
Not applicable — no UI/frontend/docs changes in this PR.
Notes
review.security_focusfield out ofRepositorySettingsSchema/OpenAPI intentionally:review.profile,review.inline_comments, andreview.path_instructionsare all manifest-only (.gittensory.yml-only) fields with no DB column, confirmed unaffected bynpm run ui:openapi:settings-parity(still reports the same 62 fields) —security_focusfollows that exact precedent rather than the full DB+OpenAPI config-as-code checklist, which applies toRepositorySettings-backed fields.Closes #2566