Skip to content

REFACTOR: Migrate CLI to use pyrit.models#1997

Open
rlundeen2 wants to merge 5 commits into
microsoft:mainfrom
rlundeen2:rlundeen2/phase-16-pyrit-models-plan
Open

REFACTOR: Migrate CLI to use pyrit.models#1997
rlundeen2 wants to merge 5 commits into
microsoft:mainfrom
rlundeen2:rlundeen2/phase-16-pyrit-models-plan

Conversation

@rlundeen2

@rlundeen2 rlundeen2 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

This PR migrates the CLI to use pyrit.models (now that it is a lot thinner) instead of dictionaries.

Also, this PR adds pyrit/models/catalog package (target, scenario, initializer) as the canonical typed catalog models - there were previously defined in the backend, but are needed by the API and are not presentation specific.

This is phase 16 of this pyrit.models plan: https://gist.github.com/rlundeen2/3e8daa8e12a11b4b6e52587b3c9b1dca

@rlundeen2 rlundeen2 force-pushed the rlundeen2/phase-16-pyrit-models-plan branch from ed441d2 to 37b5cfb Compare June 12, 2026 21:23
…hase 16)

Add pyrit/models/catalog package (target, scenario, initializer) as the canonical typed catalog models. Rewrite the CLI api_client and output to consume typed objects instead of dict[str, Any] payloads, and update backend mappers/routes/services plus tests to import the canonical types. Remove backend re-export shims so backend models hold only REST framing types.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@rlundeen2 rlundeen2 force-pushed the rlundeen2/phase-16-pyrit-models-plan branch from 37b5cfb to e72af5f Compare June 12, 2026 21:56
@romanlutz

Copy link
Copy Markdown
Contributor

The title and description both say pyrit.modes somehow which is confusing me. You meant models I think (?) but it's consistent enough that I want to get that clarified first.

@rlundeen2 rlundeen2 changed the title REFACTOR: Migrate CLI to use pyrit.modes REFACTOR: Migrate CLI to use pyrit.models Jun 15, 2026
@rlundeen2

Copy link
Copy Markdown
Contributor Author

The title and description both say pyrit.modes somehow which is confusing me. You meant models I think (?) but it's consistent enough that I want to get that clarified first.

Yep, meant to be models, sorry!

…rit-models-plan

# Conflicts:
#	pyrit/backend/mappers/target_mappers.py
#	pyrit/backend/routes/scenarios.py
#	pyrit/cli/_output.py
#	pyrit/cli/api_client.py
#	tests/unit/cli/test_output.py
Comment thread pyrit/models/catalog/__init__.py Outdated
Comment thread pyrit/models/catalog/target.py
Comment thread pyrit/models/catalog/target.py Outdated
rlundeen2 and others added 3 commits June 22, 2026 15:49
Co-authored-by: hannahwestra25 <hannahwestra@microsoft.com>
…rit-models-plan

# Conflicts:
#	pyrit/backend/routes/scenarios.py
#	pyrit/cli/_output.py
#	tests/unit/backend/test_scenario_run_service.py
#	tests/unit/cli/test_output.py
Mirrors the target.py fix: these catalog models ARE the FastAPI REST

response models, so Field(..., description=...) belongs on them and surfaces

in the OpenAPI schema. Removes the misleading docstring claim that

descriptions live in the backend layer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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.

flagging a small divergence from pyrit/backend/models/{scenarios,initializers,targets}.py keep these as re-export shims for one release. mentioned in the gist (i.e., something like from pyrit.backend.models import RegisteredScenario will break for without DeprecationWarning.)

"""Status of a scenario run, aligned with core ScenarioRunState."""

CREATED = "CREATED"
INITIALIZING = "INITIALIZING"

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.

noting that GHC noticed INITIALIZING was dropped. (ScenarioRunState doesn't have INTIALIZING as a status). is that not needed anymore?

Comment thread pyrit/cli/pyrit_scan.py
return 1

if run.get("status") == "COMPLETED":
if run.status == "COMPLETED":

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.

compare to Enum instead of string?

Comment thread pyrit/cli/pyrit_scan.py
ScenarioRunSummary,
)

_TERMINAL_STATUSES = {"COMPLETED", "FAILED", "CANCELLED"}

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.

should be ScenarioRunState Enums?

Comment thread pyrit/cli/pyrit_shell.py

# Print results
if run.get("status") == "COMPLETED":
if run.status == "COMPLETED":

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.

same here

Comment thread pyrit/cli/pyrit_shell.py

prompt = "pyrit> "

_TERMINAL_STATUSES = {"COMPLETED", "FAILED", "CANCELLED"}

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.

same here

Comment thread pyrit/cli/pyrit_scan.py
await _output.print_scenario_result_async(result_dict=detail)
await _output.print_scenario_result_async(result=detail)
except Exception:
_output.print_scenario_run_summary(run=run)

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.

if the server sends back a malformed payload that can't be deserialized properly (on model_validate in get_scenario_run_results_async), the error will get swallowed here without the user knowing. (same in pyrit_shell)

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.

maybe log the error at least

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.

4 participants