@dk/hipp 0.1.13 → 0.1.14

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 +3 -11
  2. package/hipp.js +30 -72
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -175,16 +175,8 @@ PERFORMANCE OF THIS SOFTWARE.
175
175
  ```json
176
176
  {
177
177
  "origin": "git@github.com:dmytri/hipp.git",
178
- "tag": "v0.1.13"
178
+ "tag": "v0.1.14",
179
+ "hash": "c2a32be7dbb481c7f9e9444b993616bb1e10d41cf9c0b787642873833ebcc77e",
180
+ "signature": "RsopqB7L4VWwi1jBmG1dG6L+Zo0ZV7m5k6jfA+KwafViXgWw6KQniJcCs8aqgujarAANd5AzyHBdlWCNoIFzBg=="
179
181
  }
180
182
  ```
181
-
182
- ```npx @dk/hipp @dk/hipp@0.1.13```
183
- <!-- HIPP-MANIFEST -->
184
- ```json
185
- {
186
- "hash": "0157b775d49e9715e954bc9838f5017632c0fd2e2418d814b0e2bbb92abe3fc3",
187
- "signature": "jyq8xJjFAt5HtqQWPPHw52A2ph7zVxEYD1QClEY3jRFcVFdUlaJj+sGatgP/FChjaI57HZM8flYUvl2r1DA5Dw=="
188
- }
189
- ```
190
- <!-- /HIPP-MANIFEST -->
package/hipp.js CHANGED
@@ -123,46 +123,7 @@ function buildSignData(hash, origin, tag) {
123
123
  return `${hash}\n${origin}\n${tag}\n`;
124
124
  }
125
125
 
126
- const MANIFEST_START = '<!-- HIPP-MANIFEST -->';
127
- const MANIFEST_END = '<!-- /HIPP-MANIFEST -->';
128
-
129
- function appendManifestToReadme(readmeContent, manifest) {
130
- return `${readmeContent}${MANIFEST_START}\n\`\`\`json\n${manifest}\n\`\`\`\n${MANIFEST_END}\n`;
131
- }
132
-
133
- function extractManifestFromReadme(readmeContent) {
134
- const startIdx = readmeContent.indexOf(MANIFEST_START);
135
- if (startIdx === -1) return null;
136
- const endIdx = readmeContent.indexOf(MANIFEST_END, startIdx);
137
- if (endIdx === -1) return null;
138
- const content = readmeContent.slice(startIdx + MANIFEST_START.length, endIdx).trim();
139
- const match = content.match(/^```json\n(.+)\n```$/s);
140
- if (!match) return null;
141
- return match[1];
142
- }
143
-
144
- function stripManifestFromReadme(readmeContent) {
145
- const startIdx = readmeContent.indexOf(MANIFEST_START);
146
- const endIdx = readmeContent.indexOf(MANIFEST_END, startIdx);
147
- if (startIdx === -1 || endIdx === -1) return readmeContent;
148
-
149
- const endLineIdx = readmeContent.indexOf('\n', endIdx);
150
- const endOfManifest = endLineIdx !== -1 ? endLineIdx + 1 : readmeContent.length;
151
-
152
- const beforeWithNewline = readmeContent.slice(0, startIdx);
153
- const lastNewlineBefore = beforeWithNewline.lastIndexOf('\n');
154
- const before = lastNewlineBefore !== -1 ? beforeWithNewline.slice(0, lastNewlineBefore) : beforeWithNewline;
155
-
156
- const after = readmeContent.slice(endOfManifest);
157
- return before + '\n' + after;
158
- }
159
-
160
- function computeReadmeHash(readmeContent) {
161
- const stripped = stripManifestFromReadme(readmeContent);
162
- return sha256(stripped);
163
- }
164
-
165
- function extractJsonMetaFromReadme(readmeContent) {
126
+ function findLastJsonBlock(readmeContent) {
166
127
  const lines = readmeContent.split('\n');
167
128
  let jsonStart = -1;
168
129
  let braceCount = 0;
@@ -186,7 +147,7 @@ function extractJsonMetaFromReadme(readmeContent) {
186
147
  const jsonStr = lines.slice(jsonStart, i + 1).join('\n');
187
148
  try {
188
149
  const parsed = JSON.parse(jsonStr);
189
- if (parsed.origin && parsed.tag) {
150
+ if (parsed.origin && parsed.tag && parsed.hash && parsed.signature) {
190
151
  lastValid = parsed;
191
152
  }
192
153
  } catch {
@@ -199,6 +160,14 @@ function extractJsonMetaFromReadme(readmeContent) {
199
160
  return lastValid;
200
161
  }
201
162
 
163
+ function computeReadmeHash(readmeContent) {
164
+ const jsonBlock = findLastJsonBlock(readmeContent);
165
+ if (!jsonBlock) return sha256(readmeContent);
166
+ const jsonStr = JSON.stringify(jsonBlock, null, 2);
167
+ const beforeJson = readmeContent.split('```json')[0];
168
+ return sha256(beforeJson + '```json\n' + jsonStr + '\n```\n');
169
+ }
170
+
202
171
  function safeStageName(name) {
203
172
  return name.replace(/[^a-zA-Z0-9._-]/g, '-');
204
173
  }
@@ -490,23 +459,12 @@ async function runVerify(packageSpec) {
490
459
  }
491
460
 
492
461
  const stagedReadme = fs.readFileSync(stagedReadmePath, 'utf8');
493
- const jsonMeta = extractJsonMetaFromReadme(stagedReadme);
494
- if (!jsonMeta || !jsonMeta.origin || !jsonMeta.tag) {
495
- fail(`❌ JSON meta (origin/tag) not found in README`);
496
- }
497
-
498
- const manifestStr = extractManifestFromReadme(stagedReadme);
499
- if (!manifestStr) {
500
- fail(`❌ Manifest not found in README`);
462
+ const manifest = findLastJsonBlock(stagedReadme);
463
+ if (!manifest || !manifest.origin || !manifest.tag || !manifest.hash || !manifest.signature) {
464
+ fail(`❌ Manifest not found or invalid in README`);
501
465
  }
502
466
 
503
- const manifest = parseManifest(manifestStr);
504
- if (!manifest || !manifest.hash || !manifest.signature) {
505
- fail(`❌ Invalid manifest format`);
506
- }
507
-
508
- const originUrl = jsonMeta.origin;
509
- const tag = jsonMeta.tag;
467
+ const { origin: originUrl, tag, hash: npmHash, signature } = manifest;
510
468
 
511
469
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), `hipp-verify-git-`));
512
470
  const stageDir = fs.mkdtempSync(path.join(os.tmpdir(), `hipp-verify-stage-`));
@@ -531,21 +489,16 @@ async function runVerify(packageSpec) {
531
489
  fail(`❌ README.md not found in git at tag ${tag}`);
532
490
  }
533
491
 
534
- let stagedReadme = fs.readFileSync(stagedReadmePath, 'utf8');
535
- const verifyBlock = '```npx @dk/hipp ' + pkgName + '@' + tag + '```';
536
- const jsonMetaStr = '```json\n{\n "origin": "' + originUrl + '",\n "tag": "' + tag + '"\n}\n```';
537
- stagedReadme = stagedReadme.trimEnd() + '\n\n' + jsonMetaStr + '\n\n' + verifyBlock + '\n';
538
-
539
- const stagedHash = computeReadmeHash(stagedReadme);
492
+ const stagedHash = sha256(fs.readFileSync(stagedReadmePath, 'utf8'));
540
493
 
541
- if (stagedHash !== manifest.hash) {
494
+ if (stagedHash !== npmHash) {
542
495
  fail(`❌ Hash mismatch: git content does not match npm manifest`);
543
496
  }
544
497
 
545
- log.success(`🔒 Content hash verified: ${manifest.hash.slice(0, 12)}...`);
498
+ log.success(`🔒 Content hash verified: ${npmHash.slice(0, 12)}...`);
546
499
 
547
- const signData = buildSignData(manifest.hash, originUrl, tag);
548
- const signatureValid = verifySignature(signData, manifest.signature, publicKey);
500
+ const signData = buildSignData(npmHash, originUrl, tag);
501
+ const signatureValid = verifySignature(signData, signature, publicKey);
549
502
 
550
503
  if (!signatureValid) {
551
504
  fail(`❌ Signature verification failed`);
@@ -653,15 +606,20 @@ async function run() {
653
606
  stagedReadme = fs.readFileSync(stagedReadmePath, 'utf8');
654
607
  }
655
608
 
656
- const verifyBlock = '```npx @dk/hipp ' + pkg.name + '@' + version + '```';
657
- const jsonMetaStr = '```json\n{\n "origin": "' + provenance.remoteUrl + '",\n "tag": "' + rawTag + '"\n}\n```';
658
- stagedReadme = stagedReadme.trimEnd() + '\n\n' + jsonMetaStr + '\n\n' + verifyBlock + '\n';
609
+ stagedReadme = stagedReadme.trimEnd() + '\n\n';
659
610
 
660
- const readmeHash = computeReadmeHash(stagedReadme);
611
+ const readmeHash = sha256(stagedReadme);
661
612
  const dataToSign = buildSignData(readmeHash, provenance.remoteUrl, rawTag);
662
613
  const signature = signContent(dataToSign, privateKey);
663
- const manifest = createManifest(readmeHash, signature);
664
- stagedReadme = appendManifestToReadme(stagedReadme, manifest);
614
+
615
+ const manifestJson = {
616
+ origin: provenance.remoteUrl,
617
+ tag: rawTag,
618
+ hash: readmeHash,
619
+ signature: signature,
620
+ };
621
+
622
+ stagedReadme += '```json\n' + JSON.stringify(manifestJson, null, 2) + '\n```\n';
665
623
 
666
624
  fs.writeFileSync(stagedReadmePath, stagedReadme);
667
625
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dk/hipp",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "High Integrity Package Publisher",
5
5
  "main": "hipp.js",
6
6
  "bin": {