fix(tests): apply user edits when creating test from template
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
The form captured name/description/platform/procedure/tool edits but never sent them — the created test always used the raw template values. - TestTemplateInstantiate schema: add optional override fields (name, description, platform, procedure_text, tool_used) - create_test_from_template service: accept *_override kwargs; use override value when provided, fall back to template value - Router: pass all override fields from payload to service - Frontend API createTestFromTemplate: accept overrides object, spread into body - TestFromTemplateForm: pass all form state values as overrides Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -185,6 +185,11 @@ def create_test_from_template(
|
|||||||
template_id=payload.template_id,
|
template_id=payload.template_id,
|
||||||
technique_id_or_mitre=payload.technique_id,
|
technique_id_or_mitre=payload.technique_id,
|
||||||
creator_id=current_user.id,
|
creator_id=current_user.id,
|
||||||
|
name_override=payload.name,
|
||||||
|
description_override=payload.description,
|
||||||
|
platform_override=payload.platform,
|
||||||
|
procedure_text_override=payload.procedure_text,
|
||||||
|
tool_used_override=payload.tool_used,
|
||||||
)
|
)
|
||||||
log_action(
|
log_action(
|
||||||
db,
|
db,
|
||||||
|
|||||||
@@ -72,7 +72,17 @@ class TestTemplateSummary(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class TestTemplateInstantiate(BaseModel):
|
class TestTemplateInstantiate(BaseModel):
|
||||||
"""Payload to create a real test from an existing template."""
|
"""Payload to create a real test from an existing template.
|
||||||
|
|
||||||
|
Optional override fields take precedence over the template values when provided.
|
||||||
|
"""
|
||||||
|
|
||||||
template_id: uuid.UUID
|
template_id: uuid.UUID
|
||||||
technique_id: str # accepts both UUID and MITRE ID (e.g. "T1059.001")
|
technique_id: str # accepts both UUID and MITRE ID (e.g. "T1059.001")
|
||||||
|
|
||||||
|
# User-editable overrides (if omitted the template value is used)
|
||||||
|
name: str | None = None
|
||||||
|
description: str | None = None
|
||||||
|
platform: str | None = None
|
||||||
|
procedure_text: str | None = None
|
||||||
|
tool_used: str | None = None
|
||||||
|
|||||||
@@ -93,10 +93,17 @@ def create_test_from_template(
|
|||||||
template_id: uuid.UUID,
|
template_id: uuid.UUID,
|
||||||
technique_id_or_mitre: str,
|
technique_id_or_mitre: str,
|
||||||
creator_id: uuid.UUID,
|
creator_id: uuid.UUID,
|
||||||
|
# Optional user-edited overrides (take priority over template values)
|
||||||
|
name_override: str | None = None,
|
||||||
|
description_override: str | None = None,
|
||||||
|
platform_override: str | None = None,
|
||||||
|
procedure_text_override: str | None = None,
|
||||||
|
tool_used_override: str | None = None,
|
||||||
) -> Test:
|
) -> Test:
|
||||||
"""Instantiate a Test from a TestTemplate.
|
"""Instantiate a Test from a TestTemplate.
|
||||||
|
|
||||||
technique_id_or_mitre can be a UUID string or MITRE ID (e.g. T1059.001).
|
technique_id_or_mitre can be a UUID string or MITRE ID (e.g. T1059.001).
|
||||||
|
Override fields, when provided, take precedence over the template's values.
|
||||||
Raises EntityNotFoundError if template or technique not found.
|
Raises EntityNotFoundError if template or technique not found.
|
||||||
Does not commit; caller uses UnitOfWork.
|
Does not commit; caller uses UnitOfWork.
|
||||||
"""
|
"""
|
||||||
@@ -121,11 +128,11 @@ def create_test_from_template(
|
|||||||
|
|
||||||
test = Test(
|
test = Test(
|
||||||
technique_id=technique.id,
|
technique_id=technique.id,
|
||||||
name=template.name,
|
name=name_override if name_override is not None else template.name,
|
||||||
description=template.description,
|
description=description_override if description_override is not None else template.description,
|
||||||
platform=template.platform,
|
platform=platform_override if platform_override is not None else template.platform,
|
||||||
procedure_text=template.attack_procedure,
|
procedure_text=procedure_text_override if procedure_text_override is not None else template.attack_procedure,
|
||||||
tool_used=template.tool_suggested,
|
tool_used=tool_used_override if tool_used_override is not None else template.tool_suggested,
|
||||||
remediation_steps=template.suggested_remediation,
|
remediation_steps=template.suggested_remediation,
|
||||||
created_by=creator_id,
|
created_by=creator_id,
|
||||||
state=TestState.draft,
|
state=TestState.draft,
|
||||||
|
|||||||
@@ -91,14 +91,22 @@ export async function createTest(payload: TestCreatePayload): Promise<Test> {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create a test from an existing template. */
|
/** Create a test from an existing template, with optional field overrides. */
|
||||||
export async function createTestFromTemplate(
|
export async function createTestFromTemplate(
|
||||||
templateId: string,
|
templateId: string,
|
||||||
techniqueId: string,
|
techniqueId: string,
|
||||||
|
overrides?: {
|
||||||
|
name?: string;
|
||||||
|
description?: string;
|
||||||
|
platform?: string;
|
||||||
|
procedure_text?: string;
|
||||||
|
tool_used?: string;
|
||||||
|
},
|
||||||
): Promise<Test> {
|
): Promise<Test> {
|
||||||
const { data } = await client.post<Test>("/tests/from-template", {
|
const { data } = await client.post<Test>("/tests/from-template", {
|
||||||
template_id: templateId,
|
template_id: templateId,
|
||||||
technique_id: techniqueId,
|
technique_id: techniqueId,
|
||||||
|
...overrides,
|
||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,14 @@ export default function TestFromTemplateForm({
|
|||||||
// ── Submit ─────────────────────────────────────────────────────
|
// ── Submit ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
const createMutation = useMutation({
|
const createMutation = useMutation({
|
||||||
mutationFn: () => createTestFromTemplate(templateId, technique),
|
mutationFn: () =>
|
||||||
|
createTestFromTemplate(templateId, technique, {
|
||||||
|
name: name.trim() || undefined,
|
||||||
|
description: description.trim() || undefined,
|
||||||
|
platform: platform.trim() || undefined,
|
||||||
|
procedure_text: procedureText.trim() || undefined,
|
||||||
|
tool_used: toolUsed.trim() || undefined,
|
||||||
|
}),
|
||||||
onSuccess: (test) => {
|
onSuccess: (test) => {
|
||||||
navigate(`/tests/${test.id}`);
|
navigate(`/tests/${test.id}`);
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user