Skip to content

feat(cli): --run-name for deterministic, resumable run dirs#792

Open
seanturner83 wants to merge 2 commits into
usestrix:mainfrom
seanturner83:feat/cli-run-name
Open

feat(cli): --run-name for deterministic, resumable run dirs#792
seanturner83 wants to merge 2 commits into
usestrix:mainfrom
seanturner83:feat/cli-run-name

Conversation

@seanturner83

Copy link
Copy Markdown
Contributor

What

Adds a --run-name flag that forces the run directory name (./strix_runs/<RUN_NAME>/) instead of auto-generating one.

Why

generate_run_name() always auto-derives the run dir name, so a fresh scan's dir is unpredictable. A caller that needs to know the run dir before the scan starts has no way to key it — which blocks CI/automation patterns:

  • Resuming across a credential / wall-clock boundary — e.g. assume a fresh cloud token every ~50 min, kill Strix, strix --resume <name>. That needs the name pinned up front.
  • Restoring prior run state into a known dir before invoking Strix.

Today the only workaround is to scan strix_runs/ for the newest dir after the first iteration (find | head -1), which is fragile when a stale dir is present.

Behaviour

  • Precedence: --run-name > --resume > auto-generate. Absent flag = today's behaviour, unchanged.
  • Consistency: when both --run-name and --resume are given they must name the same dir — otherwise we'd resume one run and persist to another. Enforced with a clear error, not silently resolved.
  • Safety: the name is validated as a single filesystem-safe path segment (no /, no .., not ./..), since run_dir_for() joins it straight onto strix_runs/.

Tests

tests/test_cli_run_name.py (9, via parse_arguments() + monkeypatched argv, matching test_cli_target_list.py): accepts a single segment, defaults to None, rejects traversal (a/b, ../escape, /abs) and ./.., rejects a --run-name/--resume conflict. ruff clean.

🤖 Generated with Claude Code

generate_run_name() always auto-derives the run dir name, so a fresh scan's dir
is unpredictable and a caller that needs to know it *before* the scan starts has
no way to key it. That blocks CI/automation patterns:

  - resuming a scan across a credential / wall-clock boundary (assume a fresh
    token every ~50min, kill Strix, `strix --resume <name>`), which needs the
    name pinned up front, and
  - restoring prior run state into a known dir before invoking Strix.

Today the only workaround is to scan strix_runs/ for the newest dir after the
first iteration, which is fragile when a stale dir is present.

Add --run-name: force ./strix_runs/<RUN_NAME>/ instead of generating. Precedence
is --run-name > --resume > auto; when both --run-name and --resume are passed
they must name the same dir (else we'd resume one run and persist to another) —
enforced, not silently resolved. The name is validated as a single
filesystem-safe path segment (no '/', no '..') since run_dir_for() joins it
straight onto strix_runs/. Absent flag = today's behaviour, unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds deterministic names for scan run directories. The main changes are:

  • Adds the --run-name CLI option.
  • Validates names as single path segments.
  • Enforces agreement between --run-name and --resume.
  • Adds argument-parsing tests for valid and invalid names.

Confidence Score: 4/5

The deterministic fresh-run path can overwrite and mix state in an existing run directory.

  • A repeated --run-name enters fresh-run initialization rather than resume handling.
  • Existing metadata is replaced while stale artifacts can remain.
  • Name parsing and resume-conflict validation otherwise follow the described behavior.

strix/interface/main.py

Important Files Changed

Filename Overview
strix/interface/main.py Adds run-name parsing, validation, conflict handling, and precedence, but allows fresh runs to reuse existing run directories.
tests/test_cli_run_name.py Covers parsing, traversal rejection, dot segments, defaults, and resume conflicts, but not existing-directory collisions.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
strix/interface/main.py:901
**Existing Run Directory Is Reused**

When a fresh invocation passes a name already present under `strix_runs`, this selection enters the `not args.resume` path. `_persist_run_record()` then replaces the prior `run.json`, while old vulnerability and state files can remain, so repeated use of a deterministic name can destroy metadata and mix artifacts from separate scans. The fresh path should reject an existing run directory and require `--resume`, or explicitly replace the directory as one unit.

Reviews (1): Last reviewed commit: "feat(cli): --run-name for deterministic,..." | Re-trigger Greptile

Comment thread strix/interface/main.py
# dir); else --resume reuses the prior run's name; else auto-generate. The
# --run-name/--resume consistency check above guarantees the first two agree
# when both are set, so this collapses cleanly.
args.run_name = args.run_name or args.resume or generate_run_name(args.targets_info)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Existing Run Directory Is Reused

When a fresh invocation passes a name already present under strix_runs, this selection enters the not args.resume path. _persist_run_record() then replaces the prior run.json, while old vulnerability and state files can remain, so repeated use of a deterministic name can destroy metadata and mix artifacts from separate scans. The fresh path should reject an existing run directory and require --resume, or explicitly replace the directory as one unit.

Prompt To Fix With AI
This is a comment left during a code review.
Path: strix/interface/main.py
Line: 901

Comment:
**Existing Run Directory Is Reused**

When a fresh invocation passes a name already present under `strix_runs`, this selection enters the `not args.resume` path. `_persist_run_record()` then replaces the prior `run.json`, while old vulnerability and state files can remain, so repeated use of a deterministic name can destroy metadata and mix artifacts from separate scans. The fresh path should reject an existing run directory and require `--resume`, or explicitly replace the directory as one unit.

How can I resolve this? If you propose a fix, please make it concise.

Greptile P1: a fresh (non-resume) --run-name naming an existing run dir enters
the not-args.resume path, where _persist_run_record() rewrites run.json but
leaves the prior run's vulnerability/state files in place — mixing artifacts
from two scans. Guard it in parse_arguments(): a non-resume --run-name whose
run_dir_for() already exists is rejected with a message pointing at --resume
(auto-generated names are collision-free, so this only bites an explicit name).
+2 tests (existing dir rejected, new dir accepted).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@seanturner83

Copy link
Copy Markdown
Contributor Author

Good catch — fixed in the latest push. A fresh (non-resume) --run-name that names an existing run dir is now rejected in parse_arguments() with a message pointing at --resume (the fresh path would rewrite run.json but leave the prior run's findings/state, mixing artifacts). Auto-generated names are collision-free so this only guards an explicit name. Added tests for both the existing-dir rejection and the new-dir accept.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant