fix(ci): normalize shell validation input (fixes #3)
ForgeFlow quality gate / quality (pull_request) Successful in 7m26s
Managed validation / full (pull_request) Canceled after 0s
ForgeFlow quality gate / secret-scan (pull_request) Successful in 6s

This commit is contained in:
NuklearRabbit
2026-08-29 02:30:19 +02:00
parent 79dc6d367b
commit 408dea0c2d
3 changed files with 18 additions and 18 deletions
+10 -17
View File
@@ -8,15 +8,6 @@ import shellVerification from '../src/shared/shell-verification.cjs';
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');
assert.equal(invocation.command, 'bash');
assert.deepEqual(invocation.args, ['-n', 'examples/server/forgeflow-deploy']);
assert.equal(invocation.options.cwd, 'C:\\Projects\\ForgeFlow');
assert.equal(invocation.args[1].includes('\\'), false);
assert.equal(/^[A-Za-z]:/.test(invocation.args[1]), false);
});
test('Shell validation refuses absolute and escaping script paths', () => {
assert.throws(() => normalizeRelativePosixPath('C:\\Projects\\ForgeFlow\\script.sh'), /must be relative/);
assert.throws(() => normalizeRelativePosixPath('/tmp/script.sh'), /must be relative/);
@@ -34,11 +25,19 @@ test('Bash syntax validation works from a project root containing spaces', async
await mkdir(relativeDirectory, { recursive: true });
await copyFile(new URL('../examples/server/forgeflow-deploy', import.meta.url), path.join(relativeDirectory, 'forgeflow-deploy'));
const invocation = bashSyntaxCheckInvocation(tempBase);
assert.equal(invocation.options.cwd, tempBase);
assert.deepEqual(invocation.args, ['-n']);
assert.equal(invocation.options.input.includes('\r'), false);
const result = spawnSync(invocation.command, invocation.args, invocation.options);
assert.equal(result.status, 0, result.stderr);
} finally {
try {
await rm(tempBase, { recursive: true, force: true, maxRetries: 20, retryDelay: 100 });
await rm(tempBase, {
recursive: true,
force: true,
maxRetries: 20,
retryDelay: 100
});
} catch (error) {
// Git Bash on Windows can retain a short-lived working-directory handle
// after bash -n exits. Do not fail a successful syntax test solely because
@@ -48,7 +47,6 @@ 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');
@@ -67,7 +65,6 @@ test('Bash syntax validation from text detects malformed scripts', (t) => {
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
@@ -89,13 +86,9 @@ write_status "unhealthy"
});
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/
);
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);