Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 2s
- Updated all 150+ :tangle headers across harness/ and skills/ to use elisp (expand-file-name) to target INSTALL_DIR dynamically. - Cleaned up environment/ directory depth by moving memory-image.lisp to state/. - Moved test scripts to tests/ and deleted redundant chat scripts.
160 lines
6.6 KiB
Org Mode
160 lines
6.6 KiB
Org Mode
:PROPERTIES:
|
|
:ID: tool-permissions-skill-001
|
|
:CREATED: [2026-04-23 Thu]
|
|
:END:
|
|
#+TITLE: SKILL: Tool Permission Tiers
|
|
#+STARTUP: content
|
|
#+FILETAGS: :security:permissions:tool:
|
|
|
|
* Overview
|
|
This skill implements tool permission tiers for security - controlling which cognitive tools can execute without user interaction.
|
|
|
|
Also provides vector embeddings via Ollama or llama.cpp.
|
|
|
|
** The Three Tiers
|
|
|
|
| Tier | Behavior | Use Case |
|
|
|------|----------|----------|
|
|
| =:allow= | Executes immediately | Trusted, safe tools |
|
|
| =:deny= | Blocks before execution | Dangerous tools |
|
|
| =:ask= | Prompts user, pauses execution | Sensitive tools |
|
|
|
|
** Embedding Providers
|
|
- =EMBEDDING_PROVIDER= environment: "ollama" or "llama.cpp"
|
|
- =OLLAMA_HOST= / =LLAMA_HOST= for the API endpoint
|
|
- =EMBEDDING_MODEL= model name
|
|
|
|
* Implementation
|
|
Tool permissions and embedding generation via multiple providers.
|
|
|
|
#+begin_src lisp :tangle (expand-file-name "org-skill-tool-permissions.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/skills"))
|
|
(in-package :opencortex)
|
|
|
|
(defvar *tool-permissions* (make-hash-table :test 'equal)
|
|
"Hash table mapping tool names to :allow/:deny/:ask.")
|
|
|
|
(defun get-tool-permission (tool-name)
|
|
(let ((key (string-downcase (string tool-name))))
|
|
(or (gethash key *tool-permissions*) :allow)))
|
|
|
|
(defun set-tool-permission (tool-name tier)
|
|
(setf (gethash (string-downcase (string tool-name)) *tool-permissions*) tier)
|
|
(harness-log "TOOL PERMISSION: Set ~a = ~a" tool-name tier))
|
|
|
|
(defun check-tool-permission-gate (tool-name context)
|
|
(declare (ignore context))
|
|
(let ((perm (get-tool-permission tool-name)))
|
|
(case perm
|
|
(:allow :allow)
|
|
(:deny :deny)
|
|
(:ask (list :ask tool-name context))
|
|
(t :allow))))
|
|
|
|
(def-cognitive-tool :get-embedding
|
|
"Generates vector embeddings via Ollama or llama.cpp API."
|
|
((:text :type :string :description "Text to embed."))
|
|
:body (lambda (args)
|
|
(let* ((text (getf args :text))
|
|
(provider (or (uiop:getenv "EMBEDDING_PROVIDER") "ollama"))
|
|
(model (or (uiop:getenv "EMBEDDING_MODEL") "nomic-embed-text"))
|
|
(embedding nil))
|
|
(cond
|
|
((string= provider "ollama")
|
|
(let* ((host (or (uiop:getenv "OLLAMA_HOST") "localhost:11434"))
|
|
(url (format nil "http://~a/api/embeddings" host))
|
|
(body (cl-json:encode-json-to-string `((model . ,model) (prompt . ,text)))))
|
|
(handler-case
|
|
(let* ((response (dex:post url :headers '(("Content-Type" . "application/json")) :content body :connect-timeout 5 :read-timeout 30))
|
|
(json (cl-json:decode-json-from-string response))
|
|
(vec (cdr (assoc :embedding json))))
|
|
(when vec (setf embedding vec)))
|
|
(error (c) (harness-log "EMBEDDING: Ollama failed: ~a" c)))))
|
|
((string= provider "llama.cpp")
|
|
(let* ((host (or (uiop:getenv "LLAMA_HOST") "localhost:8080"))
|
|
(url (format nil "http://~a/v1/embeddings" host))
|
|
(body (cl-json:encode-json-to-string `((model . ,model) (input . ,text)))))
|
|
(handler-case
|
|
(let* ((response (dex:post url :headers '(("Content-Type" . "application/json")) :content body :connect-timeout 5 :read-timeout 30))
|
|
(json (cl-json:decode-json-from-string response))
|
|
(data (cdr (assoc :data json)))
|
|
(vec (when data (cdr (assoc :embedding (car data))))))
|
|
(when vec (setf embedding vec)))
|
|
(error (c) (harness-log "EMBEDDING: llama.cpp failed: ~a" c))))))
|
|
(if embedding
|
|
(list :status :success :vector embedding)
|
|
(list :status :error :message "Embedding generation failed")))))
|
|
|
|
(def-cognitive-tool :tool-permissions
|
|
"View or set tool permission tiers."
|
|
((:tool :type :string :description "Tool name")
|
|
(:action :type :keyword :description "Action: :get, :set, :list" :default :get)
|
|
(:tier :type :keyword :description "For :set: :allow/:deny/:ask"))
|
|
:body (lambda (args)
|
|
(let ((tool (getf args :tool))
|
|
(action (getf args :action :get))
|
|
(tier (getf args :tier)))
|
|
(case action
|
|
(:get (list :status :success :tool tool :permission (get-tool-permission tool)))
|
|
(:set (progn (set-tool-permission tool tier)
|
|
(list :status :success :message (format nil "Set ~a = ~a" tool tier))))
|
|
(:list (let ((r nil))
|
|
(maphash (lambda (k v) (push (list :tool k :permission v) r)) *tool-permissions*)
|
|
(list :status :success :tools r)))
|
|
(t (list :status :error :message "Invalid action"))))))
|
|
|
|
;; Defaults
|
|
(set-tool-permission :shell :deny)
|
|
(set-tool-permission :delete-file :deny)
|
|
(set-tool-permission :eval :ask)
|
|
(set-tool-permission :write-file :ask)
|
|
(harness-log "TOOL PERMISSIONS: Initialized")
|
|
|
|
(defskill :skill-tool-permissions
|
|
:priority 600
|
|
:trigger (lambda (c) (declare (ignore c)) nil)
|
|
:deterministic (lambda (a c)
|
|
(let ((tool (getf (getf a :payload) :tool)))
|
|
(when tool (check-tool-permission-gate tool c)))))
|
|
#+end_src
|
|
|
|
* Test Suite
|
|
|
|
These tests verify tool permissions. Run with:
|
|
~(fiveam:run! 'tool-permissions-suite)~
|
|
|
|
#+begin_src lisp :tangle (expand-file-name "tests/tool-permissions-tests.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/skills"))
|
|
(defpackage :opencortex-tool-permissions-tests
|
|
(:use :cl :fiveam :opencortex)
|
|
(:export #:tool-permissions-suite))
|
|
|
|
(in-package :opencortex-tool-permissions-tests)
|
|
|
|
(def-suite tool-permissions-suite
|
|
:description "Tests for Tool Permissions skill")
|
|
|
|
(in-suite tool-permissions-suite)
|
|
|
|
(test default-permission-is-allow
|
|
"Verify default permission is :allow."
|
|
(is (eq (get-tool-permission "unknown-tool") :allow)))
|
|
|
|
(test set-and-get-permission
|
|
"Verify setting and getting permissions."
|
|
(set-tool-permission "test-tool-abc" :deny)
|
|
(is (eq (get-tool-permission "test-tool-abc") :deny)))
|
|
|
|
(test permission-gate-allow
|
|
"Verify :allow tier passes through."
|
|
(set-tool-permission "gate-allow-tool" :allow)
|
|
(is (eq (check-tool-permission-gate "gate-allow-tool" nil) :allow)))
|
|
|
|
(test permission-gate-deny
|
|
"Verify :deny tier blocks."
|
|
(set-tool-permission "gate-deny-tool" :deny)
|
|
(is (eq (check-tool-permission-gate "gate-deny-tool" nil) :deny)))
|
|
|
|
(test permission-gate-ask
|
|
"Verify :ask tier returns ask list."
|
|
(set-tool-permission "gate-ask-tool" :ask)
|
|
(is (listp (check-tool-permission-gate "gate-ask-tool" nil))))
|
|
#+end_src |