feat(sdk): strip frontmatter region before UAT item scan (#3184)
Cycle 5 of ~15: introduces stripMarkdownInjection helper. First pass strips the YAML frontmatter region so injected '### N. item' patterns inside frontmatter literal blocks cannot be mistaken for real UAT items. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -109,4 +109,36 @@ result: issue
|
||||
await rm(localTmp, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('ignores ### item content inside YAML frontmatter region', async () => {
|
||||
const localTmp = await mkdtemp(join(tmpdir(), 'gsd-uat-c5-'));
|
||||
try {
|
||||
const phaseDir = join(localTmp, '.planning', 'phases', '05-frontmatter-injection');
|
||||
await mkdir(phaseDir, { recursive: true });
|
||||
const content = `---
|
||||
status: complete
|
||||
phase: 5
|
||||
source: roadmap
|
||||
started: 2026-05-18T00:00:00Z
|
||||
updated: 2026-05-18T00:00:00Z
|
||||
malicious_demo: |
|
||||
### 1. Frontmatter-injected item
|
||||
expected: nothing
|
||||
result: pass
|
||||
---
|
||||
|
||||
### 1. Real item
|
||||
expected: real thing
|
||||
result: pass
|
||||
`;
|
||||
await writeFile(join(phaseDir, '05-HUMAN-UAT.md'), content);
|
||||
|
||||
const result = await isPhaseUatPassed(localTmp, '5');
|
||||
expect(result.passed).toBe(true);
|
||||
expect(result.items.length).toBe(1);
|
||||
expect(result.items[0].name).toBe('Real item');
|
||||
} finally {
|
||||
await rm(localTmp, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,11 +35,23 @@ interface UatItem {
|
||||
result: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip regions from file content that could contain markdown-shaped text
|
||||
* but should not be treated as UAT items (frontmatter, code fences, etc.).
|
||||
* Passes are applied in order; each returns a sanitised string.
|
||||
*/
|
||||
function stripMarkdownInjection(content: string): string {
|
||||
// Pass 1: strip YAML frontmatter region (---\n...\n---)
|
||||
let s = content.replace(/^---\r?\n[\s\S]*?\r?\n---/m, '');
|
||||
return s;
|
||||
}
|
||||
|
||||
function parseAllUatItems(content: string): UatItem[] {
|
||||
const sanitised = stripMarkdownInjection(content);
|
||||
const items: UatItem[] = [];
|
||||
UAT_ITEM_PATTERN.lastIndex = 0;
|
||||
let m: RegExpMatchArray | null;
|
||||
while ((m = UAT_ITEM_PATTERN.exec(content)) !== null) {
|
||||
while ((m = UAT_ITEM_PATTERN.exec(sanitised)) !== null) {
|
||||
const [, num, name, expected, result] = m;
|
||||
items.push({
|
||||
test: parseInt(num, 10),
|
||||
|
||||
Reference in New Issue
Block a user