From c55cd3d84348e412ff11a3b0b396121cef4d9554 Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Tue, 19 May 2026 23:38:24 +0100 Subject: [PATCH] gateway: handle None details when expiring stale refs update_refs crashed with AttributeError when actions.yml contained an entry where the SHA key had no nested value (parses as None in Python). Two such untagged-transitive entries were added in #853 (carabiner-dev install/{ampel-bootstrap,download-and-verify}), which made the update_actions workflow fail on every subsequent dependabot bump touching those keys (e.g. PR #856 bumping carabiner-dev/actions 1.1.7 -> 1.2.0). Initialize the empty dict in place so the expiry update path runs on these entries the same way it does on any other. Generated-by: Claude Opus 4.7 (1M context) --- gateway/gateway.py | 4 +++- gateway/test_gateway.py | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/gateway/gateway.py b/gateway/gateway.py index de9529b7c..88ab59df7 100644 --- a/gateway/gateway.py +++ b/gateway/gateway.py @@ -234,7 +234,9 @@ def update_refs( refs = action_refs[name] if new_ref not in refs: - for _, details in refs.items(): + for ref_key, details in list(refs.items()): + if details is None: + refs[ref_key] = details = {} if not details.get("keep"): new_expiry = calculate_expiry(12) if "expires_at" not in details or details["expires_at"] > new_expiry: diff --git a/gateway/test_gateway.py b/gateway/test_gateway.py index f050ef17d..25f200966 100644 --- a/gateway/test_gateway.py +++ b/gateway/test_gateway.py @@ -82,6 +82,23 @@ def test_update_refs(): update_refs(steps, refs) assert refs == expected_refs +def test_update_refs_none_details(): + steps = load_yaml_string(''' + - uses: carabiner-dev/actions/install/ampel-bootstrap@9db1a064ca5691ef6f5d983031739ca287de0968 + ''') + + refs: ActionsYAML = load_yaml_string(''' + carabiner-dev/actions/install/ampel-bootstrap: + 0a075bb75a68646d05f99c85cbbf2be40dd8e442: + ''') + + update_refs(steps, refs) + + bootstrap = refs["carabiner-dev/actions/install/ampel-bootstrap"] + assert bootstrap["0a075bb75a68646d05f99c85cbbf2be40dd8e442"]["expires_at"] == calculate_expiry(12) + assert "9db1a064ca5691ef6f5d983031739ca287de0968" in bootstrap + + def test_update_refs_expiry(): steps = [ {"uses": "dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36"},