mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-05-01 13:35:46 +00:00
108 lines
6.4 KiB
HTML
108 lines
6.4 KiB
HTML
{{ define "diff" }}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
{{ template "head" . }}
|
|
{{ template "meta" .Meta }}
|
|
</head>
|
|
<body>
|
|
{{ template "nav" . }}
|
|
|
|
<main id="main-content" class="container mx-auto px-4 py-8">
|
|
<div class="space-y-6">
|
|
<!-- Breadcrumb -->
|
|
<div class="text-sm breadcrumbs">
|
|
<ul>
|
|
<li><a href="/u/{{ .Owner.Handle }}" class="link link-primary">{{ .Owner.Handle }}</a></li>
|
|
<li><a href="/r/{{ .Owner.Handle }}/{{ .Repository }}" class="link link-primary">{{ .Repository }}</a></li>
|
|
<li>Comparing {{ .FromTag }} to {{ .ToTag }}</li>
|
|
</ul>
|
|
</div>
|
|
|
|
{{ if or .FromFailed .ToFailed }}
|
|
{{ template "alert" (dict "Type" "warning" "Message" (printf "We couldn't fetch details for %s%s%s. Showing what we have." (or (and .FromFailed .FromTag) "") (or (and .FromFailed .ToFailed) " and ") (or (and .ToFailed .ToTag) ""))) }}
|
|
{{ end }}
|
|
|
|
{{ if and (not .FromFailed) (not .ToFailed) (eq .FromDigest .ToDigest) }}
|
|
{{ template "alert" (dict "Type" "info" "Message" "These manifests are identical. No layers or vulnerabilities changed.") }}
|
|
{{ end }}
|
|
|
|
<!-- Summary Card -->
|
|
<div class="card bg-base-200 shadow-sm border border-base-300 p-6">
|
|
<div class="flex flex-wrap items-center gap-2 mb-4">
|
|
<h1 class="text-xl font-bold wrap-break-word min-w-0">
|
|
<span class="whitespace-nowrap">
|
|
<span class="font-mono inline-block align-baseline max-w-[24ch] truncate" title="{{ .FromTag }}">{{ .FromTag }}</span>
|
|
<span class="text-base-content/40 mx-1" aria-hidden="true">→</span>
|
|
</span>
|
|
<span class="font-mono inline-block align-baseline max-w-[24ch] truncate" title="{{ .ToTag }}">{{ .ToTag }}</span>
|
|
</h1>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap gap-4">
|
|
<!-- Size delta -->
|
|
<div class="stat bg-base-200/50 rounded-lg p-3">
|
|
<div class="stat-title text-xs">Size</div>
|
|
<div class="stat-value text-sm">{{ humanizeByteDelta .Summary.SizeDelta }}</div>
|
|
</div>
|
|
|
|
<!-- Layer count -->
|
|
<div class="stat bg-base-200/50 rounded-lg p-3">
|
|
<div class="stat-title text-xs">Layers</div>
|
|
<div class="stat-value text-sm">{{ .Summary.LayerCountFrom }} → {{ .Summary.LayerCountTo }}</div>
|
|
</div>
|
|
|
|
{{ if .HasVulnData }}
|
|
<!-- Vulns fixed -->
|
|
{{ if gt .Summary.VulnFixedCount 0 }}
|
|
<div class="stat bg-success/10 rounded-lg p-3">
|
|
<div class="stat-title text-xs">Fixed</div>
|
|
<div class="stat-value text-sm text-success">-{{ .Summary.VulnFixedCount }} {{ pluralize .Summary.VulnFixedCount "vuln" "vulns" }}</div>
|
|
<div class="stat-desc text-xs">
|
|
{{ if gt .Summary.VulnFixedBySev.Critical 0 }}{{ .Summary.VulnFixedBySev.Critical }}<span class="sr-only"> Critical</span><span aria-hidden="true">C</span> {{ end }}
|
|
{{ if gt .Summary.VulnFixedBySev.High 0 }}{{ .Summary.VulnFixedBySev.High }}<span class="sr-only"> High</span><span aria-hidden="true">H</span> {{ end }}
|
|
{{ if gt .Summary.VulnFixedBySev.Medium 0 }}{{ .Summary.VulnFixedBySev.Medium }}<span class="sr-only"> Medium</span><span aria-hidden="true">M</span> {{ end }}
|
|
{{ if gt .Summary.VulnFixedBySev.Low 0 }}{{ .Summary.VulnFixedBySev.Low }}<span class="sr-only"> Low</span><span aria-hidden="true">L</span>{{ end }}
|
|
</div>
|
|
</div>
|
|
{{ end }}
|
|
|
|
<!-- Vulns new -->
|
|
{{ if gt .Summary.VulnNewCount 0 }}
|
|
<div class="stat bg-error/10 rounded-lg p-3">
|
|
<div class="stat-title text-xs">New</div>
|
|
<div class="stat-value text-sm text-error">+{{ .Summary.VulnNewCount }} {{ pluralize .Summary.VulnNewCount "vuln" "vulns" }}</div>
|
|
<div class="stat-desc text-xs">
|
|
{{ if gt .Summary.VulnNewBySev.Critical 0 }}{{ .Summary.VulnNewBySev.Critical }}<span class="sr-only"> Critical</span><span aria-hidden="true">C</span> {{ end }}
|
|
{{ if gt .Summary.VulnNewBySev.High 0 }}{{ .Summary.VulnNewBySev.High }}<span class="sr-only"> High</span><span aria-hidden="true">H</span> {{ end }}
|
|
{{ if gt .Summary.VulnNewBySev.Medium 0 }}{{ .Summary.VulnNewBySev.Medium }}<span class="sr-only"> Medium</span><span aria-hidden="true">M</span> {{ end }}
|
|
{{ if gt .Summary.VulnNewBySev.Low 0 }}{{ .Summary.VulnNewBySev.Low }}<span class="sr-only"> Low</span><span aria-hidden="true">L</span>{{ end }}
|
|
</div>
|
|
</div>
|
|
{{ end }}
|
|
{{ end }}
|
|
</div>
|
|
|
|
{{ if .IsMultiArch }}
|
|
<div class="flex items-center gap-3 pt-4 border-t border-base-300">
|
|
<label for="diff-arch-select" class="text-sm font-medium whitespace-nowrap">{{ icon "cpu" "size-4" }} Platform</label>
|
|
<select id="diff-arch-select" class="select select-sm select-bordered"
|
|
data-diff-url="/diff/{{ .Owner.Handle }}/{{ .Repository }}?from={{ .FromDigest }}&to={{ .ToDigest }}&platform=__VALUE__">
|
|
{{ range .CommonPlatforms }}
|
|
{{ $platKey := printf "%s/%s" .OS .Architecture }}{{ if .Variant }}{{ $platKey = printf "%s/%s/%s" .OS .Architecture .Variant }}{{ end }}
|
|
<option value="{{ $platKey }}"{{ if eq $platKey $.SelectedPlatform }} selected{{ end }}>{{ .OS }}/{{ .Architecture }}{{ if .Variant }}/{{ .Variant }}{{ end }}</option>
|
|
{{ end }}
|
|
</select>
|
|
</div>
|
|
{{ end }}
|
|
</div>
|
|
|
|
{{ template "diff-content" . }}
|
|
</div>
|
|
</main>
|
|
|
|
{{ template "footer" . }}
|
|
</body>
|
|
</html>
|
|
{{ end }}
|