{"record":{"id":"69aedb9b0ea042a9","repo":"santifer/career-ops","slug":"comeet-url-must-use-https-redacttoken-url","errorCode":null,"errorMessage":"comeet: URL must use HTTPS: ${redactToken(url)}","messagePattern":"comeet: URL must use HTTPS: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"providers/comeet.mjs","lineNumber":36,"sourceCode":"  if (typeof raw !== 'string' || !raw) return false;\n  let parsed;\n  try {\n    parsed = new URL(raw);\n  } 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  }","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/providers/comeet.mjs#L18-L54","documentation":"assertComeetUrl enforces HTTPS because the Comeet careers-api carries a per-tenant token in the query string and the scanner refuses to send credentials over plaintext. Any URL whose parsed protocol is not 'https:' (http:, ftp:, etc.) is rejected with this error, token redacted in the message.","triggerScenarios":"fetch() resolves an entry whose api or careers_url is a valid URL string with an explicit http: (or other non-https) scheme — isComeetApiUrl already rejects those, so this surfaces when the guard is bypassed, the entry is mutated between detect and fetch, or assertComeetUrl is invoked directly on http input.","commonSituations":"Copying the API URL from an old doc that used http://; writing the URL into portals.yml without the s; a config transform downgrading the scheme; testing against a local http mock by pointing the entry at it.","solutions":["Change the scheme to https:// in the entry's api/careers_url","Verify Comeet's endpoint is served over HTTPS (it is: www.comeet.co) — there is no legitimate http variant","If testing locally, use an https-capable mock or extend the provider's host allowlist consciously rather than downgrading the scheme","Grep portals.yml for 'http://' to catch all downgraded entries at once"],"exampleFix":"// before\napi: http://www.comeet.co/careers-api/2.0/company/acme/positions?token=abc\n// after\napi: https://www.comeet.co/careers-api/2.0/company/acme/positions?token=abc","handlingStrategy":"validation","validationCode":"function isHttpsUrl(raw) {\n  try { return new URL(raw).protocol === 'https:'; } catch { return false; }\n}\nif (!isHttpsUrl(entry.api)) throw new Error(`entry ${entry.name}: comeet api must be https`);","typeGuard":"function isHttpsUrlString(raw) {\n  if (typeof raw !== 'string') return false;\n  try { return new URL(raw).protocol === 'https:'; } catch { return false; }\n}","tryCatchPattern":"try {\n  assertComeetUrl(entry.api);\n} catch (err) {\n  if (String(err.message).includes('must use HTTPS')) {\n    logger.error({entry: entry.name}, 'downgrade the scheme to https:// — comeet tokens must not travel over http');\n  } else throw err;\n}","preventionTips":["Treat HTTPS as non-negotiable for any URL carrying a ?token= credential","Grep config for /^http:\\/\\// when onboarding entries","Never point provider entries at local http mocks in shared config — use a test fixture instead","Add a CI lint that rejects non-https api:/careers_url: values"],"tags":["security","https","url","config"],"backgroundTag":"invalid-url-format","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}