|
13 | 13 | ServiceType, |
14 | 14 | ) |
15 | 15 | from mlpa.core.config import env |
| 16 | +from mlpa.core.metrics import record_chat_availability_for |
| 17 | +from mlpa.core.prometheus_metrics import AvailabilityReason |
16 | 18 | from mlpa.core.routers.appattest import app_attest_auth |
17 | 19 | from mlpa.core.utils import extract_user_from_play_integrity_jwt, parse_app_attest_jwt |
18 | 20 |
|
@@ -123,27 +125,57 @@ async def authorize_chat_request( |
123 | 125 | ) |
124 | 126 |
|
125 | 127 | if not is_service_type_valid: |
| 128 | + record_chat_availability_for( |
| 129 | + AvailabilityReason.INVALID_SERVICE_TYPE_FOR_MODEL, |
| 130 | + model=chat_request.model, |
| 131 | + service_type=service_type.value, |
| 132 | + purpose="", |
| 133 | + ) |
126 | 134 | raise HTTPException( |
127 | 135 | status_code=400, |
128 | 136 | detail=f"Invalid service-type value for model {chat_request.model}. Should be one of {env.forced_model_service_type_pairs.get(chat_request.model)}", |
129 | 137 | ) |
130 | 138 |
|
131 | | - return await _authorize_common_request( |
132 | | - request=request, |
133 | | - build_authorized_request=lambda user, purpose_value: AuthorizedChatRequest( |
134 | | - user=user, |
| 139 | + try: |
| 140 | + return await _authorize_common_request( |
| 141 | + request=request, |
| 142 | + build_authorized_request=lambda user, purpose_value: AuthorizedChatRequest( |
| 143 | + user=user, |
| 144 | + service_type=service_type.value, |
| 145 | + purpose=purpose_value, |
| 146 | + **chat_request.model_dump(exclude_unset=True), |
| 147 | + ), |
| 148 | + authorization=authorization, |
| 149 | + service_type=service_type, |
| 150 | + purpose=purpose, |
| 151 | + x_dev_authorization=x_dev_authorization, |
| 152 | + use_app_attest=use_app_attest, |
| 153 | + use_qa_certificates=use_qa_certificates, |
| 154 | + use_play_integrity=use_play_integrity, |
| 155 | + ) |
| 156 | + except HTTPException as exc: |
| 157 | + # Record only the terminal auth dispositions the dependency intentionally |
| 158 | + # emits. 401 is an expected or normalized auth rejection. 400 is a |
| 159 | + # client-error request to the auth layer (invalid purpose, or malformed App |
| 160 | + # Attest base64 decoded in app_attest_auth). Any other status, including App |
| 161 | + # Attest's explicit 500, is re-raised unrecorded; auth-system-failure capture |
| 162 | + # is left to a follow-on auth backend change. Non-HTTPException errors are not |
| 163 | + # caught here and propagate unrecorded. Purpose is unresolved at these |
| 164 | + # dispositions, so a stable "" placeholder is used, never the unvalidated |
| 165 | + # header value. |
| 166 | + if exc.status_code == 401: |
| 167 | + reason = AvailabilityReason.AUTH_REJECTED |
| 168 | + elif exc.status_code == 400: |
| 169 | + reason = AvailabilityReason.INVALID_AUTH_REQUEST |
| 170 | + else: |
| 171 | + raise |
| 172 | + record_chat_availability_for( |
| 173 | + reason, |
| 174 | + model=chat_request.model, |
135 | 175 | service_type=service_type.value, |
136 | | - purpose=purpose_value, |
137 | | - **chat_request.model_dump(exclude_unset=True), |
138 | | - ), |
139 | | - authorization=authorization, |
140 | | - service_type=service_type, |
141 | | - purpose=purpose, |
142 | | - x_dev_authorization=x_dev_authorization, |
143 | | - use_app_attest=use_app_attest, |
144 | | - use_qa_certificates=use_qa_certificates, |
145 | | - use_play_integrity=use_play_integrity, |
146 | | - ) |
| 176 | + purpose="", |
| 177 | + ) |
| 178 | + raise |
147 | 179 |
|
148 | 180 |
|
149 | 181 | async def authorize_search_request( |
|
0 commit comments