Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions src/queue/processors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ import {
} from "../signals/focus-manifest";
import { decideReviewEligibility } from "../review/review-eligibility";
import {
loadPublicRepoFocusManifest,
loadRepoFocusManifest,
loadRepoFocusManifests,
loadRepoReviewContext,
Expand Down Expand Up @@ -9542,9 +9543,12 @@ async function maybePublishPrPublicSurface(
}

if (decision.willComment) {
// Maintainer review-content overrides from `.gittensory.yml` (footer text, row toggles, intro note).
// Cached, so this is a DB read after the settings resolution already loaded the manifest.
const repoFocusManifestForComment = await loadRepoFocusManifest(env, repoFullName);
// Maintainer review-content overrides may come from private self-host config, but validation warnings
// rendered in the public PR comment must come only from the repo-published manifest.
const [repoFocusManifestForComment, publicRepoFocusManifestForComment] = await Promise.all([
loadRepoFocusManifest(env, repoFullName),
loadPublicRepoFocusManifest(env, repoFullName).catch(() => null),
]);
const reviewConfig = repoFocusManifestForComment.review;
// Duplicate-winner adjudication (#dup-winner): thread the flag into the public panel builders so the
// winner's hard-duplicate block is suppressed (they recompute the winner from their own open-only sibling
Expand Down Expand Up @@ -9856,10 +9860,10 @@ async function maybePublishPrPublicSurface(
: {}),
maxFindingsCaps: reviewConfig.maxFindings,
commentVerbosity: reviewConfig.commentVerbosity,
// review-manifest validation (#2056): reuse the same manifest already loaded above for reviewConfig —
// unconditional (no manifest opt-in needed, a broken config should always fail clearly); no warnings
// ⇒ the bridge omits the section (byte-identical).
manifestWarnings: repoFocusManifestForComment.warnings,
// review-manifest validation (#2056): public PR comments may disclose only repo-published manifest
// warnings. Self-host private config can carry operator-only policy and raw invalid values, so never
// render warnings from the full/private manifest here.
manifestWarnings: publicRepoFocusManifestForComment?.warnings ?? [],
});
} else {
deterministicBody = buildPublicPrIntelligenceComment(commentArgs);
Expand Down
33 changes: 32 additions & 1 deletion test/unit/manifest-validation-collapsible.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { describe, expect, it } from "vitest";
import { afterEach, describe, expect, it } from "vitest";
import { buildManifestValidationCollapsible, buildUnifiedCommentBody } from "../../src/review/unified-comment-bridge";
import { loadPublicRepoFocusManifest, setLocalManifestReader } from "../../src/signals/focus-manifest-loader";
import { createTestEnv } from "../helpers/d1";
import type { GateCheckEvaluation } from "../../src/rules/advisory";
import type { PublicPrPanelSignalRow } from "../../src/signals/engine";

Expand Down Expand Up @@ -43,6 +45,35 @@ describe("buildManifestValidationCollapsible (#2056)", () => {
});

describe("buildUnifiedCommentBody: manifest validation wiring (#2056)", () => {
afterEach(() => setLocalManifestReader(null));

it("uses only repo-published warnings for public comments, not private self-host manifest warnings", async () => {
const env = createTestEnv();
const secret = "OPERATOR_ONLY_SECRET_9f3c";
setLocalManifestReader(async () => `gate:
linkedIssue: "wallet hotkey reward scoreability ${secret}"
`);

const publicManifest = await loadPublicRepoFocusManifest(env, "owner/repo", {
fetcher: async () => `review:
profile: loud
`,
});
const body = buildUnifiedCommentBody({
gate: gate(),
panelRows,
readinessTotal: 88,
changedFiles: 1,
footerMarkdown: footer,
manifestWarnings: publicManifest.warnings,
});

expect(body).toContain("Manifest validation");
expect(body).toContain('Manifest "review.profile"');
expect(body).not.toContain(secret);
expect(body).not.toMatch(/wallet|hotkey|reward|scoreability/i);
});

it("appends a Manifest validation collapsible when manifestWarnings is non-empty", () => {
const body = buildUnifiedCommentBody({
gate: gate(),
Expand Down