{"record":{"id":"665aa726c2a27813","repo":"affaan-m/ECC","slug":"label-digest-mismatch-expected-expecteddiges","errorCode":null,"errorMessage":"${label} digest mismatch: expected ${expectedDigest}, got ${actual}.","messagePattern":"(.+?) digest mismatch: expected (.+?), got (.+?)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"scripts/lib/nasiko-release.js","lineNumber":57,"sourceCode":"\nfunction getQualifiedRelease(version, platform = process.platform, architecture = process.arch) {\n  if (!/^v\\d+\\.\\d+\\.\\d+$/.test(String(version || ''))) {\n    throw new Error('Nasiko installation requires a pinned version such as v0.1.0; latest is not allowed.');\n  }\n  const normalized = normalizePlatform(platform, architecture);\n  const qualification = QUALIFIED_RELEASES[version]?.[`${normalized.os}/${normalized.arch}`];\n  if (!qualification) throw new Error(`Nasiko ${version} is not qualified for ${normalized.os}/${normalized.arch}.`);\n  return { version, ...normalized, ...qualification, license: LICENSE, sourceUrl: SOURCE_URL };\n}\n\nfunction digestBytes(bytes) {\n  return `sha256:${crypto.createHash('sha256').update(bytes).digest('hex')}`;\n}\n\nfunction assertDigest(bytes, expectedDigest, label) {\n  if (!SHA256_PATTERN.test(expectedDigest)) throw new Error(`${label} has an invalid expected digest.`);\n  const actual = digestBytes(bytes);\n  if (actual !== expectedDigest) throw new Error(`${label} digest mismatch: expected ${expectedDigest}, got ${actual}.`);\n}\n\nfunction validateManifest(bytes) {\n  let manifest;\n  try { manifest = JSON.parse(bytes.toString('utf8')); } catch (_error) { throw new Error('Nasiko manifest is not valid JSON.'); }\n  if (manifest.schemaVersion !== 2 || !Array.isArray(manifest.layers) || manifest.layers.length !== 1) {\n    throw new Error('Nasiko manifest must contain exactly one OCI layer.');\n  }\n  const layer = manifest.layers[0];\n  if (layer.mediaType !== 'application/gzip' || !SHA256_PATTERN.test(layer.digest)) {\n    throw new Error('Nasiko manifest layer is not a qualified gzip artifact.');\n  }\n  if (!Number.isSafeInteger(layer.size) || layer.size <= 0 || layer.size > MAX_ARCHIVE_BYTES) {\n    throw new Error('Nasiko manifest layer size is outside the allowed range.');\n  }\n  return { digest: layer.digest, size: layer.size };\n}\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/affaan-m/ECC/blob/06c5e118c4d3e6c3b7f9445f973a2194c82de193/scripts/lib/nasiko-release.js#L39-L75","documentation":"assertDigest in scripts/lib/nasiko-release.js computes sha256 over the downloaded bytes and compares them to the digest pinned in QUALIFIED_RELEASES for either the OCI manifest or the extracted binary. A mismatch aborts the install before anything is executed or written. This is the supply-chain integrity gate: it catches corrupted downloads, proxy/AV tampering, registry serving wrong content, and actual attacks.","triggerScenarios":"The bytes fetched from registry.nasiko.dev hash differently than the pinned manifestDigest or binaryDigest for the qualified release: a truncated or corrupted HTTP response, a TLS-inspecting corporate proxy or antivirus rewriting content, a transparent captive portal, the registry serving an incorrect artifact, or genuine tampering.","commonSituations":"Corporate networks with SSL inspection (Zscaler, Blue Coat) mangling binary downloads; flaky CI networks producing truncated bodies; antivirus HTTP scanning modifying payloads; an upstream re-publish of the same tag (which should be treated as an incident).","solutions":["Re-run the install once; transient truncation is the most common cause","If the mismatch is reproducible, verify manually: download the artifact with curl and compare `sha256sum` against the digest in the error message","Exclude registry.nasiko.dev from TLS interception/AV payload scanning, or run from an unrestricted network","If the manual hash confirms the registry content differs from the pinned digest, stop and report it to the maintainers - do not bypass the check"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await installNasiko({ version: 'v0.1.0' });\n} catch (error) {\n  if (/digest mismatch/.test(String(error.message))) {\n    // Fail closed: delete partial downloads, never skip verification.\n    // One retry covers transient corruption; a repeat mismatch means proxy/AV\n    // interference or a supply-chain incident - capture expected/got digests\n    // and report upstream.\n  }\n  throw error;\n}","preventionTips":["Exclude the registry origin from TLS-inspecting proxies and AV payload scanning","Never patch out or bypass the digest check to 'get past' this error","Log both digests from the message when reporting - they identify exactly which artifact was served","Retry at most once; deterministic mismatches are an incident, not a flake"],"tags":["checksum","sha256","supply-chain","integrity"],"backgroundTag":"checksum-mismatch","analyzedSha":"06c5e118c4d3e6c3b7f9445f973a2194c82de193","analyzedAt":"2026-08-18T11:27:13.915Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}