ontoref/assets/web/public/keys-diagram.svg

182 lines
11 KiB
XML
Raw Normal View History

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 860 780" font-family="JetBrains Mono, ui-monospace, monospace">
<defs>
<style>
text { font-family: inherit; }
.title { font-size:15px; font-weight:700; fill:#f1f5f9; }
.label { font-size:11px; fill:#94a3b8; }
.mono { font-size:10px; fill:#7dd3fc; }
.mono-sm { font-size:9px; fill:#7dd3fc; }
.note { font-size:10px; fill:#64748b; font-style:italic; }
.badge { font-size:9px; font-weight:600; }
.head { font-size:12px; font-weight:700; fill:#e2e8f0; }
.env { font-size:9px; fill:#fcd34d; }
.arrow { stroke:#475569; stroke-width:1.5; fill:none; marker-end:url(#arr); }
.arrow-g { stroke:#84cc16; stroke-width:1.5; fill:none; marker-end:url(#arr-g); }
.arrow-r { stroke:#f87171; stroke-width:1.5; fill:none; marker-end:url(#arr-r); }
.arrow-b { stroke:#60a5fa; stroke-width:1.5; fill:none; marker-end:url(#arr-b); }
</style>
<marker id="arr" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="#475569"/></marker>
<marker id="arr-g" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="#84cc16"/></marker>
<marker id="arr-r" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="#f87171"/></marker>
<marker id="arr-b" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="#60a5fa"/></marker>
</defs>
<!-- Background -->
<rect width="860" height="780" rx="12" fill="#0f172a"/>
<rect x="1" y="1" width="858" height="778" rx="11" fill="none" stroke="#1e293b" stroke-width="1"/>
<!-- ══ TITLE ═══════════════════════════════════════════════════════════════ -->
<text x="30" y="36" class="title">ontoref — key &amp; auth model</text>
<line x1="30" y1="45" x2="830" y2="45" stroke="#1e293b" stroke-width="1"/>
<!-- ══ SECTION 1 · KEY GENERATION ════════════════════════════════════════ -->
<text x="30" y="68" class="head">① Key generation</text>
<!-- Box: hash -->
<rect x="30" y="76" width="240" height="52" rx="6" fill="#1e293b" stroke="#334155"/>
<text x="42" y="93" class="label">generate PHC hash</text>
<text x="42" y="108" class="mono">ontoref-daemon --hash-password &lt;pw&gt;</text>
<text x="42" y="120" class="note">→ $argon2id$v=19$... (stdout)</text>
<!-- Box: roles -->
<rect x="290" y="76" width="300" height="52" rx="6" fill="#1e293b" stroke="#334155"/>
<text x="302" y="93" class="label">KeyEntry fields (in keys-overlay.json / config)</text>
<text x="302" y="108" class="mono">role: admin | viewer</text>
<text x="302" y="120" class="mono">hash: &lt;argon2id PHC string&gt; label: &lt;name&gt;</text>
<!-- Arrow -->
<line x1="270" y1="102" x2="288" y2="102" class="arrow"/>
<!-- ══ SECTION 2 · DAEMON STARTUP ════════════════════════════════════════ -->
<text x="30" y="158" class="head">② Daemon startup — load keys</text>
<!-- env vars -->
<rect x="30" y="166" width="380" height="76" rx="6" fill="#1e293b" stroke="#334155"/>
<text x="42" y="183" class="label">env vars (priority order)</text>
<text x="42" y="198" class="env">ONTOREF_ADMIN_TOKEN_FILE</text><text x="195" y="198" class="label"> path to file containing PHC hash</text>
<text x="42" y="213" class="env">ONTOREF_ADMIN_TOKEN</text><text x="172" y="213" class="label"> inline PHC hash (fallback)</text>
<text x="42" y="228" class="note"> → loads as admin key for primary project at boot</text>
<!-- keys-overlay.json -->
<rect x="430" y="166" width="240" height="76" rx="6" fill="#1e293b" stroke="#334155"/>
<text x="442" y="183" class="label">~/.config/ontoref/keys-overlay.json</text>
<text x="442" y="198" class="mono">{ "&lt;slug&gt;": [ KeyEntry, … ] }</text>
<text x="442" y="213" class="note">persisted by PUT /projects/{slug}/keys</text>
<text x="442" y="228" class="note">loaded on daemon start, merged into registry</text>
<!-- daemon box -->
<rect x="680" y="166" width="148" height="76" rx="6" fill="#172554" stroke="#3b82f6"/>
<text x="754" y="196" class="head" text-anchor="middle">daemon</text>
<text x="754" y="212" class="label" text-anchor="middle">ProjectRegistry</text>
<text x="754" y="226" class="label" text-anchor="middle">keys: RwLock&lt;Vec&lt;KeyEntry&gt;&gt;</text>
<line x1="410" y1="204" x2="428" y2="204" class="arrow"/>
<line x1="670" y1="204" x2="678" y2="204" class="arrow"/>
<!-- ══ SECTION 3 · REQUEST FLOW ══════════════════════════════════════════ -->
<text x="30" y="276" class="head">③ Request auth flow</text>
<!-- No keys -->
<rect x="30" y="284" width="180" height="42" rx="6" fill="#1e293b" stroke="#334155"/>
<text x="120" y="301" class="label" text-anchor="middle">no keys configured</text>
<text x="120" y="315" class="mono" text-anchor="middle">auth_enabled() → false</text>
<line x1="210" y1="305" x2="248" y2="305" class="arrow-g"/>
<rect x="250" y="284" width="90" height="42" rx="6" fill="#14532d" stroke="#84cc16"/>
<text x="295" y="305" class="badge" text-anchor="middle" fill="#84cc16">PASS</text>
<text x="295" y="318" class="label" text-anchor="middle">(all requests)</text>
<!-- With keys -->
<rect x="30" y="344" width="180" height="42" rx="6" fill="#1e293b" stroke="#334155"/>
<text x="120" y="361" class="label" text-anchor="middle">keys configured</text>
<text x="120" y="375" class="mono" text-anchor="middle">check_primary_auth()</text>
<!-- no bearer -->
<line x1="210" y1="365" x2="248" y2="345" class="arrow-r"/>
<rect x="250" y="330" width="120" height="32" rx="6" fill="#450a0a" stroke="#f87171"/>
<text x="310" y="345" class="badge" text-anchor="middle" fill="#f87171">401</text>
<text x="310" y="358" class="label" text-anchor="middle">missing Bearer</text>
<!-- with bearer → verify -->
<line x1="210" y1="365" x2="248" y2="380" class="arrow-b"/>
<rect x="250" y="367" width="140" height="32" rx="6" fill="#1e293b" stroke="#60a5fa"/>
<text x="320" y="382" class="mono" text-anchor="middle">argon2id verify</text>
<text x="320" y="394" class="label" text-anchor="middle">~100ms per attempt</text>
<!-- pass/fail -->
<line x1="390" y1="383" x2="428" y2="365" class="arrow-g"/>
<rect x="430" y="352" width="90" height="28" rx="6" fill="#14532d" stroke="#84cc16"/>
<text x="475" y="366" class="badge" text-anchor="middle" fill="#84cc16">PASS</text>
<text x="475" y="376" class="note" text-anchor="middle">role attached</text>
<line x1="390" y1="383" x2="428" y2="393" class="arrow-r"/>
<rect x="430" y="383" width="90" height="28" rx="6" fill="#450a0a" stroke="#f87171"/>
<text x="475" y="397" class="badge" text-anchor="middle" fill="#f87171">401</text>
<text x="475" y="407" class="note" text-anchor="middle">rate-limited</text>
<!-- session shortcut -->
<rect x="540" y="344" width="220" height="42" rx="6" fill="#1e293b" stroke="#7c3aed"/>
<text x="650" y="361" class="label" text-anchor="middle">session token shortcut</text>
<text x="650" y="375" class="mono" text-anchor="middle">UUID v4 → SessionStore O(1)</text>
<line x1="520" y1="360" x2="538" y2="360" class="arrow-b"/>
<!-- ══ SECTION 4 · PROTECTED vs PUBLIC ═══════════════════════════════════ -->
<text x="30" y="434" class="head">④ Endpoint protection</text>
<!-- Protected -->
<rect x="30" y="442" width="270" height="74" rx="6" fill="#1e293b" stroke="#f97316"/>
<text x="42" y="459" class="label" fill="#f97316">■ check_primary_auth required</text>
<text x="42" y="474" class="mono">POST /api/nickel/export</text>
<text x="42" y="488" class="mono">POST /api/cache/invalidate</text>
<text x="42" y="502" class="mono">PUT /api/projects/{slug}/keys (admin role)</text>
<!-- Public -->
<rect x="320" y="442" width="270" height="74" rx="6" fill="#1e293b" stroke="#334155"/>
<text x="332" y="459" class="label">■ public (loopback boundary)</text>
<text x="332" y="474" class="mono">GET /api/search</text>
<text x="332" y="488" class="mono">GET /api/describe/*</text>
<text x="332" y="502" class="mono">GET /api/adr/{id} GET /health</text>
<!-- Sessions -->
<rect x="608" y="442" width="220" height="74" rx="6" fill="#1e293b" stroke="#7c3aed"/>
<text x="620" y="459" class="label" fill="#a78bfa">■ session-gated (ui feature)</text>
<text x="620" y="474" class="mono">POST /api/sessions (create)</text>
<text x="620" y="488" class="mono">GET /api/sessions (list)</text>
<text x="620" y="502" class="mono">DEL /api/sessions/{id} (revoke)</text>
<!-- ══ SECTION 5 · CLI TOKEN FLOW ════════════════════════════════════════ -->
<text x="30" y="546" class="head">⑤ CLI token flow (store.nu)</text>
<rect x="30" y="554" width="390" height="58" rx="6" fill="#1e293b" stroke="#334155"/>
<text x="42" y="571" class="env">ONTOREF_TOKEN</text><text x="140" y="571" class="label"> → bearer-args → curl -H "Authorization: Bearer …"</text>
<text x="42" y="586" class="label">daemon reachable? → HTTP (token sent if set)</text>
<text x="42" y="600" class="label">daemon down? → subprocess nickel (no token, no daemon)</text>
<!-- ══ QUICK REFERENCE ═══════════════════════════════════════════════════ -->
<line x1="30" y1="630" x2="830" y2="630" stroke="#1e293b" stroke-width="1"/>
<text x="30" y="648" class="head">Quick reference</text>
<!-- col 1 -->
<text x="30" y="666" class="label">Generate hash</text>
<text x="160" y="666" class="mono-sm">ontoref-daemon --hash-password &lt;pw&gt;</text>
<text x="30" y="681" class="label">Set keys (admin)</text>
<text x="160" y="681" class="mono-sm">PUT /api/projects/{slug}/keys body: {keys:[{role,hash,label}]}</text>
<text x="30" y="696" class="label">Create session</text>
<text x="160" y="696" class="mono-sm">POST /api/sessions body: {key:&lt;password&gt;, actor:&lt;type&gt;}</text>
<!-- col 2 -->
<text x="30" y="715" class="label">Export NCL</text>
<text x="160" y="715" class="mono-sm">POST /api/nickel/export body: {path, import_path?} Bearer required</text>
<text x="30" y="730" class="label">Get ADR</text>
<text x="160" y="730" class="mono-sm">GET /api/adr/{id}?slug=&lt;slug&gt;</text>
<text x="30" y="745" class="label">Search</text>
<text x="160" y="745" class="mono-sm">GET /api/search?q=&lt;term&gt;&amp;slug=&lt;slug&gt;</text>
<text x="30" y="760" class="label">Describe project</text>
<text x="160" y="760" class="mono-sm">GET /api/describe/project?slug=&lt;slug&gt;</text>
</svg>