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:
parent
a807ee2b79
commit
7f9c790f43
6 changed files with 222 additions and 18 deletions
|
|
@ -21,7 +21,7 @@
|
|||
// Reuses: atomisk-skriv-moenster (scripts/write-org-profile.mjs:34-40);
|
||||
// writeFrontmatter (lib/frontmatter.mjs) for peker-frontmatter. Zero npm deps.
|
||||
|
||||
import { writeFileSync, mkdirSync, renameSync, existsSync } from 'node:fs';
|
||||
import { writeFileSync, mkdirSync, renameSync, existsSync, realpathSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { homedir } from 'node:os';
|
||||
|
||||
|
|
@ -52,6 +52,26 @@ function resolveUnderBundle(resolvedBundle, rel) {
|
|||
return resolved;
|
||||
}
|
||||
|
||||
// M2 (A1): den leksikalske sjekken over slipper symlinks -- en symlinket
|
||||
// katalog/original INNE i bundlen kan peke UT av den. realpathSync paa den
|
||||
// faktiske noden (destinasjons-parent etter mkdir / original foer peker-skriv)
|
||||
// maa ogsaa lande under bundle-rotas realpath, ellers avvises skrivet.
|
||||
function assertRealUnderBundle(realBundle, p, what) {
|
||||
const real = realpathSync(p);
|
||||
if (real !== realBundle && !real.startsWith(realBundle + path.sep)) {
|
||||
throw new Error(`innboks-write: ${what} resolverer utenfor bundle-rot (symlink-escape avvist): ${p}`);
|
||||
}
|
||||
return real;
|
||||
}
|
||||
|
||||
// Destinasjons-parent opprettes, realpath-sjekkes, DERETTER skrives det atomisk.
|
||||
function writeConfined(realBundle, target, data, what) {
|
||||
const dir = path.dirname(target);
|
||||
mkdirSync(dir, { recursive: true });
|
||||
assertRealUnderBundle(realBundle, dir, what);
|
||||
writeAtomic(target, data);
|
||||
}
|
||||
|
||||
// Skrevet fil = frontmatter + body verbatim, med garantert trailing newline.
|
||||
function fileContent(concept) {
|
||||
const out = `${concept.frontmatter}${concept.body}`;
|
||||
|
|
@ -86,13 +106,16 @@ export function writeConcepts(concepts, { bundleRoot, originals = [] } = {}) {
|
|||
throw new Error(`innboks-write: skriv til home-org-rot avvist: ${bundleRoot}`);
|
||||
}
|
||||
|
||||
// Bundle-rotas realpath er ankeret for alle M2-symlink-sjekker under.
|
||||
const realBundle = realpathSync(resolvedBundle);
|
||||
|
||||
const writtenConcepts = [];
|
||||
for (const concept of concepts) {
|
||||
if (!concept.destRel) {
|
||||
throw new Error(`innboks-write: konsept mangler destRel: ${concept.slug ?? '?'}`);
|
||||
}
|
||||
const target = resolveUnderBundle(resolvedBundle, concept.destRel);
|
||||
writeAtomic(target, fileContent(concept));
|
||||
writeConfined(realBundle, target, fileContent(concept), `destinasjons-katalog for ${concept.destRel}`);
|
||||
writtenConcepts.push(target);
|
||||
}
|
||||
|
||||
|
|
@ -107,6 +130,9 @@ export function writeConcepts(concepts, { bundleRoot, originals = [] } = {}) {
|
|||
if (relToBundle === '' || relToBundle.startsWith('..') || path.isAbsolute(relToBundle)) {
|
||||
throw new Error(`innboks-write: original utenfor bundle-rot: ${original.path}`);
|
||||
}
|
||||
// M2: en symlink-original i drop-zonen passerer den leksikalske sjekken
|
||||
// over, men realpathen kan peke UT av bundlen -> avvis.
|
||||
assertRealUnderBundle(realBundle, resolvedOriginal, `original ${original.path}`);
|
||||
const link = `/${relToBundle.split(path.sep).join('/')}`;
|
||||
|
||||
// Nivaa = nivaaet til foerste konsept fra samme kilde; default dokumenter/.
|
||||
|
|
@ -114,7 +140,7 @@ export function writeConcepts(concepts, { bundleRoot, originals = [] } = {}) {
|
|||
const level = sibling ? path.dirname(sibling.destRel) : 'dokumenter';
|
||||
const pointerRel = path.join(level, `${original.sourceSlug}.kilde.md`);
|
||||
const pointerTarget = resolveUnderBundle(resolvedBundle, pointerRel);
|
||||
writeAtomic(pointerTarget, pointerContent(original, link));
|
||||
writeConfined(realBundle, pointerTarget, pointerContent(original, link), `peker-katalog for ${pointerRel}`);
|
||||
writtenPointers.push(pointerTarget);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue