.nornir/assets/manifests-ingest.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 860 380" font-family="-apple-system,Segoe UI,Roboto,sans-serif" font-size="14">
<defs>
<marker id="a" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto">
<path d="M0,0 L7,3 L0,6 Z" fill="#555"/>
</marker>
</defs>
<text x="30" y="30" font-weight="700" font-size="16">Manifest ingest — one seam, one parser per ecosystem → SbomComponent</text>
<!-- manifests -->
<rect x="30" y="60" width="200" height="290" rx="8" fill="#eef3fb" stroke="#2b5fb3" stroke-width="1.5"/>
<text x="130" y="84" text-anchor="middle" font-weight="600">project manifests</text>
<text x="130" y="110" text-anchor="middle" fill="#555" font-size="12">cargo · Cargo.lock</text>
<text x="130" y="132" text-anchor="middle" fill="#555" font-size="12">pip · requirements/poetry/Pipfile</text>
<text x="130" y="154" text-anchor="middle" fill="#555" font-size="12">npm · package-lock/pnpm-lock</text>
<text x="130" y="176" text-anchor="middle" fill="#555" font-size="12">maven · pom.xml</text>
<text x="130" y="198" text-anchor="middle" fill="#555" font-size="12">go · go.mod / go.sum</text>
<text x="130" y="220" text-anchor="middle" fill="#555" font-size="12">nuget · packages.lock / .csproj</text>
<text x="130" y="242" text-anchor="middle" fill="#555" font-size="12">gem · Gemfile.lock</text>
<text x="130" y="300" text-anchor="middle" fill="#888" font-size="11">pure-Rust: toml · roxmltree</text>
<text x="130" y="317" text-anchor="middle" fill="#888" font-size="11">serde_json · hand-parse</text>
<text x="130" y="334" text-anchor="middle" fill="#888" font-size="11">ZERO shell — never runs pip/npm</text>
<!-- dispatch -->
<rect x="290" y="110" width="180" height="80" rx="8" fill="#eefaf0" stroke="#2f8f4e" stroke-width="1.5"/>
<text x="380" y="140" text-anchor="middle" font-weight="600">parse_manifest</text>
<text x="380" y="160" text-anchor="middle" fill="#555" font-size="12">dispatch by basename</text>
<text x="380" y="178" text-anchor="middle" fill="#555" font-size="11">EcosystemParser::handles</text>
<!-- parser -->
<rect x="290" y="220" width="180" height="80" rx="8" fill="#eefaf0" stroke="#2f8f4e" stroke-width="1.5"/>
<text x="380" y="250" text-anchor="middle" font-weight="600">EcosystemParser</text>
<text x="380" y="270" text-anchor="middle" fill="#555" font-size="12">one impl per ecosystem</text>
<text x="380" y="288" text-anchor="middle" fill="#555" font-size="11">.parse(file, text)</text>
<!-- component -->
<rect x="540" y="150" width="150" height="100" rx="8" fill="#f6eefb" stroke="#7a3fb3" stroke-width="1.5"/>
<text x="615" y="178" text-anchor="middle" font-weight="700">SbomComponent</text>
<text x="615" y="200" text-anchor="middle" fill="#555" font-size="12">ecosystem</text>
<text x="615" y="218" text-anchor="middle" fill="#555" font-size="12">name · version</text>
<text x="615" y="236" text-anchor="middle" fill="#555" font-size="12">license?</text>
<!-- emit -->
<rect x="720" y="150" width="120" height="100" rx="8" fill="#fdf2ec" stroke="#c26a2b" stroke-width="1.5"/>
<text x="780" y="185" text-anchor="middle" font-weight="700">sbom</text>
<text x="780" y="207" text-anchor="middle" fill="#555" font-size="12">to_cyclonedx</text>
<text x="780" y="225" text-anchor="middle" fill="#555" font-size="11">pkg:eco/name@ver</text>
<path d="M230,150 L290,150" fill="none" stroke="#555" stroke-width="1.4" marker-end="url(#a)"/>
<path d="M380,190 L380,220" fill="none" stroke="#555" stroke-width="1.4" marker-end="url(#a)"/>
<path d="M470,255 C505,250 510,215 540,205" fill="none" stroke="#555" stroke-width="1.4" marker-end="url(#a)"/>
<path d="M690,200 L720,200" fill="none" stroke="#555" stroke-width="1.4" marker-end="url(#a)"/>
<text x="470" y="360" fill="#888" font-size="12">the model is never forked — every ecosystem lands the SAME SbomComponent the cargo template does</text>
</svg>