Skip to content

Commit

Permalink
Merge pull request Aiven-Open#816 from Aiven-Open/eliax1996/ensure-ca…
Browse files Browse the repository at this point in the history
…nonical-format-of-keys-is-stable

fix: harden the order of keys that needs to be serialized
  • Loading branch information
jjaakola-aiven authored Nov 22, 2024
2 parents 1ea3ad5 + 88f7185 commit 8fda243
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 8 deletions.
32 changes: 25 additions & 7 deletions src/karapace/key_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,31 @@
See LICENSE for details
"""

from collections import OrderedDict
from enum import Enum
from karapace.typing import ArgJsonObject
from karapace.utils import json_encode
from typing import Optional
from types import MappingProxyType
from typing import Final, Optional

SCHEMA_KEY_ORDER = ["keytype", "subject", "version", "magic"]
CONFIG_KEY_ORDER = ["keytype", "subject", "magic"]
NOOP_KEY_ORDER = ["keytype", "magic"]
# used by the OrderedDict for the relative order of keys.
SCHEMA_KEY_ORDER: Final[tuple[str, str, str, str]] = ("keytype", "subject", "version", "magic")
CONFIG_KEY_ORDER: Final[tuple[str, str, str]] = ("keytype", "subject", "magic")
NOOP_KEY_ORDER: Final[tuple[str, str]] = ("keytype", "magic")

CANONICAL_KEY_ORDERS = [SCHEMA_KEY_ORDER, CONFIG_KEY_ORDER, NOOP_KEY_ORDER]
KEY_ORDER = MappingProxyType(
{
tuple(sorted(SCHEMA_KEY_ORDER)): SCHEMA_KEY_ORDER,
tuple(sorted(CONFIG_KEY_ORDER)): CONFIG_KEY_ORDER,
tuple(sorted(NOOP_KEY_ORDER)): NOOP_KEY_ORDER,
}
)

CANONICAL_KEY_ORDERS: tuple[tuple[str, str, str, str], tuple[str, str, str], tuple[str, str]] = (
SCHEMA_KEY_ORDER,
CONFIG_KEY_ORDER,
NOOP_KEY_ORDER,
)


class KeyMode(Enum):
Expand Down Expand Up @@ -72,8 +87,11 @@ def format_key(
corrected_key["version"] = key["version"]
# Magic is the last element
corrected_key["magic"] = key["magic"]
return json_encode(corrected_key, binary=True, sort_keys=False, compact=True)

fixed_order = KEY_ORDER[tuple(sorted(corrected_key.keys()))]
fixed_order_dict = OrderedDict(list(sorted(corrected_key.items(), key=lambda t: fixed_order.index(t[0]))))
return json_encode(fixed_order_dict, binary=True, sort_keys=False, compact=True)


def is_key_in_canonical_format(key: ArgJsonObject) -> bool:
return list(key.keys()) in CANONICAL_KEY_ORDERS
return tuple(key.keys()) in CANONICAL_KEY_ORDERS
2 changes: 1 addition & 1 deletion src/karapace/schema_registry_apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1307,7 +1307,7 @@ async def _forward_request_remote(
if auth_header is not None:
headers["Authorization"] = auth_header

with async_timeout.timeout(timeout):
async with async_timeout.timeout(timeout):
async with func(url, headers=headers, json=body) as response:
if response.headers.get("content-type", "").startswith(JSON_CONTENT_TYPE):
resp_content = await response.json()
Expand Down

0 comments on commit 8fda243

Please sign in to comment.