Skip to content

fix(integrations): validate cached catalog shape before returning it#3627

Open
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/integration-catalog-cache-shape
Open

fix(integrations): validate cached catalog shape before returning it#3627
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/integration-catalog-cache-shape

Conversation

@jawwad-ali

Copy link
Copy Markdown
Contributor

What

IntegrationCatalog's fetch validates a fresh payload's shape (root must be a JSON object, integrations must be a mapping) before use — but the cache-read branch returned the cached object directly:

if age < self.CACHE_DURATION:
    return json.loads(cache_file.read_text(encoding="utf-8"))   # no shape check

So a poisoned or older-format cache (e.g. {"integrations": []}) is returned as-is and later crashes with AttributeError: 'list' object has no attribute 'items' when the caller iterates integrations.

Fix

Validate the cached object with the same key checks as the fresh-fetch path before returning it. The raised ValueError is already caught by the existing surrounding except (… ValueError …), which deletes the corrupt cache files and refetches from source — the same recovery a poisoned network payload already gets.

Test

test_poisoned_cache_shape_is_dropped_and_refetched: a fresh-but-mis-shaped cache (integrations as a list) is dropped and the valid source refetched — fails before (AttributeError), passes after.


🤖 Written with the assistance of Claude Code (AI). Bug self-found; fix/tests verified locally (fail-before / pass-after), ruff clean.

The catalog cache-read branch returned json.loads(cache_file) directly, skipping
the shape validation the fresh-fetch branch enforces (dict root + 'integrations'
mapping). A poisoned or older-format cache (e.g. {"integrations": []}) was
therefore returned as-is and later crashed with 'AttributeError: list object has
no attribute items' when the caller iterated integrations. Validate the cached
object the same way; the raised ValueError is already caught by the surrounding
handler, which drops the corrupt cache and refetches from source.

Test: a fresh-but-mis-shaped cache is dropped and the valid source refetched
(fails before: AttributeError).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jawwad-ali
jawwad-ali requested a review from mnriem as a code owner July 22, 2026 05:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant