pmsec 0.9.0 → 0.10.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 +14 -14
  2. package/package.json +1 -1
  3. package/src/cli.mjs +26 -24
package/README.md CHANGED
@@ -8,37 +8,37 @@ re-verification, build-script attestation, and more.
8
8
  ## Install
9
9
 
10
10
  ```bash
11
- npx pmsec enable
12
- npx pmsec check
13
- npx pmsec disable
11
+ npx pmsec
12
+ npx pmsec --check
13
+ npx pmsec --disable
14
14
  ```
15
15
 
16
16
  ```bash
17
- uvx pmsec enable
18
- uvx pmsec check
19
- uvx pmsec disable
17
+ uvx pmsec
18
+ uvx pmsec --check
19
+ uvx pmsec --disable
20
20
  ```
21
21
 
22
22
  If your environment already enforces cooldown (or routes through a proxy
23
23
  registry), bootstrap pmsec by overriding just for that call:
24
24
 
25
25
  ```bash
26
- npx --registry=https://registry.npmjs.org/ --min-release-age=0 pmsec check
27
- uvx --index https://pypi.org/simple --exclude-newer-package pmsec=2099-01-01 pmsec check
26
+ npx --registry=https://registry.npmjs.org/ --min-release-age=0 pmsec --check
27
+ uvx --index https://pypi.org/simple --exclude-newer-package pmsec=2099-01-01 pmsec --check
28
28
  ```
29
29
 
30
30
  Zero runtime dependencies, ESM, requires Node 22+.
31
31
 
32
- ## Commands
32
+ ## Usage
33
33
 
34
- | Command | Description |
34
+ | Invocation | Description |
35
35
  | --- | --- |
36
- | `pmsec enable` | Write the hardening bundle (3-day cooldown + per-tool extras) to every selected tool's user config. |
37
- | `pmsec check` | Read each tool's config; exit 1 if any row is missing or below the bundled value. |
38
- | `pmsec disable` | Remove every key the bundle set; other keys in the file are preserved. |
36
+ | `pmsec` | Default action: write the hardening bundle (1-day cooldown + per-tool extras) to every selected tool's user config. |
37
+ | `pmsec --check` | Read each tool's config; exit 1 if any row is missing or below the bundled value. |
38
+ | `pmsec --disable` | Remove every key the bundle set; other keys in the file are preserved. |
39
39
  | `pmsec --version` | Print the installed pmsec version. |
40
40
 
41
- Options: `--tool npm,pnpm,yarn,bun,cargo,mise,uv`, `--days N` (override the 3-day default), `--force` (overwrite stricter existing cooldowns; default is monotonic), `--json`.
41
+ Options: `--tool npm,pnpm,yarn,bun,cargo,mise,uv`, `--days N` (override the 1-day default), `--force` (overwrite stricter existing cooldowns; default is monotonic), `--json`. `--check` and `--disable` are mutually exclusive.
42
42
 
43
43
  When the target file is owned by another user (typical: `~/.npmrc` left
44
44
  root-owned by an old `sudo npm config set`), the write fails with `EACCES`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmsec",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/src/cli.mjs CHANGED
@@ -17,19 +17,16 @@ export const VERSION = JSON.parse(
17
17
  readFileSync(new URL("../package.json", import.meta.url), "utf8")
18
18
  ).version;
19
19
 
20
- const USAGE = `pmsec <command> [options]
20
+ const USAGE = `pmsec [options]
21
21
 
22
22
  Zero-config install-time supply-chain hardening across npm, pnpm, yarn,
23
- bun, cargo, mise, uv. \`set\` flips on every safe-by-default key each
24
- tool exposes (cooldown, audit-level, trust-policy, hardened mode,
23
+ bun, cargo, mise, uv. Default action enables every safe-by-default key
24
+ each tool exposes (cooldown, audit-level, trust-policy, hardened mode,
25
25
  attestation re-verification, ...). No knobs.
26
26
 
27
- Commands:
28
- enable Apply the hardening bundle to all selected tools
29
- disable Remove the hardening bundle from selected tools
30
- check Verify the bundle is in place (exit 1 if anything missing)
31
-
32
27
  Options:
28
+ --check Verify the bundle is in place (exit 1 if anything missing)
29
+ --disable Remove the hardening bundle from selected tools
33
30
  --tool TOOL[,TOOL] Restrict to specific tools (npm,pnpm,yarn,bun,cargo,mise,uv)
34
31
  --days N Override cooldown days (default 1)
35
32
  --force Overwrite stricter existing cooldowns (otherwise enable is monotonic)
@@ -38,11 +35,11 @@ Options:
38
35
  -h, --help Show this help
39
36
 
40
37
  Examples:
41
- npx pmsec enable
42
- npx pmsec enable --days 7
43
- npx pmsec enable --days 1 --force
44
- npx pmsec check
45
- npx pmsec disable --tool npm
38
+ npx pmsec
39
+ npx pmsec --days 7
40
+ npx pmsec --days 1 --force
41
+ npx pmsec --check
42
+ npx pmsec --disable --tool npm
46
43
  `;
47
44
 
48
45
  function parseDays(raw) {
@@ -52,7 +49,13 @@ function parseDays(raw) {
52
49
  }
53
50
 
54
51
  function parse(argv) {
55
- const opts = { command: null, json: false, only: null, days: BUNDLE_DAYS, force: false, help: false, version: false };
52
+ const opts = { mode: "enable", json: false, only: null, days: BUNDLE_DAYS, force: false, help: false, version: false };
53
+ let modeSet = false;
54
+ const setMode = (m) => {
55
+ if (modeSet && opts.mode !== m) throw new Error(`--check and --disable are mutually exclusive`);
56
+ opts.mode = m;
57
+ modeSet = true;
58
+ };
56
59
  const positional = [];
57
60
  for (let i = 0; i < argv.length; i++) {
58
61
  const a = argv[i];
@@ -60,6 +63,8 @@ function parse(argv) {
60
63
  else if (a === "-V" || a === "--version") opts.version = true;
61
64
  else if (a === "--json") opts.json = true;
62
65
  else if (a === "--force") opts.force = true;
66
+ else if (a === "--check") setMode("check");
67
+ else if (a === "--disable") setMode("disable");
63
68
  else if (a === "--tool") opts.only = argv[++i].split(",");
64
69
  else if (a.startsWith("--tool=")) opts.only = a.slice(7).split(",");
65
70
  else if (a === "--days") opts.days = parseDays(argv[++i]);
@@ -67,8 +72,7 @@ function parse(argv) {
67
72
  else if (a.startsWith("-")) throw new Error(`unknown flag: ${a}`);
68
73
  else positional.push(a);
69
74
  }
70
- opts.command = positional[0] ?? null;
71
- if (positional.length > 1) throw new Error(`unexpected argument: ${positional[1]}`);
75
+ if (positional.length) throw new Error(`unexpected argument: ${positional[0]}`);
72
76
  return opts;
73
77
  }
74
78
 
@@ -121,8 +125,8 @@ async function runCheck(targets, { json, days }, ctx, out, err) {
121
125
  const ok = failingPrimary.length === 0 && failingExtras.length === 0;
122
126
  if (json) out.write(JSON.stringify({ bundleDays: days, rows, ok }, null, 2) + "\n");
123
127
  else out.write(renderHuman(rows, days));
124
- if (failingPrimary.length) err.write(`pmsec: ${failingPrimary.length} tool(s) below ${days} days — run \`pmsec enable\`\n`);
125
- if (failingExtras.length) err.write(`pmsec: ${failingExtras.length} hardening setting(s) not at safe value — run \`pmsec enable\`\n`);
128
+ if (failingPrimary.length) err.write(`pmsec: ${failingPrimary.length} tool(s) below ${days} days — run \`pmsec\`\n`);
129
+ if (failingExtras.length) err.write(`pmsec: ${failingExtras.length} hardening setting(s) not at safe value — run \`pmsec\`\n`);
126
130
  return ok ? 0 : 1;
127
131
  }
128
132
 
@@ -204,17 +208,15 @@ export async function run(argv, {
204
208
  try { opts = parse(argv); }
205
209
  catch (e) { err.write(`pmsec: ${e.message}\n`); return 2; }
206
210
  if (opts.version) { out.write(`pmsec ${VERSION}\n`); return 0; }
207
- if (opts.help || !opts.command) { out.write(USAGE); return opts.help ? 0 : 2; }
211
+ if (opts.help) { out.write(USAGE); return 0; }
208
212
  let targets;
209
213
  try { targets = selectTools(opts.only); }
210
214
  catch (e) { err.write(`pmsec: ${e.message}\n`); return 2; }
211
215
  const ctx = { env, home, platform };
212
216
  try {
213
- if (opts.command === "check") return await runCheck(targets, opts, ctx, out, err);
214
- if (opts.command === "enable") return await runEnable(targets, opts.json, opts.days, opts.force, ctx, out, err);
215
- if (opts.command === "disable") return await runDisable(targets, opts.json, ctx, out, err);
216
- err.write(`pmsec: unknown command "${opts.command}"\n`);
217
- return 2;
217
+ if (opts.mode === "check") return await runCheck(targets, opts, ctx, out, err);
218
+ if (opts.mode === "disable") return await runDisable(targets, opts.json, ctx, out, err);
219
+ return await runEnable(targets, opts.json, opts.days, opts.force, ctx, out, err);
218
220
  } catch (e) {
219
221
  err.write(`pmsec: ${e.message}\n`);
220
222
  return 1;