CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | /**
* Tests for src/lib/push-policy.ts.
*
* The DB-touching paths (matchProtectedTag, listRulesetsForRepo,
* canBypassProtectedTag) require a live DB; we don't have one in unit
* tests. Instead we cover:
*
* - The pure formatPolicyError formatter — exhaustive.
* - The fail-open guarantee on bad input (empty refs, missing repo id).
* - Module shape (imports don't throw, expected exports are present).
*
* Real end-to-end coverage of the policy decisions runs in the existing
* rulesets + protected-tags test suites (which exercise evaluatePush and
* matchGlob directly). This file verifies that the new wrapper preserves
* fail-open semantics, which is the property that protects production
* pushes from a Postgres hiccup.
*/
import { describe, it, expect } from "bun:test";
import {
evaluatePushPolicy,
formatPolicyError,
ZERO_SHA,
} from "../lib/push-policy";
describe("ZERO_SHA constant", () => {
it("is exactly 40 zeros", () => {
expect(ZERO_SHA).toBe("0000000000000000000000000000000000000000");
expect(ZERO_SHA.length).toBe(40);
});
});
describe("formatPolicyError", () => {
it("returns a generic message when violations is empty", () => {
expect(formatPolicyError([])).toBe("Push rejected by Gluecron policy.");
});
it("returns a generic message when violations is null/undefined", () => {
expect(formatPolicyError(null as any)).toBe(
"Push rejected by Gluecron policy."
);
expect(formatPolicyError(undefined as any)).toBe(
"Push rejected by Gluecron policy."
);
});
it("renders one violation as a bulleted list", () => {
const out = formatPolicyError(['tag "v1.0" is protected']);
expect(out).toContain("Push rejected by Gluecron policy:");
expect(out).toContain(' - tag "v1.0" is protected');
});
it("renders multiple violations on separate lines", () => {
const out = formatPolicyError([
'tag "v1.0" is protected',
'ruleset "no-prod-pushes" rule branch_name_pattern: blocked',
]);
const lines = out.trimEnd().split("\n");
expect(lines[0]).toBe("Push rejected by Gluecron policy:");
expect(lines[1]).toBe(' - tag "v1.0" is protected');
expect(lines[2]).toBe(
' - ruleset "no-prod-pushes" rule branch_name_pattern: blocked'
);
});
it("ends with a newline (so git surfaces the body cleanly)", () => {
expect(formatPolicyError(["one violation"]).endsWith("\n")).toBe(true);
});
});
describe("evaluatePushPolicy — fail-open on bad input", () => {
it("returns allowed=true for an empty refs list", async () => {
const r = await evaluatePushPolicy({
repositoryId: "repo-1",
refs: [],
pusherUserId: null,
});
expect(r.allowed).toBe(true);
expect(r.violations).toEqual([]);
});
it("returns allowed=true for missing repositoryId", async () => {
const r = await evaluatePushPolicy({
repositoryId: "" as any,
refs: [
{
oldSha: ZERO_SHA,
newSha: "a".repeat(40),
refName: "refs/tags/v1.0",
},
],
pusherUserId: null,
});
expect(r.allowed).toBe(true);
});
it("returns allowed=true when DB is unreachable (refs target a nonexistent repo)", async () => {
// No real repo exists with id "definitely-not-a-real-repo-id"; the
// matchProtectedTag + listRulesetsForRepo callers catch their own
// errors and return empty arrays, so the wrapper returns allowed.
const r = await evaluatePushPolicy({
repositoryId: "definitely-not-a-real-repo-id",
refs: [
{
oldSha: ZERO_SHA,
newSha: "a".repeat(40),
refName: "refs/heads/main",
},
],
pusherUserId: null,
});
expect(r.allowed).toBe(true);
});
});
describe("evaluatePushPolicy — module shape", () => {
it("exports the functions the route depends on", async () => {
const mod = await import("../lib/push-policy");
expect(typeof mod.evaluatePushPolicy).toBe("function");
expect(typeof mod.formatPolicyError).toBe("function");
expect(typeof mod.ZERO_SHA).toBe("string");
});
});
|