Files
frontend/scripts/test-pre-commit.mjs
T
ksv741 ca0ad4f824
Frontend verify / commits (pull_request) Successful in 28s
Frontend verify / security (pull_request) Successful in 10s
Frontend verify / verify (pull_request) Successful in 8m19s
refactor: enforce frontend view model boundaries
2026-09-28 18:48:23 +03:00

80 lines
3.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import { execFileSync, spawnSync } from "node:child_process";
import { randomBytes } from "node:crypto";
import {
existsSync,
mkdirSync,
mkdtempSync,
rmSync,
writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import nodePath from "node:path";
import { test } from "node:test";
const GITHUB_TOKEN_RANDOM_BYTES = 18;
test("pre-commit scans the index, redacts findings and fails closed", () => {
const hook = nodePath.resolve(".husky/pre-commit");
const cwd = mkdtempSync(nodePath.join(tmpdir(), "frontend-hook-"));
const bin = nodePath.join(cwd, "bin");
const marker = nodePath.join(cwd, "downstream");
const token = `ghp_${randomBytes(GITHUB_TOKEN_RANDOM_BYTES).toString("hex")}`;
const git = (...arguments_) =>
execFileSync("git", arguments_, { cwd, stdio: "pipe" }); // eslint-disable-line sonarjs/no-os-command-from-path -- Repository checks use the developer/CI Git installation; arguments never invoke a shell.
const run = (path = `${bin}${nodePath.delimiter}${process.env.PATH}`) =>
spawnSync("/bin/sh", ["-e", hook], {
cwd,
encoding: "utf8",
env: { ...process.env, PATH: path },
});
try {
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Path is built from this check’s private mkdtemp directory and fixed filenames.
mkdirSync(bin);
for (const command of ["npx", "npm"]) {
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Path is built from this check’s private mkdtemp directory and fixed filenames.
writeFileSync(
nodePath.join(bin, command),
"#!/bin/sh\necho ran >> downstream\n",
{
mode: 0o755,
},
);
}
git("init", "--quiet");
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Path is built from this check’s private mkdtemp directory and fixed filenames.
writeFileSync(nodePath.join(cwd, "sample.txt"), "safe staged content\n");
git("add", "sample.txt");
// An unstaged secret must not be mistaken for the index being committed.
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Path is built from this check’s private mkdtemp directory and fixed filenames.
writeFileSync(nodePath.join(cwd, "sample.txt"), `token=${token}\n`);
let result = run();
assert.equal(
result.status,
0,
"clean index must pass; install Gitleaks first",
);
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Path is built from this check’s private mkdtemp directory and fixed filenames.
assert.ok(existsSync(marker));
rmSync(marker);
git("add", "sample.txt");
result = run();
assert.equal(result.status, 1, "staged secret must block commit");
assert.ok(!`${result.stdout}${result.stderr}`.includes(token));
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Path is built from this check’s private mkdtemp directory and fixed filenames.
assert.ok(!existsSync(marker), "formatting/dependency checks must not run");
result = run(bin);
assert.notEqual(result.status, 0, "missing Gitleaks must block commit");
// eslint-disable-next-line security/detect-non-literal-fs-filename -- Path is built from this check’s private mkdtemp directory and fixed filenames.
assert.ok(!existsSync(marker));
}
finally {
rmSync(cwd, { force: true, recursive: true });
}
});