fix: feat: persist red-team cross-patterns in repo for continuity across runs (#853)
- Move CROSS_PATTERNS_FILE from /tmp/red-team-cross-patterns.jsonl to tools/red-team/cross-patterns.jsonl (repo-tracked path) - Remove the reset (> file) at sweep start so patterns accumulate across runs - Generate a SWEEP_ID (sweep-YYYYMMDD-HHMMSS) at sweep start and stamp each new entry with sweep_id for traceability - Deduplicate on (pattern, candidate, result): entries already present in the file are skipped; intra-batch duplicates are also suppressed - Create tools/red-team/ directory with .gitkeep - Add mkdir -p guards in both scripts so the directory is created on first run Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3d8bbb0975
commit
fe3a3d7d94
3 changed files with 35 additions and 6 deletions
|
|
@ -11,7 +11,7 @@ INJECT="$REPO_ROOT/tools/push3-transpiler/inject.sh"
|
||||||
ATTACKS_OUT="$REPO_ROOT/onchain/script/backtesting/attacks"
|
ATTACKS_OUT="$REPO_ROOT/onchain/script/backtesting/attacks"
|
||||||
PROGRESS_FILE="/tmp/red-team-sweep-progress.json"
|
PROGRESS_FILE="/tmp/red-team-sweep-progress.json"
|
||||||
MEMORY_FILE="$REPO_ROOT/tmp/red-team-memory.jsonl"
|
MEMORY_FILE="$REPO_ROOT/tmp/red-team-memory.jsonl"
|
||||||
CROSS_PATTERNS_FILE="/tmp/red-team-cross-patterns.jsonl"
|
CROSS_PATTERNS_FILE="$REPO_ROOT/tools/red-team/cross-patterns.jsonl"
|
||||||
SWEEP_TSV="/tmp/sweep-results.tsv"
|
SWEEP_TSV="/tmp/sweep-results.tsv"
|
||||||
OPT_SOL="$REPO_ROOT/onchain/src/OptimizerV3.sol"
|
OPT_SOL="$REPO_ROOT/onchain/src/OptimizerV3.sol"
|
||||||
TIMEOUT_PER="${1:-3600}"
|
TIMEOUT_PER="${1:-3600}"
|
||||||
|
|
@ -22,9 +22,11 @@ die() { log "FATAL: $*" >&2; exit 1; }
|
||||||
[[ -f "$INJECT" ]] || die "inject.sh not found at $INJECT"
|
[[ -f "$INJECT" ]] || die "inject.sh not found at $INJECT"
|
||||||
|
|
||||||
mkdir -p "$ATTACKS_OUT"
|
mkdir -p "$ATTACKS_OUT"
|
||||||
|
mkdir -p "$(dirname "$CROSS_PATTERNS_FILE")"
|
||||||
|
|
||||||
# Reset cross-patterns file for this sweep invocation (prevents stale data from prior runs)
|
# Generate a unique sweep ID for traceability across runs
|
||||||
> "$CROSS_PATTERNS_FILE"
|
SWEEP_ID="sweep-$(date -u +%Y%m%d-%H%M%S)"
|
||||||
|
log "Sweep ID: $SWEEP_ID"
|
||||||
|
|
||||||
# Load progress
|
# Load progress
|
||||||
completed=()
|
completed=()
|
||||||
|
|
@ -217,11 +219,12 @@ PYEOF
|
||||||
# 4c. Extract abstract patterns into cross-candidate file, then clear raw memory
|
# 4c. Extract abstract patterns into cross-candidate file, then clear raw memory
|
||||||
if [[ -f "$MEMORY_FILE" && -s "$MEMORY_FILE" ]]; then
|
if [[ -f "$MEMORY_FILE" && -s "$MEMORY_FILE" ]]; then
|
||||||
set +e
|
set +e
|
||||||
_extract_out=$(python3 - "$MEMORY_FILE" "$CROSS_PATTERNS_FILE" <<'PYEOF'
|
_extract_out=$(python3 - "$MEMORY_FILE" "$CROSS_PATTERNS_FILE" "$SWEEP_ID" <<'PYEOF'
|
||||||
import json, sys
|
import json, sys
|
||||||
|
|
||||||
mem_file = sys.argv[1]
|
mem_file = sys.argv[1]
|
||||||
cross_file = sys.argv[2]
|
cross_file = sys.argv[2]
|
||||||
|
sweep_id = sys.argv[3] if len(sys.argv) > 3 else "unknown"
|
||||||
|
|
||||||
new_entries = []
|
new_entries = []
|
||||||
with open(mem_file) as f:
|
with open(mem_file) as f:
|
||||||
|
|
@ -237,11 +240,36 @@ if not new_entries:
|
||||||
print("No memory entries to extract")
|
print("No memory entries to extract")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
# Load existing (pattern, candidate, result) keys for deduplication
|
||||||
|
existing_keys = set()
|
||||||
|
try:
|
||||||
|
with open(cross_file) as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
if line:
|
||||||
|
try:
|
||||||
|
e = json.loads(line)
|
||||||
|
existing_keys.add((e.get("pattern", ""), e.get("candidate", ""), e.get("result", "")))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
appended = 0
|
||||||
|
skipped = 0
|
||||||
with open(cross_file, 'a') as f:
|
with open(cross_file, 'a') as f:
|
||||||
for e in new_entries:
|
for e in new_entries:
|
||||||
|
key = (e.get("pattern", ""), e.get("candidate", ""), e.get("result", ""))
|
||||||
|
if key in existing_keys:
|
||||||
|
skipped += 1
|
||||||
|
continue
|
||||||
|
e["sweep_id"] = sweep_id
|
||||||
|
existing_keys.add(key) # prevent intra-batch duplicates
|
||||||
f.write(json.dumps(e) + '\n')
|
f.write(json.dumps(e) + '\n')
|
||||||
|
appended += 1
|
||||||
|
|
||||||
print(f"Extracted {len(new_entries)} entr{'y' if len(new_entries)==1 else 'ies'} to cross-patterns file")
|
total = appended + skipped
|
||||||
|
print(f"Extracted {appended} new entr{'y' if appended==1 else 'ies'} ({skipped} duplicate{'s' if skipped!=1 else ''} skipped) to cross-patterns file")
|
||||||
PYEOF
|
PYEOF
|
||||||
)
|
)
|
||||||
_py_exit=$?
|
_py_exit=$?
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ REPORT_DIR="$REPO_ROOT/tmp"
|
||||||
REPORT="$REPORT_DIR/red-team-report.txt"
|
REPORT="$REPORT_DIR/red-team-report.txt"
|
||||||
STREAM_LOG="$REPORT_DIR/red-team-stream.jsonl"
|
STREAM_LOG="$REPORT_DIR/red-team-stream.jsonl"
|
||||||
MEMORY_FILE="$REPO_ROOT/tmp/red-team-memory.jsonl"
|
MEMORY_FILE="$REPO_ROOT/tmp/red-team-memory.jsonl"
|
||||||
CROSS_PATTERNS_FILE="/tmp/red-team-cross-patterns.jsonl"
|
CROSS_PATTERNS_FILE="$REPO_ROOT/tools/red-team/cross-patterns.jsonl"
|
||||||
ATTACK_EXPORT="$REPORT_DIR/red-team-attacks.jsonl"
|
ATTACK_EXPORT="$REPORT_DIR/red-team-attacks.jsonl"
|
||||||
ATTACK_SNAPSHOTS="$REPORT_DIR/red-team-snapshots.jsonl"
|
ATTACK_SNAPSHOTS="$REPORT_DIR/red-team-snapshots.jsonl"
|
||||||
DEPLOYMENTS="$REPO_ROOT/onchain/deployments-local.json"
|
DEPLOYMENTS="$REPO_ROOT/onchain/deployments-local.json"
|
||||||
|
|
@ -581,6 +581,7 @@ PROMPT=${PROMPT//\{\{MEMORY_SECTION\}\}/$MEMORY_SECTION}
|
||||||
# ── 7. Create output directory and run the agent ───────────────────────────────
|
# ── 7. Create output directory and run the agent ───────────────────────────────
|
||||||
mkdir -p "$REPORT_DIR"
|
mkdir -p "$REPORT_DIR"
|
||||||
mkdir -p "$(dirname "$MEMORY_FILE")"
|
mkdir -p "$(dirname "$MEMORY_FILE")"
|
||||||
|
mkdir -p "$(dirname "$CROSS_PATTERNS_FILE")"
|
||||||
|
|
||||||
log "Spawning Claude red-team agent (timeout: ${CLAUDE_TIMEOUT}s)..."
|
log "Spawning Claude red-team agent (timeout: ${CLAUDE_TIMEOUT}s)..."
|
||||||
log " Report will be written to: $REPORT"
|
log " Report will be written to: $REPORT"
|
||||||
|
|
|
||||||
0
tools/red-team/.gitkeep
Normal file
0
tools/red-team/.gitkeep
Normal file
Loading…
Add table
Add a link
Reference in a new issue