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
58 changes: 43 additions & 15 deletions src/review/enrichment-wire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,45 @@ const REES_PROFILE_NAMES = ["fast", "balanced", "deep"] as const;
type ReesProfileName = (typeof REES_PROFILE_NAMES)[number];
const REES_PROFILE_NAME_SET = new Set<string>(REES_PROFILE_NAMES);

function markdownHeadingLevel(line: string): number | undefined {
const match = /^(#{1,6})\s+/.exec(line.trimStart());
return match?.[1]?.length;
}

function isPublicSafeEnrichmentLine(line: string): boolean {
try {
sanitizePublicComment(line);
return true;
} catch {
return false;
}
}

function retainPublicSafeEnrichmentSections(
defanged: string,
): string | undefined {
const lines = defanged.split("\n");
const safeLines: string[] = [];
for (let index = 0; index < lines.length; index += 1) {
const line = lines[index] ?? "";
const headingLevel = markdownHeadingLevel(line);
if (isPublicSafeEnrichmentLine(line)) {
safeLines.push(line);
continue;
}
if (headingLevel === undefined) continue;

while (index + 1 < lines.length) {
const nextLevel = markdownHeadingLevel(lines[index + 1] ?? "");
if (nextLevel !== undefined && nextLevel <= headingLevel) break;
index += 1;
}
}

const safeBlock = safeLines.join("\n").trim();
return safeBlock || undefined;
}

function sanitizeEnrichmentPromptSection(value: unknown): string | undefined {
if (typeof value !== "string") return undefined;
const trimmed = value.trim();
Expand All @@ -172,21 +211,10 @@ function sanitizeEnrichmentPromptSection(value: unknown): string | undefined {
MAX_ENRICHMENT_PROMPT_SECTION_CHARS,
);
} catch {
const safeLines = defanged
.split("\n")
.filter((line) => {
try {
sanitizePublicComment(line);
return true;
} catch {
return false;
}
})
.join("\n")
.trim();
return safeLines
? safeLines.slice(0, MAX_ENRICHMENT_PROMPT_SECTION_CHARS)
: undefined;
return retainPublicSafeEnrichmentSections(defanged)?.slice(
0,
MAX_ENRICHMENT_PROMPT_SECTION_CHARS,
);
}
}

Expand Down
35 changes: 35 additions & 0 deletions test/unit/enrichment-wire.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,41 @@ describe("buildReviewEnrichment", () => {
expect(result?.systemSuffix).toContain("untrusted advisory context");
});

it("drops non-public-safe enrichment sections with adjacent unlabeled values", async () => {
globalThis.fetch = vi.fn(
async () =>
({
ok: true,
json: async () => ({
promptSection: [
"## EXTERNAL REVIEW BRIEF",
"### Dependency advisory",
"- package left-pad has CVE-2099-0001",
"### wallet",
"- adjacent unlabeled identifier",
"extra evidence without a forbidden label",
"### Safe follow-up",
"- retain public context",
].join("\n"),
}),
}) as Response,
) as unknown as typeof fetch;

const result = await buildReviewEnrichment(
env({ REES_URL: "https://r" }),
input,
);

expect(result?.promptSection).toContain("## EXTERNAL REVIEW BRIEF");
expect(result?.promptSection).toContain("### Dependency advisory");
expect(result?.promptSection).toContain("### Safe follow-up");
expect(result?.promptSection).not.toContain("### wallet");
expect(result?.promptSection).not.toContain("adjacent unlabeled identifier");
expect(result?.promptSection).not.toContain(
"extra evidence without a forbidden label",
);
});

it("undefined on a fetch throw (timeout/network) — fail-safe", async () => {
globalThis.fetch = vi.fn(async () => {
throw new Error("timeout");
Expand Down