docs: rename OACP to Harness Protocol and revamp protocol.org with verbose literate text

This commit is contained in:
2026-04-12 18:54:00 -04:00
parent 5c7a925e4d
commit 117f3143d3
16 changed files with 111 additions and 82 deletions

View File

@@ -34,7 +34,7 @@ RUN sbcl --non-interactive \
# Ensure the binary is executable
RUN chmod +x /app/org-agent-server
# Expose the OACP and Web Dashboard ports
# Expose the Harness Protocol and Web Dashboard ports
EXPOSE 9105 8080
# The app expects the memex to be mounted here

View File

@@ -35,7 +35,7 @@ docker-compose up --build -d
* 4. Interaction Gateways
Once the harness is "Ready", you can interact with it via multiple sensors.
** Gateway A: Emacs (OACP)
** Gateway A: Emacs (Harness Protocol)
If you have configured the ~org-agent~ package in Emacs:
1. Open a chat buffer: ~M-x org-agent-chat-open~.
2. Send: "Are you online, agent?"

View File

@@ -24,7 +24,7 @@ flowchart TD
H -- Pointers --> S2
end
subgraph IPCSlow[External Layer]
E[Emacs / Actuators] -. OACP .-> H
E[Emacs / Actuators] -. Harness Protocol .-> H
end
#+end_src

View File

@@ -10,7 +10,7 @@ The `package.lisp` file defines the public API of the `org-agent` kernel. It exp
(defpackage :org-agent
(:use :cl)
(:export
;; --- OACP Protocol ---
;; --- Harness Protocol Protocol ---
#:frame-message
#:parse-message
#:make-hello-message

View File

@@ -1,23 +1,51 @@
#+TITLE: The Communication Protocol (protocol.lisp)
#+TITLE: The Harness Protocol (protocol.lisp)
#+AUTHOR: Amr
#+FILETAGS: :kernel:protocol:
#+FILETAGS: :harness:protocol:
#+STARTUP: content
* The Communication Protocol (protocol.lisp)
** Deep Reasoning: Why Hex-Length Framing?
Streaming raw JSON over a socket is fragile. If a 5MB Org AST is fragmented by the OS network stack, a standard parser will crash or desynchronize.
- **Physical Boundary:** By prefixing every message with a 6-character hex length, we create a deterministic physical boundary.
- **Actuator-Agnosticism:** This protocol makes the harness a "Dumb Terminal" host. Any program (Bash, Python, WebSockets) that can calculate a length and send bytes can now become an agentic interface.
* The Harness Protocol (protocol.lisp)
** Architectural Intent: Deterministic Framing & Reader Security
The Org-Agent architecture mandates that the Lisp harness operates as a perfectly deterministic, highly secure computational engine. When the harness needs to communicate with external actuators (such as an Emacs instance, a web dashboard, or a Python script), it cannot rely on loose, unpredictable data streams.
Streaming raw JSON or arbitrary text over a socket is inherently fragile. If a 5MB Org Abstract Syntax Tree (AST) representing a massive document is fragmented by the operating system's network stack during transmission, a standard stream parser might attempt to evaluate an incomplete string. This leads to immediate crashes, desynchronization, and unpredictable state corruption.
To solve this, we implemented the **Harness Protocol**, which enforces absolute deterministic boundaries around every single message crossing the wire.
*** 1. Physical Boundary via Hex-Length Prefixing
By prefixing every message with a strict 6-character hexadecimal length string, we create an unbreakable physical boundary. The Lisp reader will simply read exactly the number of bytes specified by the hex length. It will never under-read (crashing on a partial form) and never over-read (consuming bytes meant for the next message).
*** 2. Actuator-Agnosticism ("Dumb Terminal" Architecture)
This protocol enforces the "Thin Harness" principle by keeping the Lisp kernel completely agnostic of *who* is talking to it. The Lisp side does not care if the client is Emacs Lisp, a bash script using `netcat`, or a Rust binary. Any program capable of calculating a byte length, formatting a 6-character hex string, and opening a TCP socket can instantly become a full-fledged agentic interface to the Lisp Machine.
*** 3. Preventing Reader Macro Injection
Lisp's `read-from-string` is powerful because it allows executable reader macros (like `#.` which executes code during the read phase). This is a massive security vulnerability if reading untrusted network data. The Harness Protocol mandates that `*read-eval*` is explicitly bound to `nil` before any string parsing occurs, physically preventing arbitrary code execution.
** Message Framing Logic
#+begin_src mermaid
flowchart LR
subgraph Client
A[Raw Lisp Property List] --> B[Calculate Byte Length]
B --> C[Format 6-char Hex Prefix]
C --> D[Concatenate: Length + List]
end
D -- TCP Socket --> E[Harness]
subgraph Harness
E --> F[Read 6 Hex Chars]
F --> G[Read Exact Byte Count]
G --> H[Parse S-Expression]
end
#+end_src
** Package Context
We begin by ensuring we are in the correct package.
We begin by ensuring we are executing within the correct isolated package namespace.
#+begin_src lisp :tangle ../src/protocol.lisp
(in-package :org-agent)
#+end_src
** Actuator Registry
Global registry mapping target keywords to their physical actuator functions.
To maintain a decoupled architecture, the harness maintains a global registry mapping target keywords to their physical actuator functions. This allows new actuator types to be hot-loaded as skills without touching the core routing logic.
#+begin_src lisp :tangle ../src/protocol.lisp
(defvar *actuator-registry* (make-hash-table :test 'equal)
@@ -25,7 +53,7 @@ Global registry mapping target keywords to their physical actuator functions.
#+end_src
** Actuator Registration
Registers an actuator function. Actuators receive two arguments: (ACTION CONTEXT).
This is the interface for registering a new actuator function. Actuators are expected to receive two arguments: the `ACTION` property list, and the surrounding `CONTEXT`.
#+begin_src lisp :tangle ../src/protocol.lisp
(defun register-actuator (name fn)
@@ -34,16 +62,16 @@ Registers an actuator function. Actuators receive two arguments: (ACTION CONTEXT
#+end_src
** Message Framing (frame-message)
The `frame-message` function is responsible for preparing a string for transmission over the wire. It calculates the length and, if security is enabled via environment variables, appends an HMAC-SHA256 signature to guarantee message integrity.
The `frame-message` function prepares an outgoing string for transmission over the wire. It calculates the exact byte length, converts that length into a zero-padded, lowercase 6-character hex string, and prefixes it to the message. If security is enabled via environment variables, it also appends an HMAC-SHA256 cryptographic signature to guarantee message integrity against tampering.
#+begin_src lisp :tangle ../src/protocol.lisp
(defun frame-message (msg-string)
"Prefix MSG-STRING with a 6-character hex length (lowercase).
FUTURE: Will also prefix a 64-char HMAC signature when OACP_ENFORCE_HMAC=true."
If HARNESS_PROTOCOL_ENFORCE_HMAC is true, it prefixes a 64-char HMAC signature."
(let ((len (length msg-string))
(enforce-hmac (uiop:getenv "OACP_ENFORCE_HMAC")))
(enforce-hmac (uiop:getenv "HARNESS_PROTOCOL_ENFORCE_HMAC")))
(if (and enforce-hmac (string-equal enforce-hmac "true"))
(let* ((secret (or (uiop:getenv "OACP_HMAC_SECRET") "default-insecure-secret"))
(let* ((secret (or (uiop:getenv "HARNESS_PROTOCOL_HMAC_SECRET") "default-insecure-secret"))
(key (ironclad:ascii-string-to-byte-array secret))
(hmac (ironclad:make-mac :hmac key :sha256))
(payload-bytes (ironclad:ascii-string-to-byte-array msg-string)))
@@ -54,21 +82,22 @@ The `frame-message` function is responsible for preparing a string for transmiss
#+end_src
** Message Parsing (parse-message)
Parsing is the inverse of framing. This function performs three critical safety checks:
1. It validates the 6-character hex length prefix.
2. It verifies the HMAC signature (if enabled) to prevent man-in-the-middle attacks.
3. It binds `*read-eval*` to `nil` before calling `read-from-string`, preventing "Reader Macro Injection" which could otherwise execute arbitrary Lisp code during deserialization.
Parsing is the critical, high-security inverse of framing. This function acts as the final perimeter defense before strings become live Lisp code. It performs three critical safety checks:
1. **Length Validation:** It strictly validates the 6-character hex length prefix and ensures the message size matches perfectly.
2. **Integrity Validation (HMAC):** If enabled, it recalculates the cryptographic hash to prevent man-in-the-middle attacks or data corruption.
3. **Jailed Deserialization:** Most importantly, it dynamically binds `*read-eval*` to `nil`. This isolates the `read-from-string` call, completely neutralizing "Reader Macro Injection" attacks where a malicious client might try to sneak executing code inside an AST node. Finally, it calls out to `validate-harness-protocol-schema` to enforce structural property-list correctness.
#+begin_src lisp :tangle ../src/protocol.lisp
(defun parse-message (framed-string)
"Extract and parse the S-expression from a framed string, securely preventing reader macro injection."
(when (< (length framed-string) 6)
(error "Framed string too short"))
(let* ((enforce-hmac (uiop:getenv "OACP_ENFORCE_HMAC"))
(let* ((enforce-hmac (uiop:getenv "HARNESS_PROTOCOL_ENFORCE_HMAC"))
(use-hmac (and enforce-hmac (string-equal enforce-hmac "true")))
(prefix-len (if use-hmac 70 6)))
(when (< (length framed-string) prefix-len)
(error "Framed string too short for OACP signature/length"))
(error "Framed string too short for Harness Protocol signature/length"))
(let* ((len-str (subseq framed-string 0 6))
(signature (when use-hmac (subseq framed-string 6 70)))
@@ -81,24 +110,24 @@ Parsing is the inverse of framing. This function performs three critical safety
;; HMAC Validation Foundation
(when use-hmac
(let* ((secret (or (uiop:getenv "OACP_HMAC_SECRET") "default-insecure-secret"))
(let* ((secret (or (uiop:getenv "HARNESS_PROTOCOL_HMAC_SECRET") "default-insecure-secret"))
(key (ironclad:ascii-string-to-byte-array secret))
(hmac (ironclad:make-mac :hmac key :sha256))
(payload-bytes (ironclad:ascii-string-to-byte-array actual-msg)))
(ironclad:update-mac hmac payload-bytes)
(let ((expected-signature (ironclad:byte-array-to-hex-string (ironclad:produce-mac hmac))))
(unless (string-equal signature expected-signature)
(error "OACP Integrity Failure: HMAC signature mismatch")))))
(error "Harness Protocol Integrity Failure: HMAC signature mismatch")))))
;; SECURITY: Prevent Reader Macro Injection (e.g. #. ) during deserialization
(let ((*read-eval* nil))
(let ((msg (read-from-string actual-msg)))
(validate-oacp-schema msg)
(validate-harness-protocol-schema msg)
msg)))))
#+end_src
** Handshaking (make-hello-message)
Every OACP connection begins with a `HELLO` handshake. This function constructs the standard response that the harness sends to a client to announce its capabilities and version.
Every connection begins with a strict `HELLO` handshake. This function constructs the standard response that the harness sends to any connecting client, announcing its current capabilities, authentication requirements, and the protocol version. This allows clients to adapt dynamically if the harness topology changes.
#+begin_src lisp :tangle ../src/protocol.lisp
(defun make-hello-message (version)

View File

@@ -42,7 +42,7 @@
(defsystem :org-agent/tests
:depends-on (:org-agent :fiveam)
:components ((:file "tests/oacp-tests")
:components ((:file "tests/harness-protocol-tests")
(:file "tests/pipeline-tests")
(:file "tests/peripheral-vision-tests")
(:file "tests/safety-harness-tests")
@@ -61,7 +61,7 @@
(:file "tests/playwright-tests")
(:file "tests/chaos-qa"))
:perform (test-op (o s)
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :oacp-suite :org-agent-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :harness-protocol-suite :org-agent-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :pipeline-suite :org-agent-pipeline-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :vision-suite :org-agent-peripheral-vision-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :safety-suite :org-agent-safety-tests))

View File

@@ -37,7 +37,7 @@
(defsystem :org-agent/tests
:depends-on (:org-agent :fiveam)
:components ((:file "tests/oacp-tests")
:components ((:file "tests/protocol-tests")
(:file "tests/pipeline-tests")
(:file "tests/peripheral-vision-tests")
(:file "tests/safety-harness-tests")
@@ -56,7 +56,7 @@
(:file "tests/playwright-tests")
(:file "tests/chaos-qa"))
:perform (test-op (o s)
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :oacp-suite :org-agent-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :harness-protocol-suite :org-agent-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :pipeline-suite :org-agent-pipeline-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :vision-suite :org-agent-peripheral-vision-tests))
(uiop:symbol-call :fiveam :run! (uiop:find-symbol* :safety-suite :org-agent-safety-tests))

View File

@@ -20,7 +20,7 @@ The *Chaos Gauntlet* is an adversarial testing skill designed to ensure the syst
Verify the system's stability and error-handling capabilities under stress.
** 2. User Needs
- *Failure Simulation:* Ability to inject artificial delays or errors into the OACP bus.
- *Failure Simulation:* Ability to inject artificial delays or errors into the Harness Protocol bus.
- *Byzantine Response Testing:* Test how System 2 handles nonsensical or malicious System 1 proposals.
- *Network Resilience:* Simulate Gitea or LLM provider timeouts.
- *Recovery Verification:* Ensure the harness can recover from a "skip-event" restart.

View File

@@ -1,13 +1,13 @@
:PROPERTIES:
:ID: org-skill-oacp-validator
:ID: org-skill-harness-protocol-validator
:CREATED: [2026-04-12 Sun 14:35]
:END:
#+TITLE: SKILL: OACP Schema Validator (Universal Literate Note)
#+TITLE: SKILL: Harness Protocol Schema Validator (Universal Literate Note)
#+STARTUP: content
#+FILETAGS: :protocol:oacp:security:validation:psf:
#+FILETAGS: :protocol:harness-protocol:security:validation:psf:
* Overview
The *OACP Schema Validator* skill provides deep structural validation for all messages entering the org-agent kernel. It ensures that every property list adheres to a strict schema, preventing malformed data from causing harness-level errors.
The *Harness Protocol Schema Validator* skill provides deep structural validation for all messages entering the org-agent kernel. It ensures that every property list adheres to a strict schema, preventing malformed data from causing harness-level errors.
* Phase A: Demand (PRD)
:PROPERTIES:
@@ -15,7 +15,7 @@ The *OACP Schema Validator* skill provides deep structural validation for all me
:END:
** 1. Purpose
Enforce a formal grammar for the Org-Agent Control Protocol (OACP).
Enforce a formal grammar for the Org-Agent Control Protocol (Harness Protocol).
** 2. User Needs
- *Type Safety:* Ensure mandatory keys (e.g., `:type`, `:payload`) are present.
@@ -38,7 +38,7 @@ Decouple protocol parsing (framing/unframing) from semantic validation.
** 2. Semantic Interfaces
#+begin_src lisp
(defun validate-oacp-schema (msg)
(defun validate-harness-protocol-schema (msg)
"Returns T if the message is valid, NIL (and signals error) otherwise.")
#+end_src
@@ -48,44 +48,44 @@ Decouple protocol parsing (framing/unframing) from semantic validation.
#+begin_src lisp :tangle ../src/protocol-validator.lisp
(in-package :org-agent)
(defun validate-oacp-schema (msg)
"Strict structural validation for incoming OACP messages."
(defun validate-harness-protocol-schema (msg)
"Strict structural validation for incoming Harness Protocol messages."
(unless (listp msg)
(error "OACP Schema Error: Message must be a property list (got ~s)" (type-of msg)))
(error "Harness Protocol Schema Error: Message must be a property list (got ~s)" (type-of msg)))
(let ((type (getf msg :type)))
(unless (member type '(:REQUEST :EVENT :RESPONSE :LOG))
(error "OACP Schema Error: Invalid message type '~a'" type))
(error "Harness Protocol Schema Error: Invalid message type '~a'" type))
(case type
(:REQUEST
(unless (getf msg :target)
(error "OACP Schema Error: REQUEST missing mandatory :target"))
(error "Harness Protocol Schema Error: REQUEST missing mandatory :target"))
(unless (getf msg :payload)
(error "OACP Schema Error: REQUEST missing mandatory :payload")))
(error "Harness Protocol Schema Error: REQUEST missing mandatory :payload")))
(:EVENT
(let ((payload (getf msg :payload)))
(unless (and payload (listp payload))
(error "OACP Schema Error: EVENT missing or invalid :payload"))
(error "Harness Protocol Schema Error: EVENT missing or invalid :payload"))
(unless (or (getf payload :action) (getf payload :sensor))
(error "OACP Schema Error: EVENT payload must contain :action or :sensor"))))
(error "Harness Protocol Schema Error: EVENT payload must contain :action or :sensor"))))
(:RESPONSE
(unless (getf msg :payload)
(error "OACP Schema Error: RESPONSE missing mandatory :payload"))))
(error "Harness Protocol Schema Error: RESPONSE missing mandatory :payload"))))
t))
#+end_src
* Registration
#+begin_src lisp :tangle ../src/protocol-validator.lisp
(defskill :skill-oacp-validator
(defskill :skill-harness-protocol-validator
:priority 95
:trigger (lambda (ctx) (member (getf (getf ctx :payload) :sensor) '(:protocol-received)))
:neuro nil
:symbolic (lambda (action ctx)
(declare (ignore ctx))
(validate-oacp-schema action)
(validate-harness-protocol-schema action)
action))
#+end_src

View File

@@ -54,7 +54,7 @@ Define the core functional and security requirements for the neurosymbolic harne
** 3. Success Criteria
*** TODO Harness Lisp stability (Heartbeat consistency)
*** TODO OACP communication reliability
*** TODO Harness Protocol communication reliability
*** TODO Org AST-to-Lisp conversion fidelity
*** TODO Deliberate Safety Gating (The Harness) enforcement
@@ -64,7 +64,7 @@ Define the core functional and security requirements for the neurosymbolic harne
:END:
** 1. Architectural Intent
The harness is transport-agnostic and business-logic-agnostic. It communicates with external actuators (Emacs, Web, Signal) via the Org-Agent Communication Protocol (OACP).
The harness is transport-agnostic and business-logic-agnostic. It communicates with external actuators (Emacs, Web, Signal) via the Org-Agent Communication Protocol (Harness Protocol).
** 2. Semantic Interfaces
#+begin_src lisp

View File

@@ -12,7 +12,7 @@
;; org-agent provides a Neurosymbolic Lisp Machine interface for Emacs.
;; It acts as the sensor/actuator array, communicating with a persistent
;; Common Lisp daemon over a high-speed OACP socket.
;; Common Lisp daemon over a high-speed Harness Protocol socket.
;;; Code:
@@ -100,7 +100,7 @@ will assume you have started it manually (e.g., via SBCL)."
(message "org-agent: Killed daemon process.")))
(defun org-agent--filter (proc string)
"Handle incoming OACP messages from the daemon via PROC with STRING."
"Handle incoming Harness Protocol messages from the daemon via PROC with STRING."
(let ((buf (process-buffer proc)))
(when (buffer-live-p buf)
(with-current-buffer buf
@@ -109,7 +109,7 @@ will assume you have started it manually (e.g., via SBCL)."
(org-agent--process-buffer buf proc)))))
(defun org-agent--process-buffer (buffer &optional proc)
"Process the OACP message BUFFER, optionally using PROC."
"Process the Harness Protocol message BUFFER, optionally using PROC."
(with-current-buffer buffer
(goto-char (point-min))
(while (>= (buffer-size) 6)
@@ -127,13 +127,13 @@ will assume you have started it manually (e.g., via SBCL)."
(setq msg-len 1000000)))))) ; Break loop
(defun org-agent--plist-get (plist prop)
"Case-insensitive keyword lookup for OACP compatibility."
"Case-insensitive keyword lookup for Harness Protocol compatibility."
(or (plist-get plist prop)
(plist-get plist (intern (upcase (symbol-name prop))))
(plist-get plist (intern (downcase (symbol-name prop))))))
(defun org-agent--handle-message (proc plist)
"Route and execute incoming OACP messages from PROC using PLIST."
"Route and execute incoming Harness Protocol messages from PROC using PLIST."
(let ((type (org-agent--plist-get plist :type))
(id (org-agent--plist-get plist :id))
(payload (or (org-agent--plist-get plist :payload) plist)))
@@ -190,7 +190,7 @@ will assume you have started it manually (e.g., via SBCL)."
(message "org-agent: Connection lost.")))
(defun org-agent-send (plist)
"Send a Lisp PLIST to the daemon using OACP framing."
"Send a Lisp PLIST to the daemon using Harness Protocol framing."
(let* ((msg (prin1-to-string plist))
(len (length msg))
(framed (format "%06x%s" len msg)))

View File

@@ -1,7 +1,7 @@
(defpackage :org-agent
(:use :cl)
(:export
;; --- OACP Protocol ---
;; --- Harness Protocol Protocol ---
#:frame-message
#:parse-message
#:make-hello-message

View File

@@ -1,39 +1,39 @@
(in-package :org-agent)
(defun validate-oacp-schema (msg)
"Strict structural validation for incoming OACP messages."
(defun validate-harness-protocol-schema (msg)
"Strict structural validation for incoming Harness Protocol messages."
(unless (listp msg)
(error "OACP Schema Error: Message must be a property list (got ~s)" (type-of msg)))
(error "Harness Protocol Schema Error: Message must be a property list (got ~s)" (type-of msg)))
(let ((type (getf msg :type)))
(unless (member type '(:REQUEST :EVENT :RESPONSE :LOG))
(error "OACP Schema Error: Invalid message type '~a'" type))
(error "Harness Protocol Schema Error: Invalid message type '~a'" type))
(case type
(:REQUEST
(unless (getf msg :target)
(error "OACP Schema Error: REQUEST missing mandatory :target"))
(error "Harness Protocol Schema Error: REQUEST missing mandatory :target"))
(unless (getf msg :payload)
(error "OACP Schema Error: REQUEST missing mandatory :payload")))
(error "Harness Protocol Schema Error: REQUEST missing mandatory :payload")))
(:EVENT
(let ((payload (getf msg :payload)))
(unless (and payload (listp payload))
(error "OACP Schema Error: EVENT missing or invalid :payload"))
(error "Harness Protocol Schema Error: EVENT missing or invalid :payload"))
(unless (or (getf payload :action) (getf payload :sensor))
(error "OACP Schema Error: EVENT payload must contain :action or :sensor"))))
(error "Harness Protocol Schema Error: EVENT payload must contain :action or :sensor"))))
(:RESPONSE
(unless (getf msg :payload)
(error "OACP Schema Error: RESPONSE missing mandatory :payload"))))
(error "Harness Protocol Schema Error: RESPONSE missing mandatory :payload"))))
t))
(defskill :skill-oacp-validator
(defskill :skill-harness-protocol-validator
:priority 95
:trigger (lambda (ctx) (member (getf (getf ctx :payload) :sensor) '(:protocol-received)))
:neuro nil
:symbolic (lambda (action ctx)
(declare (ignore ctx))
(validate-oacp-schema action)
(validate-harness-protocol-schema action)
action))

View File

@@ -9,11 +9,11 @@
(defun frame-message (msg-string)
"Prefix MSG-STRING with a 6-character hex length (lowercase).
FUTURE: Will also prefix a 64-char HMAC signature when OACP_ENFORCE_HMAC=true."
If HARNESS_PROTOCOL_ENFORCE_HMAC is true, it prefixes a 64-char HMAC signature."
(let ((len (length msg-string))
(enforce-hmac (uiop:getenv "OACP_ENFORCE_HMAC")))
(enforce-hmac (uiop:getenv "HARNESS_PROTOCOL_ENFORCE_HMAC")))
(if (and enforce-hmac (string-equal enforce-hmac "true"))
(let* ((secret (or (uiop:getenv "OACP_HMAC_SECRET") "default-insecure-secret"))
(let* ((secret (or (uiop:getenv "HARNESS_PROTOCOL_HMAC_SECRET") "default-insecure-secret"))
(key (ironclad:ascii-string-to-byte-array secret))
(hmac (ironclad:make-mac :hmac key :sha256))
(payload-bytes (ironclad:ascii-string-to-byte-array msg-string)))
@@ -26,11 +26,11 @@
"Extract and parse the S-expression from a framed string, securely preventing reader macro injection."
(when (< (length framed-string) 6)
(error "Framed string too short"))
(let* ((enforce-hmac (uiop:getenv "OACP_ENFORCE_HMAC"))
(let* ((enforce-hmac (uiop:getenv "HARNESS_PROTOCOL_ENFORCE_HMAC"))
(use-hmac (and enforce-hmac (string-equal enforce-hmac "true")))
(prefix-len (if use-hmac 70 6)))
(when (< (length framed-string) prefix-len)
(error "Framed string too short for OACP signature/length"))
(error "Framed string too short for Harness Protocol signature/length"))
(let* ((len-str (subseq framed-string 0 6))
(signature (when use-hmac (subseq framed-string 6 70)))
@@ -43,19 +43,19 @@
;; HMAC Validation Foundation
(when use-hmac
(let* ((secret (or (uiop:getenv "OACP_HMAC_SECRET") "default-insecure-secret"))
(let* ((secret (or (uiop:getenv "HARNESS_PROTOCOL_HMAC_SECRET") "default-insecure-secret"))
(key (ironclad:ascii-string-to-byte-array secret))
(hmac (ironclad:make-mac :hmac key :sha256))
(payload-bytes (ironclad:ascii-string-to-byte-array actual-msg)))
(ironclad:update-mac hmac payload-bytes)
(let ((expected-signature (ironclad:byte-array-to-hex-string (ironclad:produce-mac hmac))))
(unless (string-equal signature expected-signature)
(error "OACP Integrity Failure: HMAC signature mismatch")))))
(error "Harness Protocol Integrity Failure: HMAC signature mismatch")))))
;; SECURITY: Prevent Reader Macro Injection (e.g. #. ) during deserialization
(let ((*read-eval* nil))
(let ((msg (read-from-string actual-msg)))
(validate-oacp-schema msg)
(validate-harness-protocol-schema msg)
msg)))))
(defun make-hello-message (version)

View File

@@ -15,7 +15,7 @@
(should (string= "000014(:type :EVENT :id 1)" captured-framed)))))
(ert-deftest test-org-agent-parsing ()
"Verify that the filter correctly parses OACP framed messages."
"Verify that the filter correctly parses Harness Protocol framed messages."
(let ((mock-buffer (generate-new-buffer " *org-agent-test*"))
(received-plist nil))
(cl-letf (((symbol-function 'org-agent--handle-message)

View File

@@ -2,9 +2,9 @@
(:use :cl :fiveam :org-agent))
(in-package :org-agent-tests)
(def-suite oacp-suite
:description "Test suite for org-agent Communication Protocol (OACP)")
(in-suite oacp-suite)
(def-suite harness-protocol-suite
:description "Test suite for org-agent Communication Protocol (Harness Protocol)")
(in-suite harness-protocol-suite)
(test test-framing
"Verify that messages are correctly prefixed with a 6-character hex length."