All MicroEvals
1. [L16 / as_str] — Broken reference / Ambiguity: as_str is ...
Create MicroEval

1. [L16 / as_str] — Broken reference / Ambiguity: as_str is ...

Prompt

1. [L16 / as_str] — Broken reference / Ambiguity: as_str is imported from app.utils.clock, but its existence and behavior cannot be verified. If it converts None to "None", nullable IDs used at L218, L233 and L238 may be incorrectly queried as literal strings. 2. L34, L169, L179 / SecretStr handling — Type / Logic error: Using str() on Pydantic SecretStr fields (session_secret, admin_token, worker_token) returns the masked value "**********" rather than the actual secret. This can cause session cookies and authenticated requests to use or accept the wrong credentials. 3. [L32–43 / _session_secret] — Multi-process configuration error: When session_secret is unset, the application generates a process-local ephemeral signing key. Different workers therefore use different keys, and restarts invalidate existing session cookies. Valid cookies may be rejected, causing users to receive new client IDs and lose access to their existing conversations and jobs. 4. [L37–43 / _ephemeral_secret] — Concurrency error: Lazy initialization of _ephemeral_secret is not synchronized. Concurrent threads can both observe None, generate different keys and overwrite each other, invalidating cookies already signed with the discarded key. 5. [L51–54 / _encode_session] — Logic error: _encode_session does not validate that client_id matches the 32-character lowercase hexadecimal format enforced by _decode_session. It can therefore generate tokens that the decoder will always reject. 6. [L123–130 / load_access] — Logic error: When an existing session token expires or fails validation, load_access silently assigns a new uuid.uuid4().hex client ID. This permanently orphans conversations and jobs associated with the previous ID. 7. [L126–127 / load_access] — Session expiration logic: A valid session is never re-issued or refreshed. Consequently, issued_at and the cookie’s Max-Age remain fixed from the initial visit. Once the maximum session age is reached, the cookie expires and the user receives a new client ID. 8. [L128–130 / load_access] — Race condition: Parallel requests from a client without an existing session cookie can each generate a different client ID and Set-Cookie header. Only the last cookie stored by the browser survives, potentially orphaning data created under the other IDs. 9. [L133–139 / _bearer_token] — Logic error: header.partition(" ") is called before leading whitespace is stripped. An Authorization header with leading spaces can therefore produce an empty scheme and fail to parse an otherwise valid Bearer token. 10. [L150 / _token_matches] — Encoding / Runtime error: Starlette decodes header values as Latin-1, but the provided token is re-encoded as UTF-8 before comparison. Non-ASCII tokens can therefore fail authentication even when sent correctly. Additionally, .encode("utf-8") can raise an unhandled UnicodeEncodeError for strings containing surrogate code points. 11. [L155 / _token_error] — Logic error: The custom header value is not stripped or length-bounded consistently with _bearer_token. A whitespace-only header can prevent fallback to the Bearer token and produce 403 instead of 401; surrounding whitespace can cause valid tokens to fail comparison, and oversized custom headers bypass the 4096-character limit. 12. [L202 / JobAccess.owned_by] — Logic error: The database owner is compared directly with the cookie client ID. If client_id is stored in a PostgreSQL UUID column, the database may return a hyphenated UUID while the cookie ID uses 32 hexadecimal characters without hyphens. Ownership checks will then incorrectly fail. 13. [L183–186 / ConversationAccess] — Interface inconsistency: ConversationAccess lacks the owned_by(self, client_id: str) -> bool method that exists on JobAccess, resulting in inconsistent access-control interfaces. 14. [L211, L226 / conversation_access, job_access] — Runtime error: conversation_id and job_id are passed directly to .eq("id", ...) without UUID format validation or exception handling. Malformed IDs or database query failures can raise unhandled exceptions and result in HTTP 500 responses instead of returning exists=False. 15. [L215, L230 / conversation_access, job_access] — API ambiguity / Runtime error: response.maybe_single() is called on the result of .execute(). In standard Supabase/PostgREST clients, maybe_single() is a query-builder method that must be called before .execute(). The returned API response does not provide this method, so the calls raise AttributeError unless the custom SupabaseDatabase implements a non-standard response wrapper. 16. [L226–238 / job_access] — Logic error: When a job has a non-null conversation_id, but conversation_access returns exists=False, job_access still populates JobAccess.conversation_id with the nonexistent conversation ID while setting owner to None. from __future__ import annotations import hashlib import hmac import logging import secrets import time import uuid from dataclasses import dataclass from typing import Any from fastapi import Request from app.config import get_settings from app.database import SupabaseDatabase from app.utils.clock import as_str SESSION_COOKIE = "chat_session" SESSION_TOKEN_VERSION = "v1" SESSION_MAX_AGE_SECONDS = 31_536_000 SESSION_CLOCK_SKEW_SECONDS = 300 SESSION_ID_LENGTH = 32 SESSION_HEX_DIGITS = frozenset("0123456789abcdef") ADMIN_TOKEN_HEADER = "x-admin-token" WORKER_TOKEN_HEADER = "x-worker-token" logger = logging.getLogger("app.access") _ephemeral_secret: str | None = None def _session_secret() -> str: global _ephemeral_secret configured = str(get_settings().session_secret or "").strip() if configured: return configured if _ephemeral_secret is None: _ephemeral_secret = secrets.token_urlsafe(48) logger.warning( "session_secret_missing", extra={"detail": "Az ephemeral munkamenet-kulcs elvész az újraindításkor."}, ) return _ephemeral_secret def _signature(payload: str) -> str: key = _session_secret().encode("utf-8") return hmac.new(key, payload.encode("utf-8"), hashlib.sha256).hexdigest() def _encode_session(client_id: str) -> str: issued_at = int(time.time()) payload = f"{SESSION_TOKEN_VERSION}.{client_id}.{issued_at}" return f"{payload}.{_signature(payload)}" def _decode_session(token: Any) -> str | None: if not isinstance(token, str): return None if len(token) > 256: return None parts = token.split(".") if len(parts) != 4: return None version, client_id, issued_raw, signature = parts if version != SESSION_TOKEN_VERSION: return None if len(client_id) != SESSION_ID_LENGTH: return None if any(character not in SESSION_HEX_DIGITS for character in client_id): return None if not issued_raw.isascii() or not issued_raw.isdigit() or len(issued_raw) > 12: return None payload = f"{version}.{client_id}.{issued_raw}" try: provided_signature = signature.encode("utf-8") except UnicodeEncodeError: return None if not hmac.compare_digest(provided_signature, _signature(payload).encode("utf-8")): return None issued_at = int(issued_raw) current = int(time.time()) if issued_at <= 0: return None if issued_at > current + SESSION_CLOCK_SKEW_SECONDS: return None if current - issued_at > SESSION_MAX_AGE_SECONDS: return None return client_id def _is_secure_request(request: Request) -> bool: forwarded = (request.headers.get("x-forwarded-proto") or "").split(",")[0].strip().lower() if forwarded in ("https", "http"): return forwarded == "https" return request.url.scheme == "https" def _cookie_header(client_id: str, secure: bool) -> str: attributes = [ f"{SESSION_COOKIE}={_encode_session(client_id)}", "Path=/", f"Max-Age={SESSION_MAX_AGE_SECONDS}", "HttpOnly", "SameSite=Lax", ] if secure: attributes.append("Secure") return "; ".join(attributes) @dataclass(frozen=True) class Access: client_id: str set_cookie: str | None def headers(self) -> dict[str, str]: if not self.set_cookie: return {} return {"Set-Cookie": self.set_cookie} def load_access(request: Request) -> Access: token = request.cookies.get(SESSION_COOKIE) existing = _decode_session(token) if existing is not None: return Access(client_id=existing, set_cookie=None) client_id = uuid.uuid4().hex cookie = _cookie_header(client_id, _is_secure_request(request)) return Access(client_id=client_id, set_cookie=cookie) def _bearer_token(request: Request) -> str | None: header = request.headers.get("authorization") if not header: return None scheme, _, value = header.partition(" ") if scheme.strip().lower() != "bearer": return None token = value.strip() if not token or len(token) > 4096: return None return token def _token_matches(provided: str | None, expected: str) -> bool: if not provided: return False return hmac.compare_digest( provided.encode("utf-8"), expected.encode("utf-8") ) def _token_error( request: Request, header_name: str, expected: str, missing_message: str ) -> tuple[str, int] | None: if not expected: logger.error("access_token_not_configured", extra={"header": header_name}) return (missing_message, 503) provided = request.headers.get(header_name) or _bearer_token(request) if not provided: return ("Bejelentkezés szükséges.", 401) if not _token_matches(provided, expected): return ("Tiltott művelet.", 403) return None def admin_error(request: Request) -> tuple[str, int] | None: expected = str(get_settings().admin_token or "").strip() return _token_error( request, ADMIN_TOKEN_HEADER, expected, "A rendszerfelügyeleti végpont nincs konfigurálva.", ) def worker_error(request: Request) -> tuple[str, int] | None: expected = str(get_settings().worker_token or "").strip() return _token_error( request, WORKER_TOKEN_HEADER, expected, "A háttérmunkás végpont nincs konfigurálva.", ) @dataclass(frozen=True) class ConversationAccess: exists: bool owner: str | None @dataclass(frozen=True) class JobAccess: exists: bool conversation_id: str | None owner: str | None status: str | None def owned_by(self, client_id: str) -> bool: return bool(self.owner) and self.owner == client_id async def conversation_access( database: SupabaseDatabase, conversation_id: str ) -> ConversationAccess: response = await ( database.table("chat_conversations") .select("id, client_id") .eq("id", conversation_id) .limit(1) .execute() ) row = response.maybe_single() if row is None: return ConversationAccess(exists=False, owner=None) owner = as_str(row.get("client_id")) or None return ConversationAccess(exists=True, owner=owner) async def job_access(database: SupabaseDatabase, job_id: str) -> JobAccess: response = await ( database.table("chat_jobs") .select("id, conversation_id, status") .eq("id", job_id) .limit(1) .execute() ) row = response.maybe_single() if row is None: return JobAccess(exists=False, conversation_id=None, owner=None, status=None) conversation_id = as_str(row.get("conversation_id")) or None owner: str | None = None if conversation_id is not None: access = await conversation_access(database, conversation_id) owner = access.owner if access.exists else None status = as_str(row.get("status")) or None return JobAccess( exists=True, conversation_id=conversation_id, owner=owner, status=status, ) return the complete code with every listed error corrected; do not include any comments in it, nothing else in reply. keep imported files because they are exist. Prohibit the use of any of the following: authentication/authorization, access control, security policies/auditing/monitoring/ rate/usage/product limits, quotas, billing/payments, tests/documentation, source/config comments, placeholder/mock/dummy implementations, fake services, TODO, unimplemented methods, omitted files/functions.

Drag to resize

Response not available

Drag to resize

Response not available

Drag to resize
Drag to resize
Drag to resize