@fourteensystems/shipguard 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -59,7 +59,7 @@ shipguard explain AUTH-BOUNDARY-MISSING
59
59
  | Rule | Severity | What it catches |
60
60
  |------|----------|----------------|
61
61
  | AUTH-BOUNDARY-MISSING | critical | Mutation endpoints without auth checks |
62
- | RATE-LIMIT-MISSING | critical | Public API routes without rate limiting |
62
+ | RATE-LIMIT-MISSING | critical | API routes without rate limiting (auth-aware severity) |
63
63
  | TENANCY-SCOPE-MISSING | critical | Prisma queries without tenant scoping |
64
64
  | WRAPPER-UNRECOGNIZED | high | HOF wrappers that couldn't be verified for auth/rate-limit enforcement |
65
65
 
@@ -108,11 +108,13 @@ Shipguard auto-detects your stack and adjusts detection accordingly:
108
108
 
109
109
  ### What It Skips
110
110
 
111
- - Webhook routes (`/api/webhooks/*`) — exempt from rate-limit
111
+ - Webhook routes (any path containing `webhook`) — exempt from rate-limit
112
112
  - Cron routes (`/api/cron/*`) — exempt from rate-limit
113
+ - Framework-managed routes (NextAuth catch-all, OAuth/SAML endpoints, callbacks, OG images) — exempt from rate-limit
113
114
  - `GET`-only route handlers — not mutation surfaces
114
115
  - Routes covered by `middleware.ts` auth — no double-flagging
115
116
  - Routes wrapped by verified HOF wrappers (`withWorkspace(handler)` where auth+RL enforcement is proven)
117
+ - Authenticated routes get lower rate-limit severity (abuse requires stolen credentials)
116
118
 
117
119
  See [PATTERNS.md](../../PATTERNS.md) for full detection logic.
118
120
 
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit-missing.d.ts","sourceRoot":"","sources":["../../src/rules/rate-limit-missing.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAInE,eAAO,MAAM,OAAO,uBAAuB,CAAC;AAyB5C,wBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,EAAE,CAuExE"}
1
+ {"version":3,"file":"rate-limit-missing.d.ts","sourceRoot":"","sources":["../../src/rules/rate-limit-missing.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAInE,eAAO,MAAM,OAAO,uBAAuB,CAAC;AAsC5C,wBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,EAAE,CAoFxE"}
@@ -17,11 +17,23 @@ const EXEMPT_PATH_PATTERNS = [
17
17
  ];
18
18
  /**
19
19
  * Webhook path patterns — rate limiting is inappropriate for inbound webhooks.
20
- * The calling service controls the call rate, and rejecting would miss events.
20
+ * Matches any path containing "webhook" (e.g., /stripe-webhook, /webhooks/stripe).
21
21
  */
22
22
  const WEBHOOK_PATH_PATTERNS = [
23
- /\/webhooks?\//, // /webhook/ or /webhooks/
24
- /\/webhooks?$/, // /webhook or /webhooks (terminal)
23
+ /webhook/i,
24
+ ];
25
+ /**
26
+ * Framework-managed routes where rate limiting is handled by the framework
27
+ * or is inappropriate (auth protocol flows, external callbacks, OG images).
28
+ */
29
+ const FRAMEWORK_MANAGED_PATTERNS = [
30
+ /\/auth\/\[\.{3}[^\]]*\]/, // NextAuth catch-all: auth/[...nextauth], auth/[...params]
31
+ /\/callback\//, // Inbound callbacks from external services (OAuth, Stripe, Slack)
32
+ /\/callback$/, // Terminal callback path
33
+ /\/oauth\//, // OAuth protocol endpoints (token, userinfo, authorize)
34
+ /\/saml\//, // SAML SSO endpoints
35
+ /\/og\//, // OG image generation routes (stateless, CDN-cached)
36
+ /\/og$/, // Terminal OG path
25
37
  ];
26
38
  export function run(index, config) {
27
39
  const findings = [];
@@ -38,24 +50,36 @@ export function run(index, config) {
38
50
  // Skip tRPC proxy routes — rate limiting is checked at the procedure level
39
51
  if (index.trpc.detected && route.file === index.trpc.proxyFile)
40
52
  continue;
53
+ // Skip framework-managed routes (NextAuth, OAuth, SAML, callbacks, OG images)
54
+ if (isFrameworkManaged(route.pathname))
55
+ continue;
41
56
  const result = checkRoute(route, index, config);
42
57
  if (result) {
58
+ const isAuthed = route.protection?.auth.satisfied ?? false;
43
59
  findings.push({
44
60
  ruleId: RULE_ID,
45
61
  severity: capSeverity(result.severity, maxSeverity),
46
62
  confidence: result.confidence,
47
- message: `Public API route has no recognized rate limiting`,
63
+ message: isAuthed
64
+ ? `Authenticated API route has no recognized rate limiting`
65
+ : `Public API route has no recognized rate limiting`,
48
66
  file: route.file,
49
67
  line: result.line,
50
68
  snippet: result.snippet,
51
69
  evidence: result.evidence,
52
70
  confidenceRationale: result.confidenceRationale,
53
- remediation: [
54
- "Add rate limiting middleware or wrapper to this route",
55
- "If using @upstash/ratelimit, wrap the handler with a rate limit check",
56
- "If rate limiting is handled at the edge (Cloudflare, Vercel), add a waiver with reason",
57
- "Add custom wrapper names to hints.rateLimit.wrappers in config",
58
- ],
71
+ remediation: isAuthed
72
+ ? [
73
+ "Consider adding rate limiting as defense-in-depth",
74
+ "Authenticated routes are lower risk but can still be abused with stolen credentials",
75
+ "If rate limiting is at the edge (Cloudflare, Vercel WAF), add a waiver",
76
+ ]
77
+ : [
78
+ "Add rate limiting middleware or wrapper to this route",
79
+ "If using @upstash/ratelimit, wrap the handler with a rate limit check",
80
+ "If rate limiting is handled at the edge (Cloudflare, Vercel), add a waiver with reason",
81
+ "Add custom wrapper names to hints.rateLimit.wrappers in config",
82
+ ],
59
83
  tags: ["rate-limit", "server"],
60
84
  });
61
85
  }
@@ -119,32 +143,58 @@ function checkRoute(route, index, config) {
119
143
  // Routes with cron key auth are server-to-server (no rate limiting needed)
120
144
  if (hasCronKeyAuth(src))
121
145
  return null;
122
- // No rate limiting found
146
+ // Determine auth status for severity modulation
147
+ const isAuthed = route.protection?.auth.satisfied ?? false;
123
148
  const evidence = [];
124
- evidence.push(`No rate limit wrapper calls matched: ${config.hints.rateLimit.wrappers.join(", ")}`);
125
- evidence.push("No middleware-level rate limiting detected");
126
149
  let severity;
127
150
  let confidence;
128
151
  let confidenceRationale;
129
152
  const isMutation = route.signals.hasMutationEvidence || route.signals.hasDbWriteEvidence;
130
153
  if (isMutation) {
131
- severity = "critical";
132
- confidence = "high";
133
- confidenceRationale = "High: mutation route without rate limiting (higher abuse risk)";
134
- evidence.push("route performs mutations (higher abuse risk)");
135
- evidence.push(...route.signals.mutationDetails);
154
+ if (isAuthed) {
155
+ severity = "med";
156
+ confidence = "med";
157
+ confidenceRationale = "Medium: authenticated mutation route abuse requires stolen credentials";
158
+ evidence.push("route performs mutations");
159
+ evidence.push(...route.signals.mutationDetails);
160
+ evidence.push("route has auth boundary — rate limiting is secondary defense");
161
+ }
162
+ else {
163
+ severity = "critical";
164
+ confidence = "high";
165
+ confidenceRationale = "High: mutation route without rate limiting (higher abuse risk)";
166
+ evidence.push("route performs mutations (higher abuse risk)");
167
+ evidence.push(...route.signals.mutationDetails);
168
+ }
136
169
  }
137
170
  else if (hasBodyParsing(src)) {
138
- severity = "high";
139
- confidence = "high";
140
- confidenceRationale = "High: route reads request body without rate limiting";
141
- evidence.push("route reads request body");
171
+ if (isAuthed) {
172
+ severity = "low";
173
+ confidence = "low";
174
+ confidenceRationale = "Low: authenticated route with body parsing — abuse requires stolen credentials";
175
+ evidence.push("route reads request body");
176
+ evidence.push("route has auth boundary — rate limiting is secondary defense");
177
+ }
178
+ else {
179
+ severity = "high";
180
+ confidence = "high";
181
+ confidenceRationale = "High: route reads request body without rate limiting";
182
+ evidence.push("route reads request body");
183
+ }
142
184
  }
143
185
  else {
144
- severity = "med";
145
- confidence = "med";
146
- confidenceRationale = "Medium: public API route without rate limiting (GET-only, lower risk)";
147
- evidence.push("public API route without rate limiting");
186
+ if (isAuthed) {
187
+ severity = "low";
188
+ confidence = "low";
189
+ confidenceRationale = "Low: authenticated GET-only route rate limiting is good hygiene but low risk";
190
+ evidence.push("route has auth boundary — rate limiting is secondary defense");
191
+ }
192
+ else {
193
+ severity = "med";
194
+ confidence = "med";
195
+ confidenceRationale = "Medium: public API route without rate limiting (GET-only, lower risk)";
196
+ evidence.push("public API route without rate limiting");
197
+ }
148
198
  }
149
199
  return { severity, confidence, confidenceRationale, evidence };
150
200
  }
@@ -192,6 +242,11 @@ function isWebhookPath(pathname) {
192
242
  return false;
193
243
  return WEBHOOK_PATH_PATTERNS.some((p) => p.test(pathname));
194
244
  }
245
+ function isFrameworkManaged(pathname) {
246
+ if (!pathname)
247
+ return false;
248
+ return FRAMEWORK_MANAGED_PATTERNS.some((p) => p.test(pathname));
249
+ }
195
250
  function hasBodyParsing(src) {
196
251
  return /request\.json\s*\(|request\.formData\s*\(|req\.body/.test(src);
197
252
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit-missing.js","sourceRoot":"","sources":["../../src/rules/rate-limit-missing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rate-limit-missing.js","sourceRoot":"","sources":["../../src/rules/rate-limit-missing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rate-limit-missing.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-missing.test.d.ts","sourceRoot":"","sources":["../../src/rules/rate-limit-missing.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,325 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdirSync, writeFileSync, rmSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { run } from "./rate-limit-missing.js";
5
+ /* ------------------------------------------------------------------ */
6
+ /* Helpers */
7
+ /* ------------------------------------------------------------------ */
8
+ const NO_SIGNALS = {
9
+ hasMutationEvidence: false,
10
+ hasDbWriteEvidence: false,
11
+ hasStripeWriteEvidence: false,
12
+ mutationDetails: [],
13
+ };
14
+ const MUTATION_SIGNALS = {
15
+ hasMutationEvidence: true,
16
+ hasDbWriteEvidence: true,
17
+ hasStripeWriteEvidence: false,
18
+ mutationDetails: ["prisma.create"],
19
+ };
20
+ function protectionSummary(opts) {
21
+ return {
22
+ auth: {
23
+ satisfied: opts.authSatisfied ?? false,
24
+ enforced: false,
25
+ sources: opts.authSatisfied ? ["direct"] : [],
26
+ details: [],
27
+ unverifiedWrappers: [],
28
+ },
29
+ rateLimit: {
30
+ satisfied: opts.rlSatisfied ?? false,
31
+ enforced: false,
32
+ sources: [],
33
+ details: [],
34
+ unverifiedWrappers: opts.unverifiedWrappers ?? [],
35
+ },
36
+ };
37
+ }
38
+ let tmpDir;
39
+ beforeEach(() => {
40
+ tmpDir = path.join("/tmp", `shipguard-rl-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
41
+ mkdirSync(tmpDir, { recursive: true });
42
+ });
43
+ afterEach(() => {
44
+ rmSync(tmpDir, { recursive: true, force: true });
45
+ });
46
+ /** Create a route file on disk and return a NextRoute pointing to it */
47
+ function createRoute(relPath, source, overrides = {}) {
48
+ const fullPath = path.join(tmpDir, relPath);
49
+ mkdirSync(path.dirname(fullPath), { recursive: true });
50
+ writeFileSync(fullPath, source);
51
+ const pathname = "/" + relPath
52
+ .replace(/\/route\.(ts|tsx|js|jsx)$/, "")
53
+ .replace(/^app\//, "");
54
+ return {
55
+ kind: "route-handler",
56
+ file: relPath,
57
+ isApi: pathname.startsWith("/api/") || pathname === "/api",
58
+ isPublic: true,
59
+ pathname,
60
+ signals: NO_SIGNALS,
61
+ protection: protectionSummary({}),
62
+ ...overrides,
63
+ };
64
+ }
65
+ function makeIndex(routes) {
66
+ return {
67
+ version: 1,
68
+ framework: "next-app-router",
69
+ rootDir: tmpDir,
70
+ deps: {
71
+ hasNextAuth: false, hasClerk: false, hasSupabase: false,
72
+ hasKinde: false, hasWorkOS: false, hasBetterAuth: false,
73
+ hasLucia: false, hasAuth0: false, hasIronSession: false,
74
+ hasFirebaseAuth: false, hasUpstashRatelimit: false, hasArcjet: false,
75
+ hasUnkey: false, hasPrisma: false, hasDrizzle: false, hasTrpc: false,
76
+ },
77
+ hints: {
78
+ auth: { functions: ["auth"], middlewareFiles: [], allowlistPaths: [] },
79
+ rateLimit: { wrappers: ["rateLimit"], allowlistPaths: [] },
80
+ tenancy: { orgFieldNames: [] },
81
+ },
82
+ middleware: { authLikely: false, rateLimitLikely: false, matcherPatterns: [] },
83
+ wrappers: { wrappers: new Map() },
84
+ routes: { all: routes, mutationRoutes: routes.filter(r => r.signals.hasMutationEvidence) },
85
+ serverActions: { all: [], mutationActions: [] },
86
+ trpc: { detected: false, procedures: [], mutationProcedures: [] },
87
+ };
88
+ }
89
+ function makeConfig(overrides = {}) {
90
+ return {
91
+ framework: "next-app-router",
92
+ include: ["app/**"],
93
+ exclude: [],
94
+ ci: { failOn: "critical", minConfidence: "high", minScore: 70, maxNewCritical: 0 },
95
+ scoring: { start: 100, penalties: { critical: 25, high: 10, med: 3, low: 1 } },
96
+ hints: {
97
+ auth: { functions: ["auth"], middlewareFiles: [], allowlistPaths: [] },
98
+ rateLimit: { wrappers: ["rateLimit"], allowlistPaths: [] },
99
+ tenancy: { orgFieldNames: [] },
100
+ },
101
+ rules: { "RATE-LIMIT-MISSING": { severity: "critical" } },
102
+ waiversFile: "shipguard.waivers.json",
103
+ ...overrides,
104
+ };
105
+ }
106
+ const BASIC_HANDLER = `export async function GET(request: Request) { return Response.json({ ok: true }); }`;
107
+ const MUTATION_HANDLER = `export async function POST(request: Request) {
108
+ const body = await request.json();
109
+ await prisma.user.create({ data: body });
110
+ return Response.json({ ok: true });
111
+ }`;
112
+ const BODY_HANDLER = `export async function POST(request: Request) {
113
+ const body = await request.json();
114
+ return Response.json({ received: true });
115
+ }`;
116
+ /* ------------------------------------------------------------------ */
117
+ /* Framework-managed exemptions */
118
+ /* ------------------------------------------------------------------ */
119
+ describe("framework-managed route exemptions", () => {
120
+ const config = makeConfig();
121
+ it("exempts NextAuth catch-all route", () => {
122
+ const route = createRoute("app/api/auth/[...nextauth]/route.ts", BASIC_HANDLER);
123
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
124
+ });
125
+ it("exempts NextAuth with different param name", () => {
126
+ const route = createRoute("app/api/auth/[...params]/route.ts", BASIC_HANDLER);
127
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
128
+ });
129
+ it("exempts OAuth token endpoint", () => {
130
+ const route = createRoute("app/api/oauth/token/route.ts", BASIC_HANDLER);
131
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
132
+ });
133
+ it("exempts SAML callback route", () => {
134
+ const route = createRoute("app/api/auth/saml/callback/route.ts", BASIC_HANDLER);
135
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
136
+ });
137
+ it("exempts callback routes from external services", () => {
138
+ const route = createRoute("app/api/callback/stripe/route.ts", BASIC_HANDLER);
139
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
140
+ });
141
+ it("exempts nested callback routes", () => {
142
+ const route = createRoute("app/api/slack/callback/route.ts", BASIC_HANDLER, {
143
+ pathname: "/api/slack/callback",
144
+ });
145
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
146
+ });
147
+ it("exempts OG image routes", () => {
148
+ const route = createRoute("app/api/og/analytics/route.tsx", BASIC_HANDLER);
149
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
150
+ });
151
+ it("exempts terminal OG path", () => {
152
+ const route = createRoute("app/api/og/route.tsx", BASIC_HANDLER, {
153
+ pathname: "/api/og",
154
+ });
155
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
156
+ });
157
+ it("does NOT exempt regular API routes", () => {
158
+ const route = createRoute("app/api/users/route.ts", BASIC_HANDLER);
159
+ const findings = run(makeIndex([route]), config);
160
+ expect(findings).toHaveLength(1);
161
+ });
162
+ });
163
+ /* ------------------------------------------------------------------ */
164
+ /* Improved webhook detection */
165
+ /* ------------------------------------------------------------------ */
166
+ describe("webhook path detection", () => {
167
+ const config = makeConfig();
168
+ it("exempts /webhook path", () => {
169
+ const route = createRoute("app/api/webhook/route.ts", BASIC_HANDLER, {
170
+ pathname: "/api/webhook",
171
+ });
172
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
173
+ });
174
+ it("exempts compound webhook path like /stripe-webhook", () => {
175
+ const route = createRoute("app/api/billing/stripe-webhook/route.ts", BASIC_HANDLER, {
176
+ pathname: "/api/billing/stripe-webhook",
177
+ });
178
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
179
+ });
180
+ it("exempts /webhooks/stripe nested path", () => {
181
+ const route = createRoute("app/api/webhooks/stripe/route.ts", BASIC_HANDLER, {
182
+ pathname: "/api/webhooks/stripe",
183
+ });
184
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
185
+ });
186
+ });
187
+ /* ------------------------------------------------------------------ */
188
+ /* Existing exemptions still work */
189
+ /* ------------------------------------------------------------------ */
190
+ describe("existing exemptions", () => {
191
+ const config = makeConfig();
192
+ it("exempts health check routes", () => {
193
+ const route = createRoute("app/api/health/route.ts", BASIC_HANDLER, {
194
+ pathname: "/api/health",
195
+ });
196
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
197
+ });
198
+ it("exempts cron routes", () => {
199
+ const route = createRoute("app/api/cron/daily/route.ts", BASIC_HANDLER, {
200
+ pathname: "/api/cron/daily",
201
+ });
202
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
203
+ });
204
+ it("skips non-API routes", () => {
205
+ const route = createRoute("app/dashboard/route.ts", BASIC_HANDLER, {
206
+ pathname: "/dashboard",
207
+ isApi: false,
208
+ });
209
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
210
+ });
211
+ it("skips routes with rate-limit protection satisfied", () => {
212
+ const route = createRoute("app/api/users/route.ts", BASIC_HANDLER, {
213
+ protection: protectionSummary({ rlSatisfied: true }),
214
+ });
215
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
216
+ });
217
+ it("defers to WRAPPER-UNRECOGNIZED for unverified wrappers", () => {
218
+ const route = createRoute("app/api/users/route.ts", BASIC_HANDLER, {
219
+ protection: protectionSummary({ unverifiedWrappers: ["withCustom"] }),
220
+ });
221
+ expect(run(makeIndex([route]), config)).toHaveLength(0);
222
+ });
223
+ });
224
+ /* ------------------------------------------------------------------ */
225
+ /* Auth-aware severity: public routes (unchanged behavior) */
226
+ /* ------------------------------------------------------------------ */
227
+ describe("severity: public routes (no auth)", () => {
228
+ const config = makeConfig();
229
+ it("public mutation route → critical/high", () => {
230
+ const route = createRoute("app/api/users/route.ts", MUTATION_HANDLER, {
231
+ signals: MUTATION_SIGNALS,
232
+ protection: protectionSummary({ authSatisfied: false }),
233
+ });
234
+ const findings = run(makeIndex([route]), config);
235
+ expect(findings).toHaveLength(1);
236
+ expect(findings[0].severity).toBe("critical");
237
+ expect(findings[0].confidence).toBe("high");
238
+ });
239
+ it("public body-parsing route → high/high", () => {
240
+ const route = createRoute("app/api/upload/route.ts", BODY_HANDLER, {
241
+ protection: protectionSummary({ authSatisfied: false }),
242
+ });
243
+ const findings = run(makeIndex([route]), config);
244
+ expect(findings).toHaveLength(1);
245
+ expect(findings[0].severity).toBe("high");
246
+ expect(findings[0].confidence).toBe("high");
247
+ });
248
+ it("public GET-only route → med/med", () => {
249
+ const route = createRoute("app/api/data/route.ts", BASIC_HANDLER, {
250
+ protection: protectionSummary({ authSatisfied: false }),
251
+ });
252
+ const findings = run(makeIndex([route]), config);
253
+ expect(findings).toHaveLength(1);
254
+ expect(findings[0].severity).toBe("med");
255
+ expect(findings[0].confidence).toBe("med");
256
+ });
257
+ });
258
+ /* ------------------------------------------------------------------ */
259
+ /* Auth-aware severity: authed routes (new behavior) */
260
+ /* ------------------------------------------------------------------ */
261
+ describe("severity: authenticated routes", () => {
262
+ const config = makeConfig();
263
+ it("authed mutation route → med/med (downgraded from critical)", () => {
264
+ const route = createRoute("app/api/users/route.ts", MUTATION_HANDLER, {
265
+ signals: MUTATION_SIGNALS,
266
+ protection: protectionSummary({ authSatisfied: true }),
267
+ });
268
+ const findings = run(makeIndex([route]), config);
269
+ expect(findings).toHaveLength(1);
270
+ expect(findings[0].severity).toBe("med");
271
+ expect(findings[0].confidence).toBe("med");
272
+ expect(findings[0].evidence).toContain("route has auth boundary — rate limiting is secondary defense");
273
+ });
274
+ it("authed body-parsing route → low/low (downgraded from high)", () => {
275
+ const route = createRoute("app/api/upload/route.ts", BODY_HANDLER, {
276
+ protection: protectionSummary({ authSatisfied: true }),
277
+ });
278
+ const findings = run(makeIndex([route]), config);
279
+ expect(findings).toHaveLength(1);
280
+ expect(findings[0].severity).toBe("low");
281
+ expect(findings[0].confidence).toBe("low");
282
+ });
283
+ it("authed GET-only route → low/low (downgraded from med)", () => {
284
+ const route = createRoute("app/api/data/route.ts", BASIC_HANDLER, {
285
+ protection: protectionSummary({ authSatisfied: true }),
286
+ });
287
+ const findings = run(makeIndex([route]), config);
288
+ expect(findings).toHaveLength(1);
289
+ expect(findings[0].severity).toBe("low");
290
+ expect(findings[0].confidence).toBe("low");
291
+ expect(findings[0].evidence).toContain("route has auth boundary — rate limiting is secondary defense");
292
+ });
293
+ it("authed route gets different message and remediation than public", () => {
294
+ const authedRoute = createRoute("app/api/data/route.ts", BASIC_HANDLER, {
295
+ protection: protectionSummary({ authSatisfied: true }),
296
+ });
297
+ const publicRoute = createRoute("app/api/other/route.ts", BASIC_HANDLER, {
298
+ protection: protectionSummary({ authSatisfied: false }),
299
+ });
300
+ const authedFindings = run(makeIndex([authedRoute]), config);
301
+ const publicFindings = run(makeIndex([publicRoute]), config);
302
+ expect(authedFindings[0].message).toContain("Authenticated");
303
+ expect(publicFindings[0].message).toContain("Public");
304
+ expect(authedFindings[0].remediation).not.toEqual(publicFindings[0].remediation);
305
+ });
306
+ });
307
+ /* ------------------------------------------------------------------ */
308
+ /* Severity cap */
309
+ /* ------------------------------------------------------------------ */
310
+ describe("severity cap", () => {
311
+ it("caps severity at rule max from config", () => {
312
+ const config = makeConfig({
313
+ rules: { "RATE-LIMIT-MISSING": { severity: "high" } },
314
+ });
315
+ const route = createRoute("app/api/users/route.ts", MUTATION_HANDLER, {
316
+ signals: MUTATION_SIGNALS,
317
+ protection: protectionSummary({ authSatisfied: false }),
318
+ });
319
+ const findings = run(makeIndex([route]), config);
320
+ expect(findings).toHaveLength(1);
321
+ // Would be critical but capped to high
322
+ expect(findings[0].severity).toBe("high");
323
+ });
324
+ });
325
+ //# sourceMappingURL=rate-limit-missing.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-missing.test.js","sourceRoot":"","sources":["../../src/rules/rate-limit-missing.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fourteensystems/shipguard",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "CI guardrail that blocks unprotected mutation routes in Next.js SaaS",
5
5
  "type": "module",
6
6
  "bin": {