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.
- package/README.md +14 -14
- package/package.json +1 -1
- 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
|
|
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
|
|
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
|
-
##
|
|
32
|
+
## Usage
|
|
33
33
|
|
|
34
|
-
|
|
|
34
|
+
| Invocation | Description |
|
|
35
35
|
| --- | --- |
|
|
36
|
-
| `pmsec
|
|
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
|
|
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
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
|
|
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.
|
|
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
|
|
42
|
-
npx pmsec
|
|
43
|
-
npx pmsec
|
|
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 = {
|
|
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
|
-
|
|
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
|
|
125
|
-
if (failingExtras.length) err.write(`pmsec: ${failingExtras.length} hardening setting(s) not at safe value — run \`pmsec
|
|
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
|
|
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.
|
|
214
|
-
if (opts.
|
|
215
|
-
|
|
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;
|