This is an automated email from the ASF dual-hosted git repository. szaszm pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
commit 8dbbd228a1812753fa5fd722cfd77300151bb6a4 Author: Gabor Gyimesi <[email protected]> AuthorDate: Fri Oct 2 17:32:32 2026 +0200 MINIFICPP-2914 Fix stale and unescaped data on the CI status page - Pass cache: 'no-cache' on both API calls, so the browser returns the current state. - Sort runs by created_at descending instead of trusting runs[0] - Read the workflow name from the runs payload instead of making a second request per workflow to delay reaching request limits. - Escape API-supplied strings before interpolating them into HTML Fix generated using Claude Code. Closes #2274 Signed-off-by: Marton Szasz <[email protected]> --- docs/status/index.html | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/status/index.html b/docs/status/index.html index 70724a5e2..f153f7d88 100644 --- a/docs/status/index.html +++ b/docs/status/index.html @@ -479,7 +479,7 @@ try { const r = await fetch( `https://api.github.com/repos/${CONFIG.owner}/${CONFIG.repo}/actions/workflows/${file}`, - { headers: getHeaders() } + { headers: getHeaders(), cache: 'no-cache' } ); if (!r.ok) return null; const data = await r.json(); @@ -494,7 +494,7 @@ try { const r = await fetch( `https://api.github.com/repos/${owner}/${repo}/actions/workflows/${file}/runs?per_page=10&branch=${CONFIG.branch}`, - { headers: getHeaders() } + { headers: getHeaders(), cache: 'no-cache' } ); if (!r.ok) { const e = await r.json().catch(() => ({})); @@ -503,14 +503,15 @@ continue; } const data = await r.json(); - const runs = data.workflow_runs || []; + // The API documents no ordering guarantee for workflow runs, so sort newest-first ourselves. + const runs = (data.workflow_runs || []).sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); if (runs.length === 0) { const name = await fetchWorkflowName(file); results.push({ file, name, error: 'No runs found' }); continue; } const latest = runs[0]; - const name = await fetchWorkflowName(file) || latest.name; + const name = latest.name; results.push({ file, name, @@ -549,6 +550,12 @@ return `${Math.floor(diff / 86400)}d ago`; } + const HTML_ESCAPES = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; + + function esc(value) { + return String(value).replace(/[&<>"']/g, c => HTML_ESCAPES[c]); + } + function renderCard(wf, idx) { const s = effectiveStatus(wf); const bars = (wf.history || []).slice(0, 10).map(h => { @@ -559,13 +566,13 @@ <div class="workflow-card" style="animation-delay:${idx * 0.06}s"> <div class="status-dot ${s}"></div> <div class="workflow-info"> - <div class="workflow-name">${wf.name || wf.file}</div> + <div class="workflow-name">${esc(wf.name || wf.file)}</div> <div class="workflow-sub"> - <span>${wf.file}</span> - ${wf.head_branch ? `<span>branch: ${wf.head_branch}</span>` : ''} - ${wf.run_number ? `<a href="${wf.html_url}" target="_blank">run #${wf.run_number}</a>` : ''} + <span>${esc(wf.file)}</span> + ${wf.head_branch ? `<span>branch: ${esc(wf.head_branch)}</span>` : ''} + ${wf.run_number ? `<a href="${esc(wf.html_url)}" target="_blank">run #${wf.run_number}</a>` : ''} ${wf.updated_at ? `<span>${timeAgo(wf.updated_at)}</span>` : ''} - ${wf.error ? `<span class="err">⚠ ${wf.error}</span>` : ''} + ${wf.error ? `<span class="err">⚠ ${esc(wf.error)}</span>` : ''} </div> </div> <div class="history-bars">${bars}</div>
