{"record":{"id":"1d07f3fa4bacb17b","repo":"santifer/career-ops","slug":"comeet-url-path-must-be-the-careers-api-endpoint","errorCode":null,"errorMessage":"comeet: URL path must be the careers-api endpoint: ${redactToken(url)}","messagePattern":"comeet: URL path must be the careers-api endpoint: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"providers/comeet.mjs","lineNumber":40,"sourceCode":"  } catch {\n    return false;\n  }\n  return parsed.protocol === 'https:' && parsed.hostname === COMEET_API_HOST && parsed.pathname.startsWith('/careers-api/');\n}\n\n/** @param {string} url */\nfunction assertComeetUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`comeet: invalid URL: ${redactToken(url)}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`comeet: URL must use HTTPS: ${redactToken(url)}`);\n  if (parsed.hostname !== COMEET_API_HOST)\n    throw new Error(`comeet: untrusted hostname \"${parsed.hostname}\" — must be ${COMEET_API_HOST}`);\n  if (!parsed.pathname.startsWith('/careers-api/'))\n    throw new Error(`comeet: URL path must be the careers-api endpoint: ${redactToken(url)}`);\n  return url;\n}\n\n// Redact the per-tenant ?token= so neither the (informational, possibly-logged)\n// DetectHit url nor a thrown validation error carries the secret. Best-effort:\n// falls back to a regex strip when the value can't be parsed as a URL.\nfunction redactToken(url) {\n  try {\n    const parsed = new URL(url);\n    if (parsed.searchParams.has('token')) parsed.searchParams.set('token', 'REDACTED');\n    return parsed.href;\n  } catch {\n    return typeof url === 'string' ? url.replace(/([?&]token=)[^&#]*/gi, '$1REDACTED') : url;\n  }\n}\n\n/** @param {import('./_types.js').PortalEntry} entry */\nfunction resolveApiUrl(entry) {","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/comeet.mjs#L22-L58","documentation":"Thrown by comeet's assertComeetUrl when the URL is valid https on www.comeet.co but its pathname does not start with /careers-api/. The path prefix check complements the hostname pin so a URL on the API host but outside the careers endpoint cannot be driven. Defense-in-depth: resolveApiUrl's isComeetApiUrl applies the same startsWith('/careers-api/') check and returns null (→ error 165) first, so fetch() surfaces 165. Reachable via a direct assertComeetUrl call.","triggerScenarios":"assertComeetUrl is called directly with an https://www.comeet.co/... URL whose path is not under /careers-api/ (e.g. a marketing page or a different API version path). Through fetch(), the same input fails isComeetApiUrl and reports as error 165.","commonSituations":"Using a Comeet URL that is on the right host but is not the positions endpoint; a direct test against a stub path; an entry whose api: was copied from a non-careers-api Comeet page.","solutions":["For direct calls, use the full positions URL: https://www.comeet.co/careers-api/2.0/company/<uid>/positions?token=<token>.","For fetch() use, set entry.api to that full positions URL (this shows as 165, same fix).","Copy the URL from Comeet's careers-API documentation, not from the browser address bar of the branded jobs page."],"exampleFix":"// before — right host, wrong path\nassertComeetUrl('https://www.comeet.co/jobs/abc');\n\n// after — careers-api positions endpoint\nassertComeetUrl('https://www.comeet.co/careers-api/2.0/company/abc/positions?token=TOKEN');","handlingStrategy":"validation","validationCode":"function isComeetCareersApiPath(u) {\n  try { return new URL(u).pathname.startsWith('/careers-api/'); } catch { return false; }\n}","typeGuard":"function isComeetPositionsUrl(u) {\n  if (typeof u !== 'string' || !u) return false;\n  try {\n    const p = new URL(u);\n    return p.protocol === 'https:' && p.hostname === 'www.comeet.co' && p.pathname.startsWith('/careers-api/');\n  } catch { return false; }\n}","tryCatchPattern":"try { assertComeetUrl(url); }\ncatch (e) {\n  if (/^comeet: URL path must be the careers-api endpoint/.test(e.message)) { /* not the positions endpoint — skip */ }\n  else throw e;\n}","preventionTips":["Copy the full positions URL from Comeet's careers-API docs.","Ensure the path is under /careers-api/ (the branded /jobs/ page is not).","Through fetch() this is pre-empted by 165."],"tags":["url-validation","comeet","ssrf","path-validation","defense-in-depth"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}