Restrict job log links to http(s) URLs

This commit is contained in:
Rūdolfs Ošiņš
2026-05-28 16:16:41 +02:00
parent 74b3c079ad
commit 747d9b05f9
2 changed files with 24 additions and 15 deletions
+12 -15
View File
@@ -24,6 +24,8 @@
</script>
<script lang="ts">
import { safeHttpUrl } from "@app/lib/utils";
import Button from "@app/components/Button.svelte";
import Icon from "@app/components/Icon.svelte";
import Loading from "@app/components/Loading.svelte";
@@ -42,7 +44,7 @@
type RunView = {
run: Run;
label: string;
linkable: boolean;
safeLog: string | undefined;
};
type HostGroup = {
@@ -73,13 +75,6 @@
}
}
function isLinkable(url: URL | undefined): boolean {
if (!url) return false;
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
if (url.host === "no.url.example.com") return false;
return true;
}
function runLabel(run: Run, url: URL | undefined): string {
if (url && url.host === "github.com") {
const m = url.pathname.match(/\/actions\/runs\/(\d+)/);
@@ -134,10 +129,12 @@
for (const run of job.runs) {
const url = parseUrl(run.log);
const host = url && url.host ? url.host : "(unknown host)";
const safeLog =
url?.host !== "no.url.example.com" ? safeHttpUrl(run.log) : undefined;
const view: RunView = {
run,
label: runLabel(run, url),
linkable: isLinkable(url),
safeLog,
};
const key = run.node.id;
let entry = byNode[key];
@@ -375,12 +372,12 @@
{#if !isCollapsed}
{#if group.flatRuns}
{#each group.flatRuns as view (view.run.runId)}
{#if view.linkable}
{#if view.safeLog}
<a
class="row run-row"
href={view.run.log}
href={view.safeLog}
target="_blank"
rel="noreferrer">
rel="noopener noreferrer">
<span class="chip {view.run.status}">
{#if view.run.status === "succeeded"}
<Icon name="checkmark" />
@@ -419,12 +416,12 @@
{#each group.hosts as host}
<div class="row host-row"><span>{host.host}</span></div>
{#each host.runs as view (view.run.runId)}
{#if view.linkable}
{#if view.safeLog}
<a
class="row run-row"
href={view.run.log}
href={view.safeLog}
target="_blank"
rel="noreferrer">
rel="noopener noreferrer">
<span class="chip {view.run.status}">
{#if view.run.status === "succeeded"}
<Icon name="checkmark" />
+12
View File
@@ -224,6 +224,18 @@ export function isOnion(addr: string): boolean {
return addr.endsWith(".onion");
}
export function safeHttpUrl(url: string): string | undefined {
try {
const parsed = new URL(url);
if (parsed.protocol === "http:" || parsed.protocol === "https:") {
return parsed.toString();
}
} catch {
// fall through
}
return undefined;
}
// Get the gravatar URL of an email.
export function gravatarURL(email: string): string {
const address = email.trim().toLowerCase();