mirror of
https://github.com/boshu2/agentops.git
synced 2026-09-14 15:08:13 +08:00
8061085c89
AO now performs intent snapshots, subject manifests, strict evidence verification, atomic verdict storage, and orphan inspection through the Go binary. The command handler keeps verification separate from presentation so it meets the existing complexity limit. These operations preserve the existing evidence formats, require explicit protected storage where applicable, and run outside a checkout without Python. The unchanged Python implementation remains a developer oracle; agents still provide semantic judgment. Codex and Claude skills now default to a fresh reviewer from the author’s model family. Callers can explicitly request cross-model review or pin its model. Reviewer adapters use a finite caller timeout or remaining deadline instead of a fixed ten-minute default, while retaining output limits and abnormal-termination cleanup. Validation: Go build, vet, tests and race/shuffle tests; 1,334 shell tests; aggregate runner; regeneration check; 72 full-mode gates. Independent checks exercised 84 storage-boundary rejections and 21 evidence operations with an empty PATH. Both canonical and generated RPI reference suites pass all 48 tests after updating the migrated oracle import without weakening assertions. Change-sensitive checks explicitly compare the final committed candidate with the original PR base. Linux, Windows, installer, security, and required summary checks are green.
132 lines
4.0 KiB
Bash
Executable File
132 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Shared fail-closed codex runner (STALL/ECHO/MISSING defenses + distinct exit
|
|
# codes). age-gate-the-ungated-egwt.8. `CDPATH=` is an intentional env-prefix
|
|
# (clears CDPATH for that one cd), not a botched assignment.
|
|
# shellcheck disable=SC1007
|
|
. "$(CDPATH= cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/codex-exec.sh"
|
|
|
|
EXPECTED_CSV="using-agentops,swarm,research"
|
|
WORKDIR="/tmp"
|
|
PROFILE="${CODEX_VALIDATE_PROFILE:-safe}"
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
validate-codex-cli-skills.sh
|
|
|
|
Open a fresh non-interactive Codex session and verify that expected AgentOps
|
|
skills are visible to the runtime.
|
|
|
|
Options:
|
|
--expected <a,b,c> Comma-separated skill names to require
|
|
--workdir <dir> Working directory for the ephemeral Codex session
|
|
--profile <name> Codex profile to use (default: safe)
|
|
--timeout <seconds> Positive finite execution budget; no default
|
|
--deadline-epoch <seconds> Absolute Unix deadline for the caller's whole run
|
|
--help Show this help
|
|
|
|
Declare at least one execution bound with these options or the corresponding
|
|
CODEX_EXEC_TIMEOUT / CODEX_EXEC_DEADLINE_EPOCH environment variables. The earlier
|
|
bound wins when both are set. Reuse the same absolute deadline across retries.
|
|
EOF
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--expected)
|
|
EXPECTED_CSV="${2:-}"
|
|
shift 2
|
|
;;
|
|
--workdir)
|
|
WORKDIR="${2:-}"
|
|
shift 2
|
|
;;
|
|
--profile)
|
|
PROFILE="${2:-}"
|
|
shift 2
|
|
;;
|
|
--timeout)
|
|
# shellcheck disable=SC2034 # consumed by the sourced codex_exec_guarded.
|
|
CODEX_EXEC_TIMEOUT="${2-}"
|
|
shift 2
|
|
;;
|
|
--deadline-epoch)
|
|
# shellcheck disable=SC2034 # consumed by the sourced codex_exec_guarded.
|
|
CODEX_EXEC_DEADLINE_EPOCH="${2-}"
|
|
shift 2
|
|
;;
|
|
--help|-h)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown arg: $1" >&2
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
command -v codex >/dev/null 2>&1 || {
|
|
echo "codex CLI not found in PATH" >&2
|
|
exit 1
|
|
}
|
|
|
|
mkdir -p "$WORKDIR"
|
|
OUTPUT_FILE="$(mktemp)"
|
|
cleanup() {
|
|
rm -f "$OUTPUT_FILE"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
PROMPT="List the available skill names you can see in this session. Return only a comma-separated list."
|
|
# The runner reads CODEX_EXEC_EXTRA_ARGS as an ARRAY from the current shell scope
|
|
# (it runs as a sourced function, not a subprocess) — a bash array cannot be set
|
|
# via a `VAR=... cmd` command-prefix, so assign it here before the call.
|
|
# shellcheck disable=SC2034 # consumed by codex_exec_guarded in lib/codex-exec.sh (sourced).
|
|
CODEX_EXEC_EXTRA_ARGS=(--profile "$PROFILE" --json)
|
|
if ! CODEX_EXEC_SANDBOX=read-only CODEX_EXEC_SKIP_GIT_CHECK=1 \
|
|
CODEX_EXEC_PROMPT_ARG="$PROMPT" CODEX_EXEC_OUT_FILE="$OUTPUT_FILE" \
|
|
codex_exec_guarded; then
|
|
echo "headless codex run failed while checking skill discovery" >&2
|
|
exit 1
|
|
fi
|
|
|
|
python3 - "$OUTPUT_FILE" "$EXPECTED_CSV" <<'PY'
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
path = Path(sys.argv[1])
|
|
expected = [item.strip() for item in sys.argv[2].split(",") if item.strip()]
|
|
messages = []
|
|
for line in path.read_text().splitlines():
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
try:
|
|
payload = json.loads(line)
|
|
except json.JSONDecodeError:
|
|
continue
|
|
item = payload.get("item")
|
|
if payload.get("type") == "item.completed" and isinstance(item, dict) and item.get("type") == "agent_message":
|
|
text = item.get("text", "").strip()
|
|
if text:
|
|
messages.append(text)
|
|
|
|
if not messages:
|
|
print("No agent message found in headless codex output", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
visible = {part.strip() for part in messages[-1].split(",") if part.strip()}
|
|
missing = [name for name in expected if name not in visible]
|
|
if missing:
|
|
print("Missing expected skills: " + ", ".join(missing), file=sys.stderr)
|
|
print("Visible skills: " + ", ".join(sorted(visible)), file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
print("Visible skills: " + ", ".join(sorted(visible)))
|
|
print("Required skills present: " + ", ".join(expected))
|
|
PY
|