@dk/hipp 0.1.34 → 0.1.36
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 +53 -38
- package/hipp.js +6 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,6 +6,16 @@ By Dmytri Kleiner <dev@dmytri.to>
|
|
|
6
6
|
commits and merge conflicts by treating Git Tags as the single source of truth.
|
|
7
7
|
Your `package.json` version stays at `0.0.0` (or matches your latest tag).
|
|
8
8
|
|
|
9
|
+
## TL;DR
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
git tag v1.0.0
|
|
13
|
+
git push origin main --tags
|
|
14
|
+
npx @dk/hipp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Your package is published with version `1.0.0`. No version-bump commits. No merge conflicts.
|
|
18
|
+
|
|
9
19
|
---
|
|
10
20
|
|
|
11
21
|
## The Problem
|
|
@@ -13,11 +23,11 @@ Your `package.json` version stays at `0.0.0` (or matches your latest tag).
|
|
|
13
23
|
Traditional NPM versioning requires storing the "Version of Truth" in `package.json`.
|
|
14
24
|
This creates a **State Conflict**:
|
|
15
25
|
|
|
16
|
-
- `npm version` and `git tag` are two distinct, non-atomic actions
|
|
17
|
-
- If you tag a commit but forget to update the JSON (or vice-versa), your
|
|
26
|
+
- 🔄 `npm version` and `git tag` are two distinct, non-atomic actions
|
|
27
|
+
- 🤷 If you tag a commit but forget to update the JSON (or vice-versa), your
|
|
18
28
|
registry package and Git history diverge
|
|
19
|
-
- Every release requires a "chore: bump version" commit
|
|
20
|
-
- When multiple branches are developed simultaneously, these trivial changes
|
|
29
|
+
- 🗑️ Every release requires a "chore: bump version" commit
|
|
30
|
+
- 😫 When multiple branches are developed simultaneously, these trivial changes
|
|
21
31
|
cause constant merge conflicts
|
|
22
32
|
|
|
23
33
|
## The Solution
|
|
@@ -70,15 +80,15 @@ Pass npm options via `--`:
|
|
|
70
80
|
npx @dk/hipp -- --access public --tag beta
|
|
71
81
|
```
|
|
72
82
|
|
|
73
|
-
HIPP
|
|
83
|
+
### What Happens When You Run HIPP
|
|
74
84
|
|
|
75
|
-
1. **Key Generation
|
|
76
|
-
2. **Verify
|
|
77
|
-
3. **Clean Check
|
|
78
|
-
4. **Validate
|
|
79
|
-
5. **Sign
|
|
80
|
-
6. **Publish
|
|
81
|
-
7. **Confirm
|
|
85
|
+
1. **Key Generation** - Generate Ed25519 signing keys if needed (`hipp.priv`, `hipp.pub`)
|
|
86
|
+
2. **Verify** - Ensure `package.json` version is `0.0.0` or matches the git tag
|
|
87
|
+
3. **Clean Check** - Ensure your git status is clean
|
|
88
|
+
4. **Validate** - Extract and verify the latest tag against Semver rules
|
|
89
|
+
5. **Sign** - Create a cryptographic manifest of your package content
|
|
90
|
+
6. **Publish** - Publish to npm from a staging directory (never mutating your source)
|
|
91
|
+
7. **Confirm** - Ask for confirmation before ignition (skip with `-y`)
|
|
82
92
|
|
|
83
93
|
### Signing Keys
|
|
84
94
|
|
|
@@ -90,15 +100,19 @@ On first run, HIPP generates an Ed25519 keypair:
|
|
|
90
100
|
|
|
91
101
|
The private key holder can sign packages. The public key verifies signatures.
|
|
92
102
|
|
|
93
|
-
|
|
103
|
+
#### Key Rotation
|
|
104
|
+
|
|
105
|
+
Delete `hipp.pub` and run HIPP again. A new keypair will be
|
|
94
106
|
generated and committed automatically. Verification uses the public key from
|
|
95
107
|
the specific git revision at the tag, so previous packages remain verifiable
|
|
96
108
|
with their original keys.
|
|
97
109
|
|
|
98
|
-
|
|
99
|
-
`hipp.pub`, run HIPP, and a new keypair will be generated for that revision.
|
|
110
|
+
#### Multiple Publishers
|
|
100
111
|
|
|
101
|
-
|
|
112
|
+
Each developer can use their own private key. Delete `hipp.pub`, run HIPP, and
|
|
113
|
+
a new keypair will be generated for that revision.
|
|
114
|
+
|
|
115
|
+
#### Why This Works
|
|
102
116
|
|
|
103
117
|
The public key in `hipp.pub` is committed to git at the specific revision of
|
|
104
118
|
each release. Verification always uses the key from that historical revision,
|
|
@@ -111,7 +125,7 @@ not a current one. This means:
|
|
|
111
125
|
|
|
112
126
|
### Options
|
|
113
127
|
|
|
114
|
-
|
|
128
|
+
- `-y, --yes` - Skip the confirmation prompt (ideal for CI/CD pipelines)
|
|
115
129
|
|
|
116
130
|
To pass additional flags to npm publish (like access or a custom registry), use `--`:
|
|
117
131
|
|
|
@@ -126,20 +140,21 @@ npx @dk/hipp -- --access public --tag beta
|
|
|
126
140
|
HIPP provides out-of-band verification to prove package integrity:
|
|
127
141
|
|
|
128
142
|
```bash
|
|
129
|
-
npx @dk/hipp verify # auto-detect: local hipp repo → published version, else @dk/hipp
|
|
130
|
-
npx @dk/hipp verify --self # always verifies @dk/hipp itself
|
|
131
|
-
npx @dk/hipp verify @scope/package # verifies latest of a package
|
|
132
|
-
npx @dk/hipp verify @scope/package@1.0.0 # verifies specific version
|
|
143
|
+
npx @dk/hipp --verify # auto-detect: local hipp repo → published version, else @dk/hipp
|
|
144
|
+
npx @dk/hipp --verify --self # always verifies @dk/hipp itself
|
|
145
|
+
npx @dk/hipp --verify @scope/package # verifies latest of a package
|
|
146
|
+
npx @dk/hipp --verify @scope/package@1.0.0 # verifies specific version
|
|
133
147
|
```
|
|
134
148
|
|
|
135
149
|
### How Verification Works
|
|
136
150
|
|
|
137
|
-
|
|
151
|
+
#### Step 1: Get Manifest from npm
|
|
138
152
|
|
|
139
153
|
1. Fetch the package tarball from npm registry
|
|
140
154
|
2. Extract the README and parse the JSON manifest appended to it
|
|
141
155
|
|
|
142
156
|
The manifest contains:
|
|
157
|
+
|
|
143
158
|
```json
|
|
144
159
|
{
|
|
145
160
|
"origin": "git@github.com:dk/your-package.git",
|
|
@@ -156,7 +171,7 @@ The manifest contains:
|
|
|
156
171
|
}
|
|
157
172
|
```
|
|
158
173
|
|
|
159
|
-
|
|
174
|
+
#### Step 2: Clone Git and Verify
|
|
160
175
|
|
|
161
176
|
3. Clone the repository at the tagged commit (using origin/tag from manifest)
|
|
162
177
|
4. Verify the cloned commit hash matches the `revision` field in manifest
|
|
@@ -165,13 +180,13 @@ The manifest contains:
|
|
|
165
180
|
7. Compute SHA256 hash of the clean tarball
|
|
166
181
|
8. Compare with the `hash` field from the npm manifest
|
|
167
182
|
|
|
168
|
-
|
|
183
|
+
#### Step 3: Verify Signature
|
|
169
184
|
|
|
170
185
|
9. Read `hipp.pub` from the cloned repository
|
|
171
186
|
10. Verify the signature was created by signing:
|
|
172
187
|
`hash + "\n" + origin + "\n" + tag + "\n" + revision + "\n" + name + "\n" + email`
|
|
173
188
|
|
|
174
|
-
|
|
189
|
+
#### Step 4: Rebuild Verification
|
|
175
190
|
|
|
176
191
|
11. Append the manifest to the staged README
|
|
177
192
|
12. Update the staged `package.json` version to match the tag
|
|
@@ -187,15 +202,15 @@ The manifest contains:
|
|
|
187
202
|
|
|
188
203
|
### What Verification Guarantees
|
|
189
204
|
|
|
190
|
-
- **Integrity
|
|
191
|
-
- **Authenticity
|
|
192
|
-
- **Reproducibility
|
|
205
|
+
- **Integrity** - The code in npm exactly matches git at the tagged commit
|
|
206
|
+
- **Authenticity** - The package was published by the holder of the private key
|
|
207
|
+
- **Reproducibility** - The npm tarball is byte-for-byte identical to a git rebuild
|
|
193
208
|
|
|
194
209
|
### What Verification Does NOT Guarantee
|
|
195
210
|
|
|
196
|
-
- **Code is safe or bug-free
|
|
197
|
-
- **Publisher is trustworthy
|
|
198
|
-
- **Name/email is accurate
|
|
211
|
+
- **Code is safe or bug-free** - Malicious or buggy code can be signed
|
|
212
|
+
- **Publisher is trustworthy** - The key holder could sign bad code intentionally
|
|
213
|
+
- **Name/email is accurate** - These are read from local `git config` and could be set to anything
|
|
199
214
|
|
|
200
215
|
Verification proves that npm matches git - it says nothing about whether that
|
|
201
216
|
code is correct or safe.
|
|
@@ -240,7 +255,7 @@ HIPP enforces strict integrity rules when publishing:
|
|
|
240
255
|
|
|
241
256
|
## License
|
|
242
257
|
|
|
243
|
-
**0BSD** (BSD Zero Clause License)
|
|
258
|
+
**0BSD** (BSD Zero Clause License) By Dmytri Kleiner <dev@dmytri.to>
|
|
244
259
|
|
|
245
260
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
246
261
|
purpose with or without fee is hereby granted.
|
|
@@ -258,21 +273,21 @@ PERFORMANCE OF THIS SOFTWARE.
|
|
|
258
273
|
Verify this package with [@dk/hipp](https://www.npmjs.com/package/@dk/hipp):
|
|
259
274
|
|
|
260
275
|
```bash
|
|
261
|
-
npx @dk/hipp verify @dk/hipp@0.1.
|
|
276
|
+
npx @dk/hipp --verify @dk/hipp@0.1.36
|
|
262
277
|
```
|
|
263
278
|
|
|
264
279
|
```json
|
|
265
280
|
{
|
|
266
281
|
"origin": "git@github.com:dmytri/hipp.git",
|
|
267
|
-
"tag": "v0.1.
|
|
268
|
-
"revision": "
|
|
269
|
-
"hash": "
|
|
270
|
-
"signature": "
|
|
282
|
+
"tag": "v0.1.36",
|
|
283
|
+
"revision": "e3190c19274fd1dcf9c9f8d4f3a0af842214e4b7",
|
|
284
|
+
"hash": "af45dd66df7b54705c7c0c2a5e3bd24222727bc34668e2d89c8079175cdd1df4",
|
|
285
|
+
"signature": "hFkmTxDeTNHOhvvVlySj2Amg5Wq2vuFR1fJzBU0d4Th5ixMvkbpdLcYiHu719sZVAWsUycnu56pH2rXZCvN+BA==",
|
|
271
286
|
"name": "Dmytri Kleiner",
|
|
272
287
|
"email": "dev@dmytri.to",
|
|
273
288
|
"npm": "11.12.1",
|
|
274
289
|
"node": "v25.8.2",
|
|
275
290
|
"git": "git version 2.47.3",
|
|
276
|
-
"hipp": "0.1.
|
|
291
|
+
"hipp": "0.1.36"
|
|
277
292
|
}
|
|
278
293
|
```
|
package/hipp.js
CHANGED
|
@@ -564,7 +564,7 @@ async function runVerify(packageSpec) {
|
|
|
564
564
|
stagedReadme = stagedReadme.trimEnd() + '\n\n## Verify\n\n' +
|
|
565
565
|
'Verify this package with [@dk/hipp](https://www.npmjs.com/package/@dk/hipp):\n\n' +
|
|
566
566
|
'```bash\n' +
|
|
567
|
-
`npx @dk/hipp verify ${pkgName}@${tagVersion}\n` +
|
|
567
|
+
`npx @dk/hipp --verify ${pkgName}@${tagVersion}\n` +
|
|
568
568
|
'```\n\n' +
|
|
569
569
|
'```json\n' + JSON.stringify(manifest, null, 2) + '\n```\n';
|
|
570
570
|
fs.writeFileSync(stagedReadmePath, stagedReadme);
|
|
@@ -746,7 +746,7 @@ async function run() {
|
|
|
746
746
|
stagedReadme = stagedReadme.trimEnd() + '\n\n## Verify\n\n' +
|
|
747
747
|
'Verify this package with [@dk/hipp](https://www.npmjs.com/package/@dk/hipp):\n\n' +
|
|
748
748
|
'```bash\n' +
|
|
749
|
-
`npx @dk/hipp verify ${pkg.name}@${version}\n` +
|
|
749
|
+
`npx @dk/hipp --verify ${pkg.name}@${version}\n` +
|
|
750
750
|
'```\n\n' +
|
|
751
751
|
'```json\n' + JSON.stringify(manifestJson, null, 2) + '\n```\n';
|
|
752
752
|
fs.writeFileSync(stagedReadmePath, stagedReadme);
|
|
@@ -787,8 +787,8 @@ async function run() {
|
|
|
787
787
|
}
|
|
788
788
|
}
|
|
789
789
|
|
|
790
|
-
const isVerify = process.argv.includes('verify');
|
|
791
|
-
const verifyIndex = process.argv.indexOf('verify');
|
|
790
|
+
const isVerify = process.argv.includes('--verify');
|
|
791
|
+
const verifyIndex = process.argv.indexOf('--verify');
|
|
792
792
|
const packageSpec = verifyIndex !== -1 ? process.argv[verifyIndex + 1] : null;
|
|
793
793
|
|
|
794
794
|
if (isVerify) {
|
|
@@ -817,8 +817,8 @@ if (isVerify) {
|
|
|
817
817
|
|
|
818
818
|
Usage:
|
|
819
819
|
npx hipp [options] [-- npm-options]
|
|
820
|
-
npx hipp verify [@package[@version]]
|
|
821
|
-
npx hipp verify --self
|
|
820
|
+
npx hipp --verify [@package[@version]]
|
|
821
|
+
npx hipp --verify --self
|
|
822
822
|
|
|
823
823
|
Without arguments: in a hipp repo (package.json version 0.0.0 or matching
|
|
824
824
|
a semver tag on HEAD), verifies the published package at that version.
|