From 8b925cc1008175aa3c6fa8328a3a81896e26dc3a Mon Sep 17 00:00:00 2001 From: Gladwin Johnson <90415114+gladjohn@users.noreply.github.com> Date: Fri, 10 Jul 2026 09:11:43 -0700 Subject: [PATCH 1/3] Add test coverage for past expires_on in Managed Identity Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/test_mi.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_mi.py b/tests/test_mi.py index fd3834c8..f5395965 100644 --- a/tests/test_mi.py +++ b/tests/test_mi.py @@ -302,6 +302,32 @@ def test_app_service_resource_id_parameter_should_be_mi_res_id(self): headers={'X-IDENTITY-HEADER': 'foo', 'Metadata': 'true'}, ) + def test_past_expires_on_should_not_be_cached_long(self): + # Regression test: a Managed Identity endpoint returning a PAST "expires_on" + # timestamp must NOT result in a long-lived (or any) cached token. MSAL Python + # computes expires_in = expires_on - now, so a past timestamp yields a + # non-positive (already-expired) lifetime and the token is not served from cache. + past_expires_on = int(time.time()) - 3600 # 1 hour in the past + with patch.object(self.app._http_client, "get", return_value=MinimalResponse( + status_code=200, + text='{"access_token": "AT", "expires_on": "%s", "resource": "R"}' % past_expires_on, + )) as mocked_method: + first = self.app.acquire_token_for_client(resource="R") + # Must not be inflated into a huge positive lifetime (a past absolute epoch + # value must never be treated as a relative "seconds from now"). + self.assertLessEqual( + first["expires_in"], 0, + "A past expires_on must yield a non-positive expires_in, not an inflated lifetime") + # A subsequent acquisition must re-hit the endpoint (cache miss), proving + # the past-dated token was neither cached nor served. + second = self.app.acquire_token_for_client(resource="R") + self.assertEqual( + "identity_provider", second["token_source"], + "A token minted from a past expires_on must not be served from cache") + self.assertEqual( + 2, mocked_method.call_count, + "Second acquisition should re-call the MI endpoint, not reuse a stale cache entry") + @patch.dict(os.environ, {"MSI_ENDPOINT": "http://localhost", "MSI_SECRET": "foo"}) class MachineLearningTestCase(ClientTestCase): From 833c42fb744a16c17f8f93f150412b35d064d5ef Mon Sep 17 00:00:00 2001 From: Gladwin Johnson <90415114+gladjohn@users.noreply.github.com> Date: Fri, 10 Jul 2026 09:22:37 -0700 Subject: [PATCH 2/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- tests/test_mi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_mi.py b/tests/test_mi.py index f5395965..33290b93 100644 --- a/tests/test_mi.py +++ b/tests/test_mi.py @@ -304,9 +304,9 @@ def test_app_service_resource_id_parameter_should_be_mi_res_id(self): def test_past_expires_on_should_not_be_cached_long(self): # Regression test: a Managed Identity endpoint returning a PAST "expires_on" - # timestamp must NOT result in a long-lived (or any) cached token. MSAL Python - # computes expires_in = expires_on - now, so a past timestamp yields a - # non-positive (already-expired) lifetime and the token is not served from cache. + # timestamp must NOT result in a long-lived cached token. MSAL Python computes + # expires_in = expires_on - now; a past timestamp yields a non-positive lifetime, + # so any cached entry is immediately treated as expired and not served from cache. past_expires_on = int(time.time()) - 3600 # 1 hour in the past with patch.object(self.app._http_client, "get", return_value=MinimalResponse( status_code=200, From 71e9c5fcec07bbbaaf5d348ea126fa055454f943 Mon Sep 17 00:00:00 2001 From: Gladwin Johnson <90415114+gladjohn@users.noreply.github.com> Date: Fri, 10 Jul 2026 09:42:24 -0700 Subject: [PATCH 3/3] Clarify subsequent-acquisition comment in past expires_on test Follow-up to review feedback: the second comment overstated that the token is not cached; the test proves it is not served (endpoint is re-hit), not that no entry is written. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/test_mi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_mi.py b/tests/test_mi.py index 33290b93..e9fc6d00 100644 --- a/tests/test_mi.py +++ b/tests/test_mi.py @@ -318,8 +318,8 @@ def test_past_expires_on_should_not_be_cached_long(self): self.assertLessEqual( first["expires_in"], 0, "A past expires_on must yield a non-positive expires_in, not an inflated lifetime") - # A subsequent acquisition must re-hit the endpoint (cache miss), proving - # the past-dated token was neither cached nor served. + # A subsequent acquisition must re-hit the endpoint, proving the past-dated + # token is treated as already expired and is not served from the cache. second = self.app.acquire_token_for_client(resource="R") self.assertEqual( "identity_provider", second["token_source"],