mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-29 04:25:52 +01:00
Harden LLM wiki source redaction
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
771efddc98
commit
a9d8d3eb79
3 files changed
+16
-3
No files matched your search
@@ -76,6 +76,7 @@ const DEFAULT_ROUTE_SIDEBAR_EXPANDED_PATHS = [
|
||||
"wiki",
|
||||
"wiki/sources",
|
||||
"wiki/projects",
|
||||
"wiki/areas",
|
||||
"wiki/entities",
|
||||
"wiki/concepts",
|
||||
"wiki/synthesis",
|
||||
|
||||
@@ -398,7 +398,7 @@ function redactDistillationSensitiveText(input: string): string {
|
||||
|
||||
function protectDistillationSourceBody(input: {
|
||||
issue: Issue;
|
||||
sourceKind: "comment" | "document";
|
||||
sourceKind: "issue" | "comment" | "document";
|
||||
sourceId: string;
|
||||
body: string;
|
||||
}): DistillationSourceProtectionResult {
|
||||
@@ -1465,6 +1465,13 @@ export async function assemblePaperclipSourceBundle(ctx: PluginContext, input: P
|
||||
const remaining = { value: maxCharacters - lines.join("\n").length };
|
||||
|
||||
for (const issue of issues) {
|
||||
const protectedIssue = protectDistillationSourceBody({
|
||||
issue,
|
||||
sourceKind: "issue",
|
||||
sourceId: issue.id,
|
||||
body: issue.description?.trim() ? issue.description.trim() : "_No issue description._",
|
||||
});
|
||||
if (protectedIssue.warning) warnings.push(protectedIssue.warning);
|
||||
const issueBody = [
|
||||
`- Issue ID: ${issue.id}`,
|
||||
issue.identifier ? `- Identifier: ${issue.identifier}` : null,
|
||||
@@ -1474,7 +1481,7 @@ export async function assemblePaperclipSourceBundle(ctx: PluginContext, input: P
|
||||
issue.projectId ? `- Project ID: ${issue.projectId}` : null,
|
||||
`- Updated at: ${isoString(issue.updatedAt) ?? "unknown"}`,
|
||||
"",
|
||||
issue.description?.trim() ? issue.description.trim() : "_No issue description._",
|
||||
protectedIssue.body,
|
||||
].filter((line): line is string => line !== null).join("\n");
|
||||
appendBoundedSection({
|
||||
lines,
|
||||
@@ -1488,6 +1495,7 @@ export async function assemblePaperclipSourceBundle(ctx: PluginContext, input: P
|
||||
projectId: issue.projectId ?? null,
|
||||
title: issue.title,
|
||||
updatedAt: isoString(issue.updatedAt) ?? undefined,
|
||||
...protectedIssue.refPatch,
|
||||
},
|
||||
remaining,
|
||||
perSourceLimit,
|
||||
|
||||
@@ -1294,7 +1294,7 @@ Route sidebar state stays attached to the selected wiki page.
|
||||
identifier: "PAP-4002",
|
||||
title: "Sensitive source issue",
|
||||
projectId: "77777777-7777-4777-8777-777777777777",
|
||||
description: "Keep the project page current without copying credential material into the wiki.",
|
||||
description: "Keep the project page current without copying OPENAI_API_KEY=sk-supersecretissuevalue1234567890 into the wiki.",
|
||||
updatedAt: new Date("2026-05-04T10:00:00Z"),
|
||||
});
|
||||
harness.seed({
|
||||
@@ -1335,11 +1335,14 @@ Route sidebar state stays attached to the selected wiki page.
|
||||
expect(run.bundle.markdown).toContain("Suppressed by LLM Wiki distillation security policy");
|
||||
expect(run.bundle.markdown).not.toContain("ghp_supersecretcommenttoken1234567890");
|
||||
expect(run.bundle.markdown).not.toContain("sk-supersecretdocumentvalue1234567890");
|
||||
expect(run.bundle.markdown).not.toContain("sk-supersecretissuevalue1234567890");
|
||||
expect(run.bundle.warnings).toEqual(expect.arrayContaining([
|
||||
expect.stringContaining("Suppressed issue content"),
|
||||
expect.stringContaining("Suppressed comment content"),
|
||||
expect.stringContaining("Suppressed document content"),
|
||||
]));
|
||||
expect(run.bundle.sourceRefs).toEqual(expect.arrayContaining([
|
||||
expect.objectContaining({ kind: "issue", redactionStatus: "suppressed_sensitive_content" }),
|
||||
expect.objectContaining({ kind: "comment", redactionStatus: "suppressed_sensitive_content" }),
|
||||
expect.objectContaining({ kind: "document", redactionStatus: "suppressed_sensitive_content" }),
|
||||
]));
|
||||
@@ -1351,6 +1354,7 @@ Route sidebar state stays attached to the selected wiki page.
|
||||
expect(storedMarkdown).toContain("Suppressed by LLM Wiki distillation security policy");
|
||||
expect(storedMarkdown).not.toContain("ghp_supersecretcommenttoken1234567890");
|
||||
expect(storedMarkdown).not.toContain("sk-supersecretdocumentvalue1234567890");
|
||||
expect(storedMarkdown).not.toContain("sk-supersecretissuevalue1234567890");
|
||||
});
|
||||
|
||||
it("creates source snapshots and only advances cursors after successful distillation outcomes", async () => {
|
||||
|
||||
Reference in new issue
Block a user