@dk/hipp 0.1.36 → 0.1.37

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 +6 -6
  2. package/hipp.js +39 -34
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -273,21 +273,21 @@ PERFORMANCE OF THIS SOFTWARE.
273
273
  Verify this package with [@dk/hipp](https://www.npmjs.com/package/@dk/hipp):
274
274
 
275
275
  ```bash
276
- npx @dk/hipp --verify @dk/hipp@0.1.36
276
+ npx @dk/hipp --verify @dk/hipp@0.1.37
277
277
  ```
278
278
 
279
279
  ```json
280
280
  {
281
281
  "origin": "git@github.com:dmytri/hipp.git",
282
- "tag": "v0.1.36",
283
- "revision": "e3190c19274fd1dcf9c9f8d4f3a0af842214e4b7",
284
- "hash": "af45dd66df7b54705c7c0c2a5e3bd24222727bc34668e2d89c8079175cdd1df4",
285
- "signature": "hFkmTxDeTNHOhvvVlySj2Amg5Wq2vuFR1fJzBU0d4Th5ixMvkbpdLcYiHu719sZVAWsUycnu56pH2rXZCvN+BA==",
282
+ "tag": "v0.1.37",
283
+ "revision": "3efc2c67bcb1e75b9fb3c44a2e572dba1aa1703d",
284
+ "hash": "f3cae0034df0aaa5382c0d047fff684ab30354eab2a3b7f280438a95a7ef9488",
285
+ "signature": "c7ck6ex7mu5OqR2JiRnlnU0nnBHoYPqQkSvKDnvhfyBGUKnOUyT/uEyxifj+UW+s3GB4m651zDauhjWsqVMIDw==",
286
286
  "name": "Dmytri Kleiner",
287
287
  "email": "dev@dmytri.to",
288
288
  "npm": "11.12.1",
289
289
  "node": "v25.8.2",
290
290
  "git": "git version 2.47.3",
291
- "hipp": "0.1.36"
291
+ "hipp": "0.1.37"
292
292
  }
293
293
  ```
package/hipp.js CHANGED
@@ -178,24 +178,25 @@ function findLastJsonBlock(readmeContent) {
178
178
  return lastValid;
179
179
  }
180
180
 
181
- function packAndHash(stageDir) {
182
- const result = spawnSync('npm', ['pack'], {
183
- cwd: stageDir,
184
- encoding: 'utf8',
185
- stdio: ['pipe', 'pipe', 'pipe'],
186
- });
187
-
188
- if (result.status !== 0) {
189
- throw new Error(`npm pack failed: ${result.stderr}`);
190
- }
191
-
192
- const tarballName = result.stdout.trim().split('\n').pop();
193
- const tarballPath = path.join(stageDir, tarballName);
194
-
195
- const tarballContent = fs.readFileSync(tarballPath);
196
- fs.unlinkSync(tarballPath);
197
-
198
- return { tarballName, tarballHash: sha256(tarballContent) };
181
+ function hashFiles(dir) {
182
+ const entries = [];
183
+ const walk = (d, prefix = '') => {
184
+ const items = fs.readdirSync(d);
185
+ for (const item of items.sort()) {
186
+ if (item === 'node_modules' || item === '.git' || item === 'hipp.priv') continue;
187
+ const full = path.join(d, item);
188
+ const rel = prefix ? prefix + '/' + item : item;
189
+ const stat = fs.statSync(full);
190
+ if (stat.isDirectory()) {
191
+ walk(full, rel);
192
+ } else {
193
+ const content = fs.readFileSync(full);
194
+ entries.push(rel + ':' + sha256(content));
195
+ }
196
+ }
197
+ };
198
+ walk(dir);
199
+ return sha256(entries.join('\n'));
199
200
  }
200
201
 
201
202
  function safeStageName(name) {
@@ -455,10 +456,6 @@ async function runVerify(packageSpec) {
455
456
  fail(`❌ Failed to download tarball`);
456
457
  }
457
458
 
458
- const npmTarballContent = fs.readFileSync(tarballPath);
459
- const npmHash = sha256(npmTarballContent);
460
- log.success(`📦 NPM tarball hash: ${npmHash.slice(0, 12)}...`);
461
-
462
459
  if (fs.existsSync(extractDir)) {
463
460
  fs.rmSync(extractDir, { recursive: true });
464
461
  }
@@ -531,8 +528,8 @@ async function runVerify(packageSpec) {
531
528
  const trackedFiles = getTrackedFilesFromDir(tmpDir);
532
529
  copyTrackedFilesFromDir(stageDir, tmpDir, trackedFiles);
533
530
 
534
- log.info(`📦 Packing clean git files...`);
535
- const { tarballHash: cleanHash } = packAndHash(stageDir);
531
+ log.info(`📦 Computing logical hash of git files...`);
532
+ const cleanHash = hashFiles(stageDir);
536
533
  log.success(`📦 Clean hash: ${cleanHash.slice(0, 12)}...`);
537
534
 
538
535
  log.info(`🔍 Check 2: Verifying manifest hash...`);
@@ -571,14 +568,22 @@ async function runVerify(packageSpec) {
571
568
 
572
569
  const stagedPkgPath = path.join(stageDir, 'package.json');
573
570
  const stagedPkg = JSON.parse(fs.readFileSync(stagedPkgPath, 'utf8'));
574
- stagedPkg.version = tagVersion;
575
571
  fs.writeFileSync(stagedPkgPath, JSON.stringify(stagedPkg, null, 2) + '\n');
576
572
 
577
- const { tarballHash: rebuildHash } = packAndHash(stageDir);
578
- log.success(`📦 Rebuild hash: ${rebuildHash.slice(0, 12)}...`);
573
+ const npmExtractPkgPath = path.join(packageDir, 'package.json');
574
+ const npmExtractPkg = JSON.parse(fs.readFileSync(npmExtractPkgPath, 'utf8'));
575
+ if (stagedPkg.version === '0.0.0') {
576
+ npmExtractPkg.version = '0.0.0';
577
+ fs.writeFileSync(npmExtractPkgPath, JSON.stringify(npmExtractPkg, null, 2) + '\n');
578
+ }
579
+
580
+ const npmExtractHash = hashFiles(packageDir);
581
+ const rebuildHash = hashFiles(stageDir);
582
+ log.success(`📦 NPM-extract hash: ${npmExtractHash.slice(0, 12)}...`);
583
+ log.success(`📦 Git-rebuild hash: ${rebuildHash.slice(0, 12)}...`);
579
584
 
580
- if (rebuildHash !== npmHash) {
581
- log.error(`❌ Rebuild mismatch: rebuild ${rebuildHash.slice(0, 12)} != npm ${npmHash.slice(0, 12)}`);
585
+ if (rebuildHash !== npmExtractHash) {
586
+ log.error(`❌ Rebuild mismatch: git ${rebuildHash.slice(0, 12)} != npm ${npmExtractHash.slice(0, 12)}`);
582
587
  } else {
583
588
  log.success(`🔄 Rebuild verified`);
584
589
  results.rebuild = true;
@@ -707,9 +712,9 @@ async function run() {
707
712
 
708
713
  const { privateKey } = loadOrGenerateKeys();
709
714
 
710
- log.info(`📦 Packing to compute content hash...`);
711
- const { tarballHash } = packAndHash(stageDir);
712
- log.success(`🔒 Content hash: ${tarballHash.slice(0, 12)}...`);
715
+ log.info(`📦 Computing logical hash...`);
716
+ const logicalHash = hashFiles(stageDir);
717
+ log.success(`🔒 Content hash: ${logicalHash.slice(0, 12)}...`);
713
718
 
714
719
  const stagedReadmePath = path.join(stageDir, 'README.md');
715
720
  let stagedReadme = '';
@@ -726,14 +731,14 @@ async function run() {
726
731
  const hippPkg = JSON.parse(fs.readFileSync(hippPkgPath, 'utf8'));
727
732
  const hippVersion = hippPkg.version === '0.0.0' ? version : hippPkg.version;
728
733
  const originUrl = provenance.remoteUrl;
729
- const dataToSign = buildSignData(tarballHash, originUrl, rawTag, revision, name, email);
734
+ const dataToSign = buildSignData(logicalHash, originUrl, rawTag, revision, name, email);
730
735
  const signature = signContent(dataToSign, privateKey);
731
736
 
732
737
  const manifestJson = {
733
738
  origin: originUrl,
734
739
  tag: rawTag,
735
740
  revision: revision,
736
- hash: tarballHash,
741
+ hash: logicalHash,
737
742
  signature: signature,
738
743
  name: name,
739
744
  email: email,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dk/hipp",
3
- "version": "0.1.36",
3
+ "version": "0.1.37",
4
4
  "description": "High Integrity Package Publisher",
5
5
  "main": "hipp.js",
6
6
  "bin": {