diff --git a/product-source/hololake-platform/guanghu-os/pncc-runtime/pncc-runtime.mjs b/product-source/hololake-platform/guanghu-os/pncc-runtime/pncc-runtime.mjs index fb95d423d..08c8289a6 100644 --- a/product-source/hololake-platform/guanghu-os/pncc-runtime/pncc-runtime.mjs +++ b/product-source/hololake-platform/guanghu-os/pncc-runtime/pncc-runtime.mjs @@ -25,6 +25,7 @@ const JOURNAL_SCHEMA = 'guanghu.pncc-runtime-journal/v1' const STATUS_SCHEMA = 'guanghu.pncc-runtime-status/v1' const MAX_ARTIFACT_BYTES = 2 * 1024 * 1024 const MAX_ARTIFACTS = 256 +const MAX_TREE_ENTRIES = 4096 function sha256(value) { return createHash('sha256').update(value).digest('hex') @@ -74,13 +75,28 @@ function exactGitRoot(repository) { return candidate } -function committedArtifact(repository, head, path) { +function committedTree(repository, head) { + const raw = runGit(repository, ['ls-tree', '-r', '-z', head], 'PNCC_GIT_TREE_READ', { encoding: 'buffer' }) + if (!Buffer.isBuffer(raw) || raw.length === 0) fail('PNCC_COMMITTED_TREE_EMPTY') + const entries = new Map() + for (const record of raw.toString('utf8').split('\0')) { + if (!record) continue + const tab = record.indexOf('\t') + if (tab < 1) fail('PNCC_COMMITTED_TREE_ENTRY_INVALID') + const header = record.slice(0, tab).split(' ') + const path = record.slice(tab + 1) + if (header.length !== 3 || entries.has(path)) fail('PNCC_COMMITTED_TREE_ENTRY_INVALID') + entries.set(path, { mode: header[0], type: header[1], object: validateFullHead(header[2]) }) + if (entries.size > MAX_TREE_ENTRIES) fail('PNCC_COMMITTED_TREE_ENTRY_LIMIT_EXCEEDED') + } + return entries +} + +function committedArtifact(repository, path, tree) { validateRelativePath(path) - const treeEntry = String(runGit(repository, ['ls-tree', head, '--', path], 'PNCC_GIT_TREE_ENTRY_READ')).trim() - const match = treeEntry.match(/^([0-9]{6}) blob ([0-9a-f]{40})\t(.+)$/u) - if (!match || match[3] !== path) fail('PNCC_COMMITTED_PATH_NOT_EXACT_BLOB', path) - const mode = match[1] - const object = validateFullHead(match[2].toLowerCase()) + const entry = tree.get(path) + if (!entry || entry.type !== 'blob') fail('PNCC_COMMITTED_PATH_NOT_EXACT_BLOB', path) + const { mode, object } = entry const type = String(runGit(repository, ['cat-file', '-t', object], 'PNCC_GIT_OBJECT_TYPE_READ')).trim() if (type !== 'blob') fail('PNCC_COMMITTED_OBJECT_NOT_BLOB', path) if (!['100644', '100755'].includes(mode)) fail('PNCC_COMMITTED_OBJECT_NOT_REGULAR_FILE', path) @@ -91,8 +107,8 @@ function committedArtifact(repository, head, path) { return { relativePath: path, gitObjectId: object, sha256: sha256(bytes), byteLength: bytes.length, bytes } } -function parseManifest(repository, head) { - const evidence = committedArtifact(repository, head, MANIFEST_PATH) +function parseManifest(repository, tree) { + const evidence = committedArtifact(repository, MANIFEST_PATH, tree) let manifest try { manifest = JSON.parse(evidence.bytes.toString('utf8')) @@ -123,7 +139,8 @@ export function inspectPersonaRepository(repositoryPath, nodeId) { const head = validateFullHead(String(runGit(repository, ['rev-parse', 'HEAD'], 'PNCC_GIT_HEAD_READ')).trim().toLowerCase()) const dirty = String(runGit(repository, ['status', '--porcelain', '--untracked-files=all'], 'PNCC_GIT_STATUS_READ')).trim() if (dirty) fail('PNCC_REPOSITORY_DIRTY') - const { manifest, evidence: manifestEvidence } = parseManifest(repository, head) + const tree = committedTree(repository, head) + const { manifest, evidence: manifestEvidence } = parseManifest(repository, tree) if (manifest.primaryNode !== nodeId) fail('PNCC_PRIMARY_NODE_MISMATCH') const paths = new Set([manifest.brainEntry, manifest.currentCheckpoint, manifest.cognitiveGravity.sourcePath]) @@ -135,7 +152,7 @@ export function inspectPersonaRepository(repositoryPath, nodeId) { } if (paths.size > MAX_ARTIFACTS) fail('PNCC_DECLARED_ARTIFACT_LIMIT_EXCEEDED') const artifacts = [...paths].sort().map((path) => { - const artifact = committedArtifact(repository, head, path) + const artifact = committedArtifact(repository, path, tree) return { relativePath: artifact.relativePath, gitObjectId: artifact.gitObjectId, sha256: artifact.sha256, byteLength: artifact.byteLength } }) return {