Skip to content

FEAT: Change saved registry entries through the API (part 21) - #4072

Open
varunj-msft wants to merge 246 commits into
microsoft:mainfrom
varunj-msft:varunj-msft/13178-Edit-Saved-Entries
Open

varunj-msft wants to merge 246 commits into
microsoft:mainfrom
varunj-msft:varunj-msft/13178-Edit-Saved-Entries

Conversation

@varunj-msft

@varunj-msft varunj-msft commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Description

Part 21 of saving Registry entries across restarts. Stacked on part 20 (#4071); changing saved entries from the Registry tabs comes after it. This PR's own changes: varunj-msft/PyRIT@varunj-msft/13178-Delete-Saved-Entries...varunj-msft/13178-Edit-Saved-Entries

Design: 4.7 Editing and deleting, 4.6 When a saved entry can't be restored. Where every part fits: PR map.

This is one of the changes for saving Registry entries across restarts. Until the earlier PRs merge, the diff here also shows their changes.

Fixing a saved entry, including one that failed to restore, meant deleting it and saving it again under the same name.

  • GET /api/saved-entries/{kind}/{name} now returns the stored recipe to a caller who may change the entry. PUT /api/saved-entries/{kind}/{name} takes it back, changed, with the version it read as expected_version.
  • A target, converter or scorer changes its params. A technique changes anything its create request takes except its name, attack type and persist. The name, the class or attack type, and who saved the entry stay the same, and the entry stays saved (422 otherwise).
  • The entry is rebuilt through the API that creates one, so every check a new entry gets still applies: no credentials, no Temporary entries, the settings only an administrator may use, and the typed 400 for settings that can't be saved.
  • The recipe is overwritten only if it is still the version read (409 otherwise), under the same lock saving and deleting take.
  • The running entry is replaced. If the edit fails, it's put back, and if the new entry can't be registered after the write, the old recipe is written back.
  • Registered entries that hold the old entry keep it until the next apply or restart; the response lists them in still_using_old. The old entry's resources are released only when nothing holds it and no work is in progress.
  • An entry that failed to restore is only saved (running is false); Retry restores it.

What stays the same: creating, deleting and restoring work as before, and settings changed for one run in the Scanner are still never saved.

Not covered:

  • Changing saved entries from the Registry tabs comes next, with the target, converter and technique dialogs in an edit mode. Until then, use the API.

varunj-msft and others added 30 commits October 26, 2026 20:05
…API input

External construction now rejects a parameter whose type includes Path unless the
calling service passes the name in allowed_path_params after making the value safe.
The converter service allows its upload parameters once they are stored, and the
target service allows the server-set upload folder and the GitHubCopilotTarget
working directory. The scorer-only check is removed, and the "Valid parameters"
list leaves out path parameters callers cannot set.
The target catalog now applies the path rule to required parameters too, so a
target that needs a disallowed path is left out instead of listed without the
field, matching the scorer catalog. allowed_path_params is typed frozenset[str]
so a bare string cannot turn the allow-list into a substring match.
The target catalog still lists a target whose required path parameter is its
server-set upload folder when the server has one, and leaves it out otherwise.
DELETE /api/scenario-presets/{name} and /api/scenario-suites/{name} accept an
optional ?expected_version= query. When supplied, the delete is refused with 409
if the stored document changed after the caller read it, so confirming a delete
in the GUI cannot discard an edit the caller never saw. Without it the delete
stays unconditional, preserving existing callers.

Locally the version is compared inside the existing per-document lock; on Azure
Blob the delete carries the read ETag with MatchConditions.IfNotModified. A
versioned delete of a document that is already gone still reports 404.

The preset and suite libraries send the version they loaded and, on 409, close
the confirmation, reload, and explain that the item changed.

Follow-up to review feedback on microsoft#3057.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
# Conflicts:
#	tests/unit/backend/test_converter_service.py
The OpenAI SDK adds that variable's headers to every request, so a saved
OpenAI target would send whatever the server puts there, which can be a
credential. While it's set, saving an OpenAI target is refused and a
saved one isn't restored; the message names the variable, never its
value. Targets declare such variables in server_header_variables.
Saving converters and scorers follows the same rules as saving targets now: a type that only a scan's launch script added can't be saved, a class without cached metadata is checked the way restore checks it, only a taken name is reported as a conflict, a storage failure logs its short reason, and the owner is recorded only when the entry is saved.
Saving a technique follows the same rules as the other saved entries now: an attack type that only a scan's launch script added can't be saved, a name or tag clash while registering is a conflict, and the owner is recorded only when the technique is saved. A held technique name is refused when a technique is checked before saving too.
An edit of a saved entry that couldn't be restored now registers it once its new settings work, which frees its name; an edit that still fails keeps the name held. Only a taken name is reported as a conflict, and storage failures are caught as storage errors.

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