{"record":{"id":"cd6816bf4b503df7","repo":"affaan-m/ECC","slug":"nasiko-manifest-layer-is-not-a-qualified-gzip-arti","errorCode":null,"errorMessage":"Nasiko manifest layer is not a qualified gzip artifact.","messagePattern":"Nasiko manifest layer is not a qualified gzip artifact\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/nasiko-release.js","lineNumber":68,"sourceCode":"function 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\nfunction readTarString(block, offset, length) {\n  return block.subarray(offset, offset + length).toString('utf8').replace(/\\0.*$/, '');\n}\n\nfunction extractQualifiedTarGzip(archiveBytes, expectedName) {\n  let tar;\n  try { tar = zlib.gunzipSync(archiveBytes, { maxOutputLength: MAX_BINARY_BYTES + 2048 }); }\n  catch (_error) { throw new Error('Nasiko archive is invalid or exceeds the decompressed size limit.'); }\n  let offset = 0;\n  let binary = null;\n  while (offset + 512 <= tar.length) {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/affaan-m/ECC/blob/06c5e118c4d3e6c3b7f9445f973a2194c82de193/scripts/lib/nasiko-release.js#L50-L86","documentation":"validateManifest in scripts/lib/nasiko-release.js validates the single layer entry after the structure check: mediaType must be exactly 'application/gzip' and digest must match the sha256:<64 lowercase hex> pattern. Other media types (uncompressed layers, zstd-compressed layers, foreign layers) or malformed digests are rejected because extraction only supports the qualified gzip artifact format.","triggerScenarios":"manifest.layers[0].mediaType is anything other than 'application/gzip' (for example 'application/vnd.docker.image.rootfs.diff.tar' or the zstd variant), or layer.digest fails /^sha256:[a-f0-9]{64}$/ (wrong algorithm prefix, uppercase hex, wrong length, missing prefix).","commonSituations":"Upstream recompressed layers with zstd to save bandwidth; a hand-crafted or modified manifest with a truncated digest string; mirrors that normalize or rewrite media types.","solutions":["Re-publish the release with a single application/gzip layer, or extend validation/extraction support if a new format is intentionally adopted","Fix malformed digests in the manifest so they are full lowercase sha256:<64 hex> values","Update the ECC checkout if upstream intentionally changed the qualified artifact format"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await installNasiko({ version: 'v0.1.0' });\n} catch (error) {\n  if (/not a qualified gzip artifact/.test(String(error.message))) {\n    // The layer mediaType/digest shape changed upstream. Fix the publishing\n    // pipeline to emit application/gzip with a sha256:64hex digest.\n  }\n  throw error;\n}","preventionTips":["Freeze the layer mediaType ('application/gzip') in the release pipeline","Add a post-publish assertion that layer.digest matches /^sha256:[a-f0-9]{64}$/","Avoid recompression steps (gzip -> zstd) without updating the installer"],"tags":["oci","manifest","media-type","digest"],"backgroundTag":"oci-manifest-invalid","analyzedSha":"06c5e118c4d3e6c3b7f9445f973a2194c82de193","analyzedAt":"2026-08-18T11:27:13.915Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}