Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions .Pipelines/CI-AND-RELEASE-PIPELINES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ including what each pipeline does, when it runs, and how to trigger a release.

## Pipeline Files

| File | Purpose |
|------|---------|
| [`azure-pipelines.yml`](../azure-pipelines.yml) | PR gate and post-merge CI — calls the shared template with `runPublish: false` |
| [`pipeline-publish.yml`](pipeline-publish.yml) | Release pipeline — manually queued, builds and publishes to PyPI |
| [`template-pipeline-stages.yml`](template-pipeline-stages.yml) | Shared stages template — PreBuildCheck, Validate, and CI stages reused by both pipelines |
| [`credscan-exclusion.json`](credscan-exclusion.json) | CredScan suppression file for known test fixtures |
| File | ADO Pipeline | Purpose |
|------|-------------|---------|
| [`azure-pipelines.yml`](../azure-pipelines.yml) | [MSAL.Python-PR-OneBranch-Official (3064)](https://dev.azure.com/IdentityDivision/IDDP/_build?definitionId=3064) | PR gate, post-merge CI, and performance benchmarks — calls the shared template with `runPublish: false`; runs benchmarks on post-merge pushes to `dev` |
| [`pipeline-publish.yml`](pipeline-publish.yml) | [MSAL.Python-Publish (3067)](https://dev.azure.com/IdentityDivision/IDDP/_build?definitionId=3067) | Release pipeline — manually queued, builds and publishes to PyPI |
Comment thread
RyAuld marked this conversation as resolved.
| [`template-pipeline-stages.yml`](template-pipeline-stages.yml) | — | Shared stages template — PreBuildCheck, Validate, and CI stages reused by both pipelines |
| [`credscan-exclusion.json`](credscan-exclusion.json) | — | CredScan suppression file for known test fixtures |

---

## PR / CI Pipeline (`azure-pipelines.yml`)
## PR / CI Pipeline — [MSAL.Python-PR-OneBranch-Official (3064)](https://dev.azure.com/IdentityDivision/IDDP/_build?definitionId=3064)

### Triggers

Expand All @@ -29,13 +29,14 @@ including what each pipeline does, when it runs, and how to trigger a release.
### Stages

```
PreBuildCheck ─► CI
PreBuildCheck ─► CI ─► Benchmark (post-merge to dev only)
```

| Stage | What it does |
|-------|-------------|
| **PreBuildCheck** | Runs SDL security scans: PoliCheck (policy/offensive content), CredScan (leaked credentials), and PostAnalysis (breaks the build on findings) |
| **CI** | Runs the full test suite on Python 3.9, 3.10, 3.11, 3.12, 3.13, and 3.14 |
| Stage | What it does | When it runs |
|-------|-------------|-------------|
| **PreBuildCheck** | Runs SDL security scans: PoliCheck (policy/offensive content), CredScan (leaked credentials), and PostAnalysis (breaks the build on findings) | Always |
| **CI** | Runs the full test suite on Python 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, and 3.14 | Always |
| **Benchmark** | Runs performance benchmarks on Python 3.9 and publishes `benchmark-results` artifact | Post-merge pushes to `dev` and manual runs only |

The Validate stage is **skipped** on PR/CI runs (it only applies to release builds).

Expand All @@ -45,7 +46,7 @@ The Validate stage is **skipped** on PR/CI runs (it only applies to release buil

---

## Release Pipeline (`pipeline-publish.yml`)
## Release Pipeline — [MSAL.Python-Publish (3067)](https://dev.azure.com/IdentityDivision/IDDP/_build?definitionId=3067)

### Triggers

Expand All @@ -70,7 +71,7 @@ PreBuildCheck ─► Validate ─► CI ─► Build ─┬─► PublishMSALPyt
|-------|-------------|-----------|
| **PreBuildCheck** | PoliCheck + CredScan scans | Always |
| **Validate** | Asserts the `packageVersion` parameter matches `msal/sku.py __version__` | Always (release runs only) |
| **CI** | Full test matrix (Python 3.9–3.14) | After Validate passes |
| **CI** | Full test matrix (Python 3.8–3.14) | After Validate passes |
| **Build** | Builds `sdist` and `wheel` via `python -m build`; publishes `python-dist` artifact | After CI passes |
| **PublishMSALPython** | Uploads to test.pypi.org | `publishTarget == test.pypi.org (Preview / RC)` |
| **PublishPyPI** | Uploads to PyPI via ESRP; requires manual approval | `publishTarget == pypi.org (ESRP Production)` |
Expand Down
32 changes: 31 additions & 1 deletion .Pipelines/template-pipeline-stages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ stages:
GdnBreakGdnToolCredScan: true
GdnBreakGdnToolPoliCheck: true

- task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@3
displayName: 'Publish Security Analysis Logs (TSA)'
condition: succeededOrFailed()
Comment thread
RyAuld marked this conversation as resolved.
inputs:
tsaConfigFile: '$(Build.SourcesDirectory)/.Pipelines/tsaConfig.json'

- task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3
displayName: 'Clean agent directories'
condition: always()

# ══════════════════════════════════════════════════════════════════════════════
# Stage 1 · Validate — verify packageVersion matches msal/sku.py __version__
# Skipped when runPublish is false (PR / merge builds).
Expand Down Expand Up @@ -127,6 +137,8 @@ stages:
vmImage: ubuntu-latest
strategy:
matrix:
Python38:
python.version: '3.8'
Python39:
python.version: '3.9'
Python310:
Expand Down Expand Up @@ -185,11 +197,20 @@ stages:
pip install pytest pytest-azurepipelines
mkdir -p test-results
set -o pipefail
pytest -vv --junitxml=test-results/junit.xml 2>&1 | tee test-results/pytest.log
pytest -vv --benchmark-skip --junitxml=test-results/junit.xml --deselect tests/test_cryptography.py::CryptographyTestCase::test_ceiling_should_be_latest_cryptography_version_plus_three --deselect tests/test_cryptography.py::CryptographyTestCase::test_should_be_run_with_latest_version_of_cryptography 2>&1 | tee test-results/pytest.log
displayName: 'Run tests'
retryCountOnTaskFailure: 3
env:
LAB_APP_CLIENT_CERT_PFX_PATH: $(LAB_APP_CLIENT_CERT_PFX_PATH)

# Run cryptography version-gating tests separately as a warning-only check.
# These tests fail when a new cryptography major version is released and setup.cfg
# needs its upper bound bumped. They should not block unrelated PRs.
- bash: |
pytest -vv tests/test_cryptography.py::CryptographyTestCase::test_ceiling_should_be_latest_cryptography_version_plus_three tests/test_cryptography.py::CryptographyTestCase::test_should_be_run_with_latest_version_of_cryptography --junitxml=test-results/junit-crypto-ceiling.xml
displayName: 'Check cryptography ceiling (warning only)'
continueOnError: true

- task: PublishTestResults@2
displayName: 'Publish test results'
condition: succeededOrFailed()
Expand All @@ -199,6 +220,15 @@ stages:
failTaskOnFailedTests: true
testRunTitle: 'Python $(python.version)'

- task: PublishTestResults@2
displayName: 'Publish cryptography ceiling results'
condition: succeededOrFailed()
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: 'test-results/junit-crypto-ceiling.xml'
failTaskOnFailedTests: false
testRunTitle: 'Cryptography ceiling check $(python.version)'

- bash: rm -f "$(Agent.TempDirectory)/lab-auth.pfx"
displayName: 'Clean up lab certificate'
condition: always()
17 changes: 17 additions & 0 deletions .Pipelines/tsaConfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"codebaseName": "MSAL Python",
"notificationAliases": [
"IdentityDevExDotnet@microsoft.com"
],
"codebaseAdmins": [
"EUROPE\\aadidagt"
],
"instanceUrl": "https://identitydivision.visualstudio.com",
"projectName": "IDDP",
"areaPath": "IDDP\\DevEx-Client-SDK\\Python",
"iterationPath": "IDDP\\Unscheduled",
"tools": [
"credscan",
"policheck"
]
}
Comment thread
RyAuld marked this conversation as resolved.
131 changes: 0 additions & 131 deletions .github/workflows/python-package.yml

This file was deleted.

53 changes: 53 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,56 @@ stages:
- template: .Pipelines/template-pipeline-stages.yml
parameters:
runPublish: false

- stage: Benchmark
displayName: 'Run benchmarks'
dependsOn: CI
# Only run on post-merge pushes to dev — not on PRs or scheduled runs.
# Benchmarks are noisy and the baseline cache is only meaningful on a stable branch.
condition: |
and(
succeeded('CI'),
eq(variables['Build.SourceBranch'], 'refs/heads/dev'),
or(
eq(variables['Build.Reason'], 'IndividualCI'),
eq(variables['Build.Reason'], 'BatchedCI'),
eq(variables['Build.Reason'], 'Manual')
Comment thread
RyAuld marked this conversation as resolved.
)
)
jobs:
- job: Benchmark
displayName: 'Performance benchmarks (Python 3.9)'
pool:
vmImage: ubuntu-latest
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.9'
displayName: 'Set up Python 3.9'

- script: |
python -m pip install --upgrade pip
pip install pytest -r requirements.txt
displayName: 'Install dependencies'

- task: Cache@2
displayName: 'Restore performance baseline cache'
inputs:
key: 'perf-baseline | "$(Agent.OS)" | tests/test_benchmark.py'
path: .perf.baseline

- bash: |
pytest --benchmark-only --benchmark-json benchmark.json --log-cli-level INFO tests/test_benchmark.py
displayName: 'Run benchmarks'

- bash: |
[ -f benchmark.json ] && echo "##vso[task.setvariable variable=benchmarkFileExists]true"
displayName: 'Check benchmark output exists'
condition: succeededOrFailed()

- task: PublishPipelineArtifact@1
displayName: 'Publish benchmark results'
condition: and(succeededOrFailed(), eq(variables['benchmarkFileExists'], 'true'))
inputs:
targetPath: 'benchmark.json'
artifact: 'benchmark-results'
Loading