@dk/hipp 0.1.17 → 0.1.20

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 +30 -15
  2. package/hipp.js +37 -12
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -109,32 +109,36 @@ The manifest contains:
109
109
  {
110
110
  "origin": "git@github.com:dk/your-package.git",
111
111
  "tag": "v1.0.0",
112
+ "revision": "<git-commit-hash>",
112
113
  "hash": "<sha256-of-tarball>",
113
114
  "signature": "<base64-ed25519-signature>",
114
115
  "name": "Jane Developer",
115
- "email": "jane@example.com"
116
+ "email": "jane@example.com",
117
+ "npm": "10.2.4",
118
+ "node": "v20.11.0"
116
119
  }
117
120
  ```
118
121
 
119
122
  **Step 2: Clone git and verify**
120
123
 
121
124
  3. Clone the repository at the tagged commit (using origin/tag from manifest)
122
- 4. Stage all tracked files
123
- 5. Run `npm pack` to create a tarball
124
- 6. Compute SHA256 hash of the clean tarball
125
- 7. Compare with the `hash` field from the npm manifest
125
+ 4. Verify the cloned commit hash matches the `revision` field in manifest
126
+ 5. Stage all tracked files
127
+ 6. Run `npm pack` to create a tarball
128
+ 7. Compute SHA256 hash of the clean tarball
129
+ 8. Compare with the `hash` field from the npm manifest
126
130
 
127
131
  **Step 3: Verify signature**
128
132
 
129
- 8. Read `hipp.pub` from the cloned repository
130
- 9. Verify the signature was created by signing:
131
- `hash + "\n" + origin + "\n" + tag + "\n" + name + "\n" + email`
133
+ 9. Read `hipp.pub` from the cloned repository
134
+ 10. Verify the signature was created by signing:
135
+ `hash + "\n" + origin + "\n" + tag + "\n" + revision + "\n" + name + "\n" + email`
132
136
 
133
137
  **Step 4: Rebuild verification**
134
138
 
135
- 10. Append the manifest to the staged README
136
- 11. Update the staged `package.json` version to match the tag
137
- 12. Run `npm pack` again and verify the hash matches the npm tarball
139
+ 11. Append the manifest to the staged README
140
+ 12. Update the staged `package.json` version to match the tag
141
+ 13. Run `npm pack` again and verify the hash matches the npm tarball
138
142
 
139
143
  ### Three Verification Checks
140
144
 
@@ -211,13 +215,24 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
211
215
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
212
216
  PERFORMANCE OF THIS SOFTWARE.
213
217
 
218
+ ## Verify
219
+
220
+ Verify this package with [@dk/hipp](https://www.npmjs.com/package/@dk/hipp):
221
+
222
+ ```bash
223
+ npx @dk/hipp verify @dk/hipp@0.1.20
224
+ ```
225
+
214
226
  ```json
215
227
  {
216
228
  "origin": "git@github.com:dmytri/hipp.git",
217
- "tag": "v0.1.17",
218
- "hash": "7a9817b5d57a5c5c43cac3d608d4a0e907dcbdf8031252a62b29195391b38b26",
219
- "signature": "/o75TYcgRUS0pVQEmJeCamZ5z6wTDQtawuaKYd4lbZCBWuqEeuaPECRefTgzC7tDr6bCyFd6p4biPGWIroBlCA==",
229
+ "tag": "v0.1.20",
230
+ "revision": "1d5a16d3e837ffd79d4c6704cf1945f6d0b84a60",
231
+ "hash": "71fe169e31a68c92c249ae2a443a4062dc379b36bf854a290576e7b595ca4e58",
232
+ "signature": "UpVrjogkhwUyPvGj6bK4vOUj3p9R/JDvuDaupOibXFyK5FibLWzpMwjQWHJa78wYx4D4f/BmAn99J3Xt4icaDg==",
220
233
  "name": "Dmytri Kleiner",
221
- "email": "dev@dmytri.to"
234
+ "email": "dev@dmytri.to",
235
+ "npm": "11.12.1",
236
+ "node": "v25.8.2"
222
237
  }
223
238
  ```
package/hipp.js CHANGED
@@ -121,8 +121,8 @@ function verifySignature(data, signature, publicKey) {
121
121
  }, Buffer.from(signature, 'base64'));
122
122
  }
123
123
 
124
- function buildSignData(hash, origin, tag, name, email) {
125
- return `${hash}\n${origin}\n${tag}\n${name}\n${email}\n`;
124
+ function buildSignData(hash, origin, tag, revision, name, email) {
125
+ return `${hash}\n${origin}\n${tag}\n${revision}\n${name}\n${email}\n`;
126
126
  }
127
127
 
128
128
  function findLastJsonBlock(readmeContent) {
@@ -463,11 +463,11 @@ async function runVerify(packageSpec) {
463
463
 
464
464
  const npmReadme = fs.readFileSync(npmReadmePath, 'utf8');
465
465
  manifest = findLastJsonBlock(npmReadme);
466
- if (!manifest || !manifest.origin || !manifest.tag || !manifest.hash || !manifest.signature || !manifest.name || !manifest.email) {
466
+ if (!manifest || !manifest.origin || !manifest.tag || !manifest.revision || !manifest.hash || !manifest.signature || !manifest.name || !manifest.email) {
467
467
  fail(`❌ Manifest not found or invalid in README`);
468
468
  }
469
469
 
470
- const { origin: originUrl, tag, signature, name, email } = manifest;
470
+ const { origin: originUrl, tag, revision, signature, name, email, npm: npmVer, node: nodeVer } = manifest;
471
471
 
472
472
  log.info(`đŸŒŋ Cloning git origin at tag ${tag}...`);
473
473
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), `hipp-verify-git-`));
@@ -476,6 +476,12 @@ async function runVerify(packageSpec) {
476
476
  try {
477
477
  git(['clone', '--branch', tag, '--depth', '1', originUrl, tmpDir], { stdio: 'pipe' });
478
478
 
479
+ const clonedRevision = git(['rev-parse', 'HEAD'], { cwd: tmpDir });
480
+ if (clonedRevision !== revision) {
481
+ fail(`❌ Revision mismatch: manifest claims ${revision.slice(0, 12)} but tag points to ${clonedRevision.slice(0, 12)}`);
482
+ }
483
+ log.success(`đŸˇī¸ Revision verified: ${revision.slice(0, 12)}...`);
484
+
479
485
  const publicKeyPath = path.join(tmpDir, 'hipp.pub');
480
486
  if (!fs.existsSync(publicKeyPath)) {
481
487
  fail(`❌ hipp.pub not found in git at tag ${tag}`);
@@ -498,7 +504,7 @@ async function runVerify(packageSpec) {
498
504
  log.success(`🔒 Manifest hash verified`);
499
505
 
500
506
  log.info(`🔍 Check 1: Verifying signature...`);
501
- const signData = buildSignData(manifest.hash, originUrl, tag, name, email);
507
+ const signData = buildSignData(manifest.hash, originUrl, tag, revision, name, email);
502
508
  const signatureValid = verifySignature(signData, signature, publicKey);
503
509
  if (!signatureValid) {
504
510
  fail(`❌ Signature verification failed`);
@@ -508,15 +514,20 @@ async function runVerify(packageSpec) {
508
514
  log.info(`🔍 Check 3: Rebuilding from source...`);
509
515
  const stagedReadmePath = path.join(stageDir, 'README.md');
510
516
  let stagedReadme = fs.readFileSync(stagedReadmePath, 'utf8');
511
- stagedReadme = stagedReadme.trimEnd() + '\n\n```json\n' + JSON.stringify(manifest, null, 2) + '\n```\n';
512
- fs.writeFileSync(stagedReadmePath, stagedReadme);
513
-
514
- const stagedPkgPath = path.join(stageDir, 'package.json');
515
- const stagedPkg = JSON.parse(fs.readFileSync(stagedPkgPath, 'utf8'));
516
517
  const tagVersion = semver.clean(tag);
517
518
  if (!tagVersion) {
518
519
  fail(`❌ Tag ${tag} is not valid semver`);
519
520
  }
521
+ stagedReadme = stagedReadme.trimEnd() + '\n\n## Verify\n\n' +
522
+ 'Verify this package with [@dk/hipp](https://www.npmjs.com/package/@dk/hipp):\n\n' +
523
+ '```bash\n' +
524
+ `npx @dk/hipp verify ${pkgName}@${tagVersion}\n` +
525
+ '```\n\n' +
526
+ '```json\n' + JSON.stringify(manifest, null, 2) + '\n```\n';
527
+ fs.writeFileSync(stagedReadmePath, stagedReadme);
528
+
529
+ const stagedPkgPath = path.join(stageDir, 'package.json');
530
+ const stagedPkg = JSON.parse(fs.readFileSync(stagedPkgPath, 'utf8'));
520
531
  stagedPkg.version = tagVersion;
521
532
  fs.writeFileSync(stagedPkgPath, JSON.stringify(stagedPkg, null, 2) + '\n');
522
533
 
@@ -535,6 +546,9 @@ async function runVerify(packageSpec) {
535
546
  log.info(`📍 Publisher: ${name} <${email}>`);
536
547
  log.info(`📍 Origin: ${originUrl}`);
537
548
  log.info(`📍 Tag: ${tag}`);
549
+ if (npmVer && nodeVer) {
550
+ log.info(`â„šī¸ npm: ${npmVer} | node: ${nodeVer}`);
551
+ }
538
552
  } finally {
539
553
  fs.rmSync(tmpDir, { recursive: true, force: true });
540
554
  fs.rmSync(stageDir, { recursive: true, force: true });
@@ -633,19 +647,30 @@ async function run() {
633
647
  }
634
648
 
635
649
  const { name, email } = getGitUserInfo();
636
- const dataToSign = buildSignData(tarballHash, provenance.remoteUrl, rawTag, name, email);
650
+ const revision = refInfo.head;
651
+ const npmVersion = runCmd('npm', ['--version']).stdout.trim();
652
+ const nodeVersion = process.version;
653
+ const dataToSign = buildSignData(tarballHash, provenance.remoteUrl, rawTag, revision, name, email);
637
654
  const signature = signContent(dataToSign, privateKey);
638
655
 
639
656
  const manifestJson = {
640
657
  origin: provenance.remoteUrl,
641
658
  tag: rawTag,
659
+ revision: revision,
642
660
  hash: tarballHash,
643
661
  signature: signature,
644
662
  name: name,
645
663
  email: email,
664
+ npm: npmVersion,
665
+ node: nodeVersion,
646
666
  };
647
667
 
648
- stagedReadme = stagedReadme.trimEnd() + '\n\n```json\n' + JSON.stringify(manifestJson, null, 2) + '\n```\n';
668
+ stagedReadme = stagedReadme.trimEnd() + '\n\n## Verify\n\n' +
669
+ 'Verify this package with [@dk/hipp](https://www.npmjs.com/package/@dk/hipp):\n\n' +
670
+ '```bash\n' +
671
+ `npx @dk/hipp verify ${pkg.name}@${version}\n` +
672
+ '```\n\n' +
673
+ '```json\n' + JSON.stringify(manifestJson, null, 2) + '\n```\n';
649
674
  fs.writeFileSync(stagedReadmePath, stagedReadme);
650
675
 
651
676
  const stagedPkgPath = path.join(stageDir, 'package.json');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dk/hipp",
3
- "version": "0.1.17",
3
+ "version": "0.1.20",
4
4
  "description": "High Integrity Package Publisher",
5
5
  "main": "hipp.js",
6
6
  "bin": {