Skip to content

FEAT: Save techniques (part 14) - #4066

Open
varunj-msft wants to merge 353 commits into
microsoft:mainfrom
varunj-msft:varunj-msft/13178-Save-Techniques
Open

varunj-msft wants to merge 353 commits into
microsoft:mainfrom
varunj-msft:varunj-msft/13178-Save-Techniques

Conversation

@varunj-msft

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

Copy link
Copy Markdown
Contributor

Description

Part 14 of saving Registry entries across restarts. Stacked on part 13 (#4052); part 15 (#4067) builds on it. This PR's own changes: varunj-msft/PyRIT@varunj-msft/13178-Save-Converters-From-Registry...varunj-msft/13178-Save-Techniques

Design: 4.1 What gets saved, 4.3 What a recipe holds. Where every part fits: PR map.

This is one of the changes for saving Registry entries across restarts. It builds on #4052, which saves converters from the Registry. Until the earlier PRs merge, the diff here also shows their changes.

A technique made with New technique, or through POST /api/techniques, was gone after the backend restarted. It now saves by default and comes back at every start, like saved targets and converters.

  • POST /api/techniques takes "persist": true. A saved technique's name follows the saved-name rule (lowercase letters, digits and underscores, starting with a letter, up to 64 characters), or the request gets a 422. Its recipe is the create request without the name, plus who saved it.
  • A technique that uses a Temporary converter or adversarial target can't be saved, since those are gone after a restart (typed 400, /errors/not-saveable). Its attack type and attack parameters get the checks restore runs, so a type that can't be saved, a credential, or a Temporary entry named in the parameters is refused the same way. A name another technique has, or a tag that matches a technique's name or another spelling of a tag in use, is a 409 before anything is written, and storage that can't be written is a 503.
  • Restore rebuilds a saved technique with the call the API uses, after the converters and targets it names, and keeps who saved it out of the attack's settings. Techniques the startup scripts register are marked From configuration.
  • A scan's launch script that registers a technique under a saved technique's name or one of its tags stops the scan, even when the script catches the refusal, so the saved technique can't run in its place.
  • GET /api/techniques gives each technique an origin: saved, configuration or temporary.
  • The technique editor saves by default. When a converter or adversarial target it uses is Temporary, or the backend refuses those exact settings, the button reads Create as Temporary and a warning says why. A taken name shows on the name field.
  • The Techniques table labels each technique Saved, From configuration or Temporary. The backend README and the GUI doc cover saving techniques.

What stays the same: a technique created without persist is Temporary, as before. Settings changed for one run in the Scanner (POST /api/techniques/{name}/edit) are never saved. Startup techniques work as before; they're only labeled From configuration.

Screenshots: New technique saves by default, the saved technique in the Techniques table, and a technique that uses a Temporary converter offered as Temporary with the reason.
techniques_1_new_technique_saves_by_default
techniques_2_saved_technique_row
techniques_3_temporary_converter_offers_temporary

Not covered:

The dialog asks for a registry name and suggests one, saves the target by
default, and creates a Temporary target only when it can't be saved, saying
why before it is created. The Targets table labels each target Saved, From
configuration or Temporary.
# Conflicts:
#	pyrit/registry/registry_recipe_restore.py
# Conflicts:
#	pyrit/registry/registry_recipe_restore.py
# Conflicts:
#	tests/unit/registry/test_instance_registry.py
…entials

The Azure Speech converters and the Azure Content Safety scorer read this
server's key when theirs is empty, or else sign in with its Azure identity, and
no value turns that off. They now declare that key as a server fallback, so a
saved one is refused when it's saved or restored, as saved targets already are.
The audio scorers transcribe with this server's Speech settings, and the local
refusal classifier scorer can load its model from a folder on this server or
download it with this server's Hugging Face sign-in, so those can't be saved.

A class that declares no auth modes now supports only api_key in the saved-entry
check, as the saveability check already assumed, so a recipe can't pass by
adding an auth_mode the class doesn't take.
Only targets can be saved through the API so far. The steps that turn off the
server values an entry would read, refuse what it still can't hold or a
Temporary entry it names, write its recipe, register it, and delete the recipe
again if registering fails move from the target service into a shared module,
along with the route helpers for the owner and the not-saveable problem. The
origin enum becomes RegistryEntryOrigin, read by registry_entry_origin, so
converters and scorers can use the same pieces. Targets behave as before.
POST /api/converters and POST /api/scorers take "persist": true, as
POST /api/targets does: the entry is built the way restore builds it, saved
under registry_recipes_source with the signed-in user, and restored at every
start. An entry that would use a Temporary target is refused, as is one that
would use this server's credentials. A converter that would keep an uploaded
file, or a copy made with source, can't be saved yet.

Each listed converter and scorer carries its origin, and the converters and
scorers the startup scripts register are marked as coming from configuration.
A saved converter can't be removed through the API yet, since it would come
back from its file at the next start.
The runtime status keeps its short summary. The restore log now also lists each field's full location
and message, escaped, without the stored values, and with URL credentials removed. Credentials are
removed before a location is shortened, so the summary can't keep part of one either.
# Conflicts:
#	pyrit/registry/registry_recipe_storage.py

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.

3 participants