Files
Bo d972fa2090 Prepare AgentOps 4.0.0 plugins, skills and CLI release (#1143)
## What

Prepare AgentOps 4.0.0 across the Claude plugin, Codex plugin, skills
and CLI. Claude writers capture the supplied check status during its
original invocation, and plugin conformance verifies exact skill
membership and link destinations. Full release security now scans the
repository and blocks on Python collection failures that previously
produced a false green result.

## Why

The 3.6.0-to-current interval removes published commands and 20 skill
names, so this is a major release with migration instructions. Release
validation also exposed stale skill assertions and test prerequisites
that need to match the current product contracts without weakening
acceptance.

## How I tested

- Native Claude Opus/Haiku success, failing-check and direct-writer
trials: each check ran once, and the direct child returned plain JSON.
- Actual fresh installs and upgrades from 3.6.0 in isolated Codex and
Claude homes: 34 skills, expected agents, and exact installed package
bytes.
- Exact candidate `b721d02559e1495be6095ad97b820e88ceb4a049`: all 73
full repository gates, regeneration parity, and the complete local
release rehearsal passed. All 12 security tools ran with zero skips,
tool errors, critical findings or high-severity security findings. The
unchanged advisory policy reports 35 quality-high findings on unchanged
files.
- Python: 327 tests and 72 subtests passed. Hosted Bats: 1,509 passed,
31 environment-dependent skips, zero failures. Go
lint/build/vet/race/shuffle checks and CLI smoke/integration passed.
- All 11 hosted checks passed, including Windows correctness,
macOS/Linux installation, security, and the six-target no-publish
GoReleaser snapshot. Local archive checksums and a real macOS CLI
initialization/status/version smoke also passed.
- Fresh author-distinct review passed all four acceptance criteria and
all 35 changed paths with no unchecked acceptance. Canonical subject and
caller-intent verification passed; verdict digest
`68af2c935ed0106cd91b3950f5d168e662f4071f660fcbd113c36b7cd0f0426e` binds
manifest
`7affc77e25eaff69ba36c5ce05582b4f0385c954b76b62c02b97f97041f489b2`.

## Checklist

- [x] Breaking changes documented in the migration guide and complete
release notes.
- [x] No credentials or private runtime proof included.
- [x] Final full release checks pass on the exact candidate.
- [x] Fresh author-distinct final PASS is recorded before merge.

This prepares the release candidate; it does not publish a tag or
release.

Coverage limits remain explicit: native plugin tests used isolated macOS
homes and local marketplaces, guard installation remains opt-in, and
reader instructions do not prove sandbox confinement. Semgrep retains
pre-existing warning-level parser diagnostics. Snapshot metadata follows
the existing 3.6.0 tag; this is a packaging rehearsal, not a published
4.0.0 archive.
2026-09-13 17:21:16 -04:00

149 lines
4.0 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$REPO_ROOT"
MODE="quick"
JSON_OUTPUT=false
REQUIRE_TOOLS=false
usage() {
cat <<'USAGE'
Usage: scripts/security-gate.sh [--mode quick|full] [--json] [--require-tools]
Runs the unified security gate using scripts/toolchain-validate.sh.
Options:
--mode quick|full quick = changed scope, skip slow tests (default); full = repository-wide suite
--json output machine-readable summary JSON
--require-tools fail if any scanner reports not_installed/error
-h, --help show this help
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--mode)
MODE="${2:-}"
shift 2
;;
--json)
JSON_OUTPUT=true
shift
;;
--require-tools)
REQUIRE_TOOLS=true
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
usage >&2
exit 1
;;
esac
done
if [[ "$MODE" != "quick" && "$MODE" != "full" ]]; then
echo "Invalid mode: $MODE (expected quick or full)" >&2
exit 1
fi
# Canonical scanner invocation contract: scripts/toolchain-validate.sh --gate
TOOLCHAIN_SCRIPT="${SECURITY_GATE_TOOLCHAIN_SCRIPT:-scripts/toolchain-validate.sh}"
if [[ ! -x "$TOOLCHAIN_SCRIPT" ]]; then
echo "Missing executable: $TOOLCHAIN_SCRIPT" >&2
exit 1
fi
RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)-${MODE}"
SECURITY_BASE="${SECURITY_GATE_OUTPUT_DIR:-${TMPDIR:-/tmp}/agentops-security}"
SECURITY_DIR="$SECURITY_BASE/$RUN_ID"
mkdir -p "$SECURITY_DIR"
TOOLCHAIN_ARGS=(--all --gate --json)
if [[ "$MODE" == "quick" ]]; then
TOOLCHAIN_ARGS=(--quick --gate --json)
fi
set +e
TOOLCHAIN_OUTPUT="$($TOOLCHAIN_SCRIPT "${TOOLCHAIN_ARGS[@]}" 2>&1)"
TOOLCHAIN_EXIT=$?
set -e
SUMMARY_JSON="$SECURITY_DIR/summary.json"
printf '%s\n' "$TOOLCHAIN_OUTPUT" > "$SUMMARY_JSON"
TOOLING_SRC="${TOOLCHAIN_OUTPUT_DIR:-${TMPDIR:-/tmp}/agentops-tooling}"
if [[ -d "$TOOLING_SRC" ]]; then
cp -a "$TOOLING_SRC/." "$SECURITY_DIR/" 2>/dev/null || true
fi
if command -v jq >/dev/null 2>&1 && jq empty "$SUMMARY_JSON" >/dev/null 2>&1; then
GATE_STATUS="$(jq -r '.gate_status // "UNKNOWN"' "$SUMMARY_JSON")"
MISSING_TOOLS="$(jq -r '[.tools[] | select(. == "not_installed" or . == "error")] | length' "$SUMMARY_JSON")"
EXTENDED_JSON="$SECURITY_DIR/security-gate-summary.json"
jq -n \
--arg mode "$MODE" \
--arg run_id "$RUN_ID" \
--arg output_dir "$SECURITY_DIR" \
--argjson toolchain "$(cat "$SUMMARY_JSON")" \
--arg gate_status "$GATE_STATUS" \
--argjson missing_tools "$MISSING_TOOLS" \
--arg require_tools "$REQUIRE_TOOLS" \
'{
mode: $mode,
run_id: $run_id,
output_dir: $output_dir,
gate_status: $gate_status,
missing_tool_count: $missing_tools,
require_tools: ($require_tools == "true"),
toolchain: $toolchain
}' > "$EXTENDED_JSON"
if [[ "$REQUIRE_TOOLS" == "true" && "$MISSING_TOOLS" -gt 0 ]]; then
if [[ "$JSON_OUTPUT" == "true" ]]; then
cat "$EXTENDED_JSON"
else
echo "Security gate FAILED: missing/error tools detected ($MISSING_TOOLS)"
echo "Report: $EXTENDED_JSON"
fi
exit 4
fi
if [[ "$JSON_OUTPUT" == "true" ]]; then
cat "$EXTENDED_JSON"
else
echo "Security gate mode: $MODE"
echo "Gate status: $GATE_STATUS"
echo "Missing/error tools: $MISSING_TOOLS"
echo "Report: $EXTENDED_JSON"
fi
else
if [[ "$JSON_OUTPUT" == "true" ]]; then
jq -n \
--arg mode "$MODE" \
--arg run_id "$RUN_ID" \
--arg output_dir "$SECURITY_DIR" \
--arg raw "$TOOLCHAIN_OUTPUT" \
'{mode: $mode, run_id: $run_id, output_dir: $output_dir, parse_error: true, raw_output: $raw}'
else
echo "Security gate warning: toolchain output was not valid JSON"
echo "Raw output saved to: $SUMMARY_JSON"
fi
exit 1
fi
# Preserve toolchain gate semantics for findings.
if [[ "$TOOLCHAIN_EXIT" -ne 0 ]]; then
exit "$TOOLCHAIN_EXIT"
fi
exit 0