Files
microsoft-SkillOpt/scripts/smoke_superpowers.sh
NovusEdge f76df89475 fix(adapters): harden evidence, fail closed on more edges (Copilot round 3)
Addresses 8 further Copilot inline findings across 04d3b65/4c2aa21:

- pytest_runs: drop the trivially-overwritable .count sidecar; derive the count
  from nonce-tagged log lines (per-run os.urandom nonce). Documented honestly as
  tamper-EVIDENT, not tamper-proof, since an unsandboxed agent runs as the same
  OS user; harness_test_passes (parent re-runs the tests) remains the
  authoritative unforgeable gate.
- Refuse SKILLOPT_HOST_AUTH=1 together with SKILLOPT_SANDBOX: host ~/.claude is
  not mounted, so the credential symlinks would dangle and auth silently fail.
- Raise on an unknown --scenario instead of returning an empty score=0 result
  that looks like a real evaluation.
- POSIX guard: the bash shims + claude/git shell-out are POSIX-only; raise a
  clear error on non-POSIX hosts rather than failing obscurely.
- CLI: catch git CalledProcessError / ValueError / RuntimeError so missing
  git/claude, bad SHA, and unknown scenarios exit non-zero with a message
  instead of dumping a traceback.
- Clarify that superpowers_version is a reporting label; the checkout is
  controlled solely by pinned_sha (--sha).
- Smoke sanitizer: also redact /tmp workspace paths and soften the "no host
  paths" claim to best-effort.

Tests: 49 focused, full suite 309 passed / 6 skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 02:43:19 +03:00

91 lines
3.0 KiB
Bash
Executable File

#!/bin/bash
# Smoke test for Superpowers adapter integration.
# Run this manually (not in CI) to verify the adapter works with the real harness.
#
# Prerequisites:
# - Claude Code installed, ANTHROPIC_API_KEY set (or SKILLOPT_HOST_AUTH=1 for a
# trusted candidate on your own machine)
# - Same model/settings/pinned SHA for baseline and candidate runs
#
# Usage:
# ./scripts/smoke_superpowers.sh [candidate_skill_path]
#
# Output goes to smoke_results/ (gitignored). Results embed raw agent output and
# local paths: do NOT commit them. Sanitized excerpts are written alongside each
# run for pasting into a PR description or attaching as an artifact.
set -euo pipefail
SKILL="${1:-}"
SCENARIO="${SKILLOPT_SCENARIO:-test-passes-verify}"
SHA="${SKILLOPT_SHA:-d884ae04edebef577e82ff7c4e143debd0bbec99}"
OUTDIR="smoke_results/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$OUTDIR"
echo "Smoke test: Superpowers adapter"
echo "Output: $OUTDIR (gitignored - do not commit)"
echo "Scenario: $SCENARIO"
echo "SHA: $SHA"
echo ""
run_scenario() {
local name="$1"
local candidate="${2:-}"
local outfile="$OUTDIR/${name}.json"
echo "=== $name ==="
local args=(
--skill verification-before-completion
--scenario "$SCENARIO"
--sha "$SHA"
--json
)
if [[ -n "$candidate" ]]; then
args+=(--candidate "$candidate")
fi
# No || true - fail if runner errors
python -m skillopt_sleep.adapters.superpowers "${args[@]}" > "$outfile"
# Best-effort sanitized summary for sharing: home dir, temp workspace paths
# and api-key-shaped tokens are redacted. Skim before sharing - it is a
# heuristic scrub, not a guarantee.
python - "$outfile" "$OUTDIR/${name}.summary.txt" <<'PY'
import json, os, re, sys
data = json.load(open(sys.argv[1]))
home = os.path.expanduser("~")
def clean(t):
t = t.replace(home, "~")
t = re.sub(r"/tmp/\S*skillopt\S*", "<workspace>", t)
t = re.sub(r"/(?:tmp|var)/\S*", "<path>", t)
return re.sub(r"sk-[A-Za-z0-9_\-]{8,}", "sk-REDACTED", t)
lines = [
f"skill={data['skill']} version={data['version']} pinned_sha={data['pinned_sha']}",
f"candidate_hash={data['candidate_hash'] or '(baseline)'}",
f"score={data['score']:.2f} passed={data['passed']} failed={data['failed']}",
]
for s in data["scenarios"]:
lines.append(f"\n[{s['id']}] passed={s['passed']} error={s.get('error') or 'none'}")
lines.append(f" evidence: {json.dumps(s.get('evidence', {}))}")
for c in s["checks"]:
lines.append(f" {'PASS' if c['passed'] else 'FAIL'} {c['description']}")
lines.append(" output excerpt:")
for ln in clean(s.get("output", ""))[:800].splitlines():
lines.append(f" {ln}")
text = "\n".join(lines)
open(sys.argv[2], "w").write(text + "\n")
print(text)
PY
}
run_scenario "baseline"
if [[ -n "$SKILL" ]]; then
run_scenario "candidate" "$SKILL"
fi
echo ""
echo "Results in $OUTDIR (gitignored)."
echo "Share the *.summary.txt excerpts in the PR; do not commit the raw JSON."