feat(jira): implement full ticket hierarchy for campaigns and tests
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Jira tickets now follow the correct hierarchy:
OFS-9107 (system parent)
├── Standalone test ticket (unchanged — was already working)
└── Campaign ticket (NEW — created on campaign creation)
├── Test 1 ticket (NEW — created per test)
└── Test 2 ticket (NEW — created per test)
Changes:
- jira_service: add auto_create_campaign_issue() — creates campaign
ticket as child of OFS-9107; stores JiraLink(entity_type=campaign)
- jira_service: add get_campaign_jira_key() / get_test_jira_key()
helpers to look up existing Jira links by entity
- jira_service: auto_create_test_issue() gains parent_ticket_override
param — when set, uses it as parent instead of OFS-9107
- campaigns router/create_campaign: triggers auto_create_campaign_issue
after commit
- campaigns router/from-threat-actor: triggers campaign ticket then
iterates campaign_tests and creates each test ticket under it
- campaigns router/add_test_to_campaign: if campaign has a Jira ticket
and the test has none yet, creates test ticket under campaign ticket
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -122,16 +122,28 @@ def create_campaign(
|
||||
tags=payload.tags,
|
||||
scheduled_at=payload.scheduled_at,
|
||||
)
|
||||
campaign_id = result["id"]
|
||||
log_action(
|
||||
db,
|
||||
user_id=current_user.id,
|
||||
action="create_campaign",
|
||||
entity_type="campaign",
|
||||
entity_id=result["id"],
|
||||
entity_id=campaign_id,
|
||||
details={"name": payload.name, "type": payload.type},
|
||||
)
|
||||
uow.commit()
|
||||
|
||||
# Auto-create Jira ticket for campaign under OFS-9107 (non-fatal)
|
||||
try:
|
||||
from app.services.jira_service import auto_create_campaign_issue
|
||||
from app.models.campaign import Campaign as CampaignModel
|
||||
campaign_obj = db.query(CampaignModel).filter(CampaignModel.id == campaign_id).first()
|
||||
if campaign_obj:
|
||||
auto_create_campaign_issue(db, campaign_obj, current_user)
|
||||
db.commit()
|
||||
except Exception:
|
||||
logger.exception("Jira campaign ticket creation failed for campaign %s", campaign_id)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -205,6 +217,33 @@ def add_test_to_campaign(
|
||||
phase=payload.phase,
|
||||
)
|
||||
uow.commit()
|
||||
|
||||
# If the campaign has a Jira ticket and the test doesn't, create a test
|
||||
# ticket nested under the campaign ticket (non-fatal).
|
||||
try:
|
||||
from app.services.jira_service import (
|
||||
auto_create_test_issue,
|
||||
get_campaign_jira_key,
|
||||
get_test_jira_key,
|
||||
)
|
||||
from app.models.test import Test as TestModel
|
||||
campaign_jira_key = get_campaign_jira_key(db, campaign_id)
|
||||
if campaign_jira_key:
|
||||
existing_test_key = get_test_jira_key(db, payload.test_id)
|
||||
if not existing_test_key:
|
||||
test_obj = db.query(TestModel).filter(TestModel.id == payload.test_id).first()
|
||||
if test_obj:
|
||||
auto_create_test_issue(
|
||||
db, test_obj, current_user,
|
||||
parent_ticket_override=campaign_jira_key,
|
||||
)
|
||||
db.commit()
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Jira test ticket creation failed for test %s in campaign %s",
|
||||
payload.test_id, campaign_id,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -336,6 +375,24 @@ def generate_campaign_from_actor(
|
||||
)
|
||||
uow.commit()
|
||||
|
||||
# Auto-create Jira tickets: campaign under OFS-9107, each test under campaign ticket (non-fatal)
|
||||
try:
|
||||
from app.services.jira_service import auto_create_campaign_issue, auto_create_test_issue
|
||||
db.refresh(campaign)
|
||||
campaign_ticket = auto_create_campaign_issue(db, campaign, current_user)
|
||||
if campaign_ticket:
|
||||
for ct in campaign.campaign_tests:
|
||||
if ct.test:
|
||||
auto_create_test_issue(
|
||||
db, ct.test, current_user,
|
||||
parent_ticket_override=campaign_ticket,
|
||||
)
|
||||
db.commit()
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Jira ticket creation failed for auto-generated campaign %s", campaign.id
|
||||
)
|
||||
|
||||
return serialize_campaign(db, campaign)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user