diff --git a/bin/oai-spec-validate-markdown b/bin/oai-spec-validate-markdown index d18580e..05a0b9c 100755 --- a/bin/oai-spec-validate-markdown +++ b/bin/oai-spec-validate-markdown @@ -16,6 +16,7 @@ SPEC_CONFIG_LINT="${OAI_BUILD_INFRA_SPEC_CONFIG:-$PACKAGE_DIR/configs/markdownli LINKSPECTOR_CONFIG="${OAI_BUILD_INFRA_LINKSPECTOR_CONFIG:-.linkspector.yml}" MARKDOWNLINT="$(resolve_node_bin markdownlint-cli2 "$PACKAGE_DIR")" LINKSPECTOR="$(resolve_node_bin linkspector "$PACKAGE_DIR")" +LINKSPECTOR_NODE_OPTIONS="${NODE_OPTIONS:-}" if [ ! -f "$CONFIG_FILE" ]; then echo "Error: $CONFIG_FILE not found" @@ -32,5 +33,9 @@ fi "$MARKDOWNLINT" --config "$ROOT_CONFIG" "*.md" if [ -f "$LINKSPECTOR_CONFIG" ]; then - "$LINKSPECTOR" check --config "$LINKSPECTOR_CONFIG" + if [ "${OAI_BUILD_INFRA_LINKSPECTOR_NO_SANDBOX:-}" = "1" ] || { [ "${GITHUB_ACTIONS:-}" = "true" ] && [ "${OAI_BUILD_INFRA_LINKSPECTOR_NO_SANDBOX:-}" != "0" ]; }; then + LINKSPECTOR_NODE_OPTIONS="${LINKSPECTOR_NODE_OPTIONS:+$LINKSPECTOR_NODE_OPTIONS }--require $PACKAGE_DIR/src/shell/linkspector-no-sandbox.cjs" + fi + + NODE_OPTIONS="$LINKSPECTOR_NODE_OPTIONS" "$LINKSPECTOR" check --config "$LINKSPECTOR_CONFIG" fi diff --git a/src/shell/linkspector-no-sandbox.cjs b/src/shell/linkspector-no-sandbox.cjs new file mode 100644 index 0000000..c846066 --- /dev/null +++ b/src/shell/linkspector-no-sandbox.cjs @@ -0,0 +1,10 @@ +// Linkspector adds Chromium's --no-sandbox flag when it detects a root user. +// GitHub-hosted runners can also require --no-sandbox even when not running as +// root, so this shim forces Linkspector down that existing launch path. +if (typeof process.getuid === "function") { + Object.defineProperty(process, "getuid", { + value: () => 0, + configurable: true, + writable: true + }); +} diff --git a/tests/shell/bin-resolution.test.mjs b/tests/shell/bin-resolution.test.mjs index 33fe715..4405fe8 100644 --- a/tests/shell/bin-resolution.test.mjs +++ b/tests/shell/bin-resolution.test.mjs @@ -43,6 +43,51 @@ describe("shell command bin resolution", () => { expect(output).toContain("linkspector check --config"); }); + test("validate-markdown preloads the linkspector no-sandbox shim in GitHub Actions", () => { + const { consumer, installedPackage, consumerBin } = createInstalledPackageFixture(); + + writeFileSync(join(consumer, "README.md"), "# Fixture\n"); + writeFileSync(join(consumer, ".linkspector.yml"), "dirs:\n - .\n"); + writeBin(join(consumerBin, "markdownlint-cli2"), "echo markdownlint \"$@\""); + writeBin(join(consumerBin, "linkspector"), "echo NODE_OPTIONS=\"$NODE_OPTIONS\"\necho linkspector \"$@\""); + + const output = execFileSync("bash", [join(installedPackage, "bin/oai-spec-validate-markdown")], { + cwd: consumer, + encoding: "utf8", + env: { + ...process.env, + GITHUB_ACTIONS: "true", + PATH: `${consumerBin}:${process.env.PATH}` + } + }); + + expect(output).toContain("linkspector-no-sandbox.cjs"); + expect(output).toContain("linkspector check --config"); + }); + + test("validate-markdown can disable the linkspector no-sandbox shim", () => { + const { consumer, installedPackage, consumerBin } = createInstalledPackageFixture(); + + writeFileSync(join(consumer, "README.md"), "# Fixture\n"); + writeFileSync(join(consumer, ".linkspector.yml"), "dirs:\n - .\n"); + writeBin(join(consumerBin, "markdownlint-cli2"), "echo markdownlint \"$@\""); + writeBin(join(consumerBin, "linkspector"), "echo NODE_OPTIONS=\"$NODE_OPTIONS\"\necho linkspector \"$@\""); + + const output = execFileSync("bash", [join(installedPackage, "bin/oai-spec-validate-markdown")], { + cwd: consumer, + encoding: "utf8", + env: { + ...process.env, + GITHUB_ACTIONS: "true", + OAI_BUILD_INFRA_LINKSPECTOR_NO_SANDBOX: "0", + PATH: `${consumerBin}:${process.env.PATH}` + } + }); + + expect(output).not.toContain("linkspector-no-sandbox.cjs"); + expect(output).toContain("linkspector check --config"); + }); + test("validate-markdown skips linkspector when no linkspector config exists", () => { const { consumer, installedPackage, consumerBin } = createInstalledPackageFixture();