Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 35 additions & 21 deletions tests/gateway/startup-permissions/run-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ function check(name, cond, reason) {
record(name, cond ? "PASS" : "FAIL", reason);
}

/* POSIX file-mode-bit assertions are meaningless on win32: chmod/fchmod are no-ops there,
* so a tightened file/dir just keeps whatever default mode Windows reports, never the
* exact 0640/0750/0644 this pass enforces on POSIX. Route every exact-mode check through
* this helper instead of a bare check() so it skips (not fails) on win32, matching the
* SKIP convention this file already uses for its two runtime-creation-mode tests below. */
function checkPosixMode(name, actualMode, expectedMode, reason) {
if (process.platform === "win32") {
console.log(`SKIP ${name} (POSIX modes are not meaningful on win32)`);
results.push({ name, status: "SKIP", reason: "win32" });
return;
}
check(name, actualMode === expectedMode, reason);
}

function freshDir(prefix) {
return fs.mkdtempSync(path.join(os.tmpdir(), `gs-startup-permissions-${prefix}-`));
}
Expand Down Expand Up @@ -181,24 +195,24 @@ function tightenStateDirPermissionsRetrofitsEveryRealSensitivePathToTheAccessMod

const changed = startupPermissions.tightenStateDirPermissions(dir);

check("real-writer-claim-file-tightened-to-0640", mode(claimPath) === 0o640, mode(claimPath).toString(8));
check("real-bundle-file-tightened-to-0640", mode(chain.bundlePath(dir, "bundle-real-1")) === 0o640, "");
check("real-chain-jsonl-tightened-to-0640", mode(chain.chainPath(dir)) === 0o640, "");
check("real-head-json-tightened-to-0640", mode(chain.headPath(dir)) === 0o640, "");
check("real-quarantined-bundle-tightened-to-0640", mode(quarantinedBundlePath) === 0o640, "");
check("real-wal-file-tightened-to-0640", mode(walPath) === 0o640, "");
check("real-intent-file-tightened-to-0640", mode(intentPath) === 0o640, "");
check("real-signature-file-tightened-to-0640", mode(signaturePath) === 0o640, "");

check("real-state-dir-tightened-to-0750", mode(dir) === 0o750, "");
check("real-sessions-dir-tightened-to-0750", mode(chain.sessionsDir(dir)) === 0o750, "");
check("real-quarantine-dir-tightened-to-0750", mode(quarantineDir) === 0o750, "");
check("real-recovery-dir-tightened-to-0750", mode(recovery.recoveryDir(dir)) === 0o750, "");
check("real-active-dir-tightened-to-0750", mode(recovery.activeDir(dir)) === 0o750, "");
check("real-intents-dir-tightened-to-0750", mode(recovery.intentsDir(dir)) === 0o750, "");
check("real-signatures-dir-tightened-to-0750", mode(recovery.signaturesDir(dir)) === 0o750, "");

check("gateway-status-json-mode-untouched-by-this-pass", mode(statusPath) === 0o644,
checkPosixMode("real-writer-claim-file-tightened-to-0640", mode(claimPath), 0o640, mode(claimPath).toString(8));
checkPosixMode("real-bundle-file-tightened-to-0640", mode(chain.bundlePath(dir, "bundle-real-1")), 0o640, "");
checkPosixMode("real-chain-jsonl-tightened-to-0640", mode(chain.chainPath(dir)), 0o640, "");
checkPosixMode("real-head-json-tightened-to-0640", mode(chain.headPath(dir)), 0o640, "");
checkPosixMode("real-quarantined-bundle-tightened-to-0640", mode(quarantinedBundlePath), 0o640, "");
checkPosixMode("real-wal-file-tightened-to-0640", mode(walPath), 0o640, "");
checkPosixMode("real-intent-file-tightened-to-0640", mode(intentPath), 0o640, "");
checkPosixMode("real-signature-file-tightened-to-0640", mode(signaturePath), 0o640, "");

checkPosixMode("real-state-dir-tightened-to-0750", mode(dir), 0o750, "");
checkPosixMode("real-sessions-dir-tightened-to-0750", mode(chain.sessionsDir(dir)), 0o750, "");
checkPosixMode("real-quarantine-dir-tightened-to-0750", mode(quarantineDir), 0o750, "");
checkPosixMode("real-recovery-dir-tightened-to-0750", mode(recovery.recoveryDir(dir)), 0o750, "");
checkPosixMode("real-active-dir-tightened-to-0750", mode(recovery.activeDir(dir)), 0o750, "");
checkPosixMode("real-intents-dir-tightened-to-0750", mode(recovery.intentsDir(dir)), 0o750, "");
checkPosixMode("real-signatures-dir-tightened-to-0750", mode(recovery.signaturesDir(dir)), 0o750, "");

checkPosixMode("gateway-status-json-mode-untouched-by-this-pass", mode(statusPath), 0o644,
`expected the operator status file to be left at 0644, got ${mode(statusPath).toString(8)}`);
check("gateway-status-json-not-reported-as-changed",
!changed.files.includes(statusPath), JSON.stringify(changed.files));
Expand All @@ -223,7 +237,7 @@ function freshDeploymentWithNothingOnDiskYetDoesNotThrow() {
changed && changed.dirs.includes(dir), JSON.stringify(changed));
check("empty-state-dir-reports-no-files-changed",
changed && changed.files.length === 0, JSON.stringify(changed));
check("empty-state-dir-mode-is-0750", mode(dir) === 0o750, mode(dir).toString(8));
checkPosixMode("empty-state-dir-mode-is-0750", mode(dir), 0o750, mode(dir).toString(8));
}

function partiallyPopulatedDeploymentSkipsWhatIsMissingAndTightensWhatExists() {
Expand All @@ -239,8 +253,8 @@ function partiallyPopulatedDeploymentSkipsWhatIsMissingAndTightensWhatExists() {
try { changed = startupPermissions.tightenStateDirPermissions(dir); }
catch (error) { threw = error; }
check("partial-deployment-does-not-throw", threw === null, threw && threw.message);
check("partial-deployment-tightens-the-existing-claim-file",
mode(claim.path) === 0o640, mode(claim.path).toString(8));
checkPosixMode("partial-deployment-tightens-the-existing-claim-file",
mode(claim.path), 0o640, mode(claim.path).toString(8));
check("partial-deployment-reports-only-the-existing-file",
changed.files.length === 1 && changed.files[0] === claim.path, JSON.stringify(changed.files));
}
Expand Down
37 changes: 29 additions & 8 deletions tests/state-store/atomic-primitives/run-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,14 @@ let failures = 0;
const results = [];

function record(name, status, reason) {
const line = status === "PASS" ? `PASS ${name}` : `FAIL ${name}+${reason || "unknown"}`;
console.log(line);
/* Codex PR #34 review: checkPosixMode's SKIP calls (below) were being printed with the
* generic "FAIL" prefix -- this function only special-cased "PASS", treating every other
* status (including a deliberate SKIP) as "FAIL" text even though `failures` and the
* SUMMARY line correctly counted it as skipped, not failed. That left Windows CI logs
* showing "FAIL ..." lines for assertions that actually passed (by skipping), which is
* misleading even though the process still exits 0. */
const prefix = status === "PASS" ? "PASS" : status === "SKIP" ? "SKIP" : "FAIL";
console.log(`${prefix} ${name}${status === "PASS" ? "" : `+${reason || "unknown"}`}`);
results.push({ name, status, reason: reason || "" });
if (status === "FAIL") failures++;
}
Expand All @@ -42,6 +48,20 @@ function check(name, cond, reason) {
if (cond) record(name, "PASS"); else record(name, "FAIL", reason);
}

/* POSIX file-mode-bit assertions are meaningless on win32: fchmodSync/chmod are no-ops
* there, so a freshly created file just keeps whatever default mode Windows reports,
* never the exact 0640/0644 this codebase enforces on POSIX. Route every exact-mode
* check through this helper instead of a bare check() so it skips (not fails) on win32,
* matching the SKIP convention already used elsewhere in this test suite family
* (tests/gateway/recovery/run-tests.js, tests/gateway/startup-permissions/run-tests.js). */
function checkPosixMode(name, actualMode, expectedMode, reason) {
if (process.platform === "win32") {
record(name, "SKIP", "POSIX file mode bits do not apply on win32");
Comment thread
pjpoulose marked this conversation as resolved.
return;
}
check(name, actualMode === expectedMode, reason);
}

function freshDir(prefix) {
return fs.mkdtempSync(path.join(os.tmpdir(), `gs-atomic-${prefix}-`));
}
Expand Down Expand Up @@ -282,7 +302,7 @@ function atomicCreateExclusiveDefaultModeIsGroupReadable() {
const target = path.join(dir, "record.json");
stateStore.atomicCreateExclusive(target, "payload");
const mode = fs.statSync(target).mode & 0o777;
check("atomicCreateExclusive-default-mode-is-0640", mode === 0o640,
checkPosixMode("atomicCreateExclusive-default-mode-is-0640", mode, 0o640,
`expected the new access-model default 0640, got ${mode.toString(8)}`);
}

Expand All @@ -292,7 +312,7 @@ function atomicOverwriteFileDefaultModeIsGroupReadable() {
fs.writeFileSync(target, "seed");
stateStore.atomicOverwriteFile(target, "new-content", dir);
const mode = fs.statSync(target).mode & 0o777;
check("atomicOverwriteFile-default-mode-is-0640", mode === 0o640,
checkPosixMode("atomicOverwriteFile-default-mode-is-0640", mode, 0o640,
`expected the new access-model default 0640, got ${mode.toString(8)}`);
}

Expand All @@ -310,7 +330,7 @@ function atomicCreateExclusiveUmaskZeroStillProducesConfiguredMode() {
stateStore.atomicCreateExclusive(target, "payload");
});
const mode = fs.statSync(target).mode & 0o777;
check("atomicCreateExclusive-umask-0-still-yields-0640-not-0666", mode === 0o640,
checkPosixMode("atomicCreateExclusive-umask-0-still-yields-0640-not-0666", mode, 0o640,
`expected 0640 regardless of umask 0 -- a result of 0666 here would mean fchmodSync ` +
`is not actually running, only the ambient umask is -- got ${mode.toString(8)}`);
}
Expand All @@ -333,9 +353,9 @@ function atomicOverwriteFileRenameCarriesNewInodeModeOverPreExistingFile() {
stateStore.atomicOverwriteFile(target, "new-content", dir);
});
const mode = fs.statSync(target).mode & 0o777;
check("atomicOverwriteFile-pre-existing-target-really-was-0644", preExistingMode === 0o644,
checkPosixMode("atomicOverwriteFile-pre-existing-target-really-was-0644", preExistingMode, 0o644,
`test setup invariant broken: expected the pre-existing target to be 0644, got ${preExistingMode.toString(8)}`);
check("atomicOverwriteFile-rename-carries-new-inode-mode-not-preexisting-0644", mode === 0o640,
checkPosixMode("atomicOverwriteFile-rename-carries-new-inode-mode-not-preexisting-0644", mode, 0o640,
`expected the post-rename target to carry the NEW temp file's mode (0640), not the ` +
`pre-existing target's 0644 -- got ${mode.toString(8)}`);
check("atomicOverwriteFile-rename-carries-new-inode-mode-content-still-correct",
Expand Down Expand Up @@ -496,7 +516,8 @@ function main() {

const passed = results.filter((r) => r.status === "PASS").length;
const failed = results.filter((r) => r.status === "FAIL").length;
console.log(`SUMMARY passed=${passed} failed=${failed} skipped=0`);
const skipped = results.filter((r) => r.status === "SKIP").length;
console.log(`SUMMARY passed=${passed} failed=${failed} skipped=${skipped}`);
process.exit(failures ? 1 : 0);
}

Expand Down
Loading