mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-08 08:11:17 -10:00
fix(context): reject dangling destination leaf symlinks
This commit is contained in:
1 parent
d13b04c6c2
commit
51209941ef
2 files changed
+34
-2
No files matched your search
@@ -427,7 +427,14 @@ Examples:
|
||||
mkdirSync(targetRoot, { recursive: true });
|
||||
assertDestinationNamespaceContained(targetRoot, installName);
|
||||
const targetDir = join(targetRoot, installName);
|
||||
if (existsSync(targetDir)) {
|
||||
let targetExists = false;
|
||||
try {
|
||||
lstatSync(targetDir);
|
||||
targetExists = true;
|
||||
} catch (err) {
|
||||
if ((err as NodeJS.ErrnoException).code !== "ENOENT") throw err;
|
||||
}
|
||||
if (targetExists) {
|
||||
throw new Error(`A context pack named '${installName}' already exists at ${targetDir}. Remove it first or use --name to install under a different name.`);
|
||||
}
|
||||
cpSync(sourceDir, targetDir, { recursive: true });
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// the CLI trust boundary like the existing manifest hardening). PM watch: the
|
||||
// matrix pins the ACTUAL reject + no-write behavior verbatim, per clause.
|
||||
import { describe, it, expect, vi, afterEach } from "vitest";
|
||||
import { existsSync, mkdirSync, mkdtempSync, readdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
||||
import { existsSync, lstatSync, mkdirSync, mkdtempSync, readdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { Command } from "commander";
|
||||
@@ -150,6 +150,31 @@ describe("ATOM 2 — `context add` write boundary rejects unsafe install refs BE
|
||||
expect(readdirSync(outside), "outside dir untouched").toEqual([]);
|
||||
});
|
||||
|
||||
it("HIGH-1: rejects a dangling destination leaf symlink through the normal CLI error path", async () => {
|
||||
const home = isolatedHome();
|
||||
const src = validSourcePack();
|
||||
tmpSrcs.push(src);
|
||||
const storeRoot = join(home, "context-packs");
|
||||
const outside = join(home, "outside-missing");
|
||||
const leaf = join(storeRoot, "dangle");
|
||||
mkdirSync(storeRoot, { recursive: true });
|
||||
symlinkSync(outside, leaf);
|
||||
const origErr = console.error;
|
||||
const errLogs: string[] = [];
|
||||
console.error = (...a: unknown[]) => { errLogs.push(a.map(String).join(" ")); };
|
||||
const origExit = process.exitCode;
|
||||
try {
|
||||
await makeCmd().parseAsync(["node", "rig", "context", "add", src, "--name", "dangle"]);
|
||||
expect(process.exitCode, "normal CLI rejection, never a signal/abort").toBe(1);
|
||||
} finally {
|
||||
console.error = origErr;
|
||||
process.exitCode = origExit;
|
||||
}
|
||||
expect(errLogs.join("\n")).toMatch(/symlink|already exists|unsafe/i);
|
||||
expect(lstatSync(leaf).isSymbolicLink(), "dangling leaf remains unchanged").toBe(true);
|
||||
expect(existsSync(outside), "outside target remains absent").toBe(false);
|
||||
});
|
||||
|
||||
// Slice-03 lineage repair (R2 terminal HIGH-2): the install boundary must
|
||||
// enforce the bounded, delimiter-free version predicate BEFORE any write.
|
||||
it("HIGH-2: rejects an unsafe manifest version at the install boundary BEFORE any fs mutation", async () => {
|
||||
|
||||
Reference in new issue
Block a user