Skip to content

Commit c751155

Browse files
authored
Expose recipe fuzz results as typed workload artifacts (#1880)
1 parent 2f58c6c commit c751155

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

packages/cli/src/commands/recipe-run-workflow-evidence.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ function recipeWorkloadArtifactPayloads(execution: ExecutionResult, artifact: st
395395

396396
function collectRecipeArtifactPayloadsFromContainer(container: Record<string, unknown> | undefined, artifact: string, expectedSchema: string | undefined, out: Array<{ name: string; payload: Record<string, unknown> }>): void {
397397
if (!container) return
398+
collectRecipeFuzzSuiteArtifactPayloads(container, artifact, expectedSchema, out)
398399
const artifacts = isRecord(container.artifacts) ? container.artifacts : undefined
399400
for (const [name, value] of Object.entries(artifacts ?? {})) {
400401
if (!artifactNameMatches(name, artifact)) continue
@@ -409,6 +410,22 @@ function collectRecipeArtifactPayloadsFromContainer(container: Record<string, un
409410
}
410411
}
411412

413+
function collectRecipeFuzzSuiteArtifactPayloads(result: Record<string, unknown>, artifact: string, expectedSchema: string | undefined, out: Array<{ name: string; payload: Record<string, unknown> }>): void {
414+
if (result.schema !== "wp-codebox/fuzz-suite-result/v1" || (expectedSchema && result.schema !== expectedSchema)) return
415+
const add = (name: string) => {
416+
if (!artifact || artifactNameMatches(name, artifact)) out.push({ name, payload: result })
417+
}
418+
419+
// Keep the normalized result envelope intact; consumers receive real fuzz evidence, not a lossy wrapper.
420+
add("wp-codebox-fuzz-suite-result")
421+
add("result-envelope")
422+
if (Array.isArray(result.cases)) add("case-log")
423+
if (isRecord(result.coverageSummary)) add("coverage-summary")
424+
if (Array.isArray(result.cases) && result.cases.some((fuzzCase) => isRecord(fuzzCase) && isRecord(fuzzCase.metadata) && isRecord(fuzzCase.metadata.replay))) {
425+
add("replay-data")
426+
}
427+
}
428+
412429
function recipeRestDbQueryProfilesFromJson(json: Record<string, unknown> | undefined): Array<{ profile: Record<string, unknown> }> {
413430
const profiles: Array<{ profile: Record<string, unknown> }> = []
414431
if (!json) return profiles

tests/nested-fuzz-suite-recipe-command.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,4 +318,36 @@ assert.equal(fallbackExecution.exitCode, 0)
318318
assert.equal(fallbackResult.status, "passed")
319319
assert.deepEqual(executed.map((spec) => spec.command), ["wordpress.run-php", "wordpress.run-php"])
320320

321+
executed.length = 0
322+
const collectableFuzzSuiteWorkload: WorkspaceRecipe = {
323+
schema: "wp-codebox/workspace-recipe/v1",
324+
workflow: {
325+
steps: [{ command: "wordpress.run-workload", args: [`workload-json=${JSON.stringify({
326+
schema: "wp-codebox/wordpress-workload-run/v1",
327+
steps: [{ command: "wp-codebox/run-fuzz-suite", args: [`input-json=${JSON.stringify(suite)}`] }],
328+
after: [
329+
{ command: "wordpress.collect-workload-result", args: ["artifact=wp-codebox-fuzz-suite-result"] },
330+
{ command: "wordpress.collect-workload-result", args: ["artifact=case-log"] },
331+
{ command: "wordpress.collect-workload-result", args: ["artifact=coverage-summary"] },
332+
{ command: "wordpress.collect-workload-result", args: ["artifact=result-envelope"] },
333+
{ command: "wordpress.collect-workload-result", args: ["artifact=replay-data"] },
334+
],
335+
})}`] }],
336+
},
337+
}
338+
assertWorkspaceRecipeJsonSchema(collectableFuzzSuiteWorkload, { recipeCommandIds: ["wordpress.run-workload", "wp-codebox/run-fuzz-suite", "wordpress.run-php", "wordpress.collect-workload-result"] })
339+
const collectableFuzzSuiteExecution = await executeRecipeWorkflowStep(runtime, { phase: "steps", index: 0, step: collectableFuzzSuiteWorkload.workflow.steps[0]! }, process.cwd())
340+
const collectableFuzzSuiteResult = JSON.parse(collectableFuzzSuiteExecution.stdout)
341+
assert.equal(collectableFuzzSuiteExecution.exitCode, 0)
342+
assert.equal(collectableFuzzSuiteResult.steps, 6)
343+
for (const artifact of ["wp-codebox-fuzz-suite-result", "case-log", "coverage-summary", "result-envelope", "replay-data"]) {
344+
const payload = collectableFuzzSuiteResult.artifacts[artifact]
345+
assert.equal(payload.schema, "wp-codebox/fuzz-suite-result/v1")
346+
assert.equal(payload.status, "passed")
347+
assert.equal(payload.cases[0].id, "case-one")
348+
}
349+
assert.equal(collectableFuzzSuiteResult.artifacts["coverage-summary"].coverageSummary.executed, 1)
350+
assert.equal(collectableFuzzSuiteResult.artifacts["replay-data"].cases[0].metadata.replay.caseId, "case-one")
351+
assert.deepEqual(executed.map((spec) => spec.command), ["wordpress.run-php"])
352+
321353
console.log("nested fuzz suite recipe command ok")

0 commit comments

Comments
 (0)