From 8415060c6c92679bd3adf8f5201b1feb8f00d63c Mon Sep 17 00:00:00 2001 From: Jared Atkinson Date: Wed, 19 Aug 2026 21:43:08 -0700 Subject: [PATCH 1/2] fix: handle missing enterprise SAML provider response Treat a null or missing enterprise object from the enterprise SAML provider GraphQL query as a non-fatal collection condition instead of attempting to call get() on None. Log a dedicated warning for the missing enterprise object so operators can distinguish it from an enterprise that exists but has no SAML identity provider configured. Add regression coverage for null enterprise responses, missing enterprise responses, and valid enterprise responses without a SAML provider. --- src/openhound_github/resources/enterprise.py | 9 +++- tests/test_enterprise_resources.py | 53 ++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/openhound_github/resources/enterprise.py b/src/openhound_github/resources/enterprise.py index 0a6da47..08ab1f5 100644 --- a/src/openhound_github/resources/enterprise.py +++ b/src/openhound_github/resources/enterprise.py @@ -638,7 +638,14 @@ def enterprise_saml_provider(enterprise_data: Enterprise, ctx: SourceContext): ) return - enterprise_object = (response.get("data") or {}).get("enterprise", {}) + enterprise_object = (response.get("data") or {}).get("enterprise") + if not enterprise_object: + logger.warning( + "No enterprise object returned while fetching SAML provider for enterprise '%s'", + ctx.enterprise_name, + ) + return + saml_provider = (enterprise_object.get("ownerInfo") or {}).get("samlIdentityProvider") if not saml_provider: logger.warning( diff --git a/tests/test_enterprise_resources.py b/tests/test_enterprise_resources.py index 81a8c02..68b82fa 100644 --- a/tests/test_enterprise_resources.py +++ b/tests/test_enterprise_resources.py @@ -144,6 +144,59 @@ def test_enterprise_saml_provider_logs_and_returns_on_request_failure(caplog) -> ) +def test_enterprise_saml_provider_logs_and_returns_when_enterprise_is_null( + caplog, +) -> None: + client = _FakeClient(payload={"data": {"enterprise": None}}) + ctx = SourceContext(client=client, sso_client=client, enterprise_name="acme") + enterprise_data = SimpleNamespace(id="E_1", name="Acme", slug="acme") + + with caplog.at_level(logging.WARNING, logger="openhound_github.resources.enterprise"): + rows = list(enterprise_saml_provider.__wrapped__(enterprise_data, ctx)) + + assert rows == [] + assert any( + "No enterprise object returned while fetching SAML provider for enterprise 'acme'" + in message + for message in caplog.messages + ) + + +def test_enterprise_saml_provider_logs_and_returns_when_enterprise_is_missing( + caplog, +) -> None: + client = _FakeClient(payload={"data": {}}) + ctx = SourceContext(client=client, sso_client=client, enterprise_name="acme") + enterprise_data = SimpleNamespace(id="E_1", name="Acme", slug="acme") + + with caplog.at_level(logging.WARNING, logger="openhound_github.resources.enterprise"): + rows = list(enterprise_saml_provider.__wrapped__(enterprise_data, ctx)) + + assert rows == [] + assert any( + "No enterprise object returned while fetching SAML provider for enterprise 'acme'" + in message + for message in caplog.messages + ) + + +def test_enterprise_saml_provider_logs_and_returns_when_provider_is_missing( + caplog, +) -> None: + client = _FakeClient(payload={"data": {"enterprise": {"ownerInfo": {}}}}) + ctx = SourceContext(client=client, sso_client=client, enterprise_name="acme") + enterprise_data = SimpleNamespace(id="E_1", name="Acme", slug="acme") + + with caplog.at_level(logging.WARNING, logger="openhound_github.resources.enterprise"): + rows = list(enterprise_saml_provider.__wrapped__(enterprise_data, ctx)) + + assert rows == [] + assert any( + "No enterprise SAML provider returned for enterprise 'acme'" in message + for message in caplog.messages + ) + + def test_enterprise_external_identity_logs_and_returns_on_pagination_failure( caplog, ) -> None: From b2844c357f2a614ed69f15d39c3836ed3ad07c45 Mon Sep 17 00:00:00 2001 From: Jared Atkinson Date: Thu, 20 Aug 2026 12:11:56 -0700 Subject: [PATCH 2/2] test: assert enterprise SAML warnings use warning level Tighten the BED-9435 regression tests so the null-enterprise and missing-provider cases verify both the emitted message and the exact WARNING log level. This prevents higher-severity records from accidentally satisfying the warning-path assertions. --- tests/test_enterprise_resources.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/test_enterprise_resources.py b/tests/test_enterprise_resources.py index 68b82fa..61a5272 100644 --- a/tests/test_enterprise_resources.py +++ b/tests/test_enterprise_resources.py @@ -157,8 +157,9 @@ def test_enterprise_saml_provider_logs_and_returns_when_enterprise_is_null( assert rows == [] assert any( "No enterprise object returned while fetching SAML provider for enterprise 'acme'" - in message - for message in caplog.messages + in record.getMessage() + and record.levelno == logging.WARNING + for record in caplog.records ) @@ -175,8 +176,9 @@ def test_enterprise_saml_provider_logs_and_returns_when_enterprise_is_missing( assert rows == [] assert any( "No enterprise object returned while fetching SAML provider for enterprise 'acme'" - in message - for message in caplog.messages + in record.getMessage() + and record.levelno == logging.WARNING + for record in caplog.records ) @@ -192,8 +194,10 @@ def test_enterprise_saml_provider_logs_and_returns_when_provider_is_missing( assert rows == [] assert any( - "No enterprise SAML provider returned for enterprise 'acme'" in message - for message in caplog.messages + "No enterprise SAML provider returned for enterprise 'acme'" + in record.getMessage() + and record.levelno == logging.WARNING + for record in caplog.records )