@kaynooo/pkg-tools 0.5.0 → 0.6.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.
Files changed (3) hide show
  1. package/README.md +3 -2
  2. package/dist/cli.js +39 -17
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -12,9 +12,9 @@ pkg left-pad@1.3.0 @types/node --json
12
12
 
13
13
  - Whether the name exists, the version the request resolves to (an exact version, a dist-tag or a range), the latest version, and the highest stable version at least two weeks old (`safe`), each with its publish date.
14
14
  - Weekly downloads (public registry only), licence and repository.
15
- - Warnings for a version under the minimum age (with the `safe` version to use instead), `preinstall`, `install` and `postinstall` scripts, a deprecated version, and a name that is a near miss of a popular package (one or two edits, other separators or case, or the same name under another scope).
15
+ - Warnings for a version under the minimum age (with the `safe` version to use instead; a fresh version clear of an advisory at `blockSeverity` or above that `safe` has is let through, with a warning naming the GHSAs it fixes), `preinstall`, `install` and `postinstall` scripts, a deprecated version, and a name that is a near miss of a popular package (one or two edits, other separators or case, or the same name under another scope).
16
16
 
17
- `pkg` exits 1 when a package is blocked (missing, the request matches no version or is not a valid range, the resolved version is too fresh or has no publish date on npmjs.org, its licence is outside the allowlist, or an advisory reaches the threshold), 2 when it could not check (the registry unreachable, slower than 10 s or answering badly, a broken `.pkgrc.json`, `bunfig.toml` or `.npmrc`) or on a usage error; other warnings exit 0. `--json` prints one report, or an array for several names, `--min-age <days>` changes the 14 days.
17
+ `pkg` exits 1 when a package is blocked (missing, the request matches no version or is not a valid range, the resolved version is too fresh (unless it fixes an advisory of the safe version at the threshold) or has no publish date on npmjs.org, its licence is outside the allowlist, or an advisory reaches the threshold), 2 when it could not check (the registry unreachable, slower than 10 s or answering badly, a broken `.pkgrc.json`, `bunfig.toml` or `.npmrc`) or on a usage error; other warnings exit 0. `--json` prints one report, or an array for several names, `--min-age <days>` changes the 14 days.
18
18
 
19
19
  ## Config: licence allowlist and advisory threshold
20
20
 
@@ -38,6 +38,7 @@ pkg audit ~/Workspace/app --audit-level high --ignore GHSA-238p-pmpm-9mq7 --json
38
38
 
39
39
  - `--audit-level <low|moderate|high|critical>` (`low`) keeps only the advisories at that severity or above, and `--ignore <GHSA or id>` (repeatable) skips an advisory; `blockSeverity` is for `pkg check` and does not apply here.
40
40
  - `--json` prints the packages with a finding as `[{name, version, license, blocked, warnings, advisories}]`; `--min-age <days>` changes the 14 days.
41
+ - A pin under the minimum age fixing an advisory of the `safe` version at `blockSeverity` or above (not one `--ignore` skips) is let through as `pkg check` lets it, a warning naming the GHSAs.
41
42
  - It exits 1 when a package is missing, too fresh or outside the allowlist, or an advisory remains after the level and the ignores; install scripts and near misses alone exit 0. When the advisories of a registry could not be read it warns which, never prints a clean result for them, and exits 2 unless something already blocks.
42
43
  - An `npm:` alias (`"lodash": "npm:other@1.0.0"`) is audited as the package it names.
43
44
 
package/dist/cli.js CHANGED
@@ -1143,6 +1143,14 @@ var init_secrets = __esm(() => {
1143
1143
  SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "session", "jwt", "ssn", "iban", "card", "cvv", "otp"]);
1144
1144
  });
1145
1145
 
1146
+ // ../kit/src/sessions.ts
1147
+ var {Glob } = globalThis.Bun;
1148
+ var SESSION_FILES, ACCOUNT_DIRS;
1149
+ var init_sessions = __esm(() => {
1150
+ SESSION_FILES = new Glob("*.json");
1151
+ ACCOUNT_DIRS = new Glob("*/sessions");
1152
+ });
1153
+
1146
1154
  // ../kit/src/index.ts
1147
1155
  var init_src = __esm(() => {
1148
1156
  init_args();
@@ -1156,6 +1164,7 @@ var init_src = __esm(() => {
1156
1164
  init_logs();
1157
1165
  init_process();
1158
1166
  init_secrets();
1167
+ init_sessions();
1159
1168
  init_style();
1160
1169
  init_text();
1161
1170
  init_tool();
@@ -2062,6 +2071,9 @@ function ageDays(published, now) {
2062
2071
  const at = Date.parse(published ?? "");
2063
2072
  return Number.isNaN(at) ? undefined : (now - at) / DAY;
2064
2073
  }
2074
+ function daysAgo(age) {
2075
+ return age < 1 ? "less than a day" : `${Math.floor(age)} day${Math.floor(age) === 1 ? "" : "s"}`;
2076
+ }
2065
2077
  function installScriptsOf(version) {
2066
2078
  return Object.fromEntries(INSTALL_SCRIPTS.flatMap((name) => version?.scripts?.[name] === undefined ? [] : [[name, version.scripts[name]]]));
2067
2079
  }
@@ -2072,7 +2084,7 @@ function safeRelease(packument, now, minAgeDays) {
2072
2084
  }
2073
2085
  function analyze(input) {
2074
2086
  const { spec, packument, registry, now = Date.now(), minAgeDays = DEFAULT_MIN_AGE_DAYS } = input;
2075
- const report = { name: spec.name, registry, exists: packument !== undefined, requested: spec.request, installScripts: {}, nearMisses: nearMisses(spec.name), advisories: input.advisories ?? [], warnings: [], blocked: false, downloads: input.downloads };
2087
+ const report = { name: spec.name, registry, exists: packument !== undefined, requested: spec.request, installScripts: {}, nearMisses: nearMisses(spec.name), advisories: input.advisories ?? [], fixes: [], warnings: [], blocked: false, downloads: input.downloads };
2076
2088
  if (report.nearMisses.length > 0)
2077
2089
  report.warnings.push(`name looks like ${report.nearMisses.join("; ")}, check it is the package meant`);
2078
2090
  if (packument === undefined) {
@@ -2098,13 +2110,17 @@ function analyze(input) {
2098
2110
  return report;
2099
2111
  }
2100
2112
  const age = ageDays(report.published, now);
2113
+ const kept = new Set(report.advisories.map((each) => each.id));
2114
+ report.fixes = report.safe?.version === version ? [] : (input.safeAdvisories ?? []).filter((each) => !kept.has(each.id));
2101
2115
  if (age === undefined) {
2102
2116
  const isBlocking = minAgeDays > 0 && registry === PUBLIC_HOST;
2103
2117
  report.blocked ||= isBlocking;
2104
2118
  report.warnings.push(`${registry} gives no publish date for ${version}, its age cannot be checked${isBlocking ? " and it is refused" : ""}`);
2119
+ } else if (age < minAgeDays && report.fixes.length > 0) {
2120
+ report.warnings.push(`${version} was published ${daysAgo(age)} ago, under ${minAgeDays} days, but it fixes ${report.fixes.map((each) => `${each.ghsa ?? each.id} (${each.severity})`).join(", ")} that ${report.safe?.version} has, so its age does not hold it back`);
2105
2121
  } else if (age < minAgeDays) {
2106
2122
  report.blocked = true;
2107
- report.warnings.push(`${version} was published ${age < 1 ? "less than a day" : `${Math.floor(age)} day${Math.floor(age) === 1 ? "" : "s"}`} ago, under ${minAgeDays} days${report.safe === undefined ? ", and no older stable version exists" : `, use ${spec.name}@${report.safe.version}`}`);
2123
+ report.warnings.push(`${version} was published ${daysAgo(age)} ago, under ${minAgeDays} days${report.safe === undefined ? ", and no older stable version exists" : `, use ${spec.name}@${report.safe.version}`}`);
2108
2124
  }
2109
2125
  const scripts = Object.keys(report.installScripts);
2110
2126
  if (scripts.length > 0)
@@ -2159,10 +2175,11 @@ async function checkPackage(text, context) {
2159
2175
  const blockSeverity = context.settings?.blockSeverity ?? DEFAULT_BLOCK_SEVERITY;
2160
2176
  if (report.version === undefined)
2161
2177
  return report;
2162
- const { found, unavailable, isUnsupported } = await fetchAdvisories({ [spec.name]: [report.version] }, registry, context.fetcher);
2178
+ const safe = report.safe?.version;
2179
+ const { found, unavailable, isUnsupported } = await fetchAdvisories({ [spec.name]: safe === undefined || safe === report.version ? [report.version] : [report.version, safe] }, registry, context.fetcher);
2163
2180
  if (unavailable !== undefined && isUnsupported !== true)
2164
2181
  return unreachable(unavailable);
2165
- const checked = analyze({ ...input, blockSeverity, advisories: advisoriesFor(found[spec.name], report.version) });
2182
+ const checked = analyze({ ...input, blockSeverity, advisories: advisoriesFor(found[spec.name], report.version), safeAdvisories: safe === undefined ? [] : filterAdvisories(advisoriesFor(found[spec.name], safe), blockSeverity) });
2166
2183
  if (unavailable !== undefined)
2167
2184
  checked.warnings.push(`${unavailable}, so its known advisories are not checked`);
2168
2185
  return checked;
@@ -2274,11 +2291,18 @@ async function auditPackages(packages, context) {
2274
2291
  packuments.set(key, fetchPackument(name, registry, context.fetcher));
2275
2292
  return packuments.get(key);
2276
2293
  };
2294
+ const looked = [];
2295
+ for (let start = 0;start < packages.length; start += BATCH) {
2296
+ looked.push(...await Promise.all(packages.slice(start, start + BATCH).map(async ({ name, version }) => {
2297
+ const registry = registryFor(name, context.configs);
2298
+ const input = { spec: { name, request: version }, packument: await lookup(name, registry), registry: new URL(registry.url).host, now: context.now, minAgeDays: context.minAgeDays, licenses: context.settings.licenses };
2299
+ return { name, version, registry, input, safe: analyze(input).safe?.version };
2300
+ })));
2301
+ }
2277
2302
  const registries = new Map;
2278
- for (const { name, version } of packages) {
2279
- const registry = registryFor(name, context.configs);
2303
+ for (const { name, version, registry, safe } of looked) {
2280
2304
  const group = registries.get(registry.url) ?? { registry, versions: {} };
2281
- group.versions[name] = [...group.versions[name] ?? [], version];
2305
+ group.versions[name] = [...group.versions[name] ?? [], version, ...safe === undefined || safe === version ? [] : [safe]];
2282
2306
  registries.set(registry.url, group);
2283
2307
  }
2284
2308
  const advisories = {};
@@ -2289,15 +2313,13 @@ async function auditPackages(packages, context) {
2289
2313
  if (fetched.unavailable !== undefined)
2290
2314
  unavailable.push(fetched.unavailable);
2291
2315
  }
2292
- const audited = [];
2293
- for (let start = 0;start < packages.length; start += BATCH) {
2294
- audited.push(...await Promise.all(packages.slice(start, start + BATCH).map(async ({ name, version }) => {
2295
- const registry = registryFor(name, context.configs);
2296
- const found = filterAdvisories(advisoriesFor(advisories[name], version), context.level, context.ignore);
2297
- const report = analyze({ spec: { name, request: version }, packument: await lookup(name, registry), registry: new URL(registry.url).host, now: context.now, minAgeDays: context.minAgeDays, licenses: context.settings.licenses });
2298
- return { name, version, license: report.license, blocked: report.blocked || found.length > 0, warnings: report.warnings, advisories: found };
2299
- })));
2300
- }
2316
+ const blockSeverity = context.settings.blockSeverity ?? DEFAULT_BLOCK_SEVERITY;
2317
+ const audited = looked.map(({ name, version, input, safe }) => {
2318
+ const found = filterAdvisories(advisoriesFor(advisories[name], version), context.level, context.ignore);
2319
+ const safeAdvisories = safe === undefined ? [] : filterAdvisories(advisoriesFor(advisories[name], safe), blockSeverity, context.ignore);
2320
+ const report = analyze({ ...input, advisories: advisoriesFor(advisories[name], version), safeAdvisories });
2321
+ return { name, version, license: report.license, blocked: report.blocked || found.length > 0, warnings: report.warnings, advisories: found };
2322
+ });
2301
2323
  return { audited, unavailable };
2302
2324
  }
2303
2325
  function renderAudit(findings, total) {
@@ -2727,7 +2749,7 @@ var init_consumers2 = __esm(() => {
2727
2749
  init_src();
2728
2750
  import process10 from "process";
2729
2751
  // package.json
2730
- var version = "0.5.0";
2752
+ var version = "0.6.0";
2731
2753
 
2732
2754
  // src/cli.ts
2733
2755
  process10.exitCode = await runCli({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kaynooo/pkg-tools",
3
3
  "type": "module",
4
- "version": "0.5.0",
4
+ "version": "0.6.0",
5
5
  "description": "pkg: check an npm package before it is added, for a guessed name, a version under two weeks old and install scripts.",
6
6
  "author": "Kaynooo <contact@kaynooo.fr>",
7
7
  "license": "MIT",