Skip to content

Commit ce3f0b1

Browse files
gladjohnCopilot
andcommitted
test(mi-e2e): redact tokens in logs, close session, fork-guard self-hosted stages
Address PR review feedback: - Assert access_token present on the cached (second) acquisition before indexing. - Never log token material: summarize error results to safe fields only, and compare the cached token to the original via SHA-256 digest instead of raw values. - Close the requests.Session in a finally block. - Add a stage-level fork guard so forked-PR code never runs on the self-hosted MISEManagedIdentity / MISEAZUREARC pools. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5ad57850-7d1f-4b9a-bf9f-723d69a9687c
1 parent 6f210db commit ce3f0b1

2 files changed

Lines changed: 44 additions & 19 deletions

File tree

.Pipelines/template-pipeline-stages.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,8 @@ stages:
293293
- stage: MIE2EImds
294294
displayName: 'MI E2E - IMDS'
295295
dependsOn: UnitTests
296-
condition: eq(dependencies.UnitTests.result, 'Succeeded')
296+
# Fork guard: never run untrusted forked-PR code on the self-hosted pool.
297+
condition: and(eq(dependencies.UnitTests.result, 'Succeeded'), ne(variables['System.PullRequest.IsFork'], 'True'))
297298
jobs:
298299
- job: Pytest
299300
displayName: 'Managed Identity E2E - VM / IMDS'
@@ -352,7 +353,8 @@ stages:
352353
- stage: MIE2EAzureArc
353354
displayName: 'MI E2E - Azure Arc'
354355
dependsOn: UnitTests
355-
condition: eq(dependencies.UnitTests.result, 'Succeeded')
356+
# Fork guard: never run untrusted forked-PR code on the self-hosted pool.
357+
condition: and(eq(dependencies.UnitTests.result, 'Succeeded'), ne(variables['System.PullRequest.IsFork'], 'True'))
356358
jobs:
357359
- job: Pytest
358360
displayName: 'Managed Identity E2E - Azure Arc'

tests/test_mi_e2e.py

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
1919
Everywhere else (hosted agents, local dev) the tests self-skip.
2020
"""
21+
import hashlib
2122
import os
2223
import unittest
2324

@@ -46,29 +47,51 @@
4647
)
4748

4849

50+
def _safe_error(result):
51+
"""Return a log-safe summary of a failed result.
52+
53+
Only the non-sensitive error fields are surfaced, so an assertion failure can
54+
never spill an access token (or the whole result dict) into the CI logs.
55+
"""
56+
return {
57+
key: result[key]
58+
for key in ("error", "error_description", "correlation_id")
59+
if key in result
60+
}
61+
62+
4963
def _acquire_token_twice_assert_caching(test, managed_identity):
5064
"""Acquire an ARM token twice for the given managed identity and assert the first
5165
call reaches the identity provider while the second is served from the token cache.
5266
5367
Shared by the IMDS and Azure Arc E2E tests, mirroring the Go helper of the same name.
5468
"""
55-
client = ManagedIdentityClient(managed_identity, http_client=requests.Session())
56-
57-
first = client.acquire_token_for_client(resource=_ARM_RESOURCE)
58-
test.assertNotIn("error", first, "first acquisition failed: {}".format(first))
59-
test.assertIn("access_token", first)
60-
test.assertEqual(
61-
"identity_provider", first.get("token_source"),
62-
"first call should reach the identity provider")
63-
64-
second = client.acquire_token_for_client(resource=_ARM_RESOURCE)
65-
test.assertNotIn("error", second, "second acquisition failed: {}".format(second))
66-
test.assertEqual(
67-
"cache", second.get("token_source"),
68-
"second call should be served from the token cache")
69-
test.assertEqual(
70-
first["access_token"], second["access_token"],
71-
"cached token should match the original token")
69+
http_client = requests.Session()
70+
client = ManagedIdentityClient(managed_identity, http_client=http_client)
71+
try:
72+
first = client.acquire_token_for_client(resource=_ARM_RESOURCE)
73+
test.assertNotIn(
74+
"error", first, "first acquisition failed: {}".format(_safe_error(first)))
75+
test.assertIn("access_token", first)
76+
test.assertEqual(
77+
"identity_provider", first.get("token_source"),
78+
"first call should reach the identity provider")
79+
80+
second = client.acquire_token_for_client(resource=_ARM_RESOURCE)
81+
test.assertNotIn(
82+
"error", second, "second acquisition failed: {}".format(_safe_error(second)))
83+
test.assertIn("access_token", second)
84+
test.assertEqual(
85+
"cache", second.get("token_source"),
86+
"second call should be served from the token cache")
87+
# Compare tokens by SHA-256 digest so a mismatch never prints the actual
88+
# token material into CI logs.
89+
test.assertEqual(
90+
hashlib.sha256(first["access_token"].encode("utf-8")).hexdigest(),
91+
hashlib.sha256(second["access_token"].encode("utf-8")).hexdigest(),
92+
"cached token should match the original token")
93+
finally:
94+
http_client.close()
7295

7396

7497
@unittest.skipUnless(

0 commit comments

Comments
 (0)