Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ set -e
set -u
set -x

export PYTHONPATH="/app:${PYTHONPATH-}"

if [ z"$1" = "zmigrate" ]; then
COMMAND="/app/.venv/bin/django-admin migrate --settings firetower.settings"
exec /app/.venv/bin/ddtrace-run /app/.venv/bin/django-admin migrate --settings firetower.settings
elif [ z"$1" = "zserver" ]; then
COMMAND="/app/.venv/bin/granian --interface wsgi --host 0.0.0.0 --port $PORT firetower.wsgi:application"
exec /app/.venv/bin/ddtrace-run /app/.venv/bin/granian --interface wsgi --host 0.0.0.0 --port "${PORT}" firetower.wsgi:application
elif [ z"$1" = "zslack-bot" ]; then
COMMAND="/app/.venv/bin/django-admin run_slack_bot --settings firetower.settings"
exec /app/.venv/bin/ddtrace-run /app/.venv/bin/django-admin run_slack_bot --settings firetower.settings
elif [ z"$1" = "zworker" ]; then
exec /app/.venv/bin/ddtrace-run /app/.venv/bin/django-admin qcluster --settings firetower.settings
else
echo "Usage: $0 (migrate|server|slack-bot)"
echo "Usage: $0 (migrate|server|slack-bot|worker)"
exit 1
fi

export PYTHONPATH=/app:\$PYTHONPATH
/app/.venv/bin/ddtrace-run $COMMAND
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ dependencies = [
"pyserde[toml]>=0.28.0",
"notion-client>=3.0.0,<4.0.0",
"requests>=2.32.0",
"django-q2>=1.7.4",
"slack-bolt>=1.27.0",
"slack-sdk>=3.31.0",
"sentry-sdk>=2.47.0",
Expand Down
2 changes: 1 addition & 1 deletion src/firetower/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def __init__(self) -> None:
self.pagerduty = None
self.statuspage = None
self.project_key = ""
self.django_secret_key = ""
self.django_secret_key = "dummy_value_DO_NOT_USE"
self.sentry_dsn = ""
self.region_grouping: list[list[str]] = []
self.firetower_base_url = ""
Expand Down
28 changes: 28 additions & 0 deletions src/firetower/incidents/migrations/0015_schedule_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from django.db import migrations

from firetower.incidents.tasks import SCHEDULES
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migration imports mutable runtime code from tasks module

Medium Severity

The migration imports SCHEDULES from firetower.incidents.tasks at module level, coupling it to mutable runtime code. If SCHEDULES is ever renamed, restructured, or the "schedule_demo" key is removed, this migration will break on any fresh database. Additionally, importing tasks.py triggers from firetower.incidents.models import Incident, pulling in the live model class rather than the historical version — and any future import-time side effects in tasks.py will also fire during migration. The schedule data (func, schedule_type, minutes, repeats) can be inlined directly in the migration to keep it self-contained.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit eca2c31. Configure here.



def create_schedule(apps, schema_editor):
Schedule = apps.get_model("django_q", "Schedule")
schedule_name = "schedule_demo"
Schedule.objects.get_or_create(
name=schedule_name, defaults=SCHEDULES[schedule_name]
)


def delete_schedule(apps, schema_editor):
Schedule = apps.get_model("django_q", "Schedule")
schedule_name = "schedule_demo"
Schedule.objects.filter(name=schedule_name).delete()


class Migration(migrations.Migration):
dependencies = [
("incidents", "0014_add_total_downtime"),
("django_q", "0018_task_success_index"),
]

operations = [
migrations.RunPython(create_schedule, delete_schedule),
]
20 changes: 20 additions & 0 deletions src/firetower/incidents/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from logging import info

Check warning on line 1 in src/firetower/incidents/tasks.py

View check run for this annotation

@sentry/warden / warden: code-review

`info` imported from logging is not a logger method and will fail at runtime

`from logging import info` imports the module-level `logging.info` function, but calling it requires the root logger to be configured, and more importantly this pattern bypasses Sentry/Django's logger hierarchy. While `logging.info` does exist as a module function, using it here means logs won't be attributed to the `firetower.incidents.tasks` logger and may not appear under the project's configured handlers/filters. The user-visible consequence is that demo task output will be silently dropped or misrouted, making it impossible to verify the scheduled job is running.

Check warning on line 1 in src/firetower/incidents/tasks.py

View workflow job for this annotation

GitHub Actions / warden: code-review

`from logging import info` calls root logger, bypassing module-level logger configuration

The code imports `info` directly from the `logging` module, which logs to the root logger rather than a module-specific logger. This is a runtime/observability issue: messages won't be attributed to `firetower.incidents.tasks`, and they will be filtered by the root logger's level (WARNING by default), so the demo task's output will likely be silently dropped instead of appearing in worker logs.
Comment thread
sentry-warden[bot] marked this conversation as resolved.

from firetower.incidents.models import Incident

SCHEDULES = {
"schedule_demo": {
"func": "firetower.incidents.tasks.schedule_demo",
"schedule_type": "I", # Minutes
"minutes": 5,
"repeats": -1, # repeat indefinitely
},
}


def schedule_demo() -> None:
incident = Incident.objects.order_by("-created_at").first()
if incident:
info(f"Most recent incident: INC-{incident.id}: {incident.title}")
else:
info("No incidents found.")
11 changes: 11 additions & 0 deletions src/firetower/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ def _coerce_region_grouping(raw: list[Any]) -> list[list[str]]:
"firetower.incidents",
"firetower.integrations",
"firetower.slack_app",
"django_q",
]

MIDDLEWARE = [
Expand Down Expand Up @@ -374,3 +375,13 @@ class StatuspageSettings(TypedDict):
},
},
}

Q_CLUSTER = {
"name": "firetower",
"orm": "default",
Comment thread
sentry-warden[bot] marked this conversation as resolved.
"workers": 4,
"timeout": 180,
"retry": 210,
"queue_limit": 50,
"bulk": 10,
}
27 changes: 27 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading