Improve security
This commit is contained in:
@@ -338,6 +338,23 @@ def _codex_settings_with_defaults(raw: dict | None) -> dict:
|
||||
}
|
||||
|
||||
|
||||
def _claude_settings_with_defaults(raw: dict | None) -> dict:
|
||||
row = dict(raw or {})
|
||||
timeout_raw = str(row.get("timeout_seconds") or "60").strip()
|
||||
try:
|
||||
timeout_seconds = max(1, int(timeout_raw))
|
||||
except Exception:
|
||||
timeout_seconds = 60
|
||||
return {
|
||||
"command": str(row.get("command") or "claude").strip() or "claude",
|
||||
"workspace_root": str(row.get("workspace_root") or "").strip(),
|
||||
"default_profile": str(row.get("default_profile") or "").strip(),
|
||||
"timeout_seconds": timeout_seconds,
|
||||
"approver_service": str(row.get("approver_service") or "").strip().lower(),
|
||||
"approver_identifier": str(row.get("approver_identifier") or "").strip(),
|
||||
}
|
||||
|
||||
|
||||
def _enqueue_codex_task_submission(
|
||||
*,
|
||||
user,
|
||||
@@ -347,10 +364,12 @@ def _enqueue_codex_task_submission(
|
||||
mode: str = "default",
|
||||
command_text: str = "",
|
||||
source_message=None,
|
||||
provider: str = "codex_cli",
|
||||
) -> CodexRun:
|
||||
provider = str(provider or "codex_cli").strip() or "codex_cli"
|
||||
external_chat_id = resolve_external_chat_id(
|
||||
user=user,
|
||||
provider="codex_cli",
|
||||
provider=provider,
|
||||
service=source_service,
|
||||
channel=source_channel,
|
||||
)
|
||||
@@ -398,6 +417,7 @@ def _enqueue_codex_task_submission(
|
||||
action="append_update",
|
||||
provider_payload=dict(provider_payload),
|
||||
idempotency_key=idempotency_key,
|
||||
provider=provider,
|
||||
)
|
||||
return run
|
||||
|
||||
@@ -703,6 +723,12 @@ class TasksHub(LoginRequiredMixin, View):
|
||||
"mapped": mapped,
|
||||
}
|
||||
)
|
||||
enabled_providers = list(
|
||||
TaskProviderConfig.objects.filter(user=request.user, enabled=True)
|
||||
.exclude(provider="mock")
|
||||
.values_list("provider", flat=True)
|
||||
.order_by("provider")
|
||||
)
|
||||
return {
|
||||
"projects": projects,
|
||||
"project_choices": all_projects,
|
||||
@@ -711,6 +737,7 @@ class TasksHub(LoginRequiredMixin, View):
|
||||
"person_identifier_rows": person_identifier_rows,
|
||||
"selected_project": selected_project,
|
||||
"show_empty_projects": show_empty,
|
||||
"enabled_providers": enabled_providers,
|
||||
}
|
||||
|
||||
def get(self, request):
|
||||
@@ -1152,9 +1179,13 @@ class TaskSettings(LoginRequiredMixin, View):
|
||||
provider_map = _provider_row_map(request.user)
|
||||
codex_cfg = provider_map.get("codex_cli")
|
||||
codex_settings = _codex_settings_with_defaults(dict(getattr(codex_cfg, "settings", {}) or {}))
|
||||
claude_cfg = provider_map.get("claude_cli")
|
||||
claude_settings = _claude_settings_with_defaults(dict(getattr(claude_cfg, "settings", {}) or {}))
|
||||
mock_cfg = provider_map.get("mock")
|
||||
codex_provider = get_provider("codex_cli")
|
||||
claude_provider = get_provider("claude_cli")
|
||||
codex_healthcheck = codex_provider.healthcheck(codex_settings) if codex_cfg else None
|
||||
claude_healthcheck = claude_provider.healthcheck(claude_settings) if claude_cfg else None
|
||||
codex_queue_counts = {
|
||||
"pending": ExternalSyncEvent.objects.filter(
|
||||
user=request.user, provider="codex_cli", status="pending"
|
||||
@@ -1169,11 +1200,25 @@ class TaskSettings(LoginRequiredMixin, View):
|
||||
user=request.user, provider="codex_cli", status="ok"
|
||||
).count(),
|
||||
}
|
||||
claude_queue_counts = {
|
||||
"pending": ExternalSyncEvent.objects.filter(
|
||||
user=request.user, provider="claude_cli", status="pending"
|
||||
).count(),
|
||||
"waiting_approval": ExternalSyncEvent.objects.filter(
|
||||
user=request.user, provider="claude_cli", status="waiting_approval"
|
||||
).count(),
|
||||
"failed": ExternalSyncEvent.objects.filter(
|
||||
user=request.user, provider="claude_cli", status="failed"
|
||||
).count(),
|
||||
"ok": ExternalSyncEvent.objects.filter(
|
||||
user=request.user, provider="claude_cli", status="ok"
|
||||
).count(),
|
||||
}
|
||||
codex_recent_runs = CodexRun.objects.filter(user=request.user).order_by("-created_at")[:10]
|
||||
latest_worker_event = (
|
||||
ExternalSyncEvent.objects.filter(
|
||||
user=request.user,
|
||||
provider="codex_cli",
|
||||
provider__in=["codex_cli", "claude_cli"],
|
||||
)
|
||||
.filter(status__in=["ok", "failed", "waiting_approval", "retrying"])
|
||||
.order_by("-updated_at")
|
||||
@@ -1233,6 +1278,21 @@ class TaskSettings(LoginRequiredMixin, View):
|
||||
"queue_counts": codex_queue_counts,
|
||||
"recent_runs": codex_recent_runs,
|
||||
},
|
||||
"claude_provider_config": claude_cfg,
|
||||
"claude_provider_settings": {
|
||||
"command": str(claude_settings.get("command") or "claude"),
|
||||
"workspace_root": str(claude_settings.get("workspace_root") or ""),
|
||||
"default_profile": str(claude_settings.get("default_profile") or ""),
|
||||
"timeout_seconds": int(claude_settings.get("timeout_seconds") or 60),
|
||||
"approver_service": str(claude_settings.get("approver_service") or ""),
|
||||
"approver_identifier": str(claude_settings.get("approver_identifier") or ""),
|
||||
},
|
||||
"claude_compact_summary": {
|
||||
"healthcheck_ok": bool(getattr(claude_healthcheck, "ok", False)),
|
||||
"healthcheck_error": str(getattr(claude_healthcheck, "error", "") or ""),
|
||||
"healthcheck_payload": dict(getattr(claude_healthcheck, "payload", {}) or {}),
|
||||
"queue_counts": claude_queue_counts,
|
||||
},
|
||||
"person_identifiers": person_identifiers,
|
||||
"external_link_person_identifiers": external_link_person_identifiers,
|
||||
"external_link_scoped": external_link_scoped,
|
||||
@@ -1376,6 +1436,17 @@ class TaskSettings(LoginRequiredMixin, View):
|
||||
"approver_mode": "channel",
|
||||
}
|
||||
)
|
||||
elif provider == "claude_cli":
|
||||
settings_payload = _claude_settings_with_defaults(
|
||||
{
|
||||
"command": request.POST.get("command"),
|
||||
"workspace_root": request.POST.get("workspace_root"),
|
||||
"default_profile": request.POST.get("default_profile"),
|
||||
"timeout_seconds": request.POST.get("timeout_seconds"),
|
||||
"approver_service": request.POST.get("approver_service"),
|
||||
"approver_identifier": request.POST.get("approver_identifier"),
|
||||
}
|
||||
)
|
||||
row.settings = settings_payload
|
||||
row.save(update_fields=["enabled", "settings", "updated_at"])
|
||||
return _settings_redirect(request)
|
||||
@@ -1460,10 +1531,16 @@ class TaskSettings(LoginRequiredMixin, View):
|
||||
return _settings_redirect(request)
|
||||
|
||||
|
||||
_ALLOWED_SUBMIT_PROVIDERS = {"codex_cli", "claude_cli"}
|
||||
|
||||
|
||||
class TaskCodexSubmit(LoginRequiredMixin, View):
|
||||
def post(self, request):
|
||||
task_id = str(request.POST.get("task_id") or "").strip()
|
||||
next_url = str(request.POST.get("next") or reverse("tasks_hub")).strip()
|
||||
provider = str(request.POST.get("provider") or "codex_cli").strip().lower()
|
||||
if provider not in _ALLOWED_SUBMIT_PROVIDERS:
|
||||
provider = "codex_cli"
|
||||
task = get_object_or_404(
|
||||
DerivedTask.objects.select_related("project", "epic", "origin_message"),
|
||||
id=task_id,
|
||||
@@ -1471,13 +1548,14 @@ class TaskCodexSubmit(LoginRequiredMixin, View):
|
||||
)
|
||||
cfg = TaskProviderConfig.objects.filter(
|
||||
user=request.user,
|
||||
provider="codex_cli",
|
||||
provider=provider,
|
||||
enabled=True,
|
||||
).first()
|
||||
provider_label = "Claude" if provider == "claude_cli" else "Codex"
|
||||
if cfg is None:
|
||||
messages.error(
|
||||
request,
|
||||
"Codex provider is disabled. Enable it in Task Settings first.",
|
||||
f"{provider_label} provider is disabled. Enable it in Task Settings first.",
|
||||
)
|
||||
return redirect(next_url)
|
||||
run = _enqueue_codex_task_submission(
|
||||
@@ -1487,10 +1565,11 @@ class TaskCodexSubmit(LoginRequiredMixin, View):
|
||||
source_channel=str(task.source_channel or ""),
|
||||
mode="default",
|
||||
source_message=getattr(task, "origin_message", None),
|
||||
provider=provider,
|
||||
)
|
||||
messages.success(
|
||||
request,
|
||||
f"Queued approval for task #{task.reference_code} before Codex run {run.id}.",
|
||||
f"Queued approval for task #{task.reference_code} before {provider_label} run {run.id}.",
|
||||
)
|
||||
return redirect(next_url)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user