fix(backend): resolve refresh-token expiry deadlock, missing Jira on normal campaign approval, discarded threat-actor campaign start_date
- /auth/refresh now allows a short grace window past expiry and checks the blacklist, so an active session's silent refresh no longer fails the instant its own token expires - normal manager /approve flow now creates Jira tickets for the campaign and its already-linked tests, matching the admin-only /activate path - GenerateFromActorPayload now accepts start_date and threads it through to the new campaign instead of silently discarding it
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
"""Tests for generating a campaign from a threat actor's uncovered techniques.
|
||||
|
||||
Covers the Block 1 fix: the frontend sends a `start_date` when generating a
|
||||
campaign from a Threat Actor, but `GenerateFromActorPayload` used to be an
|
||||
empty schema, so the date was silently discarded and the campaign was
|
||||
created with `start_date = NULL`.
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from app.models.enums import TechniqueStatus
|
||||
from app.models.technique import Technique
|
||||
from app.models.test_template import TestTemplate
|
||||
from app.models.threat_actor import ThreatActor, ThreatActorTechnique
|
||||
from app.services.campaign_service import generate_campaign_from_threat_actor
|
||||
|
||||
|
||||
def _seed_actor_with_gap_technique(db):
|
||||
tech = Technique(
|
||||
mitre_id="T1059.001",
|
||||
name="PowerShell",
|
||||
tactic="execution",
|
||||
platforms=["windows"],
|
||||
status_global=TechniqueStatus.not_evaluated,
|
||||
)
|
||||
db.add(tech)
|
||||
db.flush()
|
||||
|
||||
template = TestTemplate(
|
||||
mitre_technique_id=tech.mitre_id,
|
||||
name="PowerShell template",
|
||||
source="custom",
|
||||
severity="high",
|
||||
is_active=True,
|
||||
)
|
||||
db.add(template)
|
||||
|
||||
actor = ThreatActor(name="APT-Test", mitre_id="G9999")
|
||||
db.add(actor)
|
||||
db.flush()
|
||||
|
||||
db.add(ThreatActorTechnique(threat_actor_id=actor.id, technique_id=tech.id))
|
||||
db.commit()
|
||||
db.refresh(actor)
|
||||
return actor
|
||||
|
||||
|
||||
def test_generate_from_actor_without_start_date_leaves_it_null(db, red_lead_user):
|
||||
actor = _seed_actor_with_gap_technique(db)
|
||||
campaign = generate_campaign_from_threat_actor(db, actor.id, red_lead_user)
|
||||
assert campaign.start_date is None
|
||||
|
||||
|
||||
def test_generate_from_actor_persists_start_date(db, red_lead_user):
|
||||
actor = _seed_actor_with_gap_technique(db)
|
||||
start_date = datetime(2026, 9, 1)
|
||||
campaign = generate_campaign_from_threat_actor(
|
||||
db, actor.id, red_lead_user, start_date=start_date,
|
||||
)
|
||||
assert campaign.start_date == start_date
|
||||
|
||||
|
||||
def test_generate_from_actor_router_forwards_start_date(api, db, red_lead_user, red_lead_headers):
|
||||
actor = _seed_actor_with_gap_technique(db)
|
||||
resp = api(
|
||||
"post",
|
||||
f"/api/v1/campaigns/from-threat-actor/{actor.id}",
|
||||
red_lead_headers,
|
||||
json={"start_date": "2026-09-01T00:00:00"},
|
||||
)
|
||||
assert resp.status_code == 201, resp.text
|
||||
assert resp.json()["start_date"] is not None
|
||||
Reference in New Issue
Block a user