Harden deploy script SSH session flow
This commit is contained in:
@@ -48,6 +48,15 @@ rsync -az --delete \
|
||||
-e "$RSYNC_RSH" \
|
||||
"$ROOT_DIR/" "$REMOTE_HOST:$REMOTE_DIR/"
|
||||
|
||||
"${SSH_PREFIX[@]}" "$REMOTE_HOST" "sudo bash $REMOTE_DIR/scripts/bootstrap-server.sh"
|
||||
"${SSH_PREFIX[@]}" "$REMOTE_HOST" "sudo chown -R ${REMOTE_USER}:${REMOTE_USER} $REMOTE_DIR"
|
||||
"${SSH_PREFIX[@]}" "$REMOTE_HOST" "cd $REMOTE_DIR && npm install --omit=dev && sudo systemctl restart boss-web && sudo systemctl restart caddy && sleep 2 && curl -fsS http://127.0.0.1:3000/api/health"
|
||||
POST_SYNC_REMOTE_CMD="
|
||||
sudo bash $REMOTE_DIR/scripts/bootstrap-server.sh &&
|
||||
sudo chown -R ${REMOTE_USER}:${REMOTE_USER} $REMOTE_DIR &&
|
||||
cd $REMOTE_DIR &&
|
||||
npm install --omit=dev &&
|
||||
sudo systemctl restart boss-web &&
|
||||
sudo systemctl restart caddy &&
|
||||
sleep 2 &&
|
||||
curl -fsS http://127.0.0.1:3000/api/health
|
||||
"
|
||||
|
||||
"${SSH_PREFIX[@]}" "$REMOTE_HOST" "$POST_SYNC_REMOTE_CMD"
|
||||
|
||||
86
tests/deploy-server-script.test.ts
Normal file
86
tests/deploy-server-script.test.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
async function writeExecutable(filePath: string, contents: string) {
|
||||
await writeFile(filePath, contents, "utf8");
|
||||
await chmod(filePath, 0o755);
|
||||
}
|
||||
|
||||
test("deploy-server merges post-rsync remote work into a single ssh session", async () => {
|
||||
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "boss-deploy-script-"));
|
||||
const binDir = path.join(tempRoot, "bin");
|
||||
const logDir = path.join(tempRoot, "logs");
|
||||
const repoRoot = "/Users/kris/code/boss";
|
||||
|
||||
await mkdir(binDir, { recursive: true });
|
||||
await mkdir(logDir, { recursive: true });
|
||||
|
||||
await writeExecutable(
|
||||
path.join(binDir, "security"),
|
||||
`#!/bin/sh
|
||||
printf 'Asd123456.'
|
||||
`,
|
||||
);
|
||||
await writeExecutable(
|
||||
path.join(binDir, "npm"),
|
||||
`#!/bin/sh
|
||||
printf '%s\\0' "$*" >> "${path.join(logDir, "npm.log")}"
|
||||
exit 0
|
||||
`,
|
||||
);
|
||||
await writeExecutable(
|
||||
path.join(binDir, "rsync"),
|
||||
`#!/bin/sh
|
||||
printf '%s\\0' "$*" >> "${path.join(logDir, "rsync.log")}"
|
||||
exit 0
|
||||
`,
|
||||
);
|
||||
await writeExecutable(
|
||||
path.join(binDir, "ssh"),
|
||||
`#!/bin/sh
|
||||
printf '%s\\0' "$*" >> "${path.join(logDir, "ssh.log")}"
|
||||
exit 0
|
||||
`,
|
||||
);
|
||||
await writeExecutable(
|
||||
path.join(binDir, "sshpass"),
|
||||
`#!/bin/sh
|
||||
if [ "$1" = "-e" ]; then
|
||||
shift
|
||||
fi
|
||||
exec "$@"
|
||||
`,
|
||||
);
|
||||
|
||||
try {
|
||||
await execFileAsync("zsh", [path.join(repoRoot, "scripts/deploy-server.sh")], {
|
||||
cwd: repoRoot,
|
||||
env: {
|
||||
...process.env,
|
||||
PATH: `${binDir}:${process.env.PATH ?? ""}`,
|
||||
},
|
||||
});
|
||||
|
||||
const sshLog = await readFile(path.join(logDir, "ssh.log"), "utf8");
|
||||
const sshCalls = sshLog
|
||||
.split("\0")
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
assert.equal(sshCalls.length, 2);
|
||||
assert.match(sshCalls[0] ?? "", /sudo mkdir -p \/opt\/boss/);
|
||||
assert.match(sshCalls[1] ?? "", /bootstrap-server\.sh/);
|
||||
assert.match(sshCalls[1] ?? "", /npm install --omit=dev/);
|
||||
assert.match(sshCalls[1] ?? "", /systemctl restart boss-web/);
|
||||
assert.match(sshCalls[1] ?? "", /curl -fsS http:\/\/127\.0\.0\.1:3000\/api\/health/);
|
||||
} finally {
|
||||
await rm(tempRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user