Merge claude/1
This commit is contained in:
commit
b94cda0ffe
@ -88,6 +88,35 @@
|
|||||||
.updater-cve-pkg { color: rgba(var(--text-rgb), 0.6); }
|
.updater-cve-pkg { color: rgba(var(--text-rgb), 0.6); }
|
||||||
.updater-cve-fix { margin-left: auto; color: rgba(var(--page-verify-rgb), 0.9); font-size: 0.76rem; }
|
.updater-cve-fix { margin-left: auto; color: rgba(var(--page-verify-rgb), 0.9); font-size: 0.76rem; }
|
||||||
|
|
||||||
|
/* Count pill next to the "Security" detail heading (e.g. "Security 28"). */
|
||||||
|
.updater-cve-count {
|
||||||
|
display: inline-block; vertical-align: middle; margin-left: 4px;
|
||||||
|
font-size: 0.68rem; font-weight: 700; line-height: 1; padding: 3px 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(var(--page-verify-rgb, var(--accent-rgb)), 0.16);
|
||||||
|
color: rgb(var(--page-verify-rgb, var(--accent-rgb)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A long CVE list stays compact: once past a handful of rows it caps its height
|
||||||
|
and scrolls internally rather than pushing the whole page down. The first row
|
||||||
|
already carries a top border, so no seam is needed at the box edge. */
|
||||||
|
.updater-cve-scroll.is-scrollable {
|
||||||
|
max-height: 260px; overflow-y: auto;
|
||||||
|
padding-right: 8px; margin-right: -4px;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: rgba(var(--text-rgb), 0.28) transparent;
|
||||||
|
/* Bottom-only fade hints there's more below; the top stays crisp so the
|
||||||
|
worst-severity rows (sorted first) are never dimmed. */
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent 100%);
|
||||||
|
mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent 100%);
|
||||||
|
}
|
||||||
|
.updater-cve-scroll.is-scrollable::-webkit-scrollbar { width: 8px; }
|
||||||
|
.updater-cve-scroll.is-scrollable::-webkit-scrollbar-track { background: transparent; }
|
||||||
|
.updater-cve-scroll.is-scrollable::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(var(--text-rgb), 0.22); border-radius: 999px;
|
||||||
|
}
|
||||||
|
.updater-cve-scroll.is-scrollable::-webkit-scrollbar-thumb:hover { background: rgba(var(--text-rgb), 0.34); }
|
||||||
|
|
||||||
/* ---- Buttons ---- */
|
/* ---- Buttons ---- */
|
||||||
.updater-btn {
|
.updater-btn {
|
||||||
display: inline-flex; align-items: center; gap: 6px;
|
display: inline-flex; align-items: center; gap: 6px;
|
||||||
|
|||||||
@ -183,6 +183,27 @@ class UpdaterPage {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sevRank(s) {
|
||||||
|
const r = { critical: 0, high: 1, medium: 2, low: 3 };
|
||||||
|
return r[(s || '').toLowerCase()] ?? 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// One CVE list, shared by the standalone Security tab and the per-app expander.
|
||||||
|
// Sorted worst-first (so the most severe are visible before any scroll) and
|
||||||
|
// wrapped in a height-capped scroll box once the list is long, so an app with
|
||||||
|
// dozens of CVEs (e.g. 28) stays compact instead of pushing the page down.
|
||||||
|
renderCveList(cves) {
|
||||||
|
const list = [...(cves || [])].sort((x, y) => this.sevRank(x.severity) - this.sevRank(y.severity));
|
||||||
|
const items = list.map(c => `
|
||||||
|
<div class="updater-cve sev-${(c.severity || 'low').toLowerCase()}">
|
||||||
|
<span class="updater-cve-sev">${this.escape((c.severity || '').toUpperCase())}</span>
|
||||||
|
<a class="updater-cve-id" href="${this.escape(c.url || ('https://nvd.nist.gov/vuln/detail/' + (c.id || '')))}" target="_blank" rel="noopener">${this.escape(c.id || 'CVE')}</a>
|
||||||
|
<span class="updater-cve-pkg">${this.escape(c.package || '')}</span>
|
||||||
|
${c.fixed_in ? `<span class="updater-cve-fix">fixed in ${this.escape(c.fixed_in)}</span>` : ''}
|
||||||
|
</div>`).join('');
|
||||||
|
return `<div class="updater-cve-scroll${list.length > 6 ? ' is-scrollable' : ''}">${items}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
// The CVE scanner's live state, stamped on cves.json by the updater generator:
|
// The CVE scanner's live state, stamped on cves.json by the updater generator:
|
||||||
// 'ready' — Trivy's vulnerability DB is present; results are real
|
// 'ready' — Trivy's vulnerability DB is present; results are real
|
||||||
// 'db_updating' — Trivy is installed but still downloading its DB (no
|
// 'db_updating' — Trivy is installed but still downloading its DB (no
|
||||||
@ -417,16 +438,9 @@ class UpdaterPage {
|
|||||||
// manual Check), so the message alone is the right button-free empty UI.
|
// manual Check), so the message alone is the right button-free empty UI.
|
||||||
if (!this.cves) return this.empty('No vulnerability scan yet — one runs automatically within a couple of minutes.');
|
if (!this.cves) return this.empty('No vulnerability scan yet — one runs automatically within a couple of minutes.');
|
||||||
if (!withCves.length) return this.empty('No known vulnerabilities in your installed apps. 🎉');
|
if (!withCves.length) return this.empty('No known vulnerabilities in your installed apps. 🎉');
|
||||||
const blocks = withCves.map(a => {
|
const blocks = withCves.map(a =>
|
||||||
const items = (a.cves || []).map(c => `
|
`<div class="updater-cve-app"><div class="updater-cve-app-name">${this.escape(a.displayName)} <span class="updater-badge sev-${a.worstSeverity}">${(a.cves || []).length}</span></div>${this.renderCveList(a.cves)}</div>`
|
||||||
<div class="updater-cve sev-${(c.severity || 'low').toLowerCase()}">
|
).join('');
|
||||||
<span class="updater-cve-sev">${this.escape((c.severity || '').toUpperCase())}</span>
|
|
||||||
<a class="updater-cve-id" href="${this.escape(c.url || ('https://nvd.nist.gov/vuln/detail/' + (c.id || '')))}" target="_blank" rel="noopener">${this.escape(c.id || 'CVE')}</a>
|
|
||||||
<span class="updater-cve-pkg">${this.escape(c.package || '')}</span>
|
|
||||||
${c.fixed_in ? `<span class="updater-cve-fix">fixed in ${this.escape(c.fixed_in)}</span>` : ''}
|
|
||||||
</div>`).join('');
|
|
||||||
return `<div class="updater-cve-app"><div class="updater-cve-app-name">${this.escape(a.displayName)} <span class="updater-badge sev-${a.worstSeverity}">${(a.cves || []).length}</span></div>${items}</div>`;
|
|
||||||
}).join('');
|
|
||||||
return `<div class="updater-list">${blocks}</div>`;
|
return `<div class="updater-list">${blocks}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,15 +494,9 @@ class UpdaterPage {
|
|||||||
<div class="updater-detail-row">${badge} <span class="updater-row-ver">${cur}${avail ? ` <span class="updater-arrow">→</span> <strong>${avail}</strong>` : ''}</span></div></div>`;
|
<div class="updater-detail-row">${badge} <span class="updater-row-ver">${cur}${avail ? ` <span class="updater-arrow">→</span> <strong>${avail}</strong>` : ''}</span></div></div>`;
|
||||||
}
|
}
|
||||||
const cves = a.cves || [];
|
const cves = a.cves || [];
|
||||||
const cveItems = cves.map((c) => `
|
const security = `<div class="updater-detail-section"><h4>Security${
|
||||||
<div class="updater-cve sev-${(c.severity || 'low').toLowerCase()}">
|
cves.length ? ` <span class="updater-cve-count">${cves.length}</span>` : ''}</h4>${
|
||||||
<span class="updater-cve-sev">${this.escape((c.severity || '').toUpperCase())}</span>
|
cves.length ? this.renderCveList(cves) : '<p class="updater-detail-empty">No known CVEs. 🎉</p>'}</div>`;
|
||||||
<a class="updater-cve-id" href="${this.escape(c.url || ('https://nvd.nist.gov/vuln/detail/' + (c.id || '')))}" target="_blank" rel="noopener">${this.escape(c.id || 'CVE')}</a>
|
|
||||||
<span class="updater-cve-pkg">${this.escape(c.package || '')}</span>
|
|
||||||
${c.fixed_in ? `<span class="updater-cve-fix">fixed in ${this.escape(c.fixed_in)}</span>` : ''}
|
|
||||||
</div>`).join('');
|
|
||||||
const security = `<div class="updater-detail-section"><h4>Security</h4>${
|
|
||||||
cves.length ? cveItems : '<p class="updater-detail-empty">No known CVEs. 🎉</p>'}</div>`;
|
|
||||||
|
|
||||||
// A rollback target exists if a snapshot field is present (future-proofing)
|
// A rollback target exists if a snapshot field is present (future-proofing)
|
||||||
// OR — the data the generator actually emits today — this app has a prior
|
// OR — the data the generator actually emits today — this app has a prior
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user