Skip to content

Commit 1a228b6

Browse files
authored
fix: fail closed on invalid Linux package roots (#53)
Co-authored-by: Joseph Yaksich <gitcommit90@users.noreply.github.com>
1 parent cc8624b commit 1a228b6

3 files changed

Lines changed: 44 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
playbooks active in every resident turn so imperative setup requests are
2424
executed instead of answered with tutorials, and evidenced machine-wide
2525
network failures are escalated directly for repair.
26+
- Made Linux release packaging fail closed unless it runs in the exact Git
27+
checkout whose `HEAD` contains the advertised version and a complete source
28+
archive, preventing a nested source copy from silently packaging only sealed
29+
runtime assets from a parent repository.
2630

2731
## [0.0.34] - 2026-08-01
2832

scripts/package-linux-host.mjs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ const sealed = [
2727
"container/channel-machine.oci.sha256",
2828
"container/channel-machine.oci.json",
2929
];
30+
31+
const repository = spawnSync("git", ["rev-parse", "--show-toplevel"], { cwd: root, encoding: "utf8" });
32+
const repositoryRoot = repository.status === 0 ? resolve(String(repository.stdout || "").trim()) : "";
33+
if (repositoryRoot !== root) {
34+
throw new Error("Linux packaging must run from the root of the exact Git checkout; a parent repository or source copy is not release authority");
35+
}
36+
const headPackage = spawnSync("git", ["show", "HEAD:package.json"], { cwd: root, encoding: "utf8" });
37+
let headVersion = "";
38+
try { headVersion = String(JSON.parse(String(headPackage.stdout || "{}")).version || "").trim(); } catch { }
39+
if (headPackage.status !== 0 || headVersion !== version) {
40+
throw new Error("Linux packaging version does not match package.json at Git HEAD");
41+
}
3042
for (const rel of sealed.slice(0, 2)) {
3143
if (!existsSync(resolve(root, rel))) {
3244
throw new Error(`Linux packaging requires the sealed channel image at ${rel} (run scripts/build-oci-channel-image.sh on a builder host).`);
@@ -45,9 +57,15 @@ try {
4557
maxBuffer: 512 * 1024 * 1024,
4658
});
4759
if (archive.status !== 0) throw new Error("Could not package the exact Git release source");
60+
if (!archive.stdout?.length) throw new Error("Exact Git release source archive was empty");
4861
const extract = spawnSync("tar", ["-xf", "-", "-C", stage], { input: archive.stdout, stdio: ["pipe", "inherit", "inherit"] });
4962
if (extract.status !== 0) throw new Error("Could not extract the Git release source for packaging");
5063

64+
const stagedPackage = resolve(stage, prefix, "package.json");
65+
if (!existsSync(stagedPackage) || String(JSON.parse(readFileSync(stagedPackage, "utf8")).version || "") !== version) {
66+
throw new Error("Exact Git release source archive is missing its versioned package contract");
67+
}
68+
5169
const containerDir = join(stage, prefix, "container");
5270
mkdirSync(containerDir, { recursive: true });
5371
for (const rel of sealed) {

test/connectors.mjs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import assert from "node:assert/strict";
2-
import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
2+
import { chmod, copyFile, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
33
import { readFileSync } from "node:fs";
44
import { tmpdir } from "node:os";
55
import { join } from "node:path";
6+
import { spawnSync } from "node:child_process";
67
import test from "node:test";
78

89
test("Linux release packaging ships pinned connectors for every supported host architecture", () => {
@@ -16,10 +17,30 @@ test("Linux release packaging ships pinned connectors for every supported host a
1617
}
1718
assert.match(packageLinux, /cloudflared-linux-\$\{connector\.arch\}/, "the verified binaries enter the Linux release archive");
1819
assert.match(packageLinux, /chmodSync\(destination, 0o755\)/, "packaged Linux connectors retain executable mode");
20+
assert.match(packageLinux, /rev-parse[\s\S]*--show-toplevel[\s\S]*repositoryRoot !== root[\s\S]*parent repository or source copy is not release authority/, "Linux packaging fails closed when a copied source tree accidentally resolves to a parent Git checkout");
21+
assert.match(packageLinux, /git", \["show", "HEAD:package\.json"\][\s\S]*headVersion !== version/, "Linux packaging binds its visible version to the exact Git HEAD");
22+
assert.match(packageLinux, /archive\.stdout\?\.length[\s\S]*stagedPackage[\s\S]*versioned package contract/, "Linux packaging rejects an empty or structurally incomplete Git source archive");
1923
assert.match(resolver, /cloudflared-linux-\$\{process\.arch\}/, "Linux resolves only the binary matching the running host architecture");
2024
assert.match(resolver, /process\.env\.HELM_APP_ROOT[\s\S]*process\.cwd\(\)/, "an installed Linux service can resolve its bundled connector from its release working directory");
2125
});
2226

27+
test("Linux release packaging rejects a source copy nested under another Git checkout", async () => {
28+
const projectRoot = join(import.meta.dirname, "..");
29+
const version = JSON.parse(readFileSync(join(projectRoot, "package.json"), "utf8")).version;
30+
const copiedRoot = await mkdtemp(join(projectRoot, ".package-root-test-"));
31+
const copiedScripts = join(copiedRoot, "scripts");
32+
await mkdir(copiedScripts);
33+
await copyFile(join(projectRoot, "scripts", "package-linux-host.mjs"), join(copiedScripts, "package-linux-host.mjs"));
34+
await writeFile(join(copiedRoot, "package.json"), `${JSON.stringify({ version })}\n`);
35+
try {
36+
const result = spawnSync(process.execPath, [join(copiedScripts, "package-linux-host.mjs")], { cwd: copiedRoot, encoding: "utf8" });
37+
assert.notEqual(result.status, 0);
38+
assert.match(`${result.stdout}\n${result.stderr}`, /parent repository or source copy is not release authority/);
39+
} finally {
40+
await rm(copiedRoot, { recursive: true, force: true });
41+
}
42+
});
43+
2344
test("Linux service working directory resolves the bundled connector without a legacy app-root environment", async (t) => {
2445
if (process.platform !== "linux") {
2546
t.skip("Linux systemd working-directory contract");

0 commit comments

Comments
 (0)