ai-saas-guard 0.26.1 → 0.27.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 CHANGED
@@ -1,15 +1,15 @@
1
1
  <h1 align="center">ai-saas-guard</h1>
2
2
 
3
3
  <p align="center">
4
- <strong>You used AI to build your SaaS. Now you need to know what is risky before launch.</strong>
4
+ <strong>You used AI to build your SaaS. Now find the launch risks before users do.</strong>
5
5
  </p>
6
6
 
7
7
  <p align="center">
8
- ai-saas-guard points reviewers to the auth, billing, data access, secrets, MCP, and deploy changes that deserve human attention first. It runs locally, reads your repo only, and does not upload code.
8
+ ai-saas-guard is a local-first launch gate for AI-built SaaS apps. It focuses on auth, billing, data access, secrets, MCP, and deploy decisions, plus CI and fake-success paths, so you know what to review before launch or merge. It runs locally, reads your repo only, and does not upload code.
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- It is not a pentest. It is a practical review checklist for launch-risk hotspots.
12
+ It is not a pentest. It is a practical, evidence-first review queue for the code that can break launch.
13
13
  </p>
14
14
 
15
15
  <p align="center">
@@ -27,40 +27,42 @@
27
27
 
28
28
  ---
29
29
 
30
- ## The Problem It Solves
30
+ ## The Launch Problem
31
31
 
32
- AI can turn an idea into a working SaaS quickly. The harder question is whether the app is ready for real users.
32
+ AI can make a SaaS look finished while the real launch blockers sit in trust-boundary code. These are the failures that hurt after real users arrive:
33
33
 
34
- The risky parts are often not the obvious UI bugs. They are the small changes that decide who can see data, who gets paid access, where secrets are exposed, and what an AI tool is allowed to do:
34
+ - one customer can see or change another customer's data
35
+ - Stripe grants access from an unsigned, duplicated, missing, or failed webhook path
36
+ - provider errors get swallowed and the app returns fake success or demo data
37
+ - a secret leaks through env config or `NEXT_PUBLIC_*`
38
+ - an MCP tool, GitHub workflow, or deploy job has more power than the launch needs
39
+ - a Next/Vercel deploy is missing production env docs, security headers, request IDs, or cost-risk hints
40
+ - a large AI PR hides auth, billing, data, deploy, or test changes inside harmless-looking work
35
41
 
36
- - Can one customer read another customer's data?
37
- - Can a Stripe webhook grant access twice, miss a failed payment, or trust an unsigned request?
38
- - Did a public environment variable expose a secret?
39
- - Did an MCP tool get shell, database, or broad filesystem access?
40
- - Did AI-generated error handling return fake success or demo data after a real provider failed?
41
- - Will the Next/Vercel deploy have the headers, env docs, logging, and request behavior needed for launch?
42
- - Did a pull request hide auth, billing, or deploy changes inside a large AI-generated diff?
43
-
44
- `ai-saas-guard` is a local-first, review-first preflight for that moment. It does not try to prove your app is secure. It is not a pentest, certification, or full audit. It gives founders, solo builders, small teams, and reviewers a short, evidence-backed list of what to check before launch or merge.
42
+ `ai-saas-guard` gives you a short local review queue for those risks. It does not prove the app is secure, certify a release, or replace human review. It tells founders, solo builders, small teams, and reviewers what deserves attention first.
45
43
 
46
44
  ## What You Get
47
45
 
48
- Run it against a repository or pull request and get findings with:
46
+ One command returns a launch-readiness report with:
49
47
 
50
- - the rule that matched
51
- - severity and file evidence
52
- - why the issue matters in a SaaS launch
53
- - how to verify it manually
54
- - a practical fix direction
48
+ - a plain launch-gate verdict at the top of terminal and Markdown output
49
+ - risky files sorted before cosmetic files
50
+ - rule ID, severity, and file evidence
51
+ - why the finding matters for an AI-built SaaS launch
52
+ - manual verification steps you can actually run
53
+ - practical fix direction, not generic advice
54
+ - terminal, JSON, SARIF, and PR markdown output for local review or CI
55
55
 
56
- It is built for common AI-SaaS stacks:
56
+ ## Problems It Helps You Catch
57
57
 
58
- - Next.js and Vercel
59
- - Supabase row-level security and storage policies
60
- - Stripe checkout, subscriptions, and webhooks
61
- - Prisma or SQL migrations
62
- - MCP server configuration
63
- - AI-generated pull requests with large mixed diffs
58
+ | Launch question | What ai-saas-guard checks |
59
+ | --- | --- |
60
+ | Can users only access their own data? | Supabase RLS, tenant/owner predicates, storage policies, API ownership hints, two-account verification guidance |
61
+ | Will billing change access correctly? | Stripe webhook signature, raw body, idempotency, entitlement paths, failure/cancel/update/refund coverage |
62
+ | Will broken integrations fail visibly? | Silent-success fallbacks, swallowed errors, hardcoded success responses, production mock/demo data, skipped or placeholder tests |
63
+ | Will production behave like local? | Next/Vercel headers, env docs, public env inventory, image/request amplification hints, request ID logging |
64
+ | Are tools and CI overpowered? | MCP side-effect classes, local policy/receipt templates, GitHub Actions permissions, concurrency, checkout depth, action pinning |
65
+ | Can reviewers trust the PR? | `pr-risk` ranking for auth, billing, RLS, deploy, API, storage, tests, silent-success paths, missing spec context, and large AI diffs |
64
66
 
65
67
  ## Current Status
66
68
 
@@ -71,24 +73,17 @@ The CLI is published on npm as `ai-saas-guard`, and the GitHub Action is availab
71
73
  | Area | Status |
72
74
  | --- | --- |
73
75
  | Public GitHub repository | Available |
74
- | npm CLI | Published as `ai-saas-guard` |
75
- | Local CLI from source | Available for development |
76
- | JSON and SARIF output | Available |
77
- | Composite GitHub Action | Available |
78
- | Project config | `.ai-saas-guard.json` rule toggles, severity overrides, and fail thresholds |
79
- | Versioned Action tags | `v0.26.1`, `v0` |
80
- | npm package | `ai-saas-guard@0.26.1` |
81
- | Current release | `0.26.1` launch-risk expansion |
76
+ | npm CLI | `ai-saas-guard@0.27.0` |
77
+ | GitHub Action | `zr9959/ai-saas-guard@v0` or fixed tag `v0.27.0` |
78
+ | Outputs | Terminal, JSON, SARIF, and PR-focused markdown |
79
+ | Project config | `.ai-saas-guard.json` rule toggles, severity overrides, suppressions, and fail thresholds |
80
+ | Privacy model | Local-first, read-only scan commands, no LLM calls, no code upload |
81
+ | Versioned Action tags | `v0.27.0`, `v0` |
82
+ | Current release | `0.27.0` launch-gate report summary for CLI and hosted Check Runs |
82
83
  | npm publishing | Trusted Publisher/OIDC, no long-lived publish token |
83
84
  | Repository trust hardening | Strict branch protection, Dependabot, CodeQL, fast-check fuzzing, signed release provenance assets, private vulnerability reporting, secret scanning, and push protection |
84
- | Runtime hardening | Per-file and total text scan caps, escaped markdown evidence, 1 MiB hosted webhook payload cap, stricter hosted deployment blockers |
85
- | Hosted production adapters | GitHub App JWT signing, installation-token request planning, bounded worker execution, and terminal-state cleanup planning |
86
- | Hosted app skeleton | Node/container HTTP ingress, health route, worker tick, in-memory provider adapters, and deployment plan validation |
87
- | Hosted staging deployment planner | Provider binding, staging release-gate evidence, Node/container deployment composition, and GitHub App promotion gating |
88
- | Hosted staging harness | File-backed webhook replay, queue/report/Check Run artifacts, worker cleanup verification, and local release-gate evidence fixtures |
89
85
  | Cloudflare hosted ingress | Deployed at `https://ai-saas-guard-hosted.zr9959.workers.dev`; Worker health and Check Run publisher configuration are live, but end-to-end GitHub App webhook delivery is still blocked pending private App settings verification |
90
- | Hosted operations evidence | Recorded in [docs/hosted-operations-evidence.md](docs/hosted-operations-evidence.md) |
91
- | Hosted GitHub App staging | Private App `ai-saas-guard-hosted` (`3834787`) installed on `zr9959/ai-saas-guard` with contents read, pull requests read, metadata read, and checks write |
86
+ | 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) |
92
87
  | OpenSSF Best Practices | Passing badge, project `12955`; `.bestpractices.json` remains the conservative evidence record |
93
88
 
94
89
  ## Quick Start
@@ -299,7 +294,7 @@ Use `suppressions` for narrower false-positive handling when one rule is noisy o
299
294
 
300
295
  ## GitHub Action
301
296
 
302
- The repo includes a composite Action. Use `v0` for the latest compatible pre-1.0 Action, a specific release tag such as `v0.26.1` for controlled upgrades, or pin a reviewed commit SHA for stricter supply-chain control:
297
+ The repo includes a composite Action. Use `v0` for the latest compatible pre-1.0 Action, a specific release tag such as `v0.27.0` for controlled upgrades, or pin a reviewed commit SHA for stricter supply-chain control:
303
298
 
304
299
  ```yaml
305
300
  name: ai-saas-guard
package/README.zh-CN.md CHANGED
@@ -1,15 +1,15 @@
1
1
  <h1 align="center">ai-saas-guard</h1>
2
2
 
3
3
  <p align="center">
4
- <strong>你用 AI 把 SaaS 做出来了。现在要知道上线前哪里最容易出事。</strong>
4
+ <strong>你用 AI 把 SaaS 做出来了。现在要在用户发现之前,先找到上线风险。</strong>
5
5
  </p>
6
6
 
7
7
  <p align="center">
8
- ai-saas-guard 会优先指出 auth、billing、data access、secrets、MCPdeploy 里最值得人工 review 的改动。它本地运行、只读仓库、不上传代码。
8
+ ai-saas-guard 是面向 AI 构建的 SaaS 的本地优先上线 gate。它会优先指出 auth、billing、data access、secrets、MCPdeploy、CI 和“假成功”路径里最值得人工 review 的改动,让你在上线前知道该先看哪里。它本地运行、只读仓库、不上传代码。
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- 它不是渗透测试,而是一份面向上线风险点的实用 review 清单。
12
+ 它不是渗透测试,而是一份证据优先的 review 队列,帮你先看最容易出事的代码。
13
13
  </p>
14
14
 
15
15
  <p align="center">
@@ -28,66 +28,61 @@
28
28
 
29
29
  ## 它解决什么问题
30
30
 
31
- AI 能很快把一个 SaaS 从想法做成可运行的产品。真正难的是:它能不能放心给真实用户用。
31
+ AI 能很快把一个 SaaS 做到“看起来能用”。真正危险的是上线后才暴露的信任边界问题:
32
32
 
33
- 上线前最危险的通常不是界面小 bug,而是那些会影响用户数据、付费权限、密钥暴露和 AI 工具权限的小改动:
34
-
35
- - 一个用户会不会看到另一个客户的数据?
36
- - Stripe webhook 会不会重复开通权限、漏处理付款失败,或者信任未签名请求?
37
- - `NEXT_PUBLIC_*` 里是不是不小心暴露了 secret?
38
- - MCP 工具是不是拿到了 shell、数据库或过宽的文件系统权限?
39
- - AI 生成的错误处理会不会在真实服务失败后仍然返回“成功”或 demo 数据?
40
- - Next/Vercel 上线前是不是缺 security headers、env 文档、请求日志或高请求量风险提示?
41
- - AI 生成的大 PR 里,是不是把 auth、billing 或 deploy 改动藏在 UI 调整中?
33
+ - 一个用户能看到或修改另一个客户的数据
34
+ - Stripe webhook 因为未签名、重复、漏处理失败事件而错误开通权限
35
+ - 真实服务失败后,AI 生成的代码仍然返回“成功”或 demo 数据
36
+ - secret env 配置或 `NEXT_PUBLIC_*` 暴露出去
37
+ - MCP 工具、GitHub workflow 或 deploy job 拿到了过大的权限
38
+ - Next/Vercel 生产环境缺 env 文档、security headers、request ID 或成本风险提示
39
+ - AI 生成的大 PR 把 auth、billing、data、deploy 或测试改动藏在“普通改动”里
42
40
 
43
41
  `ai-saas-guard` 是面向这个时刻的本地优先、review-first 上线预检工具。它不会证明你的应用绝对安全,也不是渗透测试、认证或完整安全审计。它的目标是给 founder、独立开发者、小团队和 reviewer 一份短而有证据的清单,告诉你上线或合并 PR 前最该先看哪里。
44
42
 
45
43
  ## 你会得到什么
46
44
 
47
- 对仓库或 PR 运行后,它会给出:
45
+ 一个命令会返回一份上线前 review 队列:
48
46
 
49
- - 命中的 rule
50
- - severity 和文件证据
51
- - 为什么这个问题会影响 SaaS 上线
52
- - 如何人工验证
53
- - 实际修复方向
47
+ - terminal 和 Markdown 输出开头会先给出直观上线判断
48
+ - 先看高风险文件,再看 UI 或普通重构
49
+ - 每个 finding 都有 rule ID、severity 和文件证据
50
+ - 说明它为什么会影响 AI 构建的 SaaS 上线
51
+ - 给出可以人工复现的验证步骤
52
+ - 给出实际修复方向,不只是一句泛泛建议
53
+ - 支持 terminal、JSON、SARIF 和 PR markdown,方便本地或 CI 使用
54
54
 
55
- 它适合常见 AI 构建的 SaaS 技术栈:
55
+ ## 它能帮你抓住哪些问题
56
56
 
57
- - Next.js 和 Vercel
58
- - Supabase RLS、storage policy、SQL migration
59
- - Stripe checkoutsubscriptionwebhook
60
- - Prisma SQL migration
61
- - MCP server 配置
62
- - AI 生成的大型混合 PR
57
+ | 上线问题 | ai-saas-guard 会检查什么 |
58
+ | --- | --- |
59
+ | 用户是否只能访问自己的数据? | Supabase RLStenant/owner predicatestorage policy、API ownership 提示、双账号验证建议 |
60
+ | 付费权限是否会正确开通和撤销? | Stripe webhook 签名、raw body、幂等、entitlement 路径、失败/取消/更新/退款覆盖 |
61
+ | 集成失败时会不会明显失败? | silent-success fallback、吞错、hardcoded success、production mock/demo data、跳过或占位测试 |
62
+ | 生产环境是否真的等于本地成功? | Next/Vercel headers、env 文档、public env 盘点、image/request 放大风险、request ID logging |
63
+ | 工具和 CI 权限是不是过大? | MCP side-effect 分类、本地 policy/receipt 模板、GitHub Actions 权限、concurrency、checkout depth、Action pinning |
64
+ | reviewer 能不能看懂 AI PR? | `pr-risk` 对 auth、billing、RLS、deploy、API、storage、测试、silent-success、缺 spec context 和大型 diff 排序 |
63
65
 
64
66
  ## 当前状态
65
67
 
66
68
  这个仓库是公开 GitHub 仓库。
67
69
 
68
- CLI 已发布到 npm:`ai-saas-guard@0.26.1`。GitHub Action 支持 `v0` 浮动标签,也支持固定版本标签,例如 `v0.26.1`。
70
+ CLI 已发布到 npm:`ai-saas-guard@0.27.0`。GitHub Action 支持 `v0` 浮动标签,也支持固定版本标签,例如 `v0.27.0`。
69
71
 
70
72
  | 模块 | 状态 |
71
73
  | --- | --- |
72
74
  | 公开 GitHub 仓库 | 已可用 |
73
- | npm CLI | 已发布为 `ai-saas-guard` |
74
- | 本地源码运行 | 已可用 |
75
- | JSON SARIF 输出 | 已可用 |
76
- | Markdown PR summary | 已可用 |
77
- | GitHub Action | 已可用 |
78
- | 项目配置 | `.ai-saas-guard.json` 支持规则开关、severity 覆盖和 fail threshold |
79
- | 当前版本 | `0.26.1` launch-risk expansion |
80
- | Action 标签 | `v0.26.1`、`v0` |
75
+ | npm CLI | `ai-saas-guard@0.27.0` |
76
+ | GitHub Action | `zr9959/ai-saas-guard@v0` 或固定标签 `v0.27.0` |
77
+ | 输出格式 | Terminal、JSON、SARIF PR markdown |
78
+ | 项目配置 | `.ai-saas-guard.json` 支持规则开关、severity 覆盖、suppressions 和 fail threshold |
79
+ | 隐私模型 | 本地优先、只读扫描、不调用 LLM、不上传代码 |
80
+ | 当前版本 | `0.27.0` CLI hosted Check Run 的 launch-gate report summary |
81
+ | Action 标签 | `v0.27.0`、`v0` |
81
82
  | npm 发布 | GitHub Actions Trusted Publisher/OIDC,无需长期 npm token |
82
83
  | 仓库可信度加固 | 严格 branch protection、Dependabot、CodeQL、fast-check fuzzing、signed release provenance assets、private vulnerability reporting、secret scanning 和 push protection |
83
- | 运行时加固 | 单文件和总扫描文本预算、markdown evidence 转义、1 MiB hosted webhook payload 上限、更严格的 hosted deployment 阻断 |
84
- | Hosted production adapters | GitHub App JWT 签名、installation-token 请求规划、有边界的 worker 执行和终态 cleanup 规划 |
85
- | Hosted app skeleton | Node/container HTTP ingress、health route、worker tick、in-memory provider adapters 和 deployment plan 校验 |
86
- | Hosted staging deployment planner | provider binding、staging release-gate evidence、Node/container deployment 组合和 GitHub App promotion gating |
87
- | Hosted staging harness | 本地 file-backed webhook replay、queue/report/Check Run artifact、worker cleanup 校验和 release-gate evidence fixture |
88
84
  | Cloudflare hosted ingress | 已部署到 `https://ai-saas-guard-hosted.zr9959.workers.dev`;Worker health 和 Check Run publisher 配置已在线,但端到端 GitHub App webhook delivery 仍需要验证私有 App 设置 |
89
- | Hosted operations evidence | 已记录在 [docs/hosted-operations-evidence.md](docs/hosted-operations-evidence.md) |
90
- | Hosted GitHub App staging | 私有 App `ai-saas-guard-hosted`(`3834787`)已安装到 `zr9959/ai-saas-guard`,权限为 contents read、pull requests read、metadata read、checks write |
85
+ | Hosted GitHub App staging | 私有 App `ai-saas-guard-hosted`(`3834787`)已安装到 `zr9959/ai-saas-guard`;hosted operations evidence [docs/hosted-operations-evidence.md](docs/hosted-operations-evidence.md) |
91
86
  | OpenSSF Best Practices | 已获得 passing badge,项目 `12955`;`.bestpractices.json` 继续作为保守证据记录 |
92
87
 
93
88
  ## 快速开始
@@ -479,13 +479,14 @@ export function createHostedCheckRunSummary(input) {
479
479
  const totalFindings = getHostedReportFindingTotal(report);
480
480
  const localCliCommand = `npx ai-saas-guard@${report.scannerVersion} pr-risk --root .`;
481
481
  const conclusion = resolveCheckRunConclusion(report, input.failOnSeverity);
482
+ const launchGate = hostedLaunchGateVerdict(report);
482
483
  return {
483
484
  name: CHECK_RUN_NAME,
484
485
  conclusion,
485
486
  output: {
486
487
  title: formatCheckRunTitle(totalFindings, conclusion, input.failOnSeverity),
487
- summary: "Review first: verify this launch-readiness signal before release; it is not a full security audit, pentest, or certification.",
488
- text: truncateMarkdown(formatCheckRunMarkdown(report, conclusion, localCliCommand), input.maxMarkdownChars)
488
+ summary: `Launch gate: ${launchGate}. Review first: verify this signal before release; it is not a full security audit, pentest, or certification.`,
489
+ text: truncateMarkdown(formatCheckRunMarkdown(report, conclusion, localCliCommand, launchGate), input.maxMarkdownChars)
489
490
  },
490
491
  annotations: report.evidence.slice(0, MAX_CHECK_RUN_ANNOTATIONS).map((finding) => {
491
492
  const line = finding.line ?? 1;
@@ -1056,6 +1057,22 @@ function getHostedReportFindingTotal(report) {
1056
1057
  const explicitTotal = typeof report.summaryCounts.total === "number" ? report.summaryCounts.total : 0;
1057
1058
  return Math.max(countedBySeverity, explicitTotal, report.evidence.length);
1058
1059
  }
1060
+ function hostedLaunchGateVerdict(report) {
1061
+ const summary = report.summaryCounts;
1062
+ if ((summary.critical ?? 0) > 0) {
1063
+ return "blocked";
1064
+ }
1065
+ if ((summary.high ?? 0) > 0) {
1066
+ return "review required";
1067
+ }
1068
+ if ((summary.medium ?? 0) > 0) {
1069
+ return "check before launch";
1070
+ }
1071
+ if ((summary.low ?? 0) > 0 || (summary.info ?? 0) > 0) {
1072
+ return "low-noise review";
1073
+ }
1074
+ return "clear from current heuristics";
1075
+ }
1059
1076
  function formatCheckRunTitle(totalFindings, conclusion, failOnSeverity) {
1060
1077
  if (totalFindings === 0) {
1061
1078
  return "AI SaaS Guard found no launch-readiness findings";
@@ -1065,7 +1082,7 @@ function formatCheckRunTitle(totalFindings, conclusion, failOnSeverity) {
1065
1082
  }
1066
1083
  return `AI SaaS Guard found ${totalFindings} finding${totalFindings === 1 ? "" : "s"} to review`;
1067
1084
  }
1068
- function formatCheckRunMarkdown(report, conclusion, localCliCommand) {
1085
+ function formatCheckRunMarkdown(report, conclusion, localCliCommand, launchGate) {
1069
1086
  const categories = getHostedCheckRunCategories(report);
1070
1087
  const filesToReview = getHostedCheckRunFiles(report);
1071
1088
  const findingLines = report.evidence.length === 0
@@ -1080,6 +1097,7 @@ function formatCheckRunMarkdown(report, conclusion, localCliCommand) {
1080
1097
  "",
1081
1098
  "Review first: verify findings locally before launch. This hosted check is not a full security audit, pentest, or certification.",
1082
1099
  "",
1100
+ `Launch gate: ${launchGate}`,
1083
1101
  `Conclusion: ${conclusion}`,
1084
1102
  `Local CLI: \`${localCliCommand}\``,
1085
1103
  `Retention: compact report ${report.retentionDays} days; raw source, raw diffs, secrets, and customer payloads are not retained.`,
@@ -0,0 +1,4 @@
1
+ import type { BaseReport, Finding } from "../types.js";
2
+ export declare function launchGateVerdict(report: BaseReport): string;
3
+ export declare function reviewFirst(findings: Finding[], limit?: number): string[];
4
+ export declare function manualProofSteps(findings: Finding[], limit?: number): string[];
@@ -0,0 +1,36 @@
1
+ export function launchGateVerdict(report) {
2
+ if (report.summary.critical > 0) {
3
+ return "blocked: critical launch-readiness findings need review before inviting users";
4
+ }
5
+ if (report.summary.high > 0) {
6
+ return "review required: high-risk launch paths need manual verification before launch";
7
+ }
8
+ if (report.summary.medium > 0) {
9
+ return "check before launch: medium-risk findings should be verified by an owner";
10
+ }
11
+ if (report.summary.low > 0 || report.summary.info > 0) {
12
+ return "low-noise review: confirm these hints against the launch checklist";
13
+ }
14
+ return "clear from current heuristics: no findings from this command, not a certification";
15
+ }
16
+ export function reviewFirst(findings, limit = 3) {
17
+ return findings.slice(0, limit).map((finding) => {
18
+ const firstEvidence = finding.evidence[0];
19
+ const location = firstEvidence?.line ? `${firstEvidence.file}:${firstEvidence.line}` : firstEvidence?.file;
20
+ return `${finding.severity.toUpperCase()} ${finding.ruleId}${location ? ` at ${location}` : ""} - ${finding.title}`;
21
+ });
22
+ }
23
+ export function manualProofSteps(findings, limit = 3) {
24
+ const steps = [];
25
+ const seen = new Set();
26
+ for (const finding of findings) {
27
+ const step = finding.suggestedVerification.trim();
28
+ if (!step || seen.has(step))
29
+ continue;
30
+ seen.add(step);
31
+ steps.push(step);
32
+ if (steps.length >= limit)
33
+ break;
34
+ }
35
+ return steps;
36
+ }
@@ -1,3 +1,4 @@
1
+ import { launchGateVerdict, manualProofSteps, reviewFirst } from "./launchGate.js";
1
2
  export function formatMarkdownReport(report) {
2
3
  if (report.command === "pr-risk")
3
4
  return `${formatPrRiskMarkdown(report)}\n`;
@@ -8,6 +9,7 @@ function formatPrRiskMarkdown(report) {
8
9
  lines.push("## ai-saas-guard PR risk summary");
9
10
  lines.push("");
10
11
  lines.push(summaryLine(report));
12
+ lines.push(`**Launch gate:** ${escapeMarkdownInline(launchGateVerdict(report))}`);
11
13
  if (report.categories.length > 0) {
12
14
  lines.push("");
13
15
  lines.push(`**Risk categories:** ${report.categories.map((category) => `\`${category}\``).join(", ")}`);
@@ -42,6 +44,8 @@ function formatGenericMarkdown(report) {
42
44
  lines.push(`## ai-saas-guard ${report.command}`);
43
45
  lines.push("");
44
46
  lines.push(summaryLine(report));
47
+ lines.push(`**Launch gate:** ${escapeMarkdownInline(launchGateVerdict(report))}`);
48
+ appendLaunchQueue(lines, report.findings);
45
49
  lines.push("");
46
50
  lines.push("### Findings");
47
51
  appendFindings(lines, report.findings);
@@ -56,6 +60,16 @@ function appendList(lines, items) {
56
60
  lines.push(`- ${item}`);
57
61
  }
58
62
  }
63
+ function appendLaunchQueue(lines, findings) {
64
+ if (findings.length === 0)
65
+ return;
66
+ lines.push("");
67
+ lines.push("### Review First");
68
+ appendList(lines, reviewFirst(findings).map(escapeMarkdownInline));
69
+ lines.push("");
70
+ lines.push("### Manual Proof To Run Next");
71
+ appendList(lines, manualProofSteps(findings).map(escapeMarkdownInline));
72
+ }
59
73
  function appendFindings(lines, findings) {
60
74
  if (findings.length === 0) {
61
75
  lines.push("");
@@ -1,14 +1,26 @@
1
+ import { launchGateVerdict, manualProofSteps, reviewFirst } from "./launchGate.js";
1
2
  export function formatTerminalReport(report) {
2
3
  const lines = [];
3
4
  lines.push(`ai-saas-guard ${report.command}`);
4
5
  lines.push(`Root: ${report.rootDir}`);
5
6
  lines.push(`Findings: ${report.summary.total} total | critical ${report.summary.critical} | high ${report.summary.high} | medium ${report.summary.medium} | low ${report.summary.low} | info ${report.summary.info}`);
7
+ lines.push(`Launch gate: ${launchGateVerdict(report)}`);
6
8
  if (report.findings.length === 0) {
7
9
  lines.push("");
8
10
  lines.push("No heuristic launch-readiness risks found by this command.");
9
11
  appendCommandExtras(lines, report);
10
12
  return lines.join("\n");
11
13
  }
14
+ lines.push("");
15
+ lines.push("Review first:");
16
+ for (const item of reviewFirst(report.findings)) {
17
+ lines.push(`- ${item}`);
18
+ }
19
+ lines.push("");
20
+ lines.push("Manual proof to run next:");
21
+ for (const step of manualProofSteps(report.findings)) {
22
+ lines.push(`- ${step}`);
23
+ }
12
24
  for (const [index, item] of report.findings.entries()) {
13
25
  lines.push("");
14
26
  lines.push(`${index + 1}. [${item.severity.toUpperCase()}] ${item.title}`);
@@ -2,7 +2,7 @@
2
2
 
3
3
  `ai-saas-guard` ships as a composite GitHub Action for pull request and code scanning workflows.
4
4
 
5
- Use `zr9959/ai-saas-guard@v0` for the latest compatible pre-1.0 Action. Use a specific tag such as `v0.26.1` or a reviewed commit SHA when reproducibility is more important than automatic minor updates.
5
+ Use `zr9959/ai-saas-guard@v0` for the latest compatible pre-1.0 Action. Use a specific tag such as `v0.27.0` or a reviewed commit SHA when reproducibility is more important than automatic minor updates.
6
6
 
7
7
  ## PR Summary
8
8
 
@@ -5,11 +5,11 @@
5
5
  ## Current State
6
6
 
7
7
  - Package name: `ai-saas-guard`
8
- - Current published version: `0.26.1`
8
+ - Current published version: `0.27.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.26.1`
12
+ - GitHub Release: `v0.27.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.26.1`.
21
+ 1. Create and review a release tag such as `v0.27.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.
@@ -160,7 +160,7 @@ OpenSSF Best Practices:
160
160
  Publishing:
161
161
 
162
162
  - npm package: `ai-saas-guard`
163
- - Current published release line: `v0.26.1`
163
+ - Current published release line: `v0.27.0`
164
164
  - Next source candidate: none
165
165
  - Publish workflow: `.github/workflows/npm-publish.yml`
166
166
  - Trusted Publisher: GitHub Actions for `zr9959/ai-saas-guard`, workflow `npm-publish.yml`
@@ -40,6 +40,8 @@ It covers:
40
40
 
41
41
  The schedule is weekly with cooldown windows and a small open pull request limit. This keeps update noise low while still surfacing security and maintenance updates.
42
42
 
43
+ The npm update policy ignores semver-major `@types/node` bumps while the package supports Node.js 20. This avoids accidentally type-checking against newer Node-only APIs that the published CLI does not promise to support.
44
+
43
45
  Dependabot security updates and vulnerability alerts are enabled in repository settings.
44
46
 
45
47
  ## CodeQL
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-saas-guard",
3
- "version": "0.26.1",
3
+ "version": "0.27.0",
4
4
  "description": "Repo-local launch-readiness scanner for AI-built SaaS apps.",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/zr9959/ai-saas-guard#readme",
@@ -87,6 +87,6 @@
87
87
  "devDependencies": {
88
88
  "@types/node": "^20",
89
89
  "fast-check": "^4.8.0",
90
- "typescript": "^5"
90
+ "typescript": "^6"
91
91
  }
92
92
  }