crates/nornir-git/.nornir/assets/sshkey-deploy-flow.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1080 520" font-family="ui-monospace,'JetBrains Mono',Menlo,monospace">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#0b1c2e"/>
<stop offset="1" stop-color="#06111d"/>
</linearGradient>
<marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M0 0 L10 5 L0 10 z" fill="#4fd6e0"/>
</marker>
<marker id="arrg" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
<path d="M0 0 L10 5 L0 10 z" fill="#54d98c"/>
</marker>
</defs>
<rect width="1080" height="520" fill="url(#bg)"/>
<rect x="8" y="8" width="1064" height="504" rx="10" fill="none" stroke="#1c3a4f"/>
<text x="30" y="44" fill="#9fe8f0" font-size="20" font-weight="700">nornir-git · sshkey — the ONE ed25519 OpenSSH deploy-key mint</text>
<text x="30" y="68" fill="#6f93a0" font-size="13">Pure-Rust, zero-shell (L9). nornir + dwarves used to twin this; now both consume it. No ssh-keygen subprocess.</text>
<!-- CALLERS -->
<g>
<rect x="34" y="120" width="250" height="120" rx="9" fill="#0e2436" stroke="#4fd6e0" stroke-width="1.5"/>
<text x="50" y="148" fill="#4fd6e0" font-size="14" font-weight="700">① SERVICE INSTALL</text>
<text x="50" y="174" fill="#cfe9f0" font-size="12">nornir --install --system</text>
<text x="50" y="194" fill="#cfe9f0" font-size="12">dwarves --install --system</text>
<text x="50" y="220" fill="#6f93a0" font-size="11.5">each runs as its OWN user</text>
</g>
<!-- ENSURE -->
<g>
<rect x="330" y="110" width="300" height="300" rx="9" fill="#0e2436" stroke="#4fd6e0" stroke-width="1.5"/>
<text x="348" y="138" fill="#4fd6e0" font-size="14" font-weight="700">② ensure_deploy_key(home, uid, gid)</text>
<text x="348" y="166" fill="#cfe9f0" font-size="12">comment = <home basename>@<host></text>
<text x="348" y="184" fill="#6f93a0" font-size="11.5">/home/nornir → nornir@loki</text>
<text x="348" y="200" fill="#6f93a0" font-size="11.5">/home/dwarves → dwarves@loki</text>
<rect x="348" y="216" width="264" height="120" rx="7" fill="#0b1c2e" stroke="#54d98c" stroke-width="1.2"/>
<text x="362" y="240" fill="#54d98c" font-size="13" font-weight="700">generate_ed25519_openssh(dir, comment)</text>
<text x="362" y="262" fill="#cfe9f0" font-size="12">rand_core::OsRng → ssh_key</text>
<text x="362" y="280" fill="#cfe9f0" font-size="12">PrivateKey::random(Ed25519)</text>
<text x="362" y="298" fill="#cfe9f0" font-size="12">.to_openssh(LF) (in-process)</text>
<text x="362" y="322" fill="#9fe8f0" font-size="11.5">idempotent — existing key preserved</text>
<text x="348" y="366" fill="#cfe9f0" font-size="12">chown .ssh + key files → uid:gid</text>
<text x="348" y="388" fill="#9fe8f0" font-size="12">returns DeployKey { pubkey, … }</text>
</g>
<!-- DISK -->
<g>
<rect x="686" y="110" width="330" height="150" rx="9" fill="#0e2436" stroke="#54d98c" stroke-width="1.5"/>
<text x="704" y="138" fill="#54d98c" font-size="14" font-weight="700">③ <home>/.ssh/ (dir 0700)</text>
<text x="704" y="166" fill="#cfe9f0" font-size="12">id_ed25519 — private, 0600</text>
<text x="704" y="188" fill="#cfe9f0" font-size="12">id_ed25519.pub — public, 0644</text>
<text x="704" y="214" fill="#6f93a0" font-size="11.5">ssh-ed25519 AAAA… nornir@loki</text>
<text x="704" y="236" fill="#6f93a0" font-size="11.5">owner-only private half = no leak</text>
</g>
<!-- CONSUMERS -->
<g>
<rect x="686" y="300" width="330" height="110" rx="9" fill="#0e2436" stroke="#4fd6e0" stroke-width="1.5"/>
<text x="704" y="328" fill="#4fd6e0" font-size="14" font-weight="700">④ CONSUMED BY</text>
<text x="704" y="354" fill="#cfe9f0" font-size="12">pubkey → paste as repo deploy key</text>
<text x="704" y="376" fill="#cfe9f0" font-size="12">nornir_git::ssh authenticates</text>
<text x="704" y="394" fill="#6f93a0" font-size="11.5">git-upload-pack with id_ed25519</text>
</g>
<line x1="284" y1="180" x2="326" y2="200" stroke="#4fd6e0" stroke-width="1.6" marker-end="url(#arr)"/>
<line x1="630" y1="180" x2="682" y2="180" stroke="#54d98c" stroke-width="1.6" marker-end="url(#arrg)"/>
<line x1="851" y1="262" x2="851" y2="296" stroke="#4fd6e0" stroke-width="1.6" marker-end="url(#arr)"/>
<text x="30" y="470" fill="#6f93a0" font-size="12">RED-when-broken tests: parses back as ed25519 · private is 0600 · dir 0700 · deterministic ssh-ed25519 shape · idempotent.</text>
<text x="30" y="492" fill="#6f93a0" font-size="12">functional_status rows (feature=testmatrix): ensure_deploy_key_mints · deploy_key_is_valid_ed25519 · deploy_key_idempotent.</text>
</svg>