@getfootgun/footgun 0.2.2 → 0.2.3
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 +2 -0
- package/bin/footgun.mjs +4 -1
- package/lib/badge.mjs +13 -0
- package/lib/report.mjs +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@ npx @getfootgun/footgun scan [path] [--json] [--fail-on breaks|will-break] [--ke
|
|
|
14
14
|
- `--fail-on breaks` exits 1 when something breaks now. `--fail-on will-break` also exits 1 for anything with a known break date or version. Use either in CI.
|
|
15
15
|
- Exit code 2 means the rules could not be downloaded and there is no cached copy. Exit code 3 means the scan could not run.
|
|
16
16
|
|
|
17
|
+
After a scan, `scan` prints a Markdown badge for your README, dated the day it ran. It reads "no known API traps" only when the scan found nothing at all, and "scanned" otherwise. `--json` puts the same Markdown in a `badge` field.
|
|
18
|
+
|
|
17
19
|
Requires Node 20 or later.
|
|
18
20
|
|
|
19
21
|
`scan` sends one anonymous usage count (that it ran, and how many traps matched at each severity, never paths, package names or code). Set `FOOTGUN_SHARE=false` to turn it off.
|
package/bin/footgun.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { loadPack, NoRulesError, pingCounts, sendPing } from "../lib/pack.mjs";
|
|
|
7
7
|
import { scanProject } from "../lib/scan.mjs";
|
|
8
8
|
import { runContext } from "../lib/context.mjs";
|
|
9
9
|
import { textReport, jsonReport, failed, FAIL_ON } from "../lib/report.mjs";
|
|
10
|
+
import { badgeMarkdown } from "../lib/badge.mjs";
|
|
10
11
|
const BASE = process.env.FOOTGUN_URL ?? "https://getfootgun.com";
|
|
11
12
|
const KEY = process.env.FOOTGUN_API_KEY;
|
|
12
13
|
const [a, ...rest] = process.argv.slice(2);
|
|
@@ -77,11 +78,13 @@ async function scan(args) {
|
|
|
77
78
|
// a matcher that cannot start rejects here and exits 3 in main, so no clean report is printed
|
|
78
79
|
const result = await scanProject(resolve(o.path), pack.rules);
|
|
79
80
|
const skippedRules = [...pack.skippedRules, ...result.skippedRules];
|
|
81
|
+
const badge = badgeMarkdown(result.findings, { base: BASE, date: new Date().toISOString().slice(0, 10) });
|
|
80
82
|
if (o.json) {
|
|
81
|
-
console.log(jsonReport({ findings: result.findings, skippedRules, fromCache, version: pack.version }));
|
|
83
|
+
console.log(jsonReport({ findings: result.findings, skippedRules, fromCache, version: pack.version, badge }));
|
|
82
84
|
} else {
|
|
83
85
|
for (const s of skippedRules) console.error(clean(`Skipped rule ${s.id}: ${s.why}`));
|
|
84
86
|
console.log(textReport(result.findings));
|
|
87
|
+
console.log(`\nREADME badge for this scan:\n${badge}`);
|
|
85
88
|
}
|
|
86
89
|
if (failed(result.findings, o.failOn)) process.exitCode = 1;
|
|
87
90
|
await sendPing({ url: BASE, kind: "scan", counts: pingCounts(uniqueTraps(result.findings)) });
|
package/lib/badge.mjs
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// The README badge `footgun scan` suggests. It claims only what this scan showed, on the day it ran:
|
|
2
|
+
// "no known API traps" when nothing at all was found (check-yourself items included), otherwise just "scanned".
|
|
3
|
+
|
|
4
|
+
/** "clean" only when the scan found nothing, not even a check-yourself item. */
|
|
5
|
+
export function badgeStatus(findings) {
|
|
6
|
+
return findings.length === 0 ? "clean" : "scanned";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function badgeMarkdown(findings, { base, date }) {
|
|
10
|
+
const status = badgeStatus(findings);
|
|
11
|
+
const alt = status === "clean" ? `No known API traps on ${date} · Footgun` : `Scanned by Footgun on ${date}`;
|
|
12
|
+
return `[](${base}/scan)`;
|
|
13
|
+
}
|
package/lib/report.mjs
CHANGED
|
@@ -44,6 +44,6 @@ export function textReport(findings) {
|
|
|
44
44
|
return out.join("\n");
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export function jsonReport({ findings, skippedRules, fromCache, version }) {
|
|
48
|
-
return JSON.stringify({ version, fromCache, findings, skippedRules }, null, 2);
|
|
47
|
+
export function jsonReport({ findings, skippedRules, fromCache, version, badge }) {
|
|
48
|
+
return JSON.stringify({ version, fromCache, findings, skippedRules, badge }, null, 2);
|
|
49
49
|
}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{ "name": "@getfootgun/footgun", "version": "0.2.
|
|
1
|
+
{ "name": "@getfootgun/footgun", "version": "0.2.3", "description": "Ask Footgun why a third-party API, platform, or AI tool just broke.", "bin": { "footgun": "bin/footgun.mjs" }, "scripts": { "prepublishOnly": "node ../scripts/check-publish.mjs" }, "type": "module", "license": "MIT", "files": ["bin", "lib", "README.md"], "engines": { "node": ">=20" } }
|