{"record":{"id":"7c0f91a98b96bdee","repo":"santifer/career-ops","slug":"nofluffjobs-url-must-use-https-url","errorCode":null,"errorMessage":"nofluffjobs: URL must use HTTPS: ${url}","messagePattern":"nofluffjobs: URL must use HTTPS: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/nofluffjobs.mjs","lineNumber":21,"sourceCode":"\n// NoFluffJobs provider — hits the public search posting API.\n// It intentionally returns only the core scanner job fields; richer skill and\n// salary metadata can be added later if the provider contract is expanded.\n\nconst ALLOWED_HOSTS = new Set(['nofluffjobs.com']);\nconst API_URL = 'https://nofluffjobs.com/api/search/posting';\nconst JOB_BASE = 'https://nofluffjobs.com/pl/job/';\nconst PAGE_SIZE = 20;\nconst MAX_PAGES = 5;\n\nfunction assertNoFluffUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`nofluffjobs: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`nofluffjobs: URL must use HTTPS: ${url}`);\n  if (!ALLOWED_HOSTS.has(parsed.hostname)) {\n    throw new Error(`nofluffjobs: untrusted hostname \"${parsed.hostname}\" — must be nofluffjobs.com`);\n  }\n  return parsed;\n}\n\nfunction detectUrl(entry) {\n  const url = entry.api || entry.careers_url || '';\n  if (typeof url !== 'string' || !url.trim()) return null;\n  try {\n    return { url: assertNoFluffUrl(url).href };\n  } catch {\n    return null;\n  }\n}\n\nfunction normalizeLocation(posting) {\n  const parts = [];","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/providers/nofluffjobs.mjs#L3-L39","documentation":"assertNoFluffUrl requires the HTTPS protocol. If the URL parses but parsed.protocol !== 'https:', this error is thrown. The provider refuses plain-http (or other-scheme) endpoints so that all API traffic to NoFluffJobs is encrypted.","triggerScenarios":"Passing 'http://nofluffjobs.com/...' or any non-https scheme (ftp:, file:, ws:) into the nofluffjobs provider's detect/fetch path or directly into assertNoFluffUrl.","commonSituations":"Old config entries written before the site enforced HTTPS; a URL copied from an insecure redirect or HTTP log line; hand-built URLs defaulting to http; documentation examples using http.","solutions":["Update the URL's scheme to https:// in the config or calling code","If the value comes from user/env input, normalize it (prepend https:// when a scheme is absent, reject http explicitly)","Migrate stored http:// bookmarks/links to https once, at config-load time","Keep the check enabled; do not work around it with a lower-level fetch"],"exampleFix":"// before\nassertNoFluffUrl('http://nofluffjobs.com/api/postings');\n// after\nassertNoFluffUrl('https://nofluffjobs.com/api/postings');","handlingStrategy":"validation","validationCode":"const parsed = new URL(url);\nif (parsed.protocol !== 'https:') throw new Error(`nofluffjobs requires https: ${url}`);","typeGuard":"function isHttpsUrl(u) {\n  try { return new URL(u).protocol === 'https:'; } catch { return false; }\n}","tryCatchPattern":"try {\n  await nofluffjobs.fetch(entry, ctx);\n} catch (e) {\n  if (String(e.message).startsWith('nofluffjobs: URL must use HTTPS')) {\n    entry.careers_url = entry.careers_url.replace(/^http:/, 'https:');\n    return nofluffjobs.fetch(entry, ctx);\n  }\n  throw e;\n}","preventionTips":["Add a config-load step that rewrites or rejects http:// NoFluffJobs links","Keep a lint rule in CI banning http:// in provider config files","Document the https requirement next to the config schema","Test new entries with a quick parse+protocol check before a full scan"],"tags":["url-validation","https","security"],"backgroundTag":"invalid-url","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"}