Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "axonflow",
"displayName": "AxonFlow Governance",
"description": "Policy enforcement, PII detection, and audit trails for OpenAI Codex. Hybrid governance — enforces policies on terminal commands (exec_command) via hooks, provides advisory governance for other tools via implicit-activation skills, and records compliance-grade audit trails. Self-hosted via Docker — all data stays on your infrastructure.",
"version": "0.1.0",
"version": "0.2.0",
"author": {
"name": "AxonFlow",
"email": "hello@getaxonflow.com",
Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Changelog

## [Unreleased]
## [0.2.0] - 2026-04-09

### Changed

- **Hook fail-open/fail-closed hardening (issue #1545 Direction 3).** `scripts/pre-tool-check.sh` now distinguishes curl exit code (network failure) from HTTP success with an error body. Fail-closed (exit 2, block tool) only on operator-fixable JSON-RPC errors: auth failures (-32001), method-not-found (-32601), and invalid-params (-32602). Fail-open (exit 0, allow) on everything else: curl timeouts/DNS failures/connection refused, empty response, server-internal errors (-32603), parse errors (-32700), and unknown error codes. Prevents transient governance infrastructure issues from blocking legitimate dev workflows while still catching broken configurations.

### Added

- **`scripts/uninstall.sh` cleanup helper.** Codex CLI's built-in `/plugins` uninstall only removes the registration from `~/.codex/config.toml` and leaves the local-source plugin cache directory on disk. The new helper cleans up `~/.codex/plugins/cache/axonflow-local/`, `~/.codex/plugins/cache/axonflow-codex-plugin/`, and `~/.codex/plugins/installed/axonflow-codex-plugin/`. Supports `--dry-run`. Surfaces but does not modify `~/.codex/config.toml` or `~/.codex/hooks.json` (user-owned configuration).

### Security

Expand Down
54 changes: 41 additions & 13 deletions scripts/pre-tool-check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,12 @@ if [ -z "$STATEMENT" ] || [ "$STATEMENT" = "null" ] || [ "$STATEMENT" = "{}" ];
exit 0
fi

# Call AxonFlow check_policy via MCP server
RESPONSE=$(curl -s --max-time "$REQUEST_TIMEOUT_SECONDS" -X POST "${ENDPOINT}/api/v1/mcp-server" \
# Call AxonFlow check_policy via MCP server.
#
# Issue #1545 Direction 3: fail OPEN on any network-level failure (timeout,
# DNS failure, connection refused, 5xx). Only auth/config errors reported
# by AxonFlow fail closed (see the JSONRPC_ERROR handling below).
RESPONSE=$(curl -sS --max-time "$REQUEST_TIMEOUT_SECONDS" -X POST "${ENDPOINT}/api/v1/mcp-server" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
"${AUTH_HEADER[@]}" \
Expand All @@ -99,25 +103,49 @@ RESPONSE=$(curl -s --max-time "$REQUEST_TIMEOUT_SECONDS" -X POST "${ENDPOINT}/ap
operation: "execute"
}
}
}')" 2>/dev/null || echo "")
}')" 2>/dev/null)
CURL_EXIT=$?

# Any curl-level failure (exit != 0) means the network call failed —
# timeout, DNS failure, connection refused, TCP reset. Fail open.
if [ "$CURL_EXIT" -ne 0 ]; then
exit 0
fi

# If AxonFlow is unreachable (empty response = network failure), fail-open
# Empty body from an otherwise-successful curl should also fail open
# (ambiguous: could be 204 No Content, could be a weird proxy).
if [ -z "$RESPONSE" ]; then
exit 0
fi

# Check for JSON-RPC error responses (auth failure, server error, etc.)
# Fail CLOSED on auth/config errors to prevent silent governance bypass.
# Check for JSON-RPC error responses and apply the fail-open / fail-closed
# policy from issue #1545 Direction 3:
#
# Fail CLOSED only on auth/config errors — where the operator can actually
# fix the problem — so a broken governance setup can never be silently
# bypassed. Network errors, server-internal errors, parse errors, and
# timeouts all fail OPEN to avoid blocking legitimate dev workflows on
# transient infrastructure issues.
#
# Auth errors (-32001): BLOCK — operator must fix AXONFLOW_AUTH
# Method not found (-32601): BLOCK — plugin version mismatch with agent
# Invalid params (-32602): BLOCK — plugin bug, operator should upgrade
# Parse errors (-32700): ALLOW — transient
# Internal errors (-32603): ALLOW — server-side fault, not operator's
# Everything else: ALLOW — unknown failure, default to allow
JSONRPC_ERROR=$(echo "$RESPONSE" | jq -r '.error.message // empty' 2>/dev/null || echo "")
if [ -n "$JSONRPC_ERROR" ]; then
JSONRPC_CODE=$(echo "$RESPONSE" | jq -r '.error.code // 0' 2>/dev/null || echo "0")
# Auth errors (-32001) and internal errors (-32603) = block
# Parse errors (-32700) = allow (could be transient)
if [ "$JSONRPC_CODE" != "-32700" ]; then
echo "AxonFlow governance error: ${JSONRPC_ERROR}. Fix AxonFlow configuration to restore tool access." >&2
exit 2
fi
exit 0
case "$JSONRPC_CODE" in
-32001|-32601|-32602)
echo "AxonFlow governance blocked: ${JSONRPC_ERROR} (code ${JSONRPC_CODE}). Fix AxonFlow configuration to restore tool access." >&2
exit 2
;;
*)
# Transient or server-side — fail open.
exit 0
;;
esac
fi

# Parse the MCP response to get the tool result
Expand Down
68 changes: 68 additions & 0 deletions scripts/uninstall.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
# AxonFlow Codex plugin uninstall helper.
#
# Codex CLI's built-in `/plugins` uninstall only removes the registration
# from ~/.codex/config.toml and leaves the local-source plugin directory
# on disk. This helper cleans up the leftover:
#
# - ~/.codex/plugins/cache/axonflow-local/ (cache from local source)
# - ~/.codex/plugins/installed/axonflow-codex-plugin/ (if installed via marketplace)
#
# It does NOT remove ~/.codex/config.toml entries — run `/plugins` uninstall
# inside Codex CLI first. This script is the second half of the cleanup.
#
# Usage:
# ./scripts/uninstall.sh
# ./scripts/uninstall.sh --dry-run

set -euo pipefail

DRY_RUN=0
if [ "${1:-}" = "--dry-run" ]; then
DRY_RUN=1
fi

remove_if_exists() {
local path="$1"
if [ -e "$path" ]; then
if [ "$DRY_RUN" = "1" ]; then
echo "[DRY RUN] Would remove: $path"
else
rm -rf "$path"
echo "Removed: $path"
fi
fi
}

echo "AxonFlow Codex plugin cleanup"
echo "============================="
echo

remove_if_exists "$HOME/.codex/plugins/cache/axonflow-local"
remove_if_exists "$HOME/.codex/plugins/cache/axonflow-codex-plugin"
remove_if_exists "$HOME/.codex/plugins/installed/axonflow-codex-plugin"

# Also strip AxonFlow entries from hooks.json if present.
HOOKS_FILE="$HOME/.codex/hooks.json"
if [ -f "$HOOKS_FILE" ] && grep -q "axonflow" "$HOOKS_FILE" 2>/dev/null; then
if [ "$DRY_RUN" = "1" ]; then
echo "[DRY RUN] Would prune AxonFlow entries from $HOOKS_FILE"
else
echo "Found AxonFlow entries in $HOOKS_FILE — edit manually to remove"
echo " (diff preview: grep -i axonflow $HOOKS_FILE)"
fi
fi

# Also strip AxonFlow MCP server from config.toml if present.
CONFIG_FILE="$HOME/.codex/config.toml"
if [ -f "$CONFIG_FILE" ] && grep -qi "axonflow" "$CONFIG_FILE" 2>/dev/null; then
if [ "$DRY_RUN" = "1" ]; then
echo "[DRY RUN] Would report AxonFlow references in $CONFIG_FILE"
else
echo "Found AxonFlow references in $CONFIG_FILE — run '/plugins uninstall' in Codex CLI first"
echo " (diff preview: grep -i axonflow $CONFIG_FILE)"
fi
fi

echo
echo "Done. Restart Codex CLI to complete the uninstall."
2 changes: 1 addition & 1 deletion tests/test-hooks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ else
STDERR_OUT=$(cat "$STDERR_FILE")
rm -f "$STDERR_FILE"
assert_eq "Exit code is 2 (block)" "2" "$EXIT_CODE"
assert_contains "Has governance error on stderr" "$STDERR_OUT" "governance error"
assert_contains "Has governance blocked on stderr" "$STDERR_OUT" "governance blocked"
fi

echo ""
Expand Down
Loading