{"record":{"id":"706a33e383a14ad8","repo":"santifer/career-ops","slug":"lever-url-must-use-https-url","errorCode":null,"errorMessage":"lever: URL must use HTTPS: ${url}","messagePattern":"lever: URL must use HTTPS: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/lever.mjs","lineNumber":18,"sourceCode":"// @ts-check\n/** @typedef {import('./_types.js').Provider} Provider */\n\n// Lever provider — hits the public postings endpoint.\n// Auto-detects from careers_url via jobs.(eu.)?lever.co/<slug>.\n// Handles both explicit `api:` URLs and auto-detection from `careers_url`.\n\nconst ALLOWED_LEVER_HOSTS = new Set(['api.lever.co', 'api.eu.lever.co']);\n\n/** @param {string} url */\nfunction assertLeverUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`lever: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`lever: URL must use HTTPS: ${url}`);\n  if (!ALLOWED_LEVER_HOSTS.has(parsed.hostname))\n    throw new Error(`lever: untrusted hostname \"${parsed.hostname}\" — must be one of: ${[...ALLOWED_LEVER_HOSTS].join(', ')}`);\n  return url;\n}\n\n/** @param {import('./_types.js').PortalEntry} entry */\nfunction resolveApiUrl(entry) {\n  // Explicit api: wins — lets an entry keep a human-facing corporate\n  // careers_url (e.g. https://www.coalfire.com/careers) while still pinning\n  // the Lever postings board (mirrors greenhouse's api: precedence).\n  if (entry.api) {\n    assertLeverUrl(entry.api);\n    return entry.api;\n  }\n  let url;\n  try {\n    url = new URL(entry.careers_url || '');\n  } catch {","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/lever.mjs#L1-L36","documentation":"Second guard in assertLeverUrl: after a successful parse, parsed.protocol must be 'https:'. Any non-HTTPS scheme is rejected to enforce TLS on the Lever API call.","triggerScenarios":"The URL parses but uses http://, ftp://, file://, or another non-https scheme — most often a plain-http api: or careers_url in portals.yml.","commonSituations":"A legacy config uses http://api.lever.co; a test fixture was written over HTTP; the careers_url was copied from a non-TLS source.","solutions":["Switch the scheme to https:// (Lever's API is HTTPS-only).","Verify with curl https://api.lever.co/v0/postings/<slug>.","Update any templated URL builder to emit https://."],"exampleFix":"// before\napi: http://api.lever.co/v0/postings/acme\n\n// after\napi: https://api.lever.co/v0/postings/acme","handlingStrategy":"validation","validationCode":"import { URL } from 'node:url';\nexport function isHttpsUrl(value) {\n  try { return new URL(value).protocol === 'https:'; } catch { return false; }\n}","typeGuard":"/** @param {string} url */\nfunction isHttps(url) {\n  try { return new URL(url).protocol === 'https:'; } catch { return false; }\n}","tryCatchPattern":"try {\n  assertLeverUrl(url);\n} catch (err) {\n  if (err.message.includes('HTTPS')) console.warn(`refusing non-HTTPS lever URL: ${url}`);\n  throw err;\n}","preventionTips":["Always use https:// for api.lever.co / api.eu.lever.co.","Lint portals.yml to reject http:// on lever entries.","Avoid constructing lever URLs from untrusted input without forcing https."],"tags":["url-validation","https","transport-security","lever"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}