.nornir/assets/feeds-ingest.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 840 340" 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">Advisory ingest — feeds → Advisory (range-native)</text>
<!-- sources -->
<rect x="30" y="70" width="170" height="220" rx="8" fill="#eef3fb" stroke="#2b5fb3" stroke-width="1.5"/>
<text x="115" y="94" text-anchor="middle" font-weight="600">offline feeds</text>
<text x="115" y="122" text-anchor="middle" fill="#555" font-size="12">OSV / GHSA / RUSTSEC</text>
<text x="115" y="146" text-anchor="middle" fill="#555" font-size="12">NVD CVE JSON 2.0</text>
<text x="115" y="170" text-anchor="middle" fill="#555" font-size="12">CISA KEV · FIRST EPSS</text>
<text x="115" y="194" text-anchor="middle" fill="#555" font-size="12">OpenSSF Malicious</text>
<text x="115" y="218" text-anchor="middle" fill="#555" font-size="12">CSAF VEX</text>
<text x="115" y="256" text-anchor="middle" fill="#888" font-size="11">sealed .znippy carried</text>
<text x="115" y="273" text-anchor="middle" fill="#888" font-size="11">across the airgap</text>
<!-- parse -->
<rect x="270" y="70" width="180" height="70" rx="8" fill="#eefaf0" stroke="#2f8f4e" stroke-width="1.5"/>
<text x="360" y="98" text-anchor="middle" font-weight="600">parse</text>
<text x="360" y="118" text-anchor="middle" fill="#555" font-size="12">osv · nvd · feeds · vex</text>
<!-- merge -->
<rect x="270" y="170" width="180" height="70" rx="8" fill="#eefaf0" stroke="#2f8f4e" stroke-width="1.5"/>
<text x="360" y="198" text-anchor="middle" font-weight="600">merge_by_alias</text>
<text x="360" y="218" text-anchor="middle" fill="#555" font-size="12">dedup CVE↔GHSA↔RUSTSEC</text>
<!-- enrich -->
<rect x="520" y="120" width="150" height="70" rx="8" fill="#fdf2ec" stroke="#c26a2b" stroke-width="1.5"/>
<text x="595" y="148" text-anchor="middle" font-weight="600">enrich</text>
<text x="595" y="168" text-anchor="middle" fill="#555" font-size="12">EPSS · KEV · CVSS/CWE</text>
<!-- advisory -->
<rect x="700" y="120" width="120" height="70" rx="8" fill="#f6eefb" stroke="#7a3fb3" stroke-width="1.5"/>
<text x="760" y="145" text-anchor="middle" font-weight="700">Advisory</text>
<text x="760" y="165" text-anchor="middle" fill="#555" font-size="12">ranges[]</text>
<text x="760" y="182" text-anchor="middle" fill="#555" font-size="11">affected_by()</text>
<path d="M200,150 C230,130 240,115 270,105" fill="none" stroke="#555" stroke-width="1.4" marker-end="url(#a)"/>
<path d="M360,140 L360,170" fill="none" stroke="#555" stroke-width="1.4" marker-end="url(#a)"/>
<path d="M450,205 C490,200 495,180 520,165" fill="none" stroke="#555" stroke-width="1.4" marker-end="url(#a)"/>
<path d="M670,155 L700,155" fill="none" stroke="#555" stroke-width="1.4" marker-end="url(#a)"/>
<text x="500" y="300" fill="#888" font-size="12">store ranges, match at scan time — versions::affected_by(eco, ranges, version)</text>
</svg>