{"record":{"id":"2ad962a92430a95f","repo":"santifer/career-ops","slug":"remotli-url-must-use-https-url","errorCode":null,"errorMessage":"remotli: URL must use HTTPS: ${url}","messagePattern":"remotli: URL must use HTTPS: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/remotli.mjs","lineNumber":240,"sourceCode":"\n  const postedAt = toEpochMs(job.publishedAt || job.createdAt);\n  if (postedAt !== undefined) out.postedAt = postedAt;\n\n  const salary = resolveSalary(job);\n  if (salary) out.salary = salary;\n\n  return out;\n}\n\n/** Guard the API URL: HTTPS + remotli.ch only. */\nfunction assertRemotliUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`remotli: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`remotli: URL must use HTTPS: ${url}`);\n  if (!HOST_RE.test(parsed.hostname))\n    throw new Error(`remotli: untrusted hostname \"${parsed.hostname}\" — must be remotli.ch`);\n  return url;\n}\n\n/** @type {Provider} */\nexport default {\n  id: 'remotli',\n\n  detect(entry) {\n    const raw = 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;\n    }","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/remotli.mjs#L222-L258","documentation":"assertRemotliUrl rejects any URL whose protocol is not 'https:'. remotli pins every request to remotli.ch over TLS, so an http: scheme is treated as a hard error. Because remotli builds URLs from constants, an http ORIGIN or an externally-supplied http URL would trip this.","triggerScenarios":"ORIGIN constant was set to 'http://remotli.ch'; a URL string passed in starts with http://; the hostname resolves but the scheme is cleartext.","commonSituations":"The ORIGIN constant was misconfigured during local development or testing; a config override switched to http.","solutions":["Ensure ORIGIN is 'https://remotli.ch'.","If a URL was supplied externally, upgrade it: url.replace(/^http:/, 'https:').","Search the codebase for any http://remotli reference and replace with https://."],"exampleFix":"// before\nconst ORIGIN = 'http://remotli.ch';\n// after\nconst ORIGIN = 'https://remotli.ch';","handlingStrategy":"validation","validationCode":"function ensureHttps(raw) {\n  return typeof raw === 'string' ? raw.replace(/^http:\\/\\//i, 'https://') : raw;\n}\nconst ORIGIN = ensureHttps('https://remotli.ch'); // guard against config drift","typeGuard":"null","tryCatchPattern":"try {\n  await provider.fetch(entry, ctx);\n} catch (e) {\n  if (/must use HTTPS/.test(e.message)) {\n    console.error('[bug] remotli ORIGIN is http — fix the constant');\n  } else throw e;\n}","preventionTips":["Pin ORIGIN to 'https://remotli.ch' as a constant — do not make it configurable.","Add a CI check that ORIGIN starts with https://.","Never accept http board URLs from external input."],"tags":["url-validation","https","provider","remotli","security"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}