--- title: Repos --- ```js const API = "http://127.0.0.1:8000"; ``` ```js let _repos = [], _domains = [], _sbom = [], _eps = [], _tds = [], _contribs = []; try { [_repos, _domains, _sbom, _eps, _tds, _contribs] = await Promise.all([ fetch(`${API}/repos/`).then(r => r.ok ? r.json() : []), fetch(`${API}/domains/`).then(r => r.ok ? r.json() : []), fetch(`${API}/sbom/`).then(r => r.ok ? r.json() : []), fetch(`${API}/extension-points/`).then(r => r.ok ? r.json() : []), fetch(`${API}/technical-debt/`).then(r => r.ok ? r.json() : []), fetch(`${API}/contributions/`).then(r => r.ok ? r.json() : []), ]); } catch {} ``` ```js const repos = _repos ?? []; const domains = _domains ?? []; const sbom = _sbom ?? []; const eps = _eps ?? []; const tds = _tds ?? []; const contribs = _contribs ?? []; // Lookups const domainById = Object.fromEntries(domains.map(d => [d.id, d])); const domainBySlug = Object.fromEntries(domains.map(d => [d.slug, d])); // Per-repo SBOM stats (from sbom entries) const sbomByRepo = {}; for (const e of sbom) { if (!sbomByRepo[e.repo_id]) sbomByRepo[e.repo_id] = { count: 0, snapshot_at: e.snapshot_at }; sbomByRepo[e.repo_id].count++; } // Per-domain counts const epByDomain = {}; const tdByDomain = {}; const contribByDomain = {}; // EPs are domain-scoped for (const ep of eps) { if (!ep.status || ep.status === "open" || ep.status === "in_progress") { epByDomain[ep.domain] = (epByDomain[ep.domain] ?? 0) + 1; } } for (const td of tds) { if (!td.status || td.status === "open" || td.status === "in_progress") { tdByDomain[td.domain] = (tdByDomain[td.domain] ?? 0) + 1; } } // Contributions: try to map via workstream → topic → domain (not available here; skip for now) // Use domain slug from contributions' related_workstream if available — fallback: count by type only // Build enriched repo rows const repoRows = repos .filter(r => r.status === "active") .map(r => { const domain = domainById[r.domain_id]; const domSlug = domain?.slug ?? "—"; const domName = domain?.name ?? "—"; const sbomData = sbomByRepo[r.id]; const hasSbom = !!sbomData || !!r.last_sbom_at; const pkgCount = sbomData?.count ?? 0; const lastScan = r.last_sbom_at ? new Date(r.last_sbom_at).toLocaleDateString() : (sbomData?.snapshot_at ? new Date(sbomData.snapshot_at).toLocaleDateString() : null); return { _id: r.id, _domSlug: domSlug, _hasSbom: hasSbom, repo: r.slug, domain: domName, path: r.local_path ?? "—", sbom: hasSbom ? `✓ ${lastScan}` : "⚠ not ingested", pkgs: pkgCount || (hasSbom ? "—" : 0), eps: epByDomain[domSlug] ?? 0, tds: tdByDomain[domSlug] ?? 0, }; }) .sort((a, b) => a._domSlug.localeCompare(b._domSlug) || a.repo.localeCompare(b.repo)); const gapCount = repoRows.filter(r => !r._hasSbom).length; const coveredCount = repoRows.filter(r => r._hasSbom).length; ``` # Repos ```js import {withDocHelp} from "./components/doc-overlay.js"; const _h1 = document.querySelector("#observablehq-main h1"); if (_h1) { _h1.style.position = "relative"; withDocHelp(_h1, "/docs/repos"); } ``` ```js // Summary KPIs display(html`

Registered Repos

${repoRows.length}

Domains

${new Set(repoRows.map(r => r._domSlug)).size}

SBOM Ingested

${coveredCount} / ${repoRows.length}

SBOM Gaps

${gapCount}

${gapCount === 0 ? "✓ All repos covered" : `⚠ ${gapCount} repo(s) not ingested`}
`); ``` ## Coverage Map ```js // Group by domain const byDomain = {}; for (const r of repoRows) { (byDomain[r._domSlug] = byDomain[r._domSlug] ?? []).push(r); } const domainBlocks = Object.entries(byDomain).sort(([a], [b]) => a.localeCompare(b)); if (domainBlocks.length === 0) { display(html`

No repos registered. Run make add-repo DOMAIN=<slug> SLUG=<slug> NAME="..." PATH=/path.

`); } else { display(html`
${domainBlocks.map(([slug, rows]) => { const dom = domainBySlug[slug]; const allCovered = rows.every(r => r._hasSbom); const hasEps = (epByDomain[slug] ?? 0) > 0; const hasTds = (tdByDomain[slug] ?? 0) > 0; return html`
${dom?.name ?? slug} ${allCovered ? html`SBOM ✓` : html`SBOM ⚠`} ${hasEps ? html`EPs: ${epByDomain[slug]}` : html`EPs: —`} ${hasTds ? html`TDs: ${tdByDomain[slug]}` : html`TDs: —`}
${rows.map(r => html``)}
Repo SBOM Packages Local path
${r.repo} ${r.sbom} ${r.pkgs} ${r.path}
`; })}
`); } ``` ## All Repos Table ```js const domainFilter = Inputs.select(["all", ...new Set(repoRows.map(r => r._domSlug)).values()], {label: "Domain", value: "all"}); const gapFilter = Inputs.toggle({label: "Gaps only (no SBOM)", value: false}); display(html`
${domainFilter}${gapFilter}
`); ``` ```js const filteredRows = repoRows.filter(r => (domainFilter.value === "all" || r._domSlug === domainFilter.value) && (!gapFilter.value || !r._hasSbom) ); display(Inputs.table(filteredRows.map(r => ({ Repo: r.repo, Domain: r.domain, SBOM: r.sbom, Pkgs: r.pkgs, "EPs (domain)": r.eps || "—", "TDs (domain)": r.tds || "—", Path: r.path, })), {maxWidth: 1000})); ``` ## How to Ingest a Repo ```js display(html`

Register a new repo

cd ~/the-custodian/state-hub
make add-repo DOMAIN=<slug> SLUG=<repo-slug> NAME="Display Name" PATH=/absolute/path

Ingest SBOM (single ecosystem, auto-detect lockfile at root)

make ingest-sbom REPO=<slug> REPO_PATH=/absolute/path

Ingest SBOM (multi-ecosystem repo — scans all lockfiles recursively)

make ingest-sbom REPO=<slug> SCAN=1 REPO_PATH=/absolute/path

Infra-only repos (Ansible/shell — no lockfile)

Register the repo for inventory purposes. SBOM gap is expected and intentional. Terraform providers are tracked via .terraform.lock.hcl (auto-detected by --scan).

`); ```