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

184 lines
4.5 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$REPO_ROOT"
PASS_COUNT=0
FAIL_COUNT=0
MOCK_TOOLCHAIN="$(mktemp)"
MOCK_ARGS="$(mktemp)"
TEST_OUTPUT="$(mktemp -d)"
export SECURITY_GATE_OUTPUT_DIR="$TEST_OUTPUT/security"
export TOOLCHAIN_OUTPUT_DIR="$TEST_OUTPUT/tooling"
export MOCK_ARGS
cleanup() {
rm -f "$MOCK_TOOLCHAIN"
rm -f "$MOCK_ARGS"
rm -rf "$TEST_OUTPUT"
}
trap cleanup EXIT
pass() {
echo "PASS: $1"
PASS_COUNT=$((PASS_COUNT + 1))
}
fail() {
echo "FAIL: $1"
FAIL_COUNT=$((FAIL_COUNT + 1))
}
create_mock_toolchain() {
cat >"$MOCK_TOOLCHAIN" <<'MOCK'
#!/bin/bash
printf '%s\n' "$@" > "$MOCK_ARGS"
cat <<'JSON'
{
"timestamp": "2026-02-19T00:00:00Z",
"target": "/tmp/repo",
"tools_run": 2,
"tools_skipped": 9,
"tools": {
"ruff": "pass",
"golangci-lint": "pass",
"gitleaks": "not_installed",
"shellcheck": "pass",
"radon": "skipped",
"semgrep": "not_installed",
"trivy": "not_installed",
"gosec": "pass",
"hadolint": "skipped",
"pytest": "skipped",
"go-test": "skipped"
},
"findings": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0
},
"gate_status": "PASS",
"output_dir": "/tmp/agentops-tooling"
}
JSON
exit 0
MOCK
chmod +x "$MOCK_TOOLCHAIN"
}
test_scope_arguments() {
create_mock_toolchain
SECURITY_GATE_TOOLCHAIN_SCRIPT="$MOCK_TOOLCHAIN" scripts/security-gate.sh --mode full --json >/dev/null
if grep -qx -- '--all' "$MOCK_ARGS" && grep -qx -- '--gate' "$MOCK_ARGS"; then
pass "full security explicitly requests full-repository gate scope"
else
fail "full security did not request --all --gate"
fi
SECURITY_GATE_TOOLCHAIN_SCRIPT="$MOCK_TOOLCHAIN" scripts/security-gate.sh --mode quick --json >/dev/null
if grep -qx -- '--quick' "$MOCK_ARGS" && grep -qx -- '--gate' "$MOCK_ARGS" && ! grep -qx -- '--all' "$MOCK_ARGS"; then
pass "quick security preserves ordinary changed-scope gate arguments"
else
fail "quick security scope was broadened"
fi
}
test_executable() {
if [[ -x "scripts/security-gate.sh" ]]; then
pass "security-gate.sh is executable"
else
fail "security-gate.sh is not executable"
fi
}
test_help() {
if scripts/security-gate.sh --help >/dev/null 2>&1; then
pass "--help works"
else
fail "--help failed"
fi
}
test_invalid_mode() {
if scripts/security-gate.sh --mode nope >/dev/null 2>&1; then
fail "invalid mode should fail"
else
pass "invalid mode fails"
fi
}
test_json_output() {
local output
create_mock_toolchain
output=$(SECURITY_GATE_TOOLCHAIN_SCRIPT="$MOCK_TOOLCHAIN" scripts/security-gate.sh --mode quick --json 2>/dev/null || true)
if echo "$output" | jq empty >/dev/null 2>&1; then
pass "JSON output is valid"
else
fail "JSON output is invalid"
return
fi
local has_mode has_gate has_toolchain
has_mode=$(echo "$output" | jq -e '.mode' >/dev/null 2>&1 && echo yes || echo no)
has_gate=$(echo "$output" | jq -e '.gate_status' >/dev/null 2>&1 && echo yes || echo no)
has_toolchain=$(echo "$output" | jq -e '.toolchain.findings' >/dev/null 2>&1 && echo yes || echo no)
if [[ "$has_mode" == "yes" && "$has_gate" == "yes" && "$has_toolchain" == "yes" ]]; then
pass "JSON output has required fields"
else
fail "JSON output missing required fields (mode=$has_mode gate=$has_gate toolchain=$has_toolchain)"
fi
}
test_artifacts() {
create_mock_toolchain
local test_output_dir
test_output_dir="$(mktemp -d)"
SECURITY_GATE_TOOLCHAIN_SCRIPT="$MOCK_TOOLCHAIN" \
SECURITY_GATE_OUTPUT_DIR="$test_output_dir/security" \
TOOLCHAIN_OUTPUT_DIR="$test_output_dir/tooling" \
scripts/security-gate.sh --mode quick >/dev/null 2>&1 || true
local latest
latest=$(ls -td "$test_output_dir/security"/* 2>/dev/null | head -1 || true)
if [[ -z "$latest" ]]; then
fail "no security artifacts created"
rm -rf "$test_output_dir"
return
fi
if [[ -f "$latest/security-gate-summary.json" ]]; then
pass "security-gate summary artifact created"
else
fail "missing security-gate-summary.json"
fi
rm -rf "$test_output_dir"
}
echo "================================"
echo "Testing security-gate.sh"
echo "================================"
echo ""
test_executable
test_help
test_invalid_mode
test_json_output
test_artifacts
test_scope_arguments
echo ""
echo "================================"
echo "Results: $PASS_COUNT PASS, $FAIL_COUNT FAIL"
echo "================================"
if [[ $FAIL_COUNT -gt 0 ]]; then
exit 1
fi
exit 0