Files
GIA/core/tasks/codex_approval.py

92 lines
3.2 KiB
Python

from __future__ import annotations
import hashlib
from asgiref.sync import async_to_sync
from core.clients.transport import send_message_raw
from core.models import CodexPermissionRequest, ExternalSyncEvent, TaskProviderConfig
def _deterministic_approval_key(idempotency_key: str) -> str:
digest = hashlib.sha1(str(idempotency_key or "").encode("utf-8")).hexdigest()[:12]
return f"pre-{digest}"
def queue_codex_event_with_pre_approval(
*,
user,
run,
task,
task_event,
action: str,
provider_payload: dict,
idempotency_key: str,
) -> tuple[ExternalSyncEvent, CodexPermissionRequest]:
approval_key = _deterministic_approval_key(idempotency_key)
waiting_event, _ = ExternalSyncEvent.objects.update_or_create(
idempotency_key=f"codex_waiting:{idempotency_key}",
defaults={
"user": user,
"task": task,
"task_event": task_event,
"provider": "codex_cli",
"status": "waiting_approval",
"payload": {
"action": str(action or "append_update"),
"provider_payload": dict(provider_payload or {}),
},
"error": "",
},
)
run.status = "waiting_approval"
run.error = ""
run.save(update_fields=["status", "error", "updated_at"])
request, _ = CodexPermissionRequest.objects.update_or_create(
approval_key=approval_key,
defaults={
"user": user,
"codex_run": run,
"external_sync_event": waiting_event,
"summary": "Pre-submit approval required before sending to Codex",
"requested_permissions": {
"type": "pre_submit",
"provider": "codex_cli",
"action": str(action or "append_update"),
},
"resume_payload": {
"gate_type": "pre_submit",
"action": str(action or "append_update"),
"provider_payload": dict(provider_payload or {}),
"idempotency_key": str(idempotency_key or ""),
},
"status": "pending",
"resolved_at": None,
"resolved_by_identifier": "",
"resolution_note": "",
},
)
cfg = TaskProviderConfig.objects.filter(user=user, provider="codex_cli", enabled=True).first()
settings_payload = dict(getattr(cfg, "settings", {}) or {})
approver_service = str(settings_payload.get("approver_service") or "").strip().lower()
approver_identifier = str(settings_payload.get("approver_identifier") or "").strip()
if approver_service and approver_identifier:
try:
async_to_sync(send_message_raw)(
approver_service,
approver_identifier,
text=(
f"[codex approval] key={approval_key}\n"
"summary=Pre-submit approval required before sending to Codex\n"
"requested=pre_submit\n"
f"use: .codex approve {approval_key} or .codex deny {approval_key}"
),
attachments=[],
metadata={"origin_tag": f"codex-pre-approval:{approval_key}"},
)
except Exception:
pass
return waiting_event, request