fix autofix body leak, harden prompt against injection, trigger-aware comments (#512)
* fix autofix body leak, harden prompt against injection, trigger-aware comments never forward event bodies to the agent prompt — they are user-generated content and a prompt injection vector. the agent fetches bodies on demand via MCP tools (checkout_pr, get_issue, etc.). - always set event.body to null in dispatch(), add promptFromBody: false to autofix, strip body from nested pull_request object - replace buildEventTitleBody with buildEventTitle rendering inline references like PR #497 ("Title") instead of raw markdown headings - add LEAPING_REASON_MAP for trigger-aware progress comments (e.g. "CI failure detected. Leaping into action...") - thread type through buildLeapingIntoActionComment, createLeapingComment, and updateCommentToLeaping Made-with: Cursor * rename translateWorkflowRunType.ts to workflowRunTypes.ts Made-with: Cursor
This commit is contained in:
committed by
pullfrog[bot]
parent
d525fc21be
commit
37f984f4f8
@@ -150317,17 +150317,11 @@ function buildRuntimeContext(ctx) {
|
|||||||
const filtered = Object.fromEntries(Object.entries(data).filter(([_2, v]) => v !== void 0));
|
const filtered = Object.fromEntries(Object.entries(data).filter(([_2, v]) => v !== void 0));
|
||||||
return encode(filtered);
|
return encode(filtered);
|
||||||
}
|
}
|
||||||
function buildEventTitleBody(event) {
|
function buildEventTitle(event) {
|
||||||
const sections = [];
|
|
||||||
const trimmedTitle = typeof event.title === "string" ? event.title.trim() : "";
|
const trimmedTitle = typeof event.title === "string" ? event.title.trim() : "";
|
||||||
const trimmedBody = typeof event.body === "string" ? event.body.trim() : "";
|
if (!trimmedTitle) return "";
|
||||||
if (trimmedTitle) {
|
const prefix = event.issue_number ? `${event.is_pr ? "PR" : "Issue"} #${event.issue_number}` : "";
|
||||||
sections.push(`# ${trimmedTitle}`);
|
return prefix ? `${prefix} ("${trimmedTitle}")` : `("${trimmedTitle}")`;
|
||||||
}
|
|
||||||
if (trimmedBody) {
|
|
||||||
sections.push(trimmedBody);
|
|
||||||
}
|
|
||||||
return sections.join("\n\n");
|
|
||||||
}
|
}
|
||||||
function buildEventMetadata(event) {
|
function buildEventMetadata(event) {
|
||||||
const { title: _t, body: _b, trigger, ...rest } = event;
|
const { title: _t, body: _b, trigger, ...rest } = event;
|
||||||
@@ -150485,9 +150479,9 @@ function buildContextSections(ctx) {
|
|||||||
const eventInstructionsSection = ctx.eventInstructions ? `************* EVENT-LEVEL INSTRUCTIONS *************
|
const eventInstructionsSection = ctx.eventInstructions ? `************* EVENT-LEVEL INSTRUCTIONS *************
|
||||||
|
|
||||||
${ctx.eventInstructions}` : "";
|
${ctx.eventInstructions}` : "";
|
||||||
const titleBodySection = ctx.eventTitleBody ? `${relatedLabel}
|
const titleBodySection = ctx.eventTitle ? `${relatedLabel}
|
||||||
|
|
||||||
${ctx.eventTitleBody}` : "";
|
${ctx.eventTitle}` : "";
|
||||||
const metadataSection = ctx.eventMetadata ? `--- event context ---
|
const metadataSection = ctx.eventMetadata ? `--- event context ---
|
||||||
|
|
||||||
${ctx.eventMetadata}` : "";
|
${ctx.eventMetadata}` : "";
|
||||||
@@ -150505,15 +150499,15 @@ ${metadataSection}`;
|
|||||||
return [eventInstructionsSection, userSection].filter(Boolean).join("\n\n");
|
return [eventInstructionsSection, userSection].filter(Boolean).join("\n\n");
|
||||||
}
|
}
|
||||||
function buildCommonInputs(ctx) {
|
function buildCommonInputs(ctx) {
|
||||||
const eventTitleBody = buildEventTitleBody(ctx.payload.event);
|
const eventTitle = buildEventTitle(ctx.payload.event);
|
||||||
const eventMetadata = buildEventMetadata(ctx.payload.event);
|
const eventMetadata = buildEventMetadata(ctx.payload.event);
|
||||||
const runtime = buildRuntimeContext(ctx);
|
const runtime = buildRuntimeContext(ctx);
|
||||||
const user = ctx.payload.prompt;
|
const user = ctx.payload.prompt;
|
||||||
const eventInstructions = ctx.payload.eventInstructions ?? "";
|
const eventInstructions = ctx.payload.eventInstructions ?? "";
|
||||||
const event = [eventTitleBody, eventMetadata].filter(Boolean).join("\n\n---\n\n");
|
const event = [eventTitle, eventMetadata].filter(Boolean).join("\n\n---\n\n");
|
||||||
const userQuoted = user ? user.split("\n").map((line) => `> ${line}`).join("\n") : "";
|
const userQuoted = user ? user.split("\n").map((line) => `> ${line}`).join("\n") : "";
|
||||||
return {
|
return {
|
||||||
eventTitleBody,
|
eventTitle,
|
||||||
eventMetadata,
|
eventMetadata,
|
||||||
runtime,
|
runtime,
|
||||||
user,
|
user,
|
||||||
@@ -150567,7 +150561,7 @@ If the task clearly requires no work, call \`${ghPullfrogMcpName}/report_progres
|
|||||||
const contextSections = buildContextSections({
|
const contextSections = buildContextSections({
|
||||||
payload: ctx.payload,
|
payload: ctx.payload,
|
||||||
eventInstructions: inputs.eventInstructions,
|
eventInstructions: inputs.eventInstructions,
|
||||||
eventTitleBody: inputs.eventTitleBody,
|
eventTitle: inputs.eventTitle,
|
||||||
eventMetadata: inputs.eventMetadata,
|
eventMetadata: inputs.eventMetadata,
|
||||||
userQuoted: inputs.userQuoted
|
userQuoted: inputs.userQuoted
|
||||||
});
|
});
|
||||||
|
|||||||
+11
-20
@@ -53,22 +53,13 @@ function buildRuntimeContext(ctx: InstructionsContext): string {
|
|||||||
return toonEncode(filtered);
|
return toonEncode(filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildEventTitleBody(event: PayloadEvent): string {
|
function buildEventTitle(event: PayloadEvent): string {
|
||||||
const sections: string[] = [];
|
|
||||||
|
|
||||||
// render title + body as markdown
|
|
||||||
const trimmedTitle = typeof event.title === "string" ? event.title.trim() : "";
|
const trimmedTitle = typeof event.title === "string" ? event.title.trim() : "";
|
||||||
const trimmedBody = typeof event.body === "string" ? event.body.trim() : "";
|
if (!trimmedTitle) return "";
|
||||||
|
|
||||||
if (trimmedTitle) {
|
const prefix = event.issue_number ? `${event.is_pr ? "PR" : "Issue"} #${event.issue_number}` : "";
|
||||||
sections.push(`# ${trimmedTitle}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trimmedBody) {
|
return prefix ? `${prefix} ("${trimmedTitle}")` : `("${trimmedTitle}")`;
|
||||||
sections.push(trimmedBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sections.join("\n\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildEventMetadata(event: PayloadEvent): string {
|
function buildEventMetadata(event: PayloadEvent): string {
|
||||||
@@ -261,7 +252,7 @@ export interface ResolvedInstructions {
|
|||||||
interface ContextSectionsInput {
|
interface ContextSectionsInput {
|
||||||
payload: ResolvedPayload;
|
payload: ResolvedPayload;
|
||||||
eventInstructions: string;
|
eventInstructions: string;
|
||||||
eventTitleBody: string;
|
eventTitle: string;
|
||||||
eventMetadata: string;
|
eventMetadata: string;
|
||||||
userQuoted: string;
|
userQuoted: string;
|
||||||
}
|
}
|
||||||
@@ -276,7 +267,7 @@ function buildContextSections(ctx: ContextSectionsInput): string {
|
|||||||
${ctx.eventInstructions}`
|
${ctx.eventInstructions}`
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const titleBodySection = ctx.eventTitleBody ? `${relatedLabel}\n\n${ctx.eventTitleBody}` : "";
|
const titleBodySection = ctx.eventTitle ? `${relatedLabel}\n\n${ctx.eventTitle}` : "";
|
||||||
const metadataSection = ctx.eventMetadata ? `--- event context ---\n\n${ctx.eventMetadata}` : "";
|
const metadataSection = ctx.eventMetadata ? `--- event context ---\n\n${ctx.eventMetadata}` : "";
|
||||||
|
|
||||||
const userSection = ctx.userQuoted
|
const userSection = ctx.userQuoted
|
||||||
@@ -298,7 +289,7 @@ ${metadataSection}`;
|
|||||||
|
|
||||||
// shared computation for all instruction builders
|
// shared computation for all instruction builders
|
||||||
interface CommonInputs {
|
interface CommonInputs {
|
||||||
eventTitleBody: string;
|
eventTitle: string;
|
||||||
eventMetadata: string;
|
eventMetadata: string;
|
||||||
runtime: string;
|
runtime: string;
|
||||||
user: string;
|
user: string;
|
||||||
@@ -308,12 +299,12 @@ interface CommonInputs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildCommonInputs(ctx: InstructionsContext): CommonInputs {
|
function buildCommonInputs(ctx: InstructionsContext): CommonInputs {
|
||||||
const eventTitleBody = buildEventTitleBody(ctx.payload.event);
|
const eventTitle = buildEventTitle(ctx.payload.event);
|
||||||
const eventMetadata = buildEventMetadata(ctx.payload.event);
|
const eventMetadata = buildEventMetadata(ctx.payload.event);
|
||||||
const runtime = buildRuntimeContext(ctx);
|
const runtime = buildRuntimeContext(ctx);
|
||||||
const user = ctx.payload.prompt;
|
const user = ctx.payload.prompt;
|
||||||
const eventInstructions = ctx.payload.eventInstructions ?? "";
|
const eventInstructions = ctx.payload.eventInstructions ?? "";
|
||||||
const event = [eventTitleBody, eventMetadata].filter(Boolean).join("\n\n---\n\n");
|
const event = [eventTitle, eventMetadata].filter(Boolean).join("\n\n---\n\n");
|
||||||
const userQuoted = user
|
const userQuoted = user
|
||||||
? user
|
? user
|
||||||
.split("\n")
|
.split("\n")
|
||||||
@@ -321,7 +312,7 @@ function buildCommonInputs(ctx: InstructionsContext): CommonInputs {
|
|||||||
.join("\n")
|
.join("\n")
|
||||||
: "";
|
: "";
|
||||||
return {
|
return {
|
||||||
eventTitleBody,
|
eventTitle,
|
||||||
eventMetadata,
|
eventMetadata,
|
||||||
runtime,
|
runtime,
|
||||||
user,
|
user,
|
||||||
@@ -388,7 +379,7 @@ If the task clearly requires no work, call \`${ghPullfrogMcpName}/report_progres
|
|||||||
const contextSections = buildContextSections({
|
const contextSections = buildContextSections({
|
||||||
payload: ctx.payload,
|
payload: ctx.payload,
|
||||||
eventInstructions: inputs.eventInstructions,
|
eventInstructions: inputs.eventInstructions,
|
||||||
eventTitleBody: inputs.eventTitleBody,
|
eventTitle: inputs.eventTitle,
|
||||||
eventMetadata: inputs.eventMetadata,
|
eventMetadata: inputs.eventMetadata,
|
||||||
userQuoted: inputs.userQuoted,
|
userQuoted: inputs.userQuoted,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user