ai-saas-guard 0.41.0 → 0.43.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 +8 -6
- package/dist/hosted/beta.d.ts +97 -0
- package/dist/hosted/beta.js +132 -0
- package/dist/hosted/worker.d.ts +36 -0
- package/dist/hosted/worker.js +78 -0
- package/docs/README.zh-CN.md +8 -6
- package/docs/hosted-node-container-app.md +7 -2
- package/docs/hosted-operational-release-gate.md +35 -0
- package/docs/hosted-operations-evidence.md +8 -0
- package/docs/npm-publishing.md +3 -3
- package/hosted/cloudflare-worker/README.md +1 -1
- package/hosted/cloudflare-worker/wrangler.jsonc +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -235,13 +235,13 @@ The CLI is published on npm as `ai-saas-guard`, and the GitHub Action is availab
|
|
|
235
235
|
| Area | Status |
|
|
236
236
|
| --- | --- |
|
|
237
237
|
| Public GitHub repository | Available |
|
|
238
|
-
| npm CLI | `ai-saas-guard@0.
|
|
239
|
-
| GitHub Action | `zr9959/ai-saas-guard@v0` or fixed tag `v0.
|
|
238
|
+
| npm CLI | `ai-saas-guard@0.43.0` |
|
|
239
|
+
| GitHub Action | `zr9959/ai-saas-guard@v0` or fixed tag `v0.43.0` |
|
|
240
240
|
| Outputs | Launch decision queue, short summary, terminal, JSON, SARIF, and PR-focused markdown |
|
|
241
241
|
| Project config | `.ai-saas-guard.json` rule toggles, severity overrides, suppressions, and fail thresholds |
|
|
242
242
|
| Privacy model | Local-first, read-only scan commands, no LLM calls, no code upload |
|
|
243
|
-
| Versioned Action tags | `v0.
|
|
244
|
-
| Current release | `0.
|
|
243
|
+
| Versioned Action tags | `v0.43.0`, `v0` |
|
|
244
|
+
| Current release | `0.43.0` adds pre-commercial hosted gates for Phase 4 beta readiness and Phase 5 team launch readiness while keeping billing disabled |
|
|
245
245
|
| npm publishing | Trusted Publisher/OIDC, no long-lived publish token |
|
|
246
246
|
| Repository trust hardening | Strict branch protection, Dependabot, CodeQL, fast-check fuzzing, signed release provenance assets, private vulnerability reporting, secret scanning, and push protection |
|
|
247
247
|
| Cloudflare hosted ingress | Deployed at `https://ai-saas-guard-hosted.zr9959.workers.dev`; public install/privacy notes are in [docs/hosted-install-privacy.md](docs/hosted-install-privacy.md); signed GitHub App webhook delivery and compact Check Run smoke now pass in staging |
|
|
@@ -367,7 +367,9 @@ Deployed worker staging evidence is documented in [docs/hosted-deployed-worker-s
|
|
|
367
367
|
|
|
368
368
|
The first live hosted ingress is deployed on Cloudflare Workers at `https://ai-saas-guard-hosted.zr9959.workers.dev` and documented in [hosted/cloudflare-worker/README.md](hosted/cloudflare-worker/README.md). It exposes `/healthz`, `/github/app/install-info`, `/github/app/manifest-callback`, and signed `/github/webhook` intake backed by Cloudflare KV. A private staging GitHub App, `ai-saas-guard-hosted`, is installed on `zr9959/ai-saas-guard` with selected-repository access and the first-slice permission contract. The Worker verifies signatures, stores compact pull request identity records, exchanges a scoped installation token, fetches PR file metadata from GitHub, classifies PR-risk hotspots, and publishes a bounded selected-repository hosted check with a review queue and manual proof prompt. Signed installation deletion and repository removal events delete matching compact records. Current deployed evidence is tracked in [docs/hosted-operations-evidence.md](docs/hosted-operations-evidence.md): health, signed webhook delivery, compact KV records, cleanup, and Check Run publication pass in staging. The Cloudflare Worker still does not run a full source checkout scan worker or store raw webhook payloads, PR title/body text, raw diffs, source, secrets, checkout paths, or installation tokens.
|
|
369
369
|
|
|
370
|
-
The next hosted source-checkout step is intentionally narrow: deploy the existing read-only checkout worker behind the same selected-repository identity, keep the fixed `pr-risk --json` command, write only compact findings to the Check Run, and require deployed cleanup/log-boundary/rollback evidence before broader trial use. The
|
|
370
|
+
The next hosted source-checkout step is intentionally narrow: deploy the existing read-only checkout worker behind the same selected-repository identity, keep the fixed `pr-risk --json` command, write only compact findings to the Check Run, and require deployed cleanup/log-boundary/rollback evidence before broader trial use. The hosted worker export includes `createHostedSourceCheckoutTrialPlan`, `createHostedSourceCheckoutEvidence`, and `evaluateHostedSourceCheckoutTrialGate` so Phase 3 has one machine-checkable gate for checkout start/end, token removal, CLI start/end, compact report write, Check Run write, cleanup status, live smoke, rollback, monitoring, and incident-owner proof before Phase 4 beta.
|
|
371
|
+
|
|
372
|
+
The `ai-saas-guard/hosted/beta` export adds `evaluateHostedBetaReadinessGate` and `evaluateTeamLaunchGateReadiness`. These pre-commercial gates block hosted beta unless selected-repository install limits, abuse controls, safe telemetry, uninstall deletion proof, rollback, support ownership, beta smoke, and no-audit-claim wording are ready; they also block team use unless org policy config, required status-check docs, suppression audit, reviewer checklist, release evidence export, retention docs, and billing-disabled proof are in place.
|
|
371
373
|
|
|
372
374
|
Hosted install and privacy details are summarized in [docs/hosted-install-privacy.md](docs/hosted-install-privacy.md): selected-repository permissions, supported events, Check Run data boundaries, uninstall cleanup, and why the local CLI remains the private/offline path.
|
|
373
375
|
|
|
@@ -423,7 +425,7 @@ Use `suppressions` for narrower false-positive handling when one rule is noisy o
|
|
|
423
425
|
|
|
424
426
|
## GitHub Action
|
|
425
427
|
|
|
426
|
-
The repo includes a composite Action. Use `v0` for the latest compatible pre-1.0 Action, a specific release tag such as `v0.
|
|
428
|
+
The repo includes a composite Action. Use `v0` for the latest compatible pre-1.0 Action, a specific release tag such as `v0.43.0` for controlled upgrades, or pin a reviewed commit SHA for stricter supply-chain control:
|
|
427
429
|
|
|
428
430
|
```yaml
|
|
429
431
|
name: ai-saas-guard
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export interface HostedBetaReadinessGateInput {
|
|
2
|
+
requestedAt: string;
|
|
3
|
+
phase3GatePassed: boolean;
|
|
4
|
+
selectedRepositoryInstallOnly: boolean;
|
|
5
|
+
publicInstallDocsReady: boolean;
|
|
6
|
+
rateLimitEnabled: boolean;
|
|
7
|
+
abuseKillSwitchReady: boolean;
|
|
8
|
+
telemetrySafe: boolean;
|
|
9
|
+
uninstallDeletionTested: boolean;
|
|
10
|
+
rollbackTested: boolean;
|
|
11
|
+
incidentOwnerRecorded: boolean;
|
|
12
|
+
supportPathReady: boolean;
|
|
13
|
+
betaSmokePassed: boolean;
|
|
14
|
+
avoidsAuditClaims: boolean;
|
|
15
|
+
noRawSourceStorage: boolean;
|
|
16
|
+
noRawDiffStorage: boolean;
|
|
17
|
+
noPrTextStorage: boolean;
|
|
18
|
+
maxReposPerInstallation: number;
|
|
19
|
+
maxConcurrentScans: number;
|
|
20
|
+
rawSource?: string;
|
|
21
|
+
rawDiff?: string;
|
|
22
|
+
prText?: string;
|
|
23
|
+
installationToken?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface HostedBetaReadinessGate {
|
|
26
|
+
phase: "phase_4_hosted_beta_readiness";
|
|
27
|
+
readyForPublicBeta: boolean;
|
|
28
|
+
blockedReasons: string[];
|
|
29
|
+
requestedAt: string;
|
|
30
|
+
installBoundary: {
|
|
31
|
+
selectedRepositoryOnly: true;
|
|
32
|
+
maxReposPerInstallation: number;
|
|
33
|
+
maxConcurrentScans: number;
|
|
34
|
+
};
|
|
35
|
+
operations: {
|
|
36
|
+
rateLimitEnabled: boolean;
|
|
37
|
+
abuseKillSwitchReady: boolean;
|
|
38
|
+
telemetrySafe: boolean;
|
|
39
|
+
uninstallDeletionTested: boolean;
|
|
40
|
+
rollbackTested: boolean;
|
|
41
|
+
incidentOwnerRecorded: boolean;
|
|
42
|
+
supportPathReady: boolean;
|
|
43
|
+
betaSmokePassed: boolean;
|
|
44
|
+
};
|
|
45
|
+
nextAction: string;
|
|
46
|
+
privacy: {
|
|
47
|
+
includesRawSource: false;
|
|
48
|
+
includesRawDiffs: false;
|
|
49
|
+
includesUntrustedPrText: false;
|
|
50
|
+
includesInstallationToken: false;
|
|
51
|
+
claimsPentest: false;
|
|
52
|
+
claimsFullAudit: false;
|
|
53
|
+
claimsCertification: false;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export interface TeamLaunchGateReadinessInput {
|
|
57
|
+
requestedAt: string;
|
|
58
|
+
hostedBetaGatePassed: boolean;
|
|
59
|
+
orgPolicyConfigReady: boolean;
|
|
60
|
+
requiredStatusCheckDocumented: boolean;
|
|
61
|
+
suppressionAuditReady: boolean;
|
|
62
|
+
reviewerChecklistReady: boolean;
|
|
63
|
+
releaseEvidenceExportReady: boolean;
|
|
64
|
+
teamDocsReady: boolean;
|
|
65
|
+
adminBypassDocumented: boolean;
|
|
66
|
+
retentionPolicyDocumented: boolean;
|
|
67
|
+
noCommercialBillingEnabled: boolean;
|
|
68
|
+
rawSource?: string;
|
|
69
|
+
customerPayload?: unknown;
|
|
70
|
+
}
|
|
71
|
+
export interface TeamLaunchGateReadiness {
|
|
72
|
+
phase: "phase_5_team_launch_gate";
|
|
73
|
+
readyForTeamUse: boolean;
|
|
74
|
+
blockedReasons: string[];
|
|
75
|
+
requestedAt: string;
|
|
76
|
+
teamControls: {
|
|
77
|
+
orgPolicyConfigReady: boolean;
|
|
78
|
+
requiredStatusCheckDocumented: boolean;
|
|
79
|
+
suppressionAuditReady: boolean;
|
|
80
|
+
reviewerChecklistReady: boolean;
|
|
81
|
+
releaseEvidenceExportReady: boolean;
|
|
82
|
+
teamDocsReady: boolean;
|
|
83
|
+
adminBypassDocumented: boolean;
|
|
84
|
+
retentionPolicyDocumented: boolean;
|
|
85
|
+
};
|
|
86
|
+
commercialization: {
|
|
87
|
+
enabled: false;
|
|
88
|
+
reason: "pre_commercial_feedback_stage";
|
|
89
|
+
};
|
|
90
|
+
nextAction: string;
|
|
91
|
+
privacy: {
|
|
92
|
+
includesRawSource: false;
|
|
93
|
+
includesCustomerPayloads: false;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export declare function evaluateHostedBetaReadinessGate(input: HostedBetaReadinessGateInput): HostedBetaReadinessGate;
|
|
97
|
+
export declare function evaluateTeamLaunchGateReadiness(input: TeamLaunchGateReadinessInput): TeamLaunchGateReadiness;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
const MAX_BETA_REPOS_PER_INSTALLATION = 10;
|
|
2
|
+
const MAX_BETA_CONCURRENT_SCANS = 5;
|
|
3
|
+
export function evaluateHostedBetaReadinessGate(input) {
|
|
4
|
+
const blockedReasons = hostedBetaBlockedReasons(input);
|
|
5
|
+
return {
|
|
6
|
+
phase: "phase_4_hosted_beta_readiness",
|
|
7
|
+
readyForPublicBeta: blockedReasons.length === 0,
|
|
8
|
+
blockedReasons,
|
|
9
|
+
requestedAt: input.requestedAt,
|
|
10
|
+
installBoundary: {
|
|
11
|
+
selectedRepositoryOnly: true,
|
|
12
|
+
maxReposPerInstallation: Math.max(0, Math.floor(input.maxReposPerInstallation)),
|
|
13
|
+
maxConcurrentScans: Math.max(0, Math.floor(input.maxConcurrentScans))
|
|
14
|
+
},
|
|
15
|
+
operations: {
|
|
16
|
+
rateLimitEnabled: input.rateLimitEnabled,
|
|
17
|
+
abuseKillSwitchReady: input.abuseKillSwitchReady,
|
|
18
|
+
telemetrySafe: input.telemetrySafe,
|
|
19
|
+
uninstallDeletionTested: input.uninstallDeletionTested,
|
|
20
|
+
rollbackTested: input.rollbackTested,
|
|
21
|
+
incidentOwnerRecorded: input.incidentOwnerRecorded,
|
|
22
|
+
supportPathReady: input.supportPathReady,
|
|
23
|
+
betaSmokePassed: input.betaSmokePassed
|
|
24
|
+
},
|
|
25
|
+
nextAction: blockedReasons.length === 0
|
|
26
|
+
? "Open a limited public beta only for selected repositories and keep collecting operational evidence before commercialization."
|
|
27
|
+
: "Do not open hosted beta. Resolve the blocked reasons and rerun the beta readiness gate.",
|
|
28
|
+
privacy: {
|
|
29
|
+
includesRawSource: false,
|
|
30
|
+
includesRawDiffs: false,
|
|
31
|
+
includesUntrustedPrText: false,
|
|
32
|
+
includesInstallationToken: false,
|
|
33
|
+
claimsPentest: false,
|
|
34
|
+
claimsFullAudit: false,
|
|
35
|
+
claimsCertification: false
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function evaluateTeamLaunchGateReadiness(input) {
|
|
40
|
+
const blockedReasons = teamLaunchBlockedReasons(input);
|
|
41
|
+
return {
|
|
42
|
+
phase: "phase_5_team_launch_gate",
|
|
43
|
+
readyForTeamUse: blockedReasons.length === 0,
|
|
44
|
+
blockedReasons,
|
|
45
|
+
requestedAt: input.requestedAt,
|
|
46
|
+
teamControls: {
|
|
47
|
+
orgPolicyConfigReady: input.orgPolicyConfigReady,
|
|
48
|
+
requiredStatusCheckDocumented: input.requiredStatusCheckDocumented,
|
|
49
|
+
suppressionAuditReady: input.suppressionAuditReady,
|
|
50
|
+
reviewerChecklistReady: input.reviewerChecklistReady,
|
|
51
|
+
releaseEvidenceExportReady: input.releaseEvidenceExportReady,
|
|
52
|
+
teamDocsReady: input.teamDocsReady,
|
|
53
|
+
adminBypassDocumented: input.adminBypassDocumented,
|
|
54
|
+
retentionPolicyDocumented: input.retentionPolicyDocumented
|
|
55
|
+
},
|
|
56
|
+
commercialization: {
|
|
57
|
+
enabled: false,
|
|
58
|
+
reason: "pre_commercial_feedback_stage"
|
|
59
|
+
},
|
|
60
|
+
nextAction: blockedReasons.length === 0
|
|
61
|
+
? "Use the team launch gate with design partners, collect user feedback, and delay commercialization until usage evidence exists."
|
|
62
|
+
: "Do not sell or commercialize. Resolve the team launch gate blockers before inviting teams beyond beta.",
|
|
63
|
+
privacy: {
|
|
64
|
+
includesRawSource: false,
|
|
65
|
+
includesCustomerPayloads: false
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function hostedBetaBlockedReasons(input) {
|
|
70
|
+
const reasons = [];
|
|
71
|
+
if (!input.phase3GatePassed)
|
|
72
|
+
reasons.push("phase3_gate_missing");
|
|
73
|
+
if (!input.selectedRepositoryInstallOnly)
|
|
74
|
+
reasons.push("selected_repository_install_required");
|
|
75
|
+
if (!input.publicInstallDocsReady)
|
|
76
|
+
reasons.push("public_install_docs_missing");
|
|
77
|
+
if (!input.rateLimitEnabled)
|
|
78
|
+
reasons.push("rate_limit_missing");
|
|
79
|
+
if (!input.abuseKillSwitchReady)
|
|
80
|
+
reasons.push("abuse_kill_switch_missing");
|
|
81
|
+
if (!input.telemetrySafe)
|
|
82
|
+
reasons.push("safe_telemetry_missing");
|
|
83
|
+
if (!input.uninstallDeletionTested)
|
|
84
|
+
reasons.push("uninstall_deletion_proof_missing");
|
|
85
|
+
if (!input.rollbackTested)
|
|
86
|
+
reasons.push("rollback_test_missing");
|
|
87
|
+
if (!input.incidentOwnerRecorded)
|
|
88
|
+
reasons.push("incident_owner_missing");
|
|
89
|
+
if (!input.supportPathReady)
|
|
90
|
+
reasons.push("support_path_missing");
|
|
91
|
+
if (!input.betaSmokePassed)
|
|
92
|
+
reasons.push("beta_smoke_missing");
|
|
93
|
+
if (!input.avoidsAuditClaims)
|
|
94
|
+
reasons.push("audit_claims_not_blocked");
|
|
95
|
+
if (!input.noRawSourceStorage)
|
|
96
|
+
reasons.push("raw_source_storage_blocked");
|
|
97
|
+
if (!input.noRawDiffStorage)
|
|
98
|
+
reasons.push("raw_diff_storage_blocked");
|
|
99
|
+
if (!input.noPrTextStorage)
|
|
100
|
+
reasons.push("pr_text_storage_blocked");
|
|
101
|
+
if (!Number.isFinite(input.maxReposPerInstallation) || input.maxReposPerInstallation > MAX_BETA_REPOS_PER_INSTALLATION) {
|
|
102
|
+
reasons.push("repo_limit_too_high");
|
|
103
|
+
}
|
|
104
|
+
if (!Number.isFinite(input.maxConcurrentScans) || input.maxConcurrentScans > MAX_BETA_CONCURRENT_SCANS) {
|
|
105
|
+
reasons.push("concurrency_limit_too_high");
|
|
106
|
+
}
|
|
107
|
+
return reasons;
|
|
108
|
+
}
|
|
109
|
+
function teamLaunchBlockedReasons(input) {
|
|
110
|
+
const reasons = [];
|
|
111
|
+
if (!input.hostedBetaGatePassed)
|
|
112
|
+
reasons.push("hosted_beta_gate_missing");
|
|
113
|
+
if (!input.orgPolicyConfigReady)
|
|
114
|
+
reasons.push("org_policy_config_missing");
|
|
115
|
+
if (!input.requiredStatusCheckDocumented)
|
|
116
|
+
reasons.push("required_status_check_docs_missing");
|
|
117
|
+
if (!input.suppressionAuditReady)
|
|
118
|
+
reasons.push("suppression_audit_missing");
|
|
119
|
+
if (!input.reviewerChecklistReady)
|
|
120
|
+
reasons.push("reviewer_checklist_missing");
|
|
121
|
+
if (!input.releaseEvidenceExportReady)
|
|
122
|
+
reasons.push("release_evidence_export_missing");
|
|
123
|
+
if (!input.teamDocsReady)
|
|
124
|
+
reasons.push("team_docs_missing");
|
|
125
|
+
if (!input.adminBypassDocumented)
|
|
126
|
+
reasons.push("admin_bypass_docs_missing");
|
|
127
|
+
if (!input.retentionPolicyDocumented)
|
|
128
|
+
reasons.push("retention_policy_docs_missing");
|
|
129
|
+
if (!input.noCommercialBillingEnabled)
|
|
130
|
+
reasons.push("commercial_billing_enabled_too_early");
|
|
131
|
+
return reasons;
|
|
132
|
+
}
|
package/dist/hosted/worker.d.ts
CHANGED
|
@@ -127,6 +127,41 @@ export interface HostedReadOnlyCheckoutScanGate {
|
|
|
127
127
|
claimsCompleteHostedSaas: false;
|
|
128
128
|
};
|
|
129
129
|
}
|
|
130
|
+
export interface HostedSourceCheckoutTrialGateInput extends HostedSourceCheckoutTrialPlanInput, Omit<HostedSourceCheckoutEvidenceInput, "requestedAt" | "rawSource" | "rawDiff" | "checkoutPath" | "installationToken">, Omit<HostedReadOnlyCheckoutScanGateInput, "requestedAt" | "jobKey" | "summaryCounts" | "compactFindingCount" | "rawSource" | "rawDiff" | "checkoutPath" | "installationToken"> {
|
|
131
|
+
liveSmokePassed: boolean;
|
|
132
|
+
rollbackTested: boolean;
|
|
133
|
+
monitoringEvidence: boolean;
|
|
134
|
+
incidentOwnerRecorded: boolean;
|
|
135
|
+
rawSource?: string;
|
|
136
|
+
rawDiff?: string;
|
|
137
|
+
checkoutPath?: string;
|
|
138
|
+
installationToken?: string;
|
|
139
|
+
}
|
|
140
|
+
export interface HostedSourceCheckoutTrialGate {
|
|
141
|
+
phase: "phase_3_hosted_source_checkout_trial";
|
|
142
|
+
readyForPhase4Beta: boolean;
|
|
143
|
+
blockedReasons: string[];
|
|
144
|
+
requestedAt: string;
|
|
145
|
+
repositoryFullName: string;
|
|
146
|
+
jobKey: string;
|
|
147
|
+
plan: HostedSourceCheckoutTrialPlan;
|
|
148
|
+
evidence: HostedSourceCheckoutEvidence;
|
|
149
|
+
scanGate: HostedReadOnlyCheckoutScanGate;
|
|
150
|
+
operatorProof: {
|
|
151
|
+
liveSmokePassed: boolean;
|
|
152
|
+
rollbackTested: boolean;
|
|
153
|
+
monitoringEvidence: boolean;
|
|
154
|
+
incidentOwnerRecorded: boolean;
|
|
155
|
+
};
|
|
156
|
+
nextAction: string;
|
|
157
|
+
privacy: {
|
|
158
|
+
includesRawSource: false;
|
|
159
|
+
includesRawDiffs: false;
|
|
160
|
+
includesPrivateCheckoutPath: false;
|
|
161
|
+
includesInstallationToken: false;
|
|
162
|
+
claimsPublicHostedScanner: false;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
130
165
|
export type HostedReadOnlyCheckoutScanSafeReason = "invalid_worker_plan" | "invalid_repository_full_name" | "invalid_clone_base_url" | "missing_installation_token" | "git_init_failed" | "git_remote_add_failed" | "git_fetch_head_failed" | "git_fetch_base_failed" | "git_checkout_failed" | "cli_scan_failed" | "invalid_cli_output" | "cleanup_failed";
|
|
131
166
|
export declare class HostedReadOnlyCheckoutScanError extends Error {
|
|
132
167
|
readonly safeReason: HostedReadOnlyCheckoutScanSafeReason;
|
|
@@ -144,4 +179,5 @@ export declare function createHostedReadOnlyCheckoutScanRunner(options: HostedRe
|
|
|
144
179
|
export declare function createHostedSourceCheckoutTrialPlan(input: HostedSourceCheckoutTrialPlanInput): HostedSourceCheckoutTrialPlan;
|
|
145
180
|
export declare function createHostedSourceCheckoutEvidence(input: HostedSourceCheckoutEvidenceInput): HostedSourceCheckoutEvidence;
|
|
146
181
|
export declare function evaluateHostedReadOnlyCheckoutScanGate(input: HostedReadOnlyCheckoutScanGateInput): HostedReadOnlyCheckoutScanGate;
|
|
182
|
+
export declare function evaluateHostedSourceCheckoutTrialGate(input: HostedSourceCheckoutTrialGateInput): HostedSourceCheckoutTrialGate;
|
|
147
183
|
export declare function runHostedReadOnlyCheckoutScan(input: HostedServiceScanRunnerInput, options: HostedReadOnlyCheckoutScanRunnerOptions): Promise<HostedServiceScanRunnerResult>;
|
package/dist/hosted/worker.js
CHANGED
|
@@ -173,6 +173,72 @@ export function evaluateHostedReadOnlyCheckoutScanGate(input) {
|
|
|
173
173
|
}
|
|
174
174
|
};
|
|
175
175
|
}
|
|
176
|
+
export function evaluateHostedSourceCheckoutTrialGate(input) {
|
|
177
|
+
const plan = createHostedSourceCheckoutTrialPlan(input);
|
|
178
|
+
const evidence = createHostedSourceCheckoutEvidence({
|
|
179
|
+
requestedAt: input.requestedAt,
|
|
180
|
+
jobKey: input.jobKey,
|
|
181
|
+
stages: input.stages,
|
|
182
|
+
summaryCounts: input.summaryCounts,
|
|
183
|
+
compactFindingCount: input.compactFindingCount,
|
|
184
|
+
cleanupStatus: input.cleanupStatus,
|
|
185
|
+
rawSource: input.rawSource,
|
|
186
|
+
rawDiff: input.rawDiff,
|
|
187
|
+
checkoutPath: input.checkoutPath,
|
|
188
|
+
installationToken: input.installationToken
|
|
189
|
+
});
|
|
190
|
+
const scanGate = evaluateHostedReadOnlyCheckoutScanGate({
|
|
191
|
+
requestedAt: input.requestedAt,
|
|
192
|
+
jobKey: input.jobKey,
|
|
193
|
+
commandStages: input.commandStages,
|
|
194
|
+
summaryCounts: input.summaryCounts,
|
|
195
|
+
compactFindingCount: input.compactFindingCount,
|
|
196
|
+
compactReportStored: input.compactReportStored,
|
|
197
|
+
checkRunPublished: input.checkRunPublished,
|
|
198
|
+
checkoutDeleted: input.checkoutDeleted,
|
|
199
|
+
tokenRemovedBeforeCli: input.tokenRemovedBeforeCli,
|
|
200
|
+
maxOutputBytes: input.maxOutputBytes,
|
|
201
|
+
timeoutMs: input.timeoutMs,
|
|
202
|
+
rawSource: input.rawSource,
|
|
203
|
+
rawDiff: input.rawDiff,
|
|
204
|
+
checkoutPath: input.checkoutPath,
|
|
205
|
+
installationToken: input.installationToken
|
|
206
|
+
});
|
|
207
|
+
const operatorBlockedReasons = operatorProofBlockedReasons(input);
|
|
208
|
+
const blockedReasons = [
|
|
209
|
+
...plan.blockedReasons,
|
|
210
|
+
...evidence.blockedReasons,
|
|
211
|
+
...scanGate.blockedReasons,
|
|
212
|
+
...operatorBlockedReasons
|
|
213
|
+
];
|
|
214
|
+
return {
|
|
215
|
+
phase: "phase_3_hosted_source_checkout_trial",
|
|
216
|
+
readyForPhase4Beta: blockedReasons.length === 0,
|
|
217
|
+
blockedReasons,
|
|
218
|
+
requestedAt: input.requestedAt,
|
|
219
|
+
repositoryFullName: input.repositoryFullName,
|
|
220
|
+
jobKey: input.jobKey,
|
|
221
|
+
plan,
|
|
222
|
+
evidence,
|
|
223
|
+
scanGate,
|
|
224
|
+
operatorProof: {
|
|
225
|
+
liveSmokePassed: input.liveSmokePassed,
|
|
226
|
+
rollbackTested: input.rollbackTested,
|
|
227
|
+
monitoringEvidence: input.monitoringEvidence,
|
|
228
|
+
incidentOwnerRecorded: input.incidentOwnerRecorded
|
|
229
|
+
},
|
|
230
|
+
nextAction: blockedReasons.length === 0
|
|
231
|
+
? "Phase 3 is closed for the selected-repository trial. Continue to Phase 4 beta only with the same privacy boundary."
|
|
232
|
+
: "Do not open hosted beta. Resolve the blocked reasons and rerun the selected-repository source-checkout trial gate.",
|
|
233
|
+
privacy: {
|
|
234
|
+
includesRawSource: false,
|
|
235
|
+
includesRawDiffs: false,
|
|
236
|
+
includesPrivateCheckoutPath: false,
|
|
237
|
+
includesInstallationToken: false,
|
|
238
|
+
claimsPublicHostedScanner: false
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
}
|
|
176
242
|
export async function runHostedReadOnlyCheckoutScan(input, options) {
|
|
177
243
|
const { plan } = input;
|
|
178
244
|
const { checkout, cli } = plan;
|
|
@@ -339,6 +405,18 @@ function isTrustedFixedReadOnlyPlan(input) {
|
|
|
339
405
|
function arraysEqual(left, right) {
|
|
340
406
|
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
341
407
|
}
|
|
408
|
+
function operatorProofBlockedReasons(input) {
|
|
409
|
+
const reasons = [];
|
|
410
|
+
if (!input.liveSmokePassed)
|
|
411
|
+
reasons.push("live_smoke_missing");
|
|
412
|
+
if (!input.rollbackTested)
|
|
413
|
+
reasons.push("rollback_test_missing");
|
|
414
|
+
if (!input.monitoringEvidence)
|
|
415
|
+
reasons.push("monitoring_evidence_missing");
|
|
416
|
+
if (!input.incidentOwnerRecorded)
|
|
417
|
+
reasons.push("incident_owner_missing");
|
|
418
|
+
return reasons;
|
|
419
|
+
}
|
|
342
420
|
function compactFinding(value) {
|
|
343
421
|
if (!isRecord(value))
|
|
344
422
|
return [];
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -213,18 +213,18 @@ node dist/cli.js scan --root /path/to/your-saas
|
|
|
213
213
|
|
|
214
214
|
这个仓库是公开 GitHub 仓库。
|
|
215
215
|
|
|
216
|
-
CLI 已发布到 npm:`ai-saas-guard@0.
|
|
216
|
+
CLI 已发布到 npm:`ai-saas-guard@0.43.0`。GitHub Action 支持 `v0` 浮动标签,也支持固定版本标签,例如 `v0.43.0`。
|
|
217
217
|
|
|
218
218
|
| 模块 | 状态 |
|
|
219
219
|
| --- | --- |
|
|
220
220
|
| 公开 GitHub 仓库 | 已可用 |
|
|
221
|
-
| npm CLI | `ai-saas-guard@0.
|
|
222
|
-
| GitHub Action | `zr9959/ai-saas-guard@v0` 或固定标签 `v0.
|
|
221
|
+
| npm CLI | `ai-saas-guard@0.43.0` |
|
|
222
|
+
| GitHub Action | `zr9959/ai-saas-guard@v0` 或固定标签 `v0.43.0` |
|
|
223
223
|
| 输出格式 | 上线决策队列、短 summary、Terminal、JSON、SARIF 和 PR markdown |
|
|
224
224
|
| 项目配置 | `.ai-saas-guard.json` 支持规则开关、severity 覆盖、suppressions 和 fail threshold |
|
|
225
225
|
| 隐私模型 | 本地优先、只读扫描、不调用 LLM、不上传代码 |
|
|
226
|
-
| 当前版本 | `0.
|
|
227
|
-
| Action 标签 | `v0.
|
|
226
|
+
| 当前版本 | `0.43.0` 增加商业化前的 Phase 4 hosted beta readiness gate 和 Phase 5 team launch gate,同时继续保持 billing disabled |
|
|
227
|
+
| Action 标签 | `v0.43.0`、`v0` |
|
|
228
228
|
| npm 发布 | GitHub Actions Trusted Publisher/OIDC,无需长期 npm token |
|
|
229
229
|
| 仓库可信度加固 | 严格 branch protection、Dependabot、CodeQL、fast-check fuzzing、signed release provenance assets、private vulnerability reporting、secret scanning 和 push protection |
|
|
230
230
|
| Cloudflare hosted ingress | 已部署到 `https://ai-saas-guard-hosted.zr9959.workers.dev`;安装和隐私说明见 [hosted-install-privacy.md](hosted-install-privacy.md);提供 `/github/app/install-info`,签名 GitHub App webhook delivery、compact Check Run 和 installation cleanup staging smoke 已通过 |
|
|
@@ -383,7 +383,9 @@ GitHub Marketplace wrapper 决策见 [docs/github-marketplace-wrapper-decision.m
|
|
|
383
383
|
|
|
384
384
|
当前仓库已经包含未来 Hosted GitHub App 的设计文档、纯契约测试、第一个真实 Cloudflare hosted ingress,以及 Node/container read-only checkout scan runner。私有 staging GitHub App `ai-saas-guard-hosted` 已安装到 `zr9959/ai-saas-guard`,Cloudflare 已配置所需的云端凭据绑定。Worker 代码已经能接收签名 webhook、写入 KV 队列、换取 scoped installation token、读取 GitHub PR file metadata、做 compact PR-risk classification,并发布有长度上限的 selected-repository Check Run summary;`/github/app/install-info` 会返回公开安全的安装说明、权限、事件、隐私边界和卸载说明。签名 installation deletion 和 repository removal 事件会删除匹配的 compact records。当前端到端 GitHub App webhook delivery smoke 已通过,证据记录在 [docs/hosted-operations-evidence.md](hosted-operations-evidence.md)。Cloudflare ingress 本身仍不是完整 source checkout scan worker。
|
|
385
385
|
|
|
386
|
-
下一步 hosted source checkout 仍然要保持窄边界:把现有 read-only checkout worker 放到同一个 selected-repository identity 后面,继续固定 `pr-risk --json` 命令,只把 compact findings 写入 Check Run,并在扩大 trial 前要求 deployed cleanup、log-boundary 和 rollback evidence。
|
|
386
|
+
下一步 hosted source checkout 仍然要保持窄边界:把现有 read-only checkout worker 放到同一个 selected-repository identity 后面,继续固定 `pr-risk --json` 命令,只把 compact findings 写入 Check Run,并在扩大 trial 前要求 deployed cleanup、log-boundary 和 rollback evidence。hosted worker export 现在包含 `createHostedSourceCheckoutTrialPlan`、`createHostedSourceCheckoutEvidence` 和 `evaluateHostedSourceCheckoutTrialGate`,用于在进入 Phase 4 beta 前统一检查 checkout start/end、token removal、CLI start/end、compact report write、Check Run write、cleanup status、live smoke、rollback、monitoring 和 incident owner proof。
|
|
387
|
+
|
|
388
|
+
`ai-saas-guard/hosted/beta` export 新增 `evaluateHostedBetaReadinessGate` 和 `evaluateTeamLaunchGateReadiness`。这两个商业化前 gate 会阻止 hosted beta 在 selected-repository install limit、abuse control、安全 telemetry、uninstall deletion proof、rollback、support owner、beta smoke 和 no-audit-claim wording 不完整时开放;也会阻止 team use 在 org policy config、required status-check docs、suppression audit、reviewer checklist、release evidence export、retention docs 和 billing-disabled proof 不完整时推进。
|
|
387
389
|
|
|
388
390
|
Hosted 安装、权限和隐私边界见 [hosted-install-privacy.md](hosted-install-privacy.md):selected-repository 权限、支持的 GitHub 事件、Check Run 数据边界、卸载清理,以及为什么本地 CLI 仍然是私有/离线路径。
|
|
389
391
|
|
|
@@ -24,6 +24,11 @@ The package exports `ai-saas-guard/hosted/app` with:
|
|
|
24
24
|
- `createHostedNodeCheckoutAppPlatform`
|
|
25
25
|
- `planHostedNodeContainerDeployment`
|
|
26
26
|
|
|
27
|
+
The package also exports `ai-saas-guard/hosted/beta` with:
|
|
28
|
+
|
|
29
|
+
- `evaluateHostedBetaReadinessGate`
|
|
30
|
+
- `evaluateTeamLaunchGateReadiness`
|
|
31
|
+
|
|
27
32
|
The staging deployment planner in [hosted-staging-deployment.md](hosted-staging-deployment.md) composes this Node/container deployment plan with real provider references, hosted operational release-gate evidence, and GitHub App promotion gates.
|
|
28
33
|
|
|
29
34
|
## HTTP Ingress
|
|
@@ -134,6 +139,6 @@ It does not return:
|
|
|
134
139
|
|
|
135
140
|
## Current Status
|
|
136
141
|
|
|
137
|
-
The repository can now instantiate a Node/container hosted app skeleton, route signed webhooks into the hosted service runtime, process one worker tick through adapters, compose the real read-only checkout scan runner behind a token-provider boundary, expose clamped worker safety budgets,
|
|
142
|
+
The repository can now instantiate a Node/container hosted app skeleton, route signed webhooks into the hosted service runtime, process one worker tick through adapters, compose the real read-only checkout scan runner behind a token-provider boundary, expose clamped worker safety budgets, validate provider adapter references before deployment, evaluate one Phase 3 source-checkout trial gate through `evaluateHostedSourceCheckoutTrialGate`, and evaluate pre-commercial Phase 4/5 gates through `evaluateHostedBetaReadinessGate` and `evaluateTeamLaunchGateReadiness`.
|
|
138
143
|
|
|
139
|
-
A public hosted environment still requires actual platform infrastructure, a public HTTPS webhook URL, platform secrets, durable queue/storage, worker sandboxing, GitHub Checks API credentials at runtime, monitoring, rollback, incident-response evidence, and the
|
|
144
|
+
A public hosted environment still requires actual platform infrastructure, a public HTTPS webhook URL, platform secrets, durable queue/storage, worker sandboxing, GitHub Checks API credentials at runtime, monitoring, rollback, incident-response evidence, a passing Phase 3 gate, and a passing Phase 4 beta readiness gate. Team workflow rollout additionally requires the Phase 5 team launch gate. Use [hosted-staging-deployment.md](hosted-staging-deployment.md) to plan and block staging exposure until those provider references and evidence exist.
|
|
@@ -179,6 +179,41 @@ The v0.41 source-checkout trial boundary is executable as a pure contract before
|
|
|
179
179
|
|
|
180
180
|
The evidence object must stay compact and privacy-safe. It may contain job key, stage IDs, timestamps, summary counts, compact finding count, cleanup status, and safe blocked reasons. It must not include source, diffs, checkout paths, installation tokens, PR-authored commands, private URLs, or low-level filesystem errors.
|
|
181
181
|
|
|
182
|
+
### Phase 3 Source Checkout Trial Gate
|
|
183
|
+
|
|
184
|
+
The v0.42 hosted worker export adds `evaluateHostedSourceCheckoutTrialGate`. This is the single gate for closing Phase 3 and deciding whether the project may move toward Phase 4 hosted beta.
|
|
185
|
+
|
|
186
|
+
The gate combines:
|
|
187
|
+
|
|
188
|
+
- source-checkout trial plan checks from `createHostedSourceCheckoutTrialPlan`
|
|
189
|
+
- stage evidence checks from `createHostedSourceCheckoutEvidence`
|
|
190
|
+
- read-only checkout scan checks from `evaluateHostedReadOnlyCheckoutScanGate`
|
|
191
|
+
- operator proof for live smoke, rollback, monitoring evidence, and incident owner recording
|
|
192
|
+
|
|
193
|
+
It returns `readyForPhase4Beta: true` only when all four layers pass. Otherwise it returns safe blocked reasons and the next action: do not open hosted beta until the missing proof is rerun. The response must remain compact and privacy-safe: no raw source, raw diffs, checkout paths, installation tokens, public hosted scanner claim, private URLs, or PR-authored commands.
|
|
194
|
+
|
|
195
|
+
### Phase 4 Hosted Beta Readiness Gate
|
|
196
|
+
|
|
197
|
+
The v0.43 `ai-saas-guard/hosted/beta` export adds `evaluateHostedBetaReadinessGate`. This gate is pre-commercial. It does not enable billing, pricing, usage metering, or a marketplace listing.
|
|
198
|
+
|
|
199
|
+
It returns `readyForPublicBeta: true` only when:
|
|
200
|
+
|
|
201
|
+
- Phase 3 source-checkout trial gate already passed
|
|
202
|
+
- installs remain selected-repository only
|
|
203
|
+
- public install and privacy docs are ready
|
|
204
|
+
- rate limits and an abuse kill switch are enabled
|
|
205
|
+
- telemetry records only safe operational metadata
|
|
206
|
+
- uninstall deletion, rollback, incident owner, support path, and beta smoke evidence exist
|
|
207
|
+
- public wording avoids pentest, full-audit, and certification claims
|
|
208
|
+
- raw source, raw diffs, PR-authored text, and installation tokens are not stored
|
|
209
|
+
- repository and concurrency limits stay within the beta caps
|
|
210
|
+
|
|
211
|
+
### Phase 5 Team Launch Gate
|
|
212
|
+
|
|
213
|
+
The same export adds `evaluateTeamLaunchGateReadiness`. This gate is also pre-commercial. It exists so design partners can use the hosted launch gate in a team workflow before paid packaging exists.
|
|
214
|
+
|
|
215
|
+
It returns `readyForTeamUse: true` only when the hosted beta gate passed and the team workflow has org policy config, required status-check documentation, suppression audit, reviewer checklist, release evidence export, team docs, admin-bypass documentation, retention documentation, and proof that commercial billing remains disabled.
|
|
216
|
+
|
|
182
217
|
### Log Boundary Evidence
|
|
183
218
|
|
|
184
219
|
Before exposure, sample ingress, queue, worker, report, and Check Run logs for the release candidate. The sample may contain scan key, installation ID, repository ID, PR number, head SHA, scanner version, duration, summary counts, error class, and cleanup status.
|
|
@@ -10,6 +10,14 @@ Recorded on 2026-05-25 from the deployed Cloudflare Worker plus temporary GitHub
|
|
|
10
10
|
|
|
11
11
|
| Check | Evidence | Result |
|
|
12
12
|
| --- | --- | --- |
|
|
13
|
+
| Cloudflare Worker health, v0.43.0 | `GET https://ai-saas-guard-hosted.zr9959.workers.dev/healthz` returned `ok: true`, routes including `/github/app/install-info`, `checkRunPublisher: "configured"`, `scannerVersion: "0.43.0"`, and all privacy flags set to false for raw payloads, PR text, source, diffs, secrets, customer payloads, checkout paths, and installation tokens | Passed |
|
|
14
|
+
| Public install guidance, v0.43.0 | `GET https://ai-saas-guard-hosted.zr9959.workers.dev/github/app/install-info` returned the `ai-saas-guard-hosted` install URL, selected-repository boundary wording, first-slice permissions `checks: write`, `contents: read`, `metadata: read`, `pull_requests: read`, subscribed events `pull_request`, `installation`, and `installation_repositories`, uninstall cleanup wording, `scannerVersion: "0.43.0"`, and no private keys, webhook secrets, installation tokens, source, diffs, or customer payloads | Passed |
|
|
15
|
+
| Deployed Worker version, v0.43.0 | `wrangler deploy` uploaded 38.57 KiB / gzip 9.86 KiB and deployed version `8744d3db-0114-4653-85e2-f1554ff1b26b` at `2026-05-25T14:00:03Z` verification time | Passed |
|
|
16
|
+
| Real hosted PR smoke, v0.43.0 | `node scripts/hosted-pr-smoke.mjs --evidence-file /tmp/ai-saas-guard-hosted-smoke-v0.43.json` opened temporary PR `#91`, waited for Check Run `77724168740` on head SHA `6d62e52b243d657dd949b48c3333224905caa830`, received conclusion `success`, closed the PR, restored the original branch, deleted the local branch, and deleted 9 staging KV records with `remainingSmokeKeys: 0`; `gh pr view 91` returned `state: "CLOSED"`, `git ls-remote --heads origin codex/hosted-smoke-20260525140128` returned no remote branch, and `wrangler kv key list --namespace-id fa5344fbd7944de6a776bf8731d58460 --remote` returned `[]` after cleanup | Passed |
|
|
17
|
+
| Cloudflare Worker health, v0.42.0 | `GET https://ai-saas-guard-hosted.zr9959.workers.dev/healthz` returned `ok: true`, routes including `/github/app/install-info`, `checkRunPublisher: "configured"`, `scannerVersion: "0.42.0"`, and all privacy flags set to false for raw payloads, PR text, source, diffs, secrets, customer payloads, checkout paths, and installation tokens | Passed |
|
|
18
|
+
| Public install guidance, v0.42.0 | `GET https://ai-saas-guard-hosted.zr9959.workers.dev/github/app/install-info` returned the `ai-saas-guard-hosted` install URL, selected-repository boundary wording, first-slice permissions `checks: write`, `contents: read`, `metadata: read`, `pull_requests: read`, subscribed events `pull_request`, `installation`, and `installation_repositories`, uninstall cleanup wording, `scannerVersion: "0.42.0"`, and no private keys, webhook secrets, installation tokens, source, diffs, or customer payloads | Passed |
|
|
19
|
+
| Deployed Worker version, v0.42.0 | `wrangler deploy` uploaded 38.57 KiB / gzip 9.86 KiB and deployed version `6de0811e-11bf-46a6-9b7b-cbecda409695` at `2026-05-25T13:40:11Z` verification time | Passed |
|
|
20
|
+
| Real hosted PR smoke, v0.42.0 | `node scripts/hosted-pr-smoke.mjs --evidence-file /tmp/ai-saas-guard-hosted-smoke-v0.42.json` opened temporary PR `#89`, waited for Check Run `77721238202` on head SHA `66dfffde2ffa1a563ebc45fe7b22468d2f060e22`, received conclusion `success`, closed the PR, restored the original branch, deleted the local branch, and deleted 9 staging KV records with `remainingSmokeKeys: 0`; `gh pr view 89` returned `state: "CLOSED"`, `git ls-remote --heads origin codex/hosted-smoke-20260525134106` returned no remote branch, and `wrangler kv key list --namespace-id fa5344fbd7944de6a776bf8731d58460 --remote` returned `[]` after cleanup | Passed |
|
|
13
21
|
| Cloudflare Worker health, v0.41.0 | `GET https://ai-saas-guard-hosted.zr9959.workers.dev/healthz` returned `ok: true`, routes including `/github/app/install-info`, `checkRunPublisher: "configured"`, `scannerVersion: "0.41.0"`, and all privacy flags set to false for raw payloads, PR text, source, diffs, secrets, customer payloads, checkout paths, and installation tokens | Passed |
|
|
14
22
|
| Public install guidance, v0.41.0 | `GET https://ai-saas-guard-hosted.zr9959.workers.dev/github/app/install-info` returned the `ai-saas-guard-hosted` install URL, selected-repository boundary wording, first-slice permissions `checks: write`, `contents: read`, `metadata: read`, `pull_requests: read`, subscribed events `pull_request`, `installation`, and `installation_repositories`, uninstall cleanup wording, `scannerVersion: "0.41.0"`, and no private keys, webhook secrets, installation tokens, source, diffs, or customer payloads | Passed |
|
|
15
23
|
| Deployed Worker version, v0.41.0 | `wrangler deploy` uploaded 38.57 KiB / gzip 9.86 KiB and deployed version `fb0b4726-ac75-4577-942b-fdeed7752979` at `2026-05-25T13:22:28Z` verification time | Passed |
|
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.43.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.43.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.43.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.
|
|
@@ -23,7 +23,7 @@ This Worker is a real hosted ingress with first-slice Check Run publishing code,
|
|
|
23
23
|
- `HOSTED_EVENTS`: Cloudflare KV namespace for compact delivery and queued scan records.
|
|
24
24
|
- `WEBHOOK_SECRET`: Worker secret matching the GitHub App webhook secret.
|
|
25
25
|
- `GITHUB_APP_PRIVATE_KEY`: Worker secret for the staging GitHub App private key, used only in memory to sign short-lived GitHub App JWTs.
|
|
26
|
-
- `SCANNER_VERSION`: public version string, currently `0.
|
|
26
|
+
- `SCANNER_VERSION`: public version string, currently `0.43.0`.
|
|
27
27
|
- `GITHUB_APP_ID`, `GITHUB_APP_SLUG`, `GITHUB_APP_INSTALLATION_ID`: public staging identifiers for the private GitHub App installation.
|
|
28
28
|
|
|
29
29
|
## Deployment
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-saas-guard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.0",
|
|
4
4
|
"description": "Local-first CLI that catches launch blockers in AI-built Next.js/Supabase/Stripe SaaS apps.",
|
|
5
5
|
"readmeFilename": "README.md",
|
|
6
6
|
"type": "module",
|
|
@@ -74,6 +74,10 @@
|
|
|
74
74
|
"types": "./dist/hosted/deployed-staging.d.ts",
|
|
75
75
|
"default": "./dist/hosted/deployed-staging.js"
|
|
76
76
|
},
|
|
77
|
+
"./hosted/beta": {
|
|
78
|
+
"types": "./dist/hosted/beta.d.ts",
|
|
79
|
+
"default": "./dist/hosted/beta.js"
|
|
80
|
+
},
|
|
77
81
|
"./hosted/worker": {
|
|
78
82
|
"types": "./dist/hosted/worker.d.ts",
|
|
79
83
|
"default": "./dist/hosted/worker.js"
|