Skip to content

Commit 7e46715

Browse files
authored
Merge branch 'main' into refactor/gcg-candidate-proposal-2665
2 parents 7e9401f + b581868 commit 7e46715

102 files changed

Lines changed: 7278 additions & 872 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/instructions/test.instructions.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ Most tests should be unit tests. Integration and end-to-end tests are for testin
2727
- Group tests in classes prefixed with `Test`
2828
- Use `@pytest.mark.usefixtures("patch_central_database")` on classes touching Central Memory
2929
- Reuse `tests/unit/mocks.py` helpers: `MockPromptTarget`, `get_sample_conversations`, `get_mock_target_identifier`, `openai_chat_response_json_dict`
30-
- Key fixtures from `tests/unit/conftest.py`: `patch_central_database`, `sqlite_instance`
30+
- Key memory fixtures from `tests/unit/conftest.py`:
31+
- Use `patch_central_database` for tests that access `CentralMemory` or construct targets, scorers, or attacks. Declare it explicitly even in constructor, validation, or identifier tests that do not directly query memory.
32+
- Use `sqlite_instance` when the test needs to interact with the real isolated SQLite backend.
33+
- Do not rely on memory or singleton state left behind by another test. Each test must declare its own memory dependency.
34+
- When changing shared memory fixtures, install all optional dependencies with `uv sync --extra all` and run `make unit-test`. Optional component tests must also exercise fixture isolation.
3135
- No network calls should ever happen in unit tests, but file access is okay
3236
- Unit tests should be fast and can be run in parallel.
3337

‎.pre-commit-config.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ repos:
6767
- id: detect-private-key
6868

6969
- repo: https://github.com/astral-sh/ruff-pre-commit
70-
rev: v0.16.6
70+
rev: v0.16.7
7171
hooks:
7272
- id: ruff-format
7373
- id: ruff-check

‎doc/code/executor/gcg/1_gcg_azure_ml.ipynb‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,10 +355,11 @@
355355
"The next cell polls the job until it reaches a terminal state (~20-30\n",
356356
"minutes for the small 5-step baseline above), then downloads the named\n",
357357
"`results` output and prints the final suffix. The runner writes its\n",
358-
"result file as `<result_prefix>_<timestamp>.json` (with `result_prefix`\n",
358+
"result file as `<result_prefix>_<timestamp>_<id>.json` (with `result_prefix`\n",
359359
"coming from the `GCGConfig` we built above, plus the AML output mount\n",
360-
"prepended by `--output-dir`). For our config, that resolves to\n",
361-
"`gcg_suffix_<timestamp>.json` under\n",
360+
"prepended by `--output-dir`; `<id>` is a short random suffix so concurrent\n",
361+
"runs never share a file). For our config, that resolves to\n",
362+
"`gcg_suffix_<timestamp>_<id>.json` under\n",
362363
"`<download_dir>/named-outputs/results/` once we download. The\n",
363364
"`controls` array in that file contains one entry per training step, and\n",
364365
"the last entry is the final adversarial suffix that, appended to the user\n",

‎doc/code/executor/gcg/1_gcg_azure_ml.py‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,11 @@
177177
# The next cell polls the job until it reaches a terminal state (~20-30
178178
# minutes for the small 5-step baseline above), then downloads the named
179179
# `results` output and prints the final suffix. The runner writes its
180-
# result file as `<result_prefix>_<timestamp>.json` (with `result_prefix`
180+
# result file as `<result_prefix>_<timestamp>_<id>.json` (with `result_prefix`
181181
# coming from the `GCGConfig` we built above, plus the AML output mount
182-
# prepended by `--output-dir`). For our config, that resolves to
183-
# `gcg_suffix_<timestamp>.json` under
182+
# prepended by `--output-dir`; `<id>` is a short random suffix so concurrent
183+
# runs never share a file). For our config, that resolves to
184+
# `gcg_suffix_<timestamp>_<id>.json` under
184185
# `<download_dir>/named-outputs/results/` once we download. The
185186
# `controls` array in that file contains one entry per training step, and
186187
# the last entry is the final adversarial suffix that, appended to the user

‎doc/code/registry/0_registry.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,31 @@ show_registry_contents(ScenarioRegistry.get_registry_singleton())
5454
| Instantiation | Caller provides parameters | Pre-configured by initializer |
5555
| When to use | Self-contained components with deferred configuration | Components requiring constructor parameters or compositional setup |
5656

57+
## Named Component Construction
58+
59+
Converter, target, and scorer registries use `InstanceHoldingRegistry` to build
60+
components and store them in their `.instances` registry. Use
61+
`create_named_instance(name=..., type_name=..., params=...)` to build and register
62+
a component in one operation. The instance registry stores objects; it does not
63+
construct them.
64+
65+
Duplicate names raise `ValueError`. Use `.instances.register(..., replace=True)`
66+
only when replacement is intended. Converter and target registries also reject
67+
reserved route names such as `catalog` and `types`. Use `.instances.unregister(name)`
68+
to remove an instance.
69+
70+
Constructor annotations define parameter metadata and coercion. Use `Path` for a
71+
local file input. Use `Path | str` when a component also supports a remote URL.
72+
For this union, the registry preserves the supplied type: a `Path` stays a `Path`,
73+
and a string stays a string. It never passes a URL through `Path`. Both union
74+
orders have the same metadata, `type_name: "Path | str"`, including after a JSON
75+
round-trip. Optional forms accept `None` in Python; the display type omits `None`,
76+
as it does for other optional parameters.
77+
78+
The backend owns file-upload handling and cleanup, not the registry. See the
79+
[registry API migration notes](../../gui/0_gui.md#registry-api-migration-notes)
80+
for the REST contract and temporary compatibility behavior.
81+
5782
## See Also
5883

5984
- [Class Registries](1_class_registry.ipynb) - ScenarioRegistry, InitializerRegistry

‎doc/contributing/5_unit_tests.md‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,23 @@ Testing is an art to get right! But here are some best practices in terms of uni
66

77
- Make a test that checks one thing and one thing only.
88
- Use `fixtures` generally, and specifically, if you're using something across classes, use `unit.mocks` or `integration.mocks`.
9-
- Memory isolation: Use the `patch_central_database` fixture for test database isolation and reset.
9+
- Memory isolation: Use `sqlite_instance` for a real, isolated SQLite database, or `patch_central_database` when patching CentralMemory access.
1010
- Code coverage and functionality should be checked with unit tests. Notebooks and integration tests should not be relied on for coverage.
1111
- `MagicMock` and `AsyncMock`: these are the preferred way to mock calls.
1212
- `with patch` is acceptable to patch external calls.
1313
- Don't write to the actual database, use a `MagicMock` for the memory object or use `patch_central_database` as the database connection.
1414

1515

1616
Not all of our current tests follow these practices (we're working on it!) But for some good examples, see [test_tts_send_prompt_file_save_async](../../tests/unit/prompt_target/target/test_tts_target.py), which has many of these best practices incorporated in the test.
17+
18+
## SQLite memory fixtures
19+
20+
`sqlite_instance` stays function-scoped. Each test gets a fresh in-memory database and results directory, and its SQLite singleton and CentralMemory registrations are restored afterward. The fixture owns disposal of its memory instance instead of registering process-exit cleanup callbacks for every test.
21+
22+
Declare the memory fixture explicitly even in constructor or identity tests that create targets, scorers, or attacks. Do not rely on another test leaving CentralMemory initialized.
23+
24+
Run `uv sync --extra all` before validating fixture changes with `make unit-test` so optional target tests also exercise memory isolation.
25+
26+
To avoid replaying the migration history for every ordinary test, `sqlite_template` runs the real Alembic migrations and schema check once per pytest session (once in each xdist worker). SQLite's backup API copies that private, read-only template into each test's database. Rows, schema changes, temporary tables, and result files are not shared between tests.
27+
28+
Tests of initialization, upgrades, downgrades, schema checks, and `reset_database()` must still call those production paths explicitly. The fixture does not replace or patch migration or reset APIs.

‎doc/gui/0_gui.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,33 @@ Use **Reload** to discard local edits and fetch the latest source content. Saved
190190

191191
---
192192

193+
## Registry API Migration Notes
194+
195+
Use `/api/converters/types` and `/api/targets/types` for registry build metadata.
196+
These endpoints return all constructor parameters from the registry, including
197+
lists, unions, and component references. The temporary `/catalog` routes retain
198+
their scalar-only filtering for the current UI.
199+
Create requests should supply an explicit registry `name`. Converter creation
200+
returns the complete `ConverterInstance`; read its type from
201+
`identifier.class_name`, not the old top-level `converter_type` field. Treat
202+
returned IDs as opaque registry names, not UUIDs or identifier hashes.
203+
204+
Constructor parameters typed as `Path` accept base64 data-URI uploads through REST,
205+
not server filesystem paths. Parameters typed as `Path | str` also accept Azure
206+
Blob URLs. This applies to `AddImageVideoConverter.video_path` and
207+
`ImageOverlayConverter.base_image`. Other local file inputs remain `Path`.
208+
Uploads stay in backend-owned temporary storage until deletion or shutdown,
209+
including with Azure-backed memory. Converter outputs still use configured result
210+
storage. Uploads can contain any file type; the media endpoint renders only
211+
allowlisted image, audio, and video extensions inline. Other files, including PDF,
212+
SVG, HTML, text, and executables, download as `application/octet-stream` attachments.
213+
214+
**Temporary compatibility, scheduled for removal with the chat migration:**
215+
the `/api/converters/catalog` and `/api/targets/catalog` routes project the same
216+
registry metadata for the current UI. Create requests without a name receive a
217+
generated `compat_...` name. New clients should not depend on these routes or
218+
unnamed creation.
219+
193220
## Connection Health
194221

195222
CoPyRIT monitors the backend connection and shows a status banner:

‎frontend/e2e/_attacks.ts‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import type { AddMessageResponse, BackendMessage } from "@/types";
1+
import type { AddMessageResponse, BackendMessage, TargetResponseStatus } from "@/types";
22

33
export function makeAddMessageResponse(
44
attackResultId: string,
55
conversationId: string,
66
messages: BackendMessage[],
7+
targetResponseStatus: TargetResponseStatus | null = null,
78
): AddMessageResponse {
89
return {
910
attack: {
@@ -19,6 +20,10 @@ export function makeAddMessageResponse(
1920
created_at: "2026-01-01T00:00:00Z",
2021
updated_at: "2026-01-01T00:00:00Z",
2122
},
22-
messages: { conversation_id: conversationId, messages },
23+
messages: {
24+
conversation_id: conversationId,
25+
messages,
26+
target_response_status: targetResponseStatus,
27+
},
2328
};
2429
}

0 commit comments

Comments
 (0)