Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/labview-ci/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,7 @@ def consumer_dashboard_workflow(catalog: dict, branch: str = "main") -> str:
' - "VI Snapshots and VI Browser"\n'
' - "Build LabVIEW CI Image"\n'
' - "Build LabVIEW CI Image - Linux"\n'
' - "Generate SBOM \u2014 Windows Container"\n'
" types: [completed]\n"
" schedule:\n"
" - cron: '0 * * * *'\n"
Expand Down
3 changes: 2 additions & 1 deletion .github/labview/build-sbom-report.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def build_data(args) -> dict:
meta_extra = {}

if args.platform == "windows":
platforms = [{"id": "windows", "url": None}, {"id": "linux", "url": "linux/results.json"}]
platforms = [{"id": "windows", "url": None}, {"id": "linux", "url": None}]
snap_depth = "../../"
else:
platforms = [{"id": "windows", "url": "../results.json"}, {"id": "linux", "url": None}]
Expand Down Expand Up @@ -195,6 +195,7 @@ def render(data: dict) -> str:
"sha": m.get("sha", ""),
"short": m.get("short", ""),
"platform": m.get("platform", "windows"),
"rawUrl": "results/sbom.json",
}
dash = m.get("dash_url") or ""
repo = m.get("repo") or ""
Expand Down
3 changes: 2 additions & 1 deletion .github/pages/404.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
'vi-analyzer-linux': { context: 'vi-analyzer-report', label: 'VI Analyzer', workflow: { windows: 'run-vi-analyzer-windows-container.yml' }, statuses: ['CI / VI Analyzer'] },
'masscompile': { context: 'masscompile-report', label: 'Mass Compile', workflow: { windows: 'masscompile-windows-container.yml', linux: 'masscompile-linux-container.yml' }, statuses: ['CI / Mass Compile'] },
'unit-tests': { context: 'unit-tests-report', label: 'Unit Tests', workflow: { windows: 'unit-tests-windows-container.yml' }, statuses: ['CI / Unit Tests'] },
'antidoc': { context: 'antidoc-report', label: 'Antidoc', workflow: { windows: 'run-antidoc-windows-container.yml' }, statuses: ['CI / Antidoc'] }
'antidoc': { context: 'antidoc-report', label: 'Antidoc', workflow: { windows: 'run-antidoc-windows-container.yml' }, statuses: ['CI / Antidoc'] },
'sbom': { context: 'sbom-report', label: 'SBOM', workflow: { windows: 'generate-sbom-windows-container.yml' }, statuses: ['CI / SBOM Generation', 'CI / SBOM'] }
};
function trimSlash(s) { return String(s || '').replace(/\/+$/, ''); }
function pagesBase() {
Expand Down
26 changes: 25 additions & 1 deletion .github/pages/documentation.html
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ <h2>On this page</h2>
<li class="sub"><a href="#cap-unittests">Unit Tests (worked example)</a></li>
<li class="sub"><a href="#cap-antidoc">Antidoc</a></li>
<li class="sub"><a href="#cap-snapshots">VI Snapshots / Browser</a></li>
<li class="sub"><a href="#cap-sbom">SBOM Generation</a></li>
</ol>
</li>
<li><a href="#contracts">17. Report data contracts</a></li>
Expand Down Expand Up @@ -1895,6 +1896,28 @@ <h4>Phase 2 — position-aware JSON (VI Snapshots 2.0) <span class="pill win">Wi
<p>Both 2.0 renderers <strong>auto-run on every new revision</strong> via a <code>workflow_run</code> trigger after the snapshot pipeline finishes, each behind a gate job that reads <code>config.viBrowser.positionAware</code>: the Linux workflow runs when it includes <code>linux</code>, the Windows workflow when it includes <code>windows</code> (the configurator default). Because renders are content-addressed by git blob SHA, the worklist skips every VI whose blob already has a render &mdash; <strong>unchanged VIs reuse their existing frames with no work</strong> &mdash; and queues only the new/changed blobs, so a VI a revision actually changed gets a fresh render automatically.</p>
<p>The browser now remembers its viewer mode and 2.0 platform choice in local storage, defaults to 2.0 when a VI has a 2.0 render (preferring the Windows render when both platforms exist), and shows dismissible coaching tip strips for the block-diagram toggle and the case/event selector arrows. The 2.0 auto-default is now enforced on open whenever a 2.0 render exists (unless the URL explicitly pins <code>viewer</code>/<code>plat2</code>). Those tips are browser-local too: dismissing one with <strong>Never show this again</strong> hides it only in that browser profile, and the dismissal keys are versioned so a new coaching rollout can deliberately surface the tips once more for everyone.</p>

<h3 id="cap-sbom">16.7 SBOM Generation <a class="anchor" href="#cap-sbom">#</a></h3>
<h4>At a glance</h4>
<table>
<tbody>
<tr><th>Driver</th><td><code>.github/labview/run-sbom-generation.ps1</code> <span class="pill win">Windows</span></td></tr>
<tr><th>Report builder</th><td><code>.github/labview/build-sbom-report.py</code></td></tr>
<tr><th>Workflow</th><td><code>generate-sbom-windows-container.yml</code> <span class="pill win">windows-2022</span></td></tr>
<tr><th>Output &amp; status</th><td><code>sbom/&lt;sha&gt;/</code>; commit status <code>CI / SBOM Generation</code></td></tr>
</tbody>
</table>
<p>The Windows worker invokes the VIPM CLI to inventory the revision&rsquo;s resolved LabVIEW package
dependencies and preserves its native CycloneDX document at
<code>sbom/&lt;sha&gt;/results/sbom.json</code>. The host report builder normalises that inventory into
<code>results.json</code> and a navigable <code>index.html</code>, then the workflow uploads the whole
directory as an Actions artifact and publishes it to GitHub Pages.</p>
<p>The dashboard has a per-revision <strong>SBOM</strong> column. Its status pill links to the Pages report
inside the shared report viewer; the viewer&rsquo;s <strong>CycloneDX JSON</strong> action opens the native
machine-readable document. Empty cells can dispatch SBOM generation for that revision, and SBOM participates
in Populate history, the activity switcher, revision navigation, and regeneration controls. Historical
<code>CI / SBOM</code> statuses remain readable, while new runs use the catalog-declared
<code>CI / SBOM Generation</code> context.</p>

<!-- 17 ──────────────────────────────────────────────────────────────── -->
<h2 id="contracts">17. Report data contracts <a class="anchor" href="#contracts">#</a></h2>
<p>Each capability writes a small, stable JSON document that the dashboard and the shared header consume. The
Expand All @@ -1908,7 +1931,8 @@ <h2 id="contracts">17. Report data contracts <a class="anchor" href="#contracts"
<tr><td><code>vidiff/&lt;segment&gt;/&lt;platform&gt;/vidiff/changes.json</code></td><td>VIDiff</td><td>Dashboard + VIDiff report</td></tr>
<tr><td><code>unit-tests/&lt;sha&gt;/results.json</code></td><td>Unit-test report builder</td><td>Dashboard + report</td></tr>
<tr><td><code>builds/&lt;sha&gt;/summary.json</code></td><td>Builds report builder</td><td>Dashboard cell (succeeded/failed split) + report</td></tr>
<tr><td><code>builds/&lt;sha&gt;/summary.json</code></td><td>Builds report builder</td><td>Dashboard cell (succeeded/failed split) + report</td></tr>
<tr><td><code>sbom/&lt;sha&gt;/results.json</code></td><td>SBOM report builder</td><td>Dashboard report availability + HTML report</td></tr>
<tr><td><code>sbom/&lt;sha&gt;/results/sbom.json</code></td><td>VIPM CLI</td><td>Native CycloneDX download</td></tr>
<tr><td><code>vi-snapshots/&lt;sha&gt;/manifest.json</code></td><td>Snapshot gallery builder</td><td>VI Browser</td></tr>
<tr><td><code>dependencies/index.json</code></td><td>Dashboard publisher</td><td>Dependencies page install-time inventory</td></tr>
<tr><td><code>workers/&lt;platform&gt;/&lt;version&gt;/manifest.json</code></td><td>Worker image workflows</td><td>Dependencies page installed-package status</td></tr>
Expand Down
17 changes: 13 additions & 4 deletions .github/pages/lvci-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@
vibrowser: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="14" rx="2"/><circle cx="8.5" cy="9" r="1.5"/><path d="M21 15l-4.5-4.5L7 19"/></svg>',
vianalyzer: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="10.5" cy="10.5" r="6.5"/><path d="M15.5 15.5 21 21"/><path d="M7.8 10.6l2 2 3.2-3.6"/></svg>',
builds: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.7l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.7l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><path d="M3.3 7L12 12l8.7-5"/><path d="M12 22V12"/></svg>',
sbom: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><path d="M8 13h8M8 17h8M8 9h2"/></svg>',
update: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M7 10l5 5 5-5"/><line x1="12" y1="15" x2="12" y2="3"/></svg>',
about: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9.5"/><line x1="12" y1="16" x2="12" y2="11.5"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>',
clients: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 20v-1.5a3.5 3.5 0 0 0-3.5-3.5h-6A3.5 3.5 0 0 0 4 18.5V20"/><circle cx="10.5" cy="8" r="3.5"/><path d="M21 20v-1.5a3.5 3.5 0 0 0-2.6-3.4"/><path d="M15.5 4.6a3.5 3.5 0 0 1 0 6.8"/></svg>',
Expand Down Expand Up @@ -621,6 +622,7 @@
'unit-tests-report': 'dashboard',
'antidoc-report': 'dashboard',
'builds-report': 'dashboard',
'sbom-report': 'dashboard',
'unit-tests-config': 'settings',
'worker-manifest': 'dashboard',
'report-viewer': 'dashboard',
Expand Down Expand Up @@ -672,13 +674,19 @@
regenLabel: 'Rebuild', rawLabel: 'Build log', rawName: 'builds.log',
workflow: { windows: 'build-binaries-windows-container.yml',
linux: 'build-binaries-linux-container.yml' }
},
'sbom-report': {
prefix: 'sbom', cap: 'sbom-generation', label: 'SBOM',
regenLabel: 'Regenerate SBOM', rawLabel: 'CycloneDX JSON', rawName: 'results/sbom.json',
probeName: 'results.json',
workflow: { windows: 'generate-sbom-windows-container.yml' }
}
};
var DOC = DOCTYPES[ctx] || null; // non-null only on a per-revision report

// Order the per-revision activities appear in the context-bar Activity picker
// (the report half of the unified Activity switcher; per-VI lenses join later).
var LENS_ORDER = ['snapshots', 'masscompile-report', 'vi-analyzer-report', 'unit-tests-report', 'antidoc-report', 'builds-report'];
var LENS_ORDER = ['snapshots', 'masscompile-report', 'vi-analyzer-report', 'unit-tests-report', 'antidoc-report', 'builds-report', 'sbom-report'];

var SHA_RE = /^[0-9a-f]{7,40}$/i;
var revisionListCache = {};
Expand Down Expand Up @@ -808,7 +816,8 @@
{ label: 'VI Analyzer', svg: ICON.vianalyzer, activity: 'vi-analyzer-report' },
{ label: 'Unit Tests', svg: ICON.tests, activity: 'unit-tests-report' },
{ label: 'Antidoc', svg: ICON.docs, activity: 'antidoc-report' },
{ label: 'Builds', svg: ICON.builds, activity: 'builds-report' }
{ label: 'Builds', svg: ICON.builds, activity: 'builds-report' },
{ label: 'SBOM', svg: ICON.sbom, activity: 'sbom-report' }
];
}

Expand Down Expand Up @@ -1464,7 +1473,7 @@
function reportExists(d, sha) {
if (!d || !sha) return Promise.resolve(false);
var root = base + '/' + d.prefix + '/' + sha + '/';
return fetch(root + 'summary.json', { method: 'HEAD', cache: 'no-cache' })
return fetch(root + (d.probeName || 'summary.json'), { method: 'HEAD', cache: 'no-cache' })
.then(function (r) { return r.ok ? true : fetch(root + 'index.html', { method: 'HEAD', cache: 'no-cache' }).then(function (rr) { return rr.ok; }); })
.catch(function () { return fetch(root + 'index.html', { method: 'HEAD', cache: 'no-cache' }).then(function (r) { return r.ok; }).catch(function () { return false; }); });
}
Expand All @@ -1485,7 +1494,7 @@
var LENS_GROUPS = [
{ label: 'Code & changes', keys: ['snapshots'] },
{ label: 'Quality', keys: ['masscompile-report', 'vi-analyzer-report', 'unit-tests-report'] },
{ label: 'Artifacts', keys: ['antidoc-report', 'builds-report'] }
{ label: 'Artifacts', keys: ['antidoc-report', 'builds-report', 'sbom-report'] }
];
function lensLabel(key) {
if (key === 'snapshots') return 'Snapshots';
Expand Down
5 changes: 3 additions & 2 deletions .github/pages/report-viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
return s;
};
var dec = function (raw, fb) { if (!raw) return fb; try { return decodeURIComponent(raw); } catch (e) { return fb; } };
var KNOWN = { 'masscompile-report': 1, 'vi-analyzer-report': 1, 'unit-tests-report': 1, 'antidoc-report': 1 };
var KNOWN = { 'masscompile-report': 1, 'vi-analyzer-report': 1, 'unit-tests-report': 1, 'antidoc-report': 1, 'sbom-report': 1 };
var type = dec(p.get('type'), '');
window.LVCI = {
context: KNOWN[type] ? type : 'report-viewer',
Expand Down Expand Up @@ -110,7 +110,8 @@
'masscompile-report': 'masscompile',
'vi-analyzer-report': 'vi-analyzer',
'unit-tests-report': 'unit-tests',
'antidoc-report': 'antidoc'
'antidoc-report': 'antidoc',
'sbom-report': 'sbom-generation'
})[type] || '';
}
function populateHistoryUrl() {
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/generate-sbom-windows-container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ run-name: Generate SBOM Windows container - ${{ github.event_name == 'workflow_d
# Generates a Software Bill of Materials (SBOM) for LabVIEW VIPM dependencies
# inside the project's CI worker image, processes the spdx json into a navigable
# report (build-sbom-report.py), deploys it under sbom/<sha>/, and posts the
# "CI / SBOM" commit status for the dashboard. Manual runs come through workflow_dispatch.
# "CI / SBOM Generation" commit status for the dashboard. Manual runs come through workflow_dispatch.

on:
# Triggers on changes to VIPM workspace dependencies (.vipc) or LabVIEW files in case that pulls in new dependency
Expand Down Expand Up @@ -83,7 +83,7 @@ jobs:
-H "Authorization: token $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${{ github.repository }}/statuses/${{ steps.sha.outputs.sha }}" \
-d "{\"state\":\"pending\",\"target_url\":\"https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\",\"description\":\"SBOM generation in progress\",\"context\":\"CI / SBOM\"}"
-d "{\"state\":\"pending\",\"target_url\":\"https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\",\"description\":\"SBOM generation in progress\",\"context\":\"CI / SBOM Generation\"}"

- name: Checkout repository
uses: actions/checkout@v5
Expand All @@ -110,7 +110,7 @@ jobs:
name="${IMAGE_OVERRIDE:-${GITHUB_REPOSITORY##*/}-labview}"
name=$(printf '%s' "$name" | tr '[:upper:]' '[:lower:]')
custom="ghcr.io/${owner}/${name}"
ACTION_ID="sbom"
ACTION_ID="sbom-generation"
CFG=.github/labview-ci.yml
sel=""
if [ -f "$CFG" ]; then
Expand Down Expand Up @@ -268,7 +268,7 @@ jobs:
-H "Authorization: token $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${{ github.repository }}/statuses/${{ steps.sha.outputs.sha }}" \
-d "{\"state\":\"$STATE\",\"target_url\":\"$REPORT_URL\",\"description\":\"$DESC\",\"context\":\"CI / SBOM\"}"
-d "{\"state\":\"$STATE\",\"target_url\":\"$REPORT_URL\",\"description\":\"$DESC\",\"context\":\"CI / SBOM Generation\"}"

- name: Post worker version status
if: always() && steps.pull.outcome == 'success' && steps.worker.outputs.version != ''
Expand Down
3 changes: 2 additions & 1 deletion actions/dashboard/404.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
'vi-analyzer-linux': { context: 'vi-analyzer-report', label: 'VI Analyzer', workflow: { windows: 'run-vi-analyzer-windows-container.yml' }, statuses: ['CI / VI Analyzer'] },
'masscompile': { context: 'masscompile-report', label: 'Mass Compile', workflow: { windows: 'masscompile-windows-container.yml', linux: 'masscompile-linux-container.yml' }, statuses: ['CI / Mass Compile'] },
'unit-tests': { context: 'unit-tests-report', label: 'Unit Tests', workflow: { windows: 'unit-tests-windows-container.yml' }, statuses: ['CI / Unit Tests'] },
'antidoc': { context: 'antidoc-report', label: 'Antidoc', workflow: { windows: 'run-antidoc-windows-container.yml' }, statuses: ['CI / Antidoc'] }
'antidoc': { context: 'antidoc-report', label: 'Antidoc', workflow: { windows: 'run-antidoc-windows-container.yml' }, statuses: ['CI / Antidoc'] },
'sbom': { context: 'sbom-report', label: 'SBOM', workflow: { windows: 'generate-sbom-windows-container.yml' }, statuses: ['CI / SBOM Generation', 'CI / SBOM'] }
};
function trimSlash(s) { return String(s || '').replace(/\/+$/, ''); }
function pagesBase() {
Expand Down
Loading
Loading