82ac9c7014
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled
- TestTemplate/TemplateSuggestion creation and updates now reject any mitre_technique_id that doesn't match a real, already-synced MITRE ATT&CK technique. Frontend swaps the free-text ID input for a technique picker. - Test Catalog now shows pending template suggestions before the catalog grid, with full field detail (platform, severity, tool, atomic ID, source URL, remediation) instead of just name/procedure. - A manager can edit and directly re-approve a campaign they previously rejected, instead of needing the original lead to resubmit it.
79 lines
3.0 KiB
Python
79 lines
3.0 KiB
Python
"""A TestTemplate/TemplateSuggestion's mitre_technique_id must correspond
|
|
to a real, already-synced MITRE ATT&CK technique — free text or a typo'd
|
|
ID would otherwise create an orphaned template invisible to technique
|
|
lookups and coverage reporting.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture
|
|
def technique(api, auth_headers):
|
|
resp = api(
|
|
"post", "/api/v1/techniques", auth_headers,
|
|
json={"mitre_id": "T1059.500", "name": "Command Line MITRE Validation"},
|
|
)
|
|
assert resp.status_code == 201, resp.text
|
|
return resp.json()["id"]
|
|
|
|
|
|
class TestTemplateCreateValidation:
|
|
def test_create_template_rejects_unknown_mitre_id(self, api, red_lead_headers, technique):
|
|
resp = api(
|
|
"post", "/api/v1/test-templates", red_lead_headers,
|
|
json={"mitre_technique_id": "T9999.999", "name": "Bogus template"},
|
|
)
|
|
assert resp.status_code == 400
|
|
assert "T9999.999" in resp.text
|
|
|
|
def test_create_template_accepts_known_mitre_id(self, api, red_lead_headers, technique):
|
|
resp = api(
|
|
"post", "/api/v1/test-templates", red_lead_headers,
|
|
json={"mitre_technique_id": "T1059.500", "name": "Valid template"},
|
|
)
|
|
assert resp.status_code == 201, resp.text
|
|
|
|
def test_update_template_rejects_unknown_mitre_id(self, api, red_lead_headers, technique):
|
|
created = api(
|
|
"post", "/api/v1/test-templates", red_lead_headers,
|
|
json={"mitre_technique_id": "T1059.500", "name": "Will be edited"},
|
|
)
|
|
template_id = created.json()["id"]
|
|
|
|
resp = api(
|
|
"patch", f"/api/v1/test-templates/{template_id}", red_lead_headers,
|
|
json={"mitre_technique_id": "T0000.000", "name": "Will be edited"},
|
|
)
|
|
assert resp.status_code == 400
|
|
|
|
|
|
class TestTemplateSuggestionValidation:
|
|
def test_propose_template_rejects_unknown_mitre_id(self, api, red_tech_headers, technique):
|
|
resp = api(
|
|
"post", "/api/v1/template-suggestions", red_tech_headers,
|
|
json={"mitre_technique_id": "T8888.888", "name": "Bogus proposal"},
|
|
)
|
|
assert resp.status_code == 400
|
|
|
|
def test_propose_template_accepts_known_mitre_id(self, api, red_tech_headers, technique):
|
|
resp = api(
|
|
"post", "/api/v1/template-suggestions", red_tech_headers,
|
|
json={"mitre_technique_id": "T1059.500", "name": "Valid proposal"},
|
|
)
|
|
assert resp.status_code == 201, resp.text
|
|
|
|
def test_approve_suggestion_with_edited_unknown_mitre_id_rejected(
|
|
self, api, red_tech_headers, red_lead_headers, technique,
|
|
):
|
|
created = api(
|
|
"post", "/api/v1/template-suggestions", red_tech_headers,
|
|
json={"mitre_technique_id": "T1059.500", "name": "Valid proposal"},
|
|
)
|
|
suggestion_id = created.json()["id"]
|
|
|
|
resp = api(
|
|
"post", f"/api/v1/template-suggestions/{suggestion_id}/approve", red_lead_headers,
|
|
json={"mitre_technique_id": "T7777.777"},
|
|
)
|
|
assert resp.status_code == 400
|