Skip to content

FEAT: Let each deployment configure its finding fields - #3655

Open
Adrian Gavrila (adrian-gavrila) wants to merge 19 commits into
microsoft:mainfrom
adrian-gavrila:adrian-gavrila-configurable-finding-fields
Open

Adrian Gavrila (adrian-gavrila) wants to merge 19 commits into
microsoft:mainfrom
adrian-gavrila:adrian-gavrila-configurable-finding-fields

Conversation

@adrian-gavrila

@adrian-gavrila Adrian Gavrila (adrian-gavrila) commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Description

This is the follow-up promised in #3066 (Operations, findings, evidence). #3066 pinned a finding's severity, harm type and description with CHECK constraints. This PR drops those constraints and lets each deployment define its own finding fields in Python. A deployment that configures nothing keeps the #3066 fields (Critical through Informational, the HarmCategory list, a description), and its findings migrate in place.

02-default-edit-dialog

It needs to ship in 1.2.0 together with #3066. #3066 isn't released yet, so removing FindingSeverity, /api/operations/finding-options and #3066's request shape needs no deprecation path. If 1.2.0 were cut with #3066 but without this PR, those removals would need one.

What changes

  • Fields are code. A deployment subclasses FindingsInitializer (pyrit/setup/initializers/findings.py) and returns a FindingFields from get_finding_fields().
    • The severity slot is always a required choice field, and its option order is the ranking.
    • Other fields are choices (with optional cascade levels and Other text), single-line text or multi-line text, and can carry hint, section and internal.
    • DEFAULT_FINDING_FIELDS reproduces FEAT: Findings dashboard with persistent Operations in the GUI #3066.
    • Keys are permanent; labels can change. Changing a key retires the old field, and saved values under it stay visible and read-only.
03-contoso-edit-dialog
  • Storage. One migration, d43b1bcf9c56, after c8d3e5f7a901.
    • It drops the three CHECK constraints.
    • It stores Other severity text as the severity itself, and moves harm type and description into a JSON field_values column.
    • Finding IDs, Operation links, creation times and evidence links don't change.
    • severity becomes unbounded Unicode, with a binary collation on SQL Server so sorting and counting match SQLite.
    • Downgrade refuses to run offline or while any finding exists.
    • Memory never reads FindingFields: the service passes it the severity order.
  • API. GET /api/operations/finding-fields replaces /finding-options.
    • Create and update check values against the active fields and answer 422 with a message naming the field.
    • Unchanged saved values that no longer match an option are kept.
    • Changed Other text that matches an option's key or label is rejected, with a 422 naming the option.
    • Updates keep retired values unless the request lists them in remove_retired_keys.
    • Request fields follow the existing request limits (TextStr, IdentifierStr, MAX_ITEMS).
  • Setup. The live-apply preflight rejects invalid finding fields, or two FindingsInitializers, before changing anything.
  • Export. The Word and Markdown export follows the fields: multi-line fields go in the Finding column, choice and text fields in Assessment. Internal fields and retired values are left out, and the export dialog warns when selected findings have retired values.
06-export-retired-warning
  • CoPyRIT. The finding dialog, cards, Operations counts, the Chat evidence picker and the export dialog all render from /finding-fields.
    • Retired values show read-only, with Remove (after a confirmation) and Undo.
04-remove-retired-confirmation
  • The fields reload when the runtime generation changes.
  • An open edit dialog keeps the fields it opened with and sends kept retired values back, so a live apply during an edit never clears a value.
05-contoso-finding-card 01-operations-other-count

Tests and Documentation

Tests: unit tests for the model rules, the migration (SQLite data path and SQL Server DDL compile), memory ordering, the setup preflight and the routes; Jest for the dialog, field input, retired values, cards, counts, picker and export dialog; the operations Playwright spec for the retired-value flow.

Docs: a new doc/code/setup/finding_fields.md (in doc/myst.yml) and an updated doc/gui/0_gui.md. No notebooks changed, so JupyText wasn't run.

Trial: a copy of a #3066-era SQLite database upgraded cleanly, and a custom initializer was live-applied and removed through the Configuration page.

Validation on the final tree (332fda9f2), on Windows:

Command Result
python -m pytest -n 4 --dist=loadfile tests/unit -q 32,832 passed, 71 skipped
npm test -- --silent (frontend) 173 suites, 4,041 tests passed
npm run type-check, npm run lint (frontend) Both clean
pre-commit run --files <all changed files> Pass
npx playwright test --project=seeded (frontend, seeded mode) Pass

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

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@adrian-gavrila Adrian Gavrila (adrian-gavrila) changed the title [DRAFT] FEAT: Let each deployment configure its finding fields FEAT: Let each deployment configure its finding fields Oct 29, 2026
@adrian-gavrila
Adrian Gavrila (adrian-gavrila) marked this pull request as ready for review October 29, 2026 19:01

Copilot AI left a comment

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.

🟡 Changes recommended

Unresolved defects can drop custom-field data, repeat or skip findings after severity changes, misvalidate replacement environments, and conflate distinct severities in SQL Server.

5 open issues
What changed in this PR

This follow-up to #3066 makes finding fields deployment-configurable across PyRIT’s storage, API, setup, and CoPyRIT interface, while retaining the existing fields by default.

Changes:

  • Adds initializer-based field configuration, validation, and live-apply preflight checks.
  • Migrates finding values to JSON storage and adapts ordering, updates, and exports.
  • Replaces fixed frontend fields with configurable controls, retired-value handling, and supporting tests and documentation.
File Description
tests/​unit/​setup/​test_reinitialization.py Tests finding-field preflight failures.
tests/​unit/​setup/​test_initialization.py Tests field resets and setup validation.
tests/​unit/​setup/​test_findings_initializer.py Tests initializer execution and discovery.
tests/​unit/​setup/​test_finding_fields.py Tests active-field state management.
tests/​unit/​setup/​conftest.py Adds custom-field fixtures.
tests/​unit/​models/​test_finding.py Tests flexible finding values.
tests/​unit/​memory/​test_operations_and_findings_migration.py Preserves earlier migration tests.
tests/​unit/​memory/​test_findings.py Tests persistence and configurable ordering.
tests/​unit/​memory/​test_finding_field_values_migration.py Tests migration data and database schema changes.
tests/​unit/​conftest.py Adds field-state cleanup fixture.
tests/​unit/​backend/​test_operations.py Tests field-aware routes and updates.
tests/​unit/​backend/​test_operation_service_findings.py Tests retired-value preservation and removal.
tests/​unit/​backend/​test_finding_export.py Tests configurable export projection.
tests/​unit/​backend/​test_common_models.py Tests finding request limits.
tests/​unit/​backend/​mocks.py Adds persisted-finding read helper.
tests/​unit/​backend/​conftest.py Adds configured and legacy finding fixtures.
pyrit/​setup/​initializers/​findings.py Introduces deployment field initializer.
pyrit/​setup/​initializers/​__init__.py Exports the initializer lazily.
pyrit/​setup/​initialization.py Resets fields during setup passes.
pyrit/​setup/​finding_fields.py Holds active deployment fields.
pyrit/​setup/​configuration_loader.py Adds field-definition preflight checks.
pyrit/​models/​finding.py Replaces fixed classifications with field values.
pyrit/​models/​__init__.py Updates public finding exports.
pyrit/​memory/​memory_models.py Stores severity and JSON field values.
pyrit/​memory/​memory_interface.py Accepts caller-defined severity ordering.
pyrit/​memory/​alembic/​versions/​d43b1bcf9c56_store_finding_field_values.py Migrates existing finding values and constraints.
pyrit/​backend/​services/​operation_service.py Validates values and preserves retired fields.
pyrit/​backend/​services/​finding_export.py Projects configured, non-internal fields.
pyrit/​backend/​routes/​operations.py Exposes fields and validation responses.
pyrit/​backend/​models/​operations.py Defines bounded configurable-field requests.
frontend/​src/​utils/​findingSeverity.ts Removes fixed severity helpers.
frontend/​src/​utils/​findingSeverity.test.ts Removes fixed severity tests.
frontend/​src/​utils/​findingFields.ts Adds field, cascade, and badge helpers.
frontend/​src/​utils/​findingFields.test.ts Tests configurable-field helpers.
frontend/​src/​types/​index.ts Defines configurable finding types.
frontend/​src/​test-utils/​findingFieldsFixtures.ts Adds default and custom field fixtures.
frontend/​src/​test-utils/​findingDialog.ts Adds shared dialog test helpers.
frontend/​src/​services/​api.ts Updates finding API methods.
frontend/​src/​services/​api.test.ts Tests revised API requests.
frontend/​src/​hooks/​useFindingFields.ts Loads fields and handles runtime refreshes.
frontend/​src/​hooks/​useFindingFields.test.tsx Tests loading, retries, and refreshes.
frontend/​src/​components/​Operations/​RetiredFieldValues.tsx Adds removal confirmation and undo controls.
frontend/​src/​components/​Operations/​RetiredFieldValues.test.tsx Tests retired-value controls and focus.
frontend/​src/​components/​Operations/​RetiredFieldValues.styles.ts Styles retired-value panels.
frontend/​src/​components/​Operations/​OperationsPage.tsx Renders configured severity counts.
frontend/​src/​components/​Operations/​OperationsPage.test.tsx Tests counts and field-loading failures.
frontend/​src/​components/​Operations/​Operations.styles.ts Styles configurable and retired values.
frontend/​src/​components/​Operations/​OperationDetailPage.tsx Integrates configurable finding displays and dialogs.
frontend/​src/​components/​Operations/​FindingSeverityBadge.tsx Uses configured severity labels and colors.
frontend/​src/​components/​Operations/​FindingFieldInput.tsx Adds text, choice, and cascade controls.
frontend/​src/​components/​Operations/​FindingFieldInput.styles.ts Styles configurable inputs.
frontend/​src/​components/​Operations/​FindingExportDialog.tsx Warns about excluded retired values.
frontend/​src/​components/​Operations/​FindingExportDialog.test.tsx Tests retired-value export warnings.
frontend/​src/​components/​Operations/​FindingDialog.tsx Builds drafts from configured fields.
frontend/​src/​components/​Operations/​FindingDialog.styles.ts Adds field-section styling.
frontend/​src/​components/​Operations/​FindingCardValues.tsx Displays configured and retired values.
frontend/​src/​components/​Chat/​FindingEvidenceDialog.tsx Uses configurable fields in evidence selection.
frontend/​src/​components/​Chat/​FindingEvidenceDialog.test.tsx Tests field-aware evidence workflows.
frontend/​e2e/​operations.spec.ts Updates requests and tests retired-value interactions.
doc/​myst.yml Adds finding-field documentation to navigation.
doc/​gui/​0_gui.md Describes deployment-defined finding fields.
doc/​code/​setup/​finding_fields.md Documents configuration, rules, and migration.

Review effort: Balanced

Comment thread frontend/src/utils/findingFields.ts Resolved
Comment thread pyrit/memory/memory_models.py Resolved
Comment thread pyrit/setup/configuration_loader.py Resolved
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@hannahwestra25 hannahwestra25 self-assigned this Nov 2, 2026
Re-point d43b1bcf9c56 after e7c4a2d9f013 from microsoft#3644, so the chain keeps a single head.

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

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

This branch has not been deployed

No deployments
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