{"record":{"id":"1c52a8e34844ec00","repo":"santifer/career-ops","slug":"workable-url-must-use-https-url","errorCode":null,"errorMessage":"workable: URL must use HTTPS: ${url}","messagePattern":"workable: URL must use HTTPS: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/workable.mjs","lineNumber":116,"sourceCode":"\n// Process-wide serialization: apply.workable.com fronts every tenant on the\n// same host, so this process never needs more than one in-flight request to\n// it at a time.\nlet workableQueue = Promise.resolve();\nfunction serialized(fn) {\n  const result = workableQueue.then(fn, fn);\n  workableQueue = result.then(() => undefined, () => undefined);\n  return result;\n}\n\nfunction assertWorkableUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`workable: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`workable: URL must use HTTPS: ${url}`);\n  if (!ALLOWED_WORKABLE_HOSTS.has(parsed.hostname)) {\n    throw new Error(`workable: untrusted hostname \"${parsed.hostname}\" — must be one of: ${[...ALLOWED_WORKABLE_HOSTS].join(', ')}`);\n  }\n  return url;\n}\n\n/**\n * Extract the account slug from a tracked_companies entry's careers_url.\n * @returns {string|null}\n */\nexport function resolveWorkableSlug(entry) {\n  const raw = entry && typeof entry.careers_url === 'string' ? entry.careers_url : '';\n  if (!raw) return null;\n  let parsed;\n  try {\n    parsed = new URL(raw);\n  } catch {\n    return null;","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/workable.mjs#L98-L134","documentation":"SSRF guard: the URL parsed but its protocol is not https. Built Workable URLs always use https, so this only fires if a maintainer edits widgetUrlFor/feedUrlFor to an http URL.","triggerScenarios":"A maintainer sets a Workable URL template to http:// during debugging and forgets to revert; a bad merge.","commonSituations":"Debugging change not reverted; bad merge.","solutions":["Restore https in widgetUrlFor and feedUrlFor."],"exampleFix":"// before\nconst feedUrlFor = (slug) => `http://apply.workable.com/${slug}/jobs.md`;\n// after\nconst feedUrlFor = (slug) => `https://apply.workable.com/${slug}/jobs.md`;","handlingStrategy":"validation","validationCode":"for (const tpl of [widgetUrlFor, feedUrlFor]) {\n  const u = new URL(tpl(\"acme\"));\n  if (u.protocol !== \"https:\") throw new Error(\"workable: template must be https\");\n}","typeGuard":"const isHttps = (s) => { try { return new URL(s).protocol === \"https:\"; } catch { return false; } };","tryCatchPattern":null,"preventionTips":["Treat the https requirement as load-bearing for SSRF safety — do not relax it.","CI lint that flags http:// literals in providers/."],"tags":["validation","url","ssrf-guard","https","workable","invariant"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}