Files
passepartout/skills/org-skill-credentials-vault.org

176 lines
7.1 KiB
Org Mode

:PROPERTIES:
:ID: credentials-vault-skill
:CREATED: [2026-04-09 Thu]
:END:
#+TITLE: SKILL: Credentials Vault (Universal Literate Note)
#+STARTUP: content
#+FILETAGS: :auth:security:infrastructure:psf:
#+DEPENDS_ON: id:e8b500e2-3f26-4c8e-8558-528061e178ca
* Overview
The *Credentials Vault* is the high-security enclave for the Org-Agent. It centralizes the management of LLM API keys, OAuth sessions, and browser cookies. By consolidating these into a single vault, we ensure that sensitive tokens are handled with uniform masking, validation, and Merkle-integrated persistence.
* Phase A: Demand (PRD)
:PROPERTIES:
:STATUS: SIGNED
:END:
** 1. Purpose
Securely manage all authentication tokens required for the PSF to operate.
** 2. User Needs
- *Unified Storage:* Single interface for API keys and Session Cookies.
- *Masked Logging:* Ensure credentials never appear in plaintext in `kernel-log`.
- *Guided Onboarding:* Retain and improve the Google/Gemini cookie handshake.
- *Persistence:* Securely save credentials to the Object Store via Merkle-Tree snapshots.
* Phase B: Blueprint (PROTOCOL)
:PROPERTIES:
:STATUS: SIGNED
:END:
** 1. Architectural Intent
The vault provides a secure lookup table in RAM, backed by the persistent Object Store. Access is restricted to internal kernel requests and explicitly authorized symbolic gates.
** 2. Semantic Interfaces
#+begin_src lisp
(defun vault-get-secret (provider &key type)
"Retrieves a secret (api-key or session) for a provider.")
(defun vault-set-secret (provider secret &key type)
"Securely stores a secret and triggers a Merkle snapshot.")
#+end_src
* Phase C: Success (QUALITY)
:PROPERTIES:
:STATUS: SIGNED
:END:
** 1. Success Criteria
- [ ] *No Plaintext Leaks:* Log output must use `[REDACTED]` for sensitive values.
- [ ] *Merkle Integration:* Setting a secret must increment the Object Store version.
- [ ] *Dual-Path Auth:* Support both `:api-key` and `:session-cookies`.
- [ ] *Onboarding Verification:* The cookie handshake successfully hydrates the vault.
** 2. TDD Plan
Tests in `tests/vault-tests.lisp` will verify:
1. Retrieval of keys from both `.env` (fallback) and Vault (primary).
2. Redaction of keys in log strings.
3. Successful version increment in the Object Store after `vault-set-secret`.
* Phase D: Build (Implementation)
** Package Context
#+begin_src lisp :tangle ../src/credentials-vault.lisp
(in-package :org-agent)
#+end_src
** Vault State
We maintain an in-memory hash table for secrets, which is hydrated from and persisted to the Object Store.
#+begin_src lisp :tangle ../src/credentials-vault.lisp
(defvar *vault-memory* (make-hash-table :test 'equal)
"In-memory cache of sensitive credentials.")
#+end_src
** Helper: Secret Masking
The `vault-mask-string` function ensures that diagnostic output never contains the full plaintext of a sensitive token.
#+begin_src lisp :tangle ../src/credentials-vault.lisp
(defun vault-mask-string (str)
"Returns a masked version of a sensitive string."
(if (and str (> (length str) 8))
(format nil "~a...~a" (subseq str 0 4) (subseq str (- (length str) 4)))
"[REDACTED]"))
#+end_src
** Retrieval (vault-get-secret)
This function is the secure getter for all system secrets. It prioritizes the Vault (Object Store) and falls back to environment variables for legacy compatibility.
#+begin_src lisp :tangle ../src/credentials-vault.lisp
(defun vault-get-secret (provider &key (type :api-key))
"Retrieves a credential. Type can be :api-key or :session."
(let* ((key (format nil "~a-~a" provider type))
(val (gethash key *vault-memory*)))
(if val
val
;; Fallback to environment
(let ((env-var (case provider
(:gemini "GEMINI_API_KEY")
(:openai "OPENAI_API_KEY")
(:anthropic "ANTHROPIC_API_KEY")
(:groq "GROQ_API_KEY")
(:openrouter "OPENROUTER_API_KEY")
(t nil))))
(when (and env-var (eq type :api-key))
(uiop:getenv env-var))))))
#+end_src
** Persistence (vault-set-secret)
When a secret is updated, we immediately snapshot the Object Store to ensure the credential change is versioned and durable.
#+begin_src lisp :tangle ../src/credentials-vault.lisp
(defun vault-set-secret (provider secret &key (type :api-key))
"Securely stores a secret and triggers a Merkle snapshot."
(let ((key (format nil "~a-~a" provider type)))
(setf (gethash key *vault-memory*) secret)
(kernel-log "VAULT - Updated ~a for ~a. Triggering Merkle snapshot..." type provider)
(snapshot-object-store)
t))
#+end_src
** Onboarding Logic
Retained from the legacy Google skill, this provides the instructions for the sovereign cookie handshake.
#+begin_src lisp :tangle ../src/credentials-vault.lisp
(defun vault-onboard-gemini-web ()
"Instructions for the Sovereign Cookie Handshake."
(kernel-log "--- GEMINI WEB ONBOARDING ---")
(kernel-log "1. Visit gemini.google.com")
(kernel-log "2. Run the 'Get Gemini Cookies' Bookmarklet.")
(kernel-log " CODE: javascript:(function(){const c=document.cookie.split('; ').reduce((r,v)=>{const [n,val]=v.split('=');r[n]=val;return r},{});const target=['__Secure-1PSID','__Secure-1PSIDTS'];const out=target.map(n=>({name:n,value:c[n]}));prompt('Copy JSON:',JSON.stringify(out));})();")
(kernel-log "PLATFORM GUIDE: Chrome/Firefox/Safari all support Bookmarklets via 'Add Page' or 'New Bookmark'.")
t)
#+end_src
** Registration
#+begin_src lisp :tangle ../src/credentials-vault.lisp
(progn
(defskill :skill-credentials-vault
:priority 200 ; High priority, foundational
:trigger (lambda (ctx) (eq (getf (getf ctx :payload) :sensor) :onboarding-request))
:neuro nil
:symbolic (lambda (action ctx)
(vault-onboard-gemini-web)
action)))
#+end_src
* Phase E: Chaos (Verification)
** 1. Unit Tests (FiveAM)
#+begin_src lisp :tangle ../tests/vault-tests.lisp
(defpackage :org-agent-vault-tests
(:use :cl :fiveam :org-agent))
(in-package :org-agent-vault-tests)
(def-suite vault-suite :description "Tests for the Credentials Vault.")
(in-suite vault-suite)
(test test-masking
(is (equal "sk-t...-key" (org-agent::vault-mask-string "sk-test-key")))
(is (equal "[REDACTED]" (org-agent::vault-mask-string "short"))))
(test test-vault-persistence
"Verify that setting a secret triggers a snapshot (mock check)."
(let ((old-version (org-agent::org-object-version (gethash "root" *object-store*))))
(org-agent:vault-set-secret :test "secret-val")
(is (> (org-agent::org-object-version (gethash "root" *object-store*)) old-version))))
#+end_src
** 2. Chaos Scenarios
- *Scenario A (Vault Poisoning):* Inject a malformed session string and verify the `llm-gateway` detects the invalid format and returns a standardized error instead of crashing.
- *Scenario B (Memory Wipe):* Clear `*vault-memory*` during runtime and verify the vault successfully re-hydrates from the Object Store (or environment fallback).
* Phase F: Memory (RCA)
- *[2026-04-09 Thu]:* Consolidated `auth-api-key` and `auth-google-oauth` into this vault. Introduced mandatory masking for all credential-related logging.