@parmanasystems/bundle 1.0.19 → 1.3.0
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/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28,8 +28,8 @@ import * as fs2 from "fs";
|
|
|
28
28
|
import * as path2 from "path";
|
|
29
29
|
|
|
30
30
|
// src/traverse.ts
|
|
31
|
-
import fs from "fs";
|
|
32
|
-
import path from "path";
|
|
31
|
+
import * as fs from "fs";
|
|
32
|
+
import * as path from "path";
|
|
33
33
|
var EXCLUDED_FILES = [
|
|
34
34
|
"bundle.manifest.json",
|
|
35
35
|
"bundle.sig"
|
|
@@ -130,8 +130,8 @@ function generateManifest(policyId, policyVersion, directory) {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
// src/read.ts
|
|
133
|
-
import fs3 from "fs";
|
|
134
|
-
import path3 from "path";
|
|
133
|
+
import * as fs3 from "fs";
|
|
134
|
+
import * as path3 from "path";
|
|
135
135
|
function readManifest(directory) {
|
|
136
136
|
const manifestPath = path3.join(
|
|
137
137
|
directory,
|
|
@@ -145,8 +145,8 @@ function readManifest(directory) {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
// src/verify.ts
|
|
148
|
-
import fs4 from "fs";
|
|
149
|
-
import path4 from "path";
|
|
148
|
+
import * as fs4 from "fs";
|
|
149
|
+
import * as path4 from "path";
|
|
150
150
|
function verifyManifest(manifest, directory) {
|
|
151
151
|
const files = traverseDirectory(directory);
|
|
152
152
|
const recalculatedArtifacts = files.map((relativePath) => {
|
|
@@ -193,8 +193,8 @@ function verifyManifest(manifest, directory) {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
// src/write.ts
|
|
196
|
-
import fs5 from "fs";
|
|
197
|
-
import path5 from "path";
|
|
196
|
+
import * as fs5 from "fs";
|
|
197
|
+
import * as path5 from "path";
|
|
198
198
|
function writeManifest(manifest, directory) {
|
|
199
199
|
const manifestPath = path5.join(
|
|
200
200
|
directory,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/canonicalize.ts","../src/hash.ts","../src/manifest.ts","../src/traverse.ts","../src/read.ts","../src/verify.ts","../src/write.ts"],"sourcesContent":["/**\n * Serializes `value` to a stable, pretty-printed JSON string with object keys\n * sorted recursively. This is the canonical byte representation used for all\n * bundle hashing and manifest signing operations.\n *\n * Arrays preserve their original order; only object keys are sorted.\n *\n * Enforces: INV-001, INV-048, INV-049, INV-050, INV-051, INV-052, INV-053, INV-054.\n */\nexport function canonicalize(value: unknown): string {\n return JSON.stringify(sortKeys(value), null, 2);\n}\n\nfunction sortKeys(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortKeys);\n }\n\n if (value !== null && typeof value === \"object\") {\n return Object.keys(value as Record<string, unknown>)\n .sort()\n .reduce<Record<string, unknown>>((acc, key) => {\n acc[key] = sortKeys(\n (value as Record<string, unknown>)[key]\n );\n\n return acc;\n }, {});\n }\n\n return value;\n}\n\n\n\n\n","import * as crypto from \"crypto\";\n\n/** Returns the SHA-256 hex digest of `content` (interpreted as UTF-8). Enforces: INV-047, INV-057. */\nexport function sha256(content: string): string {\n return crypto\n .createHash(\"sha256\")\n .update(content, \"utf8\")\n .digest(\"hex\");\n}\n\n\n\n\n","import * as fs from \"fs\";\nimport * as path from \"path\";\n\nimport { canonicalize } from \"./canonicalize\";\nimport { sha256 } from \"./hash\";\nimport { traverseDirectory } from \"./traverse\";\n\nimport type {\n BundleArtifact,\n BundleManifest,\n} from \"./types\";\n\n/**\n * Generates a content-addressed {@link BundleManifest} for `policyId`/`policyVersion`\n * by hashing every file under `directory` (manifest and sig files excluded).\n *\n * JSON files are canonicalized before hashing; other files have CRLF normalized\n * to LF. The final `bundle_hash` is SHA-256 of the canonical manifest with\n * `bundle_hash` set to `\"\"`, making it a deterministic commitment over all\n * artifact content.\n *\n * @param policyId - Policy identifier to embed in the manifest.\n * @param policyVersion - Policy version string (e.g. `\"v1\"`).\n * @param directory - Absolute path to the bundle directory.\n */\nexport function generateManifest(\n policyId: string,\n policyVersion: string,\n directory: string\n): BundleManifest {\n\n const files =\n traverseDirectory(directory);\n\n const artifacts: BundleArtifact[] =\n files.map((relativePath) => {\n\n const fullPath =\n path.join(\n directory,\n relativePath\n );\n\n const content =\n fs.readFileSync(\n fullPath,\n \"utf8\"\n );\n\n const canonicalContent =\n relativePath.endsWith(\".json\")\n ? canonicalize(\n JSON.parse(content)\n )\n : content.replace(\n /\\r\\n/g,\n \"\\n\"\n );\n\n return {\n path:\n relativePath,\n\n hash:\n sha256(\n canonicalContent\n ),\n };\n });\n\n const manifest: BundleManifest = {\n manifest_version:\n \"1\",\n\n policy_id:\n policyId,\n\n policy_version:\n policyVersion,\n\n artifacts,\n\n runtime_requirements: {\n required_capabilities: [\n \"replay-protection\",\n \"attestation-signing\",\n \"bundle-verification\",\n ],\n\n supported_runtime_versions: [\n \"1.0.0\",\n ],\n\n supported_schema_versions: [\n \"1.0.0\",\n ],\n },\n\n bundle_hash:\n \"\",\n };\n\n const canonical =\n canonicalize(\n manifest\n );\n\n const bundleHash =\n sha256(\n canonical\n );\n\n manifest.bundle_hash =\n bundleHash;\n\n return manifest;\n}\n\n\n\n\n","import fs from \"fs\";\nimport path from \"path\";\n\nconst EXCLUDED_FILES = [\n \"bundle.manifest.json\",\n \"bundle.sig\",\n];\n\n/**\n * Recursively enumerates all non-excluded files under `directory`, returning\n * normalized POSIX-style paths relative to `root` (defaults to `directory`).\n * Entries are sorted deterministically by name at each level.\n * `bundle.manifest.json` and `bundle.sig` are always excluded.\n *\n * @param directory - The directory to traverse.\n * @param root - The root used for computing relative output paths.\n */\nexport function traverseDirectory(\n directory: string,\n root: string = directory\n): string[] {\n const entries = fs\n .readdirSync(directory, {\n withFileTypes: true,\n })\n .sort((a, b) =>\n a.name.localeCompare(b.name)\n );\n\n const results: string[] = [];\n\n for (const entry of entries) {\n const fullPath = path.join(\n directory,\n entry.name\n );\n\n if (entry.isDirectory()) {\n results.push(\n ...traverseDirectory(\n fullPath,\n root\n )\n );\n\n continue;\n }\n\n if (\n EXCLUDED_FILES.includes(\n entry.name\n )\n ) {\n continue;\n }\n\n const relativePath =\n path.relative(\n root,\n fullPath\n );\n\n results.push(\n normalizePath(relativePath)\n );\n }\n\n return results;\n}\n\nfunction normalizePath(\n value: string\n): string {\n return value.replace(/\\\\\\\\/g, \"/\");\n}\n\n\n\n\n","import fs from \"fs\";\nimport path from \"path\";\n\nimport type {\n BundleManifest,\n} from \"./types\";\n\n/**\n * Reads and JSON-parses `bundle.manifest.json` from `directory`.\n *\n * @param directory - Path to a bundle directory containing `bundle.manifest.json`.\n */\nexport function readManifest(\n directory: string\n): BundleManifest {\n const manifestPath = path.join(\n directory,\n \"bundle.manifest.json\"\n );\n\n const content =\n fs.readFileSync(\n manifestPath,\n \"utf8\"\n );\n\n return JSON.parse(content);\n}\n\n\n\n\n","import fs from \"fs\";\nimport path from \"path\";\n\nimport { canonicalize } from \"./canonicalize\";\nimport { sha256 } from \"./hash\";\nimport { traverseDirectory } from \"./traverse\";\n\nimport type {\n BundleManifest,\n VerifyResult,\n} from \"./types\";\n\n/**\n * Re-hashes every file under `directory` and recomputes the bundle hash, then\n * compares it against `manifest.bundle_hash`.\n *\n * Returns `valid: true` only when the on-disk content matches the manifest\n * commitment exactly. Any file addition, deletion, or modification produces\n * a differing hash and `valid: false`.\n *\n * @param manifest - The reference manifest containing the expected bundle hash.\n * @param directory - Bundle directory whose contents will be re-hashed.\n */\nexport function verifyManifest(\n manifest: BundleManifest,\n directory: string\n): VerifyResult {\n\n const files =\n traverseDirectory(directory);\n\n const recalculatedArtifacts =\n files.map((relativePath) => {\n\n const fullPath =\n path.join(\n directory,\n relativePath\n );\n\n const content =\n fs.readFileSync(\n fullPath,\n \"utf8\"\n );\n\n const canonicalContent =\n relativePath.endsWith(\".json\")\n ? canonicalize(\n JSON.parse(content)\n )\n : content.replace(\n /\\r\\n/g,\n \"\\n\"\n );\n\n return {\n path: relativePath,\n\n hash:\n sha256(\n canonicalContent\n ),\n };\n });\n\n const reconstructedManifest: BundleManifest =\n {\n manifest_version:\n manifest.manifest_version,\n\n policy_id:\n manifest.policy_id,\n\n policy_version:\n manifest.policy_version,\n\n artifacts:\n recalculatedArtifacts,\n\n runtime_requirements:\n manifest.runtime_requirements,\n\n bundle_hash: \"\",\n };\n\n const canonical =\n canonicalize(\n reconstructedManifest\n );\n\n const recalculatedBundleHash =\n sha256(\n canonical\n );\n\n return {\n valid:\n recalculatedBundleHash ===\n manifest.bundle_hash,\n\n expected_bundle_hash:\n manifest.bundle_hash,\n\n actual_bundle_hash:\n recalculatedBundleHash,\n };\n}\n\n\n\n\n","import fs from \"fs\";\nimport path from \"path\";\n\nimport { canonicalize } from \"./canonicalize\";\n\nimport type {\n BundleManifest,\n} from \"./types\";\n\n/**\n * Writes `manifest` to `<directory>/bundle.manifest.json` in canonical form.\n * The output is deterministic: identical manifests always produce identical\n * bytes on disk.\n *\n * @param manifest - The manifest to persist.\n * @param directory - Destination bundle directory.\n */\nexport function writeManifest(\n manifest: BundleManifest,\n directory: string\n): void {\n const manifestPath = path.join(\n directory,\n \"bundle.manifest.json\"\n );\n\n const canonical =\n canonicalize(manifest);\n\n fs.writeFileSync(\n manifestPath,\n canonical,\n \"utf8\"\n );\n}\n\n\n\n\n"],"mappings":"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","names":["fs","path","fs","path","fs","path","path","fs","fs","path","path","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/canonicalize.ts","../src/hash.ts","../src/manifest.ts","../src/traverse.ts","../src/read.ts","../src/verify.ts","../src/write.ts"],"sourcesContent":["/**\r\n * Serializes `value` to a stable, pretty-printed JSON string with object keys\r\n * sorted recursively. This is the canonical byte representation used for all\r\n * bundle hashing and manifest signing operations.\r\n *\r\n * Arrays preserve their original order; only object keys are sorted.\r\n *\r\n * Enforces: INV-001, INV-048, INV-049, INV-050, INV-051, INV-052, INV-053, INV-054.\r\n */\r\nexport function canonicalize(value: unknown): string {\r\n return JSON.stringify(sortKeys(value), null, 2);\r\n}\r\n\r\nfunction sortKeys(value: unknown): unknown {\r\n if (Array.isArray(value)) {\r\n return value.map(sortKeys);\r\n }\r\n\r\n if (value !== null && typeof value === \"object\") {\r\n return Object.keys(value as Record<string, unknown>)\r\n .sort()\r\n .reduce<Record<string, unknown>>((acc, key) => {\r\n acc[key] = sortKeys(\r\n (value as Record<string, unknown>)[key]\r\n );\r\n\r\n return acc;\r\n }, {});\r\n }\r\n\r\n return value;\r\n}\r\n\r\n\r\n\r\n\r\n","import * as crypto from \"node:crypto\";\r\n\r\n/** Returns the SHA-256 hex digest of `content` (interpreted as UTF-8). Enforces: INV-047, INV-057. */\r\nexport function sha256(content: string): string {\r\n return crypto\r\n .createHash(\"sha256\")\r\n .update(content, \"utf8\")\r\n .digest(\"hex\");\r\n}\r\n\r\n\r\n\r\n\r\n","import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\n\r\nimport { canonicalize } from \"./canonicalize.js\";\r\nimport { sha256 } from \"./hash.js\";\r\nimport { traverseDirectory } from \"./traverse.js\";\r\n\r\nimport type {\r\n BundleArtifact,\r\n BundleManifest,\r\n} from \"./types.js\";\r\n\r\n/**\r\n * Generates a content-addressed {@link BundleManifest} for `policyId`/`policyVersion`\r\n * by hashing every file under `directory` (manifest and sig files excluded).\r\n *\r\n * JSON files are canonicalized before hashing; other files have CRLF normalized\r\n * to LF. The final `bundle_hash` is SHA-256 of the canonical manifest with\r\n * `bundle_hash` set to `\"\"`, making it a deterministic commitment over all\r\n * artifact content.\r\n *\r\n * @param policyId - Policy identifier to embed in the manifest.\r\n * @param policyVersion - Policy version string (e.g. `\"v1\"`).\r\n * @param directory - Absolute path to the bundle directory.\r\n */\r\nexport function generateManifest(\r\n policyId: string,\r\n policyVersion: string,\r\n directory: string\r\n): BundleManifest {\r\n\r\n const files =\r\n traverseDirectory(directory);\r\n\r\n const artifacts: BundleArtifact[] =\r\n files.map((relativePath) => {\r\n\r\n const fullPath =\r\n path.join(\r\n directory,\r\n relativePath\r\n );\r\n\r\n const content =\r\n fs.readFileSync(\r\n fullPath,\r\n \"utf8\"\r\n );\r\n\r\n const canonicalContent =\r\n relativePath.endsWith(\".json\")\r\n ? canonicalize(\r\n JSON.parse(content)\r\n )\r\n : content.replace(\r\n /\\r\\n/g,\r\n \"\\n\"\r\n );\r\n\r\n return {\r\n path:\r\n relativePath,\r\n\r\n hash:\r\n sha256(\r\n canonicalContent\r\n ),\r\n };\r\n });\r\n\r\n const manifest: BundleManifest = {\r\n manifest_version:\r\n \"1\",\r\n\r\n policy_id:\r\n policyId,\r\n\r\n policy_version:\r\n policyVersion,\r\n\r\n artifacts,\r\n\r\n runtime_requirements: {\r\n required_capabilities: [\r\n \"replay-protection\",\r\n \"attestation-signing\",\r\n \"bundle-verification\",\r\n ],\r\n\r\n supported_runtime_versions: [\r\n \"1.0.0\",\r\n ],\r\n\r\n supported_schema_versions: [\r\n \"1.0.0\",\r\n ],\r\n },\r\n\r\n bundle_hash:\r\n \"\",\r\n };\r\n\r\n const canonical =\r\n canonicalize(\r\n manifest\r\n );\r\n\r\n const bundleHash =\r\n sha256(\r\n canonical\r\n );\r\n\r\n manifest.bundle_hash =\r\n bundleHash;\r\n\r\n return manifest;\r\n}\r\n\r\n\r\n\r\n\r\n","import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\n\r\nconst EXCLUDED_FILES = [\r\n \"bundle.manifest.json\",\r\n \"bundle.sig\",\r\n];\r\n\r\n/**\r\n * Recursively enumerates all non-excluded files under `directory`, returning\r\n * normalized POSIX-style paths relative to `root` (defaults to `directory`).\r\n * Entries are sorted deterministically by name at each level.\r\n * `bundle.manifest.json` and `bundle.sig` are always excluded.\r\n *\r\n * @param directory - The directory to traverse.\r\n * @param root - The root used for computing relative output paths.\r\n */\r\nexport function traverseDirectory(\r\n directory: string,\r\n root: string = directory\r\n): string[] {\r\n const entries = fs\r\n .readdirSync(directory, {\r\n withFileTypes: true,\r\n })\r\n .sort((a, b) =>\r\n a.name.localeCompare(b.name)\r\n );\r\n\r\n const results: string[] = [];\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(\r\n directory,\r\n entry.name\r\n );\r\n\r\n if (entry.isDirectory()) {\r\n results.push(\r\n ...traverseDirectory(\r\n fullPath,\r\n root\r\n )\r\n );\r\n\r\n continue;\r\n }\r\n\r\n if (\r\n EXCLUDED_FILES.includes(\r\n entry.name\r\n )\r\n ) {\r\n continue;\r\n }\r\n\r\n const relativePath =\r\n path.relative(\r\n root,\r\n fullPath\r\n );\r\n\r\n results.push(\r\n normalizePath(relativePath)\r\n );\r\n }\r\n\r\n return results;\r\n}\r\n\r\nfunction normalizePath(\r\n value: string\r\n): string {\r\n return value.replace(/\\\\\\\\/g, \"/\");\r\n}\r\n\r\n\r\n\r\n\r\n","import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\n\r\nimport type {\r\n BundleManifest,\r\n} from \"./types.js\";\r\n\r\n/**\r\n * Reads and JSON-parses `bundle.manifest.json` from `directory`.\r\n *\r\n * @param directory - Path to a bundle directory containing `bundle.manifest.json`.\r\n */\r\nexport function readManifest(\r\n directory: string\r\n): BundleManifest {\r\n const manifestPath = path.join(\r\n directory,\r\n \"bundle.manifest.json\"\r\n );\r\n\r\n const content =\r\n fs.readFileSync(\r\n manifestPath,\r\n \"utf8\"\r\n );\r\n\r\n return JSON.parse(content);\r\n}\r\n\r\n\r\n\r\n\r\n","import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\n\r\nimport { canonicalize } from \"./canonicalize.js\";\r\nimport { sha256 } from \"./hash.js\";\r\nimport { traverseDirectory } from \"./traverse.js\";\r\n\r\nimport type {\r\n BundleManifest,\r\n VerifyResult,\r\n} from \"./types.js\";\r\n\r\n/**\r\n * Re-hashes every file under `directory` and recomputes the bundle hash, then\r\n * compares it against `manifest.bundle_hash`.\r\n *\r\n * Returns `valid: true` only when the on-disk content matches the manifest\r\n * commitment exactly. Any file addition, deletion, or modification produces\r\n * a differing hash and `valid: false`.\r\n *\r\n * @param manifest - The reference manifest containing the expected bundle hash.\r\n * @param directory - Bundle directory whose contents will be re-hashed.\r\n */\r\nexport function verifyManifest(\r\n manifest: BundleManifest,\r\n directory: string\r\n): VerifyResult {\r\n\r\n const files =\r\n traverseDirectory(directory);\r\n\r\n const recalculatedArtifacts =\r\n files.map((relativePath) => {\r\n\r\n const fullPath =\r\n path.join(\r\n directory,\r\n relativePath\r\n );\r\n\r\n const content =\r\n fs.readFileSync(\r\n fullPath,\r\n \"utf8\"\r\n );\r\n\r\n const canonicalContent =\r\n relativePath.endsWith(\".json\")\r\n ? canonicalize(\r\n JSON.parse(content)\r\n )\r\n : content.replace(\r\n /\\r\\n/g,\r\n \"\\n\"\r\n );\r\n\r\n return {\r\n path: relativePath,\r\n\r\n hash:\r\n sha256(\r\n canonicalContent\r\n ),\r\n };\r\n });\r\n\r\n const reconstructedManifest: BundleManifest =\r\n {\r\n manifest_version:\r\n manifest.manifest_version,\r\n\r\n policy_id:\r\n manifest.policy_id,\r\n\r\n policy_version:\r\n manifest.policy_version,\r\n\r\n artifacts:\r\n recalculatedArtifacts,\r\n\r\n runtime_requirements:\r\n manifest.runtime_requirements,\r\n\r\n bundle_hash: \"\",\r\n };\r\n\r\n const canonical =\r\n canonicalize(\r\n reconstructedManifest\r\n );\r\n\r\n const recalculatedBundleHash =\r\n sha256(\r\n canonical\r\n );\r\n\r\n return {\r\n valid:\r\n recalculatedBundleHash ===\r\n manifest.bundle_hash,\r\n\r\n expected_bundle_hash:\r\n manifest.bundle_hash,\r\n\r\n actual_bundle_hash:\r\n recalculatedBundleHash,\r\n };\r\n}\r\n\r\n\r\n\r\n\r\n","import * as fs from \"node:fs\";\r\nimport * as path from \"node:path\";\r\n\r\nimport { canonicalize } from \"./canonicalize.js\";\r\n\r\nimport type {\r\n BundleManifest,\r\n} from \"./types.js\";\r\n\r\n/**\r\n * Writes `manifest` to `<directory>/bundle.manifest.json` in canonical form.\r\n * The output is deterministic: identical manifests always produce identical\r\n * bytes on disk.\r\n *\r\n * @param manifest - The manifest to persist.\r\n * @param directory - Destination bundle directory.\r\n */\r\nexport function writeManifest(\r\n manifest: BundleManifest,\r\n directory: string\r\n): void {\r\n const manifestPath = path.join(\r\n directory,\r\n \"bundle.manifest.json\"\r\n );\r\n\r\n const canonical =\r\n canonicalize(manifest);\r\n\r\n fs.writeFileSync(\r\n manifestPath,\r\n canonical,\r\n \"utf8\"\r\n );\r\n}\r\n\r\n\r\n\r\n\r\n"],"mappings":"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","names":["fs","path","fs","path","fs","path","fs","path"]}
|