Skip to content

Commit 7585261

Browse files
authored
Merge pull request #2026 from Automattic/feat/2019-adversarial-recipe-orchestration
Run adversarial campaigns from workspace recipes
2 parents b244619 + 94f9f26 commit 7585261

18 files changed

Lines changed: 842 additions & 16 deletions

docs/recipe-contract.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ top-level fields:
8686
- `inputs`
8787
- `workflow`
8888
- `fuzzRun`
89+
- `adversarialCampaigns`
8990
- `artifacts`
9091
- `probes`
9192
- `metadata`
@@ -124,6 +125,37 @@ Use `inputs.workspace_preloads` for generic `agent-runtime/workspace-preload`
124125
artifact contracts. WP Codebox materializes declared repositories as sandbox
125126
workspace mounts; callers own the policy that decides which artifacts to pass.
126127

128+
## Adversarial Campaigns
129+
130+
`adversarialCampaigns` additively declares deterministic corpus campaigns without
131+
changing authored `fuzzRun.cases`. Each corpus action selects a registered
132+
`caseTemplates` id. Generated plans interpolate `{{case.id}}`, `{{case.input}}`,
133+
`{{action.input}}`, `{{action.inputBase64}}`, `{{matrix}}`, and
134+
`{{matrix.<name>}}` into template arguments, then execute the resulting phases
135+
through the existing runtime-backed fuzz suite, checkpoint, episode, command
136+
policy, and artifact lifecycle.
137+
138+
The built-in mutator registry contains `scalar`, `structured`, `binary`, and
139+
`sequence`; the initial neutral oracle registry contains `runtime-status`.
140+
Required capabilities fail recipe validation before services or runtimes start.
141+
Optional capabilities are reported with explicit availability in run evidence.
142+
Concurrency above one requires an `isolated-workers` capability and therefore
143+
fails closed until the selected recipe runtime provides isolated workers.
144+
145+
Run and replay through stable CLI routes:
146+
147+
```bash
148+
wp-codebox adversarial run --recipe examples/recipes/adversarial-stateful.json --json
149+
wp-codebox adversarial replay --recipe recipe.json --replay files/adversarial/<campaign>/replay/<fingerprint>.json --json
150+
```
151+
152+
Every campaign writes a bounded nested bundle under
153+
`files/adversarial/<campaign>/`, including the result, fingerprint-addressed
154+
findings, minimized replay envelopes, a manifest, and secret-scan evidence. The
155+
parent artifact manifest retains all nested files. Interruption returns bounded
156+
partial campaign evidence before the recipe runner performs its normal runtime
157+
and service teardown.
158+
127159
## External Service Boundaries
128160

129161
Use `inputs.externalServices` to declare reviewer-safe boundaries for services a
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
{
2+
"schema": "wp-codebox/workspace-recipe/v1",
3+
"runtime": {
4+
"backend": "wordpress"
5+
},
6+
"workflow": {
7+
"steps": [
8+
{
9+
"command": "wordpress.run-php",
10+
"args": ["code=delete_option( 'wp_codebox_adversarial_state' );"]
11+
}
12+
]
13+
},
14+
"adversarialCampaigns": [
15+
{
16+
"schema": "wp-codebox/adversarial-recipe-campaign/v1",
17+
"id": "neutral-stateful",
18+
"seed": "neutral-stateful-v1",
19+
"corpus": [
20+
{
21+
"id": "option-seed",
22+
"actions": [
23+
{
24+
"type": "option-roundtrip",
25+
"input": {
26+
"value": "alpha"
27+
}
28+
}
29+
],
30+
"input": {
31+
"source": "recipe"
32+
},
33+
"signals": ["baseline"]
34+
}
35+
],
36+
"caseTemplates": [
37+
{
38+
"id": "option-roundtrip",
39+
"phases": {
40+
"action": [
41+
{
42+
"command": "wordpress.run-php",
43+
"args": ["code=$value = json_decode( base64_decode( '{{action.inputBase64}}' ), true ); update_option( 'wp_codebox_adversarial_state', $value );"]
44+
}
45+
],
46+
"assert": [
47+
{
48+
"command": "wordpress.run-php",
49+
"args": ["code=if ( get_option( 'wp_codebox_adversarial_state', null ) === null ) { throw new RuntimeException( 'state was not retained' ); }"]
50+
}
51+
],
52+
"teardown": [
53+
{
54+
"command": "wordpress.run-php",
55+
"args": ["code=delete_option( 'wp_codebox_adversarial_state' );"]
56+
}
57+
]
58+
}
59+
}
60+
],
61+
"mutators": ["scalar", "structured", "sequence"],
62+
"oracles": [
63+
{
64+
"id": "runtime-status",
65+
"severity": "high"
66+
}
67+
],
68+
"matrix": [
69+
{
70+
"name": "storage",
71+
"values": ["options"]
72+
}
73+
],
74+
"concurrency": 1,
75+
"budgets": {
76+
"maxCases": 8,
77+
"maxActionsPerCase": 8,
78+
"maxInputBytes": 65536,
79+
"maxCaseTimeMs": 10000,
80+
"maxWallTimeMs": 120000,
81+
"maxArtifactBytes": 10485760
82+
},
83+
"resetPolicy": {
84+
"mode": "checkpoint-per-case",
85+
"checkpointName": "neutral-stateful-baseline"
86+
},
87+
"requiredCapabilities": ["adversarial-campaign", "artifact-export", "command:wordpress.run-php"],
88+
"optionalCapabilities": ["transport-faults"],
89+
"novelty": {
90+
"retainSignals": true
91+
},
92+
"shrinking": {
93+
"enabled": true
94+
},
95+
"replay": {
96+
"selection": "findings"
97+
}
98+
}
99+
]
100+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@
230230
"test:recipe-run-provenance": "tsx tests/recipe-run-provenance.test.ts",
231231
"test:fuzz-run-recipe": "tsx tests/fuzz-run-recipe.test.ts",
232232
"test:fuzz-suite-runner": "tsx tests/fuzz-suite-runner.test.ts",
233-
"test:adversarial-runtime": "tsx --test tests/transport-faults.test.ts tests/adversarial-campaign.test.ts tests/adversarial-browser.test.ts tests/browser-clock-control.test.ts",
233+
"test:adversarial-runtime": "tsx --test tests/transport-faults.test.ts tests/adversarial-campaign.test.ts tests/adversarial-browser.test.ts tests/browser-clock-control.test.ts tests/adversarial-recipe-orchestration.test.ts",
234234
"test:playground-fuzz-suite-public": "tsx tests/playground-fuzz-suite-public.test.ts",
235235
"test:nested-fuzz-suite-recipe-command": "tsx tests/nested-fuzz-suite-recipe-command.test.ts",
236236
"test:wordpress-fuzz-suite-builders": "tsx tests/wordpress-fuzz-suite-builders.test.ts",

0 commit comments

Comments
 (0)