{"record":{"id":"cec5174de6ec26ae","repo":"santifer/career-ops","slug":"oraclecloud-url-must-use-https-url","errorCode":null,"errorMessage":"oraclecloud: URL must use HTTPS: ${url}","messagePattern":"oraclecloud: URL must use HTTPS: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/oraclecloud.mjs","lineNumber":68,"sourceCode":"const ORACLE_HOST_RE = /^[a-z0-9-]+\\.fa\\.(?:[a-z0-9-]+\\.)?(?:ocs\\.)?oraclecloud(?:[1-9][0-9]?)?\\.com$/i;\n\nconst PAGE_SIZE = 200;\nconst MAX_PAGES = 25;             // safety cap (~5000 jobs); hard ceiling like workday\nconst RETRY_POLICY = { retries: 3 };\nconst INTER_PAGE_DELAY_MS = 150;  // WAF-aware spacing between same-host pages\n\n// facetsList is a fixed constant on the finder; %3B is the encoded ';' separator.\nconst FACETS_LIST = 'LOCATIONS%3BWORK_LOCATIONS%3BWORKPLACE_TYPES%3BTITLES%3BCATEGORIES%3BORGANIZATIONS%3BPOSTING_DATES%3BFLEX_FIELDS';\n\n/** @param {string} url */\nfunction assertOracleUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`oraclecloud: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`oraclecloud: URL must use HTTPS: ${url}`);\n  if (!ORACLE_HOST_RE.test(parsed.hostname)) {\n    throw new Error(`oraclecloud: untrusted hostname \"${parsed.hostname}\" — must match *.fa[.<region>][.ocs].oraclecloud[1-99].com`);\n  }\n  return url;\n}\n\n// NaN-safe Date.parse — `|| undefined` would also coerce a valid epoch 0.\n// (copied from greenhouse.mjs)\nfunction toEpochMs(value) {\n  if (!value) return undefined;\n  const parsed = Date.parse(value);\n  return Number.isNaN(parsed) ? undefined : parsed;\n}\n\nfunction sleep(ms, ctx) {\n  if (typeof ctx?.sleep === 'function') return ctx.sleep(ms);\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/oraclecloud.mjs#L50-L86","documentation":"Thrown by oraclecloud's assertOracleUrl() when the URL parses but protocol is not 'https:'. Second SSRF gate: blocks plaintext HTTP to Oracle career sites, preventing MITM and redirect-based exfiltration. Fires before each page fetch in the pagination loop.","triggerScenarios":"A valid URL with http: scheme passed to assertOracleUrl. Sources: entry.api or entry.careers_url in portals.yml prefixed http://, or a test fixture using http://localhost. Since buildApiUrl constructs URLs from entry data, an http:// entry propagates through resolveSite → buildApiUrl → assertOracleUrl.","commonSituations":"YAML config authored with http://. A config tool that strips SSL. Local development against a non-TLS mock. Oracle tenant URLs copied before SSL enforcement.","solutions":["Change the entry's api/careers_url to https:// in portals.yml.","For testing, use an HTTPS mock or a test-specific guard bypass.","Verify no intermediary normalizes the URL to http://."],"exampleFix":"// before\ncareers_url: 'http://acme.fa.eu.oraclecloud.com/hcmUI/CandidateExperience/en/sites/CX_1'\n\n// after\ncareers_url: 'https://acme.fa.eu.oraclecloud.com/hcmUI/CandidateExperience/en/sites/CX_1'","handlingStrategy":"validation","validationCode":"/** Normalize Oracle URL to HTTPS. */\nfunction ensureHttps(url) {\n  if (typeof url !== 'string') return null;\n  return url.replace(/^http:\\/\\//i, 'https://');\n}\n\nentry.careers_url = ensureHttps(entry.careers_url) || entry.careers_url;","typeGuard":"/** @param {string} url @returns {boolean} */\nfunction isHttpsUrl(url) {\n  try { return new URL(url).protocol === 'https:'; } catch { return false; }\n}","tryCatchPattern":"try {\n  await oracleProvider.fetch(entry, ctx);\n} catch (err) {\n  if (String(err.message).includes('must use HTTPS')) {\n    entry.careers_url = (entry.careers_url || '').replace(/^http:/i, 'https:');\n    await oracleProvider.fetch(entry, ctx);\n  } else throw err;\n}","preventionTips":["Author Oracle career URLs with https:// in config.","Lint config for http:// entries.","Use HTTPS mock servers in tests."],"tags":["url-validation","ssrf-guard","https","oraclecloud","config"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}