fix: 收紧NapCat提示词加载边界
This commit is contained in:
parent
e29ce3be86
commit
d5e9bf5b01
@ -42,6 +42,7 @@ import {
|
|||||||
} from "./tools/napcatAutomation.types.js";
|
} from "./tools/napcatAutomation.types.js";
|
||||||
import {
|
import {
|
||||||
loadNapcatAutomationPrompt,
|
loadNapcatAutomationPrompt,
|
||||||
|
type NapcatAutomationPromptName,
|
||||||
napcatAutomationPromptNames,
|
napcatAutomationPromptNames,
|
||||||
} from "./tools/napcatAutomation.prompts.js";
|
} from "./tools/napcatAutomation.prompts.js";
|
||||||
import {
|
import {
|
||||||
@ -99,6 +100,17 @@ export async function runSelfTest(): Promise<void> {
|
|||||||
throw new Error(`NapCat prompt safety contract missing: ${promptName}`);
|
throw new Error(`NapCat prompt safety contract missing: ${promptName}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let traversalPromptRejected = false;
|
||||||
|
try {
|
||||||
|
loadNapcatAutomationPrompt("../../README" as NapcatAutomationPromptName);
|
||||||
|
} catch (error) {
|
||||||
|
traversalPromptRejected = String(error).includes(
|
||||||
|
"Unsupported NapCat automation prompt",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!traversalPromptRejected) {
|
||||||
|
throw new Error("NapCat prompt traversal self-check failed");
|
||||||
|
}
|
||||||
|
|
||||||
const reviewClassifier = {
|
const reviewClassifier = {
|
||||||
localizedSecretLabelAllowed: isBenignCredentialReviewValue("密钥"),
|
localizedSecretLabelAllowed: isBenignCredentialReviewValue("密钥"),
|
||||||
|
|||||||
@ -17,14 +17,48 @@ const promptsRoot = path.resolve(
|
|||||||
'prompts',
|
'prompts',
|
||||||
'napcat',
|
'napcat',
|
||||||
);
|
);
|
||||||
|
const promptsRootBoundary = promptsRoot.endsWith(path.sep)
|
||||||
|
? promptsRoot
|
||||||
|
: `${promptsRoot}${path.sep}`;
|
||||||
|
const napcatAutomationPromptNameSet = new Set<string>(
|
||||||
|
napcatAutomationPromptNames,
|
||||||
|
);
|
||||||
|
const napcatAutomationPromptFileNames = {
|
||||||
|
'upstream-audit': 'upstream-audit.md',
|
||||||
|
'sync-candidate-review': 'sync-candidate-review.md',
|
||||||
|
'runtime-release-readiness': 'runtime-release-readiness.md',
|
||||||
|
'remote-dev-handoff': 'remote-dev-handoff.md',
|
||||||
|
} satisfies Record<NapcatAutomationPromptName, string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an external prompt name into the source-controlled NapCat prompt enum.
|
||||||
|
* @param value - Raw prompt name from CLI, JSON, MCP input, or a typed caller; only exact entries in `napcatAutomationPromptNames` are accepted.
|
||||||
|
* @returns A stable prompt name that can be mapped to a fixed file under `prompts/napcat`.
|
||||||
|
*/
|
||||||
|
export function parseNapcatAutomationPromptName(
|
||||||
|
value: string,
|
||||||
|
): NapcatAutomationPromptName {
|
||||||
|
if (napcatAutomationPromptNameSet.has(value)) {
|
||||||
|
return value as NapcatAutomationPromptName;
|
||||||
|
}
|
||||||
|
throw new Error(`Unsupported NapCat automation prompt: ${value}`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a source-controlled NapCat automation prompt by stable prompt name.
|
* Loads a source-controlled NapCat automation prompt by stable prompt name.
|
||||||
* @param name - Prompt identifier from `napcatAutomationPromptNames`; because it is an enum value rather than a user-supplied path, callers cannot escape `prompts/napcat`.
|
* @param name - Prompt identifier from `napcatAutomationPromptNames`; runtime callers may still pass untyped external strings, so the loader re-validates and resolves only fixed filenames.
|
||||||
* @returns UTF-8 prompt text used by Codex CLI automation.
|
* @returns UTF-8 prompt text used by Codex CLI automation.
|
||||||
*/
|
*/
|
||||||
export function loadNapcatAutomationPrompt(
|
export function loadNapcatAutomationPrompt(
|
||||||
name: NapcatAutomationPromptName,
|
name: NapcatAutomationPromptName,
|
||||||
): string {
|
): string {
|
||||||
return readFileSync(path.join(promptsRoot, `${name}.md`), 'utf8');
|
const promptName = parseNapcatAutomationPromptName(String(name));
|
||||||
|
const promptPath = path.resolve(
|
||||||
|
promptsRoot,
|
||||||
|
napcatAutomationPromptFileNames[promptName],
|
||||||
|
);
|
||||||
|
if (!promptPath.startsWith(promptsRootBoundary)) {
|
||||||
|
throw new Error(`NapCat automation prompt escaped prompt root: ${name}`);
|
||||||
|
}
|
||||||
|
return readFileSync(promptPath, 'utf8');
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user