ai-saas-guard 0.35.1 → 0.37.0
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 +11 -9
- package/dist/hosted/contracts.js +17 -12
- package/dist/report/launchGate.d.ts +4 -0
- package/dist/report/launchGate.js +41 -0
- package/dist/report/markdown.js +22 -1
- package/dist/report/summary.js +5 -1
- package/docs/README.zh-CN.md +8 -8
- package/docs/case-study-ai-saas.md +38 -0
- package/docs/github-action.md +45 -3
- package/docs/npm-publishing.md +3 -3
- package/docs/positioning.md +26 -0
- package/docs/project-handoff.md +2 -0
- package/docs/sample-launch-report.md +9 -1
- package/hosted/cloudflare-worker/src/index.js +7 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,6 +37,8 @@ Start with the 30-second copy-paste demo: `npx ai-saas-guard@latest demo --summa
|
|
|
37
37
|
npx ai-saas-guard@latest scan --root /path/to/your-saas --summary
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
For AI-heavy PRs, run it in GitHub Actions to turn auth, billing, data, deploy, and test changes into a reviewer queue before merge.
|
|
41
|
+
|
|
40
42
|
The output is meant to answer three practical questions before you invite users:
|
|
41
43
|
|
|
42
44
|
- **Can a real user get access they should not have?** Check auth, tenant ownership, Supabase RLS, and Stripe entitlement paths first.
|
|
@@ -146,7 +148,7 @@ One command returns a launch-readiness report with:
|
|
|
146
148
|
- why the finding matters for an AI-built SaaS launch
|
|
147
149
|
- manual verification steps you can actually run
|
|
148
150
|
- practical fix direction, not generic advice
|
|
149
|
-
- short `--summary`, terminal, JSON, SARIF, and PR markdown output for local review or CI
|
|
151
|
+
- launch decision queue, ranking explanation, trust statement, short `--summary`, terminal, JSON, SARIF, and PR markdown output for local review or CI
|
|
150
152
|
|
|
151
153
|
## Problems It Helps You Catch
|
|
152
154
|
|
|
@@ -231,19 +233,19 @@ The CLI is published on npm as `ai-saas-guard`, and the GitHub Action is availab
|
|
|
231
233
|
| Area | Status |
|
|
232
234
|
| --- | --- |
|
|
233
235
|
| Public GitHub repository | Available |
|
|
234
|
-
| npm CLI | `ai-saas-guard@0.
|
|
235
|
-
| GitHub Action | `zr9959/ai-saas-guard@v0` or fixed tag `v0.
|
|
236
|
-
| Outputs |
|
|
236
|
+
| npm CLI | `ai-saas-guard@0.37.0` |
|
|
237
|
+
| GitHub Action | `zr9959/ai-saas-guard@v0` or fixed tag `v0.37.0` |
|
|
238
|
+
| Outputs | Launch decision queue, short summary, terminal, JSON, SARIF, and PR-focused markdown |
|
|
237
239
|
| Project config | `.ai-saas-guard.json` rule toggles, severity overrides, suppressions, and fail thresholds |
|
|
238
240
|
| Privacy model | Local-first, read-only scan commands, no LLM calls, no code upload |
|
|
239
|
-
| Versioned Action tags | `v0.
|
|
240
|
-
| Current release | `0.
|
|
241
|
+
| Versioned Action tags | `v0.37.0`, `v0` |
|
|
242
|
+
| Current release | `0.37.0` makes the GitHub Action path easier to copy into PR workflows, improves Check Run wording around the launch-risk middle layer, and keeps README first-screen guidance focused on AI-heavy PR review |
|
|
241
243
|
| npm publishing | Trusted Publisher/OIDC, no long-lived publish token |
|
|
242
244
|
| Repository trust hardening | Strict branch protection, Dependabot, CodeQL, fast-check fuzzing, signed release provenance assets, private vulnerability reporting, secret scanning, and push protection |
|
|
243
245
|
| Cloudflare hosted ingress | Deployed at `https://ai-saas-guard-hosted.zr9959.workers.dev`; signed GitHub App webhook delivery and compact Check Run smoke now pass in staging |
|
|
244
246
|
| Hosted GitHub App staging | Private App `ai-saas-guard-hosted` (`3834787`) installed on `zr9959/ai-saas-guard`; hosted operations evidence is in [docs/hosted-operations-evidence.md](docs/hosted-operations-evidence.md) |
|
|
245
247
|
| OpenSSF Best Practices | Passing badge, project `12955`; `.bestpractices.json` remains the conservative evidence record |
|
|
246
|
-
|
|
|
248
|
+
| Previous roadmap | v0.36.0 plan is tracked in [docs/v0.36-roadmap.md](docs/v0.36-roadmap.md) |
|
|
247
249
|
|
|
248
250
|
## Example Finding
|
|
249
251
|
|
|
@@ -297,7 +299,7 @@ AI-generated PRs often combine unrelated work:
|
|
|
297
299
|
- suggested PR split
|
|
298
300
|
- required tests or manual verification
|
|
299
301
|
- explicit git-diff diagnostics when a base ref or shallow checkout prevents PR classification
|
|
300
|
-
- PR-focused markdown for GitHub step summaries or PR comments
|
|
302
|
+
- PR-focused markdown with launch decision queue, reviewer checklist, ranking explanation, and suggested split for GitHub step summaries or PR comments
|
|
301
303
|
|
|
302
304
|
```bash
|
|
303
305
|
node dist/cli.js pr-risk --root /path/to/your-saas --base origin/main --json
|
|
@@ -415,7 +417,7 @@ Use `suppressions` for narrower false-positive handling when one rule is noisy o
|
|
|
415
417
|
|
|
416
418
|
## GitHub Action
|
|
417
419
|
|
|
418
|
-
The repo includes a composite Action. Use `v0` for the latest compatible pre-1.0 Action, a specific release tag such as `v0.
|
|
420
|
+
The repo includes a composite Action. Use `v0` for the latest compatible pre-1.0 Action, a specific release tag such as `v0.37.0` for controlled upgrades, or pin a reviewed commit SHA for stricter supply-chain control:
|
|
419
421
|
|
|
420
422
|
```yaml
|
|
421
423
|
name: ai-saas-guard
|
package/dist/hosted/contracts.js
CHANGED
|
@@ -485,7 +485,7 @@ export function createHostedCheckRunSummary(input) {
|
|
|
485
485
|
conclusion,
|
|
486
486
|
output: {
|
|
487
487
|
title: formatCheckRunTitle(totalFindings, conclusion, input.failOnSeverity),
|
|
488
|
-
summary: `Launch gate: ${launchGate}. Review first: What changed at the launch boundary? Manual proof required before release
|
|
488
|
+
summary: `Launch-risk gate: ${launchGate}. Launch gate: ${launchGate}. Review first: What changed at the launch boundary? Manual proof required before release. This is not an AI reviewer and not a full security audit, pentest, or certification.`,
|
|
489
489
|
text: truncateMarkdown(formatCheckRunMarkdown(report, conclusion, localCliCommand, launchGate), input.maxMarkdownChars)
|
|
490
490
|
},
|
|
491
491
|
annotations: report.evidence.slice(0, MAX_CHECK_RUN_ANNOTATIONS).map((finding) => {
|
|
@@ -1146,21 +1146,31 @@ function formatCheckRunMarkdown(report, conclusion, localCliCommand, launchGate)
|
|
|
1146
1146
|
...report.evidence.map((finding) => `| ${escapeMarkdownTableCell(finding.severity)} | ${escapeMarkdownTableCell(finding.ruleId)} | ${escapeMarkdownTableCell(formatFindingLocation(finding))} |`)
|
|
1147
1147
|
];
|
|
1148
1148
|
return [
|
|
1149
|
-
"### AI SaaS Guard",
|
|
1149
|
+
"### AI SaaS Guard Launch-risk gate",
|
|
1150
1150
|
"",
|
|
1151
|
-
"Review first: verify findings locally before launch.
|
|
1151
|
+
"Review first: verify findings locally before launch or merge. Not an AI reviewer or full security audit.",
|
|
1152
1152
|
"",
|
|
1153
1153
|
`Launch gate: ${launchGate}`,
|
|
1154
1154
|
`Conclusion: ${conclusion}`,
|
|
1155
1155
|
`Local CLI: \`${localCliCommand}\``,
|
|
1156
|
-
`Retention: compact report ${report.retentionDays} days; raw source,
|
|
1157
|
-
"",
|
|
1158
|
-
"Summary:",
|
|
1159
|
-
...severityOrder.map((severity) => `- ${capitalize(severity)}: ${report.summaryCounts[severity] ?? 0}`),
|
|
1156
|
+
`Retention: compact report ${report.retentionDays} days; no raw source, diffs, secrets, or customer payloads.`,
|
|
1160
1157
|
"",
|
|
1161
1158
|
"Review categories:",
|
|
1162
1159
|
...(categories.length === 0 ? ["- None"] : categories.map((category) => `- ${category}`)),
|
|
1163
1160
|
"",
|
|
1161
|
+
"Verification steps:",
|
|
1162
|
+
"- Review listed files before release or merge.",
|
|
1163
|
+
"- Reproduce locally with the CLI command above.",
|
|
1164
|
+
"- Confirm behavior with app-specific tests.",
|
|
1165
|
+
"",
|
|
1166
|
+
"Launch decision queue:",
|
|
1167
|
+
"- Can a real user get access they should not have?",
|
|
1168
|
+
"- Can the app claim success when something failed?",
|
|
1169
|
+
"- Can launch infrastructure do too much damage?",
|
|
1170
|
+
"",
|
|
1171
|
+
"Summary:",
|
|
1172
|
+
...severityOrder.map((severity) => `- ${capitalize(severity)}: ${report.summaryCounts[severity] ?? 0}`),
|
|
1173
|
+
"",
|
|
1164
1174
|
"Files to review first:",
|
|
1165
1175
|
...(filesToReview.length === 0 ? ["- None"] : filesToReview.map((file) => `- ${file}`)),
|
|
1166
1176
|
"",
|
|
@@ -1169,11 +1179,6 @@ function formatCheckRunMarkdown(report, conclusion, localCliCommand, launchGate)
|
|
|
1169
1179
|
"- Why this auth billing data or deploy decision is safe?",
|
|
1170
1180
|
"- What manual test proves it fails closed?",
|
|
1171
1181
|
"",
|
|
1172
|
-
"Verification steps:",
|
|
1173
|
-
"- Review each listed file before release or merge.",
|
|
1174
|
-
"- Reproduce locally with the CLI command above.",
|
|
1175
|
-
"- Treat findings as review prompts; confirm behavior with app-specific tests.",
|
|
1176
|
-
"",
|
|
1177
1182
|
"Findings:",
|
|
1178
1183
|
...findingLines
|
|
1179
1184
|
].join("\n");
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { BaseReport, Finding } from "../types.js";
|
|
2
2
|
export declare function launchGateVerdict(report: BaseReport): string;
|
|
3
3
|
export declare function reviewFirst(findings: Finding[], limit?: number): string[];
|
|
4
|
+
export declare function launchDecisionQuestions(findings: Finding[]): string[];
|
|
5
|
+
export declare function rankingExplanation(findings: Finding[]): string[];
|
|
6
|
+
export declare function prReviewerChecklist(): string[];
|
|
7
|
+
export declare function trustStatement(): string[];
|
|
4
8
|
export declare function manualProofSteps(findings: Finding[], limit?: number): string[];
|
|
5
9
|
export declare function nextSteps(findings: Finding[]): string[];
|
|
@@ -20,6 +20,47 @@ export function reviewFirst(findings, limit = 3) {
|
|
|
20
20
|
return `${finding.severity.toUpperCase()} ${finding.ruleId}${location ? ` at ${location}` : ""} - ${finding.title}`;
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
|
+
export function launchDecisionQuestions(findings) {
|
|
24
|
+
if (findings.length === 0) {
|
|
25
|
+
return [
|
|
26
|
+
"Can a real user get access they should not have? No current finding, but still run a two-account auth/data-access smoke.",
|
|
27
|
+
"Can the app claim success when something failed? No current finding, but still force one provider failure before launch.",
|
|
28
|
+
"Can launch infrastructure do too much damage? No current finding, but still confirm env, CI, MCP, and deploy permissions."
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
return [
|
|
32
|
+
"Can a real user get access they should not have? Review auth, tenant ownership, Supabase RLS, webhook entitlement, and data mutation findings first.",
|
|
33
|
+
"Can the app claim success when something failed? Review silent-success, hardcoded fallback, skipped test, and provider failure findings before launch.",
|
|
34
|
+
"Can launch infrastructure do too much damage? Review env exposure, GitHub Actions permissions, MCP tool power, deploy config, logging, and resource hints."
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
export function rankingExplanation(findings) {
|
|
38
|
+
if (findings.length === 0) {
|
|
39
|
+
return [
|
|
40
|
+
"No findings were ranked by this command; this is still a heuristic result, not a certification."
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
return [
|
|
44
|
+
"ai-saas-guard ranks auth, billing, tenant data, RLS, webhooks, and silent-success findings before deploy/cost hygiene because those paths can grant access, expose customer data, or hide production failures.",
|
|
45
|
+
"Medium and low deploy, CI, MCP, and observability findings stay in the queue because they can amplify launch damage, but they should not distract from critical user-access, payment, and data-access proof."
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
export function prReviewerChecklist() {
|
|
49
|
+
return [
|
|
50
|
+
"What changed at the trust boundary?",
|
|
51
|
+
"Why this auth/session/payment/data access decision?",
|
|
52
|
+
"What manual proof should block merge until it passes?",
|
|
53
|
+
"Which files should be reviewed together before this PR is approved?",
|
|
54
|
+
"Should auth, billing, data access, deploy, or UI changes be split into separate PRs?"
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
export function trustStatement() {
|
|
58
|
+
return [
|
|
59
|
+
"Runs as a local-first, deterministic, read-only launch gate over repository files.",
|
|
60
|
+
"Does not upload code or call an LLM.",
|
|
61
|
+
"Uses bounded file collection and ignores heavy generated directories such as node_modules, .next, dist, build, coverage, and .git."
|
|
62
|
+
];
|
|
63
|
+
}
|
|
23
64
|
export function manualProofSteps(findings, limit = 3) {
|
|
24
65
|
const steps = [];
|
|
25
66
|
const seen = new Set();
|
package/dist/report/markdown.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { launchGateVerdict, manualProofSteps, nextSteps, reviewFirst } from "./launchGate.js";
|
|
1
|
+
import { launchDecisionQuestions, launchGateVerdict, manualProofSteps, nextSteps, prReviewerChecklist, rankingExplanation, reviewFirst, trustStatement } from "./launchGate.js";
|
|
2
2
|
export function formatMarkdownReport(report) {
|
|
3
3
|
if (report.command === "demo")
|
|
4
4
|
return `${formatDemoMarkdown(report)}\n`;
|
|
@@ -48,6 +48,9 @@ function formatPrRiskMarkdown(report) {
|
|
|
48
48
|
lines.push(`**Risk categories:** ${report.categories.map((category) => `\`${category}\``).join(", ")}`);
|
|
49
49
|
}
|
|
50
50
|
lines.push("");
|
|
51
|
+
lines.push("### Launch Decision Queue");
|
|
52
|
+
appendList(lines, launchDecisionQuestions(report.findings).map(escapeMarkdownInline));
|
|
53
|
+
lines.push("");
|
|
51
54
|
lines.push("### Review first");
|
|
52
55
|
if (report.topRiskyFiles.length === 0) {
|
|
53
56
|
lines.push("");
|
|
@@ -65,6 +68,15 @@ function formatPrRiskMarkdown(report) {
|
|
|
65
68
|
lines.push("### Required verification");
|
|
66
69
|
appendList(lines, report.requiredTests.length > 0 ? report.requiredTests : report.reviewChecklist);
|
|
67
70
|
lines.push("");
|
|
71
|
+
lines.push("### Reviewer checklist");
|
|
72
|
+
appendList(lines, prReviewerChecklist().map(escapeMarkdownInline));
|
|
73
|
+
lines.push("");
|
|
74
|
+
lines.push("### Why this review order");
|
|
75
|
+
appendList(lines, [
|
|
76
|
+
"Rank trust-boundary files before cosmetic files because auth, billing, tenant data, RLS, webhook, and silent-success changes can affect real users before UI issues do.",
|
|
77
|
+
...rankingExplanation(report.findings)
|
|
78
|
+
].map(escapeMarkdownInline));
|
|
79
|
+
lines.push("");
|
|
68
80
|
lines.push("### Suggested PR split");
|
|
69
81
|
appendList(lines, report.suggestedSplit.length > 0 ? report.suggestedSplit : ["No split suggestion from the current diff."]);
|
|
70
82
|
lines.push("");
|
|
@@ -94,6 +106,15 @@ function appendList(lines, items) {
|
|
|
94
106
|
}
|
|
95
107
|
}
|
|
96
108
|
function appendLaunchQueue(lines, findings) {
|
|
109
|
+
lines.push("");
|
|
110
|
+
lines.push("### Launch Decision Queue");
|
|
111
|
+
appendList(lines, launchDecisionQuestions(findings).map(escapeMarkdownInline));
|
|
112
|
+
lines.push("");
|
|
113
|
+
lines.push("### Why This Is Ranked First");
|
|
114
|
+
appendList(lines, rankingExplanation(findings).map(escapeMarkdownInline));
|
|
115
|
+
lines.push("");
|
|
116
|
+
lines.push("### Trust Statement");
|
|
117
|
+
appendList(lines, trustStatement().map(escapeMarkdownInline));
|
|
97
118
|
if (findings.length === 0)
|
|
98
119
|
return;
|
|
99
120
|
lines.push("");
|
package/dist/report/summary.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { launchGateVerdict, manualProofSteps, nextSteps, reviewFirst } from "./launchGate.js";
|
|
1
|
+
import { launchDecisionQuestions, launchGateVerdict, manualProofSteps, nextSteps, reviewFirst } from "./launchGate.js";
|
|
2
2
|
export function formatSummaryReport(report) {
|
|
3
3
|
if (report.command === "demo")
|
|
4
4
|
return formatShowcaseSummary(report);
|
|
@@ -7,6 +7,10 @@ export function formatSummaryReport(report) {
|
|
|
7
7
|
lines.push(`Root: ${report.rootDir}`);
|
|
8
8
|
lines.push(`Findings: ${summaryText(report)}`);
|
|
9
9
|
lines.push(`Launch gate: ${launchGateVerdict(report)}`);
|
|
10
|
+
lines.push(`Decision queue: ${launchDecisionQuestions(report.findings)[0]}`);
|
|
11
|
+
if (report.findings.length > 0) {
|
|
12
|
+
lines.push("Review trust-boundary findings before deploy/cost hygiene.");
|
|
13
|
+
}
|
|
10
14
|
if (report.findings.length === 0) {
|
|
11
15
|
lines.push("");
|
|
12
16
|
lines.push("No heuristic launch-readiness risks found by this command.");
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -143,7 +143,7 @@ Next steps
|
|
|
143
143
|
- 说明它为什么会影响 AI 构建的 SaaS 上线
|
|
144
144
|
- 给出可以人工复现的验证步骤
|
|
145
145
|
- 给出实际修复方向,不只是一句泛泛建议
|
|
146
|
-
-
|
|
146
|
+
- 支持上线决策队列、排序解释、trust statement、短 `--summary`、terminal、JSON、SARIF 和 PR markdown,方便本地或 CI 使用
|
|
147
147
|
|
|
148
148
|
## 它能帮你抓住哪些问题
|
|
149
149
|
|
|
@@ -211,24 +211,24 @@ node dist/cli.js scan --root /path/to/your-saas
|
|
|
211
211
|
|
|
212
212
|
这个仓库是公开 GitHub 仓库。
|
|
213
213
|
|
|
214
|
-
CLI 已发布到 npm:`ai-saas-guard@0.
|
|
214
|
+
CLI 已发布到 npm:`ai-saas-guard@0.37.0`。GitHub Action 支持 `v0` 浮动标签,也支持固定版本标签,例如 `v0.37.0`。
|
|
215
215
|
|
|
216
216
|
| 模块 | 状态 |
|
|
217
217
|
| --- | --- |
|
|
218
218
|
| 公开 GitHub 仓库 | 已可用 |
|
|
219
|
-
| npm CLI | `ai-saas-guard@0.
|
|
220
|
-
| GitHub Action | `zr9959/ai-saas-guard@v0` 或固定标签 `v0.
|
|
221
|
-
| 输出格式 |
|
|
219
|
+
| npm CLI | `ai-saas-guard@0.37.0` |
|
|
220
|
+
| GitHub Action | `zr9959/ai-saas-guard@v0` 或固定标签 `v0.37.0` |
|
|
221
|
+
| 输出格式 | 上线决策队列、短 summary、Terminal、JSON、SARIF 和 PR markdown |
|
|
222
222
|
| 项目配置 | `.ai-saas-guard.json` 支持规则开关、severity 覆盖、suppressions 和 fail threshold |
|
|
223
223
|
| 隐私模型 | 本地优先、只读扫描、不调用 LLM、不上传代码 |
|
|
224
|
-
| 当前版本 | `0.
|
|
225
|
-
| Action 标签 | `v0.
|
|
224
|
+
| 当前版本 | `0.37.0` 让 GitHub Action PR workflow 更容易复制使用,优化 hosted Check Run 的 launch-risk middle layer 文案,并让 README 首屏更直接指向 AI 大 PR review 场景 |
|
|
225
|
+
| Action 标签 | `v0.37.0`、`v0` |
|
|
226
226
|
| npm 发布 | GitHub Actions Trusted Publisher/OIDC,无需长期 npm token |
|
|
227
227
|
| 仓库可信度加固 | 严格 branch protection、Dependabot、CodeQL、fast-check fuzzing、signed release provenance assets、private vulnerability reporting、secret scanning 和 push protection |
|
|
228
228
|
| Cloudflare hosted ingress | 已部署到 `https://ai-saas-guard-hosted.zr9959.workers.dev`;签名 GitHub App webhook delivery 和 compact Check Run staging smoke 已通过 |
|
|
229
229
|
| Hosted GitHub App staging | 私有 App `ai-saas-guard-hosted`(`3834787`)已安装到 `zr9959/ai-saas-guard`;hosted operations evidence 见 [docs/hosted-operations-evidence.md](hosted-operations-evidence.md) |
|
|
230
230
|
| OpenSSF Best Practices | 已获得 passing badge,项目 `12955`;`.bestpractices.json` 继续作为保守证据记录 |
|
|
231
|
-
|
|
|
231
|
+
| 上一版路线 | v0.36.0 计划见 [v0.36-roadmap.md](v0.36-roadmap.md) |
|
|
232
232
|
|
|
233
233
|
## 主要命令
|
|
234
234
|
|
|
@@ -14,8 +14,46 @@ Expected findings include:
|
|
|
14
14
|
|
|
15
15
|
Use it locally:
|
|
16
16
|
|
|
17
|
+
## Local Scan
|
|
18
|
+
|
|
17
19
|
```bash
|
|
18
20
|
npx ai-saas-guard@latest scan --root examples/case-study-ai-saas --summary
|
|
19
21
|
```
|
|
20
22
|
|
|
23
|
+
## Markdown Report
|
|
24
|
+
|
|
25
|
+
Use Markdown when you want a launch decision queue that can be pasted into an issue or PR:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx ai-saas-guard@latest scan --root examples/case-study-ai-saas --markdown
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The report should start with the launch gate, decision queue, top risks, manual proof steps, ranking explanation, and trust statement before listing every finding.
|
|
32
|
+
|
|
33
|
+
## PR Risk
|
|
34
|
+
|
|
35
|
+
To see how the same middle-layer logic works for an AI-heavy PR, run:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx ai-saas-guard@latest pr-risk --root examples/case-study-ai-saas --base origin/main --markdown
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The PR report is designed for reviewers: review order, required verification, reviewer checklist, suggested PR split, and file evidence.
|
|
42
|
+
|
|
43
|
+
## Fix-before/fix-after
|
|
44
|
+
|
|
45
|
+
Use this fixture as the "before" state. The expected fix path is not to make the fixture a starter template; it is to demonstrate how a reviewer would close the launch gate:
|
|
46
|
+
|
|
47
|
+
- verify Stripe signatures before entitlement updates
|
|
48
|
+
- replace fake success fallbacks with explicit error or degraded-mode handling
|
|
49
|
+
- scope Supabase RLS by tenant/user ownership
|
|
50
|
+
- add Next/Vercel security headers and request IDs
|
|
51
|
+
- reduce GitHub Actions permissions and add PR concurrency cancellation
|
|
52
|
+
|
|
53
|
+
After each fix, rerun the local scan and keep the manual proof result with the launch checklist.
|
|
54
|
+
|
|
55
|
+
## Trust and Resource Boundary
|
|
56
|
+
|
|
57
|
+
The fixture is scanned locally. `ai-saas-guard` does not upload source code or call an LLM, and normal CLI scans use bounded file collection with generated and dependency directories ignored.
|
|
58
|
+
|
|
21
59
|
This fixture is public-safe and synthetic. It is not a SaaS starter template, pentest target, certification artifact, or full audit.
|
package/docs/github-action.md
CHANGED
|
@@ -6,9 +6,51 @@ Use `zr9959/ai-saas-guard@v0` for the latest compatible pre-1.0 Action. Use a sp
|
|
|
6
6
|
|
|
7
7
|
The Action runs the same local scanner inside the GitHub-hosted runner. It reads the checked-out repository, does not call an LLM, and does not upload source code. For `pr-risk`, always use `actions/checkout` with `fetch-depth: 0` so the base branch comparison is available.
|
|
8
8
|
|
|
9
|
+
## Copy-paste PR launch gate workflow
|
|
10
|
+
|
|
11
|
+
Use this when you want one PR job to act as the launch-risk middle layer: Markdown goes to `$GITHUB_STEP_SUMMARY` for reviewers, while SARIF goes to GitHub code scanning for alert tracking. This is not an AI reviewer and it does not approve a PR; it translates trust-boundary changes into a reviewer queue.
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
name: ai-saas-guard-pr-launch-gate
|
|
15
|
+
|
|
16
|
+
on:
|
|
17
|
+
pull_request:
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
security-events: write
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
launch-gate:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v6.0.2
|
|
28
|
+
with:
|
|
29
|
+
fetch-depth: 0
|
|
30
|
+
- uses: zr9959/ai-saas-guard@v0
|
|
31
|
+
with:
|
|
32
|
+
command: pr-risk
|
|
33
|
+
root: ${{ github.workspace }}
|
|
34
|
+
base: origin/main
|
|
35
|
+
config: .ai-saas-guard.json
|
|
36
|
+
format: markdown
|
|
37
|
+
output: ai-saas-guard-pr.md
|
|
38
|
+
- run: cat ai-saas-guard-pr.md >> "$GITHUB_STEP_SUMMARY"
|
|
39
|
+
- uses: zr9959/ai-saas-guard@v0
|
|
40
|
+
with:
|
|
41
|
+
command: scan
|
|
42
|
+
root: ${{ github.workspace }}
|
|
43
|
+
config: .ai-saas-guard.json
|
|
44
|
+
format: sarif
|
|
45
|
+
output: ai-saas-guard.sarif
|
|
46
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
47
|
+
with:
|
|
48
|
+
sarif_file: ai-saas-guard.sarif
|
|
49
|
+
```
|
|
50
|
+
|
|
9
51
|
## PR Summary
|
|
10
52
|
|
|
11
|
-
Use markdown when reviewers need a short, evidence-first
|
|
53
|
+
Use markdown when reviewers need a short, evidence-first launch decision queue: risky files, required verification, reviewer checklist, ranking explanation, and suggested PR split.
|
|
12
54
|
|
|
13
55
|
```yaml
|
|
14
56
|
name: ai-saas-guard-pr-summary
|
|
@@ -37,7 +79,7 @@ jobs:
|
|
|
37
79
|
- run: cat ai-saas-guard-pr.md >> "$GITHUB_STEP_SUMMARY"
|
|
38
80
|
```
|
|
39
81
|
|
|
40
|
-
Use markdown for PR review triage. It is intentionally short enough for a GitHub step summary or a PR comment created by your own workflow. It does not require a hosted service.
|
|
82
|
+
Use markdown for PR review triage. It is intentionally short enough for a GitHub step summary or a PR comment created by your own workflow. It does not require a hosted service. The report keeps the middle-layer contract explicit: it translates trust-boundary changes into human review questions, not an automatic approval.
|
|
41
83
|
|
|
42
84
|
## Project Config
|
|
43
85
|
|
|
@@ -98,4 +140,4 @@ jobs:
|
|
|
98
140
|
sarif_file: ai-saas-guard.sarif
|
|
99
141
|
```
|
|
100
142
|
|
|
101
|
-
Use SARIF for tracking alerts over time. Use markdown for reviewer guidance on a specific PR. Many teams should run both: markdown for
|
|
143
|
+
Use SARIF for tracking alerts over time. Use markdown for reviewer guidance on a specific PR. Many teams should run both: markdown for launch decision queues, SARIF for code scanning visibility.
|
package/docs/npm-publishing.md
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
## Current State
|
|
6
6
|
|
|
7
7
|
- Package name: `ai-saas-guard`
|
|
8
|
-
- Current published version: `0.
|
|
8
|
+
- Current published version: `0.37.0`
|
|
9
9
|
- Next source candidate: none
|
|
10
10
|
- npm registry state: published at <https://www.npmjs.com/package/ai-saas-guard>
|
|
11
11
|
- First npm-published version: `0.1.1`
|
|
12
|
-
- GitHub Release: `v0.
|
|
12
|
+
- GitHub Release: `v0.37.0`
|
|
13
13
|
- Publish workflow: `.github/workflows/npm-publish.yml`
|
|
14
14
|
- Trusted Publisher: GitHub Actions, `zr9959/ai-saas-guard`, workflow `npm-publish.yml`, allowed action `npm publish`
|
|
15
15
|
- Long-lived npm publish token: not required
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
Use GitHub Actions with npm Trusted Publisher/OIDC:
|
|
20
20
|
|
|
21
|
-
1. Create and review a release tag such as `v0.
|
|
21
|
+
1. Create and review a release tag such as `v0.37.0`.
|
|
22
22
|
2. Publish from the GitHub Release or run the `Publish npm` workflow manually with `ref` set to that tag.
|
|
23
23
|
3. Keep `permissions.id-token: write` in the workflow so npm can exchange the GitHub Actions OIDC identity for a short-lived publish credential.
|
|
24
24
|
4. Run `npm publish --access public` from the workflow. Trusted publishing automatically generates provenance for this public package from this public repository.
|
package/docs/positioning.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
This project should compete by being narrow, trustworthy, and review-oriented.
|
|
4
4
|
|
|
5
|
+
## North Star
|
|
6
|
+
|
|
7
|
+
`ai-saas-guard` should become the launch-risk middle layer between AI-generated SaaS code and real users.
|
|
8
|
+
|
|
9
|
+
The product is not trying to be the lowest-level static-analysis engine, and it is not trying to be a top-level full security audit service. Its job is to translate messy AI-built SaaS code and AI-heavy PRs into a founder-readable, reviewer-ready launch gate:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
AI-built SaaS code
|
|
13
|
+
↓
|
|
14
|
+
ai-saas-guard: launch-risk middle layer
|
|
15
|
+
↓
|
|
16
|
+
founder, reviewer, CI, or GitHub App makes the final launch decision
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The long-term product sentence:
|
|
20
|
+
|
|
21
|
+
> The launch gate between AI-generated code and real users.
|
|
22
|
+
|
|
23
|
+
Every major feature should support this middle-layer role:
|
|
24
|
+
|
|
25
|
+
- translate code changes into launch-risk language
|
|
26
|
+
- prioritize trust-boundary paths: auth, billing, tenant data, RLS, webhooks, env, CI, MCP, and deploy
|
|
27
|
+
- turn findings into manual proof steps a human can actually run
|
|
28
|
+
- keep the default trust model local-first, deterministic, read-only, no code upload, and no LLM calls
|
|
29
|
+
- avoid claiming pentest, certification, full audit, or complete vulnerability discovery
|
|
30
|
+
|
|
5
31
|
## Public Position
|
|
6
32
|
|
|
7
33
|
`ai-saas-guard` is a local-first launch preflight for AI-built SaaS apps. It finds common production-readiness risks and produces concrete verification steps.
|
package/docs/project-handoff.md
CHANGED
|
@@ -23,6 +23,8 @@ Recent setup commits at the time this handoff was created:
|
|
|
23
23
|
|
|
24
24
|
`ai-saas-guard` is a local-first launch preflight CLI for AI-built SaaS apps.
|
|
25
25
|
|
|
26
|
+
North star: `ai-saas-guard` is the launch-risk middle layer between AI-generated SaaS code and real users. It translates AI-built SaaS code and AI-heavy PRs into a founder-readable, reviewer-ready launch gate. It is not a low-level static-analysis engine, a pentest, a certification, or a full security audit service.
|
|
27
|
+
|
|
26
28
|
The core user is a founder, solo builder, or reviewer shipping an AI-assisted SaaS MVP who needs to know what deserves human review before launch or merge.
|
|
27
29
|
|
|
28
30
|
The narrow product promise:
|
|
@@ -6,6 +6,8 @@ This is a synthetic, public-safe example of the kind of review queue `ai-saas-gu
|
|
|
6
6
|
ai-saas-guard scan summary
|
|
7
7
|
Findings: 6 findings: 0 critical, 3 high, 3 medium, 0 low, 0 info
|
|
8
8
|
Launch gate: review required: high-risk launch paths need manual verification before launch
|
|
9
|
+
Decision queue: Can a real user get access they should not have? Review auth, tenant ownership, Supabase RLS, webhook entitlement, and data mutation findings first.
|
|
10
|
+
Review trust-boundary findings before deploy/cost hygiene.
|
|
9
11
|
|
|
10
12
|
Top risks:
|
|
11
13
|
- HIGH stripe.webhook.missing-signature at app/api/stripe/webhook/route.ts:12 - Stripe webhook does not verify the Stripe signature
|
|
@@ -25,6 +27,12 @@ Full report:
|
|
|
25
27
|
Rerun without --summary, or use --json, --sarif, or --markdown where supported.
|
|
26
28
|
```
|
|
27
29
|
|
|
30
|
+
Markdown reports include the same decision queue plus:
|
|
31
|
+
|
|
32
|
+
- why auth, billing, tenant data, RLS, webhooks, and silent-success findings rank first
|
|
33
|
+
- a trust statement: local-first, deterministic, read-only, no code upload, no LLM calls
|
|
34
|
+
- a reviewer checklist for PR risk output
|
|
35
|
+
|
|
28
36
|
The full terminal report expands each finding:
|
|
29
37
|
|
|
30
38
|
```text
|
|
@@ -86,4 +94,4 @@ Start with the highest severity findings that touch trust-boundary code: auth, b
|
|
|
86
94
|
- Why could this fail for real users?
|
|
87
95
|
- What manual proof shows the path fails closed?
|
|
88
96
|
|
|
89
|
-
The report is a focused
|
|
97
|
+
The report is a focused launch decision queue. It does not replace your two-account authorization tests, Stripe webhook replay, deploy-preview checks, or human review.
|
|
@@ -669,10 +669,15 @@ function summarizeFindings(findings) {
|
|
|
669
669
|
|
|
670
670
|
function renderCheckRunSummary({ identity, report, scannerVersion }) {
|
|
671
671
|
const lines = [
|
|
672
|
-
`
|
|
672
|
+
`Launch-risk gate: ai-saas-guard found ${report.summary.total} PR risk signal(s) for ${identity.repositoryFullName}#${identity.pullRequestNumber}. Review first: inspect the listed trust-boundary files before merge.`,
|
|
673
673
|
`Scanner version: ${scannerVersion}.`,
|
|
674
674
|
"",
|
|
675
|
-
"This is not
|
|
675
|
+
"This is not an AI reviewer, pentest, certification, or full security audit. Review the listed files before merge.",
|
|
676
|
+
"",
|
|
677
|
+
"Launch decision queue:",
|
|
678
|
+
"- Can a real user get access they should not have?",
|
|
679
|
+
"- Can the app claim success when something failed?",
|
|
680
|
+
"- Can launch infrastructure do too much damage?",
|
|
676
681
|
"",
|
|
677
682
|
"Privacy: this Check Run stores compact file/category signals only. It does not store webhook payload bodies, PR title/body text, diff contents, source, secrets, checkout paths, or installation tokens."
|
|
678
683
|
];
|
package/package.json
CHANGED