refactor(docs+comments): add Google-style docstrings and inline comments across backend
Task D — Google-style docstrings (Args/Returns) on every public function, method, and class across all 158 Python files in the backend. Zero ruff D violations (pydocstyle Google convention). Task E — Explanatory one-line comment before every code line (~11600 new comments). ruff check passes clean after isort re-sort.
This commit is contained in:
@@ -4,18 +4,34 @@ Handles checking which recurring campaigns are due, cloning them with
|
||||
fresh tests, and computing the next run date.
|
||||
"""
|
||||
|
||||
# Import logging
|
||||
import logging
|
||||
|
||||
# Import datetime, timedelta from datetime
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# Import Session from sqlalchemy.orm
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
# Import Campaign, CampaignTest from app.models.campaign
|
||||
from app.models.campaign import Campaign, CampaignTest
|
||||
|
||||
# Import TestState from app.models.enums
|
||||
from app.models.enums import TestState
|
||||
|
||||
# Import Test from app.models.test
|
||||
from app.models.test import Test
|
||||
|
||||
# Import User from app.models.user
|
||||
from app.models.user import User
|
||||
|
||||
# Import log_action from app.services.audit_service
|
||||
from app.services.audit_service import log_action
|
||||
|
||||
# Import create_notification from app.services.notification_service
|
||||
from app.services.notification_service import create_notification
|
||||
|
||||
# Assign logger = logging.getLogger(__name__)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -32,11 +48,16 @@ def calculate_next_run(current_date: datetime, pattern: str) -> datetime:
|
||||
- ``monthly`` : +30 days
|
||||
- ``quarterly``: +90 days
|
||||
"""
|
||||
# Assign offsets = {
|
||||
offsets = {
|
||||
# Literal argument value
|
||||
"weekly": timedelta(days=7),
|
||||
# Literal argument value
|
||||
"monthly": timedelta(days=30),
|
||||
# Literal argument value
|
||||
"quarterly": timedelta(days=90),
|
||||
}
|
||||
# Return current_date + offsets.get(pattern, timedelta(days=30))
|
||||
return current_date + offsets.get(pattern, timedelta(days=30))
|
||||
|
||||
|
||||
@@ -53,59 +74,99 @@ def _clone_campaign(db: Session, original: Campaign) -> Campaign:
|
||||
with the same base data (in ``draft`` state) and link it.
|
||||
3. Activate the new campaign.
|
||||
"""
|
||||
# Assign now = datetime.utcnow()
|
||||
now = datetime.utcnow()
|
||||
# Assign run_label = now.strftime("%Y-%m-%d")
|
||||
run_label = now.strftime("%Y-%m-%d")
|
||||
|
||||
# Assign child = Campaign(
|
||||
child = Campaign(
|
||||
# Keyword argument: name
|
||||
name=f"{original.name} (Run {run_label})",
|
||||
# Keyword argument: description
|
||||
description=original.description,
|
||||
# Keyword argument: type
|
||||
type=original.type,
|
||||
# Keyword argument: threat_actor_id
|
||||
threat_actor_id=original.threat_actor_id,
|
||||
# Keyword argument: status
|
||||
status="active",
|
||||
# Keyword argument: created_by
|
||||
created_by=original.created_by,
|
||||
# Keyword argument: target_platform
|
||||
target_platform=original.target_platform,
|
||||
# Keyword argument: tags
|
||||
tags=original.tags or [],
|
||||
# Keyword argument: parent_campaign_id
|
||||
parent_campaign_id=original.id,
|
||||
)
|
||||
# Stage new record(s) for database insertion
|
||||
db.add(child)
|
||||
# Flush changes to DB without committing the transaction
|
||||
db.flush() # get child.id
|
||||
|
||||
# Clone each campaign_test with a fresh Test
|
||||
original_cts = (
|
||||
db.query(CampaignTest)
|
||||
# Chain .filter() call
|
||||
.filter(CampaignTest.campaign_id == original.id)
|
||||
# Chain .order_by() call
|
||||
.order_by(CampaignTest.order_index)
|
||||
# Chain .all() call
|
||||
.all()
|
||||
)
|
||||
|
||||
# Iterate over original_cts
|
||||
for ct in original_cts:
|
||||
# Assign src_test = ct.test
|
||||
src_test = ct.test
|
||||
# Check: not src_test
|
||||
if not src_test:
|
||||
# Skip to the next loop iteration
|
||||
continue
|
||||
|
||||
# Assign new_test = Test(
|
||||
new_test = Test(
|
||||
# Keyword argument: technique_id
|
||||
technique_id=src_test.technique_id,
|
||||
# Keyword argument: name
|
||||
name=src_test.name,
|
||||
# Keyword argument: description
|
||||
description=src_test.description,
|
||||
# Keyword argument: platform
|
||||
platform=src_test.platform,
|
||||
# Keyword argument: procedure_text
|
||||
procedure_text=src_test.procedure_text,
|
||||
# Keyword argument: tool_used
|
||||
tool_used=src_test.tool_used,
|
||||
# Keyword argument: created_by
|
||||
created_by=original.created_by,
|
||||
# Keyword argument: state
|
||||
state=TestState.draft,
|
||||
)
|
||||
# Stage new record(s) for database insertion
|
||||
db.add(new_test)
|
||||
# Flush changes to DB without committing the transaction
|
||||
db.flush() # get new_test.id
|
||||
|
||||
# Assign new_ct = CampaignTest(
|
||||
new_ct = CampaignTest(
|
||||
# Keyword argument: campaign_id
|
||||
campaign_id=child.id,
|
||||
# Keyword argument: test_id
|
||||
test_id=new_test.id,
|
||||
# Keyword argument: order_index
|
||||
order_index=ct.order_index,
|
||||
# Keyword argument: phase
|
||||
phase=ct.phase,
|
||||
# depends_on is not copied — would need ID remapping
|
||||
)
|
||||
# Stage new record(s) for database insertion
|
||||
db.add(new_ct)
|
||||
|
||||
# Flush changes to DB without committing the transaction
|
||||
db.flush()
|
||||
# Return child
|
||||
return child
|
||||
|
||||
|
||||
@@ -119,78 +180,119 @@ def check_and_run_recurring_campaigns(db: Session) -> int:
|
||||
|
||||
Returns the number of campaigns spawned.
|
||||
"""
|
||||
# Assign now = datetime.utcnow()
|
||||
now = datetime.utcnow()
|
||||
|
||||
# Assign due_campaigns = (
|
||||
due_campaigns = (
|
||||
db.query(Campaign)
|
||||
# Chain .filter() call
|
||||
.filter(
|
||||
Campaign.is_recurring == True, # noqa: E712
|
||||
Campaign.next_run_at <= now,
|
||||
)
|
||||
# Chain .all() call
|
||||
.all()
|
||||
)
|
||||
|
||||
# Assign spawned = 0
|
||||
spawned = 0
|
||||
|
||||
# Iterate over due_campaigns
|
||||
for campaign in due_campaigns:
|
||||
# Attempt the following; catch errors below
|
||||
try:
|
||||
# Assign child = _clone_campaign(db, campaign)
|
||||
child = _clone_campaign(db, campaign)
|
||||
|
||||
# Update the original's scheduling fields
|
||||
campaign.last_run_at = now
|
||||
# Assign campaign.next_run_at = calculate_next_run(now, campaign.recurrence_pattern or "monthly")
|
||||
campaign.next_run_at = calculate_next_run(now, campaign.recurrence_pattern or "monthly")
|
||||
|
||||
# Commit all pending changes to the database
|
||||
db.commit()
|
||||
# Reload ORM object attributes from the database
|
||||
db.refresh(child)
|
||||
|
||||
# Audit
|
||||
log_action(
|
||||
db,
|
||||
# Keyword argument: user_id
|
||||
user_id=campaign.created_by,
|
||||
# Keyword argument: action
|
||||
action="recurring_campaign_run",
|
||||
# Keyword argument: entity_type
|
||||
entity_type="campaign",
|
||||
# Keyword argument: entity_id
|
||||
entity_id=child.id,
|
||||
# Keyword argument: details
|
||||
details={
|
||||
# Literal argument value
|
||||
"parent_campaign_id": str(campaign.id),
|
||||
# Literal argument value
|
||||
"child_campaign_name": child.name,
|
||||
# Literal argument value
|
||||
"pattern": campaign.recurrence_pattern,
|
||||
},
|
||||
)
|
||||
# Commit all pending changes to the database
|
||||
db.commit()
|
||||
|
||||
# Notify
|
||||
if campaign.created_by:
|
||||
# Call create_notification()
|
||||
create_notification(
|
||||
db,
|
||||
# Keyword argument: user_id
|
||||
user_id=campaign.created_by,
|
||||
# Keyword argument: type
|
||||
type="recurring_campaign_run",
|
||||
# Keyword argument: title
|
||||
title="Recurring campaign executed",
|
||||
# Keyword argument: message
|
||||
message=(
|
||||
f'Campaign "{child.name}" was automatically created '
|
||||
f'from recurring template "{campaign.name}".'
|
||||
),
|
||||
# Keyword argument: entity_type
|
||||
entity_type="campaign",
|
||||
# Keyword argument: entity_id
|
||||
entity_id=child.id,
|
||||
)
|
||||
|
||||
# Notify red_tech users
|
||||
red_techs = db.query(User).filter(User.role == "red_tech", User.is_active == True).all() # noqa: E712
|
||||
# Iterate over red_techs
|
||||
for user in red_techs:
|
||||
# Call create_notification()
|
||||
create_notification(
|
||||
db,
|
||||
# Keyword argument: user_id
|
||||
user_id=user.id,
|
||||
# Keyword argument: type
|
||||
type="campaign_activated",
|
||||
# Keyword argument: title
|
||||
title="New recurring campaign active",
|
||||
# Keyword argument: message
|
||||
message=f'Campaign "{child.name}" is now active and ready for execution.',
|
||||
# Keyword argument: entity_type
|
||||
entity_type="campaign",
|
||||
# Keyword argument: entity_id
|
||||
entity_id=child.id,
|
||||
)
|
||||
|
||||
# Assign spawned = 1
|
||||
spawned += 1
|
||||
# Log info: "Spawned child campaign '%s' from parent '%s'", ch
|
||||
logger.info("Spawned child campaign '%s' from parent '%s'", child.name, campaign.name)
|
||||
|
||||
# Handle Exception
|
||||
except Exception:
|
||||
# Roll back all uncommitted changes
|
||||
db.rollback()
|
||||
# Log exception: "Failed to run recurring campaign '%s'", campaign.
|
||||
logger.exception("Failed to run recurring campaign '%s'", campaign.name)
|
||||
|
||||
# Return spawned
|
||||
return spawned
|
||||
|
||||
Reference in New Issue
Block a user