Release ForgeFlow 0.5.2

This commit is contained in:
NuklearRabbit
2026-07-25 01:07:54 +02:00
parent 602309b203
commit cf1f67a823
23 changed files with 550 additions and 72 deletions
+55 -1
View File
@@ -6,7 +6,7 @@ import { spawnSync } from 'node:child_process';
import test from 'node:test';
import shellVerification from '../src/shared/shell-verification.cjs';
const { bashSyntaxCheckInvocation, normalizeRelativePosixPath } = shellVerification;
const { bashSyntaxCheckInvocation, bashSyntaxCheckFromTextInvocation, normalizeRelativePosixPath, validateShellScriptStructure, shouldRunExternalBash } = shellVerification;
test('Bash syntax validation keeps Windows project roots in cwd and passes a relative POSIX path', () => {
const invocation = bashSyntaxCheckInvocation('C:\\Projects\\ForgeFlow');
@@ -47,3 +47,57 @@ test('Bash syntax validation works from a project root containing spaces', async
}
}
});
test('Bash syntax validation from text does not depend on a Windows working directory', () => {
const invocation = bashSyntaxCheckFromTextInvocation('#!/usr/bin/env bash\nset -euo pipefail\necho ok\n');
assert.equal(invocation.command, 'bash');
assert.deepEqual(invocation.args, ['-n']);
assert.equal(invocation.options.cwd, undefined);
assert.match(invocation.options.input, /set -euo pipefail/);
});
test('Bash syntax validation from text detects malformed scripts', (t) => {
if (spawnSync('bash', ['--version'], { encoding: 'utf8' }).status !== 0) {
t.skip('Bash is not available in this environment.');
return;
}
const invocation = bashSyntaxCheckFromTextInvocation('if true; then\n echo missing fi\n');
const result = spawnSync(invocation.command, invocation.args, invocation.options);
assert.notEqual(result.status, 0);
});
test('portable server-script validation does not require a local Bash executable', () => {
const script = `#!/usr/bin/env bash
set -Eeuo pipefail
readonly CONFIG_FILE="/etc/forgeflow/targets.conf"
echo "Target configuration must be owned by root"
APP_DIR=/tmp/app
SHA=0123456789012345678901234567890123456789
COMPOSE_FILE=docker-compose.yml
write_status() { :; }
exec 9>/tmp/test.lock
flock -n 9
git -C "$APP_DIR" fetch origin main
git -C "$APP_DIR" reset --hard "$SHA"
docker compose -f "$COMPOSE_FILE" up -d --build --remove-orphans
write_status "healthy"
write_status "unhealthy"
`;
assert.equal(validateShellScriptStructure(script), true);
});
test('portable server-script validation refuses missing deployment safety markers', () => {
assert.throws(
() => validateShellScriptStructure('#!/usr/bin/env bash\nset -Eeuo pipefail\necho unsafe\n'),
/missing required safety marker/
);
});
test('Windows publication never depends on an external Bash shim', () => {
assert.equal(shouldRunExternalBash('win32'), false);
assert.equal(shouldRunExternalBash('linux'), true);
assert.equal(shouldRunExternalBash('darwin'), true);
});