constant-time auth, migration short-circuit

This commit is contained in:
Yiorgis Gozadinos 2026-05-25 16:11:39 +03:00
parent da3cfe1a58
commit c2f681dd78
No known key found for this signature in database
5 changed files with 76 additions and 4 deletions

View file

@ -1,3 +1,5 @@
import secrets
from fastapi import Depends, HTTPException, Request, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
@ -14,7 +16,7 @@ async def require_auth(
expected = getattr(request.app.state, "auth_token", None)
if expected is None:
return
if creds is None or creds.credentials != expected:
if creds is None or not secrets.compare_digest(creds.credentials, expected):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Unauthorized",

View file

@ -19,7 +19,7 @@ async def list_sources(
source_id=poller.source_id,
type=type(poller.config).__name__,
last_polled_at=poller.last_polled_at,
circuit_breaker_open=poller._breaker.is_open,
circuit_breaker_open=poller.is_circuit_open,
)
)
return summaries

View file

@ -72,6 +72,10 @@ class BasePoller:
def last_polled_at(self) -> datetime | None:
return self._last_polled_at
@property
def is_circuit_open(self) -> bool:
return self._breaker.is_open
async def run(self) -> None: # pragma: no cover - subclasses override
raise NotImplementedError

View file

@ -35,11 +35,24 @@ def _normalize_metadata(meta: dict) -> tuple[dict, bool]:
async def _apply_canonical_metadata_keys(store: Store) -> None:
"""Rewrite document.metadata so revision lives under the source-agnostic
`source_revision` key and `contentType` becomes `content_type`. Documents
whose metadata already uses the canonical keys are untouched."""
whose metadata already uses the canonical keys are untouched.
Scoped via LIKE on the JSON-encoded metadata string so already-migrated
DBs return an empty set and skip the materialisation pass on subsequent
boots. `metadata` is stored as JSON text, so the quoted key form
(`"etag"`, `"contentType"`) is unambiguous against substrings inside
values.
"""
rows = (
await store.documents_table.query().select(["id", "metadata"]).to_arrow()
await store.documents_table.query()
.where("metadata LIKE '%\"etag\"%' OR metadata LIKE '%\"contentType\"%'")
.select(["id", "metadata"])
.to_arrow()
).to_pylist()
total = len(rows)
if total == 0:
logger.info("No legacy metadata keys found; nothing to migrate")
return
logger.info("Normalising document metadata keys across %d documents", total)
rewritten = 0
skipped = 0

View file

@ -86,6 +86,59 @@ class TestV0_50_0Migration:
"md5": "m",
}
async def test_like_filter_ignores_non_key_occurrences(self, temp_db_path):
"""The WHERE short-circuit on `metadata LIKE '%"etag"%'` looks for the
quoted-key form. Values that happen to contain the substring `etag` and
composite key names like `my_etag_key` must not get rewritten."""
async with Store(temp_db_path, create=True, skip_migration_check=True) as store:
await store.set_haiku_version("0.48.1")
await store.documents_table.add(
[
# `etag` only appears as a VALUE — no `etag` key. Either
# the LIKE excludes it (no work), or it pulls it in and
# _normalize_metadata leaves it alone. Either way the row
# must end up unchanged.
DocumentRecord(
id="value-only",
content="x",
uri="u1",
metadata=json.dumps(
{
"description": "the etag of the file",
"source_revision": "v1",
}
),
),
# A composite key containing `etag` but not equal to it.
# Must not be rewritten.
DocumentRecord(
id="composite-key",
content="x",
uri="u2",
metadata=json.dumps(
{
"my_etag_key": "v",
"source_revision": "v2",
}
),
),
]
)
async with Store(temp_db_path, skip_migration_check=True) as store:
await store.migrate()
rows = await store.documents_table.query().to_list()
by_id = {r["id"]: json.loads(r["metadata"]) for r in rows}
assert by_id["value-only"] == {
"description": "the etag of the file",
"source_revision": "v1",
}
assert by_id["composite-key"] == {
"my_etag_key": "v",
"source_revision": "v2",
}
async def test_preserves_existing_canonical_keys_on_collision(self, temp_db_path):
"""If both legacy and canonical keys are present, the canonical wins
and the legacy is dropped defends against partial-migration states."""