Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
Commit6ae664d

test: assert guards are CALLED, not merely mentioned

test: assert guards are CALLED, not merely mentioned

Fixing the weakness found while fault-injecting the AI quota work:
`expect(src).toContain("someGuard")` is satisfied by `void someGuard;`,
which mentions the guard while calling nothing. Every source-level
assertion written during this audit used that form, so each of the guards
shipped this session could have been removed and its regression test
would still have passed.

Tightened to require the call form across six files — canReadPackage,
canReadRepoPackages, isRepoMember, canScimManageAccount,
recordedSubscriptionScope, bumpUsage, invalidateQuotaCache,
resetIfCycleExpired, parseReceivePackRefs, gunzipBounded — plus
from(orgMembers) for the membership lookup.

Left bare deliberately, where bare is correct: `gunzipSync` is an ABSENCE
assertion and the loose form is the strong one there; `budget_exceeded`
is a string literal; `aiTokensUsedThisMonth` is a column name; and
`scimProvisionedByOrgId` is a property, already pinned by an adjacent
assertion on the assignment form and an occurrence count.

Proven, not assumed. Replacing the npm registry's read gate with `void
canReadPackage;` now fails package-access; before this commit it passed,
meaning the private-package leak could have been reintroduced silently.
Same for stripe-subscription-scope with the scope argument neutered.
Source restored after each injection — the diff is tests only.

Suite: 3504 pass, 0 fail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ccantynz-alt committed on July 29, 2026Parent: 68eccaa
6 files changed+31316ae664d6e50e18382c3a7851b30c39cba42473f5
6 changed files+31−31
Modifiedsrc/__tests__/ai-quota-metering.test.ts+6−6View fileUnifiedSplit
137137 });
138138
139139 it("bumps the column the enforcement path actually reads", () => {
140 expect(src).toContain("bumpUsage");
140 expect(src).toContain("bumpUsage(");
141141 expect(src).toContain("aiTokensUsedThisMonth");
142142 });
143143
145145 // Otherwise a burst of calls keeps reusing a stale allow until the cache
146146 // expires and sails past the cap.
147147 const meter = slice(src, "async function meterAiQuota", "export interface");
148 expect(meter).toContain("invalidateQuotaCache");
149 expect(meter.indexOf("bumpUsage")).toBeLessThan(
150 meter.indexOf("invalidateQuotaCache")
148 expect(meter).toContain("invalidateQuotaCache(");
149 expect(meter.indexOf("bumpUsage(")).toBeLessThan(
150 meter.indexOf("invalidateQuotaCache(")
151151 );
152152 });
153153});
161161 "export async function checkAiQuotaCached",
162162 "export function invalidateQuotaCache"
163163 );
164 expect(body).toContain("resetIfCycleExpired");
165 expect(body.indexOf("resetIfCycleExpired")).toBeLessThan(
164 expect(body).toContain("resetIfCycleExpired(");
165 expect(body.indexOf("resetIfCycleExpired(")).toBeLessThan(
166166 body.indexOf("getUserQuota(userId)")
167167 );
168168 });
Modifiedsrc/__tests__/bounded-gunzip.test.ts+4−4View fileUnifiedSplit
146146
147147 it("checks write access before any decompression", () => {
148148 const gateAt = handler.indexOf(`satisfiesAccess(access, "write")`);
149 const gunzipAt = handler.indexOf("gunzipBounded");
149 const gunzipAt = handler.indexOf("gunzipBounded(");
150150 expect(gunzipAt).toBeGreaterThan(-1);
151151 expect(gateAt).toBeLessThan(gunzipAt);
152152 });
158158 it("still parses refs, so policy and post-receive keep working", () => {
159159 // The reorder moved the body read; it must not have dropped ref parsing,
160160 // or pushes would silently skip the policy gate and the hook.
161 expect(handler).toContain("parseReceivePackRefs");
162 const gunzipAt = handler.indexOf("gunzipBounded");
163 expect(handler.indexOf("parseReceivePackRefs")).toBeGreaterThan(gunzipAt);
161 expect(handler).toContain("parseReceivePackRefs(");
162 const gunzipAt = handler.indexOf("gunzipBounded(");
163 expect(handler.indexOf("parseReceivePackRefs(")).toBeGreaterThan(gunzipAt);
164164 });
165165});
Modifiedsrc/__tests__/org-team-roster.test.ts+1−1View fileUnifiedSplit
9595 })();
9696
9797 it("looks the viewer up in orgMembers", () => {
98 expect(handler).toContain("orgMembers");
98 expect(handler).toContain("from(orgMembers)");
9999 expect(handler).toContain("eq(orgMembers.userId, user.id)");
100100 });
101101
Modifiedsrc/__tests__/package-access.test.ts+8−8View fileUnifiedSplit
150150 });
151151});
152152
153describe("isRepoMember", () => {
153describe("isRepoMember(", () => {
154154 it("is false for anonymous even on a public repo", async () => {
155155 // Membership is not the same as readability — a public reader is not a
156156 // member, which is what decides visibility of private packages.
198198 it("GET /npm/ checks canReadPackage before serving", async () => {
199199 const src = sourceWithoutLineComments("routes/packages-api.ts");
200200 const body = handlerBody(src, `api.get("/npm/*"`, `api.put("/npm/*"`);
201 expect(body).toContain("canReadPackage");
201 expect(body).toContain("canReadPackage(");
202202 // The tarball branch lives inside this handler, so gating the handler
203203 // gates the tarball too — assert the gate precedes the tarball read.
204 const gateAt = body.indexOf("canReadPackage");
204 const gateAt = body.indexOf("canReadPackage(");
205205 const tarballAt = body.indexOf("match.tarball");
206206 expect(tarballAt).toBeGreaterThan(gateAt);
207207 });
213213 `api.get("/api/packages/:owner/:repo"`,
214214 `api.get("/api/packages/:owner/:repo/:pkgName`
215215 );
216 expect(listBody).toContain("canReadRepoPackages");
217 expect(listBody).toContain("isRepoMember");
216 expect(listBody).toContain("canReadRepoPackages(");
217 expect(listBody).toContain("isRepoMember(");
218218
219219 const detailBody = handlerBody(
220220 src,
221221 `api.get("/api/packages/:owner/:repo/:pkgName`,
222222 `api.get("/npm/*"`
223223 );
224 expect(detailBody).toContain("canReadRepoPackages");
224 expect(detailBody).toContain("canReadRepoPackages(");
225225 });
226226
227227 it("the package UI routes filter private packages for non-members", async () => {
231231 `ui.get("/:owner/:repo/packages"`,
232232 `ui.get("/:owner/:repo/packages/:pkgName`
233233 );
234 expect(listBody).toContain("isRepoMember");
234 expect(listBody).toContain("isRepoMember(");
235235 // The rendered rows must come from the filtered list, not the raw query.
236236 expect(listBody).toContain("visiblePkgs.map");
237237 expect(listBody).not.toContain("rows = pkgs.map");
241241 `ui.get("/:owner/:repo/packages/:pkgName`,
242242 "export default"
243243 );
244 expect(detailBody).toContain("isRepoMember");
244 expect(detailBody).toContain("isRepoMember(");
245245 });
246246});
Modifiedsrc/__tests__/scim-account-scope.test.ts+7−7View fileUnifiedSplit
134134 `scim.patch("/scim/v2/:orgId/Users/:userId"`
135135 );
136136 expect(body).toContain(DEPROVISION_MARKER);
137 expect(body).toContain("canScimManageAccount");
138 expect(body.indexOf("canScimManageAccount")).toBeLessThan(
137 expect(body).toContain("canScimManageAccount(");
138 expect(body.indexOf("canScimManageAccount(")).toBeLessThan(
139139 body.indexOf(DEPROVISION_MARKER)
140140 );
141141 });
147147 `scim.delete("/scim/v2/:orgId/Users/:userId"`
148148 );
149149 expect(body).toContain(DEPROVISION_MARKER);
150 expect(body).toContain("canScimManageAccount");
151 expect(body.indexOf("canScimManageAccount")).toBeLessThan(
150 expect(body).toContain("canScimManageAccount(");
151 expect(body.indexOf("canScimManageAccount(")).toBeLessThan(
152152 body.indexOf(DEPROVISION_MARKER)
153153 );
154154 });
160160 `scim.get("/scim/v2/:orgId/ServiceProviderConfig"`
161161 );
162162 expect(body).toContain(DEPROVISION_MARKER);
163 expect(body).toContain("canScimManageAccount");
164 expect(body.indexOf("canScimManageAccount")).toBeLessThan(
163 expect(body).toContain("canScimManageAccount(");
164 expect(body.indexOf("canScimManageAccount(")).toBeLessThan(
165165 body.indexOf(DEPROVISION_MARKER)
166166 );
167167 // Membership removal stays unconditional — that IS the deprovision.
168168 expect(body).toContain("delete(orgMembers)");
169169 expect(body.indexOf("delete(orgMembers)")).toBeLessThan(
170 body.indexOf("canScimManageAccount")
170 body.indexOf("canScimManageAccount(")
171171 );
172172 });
173173
Modifiedsrc/__tests__/stripe-subscription-scope.test.ts+5−5View fileUnifiedSplit
6666 .map((l) => l.value)
6767 .join(" ");
6868
69describe("recordedSubscriptionScope", () => {
69describe("recordedSubscriptionScope(", () => {
7070 it("returns no constraint when the event names no subscription", () => {
7171 // A one-off invoice has no subscription; the customer match is all
7272 // there is to go on, so the caller must not be over-constrained.
136136 `case "invoice.payment_failed"`
137137 );
138138 expect(body).toContain('planSlug: "free"');
139 expect(body).toContain("recordedSubscriptionScope");
140 expect(body.indexOf("recordedSubscriptionScope")).toBeGreaterThan(
139 expect(body).toContain("recordedSubscriptionScope(");
140 expect(body.indexOf("recordedSubscriptionScope(")).toBeGreaterThan(
141141 body.indexOf("stripeCustomerId, customerId")
142142 );
143143 });
145145 it("invoice.payment_failed scopes the past_due flag", () => {
146146 const body = slice(`case "invoice.payment_failed"`, "default:");
147147 expect(body).toContain('stripeSubscriptionStatus: "past_due"');
148 expect(body).toContain("recordedSubscriptionScope");
148 expect(body).toContain("recordedSubscriptionScope(");
149149 });
150150
151151 it("reconcileSubscription scopes its non-active write", () => {
152152 const body = slice("async function reconcileSubscription", "if (!slug)");
153153 expect(body).toContain("stripeSubscriptionId: sub.id");
154 expect(body).toContain("recordedSubscriptionScope");
154 expect(body).toContain("recordedSubscriptionScope(");
155155 });
156156
157157 it("leaves exactly one unscoped update — the active-upgrade path", () => {
158158