{"record":{"id":"7405196bbeb7efe4","repo":"santifer/career-ops","slug":"himalayas-url-must-use-https-url","errorCode":null,"errorMessage":"himalayas: URL must use HTTPS: ${url}","messagePattern":"himalayas: URL must use HTTPS: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/himalayas.mjs","lineNumber":22,"sourceCode":"// Himalayas provider - board-wide remote jobs API\n// (https://himalayas.app/jobs/api?limit=50). Returns { jobs: [...] }. The\n// full feed is fetched so scan.mjs's title_filter / location_filter can do\n// the local gating consistently with other zero-token board providers.\n//\n// Wire in via a `job_boards:` entry with `provider: himalayas`.\n\nconst FEED_URL = 'https://himalayas.app/jobs/api?limit=50';\nconst TRUSTED_HOST = 'himalayas.app';\n\n/** @param {string} url */\nfunction assertHimalayasUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`himalayas: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`himalayas: URL must use HTTPS: ${url}`);\n  if (parsed.hostname !== TRUSTED_HOST) {\n    throw new Error(`himalayas: untrusted hostname \"${parsed.hostname}\" - must be ${TRUSTED_HOST}`);\n  }\n  return url;\n}\n\nfunction cleanText(value) {\n  return typeof value === 'string' ? value.trim() : '';\n}\n\nfunction cleanHimalayasUrl(value) {\n  const raw = cleanText(value);\n  if (!raw) return '';\n  try {\n    const parsed = new URL(raw);\n    const host = parsed.hostname.toLowerCase();\n    const trusted = host === TRUSTED_HOST || host.endsWith(`.${TRUSTED_HOST}`);\n    return parsed.protocol === 'https:' && trusted ? parsed.href : '';","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/providers/himalayas.mjs#L4-L40","documentation":"URL scheme guard in the Himalayas board provider (assertHimalayasUrl): the parsed URL's protocol is not https:. The URL is syntactically valid but not HTTPS, and the provider only fetches the trusted himalayas.app feed over TLS. The input at fault is the URL handed to the provider (typically careers_url in portals.yml).","triggerScenarios":"A configured feed URL using http:// instead of https://, or a URL built by concatenating an http base with the API path.","commonSituations":"Old bookmarks/docs with http links, local dev proxies configured with http://, or string-built URLs where the scheme came from an untrusted default.","solutions":["Change the URL scheme to https:// in the config or code that builds it.","Hardcode https: in any URL-building helper rather than inheriting the input scheme.","Lint config at load time to reject non-https URLs for this provider.","Use the provider's FEED_URL constant instead of a hand-written URL."],"exampleFix":"// before\nconst feed = 'http://himalayas.app/jobs/api?limit=50';\n// after\nconst feed = 'https://himalayas.app/jobs/api?limit=50';","handlingStrategy":"validation","validationCode":"function isHttpsHimalayasUrl(url) {\n  try { return new URL(url).protocol === 'https:' && new URL(url).hostname === 'himalayas.app'; } catch { return false; }\n}","typeGuard":"const isHttpsUrl = (s) => { try { return new URL(s).protocol === 'https:'; } catch { return false; } };","tryCatchPattern":"try {\n  await provider.fetch(entry, ctx);\n} catch (err) {\n  if (/himalayas: URL must use HTTPS/.test(err.message)) {\n    console.error(`Switch himalayas feed to https: ${err.message}`);\n    return;\n  }\n  throw err;\n}","preventionTips":["Always use https:// for himalayas.app URLs.","Prefer the FEED_URL constant over custom URLs.","Add a config lint rejecting non-https provider URLs.","Never build the URL by concatenating an http base."],"tags":["url","https","security","himalayas"],"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"}