@@ -125,6 +125,7 @@ stages:
125125 --ignore=tests/test_e2e.py \
126126 --ignore=tests/test_e2e_manual.py \
127127 --ignore=tests/test_fmi_e2e.py \
128+ --ignore=tests/test_mi_e2e.py \
128129 --deselect tests/test_cryptography.py::CryptographyTestCase::test_ceiling_should_be_latest_cryptography_version_plus_three \
129130 --deselect tests/test_cryptography.py::CryptographyTestCase::test_should_be_run_with_latest_version_of_cryptography
130131 displayName: 'Run pytest (unit)'
@@ -275,3 +276,123 @@ stages:
275276 - bash : rm -f "$(Agent.TempDirectory)/lab-auth.pfx"
276277 displayName : ' Remove lab certificate from agent'
277278 condition : always()
279+
280+ # ══════════════════════════════════════════════════════════════════════════════
281+ # Stage 4 - MI E2E (IMDS) - REAL managed identity token acquisition on an Azure VM.
282+ # Runs on the self-hosted "MISEManagedIdentity" pool, a Windows Azure VM
283+ # that has the lab system-assigned + user-assigned identities assigned.
284+ # Mirrors the MSAL Go "MI E2E - IMDS" stage. Only the IMDS cases in
285+ # tests/test_mi_e2e.py run here (gated on MSAL_TEST_MI_IMDS); the Arc case
286+ # self-skips. No lab certificate is needed - the VM's own managed identity
287+ # is used.
288+ #
289+ # Pool assumptions (self-hosted): Python 3.x on PATH and outbound access to
290+ # PyPI for "pip install". Adjust if the pool differs.
291+ # ══════════════════════════════════════════════════════════════════════════════
292+ - stage : MIE2EImds
293+ displayName : ' MI E2E - IMDS'
294+ dependsOn : UnitTests
295+ # Fork guard: never run untrusted forked-PR code on the self-hosted pool.
296+ condition : and(eq(dependencies.UnitTests.result, 'Succeeded'), ne(variables['System.PullRequest.IsFork'], 'True'))
297+ jobs :
298+ - job : Pytest
299+ displayName : ' Managed Identity E2E - VM / IMDS'
300+ pool :
301+ type : windows
302+ isCustom : true
303+ name : MISEManagedIdentity
304+ timeoutInMinutes : 30
305+ variables :
306+ ob_outputDirectory : ' $(Build.ArtifactStagingDirectory)'
307+ steps :
308+ # msal + its dependencies (requests, cryptography, PyJWT) and pytest are PRE-PROVISIONED on the
309+ # self-hosted pool (like the Go/.NET toolchains already are), so there is no runtime pip install.
310+ # This also avoids the Arc pool's egress TLS inspection blocking files.pythonhosted.org.
311+ - task : PowerShell@2
312+ displayName : ' Run pytest (MI E2E - IMDS)'
313+ inputs :
314+ targetType : ' inline'
315+ workingDirectory : ' $(System.DefaultWorkingDirectory)'
316+ script : |
317+ $ErrorActionPreference = 'Stop'
318+ $py = (Get-Command python.exe -ErrorAction SilentlyContinue).Source
319+ if (-not $py) {
320+ $py = Get-ChildItem 'C:\Program Files\Python3*\python.exe','C:\Program Files (x86)\Python3*\python.exe','C:\Python3*\python.exe' -ErrorAction SilentlyContinue |
321+ Select-Object -First 1 -ExpandProperty FullName
322+ }
323+ if (-not $py) { throw 'Python not found on this agent. Install Python 3.x on the pool machine.' }
324+ Write-Host "Using Python: $py"
325+ & $py --version
326+ New-Item -ItemType Directory -Force -Path test-results | Out-Null
327+ & $py -m pytest -vv --junitxml=test-results/junit-mi-e2e-imds.xml tests/test_mi_e2e.py
328+ env :
329+ PYTHONUNBUFFERED : ' 1'
330+ MSAL_TEST_MI_IMDS : ' 1'
331+
332+ - task : PublishTestResults@2
333+ displayName : ' Publish MI E2E (IMDS) test results'
334+ condition : succeededOrFailed()
335+ inputs :
336+ testResultsFormat : ' JUnit'
337+ testResultsFiles : ' test-results/junit-mi-e2e-imds.xml'
338+ failTaskOnFailedTests : true
339+ testRunTitle : ' MI E2E - IMDS'
340+
341+ # ══════════════════════════════════════════════════════════════════════════════
342+ # Stage 5 - MI E2E (Azure Arc) - REAL managed identity token acquisition on an
343+ # Azure Arc-enabled machine. Runs on the self-hosted "MISEAZUREARC" pool.
344+ # Azure Arc supports the system-assigned identity only. Mirrors the MSAL Go
345+ # "MI E2E - Azure Arc" stage. tests/test_mi_e2e.py's Arc case runs here; the
346+ # IMDS cases self-skip (MSAL_TEST_MI_IMDS unset).
347+ #
348+ # Pool note: as observed for MSAL Go, the Arc machine's egress inspection can
349+ # reset TLS for package downloads. If "pip install" cannot reach PyPI, pre-provision
350+ # the dependencies on the pool (or use an offline wheel cache) and drop the install step.
351+ # ══════════════════════════════════════════════════════════════════════════════
352+ - stage : MIE2EAzureArc
353+ displayName : ' MI E2E - Azure Arc'
354+ dependsOn : UnitTests
355+ # Fork guard: never run untrusted forked-PR code on the self-hosted pool.
356+ condition : and(eq(dependencies.UnitTests.result, 'Succeeded'), ne(variables['System.PullRequest.IsFork'], 'True'))
357+ jobs :
358+ - job : Pytest
359+ displayName : ' Managed Identity E2E - Azure Arc'
360+ pool :
361+ type : windows
362+ isCustom : true
363+ name : MISEAZUREARC
364+ timeoutInMinutes : 30
365+ variables :
366+ ob_outputDirectory : ' $(Build.ArtifactStagingDirectory)'
367+ steps :
368+ # msal + its dependencies (requests, cryptography, PyJWT) and pytest are PRE-PROVISIONED on the
369+ # self-hosted pool (like the Go/.NET toolchains already are), so there is no runtime pip install.
370+ # This is required here because the Arc machine's egress TLS inspection blocks files.pythonhosted.org.
371+ - task : PowerShell@2
372+ displayName : ' Run pytest (MI E2E - Azure Arc)'
373+ inputs :
374+ targetType : ' inline'
375+ workingDirectory : ' $(System.DefaultWorkingDirectory)'
376+ script : |
377+ $ErrorActionPreference = 'Stop'
378+ $py = (Get-Command python.exe -ErrorAction SilentlyContinue).Source
379+ if (-not $py) {
380+ $py = Get-ChildItem 'C:\Program Files\Python3*\python.exe','C:\Program Files (x86)\Python3*\python.exe','C:\Python3*\python.exe' -ErrorAction SilentlyContinue |
381+ Select-Object -First 1 -ExpandProperty FullName
382+ }
383+ if (-not $py) { throw 'Python not found on this agent. Install Python 3.x on the pool machine.' }
384+ Write-Host "Using Python: $py"
385+ & $py --version
386+ New-Item -ItemType Directory -Force -Path test-results | Out-Null
387+ & $py -m pytest -vv --junitxml=test-results/junit-mi-e2e-arc.xml tests/test_mi_e2e.py
388+ env :
389+ PYTHONUNBUFFERED : ' 1'
390+
391+ - task : PublishTestResults@2
392+ displayName : ' Publish MI E2E (Azure Arc) test results'
393+ condition : succeededOrFailed()
394+ inputs :
395+ testResultsFormat : ' JUnit'
396+ testResultsFiles : ' test-results/junit-mi-e2e-arc.xml'
397+ failTaskOnFailedTests : true
398+ testRunTitle : ' MI E2E - Azure Arc'
0 commit comments