{"record":{"id":"5e9fa5caa305c585","repo":"affaan-m/ECC","slug":"nasiko-installation-requires-a-pinned-version-such","errorCode":null,"errorMessage":"Nasiko installation requires a pinned version such as v0.1.0; latest is not allowed.","messagePattern":"Nasiko installation requires a pinned version such as v0\\.1\\.0; latest is not allowed\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/nasiko-release.js","lineNumber":42,"sourceCode":"    'linux/arm64': Object.freeze({ manifestDigest: 'sha256:655021a129c7df4621a80d16ea4eab38018530bfe9a20da646641d9f4ac5c249', binaryDigest: 'sha256:85f9fa5cfbed6c276fce6df2d71e9d0c66d7d8e8d46a40297464833d38db7a7e' }),\n    'darwin/amd64': Object.freeze({ manifestDigest: 'sha256:b4188482621efd7da5a2ab630f653665ab5f80b9aceae448b6bb5fc93e003f06', binaryDigest: 'sha256:ed6232e0bb96a2dcfd86d3c25f86021091600d52f09250403a54528bfe8100a3' }),\n    'darwin/arm64': Object.freeze({ manifestDigest: 'sha256:ce7e54fa19f989a5d125c4409b3587ca9503bb5a07bc5ff223c60e0fbad437f0', binaryDigest: 'sha256:3c60f862b04eea1b9a633593b39f1a443d9ca2123cf3edfd150d313e95f3894b' }),\n    'windows/amd64': Object.freeze({ manifestDigest: 'sha256:0760fe1fc98e8fedb66796aaf891a1de9268af1338c5e88b949656fda5d9f045', binaryDigest: 'sha256:0f57672d24fc3c70e4cbbf22864e65b35b9978ddaae3793803841536e682929b' }),\n  }),\n});\n\nfunction normalizePlatform(platform = process.platform, architecture = process.arch) {\n  const osName = platform === 'win32' ? 'windows' : platform;\n  if (!['linux', 'darwin', 'windows'].includes(osName)) throw new Error(`Unsupported platform: ${platform}`);\n  const arch = architecture === 'x64' ? 'amd64' : architecture;\n  if (!['amd64', 'arm64'].includes(arch)) throw new Error(`Unsupported architecture: ${architecture}`);\n  if (osName === 'windows' && arch !== 'amd64') throw new Error(`Unsupported architecture for Windows: ${architecture}`);\n  return { os: osName, arch, binaryName: osName === 'windows' ? 'nasiko.exe' : 'nasiko' };\n}\n\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) {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/nasiko-release.js#L24-L60","documentation":"getQualifiedRelease requires an exact semver version string in the form vX.Y.Z because Nasiko installs are pinned to cryptographically qualified releases. 'latest', loose versions ('0.1.0' without 'v'), ranges, or empty input throw, ensuring digest pinning is always explicit.","triggerScenarios":"Passing 'latest', 'v0.1', '0.1.0', 'v0.1.0-beta', or an unset version into getQualifiedRelease (directly or via the Nasiko install command/config).","commonSituations":"Using 'latest' out of habit from npm; reading a version from package.json that lacks the 'v' prefix; config/env interpolation producing an empty version; attempting a prerelease build.","solutions":["Use an exact pinned tag like v0.1.0","Strip/add the 'v' prefix to match ^v\\d+\\.\\d+\\.\\d+$","Check QUALIFIED_RELEASES in scripts/lib/nasiko-release.js for versions that exist","Resolve 'latest' manually by looking up the newest release tag first"],"exampleFix":"// before\ngetQualifiedRelease('latest');\n// after\ngetQualifiedRelease('v0.1.0');","handlingStrategy":"validation","validationCode":"const VERSION_RE = /^v\\d+\\.\\d+\\.\\d+$/;\nif (!VERSION_RE.test(String(version ?? ''))) {\n  throw new Error(`version must match vX.Y.Z, got: ${version}`);\n}","typeGuard":"function isPinnedVersion(v) {\n  return typeof v === 'string' && /^v\\d+\\.\\d+\\.\\d+$/.test(v);\n}","tryCatchPattern":"try {\n  const rel = getQualifiedRelease(version);\n} catch (e) {\n  if (e.message.includes('pinned version')) {\n    console.error('Resolve latest to a concrete tag, e.g. v0.1.0, and retry.');\n  } else throw e;\n}","preventionTips":["Never use 'latest' for digest-pinned installers","Normalize version sources (package.json tags often lack the leading 'v')","Store the pinned version in config, not env that may be empty"],"tags":["versioning","validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}