{"record":{"id":"936605d059375eb8","repo":"santifer/career-ops","slug":"the-release-pointer-names-an-unusable-index-filena","errorCode":null,"errorMessage":"the release pointer names an unusable index filename (${JSON.stringify(doc.filename)}): ${url}","messagePattern":"the release pointer names an unusable index filename \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugins/h1b-sponsor/install-h1b-index.mjs","lineNumber":122,"sourceCode":"  const out = await fetchImpl(url, { timeoutMs: POINTER_TIMEOUT_MS }, async res => {\n    if (res.status !== 200) return { status: res.status };\n    const read = await readBoundedText(res, MAX_POINTER_BYTES);\n    return read.oversized ? { oversized: true } : { text: read.text };\n  });\n  if (out.status) throw new Error(`could not read the release pointer (HTTP ${out.status}): ${url}`);\n  if (out.oversized) throw new Error(`the release pointer is implausibly large: ${url}`);\n\n  let doc;\n  try {\n    doc = JSON.parse(String(out.text || ''));\n  } catch {\n    throw new Error(`the release pointer is not JSON: ${url}`);\n  }\n  if (!doc || typeof doc !== 'object') throw new Error(`the release pointer is not an object: ${url}`);\n\n  const filename = String(doc.filename || '');\n  if (!FILENAME_RE.test(filename)) {\n    throw new Error(`the release pointer names an unusable index filename (${JSON.stringify(doc.filename)}): ${url}`);\n  }\n  const sha256 = String(doc.sha256 || '').trim().toLowerCase();\n  if (!SHA256_RE.test(sha256)) {\n    throw new Error(`the release pointer does not carry a sha256 digest: ${url}`);\n  }\n  // Recorded, never acted on, so a missing or odd value costs a label rather\n  // than the install. Bounded because it lands in a file on disk.\n  const version = doc.version === undefined || doc.version === null\n    ? null\n    : String(doc.version).slice(0, 64);\n  return { filename, sha256, version };\n}\n\n/**\n * Stream the asset to `tmpFile`, hashing as it goes, and return the digest.\n *\n * Streamed rather than buffered: the body is millions of times the size of\n * anything else this plugin reads, and readBoundedText's 1 MiB ceiling exists","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/santifer/career-ops/blob/1696bec4d021768e7359f9aad6b329cba883da20/plugins/h1b-sponsor/install-h1b-index.mjs#L104-L140","documentation":"The pointer is a valid JSON object but its filename field is missing or fails FILENAME_RE, the plugin's whitelist regex for index filenames. Because the filename is used to build a download URL, the plugin refuses any name it cannot validate, and echoes the offending value via JSON.stringify. This prevents path injection or SSRF via a hostile pointer.","triggerScenarios":"fetchPointer(url) parses a JSON object whose doc.filename is undefined, empty, or does not match FILENAME_RE (e.g. contains slashes, '../', unexpected extensions).","commonSituations":"A custom H1B_API_BASE serves a pointer schema from a different/older plugin version whose filename format differs; the pointer object uses a different key (e.g. 'file' or 'asset'); a compromised or mispublished pointer names a non-index file.","solutions":["curl the pointer URL and inspect the filename value; compare it against the expected index-name pattern used by your installed plugin version.","Upgrade (or downgrade) the plugin so its FILENAME_RE matches the pointer format published by your endpoint — a version mismatch is the usual cause.","If you publish the pointer, regenerate it with a filename matching the plugin's expected pattern (no slashes, correct extension).","Restore the default endpoint (unset H1B_API_BASE) if the custom host publishes an incompatible schema."],"exampleFix":"// before (pointer contents)\n{\"filename\":\"../../etc/h1b-index.json\",\"sha256\":\"...\"}\n// after\n{\"filename\":\"h1b-index-2026-08-30.json\",\"sha256\":\"<64-hex>\"}","handlingStrategy":"validation","validationCode":"const doc = JSON.parse(await (await fetch(pointerUrl)).text());\nconst FILENAME_RE = /^[\\w.-]+\\.json$/;\nif (!FILENAME_RE.test(String(doc?.filename ?? ''))) {\n  throw new Error(`pointer filename ${JSON.stringify(doc?.filename)} will be rejected; use a flat index filename`);\n}","typeGuard":"function hasUsableIndexFilename(doc) {\n  return !!doc && typeof doc === 'object' && typeof doc.filename === 'string' && /^[\\w.-]+\\.json$/.test(doc.filename);\n}","tryCatchPattern":"try {\n  await installH1BIndex();\n} catch (e) {\n  if (String(e.message).includes('unusable index filename')) {\n    console.error('Pointer filename failed the allowlist regex; align endpoint schema with the plugin version.');\n  } else throw e;\n}","preventionTips":["Keep pointer filenames flat and simple (no paths, no slashes) so allowlist regexes accept them.","Align custom endpoint pointer schema with your installed plugin version; upgrade together.","Validate the pointer against the plugin's regex in CI before publishing.","Never construct pointer filenames from user input."],"tags":["validation","security","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"1696bec4d021768e7359f9aad6b329cba883da20","analyzedAt":"2026-09-01T19:19:23.111Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}