{"record":{"id":"7e5d40f7e3681aba","repo":"paperclipai/paperclip","slug":"invalid-published-report-url","errorCode":null,"errorMessage":"Invalid published report URL","messagePattern":"Invalid published report URL","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/scripts/publish-runner-protocol-eval-history.mjs","lineNumber":558,"sourceCode":"    index,\n    \"no-cache\",\n  );\n  return {\n    campaignId: campaign.campaignId,\n    bundleDigest: manifest.bundleDigest,\n    historySize: history.campaigns.length,\n    reportUrl: `${validatedDestination.publicBaseUrl}/${campaignPrefix}/index.html`,\n    historyUrl: `${validatedDestination.publicBaseUrl}/${validatedDestination.prefix}/index.html`,\n  };\n}\n\nexport async function writeProtocolEvalPublicationLinks(result, environment = process.env) {\n  const { campaignId, reportUrl, historyUrl } = result;\n  if (!SAFE_CAMPAIGN.test(campaignId)) throw new Error(\"Invalid published campaign ID\");\n  const safeUrl = (value) => {\n    const url = new URL(value);\n    if (url.protocol !== \"https:\" || url.username || url.password || /[\\r\\n<>]/.test(value))\n      throw new Error(\"Invalid published report URL\");\n    return url.href;\n  };\n  const report = safeUrl(reportUrl);\n  const history = safeUrl(historyUrl);\n  if (environment.GITHUB_OUTPUT)\n    await appendFile(environment.GITHUB_OUTPUT, `report_url=${report}\\nhistory_url=${history}\\n`);\n  if (environment.GITHUB_STEP_SUMMARY)\n    await appendFile(environment.GITHUB_STEP_SUMMARY, `## Published Runner Evalbook\\n\\n[Open this run's Evalbook](<${report}>) · [All eval runs](<${history}>)\\n\\nCampaign: \\`${campaignId}\\`\\n\\nPublic replay uses the Runner Lab theme; full evidence is in the workflow artifact.\\n`);\n}\n\nasync function main() {\n  const result = await publishProtocolEvalHistory({\n    viewerRoot: process.env.PAPERCLIP_RUNNER_PROTOCOL_EVAL_VIEWER_DIR,\n    reportRoot: resolve(\n      process.env.PAPERCLIP_RUNNER_PROTOCOL_EVAL_PUBLIC_REPORT_DIR ??\n        \"runner-protocol-eval-public-report\",\n    ),\n    destination: {","sourceCodeStart":540,"sourceCodeEnd":576,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/scripts/publish-runner-protocol-eval-history.mjs#L540-L576","documentation":"The safeUrl helper inside writeProtocolEvalPublicationLinks validates that report and history links are absolute https URLs without embedded credentials or control/HTML characters, then re-emits a normalized href. This error means one of the URLs to publish failed that check, so the script stops rather than emitting a potentially unsafe link into GitHub Actions outputs.","triggerScenarios":"Passing reportUrl or historyUrl that is http: (not https), includes user:pass@ credentials, is not a parseable URL, or contains \\r, \\n, '<', or '>' characters.","commonSituations":"Local dev publishes an http://localhost link; a report path is passed instead of a full URL; a URL got built by string concatenation including newlines; a misconfigured base URL (publicBaseUrl) is http.","solutions":["Ensure the published site base URL uses https (fix publicBaseUrl/prefix configuration)","Pass complete absolute URLs, not relative paths, for reportUrl/historyUrl","Strip whitespace/control characters from the URL before calling","Verify no credentials are embedded in the URL (use env-based auth instead)"],"exampleFix":"// before\nconst reportUrl = 'http://example.com/report.html';\n// after\nconst reportUrl = 'https://example.com/report.html';","handlingStrategy":"validation","validationCode":"const u = new URL(reportUrl); if (u.protocol !== 'https:' || u.username || u.password) throw new Error('reportUrl must be credentialess https');","typeGuard":"const isSafeHttpsUrl = (v) => { try { const u = new URL(v); return u.protocol === 'https:' && !u.username && !u.password && !/[\\r\\n<>]/.test(v); } catch { return false; } };","tryCatchPattern":"try { await writeProtocolEvalPublicationLinks(result); } catch (e) { if (e.message === 'Invalid published report URL') console.error('Check reportUrl/historyUrl:', result.reportUrl, result.historyUrl); throw e; }","preventionTips":["Always use https base URLs for published sites","Build URLs with the URL API, not string concatenation","Keep credentials out of URLs"],"tags":["url-validation","https","security"],"backgroundTag":"invalid-url-format","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}