import { describe, expect, it } from "@effect/vitest";import { readFileSync } from "node:fs";import { resolve } from "node:path"; import { validateReleaseTag, validateReleaseVersion } from "../scripts/validate-release-ref"; const workflow = (name: string): string => readFileSync(resolve(import.meta.dirname, "..", ".github/workflows", name), "utf8"); describe("release workflow hardening", () => { it("accepts only semver release versions and v-prefixed semver tags", () => { expect(validateReleaseVersion("1.2.3")).toBe("1.2.3"); expect(validateReleaseVersion("1.2.3-beta.4")).toBe("1.2.3-beta.4"); expect(validateReleaseTag("v1.2.3")).toBe("v1.2.3"); expect(validateReleaseTag("v1.2.3-beta.4+build.5")).toBe("v1.2.3-beta.4+build.5"); expect(() => validateReleaseVersion("v1.2.3")).toThrow(); expect(() => validateReleaseVersion("1.2")).toThrow(); expect(() => validateReleaseTag("1.2.3")).toThrow(); expect(() => validateReleaseTag("v1.2.3; echo unsafe")).toThrow(); expect(() => validateReleaseTag("v01.2.3")).toThrow(); }); it("validates release values through environment variables before shell use", () => { const publishExecutor = workflow("publish-executor-package.yml"); const release = workflow("release.yml"); const publishDesktop = workflow("publish-desktop.yml"); expect(publishExecutor).toContain( "bun run scripts/validate-release-ref.ts --tag-env RAW_RELEASE_TAG --write-env RELEASE_TAG", ); expect(release).toContain( "bun run scripts/validate-release-ref.ts --version-env RELEASE_VERSION --output tag", ); expect(publishDesktop).toContain( "bun run scripts/validate-release-ref.ts --tag-env RAW_RELEASE_TAG --write-env RELEASE_TAG", ); expect(release).not.toContain('tag="v${{ steps.detect_release.outputs.version }}"'); expect(publishDesktop).not.toContain("ref: refs/tags/${{ inputs.tag }}"); expect(publishDesktop).not.toContain('gh release download "${{ inputs.tag }}"'); expect(publishExecutor).not.toMatch(/\n\s+RELEASE_TAG: \$\{\{ github\.event_name/u); }); it("does not persist checkout credentials in release workflows", () => { for (const name of [ "publish-executor-package.yml", "release.yml", "publish-desktop.yml", "pkg-pr-new.yml", ]) { expect(workflow(name)).toContain("persist-credentials: false"); } });});
import { describe, expect, it } from "@effect/vitest";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { validateReleaseTag, validateReleaseVersion } from "../scripts/validate-release-ref";
const workflow = (name: string): string =>
readFileSync(resolve(import.meta.dirname, "..", ".github/workflows", name), "utf8");
describe("release workflow hardening", () => {
it("accepts only semver release versions and v-prefixed semver tags", () => {
expect(validateReleaseVersion("1.2.3")).toBe("1.2.3");
expect(validateReleaseVersion("1.2.3-beta.4")).toBe("1.2.3-beta.4");
expect(validateReleaseTag("v1.2.3")).toBe("v1.2.3");
expect(validateReleaseTag("v1.2.3-beta.4+build.5")).toBe("v1.2.3-beta.4+build.5");
expect(() => validateReleaseVersion("v1.2.3")).toThrow();
expect(() => validateReleaseVersion("1.2")).toThrow();
expect(() => validateReleaseTag("1.2.3")).toThrow();
expect(() => validateReleaseTag("v1.2.3; echo unsafe")).toThrow();
expect(() => validateReleaseTag("v01.2.3")).toThrow();
});
it("validates release values through environment variables before shell use", () => {
const publishExecutor = workflow("publish-executor-package.yml");
const release = workflow("release.yml");
const publishDesktop = workflow("publish-desktop.yml");
expect(publishExecutor).toContain(
"bun run scripts/validate-release-ref.ts --tag-env RAW_RELEASE_TAG --write-env RELEASE_TAG",
);
expect(release).toContain(
"bun run scripts/validate-release-ref.ts --version-env RELEASE_VERSION --output tag",
);
expect(publishDesktop).toContain(
"bun run scripts/validate-release-ref.ts --tag-env RAW_RELEASE_TAG --write-env RELEASE_TAG",
);
expect(release).not.toContain('tag="v${{ steps.detect_release.outputs.version }}"');
expect(publishDesktop).not.toContain("ref: refs/tags/${{ inputs.tag }}");
expect(publishDesktop).not.toContain('gh release download "${{ inputs.tag }}"');
expect(publishExecutor).not.toMatch(/\n\s+RELEASE_TAG: \$\{\{ github\.event_name/u);
});
it("does not persist checkout credentials in release workflows", () => {
for (const name of [
"publish-executor-package.yml",
"release.yml",
"publish-desktop.yml",
"pkg-pr-new.yml",
]) {
expect(workflow(name)).toContain("persist-credentials: false");
}
});
});