From 32d159e5048f0e92b919ad818b88d175bc69d83d Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Fri, 3 Jul 2026 16:08:58 +0800 Subject: [PATCH] Tighten Codex service failure classification Co-Authored-By: Codex --- scripts/codex_audit_service.py | 18 +++++++++++++++++- scripts/run_monthly_codex_audit.py | 18 +++++++++++++++++- service/ai_gateway_service.py | 18 +++++++++++++++++- tests/test_run_monthly_codex_audit.py | 4 ++++ 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/scripts/codex_audit_service.py b/scripts/codex_audit_service.py index 8448e3e..29e2b43 100644 --- a/scripts/codex_audit_service.py +++ b/scripts/codex_audit_service.py @@ -672,7 +672,23 @@ def _job_dedupe_key(payload: dict[str, Any]) -> str: def _classify_failure(error: str) -> str: text = error.lower() - if any(word in text for word in ("permission", "unauth", "forbidden", "oidc", "token", "allow", "secret")): + auth_config_signals = ( + "permission denied", + "unauthorized", + "forbidden", + "oidc", + "missing bearer", + "missing token", + "invalid token", + "bad credentials", + "not allowed", + "allowlist", + "api key is required", + "no api key configured", + "secret is missing", + "secret not configured", + ) + if any(signal in text for signal in auth_config_signals): return "auth_or_config_failure" if any(word in text for word in ("quota", "rate limit", "too many active", "budget")): return "quota_or_capacity_failure" diff --git a/scripts/run_monthly_codex_audit.py b/scripts/run_monthly_codex_audit.py index 1f298a9..6a4529a 100644 --- a/scripts/run_monthly_codex_audit.py +++ b/scripts/run_monthly_codex_audit.py @@ -171,7 +171,23 @@ class BridgeError(RuntimeError): def classify_service_failure(error: str) -> str: text = error.lower() - if any(word in text for word in ("permission", "unauth", "forbidden", "oidc", "token", "allow", "secret")): + auth_config_signals = ( + "permission denied", + "unauthorized", + "forbidden", + "oidc", + "missing bearer", + "missing token", + "invalid token", + "bad credentials", + "not allowed", + "allowlist", + "api key is required", + "no api key configured", + "secret is missing", + "secret not configured", + ) + if any(signal in text for signal in auth_config_signals): return "auth_or_config_failure" if any(word in text for word in ("quota", "rate limit", "too many active", "budget")): return "quota_or_capacity_failure" diff --git a/service/ai_gateway_service.py b/service/ai_gateway_service.py index 41981ae..65ffd5f 100644 --- a/service/ai_gateway_service.py +++ b/service/ai_gateway_service.py @@ -436,7 +436,23 @@ def _job_dedupe_key(payload: dict[str, Any]) -> str: def _classify_failure(error: str) -> str: text = error.lower() - if any(word in text for word in ("permission", "unauth", "forbidden", "oidc", "token", "allow", "secret")): + auth_config_signals = ( + "permission denied", + "unauthorized", + "forbidden", + "oidc", + "missing bearer", + "missing token", + "invalid token", + "bad credentials", + "not allowed", + "allowlist", + "api key is required", + "no api key configured", + "secret is missing", + "secret not configured", + ) + if any(signal in text for signal in auth_config_signals): return "auth_or_config_failure" if any(word in text for word in ("quota", "rate limit", "too many active", "budget")): return "quota_or_capacity_failure" diff --git a/tests/test_run_monthly_codex_audit.py b/tests/test_run_monthly_codex_audit.py index 8ee999c..25121ff 100644 --- a/tests/test_run_monthly_codex_audit.py +++ b/tests/test_run_monthly_codex_audit.py @@ -535,6 +535,10 @@ def test_service_failure_classification_identifies_infra_failures(self) -> None: self.assertTrue(is_service_infrastructure_failure("Codex audit service job failed [transient_service_failure]: timed out")) self.assertFalse(is_service_infrastructure_failure("Codex audit service job failed [patch_contract_failure]: invalid JSON")) + def test_service_failure_classification_ignores_source_code_secret_words(self) -> None: + message = "codex exec failed: BLOCKED_PATH_RE = r'.*token.*|.*secret.*'" + self.assertEqual(classify_service_failure(message), "unknown_failure") + def test_codex_audit_service_async_job_lifecycle(self) -> None: with tempfile.TemporaryDirectory() as tmp: env = {