Some checks failed
Deploy (Gitea) / deploy (push) Failing after 3s
1. Shell actuator: remove double bash -c wrapping (format ~s produces S-expression-safe strings, not shell-safe). Now passes cmd directly to (timeout N bash -c cmd) via run-program arg list. 2. Dispatcher: extend high-impact approval gate to :system :eval. Previously only :shell, :tool "shell", and :emacs :eval triggered HITL. Now :system :eval also requires Flight Plan approval. 3. Skill sandbox: before promoting a skill from its jailed package to :passepartout, scan for restricted symbol references (uiop:run-program, uiop:shell, uiop:run-shell-command). Block promotion on violation. New skill-entry status :sandbox-blocked for blocked skills. Test: 91 pass, 0 fail across 13 suites.
52 lines
2.5 KiB
Org Mode
52 lines
2.5 KiB
Org Mode
#+TITLE: SKILL: Shell Actuator (org-skill-shell-actuator.org)
|
|
#+AUTHOR: Agent
|
|
#+FILETAGS: :skill:actuator:shell:
|
|
#+PROPERTY: header-args:lisp :tangle ../lisp/system-actuator-shell.lisp
|
|
|
|
* Overview: The Physical Actuator
|
|
|
|
The Shell Actuator is the agent's hand in the physical world. Given a shell command, it executes it via ~bash -c~ and returns the output. This is how the agent installs packages, reads files, runs scripts, and interacts with any Unix tool.
|
|
|
|
Because shell execution is the highest-risk operation in the system, the Shell Actuator is protected by multiple safety layers:
|
|
1. The Bouncer's shell safety gate blocks destructive commands (~rm -rf /~, ~dd~, ~mkfs~)
|
|
2. The Bouncer's injection gate blocks backtick and ~$()~ patterns
|
|
3. The Bouncer's network exfil gate blocks connections to unwhitelisted hosts
|
|
4. The actuator enforces a timeout (default 30s) so hanging commands don't freeze the agent
|
|
5. The actuator caps output (default 100KB) so infinite output doesn't exhaust memory
|
|
|
|
* Implementation
|
|
|
|
** Shell Execution (actuator-shell-execute)
|
|
;; REPL-VERIFIED: 2026-05-03T13:00:00
|
|
#+begin_src lisp
|
|
(defun actuator-shell-execute (action context)
|
|
"Executes a shell command via the OS timeout binary with output limit."
|
|
(declare (ignore context))
|
|
(let* ((payload (getf action :payload))
|
|
(cmd (getf payload :cmd))
|
|
(timeout-sym (find-symbol "*BOUNCER-SHELL-TIMEOUT*" :passepartout))
|
|
(timeout (or (getf payload :timeout) (if timeout-sym (symbol-value timeout-sym) 30)))
|
|
(max-sym (find-symbol "*BOUNCER-SHELL-MAX-OUTPUT*" :passepartout))
|
|
(max-output (or (getf payload :max-output) (if max-sym (symbol-value max-sym) 100000))))
|
|
(log-message "ACT [Shell]: ~a (timeout: ~as)" cmd timeout)
|
|
(multiple-value-bind (out err code)
|
|
(uiop:run-program (list "timeout" (format nil "~a" timeout) "bash" "-c" cmd)
|
|
:output :string :error-output :string
|
|
:ignore-error-status t)
|
|
(cond
|
|
((= code 124) (format nil "ERROR: Command timed out after ~a seconds" timeout))
|
|
((> (length out) max-output)
|
|
(format nil "~a~%... (output truncated to ~a chars)" (subseq out 0 max-output) max-output))
|
|
((= code 0) out)
|
|
(t (format nil "ERROR [~a]: ~a" code err))))))
|
|
#+end_src
|
|
|
|
** Skill Registration
|
|
#+begin_src lisp
|
|
(register-actuator :shell #'actuator-shell-execute)
|
|
|
|
(defskill :passepartout-system-actuator-shell
|
|
:priority 50
|
|
:trigger (lambda (ctx) (declare (ignore ctx)) nil))
|
|
#+end_src
|