test(timeline): add the {@html} grep gate; docs(rtm): trace #850 REQ-001..013
The grep gate fails if any lib/timeline component reaches for the raw-HTML directive (CWE-79, REQ-010). The RTM gains thirteen rows tracing every #850 requirement to its implementation file(s) and test(s), Status Done. Refs #850
This commit is contained in:
24
frontend/src/lib/timeline/timeline-no-raw-html.spec.ts
Normal file
24
frontend/src/lib/timeline/timeline-no-raw-html.spec.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { readdirSync, readFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
|
||||
const timelineDir = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
/**
|
||||
* REQ-010 / CWE-79: inline event clustering renders curator event titles and import-derived
|
||||
* letter titles + sender/receiver text through every component under lib/timeline (the reused
|
||||
* LetterCard, the new EventCluster card, the existing pills/bands/strip). That text must always
|
||||
* render through Svelte's default `{...}` escaping — never `{@html}`. This grep gate fails loudly
|
||||
* the moment any timeline component reaches for the raw-HTML directive.
|
||||
*/
|
||||
describe('lib/timeline never uses {@html} (REQ-010)', () => {
|
||||
it('no timeline component contains the raw-HTML directive', () => {
|
||||
const components = readdirSync(timelineDir).filter((file) => file.endsWith('.svelte'));
|
||||
expect(components.length).toBeGreaterThan(0);
|
||||
const offenders = components.filter((file) =>
|
||||
readFileSync(join(timelineDir, file), 'utf8').includes('{@html')
|
||||
);
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user