proof-of-commitment 1.31.0 → 1.32.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 +18 -0
- package/index.js +70 -6
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -6,6 +6,24 @@
|
|
|
6
6
|
|
|
7
7
|
An MCP server and web tool that scores npm packages, PyPI packages, Rust crates, Go modules, and GitHub repos on **behavioral commitment** — signals that are harder to fake than stars, READMEs, or download counts.
|
|
8
8
|
|
|
9
|
+
```text
|
|
10
|
+
$ npx proof-of-commitment axios zod chalk lodash minimatch
|
|
11
|
+
Scoring 5 npm packages... done in 3.0s
|
|
12
|
+
|
|
13
|
+
Package Risk Score Publishers Downloads Age Provenance
|
|
14
|
+
chalk 🔴 CRITICAL 72 1 432.9M/wk 14.6y —
|
|
15
|
+
minimatch 🔴 CRITICAL 78 1 634.1M/wk 14.9y —
|
|
16
|
+
lodash 🔴 CRITICAL 80 1 158.9M/wk 14.1y —
|
|
17
|
+
zod 🔴 CRITICAL 83 1 161.2M/wk 6.3y 🔐 verified
|
|
18
|
+
axios 🔴 CRITICAL 88 1 115.7M/wk 11.8y 🔐 verified
|
|
19
|
+
⚠ COMPROMISED — axios token theft (2026-03-30)
|
|
20
|
+
|
|
21
|
+
⚠ 5 CRITICAL packages found.
|
|
22
|
+
CRITICAL = sole npm publisher + >10M weekly downloads (publish-access concentration risk)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`npm audit` flags none of these. They're not vulnerabilities — they're attack-surface concentration. One stolen npm token, one phished maintainer, and a single push reaches the whole ecosystem (axios, March 30 2026 — happened).
|
|
26
|
+
|
|
9
27
|
## The supply chain security problem
|
|
10
28
|
|
|
11
29
|
26 of the 91 npm packages with >10M weekly downloads have a **single npm publisher**. Together they account for over 3 billion downloads per week. `npm audit` doesn't surface this. Stars don't either.
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* proof-of-commitment CLI v1.
|
|
3
|
+
* proof-of-commitment CLI v1.32.0
|
|
4
4
|
* Scores npm/PyPI/Cargo/Go packages on behavioral commitment signals.
|
|
5
5
|
* Usage: npx proof-of-commitment [packages...] [options]
|
|
6
6
|
*/
|
|
@@ -609,7 +609,22 @@ function printTable(results, { totalScanned, totalCritical, lockfile } = {}) {
|
|
|
609
609
|
if (process.env.GITHUB_ACTIONS === 'true') {
|
|
610
610
|
if (effectiveCritical > 0) {
|
|
611
611
|
const critNames = results.filter(r => hasCritical(r.riskFlags)).slice(0, 5).map(r => r.name).join(', ');
|
|
612
|
-
|
|
612
|
+
// PR-check annotation is the single user-visible artifact outside the raw
|
|
613
|
+
// CI log. It must point at the conversion destination (/get-started with
|
|
614
|
+
// watchlist auto-seed), not the viewer (/audit). Pre-fix the annotation
|
|
615
|
+
// linked to /audit?packages= — same data the CI viewer already saw
|
|
616
|
+
// scrolled up in the log + an inline signup form one extra scroll away.
|
|
617
|
+
// Post-fix the link routes directly to /get-started?watch=…&eco=… which
|
|
618
|
+
// seeds the user's watchlist from this scan and arrives at an email
|
|
619
|
+
// capture as the primary form. Mirrors the same `?watch=…` URL contract
|
|
620
|
+
// (test/get-started-watch-param.test.ts) used by /audit's bottom CTA
|
|
621
|
+
// and the AUR-1579 / Snyk-comparison / Miasma / IronWorm blog posts.
|
|
622
|
+
// ref=cli-watch (not cli-ci-critical) because the latter is not in the
|
|
623
|
+
// backend's VALID_SOURCES and would get coerced to "web" — destroying
|
|
624
|
+
// attribution. cli-watch is already an accepted source.
|
|
625
|
+
const watchUrl = buildWatchUrl(results, 'cli-watch');
|
|
626
|
+
const ctaUrl = watchUrl || `https://getcommit.dev/audit?packages=${encodeURIComponent(critNames)}&utm_source=cli&utm_medium=ci-annotation`;
|
|
627
|
+
console.error(`::warning title=Commit: ${effectiveCritical} CRITICAL package${effectiveCritical > 1 ? 's' : ''}::Sole npm publisher + >10M downloads/week: ${critNames}. Watch + alert if scores change: ${ctaUrl}`);
|
|
613
628
|
}
|
|
614
629
|
if (compromisedCount > 0) {
|
|
615
630
|
const compNames = results.filter(r => r.compromised).slice(0, 5).map(r => r.name).join(', ');
|
|
@@ -650,10 +665,21 @@ function printTable(results, { totalScanned, totalCritical, lockfile } = {}) {
|
|
|
650
665
|
console.log(clr(c.dim, `\n 📊 Monitor ${effectiveCritical === 1 ? 'this package' : 'these packages'}: `) +
|
|
651
666
|
clr(c.cyan, `poc watch ${results.find(r => hasCritical(r.riskFlags))?.name || results[0]?.name}`));
|
|
652
667
|
} else if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
653
|
-
// Non-TTY (CI, piped): show
|
|
668
|
+
// Non-TTY (CI, piped): show both a clickable signup URL AND the one-step
|
|
669
|
+
// watch command. URL is for CI viewers reading log output in the browser
|
|
670
|
+
// (PR check tabs auto-link URLs); CLI command is for local-pipe / script
|
|
671
|
+
// contexts where copying a URL to a browser is friction. Two paths to
|
|
672
|
+
// the same outcome — see buildWatchUrl docstring for the rationale.
|
|
673
|
+
// Pre-fix this branch only emitted the CLI command, which requires the
|
|
674
|
+
// user to know the package name, run a second `npx`, and remember an
|
|
675
|
+
// email — a 3-decision ask in a CI log line that scrolls past.
|
|
654
676
|
const watchPkg = results.find(r => hasCritical(r.riskFlags))?.name || results[0]?.name;
|
|
677
|
+
const watchUrl = buildWatchUrl(results, 'cli-watch');
|
|
655
678
|
console.log(clr(c.dim, `\n 📊 Monitor ${effectiveCritical === 1 ? 'this' : 'these ' + effectiveCritical} CRITICAL ${effectiveCritical === 1 ? 'package' : 'packages'} — get alerted when scores change.`));
|
|
656
|
-
|
|
679
|
+
if (watchUrl) {
|
|
680
|
+
console.log(clr(c.dim, ' Web: ') + clr(c.cyan, watchUrl));
|
|
681
|
+
}
|
|
682
|
+
console.log(clr(c.dim, ' CLI: ') + clr(c.cyan, `poc watch ${watchPkg} --email you@company.com`));
|
|
657
683
|
console.log(clr(c.dim, ' Free: 3 packages, weekly digest. Developer $15/mo: 15 packages, daily scans.'));
|
|
658
684
|
}
|
|
659
685
|
// else: TTY mode — inlineSignup() will prompt interactively after printTable
|
|
@@ -664,8 +690,17 @@ function printTable(results, { totalScanned, totalCritical, lockfile } = {}) {
|
|
|
664
690
|
// text only in CI/piped output where interactive prompts can't fire.
|
|
665
691
|
// ref=audit-baseline distinguishes this funnel from audit-cli-429
|
|
666
692
|
// (rate-limit rescue) and from the static utm_source=cli help-line.
|
|
693
|
+
// Healthy-results non-TTY (CI, piped, no saved key) CTA. Mirror the
|
|
694
|
+
// CRITICAL branch's dual-path (Web + CLI). ref=audit-baseline keeps this
|
|
695
|
+
// funnel distinguishable from CRITICAL-driven cli-watch in api_keys.source
|
|
696
|
+
// breakdowns — important for measuring whether degradation-alert framing
|
|
697
|
+
// converts at all on clean results, separate from CRITICAL conversions.
|
|
698
|
+
const watchUrl = buildWatchUrl(results, 'audit-baseline');
|
|
667
699
|
console.log(clr(c.dim, '\n 📊 Get alerted if any package degrades:'));
|
|
668
|
-
|
|
700
|
+
if (watchUrl) {
|
|
701
|
+
console.log(clr(c.dim, ' Web: ') + clr(c.cyan, watchUrl));
|
|
702
|
+
}
|
|
703
|
+
console.log(clr(c.dim, ' CLI: ') + clr(c.cyan, `poc watch ${results[0]?.name || '<package>'} --email you@company.com`) + clr(c.dim, ' (free: 3 packages, weekly digest)'));
|
|
669
704
|
}
|
|
670
705
|
console.log();
|
|
671
706
|
}
|
|
@@ -703,6 +738,35 @@ function printTable(results, { totalScanned, totalCritical, lockfile } = {}) {
|
|
|
703
738
|
* Closes the second proposition-gap layer (CLI-side mirror of the
|
|
704
739
|
* 2026-06-11 audit-page watchlist auto-seed at abe53f1/df8a8be).
|
|
705
740
|
*/
|
|
741
|
+
/**
|
|
742
|
+
* Build a clickable /get-started URL that pre-seeds the watchlist from the
|
|
743
|
+
* scanned packages. Mirrors the `?watch=pkg1,pkg2,pkg3&eco=npm` URL contract
|
|
744
|
+
* pinned by test/get-started-watch-param.test.ts. The free-tier cap (3) is
|
|
745
|
+
* enforced via buildCliWatchSeeds(); /get-started.astro re-validates and the
|
|
746
|
+
* backend re-caps at PACKAGE_LIMITS.free (defense in depth across drift).
|
|
747
|
+
*
|
|
748
|
+
* Why this exists: the proven Snyk-comparison/AUR-1579 blog conversion pattern
|
|
749
|
+
* (mid-essay dual CTA + bottom dual CTA + `?watch=…` pre-seed) was sitting
|
|
750
|
+
* one repo over from the CLI for weeks. The CLI emits the highest-intent
|
|
751
|
+
* touchpoint after npm install — a CRITICAL finding in a real user's tree —
|
|
752
|
+
* but the only conversion paths it offered non-TTY users were a multi-token
|
|
753
|
+
* `poc watch X --email Y` CLI command (high friction) and a `getcommit.dev/
|
|
754
|
+
* audit?packages=…` link that drops users on the viewer page (not a converter).
|
|
755
|
+
* This helper produces the clickable conversion URL with packages pre-seeded.
|
|
756
|
+
*
|
|
757
|
+
* Returns null when no valid seeds exist (e.g. empty results, or all names
|
|
758
|
+
* fail the npm-name regex via buildCliWatchSeeds). Callers degrade gracefully
|
|
759
|
+
* to text-only CTAs without a URL.
|
|
760
|
+
*/
|
|
761
|
+
function buildWatchUrl(results, ref) {
|
|
762
|
+
const seeds = buildCliWatchSeeds(results);
|
|
763
|
+
if (seeds.length === 0) return null;
|
|
764
|
+
// All seeds from one scan share the same ecosystem; pick from the first.
|
|
765
|
+
const eco = seeds[0].ecosystem || 'npm';
|
|
766
|
+
const names = seeds.map(s => s.name).join(',');
|
|
767
|
+
return `https://getcommit.dev/get-started?watch=${encodeURIComponent(names)}&eco=${eco}&ref=${ref}&utm_source=cli`;
|
|
768
|
+
}
|
|
769
|
+
|
|
706
770
|
function buildCliWatchSeeds(results) {
|
|
707
771
|
if (!Array.isArray(results) || results.length === 0) return [];
|
|
708
772
|
const VALID_ECOS = new Set(['npm', 'pypi', 'cargo', 'golang']);
|
|
@@ -878,7 +942,7 @@ async function inlineSignup(results, opts = {}) {
|
|
|
878
942
|
|
|
879
943
|
function printHelp() {
|
|
880
944
|
console.log(`
|
|
881
|
-
${clr(c.bold, 'proof-of-commitment')} v1.
|
|
945
|
+
${clr(c.bold, 'proof-of-commitment')} v1.32.0 — supply chain risk scorer
|
|
882
946
|
|
|
883
947
|
${clr(c.bold, 'Usage:')}
|
|
884
948
|
npx proof-of-commitment Auto-detect manifest in current dir
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "proof-of-commitment",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.0",
|
|
4
4
|
"mcpName": "io.github.piiiico/proof-of-commitment",
|
|
5
5
|
"description": "Supply chain security risk scorer for npm, PyPI, Cargo, and Go packages — behavioral signals that can't be faked",
|
|
6
6
|
"type": "module",
|
|
@@ -53,6 +53,13 @@
|
|
|
53
53
|
"url": "https://github.com/piiiico/proof-of-commitment"
|
|
54
54
|
},
|
|
55
55
|
"homepage": "https://getcommit.dev/audit",
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/piiiico/proof-of-commitment/issues"
|
|
58
|
+
},
|
|
59
|
+
"funding": {
|
|
60
|
+
"type": "individual",
|
|
61
|
+
"url": "https://getcommit.dev/pricing?utm_source=npm-fund&utm_medium=package-meta"
|
|
62
|
+
},
|
|
56
63
|
"engines": {
|
|
57
64
|
"node": ">=18"
|
|
58
65
|
}
|