@dk/hipp 0.1.29 → 0.1.30

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 +8 -6
  2. package/hipp.js +105 -66
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -135,6 +135,7 @@ The manifest contains:
135
135
  "email": "jane@example.com",
136
136
  "npm": "10.2.4",
137
137
  "node": "v20.11.0",
138
+ "git": "2.34.1",
138
139
  "hipp": "0.1.22"
139
140
  }
140
141
  ```
@@ -241,20 +242,21 @@ PERFORMANCE OF THIS SOFTWARE.
241
242
  Verify this package with [@dk/hipp](https://www.npmjs.com/package/@dk/hipp):
242
243
 
243
244
  ```bash
244
- npx @dk/hipp verify @dk/hipp@0.1.29
245
+ npx @dk/hipp verify @dk/hipp@0.1.30
245
246
  ```
246
247
 
247
248
  ```json
248
249
  {
249
250
  "origin": "git@github.com:dmytri/hipp.git",
250
- "tag": "v0.1.29",
251
- "revision": "33bc07a3b6621daa7220a3febde75ef5d3416518",
252
- "hash": "af235d18cbc26f9bff5dac57a101b9722687dc7d8360c590aa81c96e23178654",
253
- "signature": "Q5UmtBUV1DbII/oNmFcnWXzyLXndcVCGxpy4kKsnSHs+YZYyt69qg71fhHR+uy9ggzBCi3sc3nwtbEHEX+TXBg==",
251
+ "tag": "v0.1.30",
252
+ "revision": "0d839e7b5eaba3c88a61c64c4524d3552c76140c",
253
+ "hash": "9005dcdfea5d0d29d28d74fea47954a1c367a2730f7ddb36e89f8683785a3c4a",
254
+ "signature": "XKG7xLbzCDxYWC2V+RhEoUWyU0Wp4F6ytufa4NJ6824Sl17VR6Abe/Aw/VS1MfOZFxifJrWGB0e8MYdZ1hCaBg==",
254
255
  "name": "Dmytri Kleiner",
255
256
  "email": "dev@dmytri.to",
256
257
  "npm": "11.12.1",
257
258
  "node": "v25.8.2",
258
- "hipp": "0.1.29"
259
+ "git": "git version 2.47.3",
260
+ "hipp": "0.1.30"
259
261
  }
260
262
  ```
package/hipp.js CHANGED
@@ -483,12 +483,20 @@ async function runVerify(packageSpec) {
483
483
  fail(`āŒ Manifest not found or invalid in README`);
484
484
  }
485
485
 
486
- const { origin: originUrl, tag, revision, signature, name, email, npm: npmVer, node: nodeVer, hipp: hippVer } = manifest;
486
+ const { origin: originUrl, tag, revision, signature, name, email, npm: npmVer, node: nodeVer, hipp: hippVer, git: gitVer } = manifest;
487
487
 
488
488
  log.info(`🌿 Cloning git origin at tag ${tag}...`);
489
489
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), `hipp-verify-git-`));
490
490
  const stageDir = fs.mkdtempSync(path.join(os.tmpdir(), `hipp-verify-stage-`));
491
491
 
492
+ const results = {
493
+ revision: false,
494
+ pub: false,
495
+ signature: false,
496
+ manifestHash: false,
497
+ rebuild: false,
498
+ };
499
+
492
500
  try {
493
501
  let cloneResult;
494
502
  try {
@@ -505,81 +513,110 @@ async function runVerify(packageSpec) {
505
513
 
506
514
  const clonedRevision = git(['rev-parse', 'HEAD'], { cwd: tmpDir });
507
515
  if (clonedRevision !== revision) {
508
- fail(`āŒ Revision mismatch: manifest claims ${revision.slice(0, 12)} but tag points to ${clonedRevision.slice(0, 12)}`);
516
+ log.error(`āŒ Revision mismatch: manifest ${revision.slice(0, 12)} != cloned ${clonedRevision.slice(0, 12)}`);
517
+ } else {
518
+ log.success(`šŸ·ļø Revision verified: ${revision.slice(0, 12)}...`);
519
+ results.revision = true;
509
520
  }
510
- log.success(`šŸ·ļø Revision verified: ${revision.slice(0, 12)}...`);
511
521
 
512
522
  const publicKeyPath = path.join(tmpDir, 'hipp.pub');
513
523
  if (!fs.existsSync(publicKeyPath)) {
514
- fail(`āŒ hipp.pub not found in git at tag ${tag}`);
515
- }
524
+ log.error(`āŒ hipp.pub not found in git at tag ${tag}`);
525
+ } else {
526
+ const publicKey = fs.readFileSync(publicKeyPath, 'utf8');
516
527
 
517
- const publicKey = fs.readFileSync(publicKeyPath, 'utf8');
528
+ log.info(`šŸ—ļø Staging git files...`);
529
+ const trackedFiles = getTrackedFilesFromDir(tmpDir);
530
+ copyTrackedFilesFromDir(stageDir, tmpDir, trackedFiles);
518
531
 
519
- log.info(`šŸ—ļø Staging git files...`);
520
- const trackedFiles = getTrackedFilesFromDir(tmpDir);
521
- copyTrackedFilesFromDir(stageDir, tmpDir, trackedFiles);
532
+ log.info(`šŸ“¦ Packing clean git files...`);
533
+ const { tarballHash: cleanHash } = packAndHash(stageDir);
534
+ log.success(`šŸ“¦ Clean hash: ${cleanHash.slice(0, 12)}...`);
522
535
 
523
- log.info(`šŸ“¦ Packing clean git files...`);
524
- const { tarballHash: cleanHash } = packAndHash(stageDir);
525
- log.success(`šŸ“¦ Clean hash: ${cleanHash.slice(0, 12)}...`);
536
+ log.info(`šŸ” Check 2: Verifying manifest hash...`);
537
+ if (cleanHash !== manifest.hash) {
538
+ log.error(`āŒ Manifest hash mismatch: clean ${cleanHash.slice(0, 12)} != manifest ${manifest.hash.slice(0, 12)}`);
539
+ } else {
540
+ log.success(`šŸ”’ Manifest hash verified`);
541
+ results.manifestHash = true;
542
+ }
526
543
 
527
- log.info(`šŸ” Check 2: Verifying manifest hash...`);
528
- if (cleanHash !== manifest.hash) {
529
- fail(`āŒ Manifest hash mismatch: clean git tarball does not match manifest`);
530
- }
531
- log.success(`šŸ”’ Manifest hash verified`);
544
+ log.info(`šŸ” Check 1: Verifying signature...`);
545
+ const signData = buildSignData(manifest.hash, originUrl, tag, revision, name, email);
546
+ const signatureValid = verifySignature(signData, signature, publicKey);
547
+ if (!signatureValid) {
548
+ log.error(`āŒ Signature verification failed`);
549
+ } else {
550
+ log.success(`šŸ” Signature verified`);
551
+ results.signature = true;
552
+ results.pub = true;
553
+ }
532
554
 
533
- log.info(`šŸ” Check 1: Verifying signature...`);
534
- const signData = buildSignData(manifest.hash, originUrl, tag, revision, name, email);
535
- const signatureValid = verifySignature(signData, signature, publicKey);
536
- if (!signatureValid) {
537
- fail(`āŒ Signature verification failed`);
538
- }
539
- log.success(`šŸ” Signature verified`);
540
-
541
- log.info(`šŸ” Check 3: Rebuilding from source...`);
542
- const stagedReadmePath = path.join(stageDir, 'README.md');
543
- let stagedReadme = fs.readFileSync(stagedReadmePath, 'utf8');
544
- const tagVersion = semver.clean(tag);
545
- if (!tagVersion) {
546
- fail(`āŒ Tag ${tag} is not valid semver`);
547
- }
548
- stagedReadme = stagedReadme.trimEnd() + '\n\n## Verify\n\n' +
549
- 'Verify this package with [@dk/hipp](https://www.npmjs.com/package/@dk/hipp):\n\n' +
550
- '```bash\n' +
551
- `npx @dk/hipp verify ${pkgName}@${tagVersion}\n` +
552
- '```\n\n' +
553
- '```json\n' + JSON.stringify(manifest, null, 2) + '\n```\n';
554
- fs.writeFileSync(stagedReadmePath, stagedReadme);
555
-
556
- const stagedPkgPath = path.join(stageDir, 'package.json');
557
- const stagedPkg = JSON.parse(fs.readFileSync(stagedPkgPath, 'utf8'));
558
- stagedPkg.version = tagVersion;
559
- fs.writeFileSync(stagedPkgPath, JSON.stringify(stagedPkg, null, 2) + '\n');
560
-
561
- const { tarballHash: rebuildHash } = packAndHash(stageDir);
562
- log.success(`šŸ“¦ Rebuild hash: ${rebuildHash.slice(0, 12)}...`);
563
-
564
- if (rebuildHash !== npmHash) {
565
- log.error(`āŒ Rebuild mismatch!`);
566
- log.error(` NPM tarball: ${npmHash}`);
567
- log.error(` Git rebuild: ${rebuildHash}`);
568
- fail(`āŒ Package integrity compromised`);
555
+ log.info(`šŸ” Check 3: Rebuilding from source...`);
556
+ const stagedReadmePath = path.join(stageDir, 'README.md');
557
+ let stagedReadme = fs.readFileSync(stagedReadmePath, 'utf8');
558
+ const tagVersion = semver.clean(tag);
559
+ if (!tagVersion) {
560
+ log.error(`āŒ Tag ${tag} is not valid semver`);
561
+ }
562
+ stagedReadme = stagedReadme.trimEnd() + '\n\n## Verify\n\n' +
563
+ 'Verify this package with [@dk/hipp](https://www.npmjs.com/package/@dk/hipp):\n\n' +
564
+ '```bash\n' +
565
+ `npx @dk/hipp verify ${pkgName}@${tagVersion}\n` +
566
+ '```\n\n' +
567
+ '```json\n' + JSON.stringify(manifest, null, 2) + '\n```\n';
568
+ fs.writeFileSync(stagedReadmePath, stagedReadme);
569
+
570
+ const stagedPkgPath = path.join(stageDir, 'package.json');
571
+ const stagedPkg = JSON.parse(fs.readFileSync(stagedPkgPath, 'utf8'));
572
+ stagedPkg.version = tagVersion;
573
+ fs.writeFileSync(stagedPkgPath, JSON.stringify(stagedPkg, null, 2) + '\n');
574
+
575
+ const { tarballHash: rebuildHash } = packAndHash(stageDir);
576
+ log.success(`šŸ“¦ Rebuild hash: ${rebuildHash.slice(0, 12)}...`);
577
+
578
+ if (rebuildHash !== npmHash) {
579
+ log.error(`āŒ Rebuild mismatch: rebuild ${rebuildHash.slice(0, 12)} != npm ${npmHash.slice(0, 12)}`);
580
+ } else {
581
+ log.success(`šŸ”„ Rebuild verified`);
582
+ results.rebuild = true;
583
+ }
569
584
  }
570
- log.success(`šŸ”„ Rebuild verified`);
571
-
572
- log.success(`āœ… Verified: all checks passed`);
573
- log.info(`šŸ“ Publisher: ${name} <${email}>`);
574
- log.info(`šŸ“ Origin: ${originUrl}`);
575
- log.info(`šŸ“ Tag: ${tag}`);
576
- if (npmVer || nodeVer || hippVer) {
577
- const parts = [];
578
- const displayHipp = hippVer === '0.0.0' ? tagVersion : hippVer;
579
- if (hippVer) parts.push(`hipp: ${displayHipp}`);
580
- if (npmVer) parts.push(`npm: ${npmVer}`);
581
- if (nodeVer) parts.push(`node: ${nodeVer}`);
582
- log.info(`ā„¹ļø ${parts.join(' | ')}`);
585
+
586
+ const allPassed = results.revision && results.pub && results.signature && results.manifestHash && results.rebuild;
587
+
588
+ if (allPassed) {
589
+ log.success(`\nāœ… Verified: all checks passed`);
590
+ log.info(`šŸ“ Publisher: ${name} <${email}>`);
591
+ log.info(`šŸ“ Origin: ${originUrl}`);
592
+ log.info(`šŸ“ Tag: ${tag}`);
593
+ if (npmVer || nodeVer || hippVer || gitVer) {
594
+ const parts = [];
595
+ const displayHipp = hippVer === '0.0.0' ? tagVersion : hippVer;
596
+ if (hippVer) parts.push(`hipp: ${displayHipp}`);
597
+ if (npmVer) parts.push(`npm: ${npmVer}`);
598
+ if (nodeVer) parts.push(`node: ${nodeVer}`);
599
+ if (gitVer) parts.push(`git: ${gitVer}`);
600
+ log.info(`ā„¹ļø ${parts.join(' | ')}`);
601
+ }
602
+ log.info(`\nThis proves npm matches git. It does NOT prove:`);
603
+ log.info(` - The code is safe or bug-free`);
604
+ log.info(` - The publisher is trustworthy`);
605
+ log.info(` - The name/email is accurate`);
606
+ } else {
607
+ log.error(`\nāŒ Verification failed.`);
608
+ if (results.revision && results.pub && results.signature) {
609
+ log.info(`\nRevision and signature verified. This failure may be due to tool`);
610
+ log.info(`version differences between publishing and verification environments.`);
611
+ if (npmVer || nodeVer || hippVer || gitVer) {
612
+ log.info(`\nPublished with: ${[
613
+ hippVer && `hipp: ${hippVer}`,
614
+ npmVer && `npm: ${npmVer}`,
615
+ nodeVer && `node: ${nodeVer}`,
616
+ gitVer && `git: ${gitVer}`,
617
+ ].filter(Boolean).join(' | ')}`);
618
+ }
619
+ }
583
620
  }
584
621
  } finally {
585
622
  fs.rmSync(tmpDir, { recursive: true, force: true });
@@ -682,6 +719,7 @@ async function run() {
682
719
  const revision = refInfo.head;
683
720
  const npmVersion = runCmd('npm', ['--version']).stdout.trim();
684
721
  const nodeVersion = process.version;
722
+ const gitVersion = runCmd('git', ['--version']).stdout.trim();
685
723
  const hippPkgPath = path.join(path.dirname(process.argv[1]), 'package.json');
686
724
  const hippPkg = JSON.parse(fs.readFileSync(hippPkgPath, 'utf8'));
687
725
  const hippVersion = hippPkg.version === '0.0.0' ? version : hippPkg.version;
@@ -699,6 +737,7 @@ async function run() {
699
737
  email: email,
700
738
  npm: npmVersion,
701
739
  node: nodeVersion,
740
+ git: gitVersion,
702
741
  hipp: hippVersion,
703
742
  };
704
743
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dk/hipp",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "description": "High Integrity Package Publisher",
5
5
  "main": "hipp.js",
6
6
  "bin": {