fix(okr): gate-herding B2 scoped strict + B3 alle lenkeformer + M2 realpath-confinement + M3 deriveType basename/ord-grense

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-07-16 20:12:35 +02:00
commit 7f9c790f43
6 changed files with 222 additions and 18 deletions

View file

@ -14,7 +14,7 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { createHash } from 'node:crypto';
import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, readdirSync, existsSync, rmSync } from 'node:fs';
import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, readdirSync, existsSync, rmSync, symlinkSync } from 'node:fs';
import { tmpdir, homedir } from 'node:os';
import { join, dirname } from 'node:path';
@ -150,3 +150,47 @@ test('writeConcepts: atomisk -- ingen .tmp lekker etter skriv', () => {
assert.deepEqual(leftover, [], 'ingen temp-fil igjen etter atomisk renameSync');
});
});
// --- M2 (A1): realpathSync-confinement -- leksikalsk sjekk alene slipper symlinks ---
test('writeConcepts: symlink-original som peker UT av bundlen avvises (M2)', () => {
withBundle(({ tmp, bundleRoot, inbox }) => {
// Fil UTENFOR bundle-rota; symlink i drop-zonen passerer den leksikalske sjekken.
const outside = join(tmp, 'utenfor.txt');
writeFileSync(outside, 'sensitivt innhold utenfor bundlen');
symlinkSync(outside, join(inbox, 'lenket.txt'));
assert.throws(
() => writeConcepts([], {
bundleRoot,
originals: [{ sourceSlug: 'lenket', path: join(inbox, 'lenket.txt') }],
}),
/symlink|utenfor bundle/,
'symlink-original skal avvises via realpathSync',
);
});
});
test('writeConcepts: symlinket destinasjons-katalog som peker UT av bundlen avvises (M2)', () => {
withBundle(({ tmp, bundleRoot }) => {
// dokumenter/ er en symlink til en katalog utenfor bundlen -> skriv gjennom
// den ville landet utenfor tross leksikalsk '..'-sjekk paa destRel.
const outsideDir = join(tmp, 'ute');
mkdirSync(outsideDir, { recursive: true });
symlinkSync(outsideDir, join(bundleRoot, 'dokumenter'));
const concept = {
slug: 'x',
sourceSlug: 'x',
destRel: 'dokumenter/x.md',
frontmatter: '---\ntype: Dokument\n---\n',
body: 'innhold',
};
assert.throws(
() => writeConcepts([concept], { bundleRoot }),
/symlink|utenfor bundle/,
'destinasjons-parent skal realpath-sjekkes foer skriv',
);
assert.deepEqual(readdirSync(outsideDir), [], 'ingenting skrevet utenfor bundlen');
});
});