#+TITLE: SKILL: Credentials Vault (org-skill-credentials-vault.org) #+AUTHOR: Agent #+FILETAGS: :system:security:vault: #+PROPERTY: header-args:lisp :tangle ../lisp/security-vault.lisp * Overview The *Credentials Vault* provides secure in-memory storage for sensitive API keys and session tokens. * Architectural Intent The Credentials Vault isolates secrets from the rest of the system in a dedicated hash-table. It provides simple get/set primitives with environment-variable fallback for known providers. This is the single place where credentials enter the system — every provider skill routes through here. ** Contract 1. (vault-set provider secret &key type): stores secret under ~(format nil "~a-~a" provider type)~ in ~*vault-memory*~. 2. (vault-get provider &key type): returns the stored secret, or falls back to the appropriate environment variable for known providers (~:openai~, ~:anthropic~, ~:openrouter~, ~:gemini~). Returns NIL if neither exists. 3. (vault-get-secret provider): wrapper — calls ~vault-get~ with ~:type :secret~. 4. (vault-set-secret provider secret): wrapper — calls ~vault-set~ with ~:type :secret~. 5. Vault isolation: storing a secret for provider A does not affect provider B's entry. Different ~:type~ values produce different keys. ** Boundaries - Does NOT encrypt at rest — that is the session layer's responsibility. - Does NOT validate key format — the provider skill does that. - Does NOT rotate or expire keys — this is a simple store. * Implementation ** Package Context #+begin_src lisp (in-package :passepartout) #+end_src ** Vault Storage ;; REPL-VERIFIED: 2026-05-03T13:00:00 #+begin_src lisp (defvar *vault-memory* (make-hash-table :test 'equal) "In-memory cache of sensitive credentials.") #+end_src ** Secret Management ;; REPL-VERIFIED: 2026-05-03T13:00:00 #+begin_src lisp (defun vault-get (provider &key (type :api-key)) "Retrieves a credential from the vault or environment." (let* ((key (format nil "~a-~a" provider type)) (val (gethash key *vault-memory*))) (if val val (let ((env-var (case provider (:gemini "GEMINI_API_KEY") (:openai "OPENAI_API_KEY") (:anthropic "ANTHROPIC_API_KEY") (:openrouter "OPENROUTER_API_KEY") (otherwise nil)))) (when env-var (uiop:getenv env-var)))))) #+end_src ** vault-set ;; REPL-VERIFIED: 2026-05-03T13:00:00 #+begin_src lisp (defun vault-set (provider secret &key (type :api-key)) "Stores a secret in the vault." (let ((key (format nil "~a-~a" provider type))) (setf (gethash key *vault-memory*) secret))) #+end_src ** Secret Wrappers (gateway-messaging) Thin wrappers that match the export names used by =gateway-messaging=. Delegates to the existing =vault-get=/=vault-set= with ~:type :secret~. ;; REPL-VERIFIED: 2026-05-03T13:00:00 #+begin_src lisp (defun vault-get-secret (provider) "Retrieves a stored secret or token for a gateway provider." (vault-get provider :type :secret)) #+end_src ** vault-set-secret ;; REPL-VERIFIED: 2026-05-03T13:00:00 #+begin_src lisp (defun vault-set-secret (provider secret) "Stores a secret or token for a gateway provider." (vault-set provider secret :type :secret)) #+end_src ** Skill Registration #+begin_src lisp (defskill :passepartout-security-vault :priority 600 :trigger (lambda (ctx) (declare (ignore ctx)) nil)) #+end_src ** Vault Memory (relocated from core-skills) #+begin_src lisp (defvar *VAULT-MEMORY* (make-hash-table :test 'equal)) #+end_src * Test Suite #+begin_src lisp (eval-when (:compile-toplevel :load-toplevel :execute) (ql:quickload :fiveam :silent t)) (defpackage :passepartout-security-vault-tests (:use :cl :fiveam :passepartout) (:export #:vault-suite)) (in-package :passepartout-security-vault-tests) (def-suite vault-suite :description "Verification of the Credentials Vault") (in-suite vault-suite) (test test-vault-round-trip "Contract 1: vault-set stores a value; vault-get retrieves it." (let ((test-key :vault-test-round-trip) (test-secret "secret-abc123")) (vault-set test-key test-secret) (is (string= test-secret (vault-get test-key))) ;; Clean up (vault-set test-key nil))) (test test-vault-missing-key "Contract 2: vault-get returns NIL for an unset, unknown provider." (is (null (vault-get :nonexistent-provider-xyz)))) (test test-vault-isolation "Contract 5: storing for provider A does not affect provider B." (vault-set :vault-prov-a "secret-a") (vault-set :vault-prov-b "secret-b") (is (string= "secret-a" (vault-get :vault-prov-a))) (is (string= "secret-b" (vault-get :vault-prov-b))) (vault-set :vault-prov-a nil) (vault-set :vault-prov-b nil)) (test test-vault-secret-wrappers "Contracts 3,4: vault-get-secret and vault-set-secret use :type :secret." (let ((test-provider :vault-secret-test)) (vault-set-secret test-provider "my-token") (is (string= "my-token" (vault-get-secret test-provider))) ;; Clean up (vault-set-secret test-provider nil))) (test test-vault-type-isolation "Contract 5: different :type values produce different keys." (vault-set :vault-type-test "key-value" :type :api-key) (vault-set :vault-type-test "secret-value" :type :secret) (is (string= "key-value" (vault-get :vault-type-test :type :api-key))) (is (string= "secret-value" (vault-get :vault-type-test :type :secret))) (vault-set :vault-type-test nil :type :api-key) (vault-set :vault-type-test nil :type :secret)) #+end_src