mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 15:03:12 +00:00
100 lines
3.7 KiB
JavaScript
100 lines
3.7 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { existsSync, readFileSync } from "node:fs";
|
|
import { spawnSync } from "node:child_process";
|
|
import test from "node:test";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const scriptPath = new URL("./deploy-web.sh", import.meta.url);
|
|
const script = readFileSync(scriptPath, "utf8");
|
|
const windowsGitBash = `${process.env.ProgramFiles ?? "C:\\Program Files"}\\Git\\bin\\bash.exe`;
|
|
const bash = process.platform === "win32" ? windowsGitBash : "bash";
|
|
const hasBash = process.platform !== "win32" || existsSync(windowsGitBash);
|
|
const nativeScriptPath = fileURLToPath(scriptPath);
|
|
const bashScriptPath =
|
|
process.platform === "win32"
|
|
? nativeScriptPath
|
|
.replace(/^([A-Za-z]):\\/, (_, drive) => `/${drive.toLowerCase()}/`)
|
|
.replaceAll("\\", "/")
|
|
: nativeScriptPath;
|
|
|
|
test("deploy script has valid bash syntax", { skip: !hasBash }, () => {
|
|
const result = spawnSync(bash, ["-n", bashScriptPath], { encoding: "utf8" });
|
|
assert.equal(result.status, 0, result.stderr);
|
|
});
|
|
|
|
test("deploy script fails closed before running tools", { skip: !hasBash }, () => {
|
|
const result = spawnSync(bash, [bashScriptPath], {
|
|
encoding: "utf8",
|
|
env: { PATH: process.env.PATH },
|
|
});
|
|
assert.notEqual(result.status, 0);
|
|
assert.match(result.stderr, /SITE_BUCKET must be set explicitly/);
|
|
});
|
|
|
|
test("target bucket mismatch fails before publishing", { skip: !hasBash }, () => {
|
|
const result = spawnSync(bash, [bashScriptPath], {
|
|
encoding: "utf8",
|
|
env: {
|
|
...process.env,
|
|
SITE_BUCKET: "wrong-bucket",
|
|
EXPECTED_SITE_BUCKET: "expected-bucket",
|
|
CLOUDFRONT_DISTRIBUTION_ID: "DIST123",
|
|
SITE_URL: "https://example.test",
|
|
EXPECTED_API_URL: "https://api.example.test/api",
|
|
VITE_API_URL: "https://api.example.test/api",
|
|
DEPLOY_RELEASE_ID: "1234567",
|
|
},
|
|
});
|
|
assert.notEqual(result.status, 0);
|
|
assert.match(result.stderr, /SITE_BUCKET does not match EXPECTED_SITE_BUCKET/);
|
|
});
|
|
|
|
test("content safety contract is present and ordered", () => {
|
|
for (const required of [
|
|
"get-bucket-versioning",
|
|
"head-object",
|
|
"list-object-versions",
|
|
"asset-versions.tsv",
|
|
"prior-asset-versions.tsv",
|
|
"prior-manifest.json",
|
|
"priorAssets",
|
|
"isCurrentManifest",
|
|
"--version-id",
|
|
"public,max-age=31536000,immutable",
|
|
"no-cache,no-store,must-revalidate",
|
|
"cloudfront wait invalidation-completed",
|
|
'fetch_route "/login"',
|
|
'fetch_route "${EXTENSIONLESS_SMOKE_PATH}"',
|
|
"Access-Control-Request-Method: GET",
|
|
".deploy/releases/${DEPLOY_RELEASE_ID}.json",
|
|
]) {
|
|
assert.ok(script.includes(required), `missing contract: ${required}`);
|
|
}
|
|
|
|
assert.ok(
|
|
script.indexOf('deployment_verified="true"') < script.indexOf("aws s3api list-object-versions"),
|
|
"pruning must occur only after remote verification",
|
|
);
|
|
assert.ok(
|
|
script.indexOf('grep -qi "^access-control-allow-methods:.*GET"') <
|
|
script.indexOf('aws s3 cp "${work_dir}/manifest.json"'),
|
|
"failed remote verification must not publish a retention manifest",
|
|
);
|
|
assert.ok(
|
|
script.indexOf('aws s3 cp "${work_dir}/manifest.json"') <
|
|
script.indexOf('deployment_verified="true"'),
|
|
"manifest publication failures must roll back the new index",
|
|
);
|
|
assert.ok(
|
|
script.indexOf('>"${work_dir}/prior-asset-keys.txt"') <
|
|
script.indexOf('aws s3 sync dist/ "s3://${SITE_BUCKET}/"'),
|
|
"the pre-manifest release must be inventoried before new assets publish",
|
|
);
|
|
assert.match(
|
|
script,
|
|
/if \(isCurrentManifest\) \{[\s\S]*manifest\.priorAssets/,
|
|
"only the current manifest may retain its pre-script rollback assets",
|
|
);
|
|
assert.match(script, /Could not inspect the current index version/);
|
|
assert.doesNotMatch(script, /s3 sync[\s\S]{0,250}--delete/);
|
|
});
|