shippingszn 0.9.2 → 0.9.4
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 +28 -20
- package/dist/index.js +65 -83
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,12 +12,13 @@ pnpm dlx shippingszn@latest
|
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
The CLI **never writes, modifies, or deletes** any files - it only reads.
|
|
15
|
-
Normal runs
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
Normal runs create a locked scan handoff for checkout and send one anonymous
|
|
16
|
+
Wall report-card summary with score, severity counts, files scanned, scanner
|
|
17
|
+
version, and safe stack tags. It never uploads source code, repo URLs, project
|
|
18
|
+
names, secrets, handles, or emails. Finding-level detail stays out of public
|
|
19
|
+
CLI/Wall output and opens inside the paid Launch Fix Kit.
|
|
19
20
|
|
|
20
|
-
Human output starts with a Launch
|
|
21
|
+
Human output starts with a Launch Debt Score, completed checks, and severity
|
|
21
22
|
counts. Run with `--json` to get the same score-and-counts summary in a
|
|
22
23
|
machine-readable shape:
|
|
23
24
|
|
|
@@ -27,8 +28,14 @@ machine-readable shape:
|
|
|
27
28
|
"band": "no_go",
|
|
28
29
|
"counts": { "critical": 1, "high": 3, "medium": 4, "lower": 2 },
|
|
29
30
|
"filesScanned": 128,
|
|
31
|
+
"coverage": { "checksCompleted": 19, "checklistAreas": 46 },
|
|
30
32
|
"detailsLocked": true,
|
|
31
|
-
"unlockUrl": "https://shippingszn.com/fix-kit"
|
|
33
|
+
"unlockUrl": "https://shippingszn.com/fix-kit?scanResultId=00000000-0000-4000-8000-000000000123",
|
|
34
|
+
"scanHandoff": {
|
|
35
|
+
"status": "uploaded",
|
|
36
|
+
"resultId": "00000000-0000-4000-8000-000000000123",
|
|
37
|
+
"unlockUrl": "https://shippingszn.com/fix-kit?scanResultId=00000000-0000-4000-8000-000000000123"
|
|
38
|
+
}
|
|
32
39
|
}
|
|
33
40
|
```
|
|
34
41
|
|
|
@@ -37,14 +44,14 @@ They unlock inside the Launch Fix Kit.
|
|
|
37
44
|
|
|
38
45
|
## Aggregate summary
|
|
39
46
|
|
|
40
|
-
Plain `npx shippingszn@latest` sends the
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
Plain `npx shippingszn@latest` sends the Wall summary automatically. The stored
|
|
48
|
+
row is anonymous and intentionally small: score, launch label, files scanned,
|
|
49
|
+
finding counts by severity, detected stack tags, scanner version, and timestamp.
|
|
43
50
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
it
|
|
51
|
+
The same run also creates a scan-specific paid-report handoff. The terminal
|
|
52
|
+
prints a `/fix-kit?scanResultId=...` URL so checkout can carry that scan into
|
|
53
|
+
the Launch Fix Kit after purchase. `--proof` is still accepted for old docs, but
|
|
54
|
+
it is no longer required.
|
|
48
55
|
|
|
49
56
|
## What gets checked
|
|
50
57
|
|
|
@@ -123,8 +130,8 @@ shippingszn [path] [options]
|
|
|
123
130
|
|
|
124
131
|
Options:
|
|
125
132
|
--json Output a machine-readable JSON summary.
|
|
126
|
-
--proof
|
|
127
|
-
Launch Fix Kit URL.
|
|
133
|
+
--proof Backward-compatible alias. Normal runs already return
|
|
134
|
+
a scan-specific Launch Fix Kit URL.
|
|
128
135
|
--base-url <url> Base URL used to build checkout and Fix Kit links.
|
|
129
136
|
--cwd <path> Directory to scan. Default: current working directory.
|
|
130
137
|
--no-color Disable ANSI colors in the human-readable summary.
|
|
@@ -151,11 +158,12 @@ summary as a comment: score, severity counts, and unlock URL.
|
|
|
151
158
|
## Privacy
|
|
152
159
|
|
|
153
160
|
`shippingszn` reads files on your machine. It never uploads source code. By
|
|
154
|
-
default it
|
|
155
|
-
|
|
156
|
-
detected stack tags, scanner version,
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
default it creates a locked scan handoff for checkout and makes one best-effort
|
|
162
|
+
outbound request to post anonymous Wall stats: score, launch label, files
|
|
163
|
+
scanned count, finding counts by severity, detected stack tags, scanner version,
|
|
164
|
+
and timestamp. Wall stats never include source code, file paths, filenames,
|
|
165
|
+
project names, repo URLs, secrets, emails, handles, finding titles, evidence, or
|
|
166
|
+
report contents. The Wall summary is automatic and not user-configurable.
|
|
159
167
|
|
|
160
168
|
## License
|
|
161
169
|
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import * as
|
|
5
|
-
import * as
|
|
4
|
+
import * as path18 from "node:path";
|
|
5
|
+
import * as process from "node:process";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
|
|
8
8
|
// src/checks/secrets.ts
|
|
@@ -3685,13 +3685,8 @@ async function publishScan(totals, filesScanned, opts) {
|
|
|
3685
3685
|
}
|
|
3686
3686
|
|
|
3687
3687
|
// src/proof.ts
|
|
3688
|
-
import * as path18 from "node:path";
|
|
3689
3688
|
var PROOF_TIMEOUT_MS = 5e3;
|
|
3690
3689
|
var MAX_FINDINGS = 100;
|
|
3691
|
-
function shouldUploadProof() {
|
|
3692
|
-
const v = process.env["SHIPPINGSZN_PROOF"] ?? "";
|
|
3693
|
-
return v === "1" || v.toLowerCase() === "true" || v === "yes";
|
|
3694
|
-
}
|
|
3695
3690
|
function clampText(value, max, fallback = "") {
|
|
3696
3691
|
const text = value ?? fallback;
|
|
3697
3692
|
return text.length > max ? text.slice(0, max - 3) + "..." : text;
|
|
@@ -3705,8 +3700,8 @@ function buildBadgeMarkdown(baseUrl, id, score) {
|
|
|
3705
3700
|
scanResultId: id,
|
|
3706
3701
|
theme: "dark"
|
|
3707
3702
|
});
|
|
3708
|
-
const
|
|
3709
|
-
return `[})](${fixKitUrl})`;
|
|
3710
3705
|
}
|
|
3711
3706
|
function buildProofPayload(report, scannerVersion) {
|
|
3712
3707
|
const counts = {
|
|
@@ -3719,7 +3714,7 @@ function buildProofPayload(report, scannerVersion) {
|
|
|
3719
3714
|
version: 1,
|
|
3720
3715
|
source: report.source ?? "cli",
|
|
3721
3716
|
scanner: "shippingszn",
|
|
3722
|
-
targetName:
|
|
3717
|
+
targetName: "Anonymous CLI scan",
|
|
3723
3718
|
score: report.launchReadiness.score,
|
|
3724
3719
|
label: report.launchReadiness.label,
|
|
3725
3720
|
decision: report.launchReadiness.decision,
|
|
@@ -4376,13 +4371,13 @@ var PKG_VERSION = (() => {
|
|
|
4376
4371
|
})();
|
|
4377
4372
|
function parseArgs(argv2) {
|
|
4378
4373
|
const opts = {
|
|
4379
|
-
cwd:
|
|
4374
|
+
cwd: process.cwd(),
|
|
4380
4375
|
json: false,
|
|
4381
|
-
baseUrl:
|
|
4376
|
+
baseUrl: process.env.SHIPPINGSZN_BASE_URL ?? process.env.VIBE_LAUNCH_CHECK_BASE_URL ?? DEFAULT_BASE_URL2,
|
|
4382
4377
|
help: false,
|
|
4383
4378
|
version: false,
|
|
4384
|
-
noColor: !!
|
|
4385
|
-
proof:
|
|
4379
|
+
noColor: !!process.env.NO_COLOR,
|
|
4380
|
+
proof: true
|
|
4386
4381
|
};
|
|
4387
4382
|
for (let i = 0; i < argv2.length; i++) {
|
|
4388
4383
|
const a = argv2[i];
|
|
@@ -4394,8 +4389,8 @@ function parseArgs(argv2) {
|
|
|
4394
4389
|
else if (a === "--no-publish" || a === "--publish")
|
|
4395
4390
|
opts.unsupportedWallFlag = a;
|
|
4396
4391
|
else if (a === "--base-url") opts.baseUrl = argv2[++i] ?? opts.baseUrl;
|
|
4397
|
-
else if (a === "--cwd") opts.cwd =
|
|
4398
|
-
else if (!a.startsWith("-")) opts.cwd =
|
|
4392
|
+
else if (a === "--cwd") opts.cwd = path18.resolve(argv2[++i] ?? opts.cwd);
|
|
4393
|
+
else if (!a.startsWith("-")) opts.cwd = path18.resolve(a);
|
|
4399
4394
|
}
|
|
4400
4395
|
return opts;
|
|
4401
4396
|
}
|
|
@@ -4415,7 +4410,7 @@ function color(enabled) {
|
|
|
4415
4410
|
}
|
|
4416
4411
|
var SEVERITY_ORDER = ["critical", "high", "medium", "lower"];
|
|
4417
4412
|
function printHelp() {
|
|
4418
|
-
|
|
4413
|
+
process.stdout.write(
|
|
4419
4414
|
`shippingszn v${PKG_VERSION}
|
|
4420
4415
|
|
|
4421
4416
|
Read-only scanner that checks the current project against a small set of
|
|
@@ -4426,8 +4421,8 @@ Usage:
|
|
|
4426
4421
|
|
|
4427
4422
|
Options:
|
|
4428
4423
|
--json Output a machine-readable JSON summary.
|
|
4429
|
-
--proof
|
|
4430
|
-
Launch Fix Kit URL.
|
|
4424
|
+
--proof Backward-compatible alias. Normal runs already return
|
|
4425
|
+
a scan-specific Launch Fix Kit URL.
|
|
4431
4426
|
--base-url <url> Base URL used to build checkout and Fix Kit links.
|
|
4432
4427
|
(default: ${DEFAULT_BASE_URL2})
|
|
4433
4428
|
--cwd <path> Directory to scan. Default: current working directory.
|
|
@@ -4438,35 +4433,36 @@ Options:
|
|
|
4438
4433
|
This is the FREE preflight. It tells you launch debt exists. It does NOT tell
|
|
4439
4434
|
you what's broken or how to fix it \u2014 that's gated behind the $49 Launch Fix Kit
|
|
4440
4435
|
(unlocks full findings + 46-item workbook + paste-ready AI-builder prompts +
|
|
4441
|
-
verification steps + red-flag checks). Read-only on disk.
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
or opt-out flag. Exit
|
|
4436
|
+
verification steps + red-flag checks). Read-only on disk. Normal runs create a
|
|
4437
|
+
locked scan handoff for checkout and send anonymous Wall stats (score, severity
|
|
4438
|
+
counts, file count, scanner version \u2014 no project name, no paths, no
|
|
4439
|
+
finding-level detail); there is no Wall publish opt-in or opt-out flag. Exit
|
|
4440
|
+
code non-zero if any critical findings.
|
|
4445
4441
|
`
|
|
4446
4442
|
);
|
|
4447
4443
|
}
|
|
4448
4444
|
function scanSource() {
|
|
4449
|
-
return
|
|
4445
|
+
return process.env.GITHUB_ACTIONS === "true" ? "github" : "cli";
|
|
4450
4446
|
}
|
|
4451
4447
|
async function run() {
|
|
4452
|
-
const opts = parseArgs(
|
|
4448
|
+
const opts = parseArgs(process.argv.slice(2));
|
|
4453
4449
|
if (opts.help) {
|
|
4454
4450
|
printHelp();
|
|
4455
4451
|
return 0;
|
|
4456
4452
|
}
|
|
4457
4453
|
if (opts.version) {
|
|
4458
|
-
|
|
4454
|
+
process.stdout.write(`${PKG_VERSION}
|
|
4459
4455
|
`);
|
|
4460
4456
|
return 0;
|
|
4461
4457
|
}
|
|
4462
4458
|
if (opts.unsupportedWallFlag) {
|
|
4463
|
-
|
|
4464
|
-
`${opts.unsupportedWallFlag} is not supported. shippingszn sends anonymous score
|
|
4459
|
+
process.stderr.write(
|
|
4460
|
+
`${opts.unsupportedWallFlag} is not supported. shippingszn sends anonymous Wall stats on normal runs: score, severity counts, file count, scanner version, and safe stack tags. It never uploads code, file paths, finding-level details, project names, repo URLs, secrets, emails, or handles.
|
|
4465
4461
|
`
|
|
4466
4462
|
);
|
|
4467
4463
|
return 2;
|
|
4468
4464
|
}
|
|
4469
|
-
const c = color(!opts.noColor &&
|
|
4465
|
+
const c = color(!opts.noColor && process.stdout.isTTY === true && !opts.json);
|
|
4470
4466
|
const files = await listFiles(opts.cwd);
|
|
4471
4467
|
const tracked = getTrackedFiles(opts.cwd);
|
|
4472
4468
|
const ctx = { rootDir: opts.cwd, files };
|
|
@@ -4489,7 +4485,7 @@ async function run() {
|
|
|
4489
4485
|
const fixKitUrl = `${trimmedBaseUrl}/fix-kit`;
|
|
4490
4486
|
const reportUrl = fixKitUrl;
|
|
4491
4487
|
const proofCreatePath = `${trimmedBaseUrl}/scan`;
|
|
4492
|
-
const proofUploadHint = "
|
|
4488
|
+
const proofUploadHint = "Normal runs automatically generate a scan-specific Launch Fix Kit URL.";
|
|
4493
4489
|
const tracked_aware = applyTrackingAwareSeverity(all, tracked);
|
|
4494
4490
|
const source = scanSource();
|
|
4495
4491
|
const enriched = tracked_aware.map((f) => {
|
|
@@ -4635,9 +4631,6 @@ async function run() {
|
|
|
4635
4631
|
const automatedAreas = CHECKLIST.filter(
|
|
4636
4632
|
(item) => item.cliCoverage === "automated"
|
|
4637
4633
|
).length;
|
|
4638
|
-
const ownerVerifyAreas = CHECKLIST.filter(
|
|
4639
|
-
(item) => item.cliCoverage === "manual_only"
|
|
4640
|
-
).length;
|
|
4641
4634
|
const SCORE_BAND_LABEL = {
|
|
4642
4635
|
blocked: "NO-GO",
|
|
4643
4636
|
fix_first: "FIX FIRST",
|
|
@@ -4668,9 +4661,8 @@ async function run() {
|
|
|
4668
4661
|
counts: { ...totals },
|
|
4669
4662
|
filesScanned: files.length,
|
|
4670
4663
|
coverage: {
|
|
4671
|
-
automatedAreas,
|
|
4672
|
-
|
|
4673
|
-
totalAreas: CHECKLIST.length
|
|
4664
|
+
checksCompleted: automatedAreas,
|
|
4665
|
+
checklistAreas: CHECKLIST.length
|
|
4674
4666
|
},
|
|
4675
4667
|
scannerVersion: PKG_VERSION,
|
|
4676
4668
|
detailsLocked: true,
|
|
@@ -4680,113 +4672,103 @@ async function run() {
|
|
|
4680
4672
|
...wallUrl ? { url: wallUrl } : {},
|
|
4681
4673
|
...wallError ? { error: wallError } : {}
|
|
4682
4674
|
},
|
|
4683
|
-
|
|
4675
|
+
scanHandoff: {
|
|
4684
4676
|
status: proofResult.status,
|
|
4685
4677
|
...proofResult.status === "uploaded" ? {
|
|
4686
|
-
url: proofResult.proofUrl,
|
|
4687
4678
|
resultId: proofResult.id,
|
|
4688
|
-
|
|
4679
|
+
unlockUrl: proofResult.reportUrl
|
|
4689
4680
|
} : {},
|
|
4690
4681
|
...proofResult.status === "failed" && proofResult.error ? { error: proofResult.error } : {}
|
|
4691
4682
|
}
|
|
4692
4683
|
};
|
|
4693
|
-
|
|
4684
|
+
process.stdout.write(JSON.stringify(scoreSummary, null, 2) + "\n");
|
|
4694
4685
|
return totals.critical > 0 ? 1 : 0;
|
|
4695
4686
|
}
|
|
4696
4687
|
const bandColor = band === "no_go" ? c.red : band === "fix_first" ? c.yellow : band === "verify_before_launch" ? c.blue : c.green;
|
|
4697
|
-
|
|
4688
|
+
process.stdout.write(
|
|
4698
4689
|
`
|
|
4699
4690
|
${c.bold("shippingszn")} ${c.dim(`v${PKG_VERSION}`)}
|
|
4700
4691
|
`
|
|
4701
4692
|
);
|
|
4702
|
-
|
|
4693
|
+
process.stdout.write(c.dim(`Scanned ${files.length} files.
|
|
4703
4694
|
|
|
4704
4695
|
`));
|
|
4705
|
-
|
|
4696
|
+
process.stdout.write(
|
|
4706
4697
|
`${c.bold("Launch Debt Score:")} ${launchReadiness.score}/100 \u2014 ${bandColor(c.bold(bandLabel))}
|
|
4707
4698
|
|
|
4708
4699
|
`
|
|
4709
4700
|
);
|
|
4710
|
-
|
|
4701
|
+
process.stdout.write(`${c.bold("Findings detected:")}
|
|
4711
4702
|
`);
|
|
4712
|
-
|
|
4703
|
+
process.stdout.write(` ${c.red(`${totals.critical} critical`)}
|
|
4713
4704
|
`);
|
|
4714
|
-
|
|
4705
|
+
process.stdout.write(` ${c.yellow(`${totals.high} high`)}
|
|
4715
4706
|
`);
|
|
4716
|
-
|
|
4707
|
+
process.stdout.write(` ${c.blue(`${totals.medium} medium`)}
|
|
4717
4708
|
`);
|
|
4718
|
-
|
|
4709
|
+
process.stdout.write(` ${c.gray(`${totals.lower} lower`)}
|
|
4719
4710
|
|
|
4720
4711
|
`);
|
|
4721
|
-
|
|
4712
|
+
process.stdout.write(`${c.bold("Coverage:")}
|
|
4722
4713
|
`);
|
|
4723
|
-
|
|
4724
|
-
c.dim(
|
|
4725
|
-
` ${automatedAreas} of ${CHECKLIST.length} launch-readiness areas checked by the scanner
|
|
4726
|
-
`
|
|
4727
|
-
)
|
|
4728
|
-
);
|
|
4729
|
-
process2.stdout.write(
|
|
4730
|
-
c.dim(` ${ownerVerifyAreas} require owner verification
|
|
4714
|
+
process.stdout.write(
|
|
4715
|
+
c.dim(` ${automatedAreas} launch-readiness checks completed
|
|
4731
4716
|
|
|
4732
4717
|
`)
|
|
4733
4718
|
);
|
|
4734
4719
|
if (totals.critical + totals.high + totals.medium + totals.lower > 0) {
|
|
4735
4720
|
if (scanSpecificUnlockUrl) {
|
|
4736
|
-
|
|
4737
|
-
|
|
4721
|
+
process.stdout.write(c.bold("Unlock this exact scan:\n"));
|
|
4722
|
+
process.stdout.write(` ${c.cyan(scanSpecificUnlockUrl)}
|
|
4738
4723
|
`);
|
|
4739
|
-
|
|
4724
|
+
process.stdout.write(
|
|
4740
4725
|
c.dim(
|
|
4741
4726
|
" Full findings, file evidence, and AI-builder prompts stay locked until purchase.\n\n"
|
|
4742
4727
|
)
|
|
4743
4728
|
);
|
|
4744
4729
|
} else {
|
|
4745
|
-
|
|
4746
|
-
|
|
4730
|
+
process.stdout.write(c.bold("Full findings are locked:\n"));
|
|
4731
|
+
process.stdout.write(` ${c.cyan(fixKitUrl)}
|
|
4747
4732
|
`);
|
|
4748
|
-
|
|
4733
|
+
process.stdout.write(
|
|
4749
4734
|
c.dim(
|
|
4750
|
-
"
|
|
4735
|
+
" This run could not attach scan evidence. The full report stays locked until purchase.\n\n"
|
|
4751
4736
|
)
|
|
4752
4737
|
);
|
|
4753
4738
|
}
|
|
4754
4739
|
} else {
|
|
4755
4740
|
if (scanSpecificUnlockUrl) {
|
|
4756
|
-
|
|
4741
|
+
process.stdout.write(
|
|
4757
4742
|
c.green("No automated findings detected for this scan.\n")
|
|
4758
4743
|
);
|
|
4759
|
-
|
|
4760
|
-
|
|
4744
|
+
process.stdout.write(c.bold("Unlock this exact scan:\n"));
|
|
4745
|
+
process.stdout.write(` ${c.cyan(scanSpecificUnlockUrl)}
|
|
4761
4746
|
|
|
4762
4747
|
`);
|
|
4763
4748
|
} else {
|
|
4764
|
-
|
|
4749
|
+
process.stdout.write(
|
|
4765
4750
|
c.green(
|
|
4766
|
-
"No automated findings detected.
|
|
4751
|
+
"No automated findings detected. Unlock the Launch Fix Kit for the full checklist and written launch report:\n"
|
|
4767
4752
|
)
|
|
4768
4753
|
);
|
|
4769
|
-
|
|
4754
|
+
process.stdout.write(` ${c.cyan(fixKitUrl)}
|
|
4770
4755
|
`);
|
|
4771
|
-
|
|
4756
|
+
process.stdout.write(
|
|
4772
4757
|
c.dim(
|
|
4773
|
-
"
|
|
4758
|
+
" This run could not attach scan evidence. The full report stays locked until purchase.\n\n"
|
|
4774
4759
|
)
|
|
4775
4760
|
);
|
|
4776
4761
|
}
|
|
4777
4762
|
}
|
|
4778
|
-
if (proofResult.status === "
|
|
4779
|
-
|
|
4780
|
-
`)
|
|
4781
|
-
} else if (proofResult.status === "failed") {
|
|
4782
|
-
process2.stdout.write(
|
|
4783
|
-
c.dim(`(Proof upload failed: ${proofResult.error ?? "unknown"})
|
|
4763
|
+
if (proofResult.status === "failed") {
|
|
4764
|
+
process.stdout.write(
|
|
4765
|
+
c.dim(`(Scan handoff failed: ${proofResult.error ?? "unknown"})
|
|
4784
4766
|
`)
|
|
4785
4767
|
);
|
|
4786
4768
|
}
|
|
4787
4769
|
if (publishResult === "published") {
|
|
4788
|
-
|
|
4789
|
-
c.dim("(Anonymous
|
|
4770
|
+
process.stdout.write(
|
|
4771
|
+
c.dim("(Anonymous Wall stats sent: score + severity counts.)\n")
|
|
4790
4772
|
);
|
|
4791
4773
|
}
|
|
4792
4774
|
if (totals.critical > 0) {
|
|
@@ -4795,12 +4777,12 @@ ${c.bold("shippingszn")} ${c.dim(`v${PKG_VERSION}`)}
|
|
|
4795
4777
|
return 0;
|
|
4796
4778
|
}
|
|
4797
4779
|
run().then(
|
|
4798
|
-
(code) =>
|
|
4780
|
+
(code) => process.exit(code),
|
|
4799
4781
|
(err) => {
|
|
4800
|
-
|
|
4782
|
+
process.stderr.write(
|
|
4801
4783
|
`shippingszn failed: ${err instanceof Error ? err.message : String(err)}
|
|
4802
4784
|
`
|
|
4803
4785
|
);
|
|
4804
|
-
|
|
4786
|
+
process.exit(2);
|
|
4805
4787
|
}
|
|
4806
4788
|
);
|
package/package.json
CHANGED