-
Notifications
You must be signed in to change notification settings - Fork 211
Add ADO publish pipeline for PyPI releases #890
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
18e024d
71abd77
360532b
302e9de
90fcfd0
8771d61
48d84f8
b9f2f59
c5a2192
4b3fbd2
bfb65a0
d03e0f7
3b78d35
a55942d
af6ec92
7ec5fb3
d342947
e171362
5460165
364eb7d
7bb5ecc
d5ad7c0
08ba113
66a42f1
c8662ac
ef7a76e
ae4b5af
8e8feab
91b7c2b
d637dc5
e3b627d
60d4080
5254163
3bfad4f
2dd89f5
14789e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| { | ||
| "tool": "Credential Scanner", | ||
| "suppressions": [ | ||
| { | ||
| "file": "certificate-with-password.pfx", | ||
| "_justification": "Self-signed certificate used only in unit tests. Not a production credential." | ||
| }, | ||
| { | ||
| "file": "test_mi.py", | ||
| "_justification": "WWW-Authenticate challenge header value used as a mock HTTP response fixture in unit tests. Not a real credential." | ||
| } | ||
| ] | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,179 @@ | ||||||
| # pipeline-publish.yml | ||||||
| # | ||||||
| # Release pipeline for the msal Python package — manually triggered only. | ||||||
| # Source: https://github.com/AzureAD/microsoft-authentication-library-for-python | ||||||
| # | ||||||
| # Publish targets: | ||||||
| # test.pypi.org (Preview / RC) — preview releases via MSAL-Test-Python-Upload SC | ||||||
| # (SC creation pending test.pypi.org API token) | ||||||
| # pypi.org (ESRP Production) — production releases via MSAL-Prod-Python-Upload SC | ||||||
|
||||||
| # pypi.org (ESRP Production) — production releases via MSAL-Prod-Python-Upload SC | |
| # pypi.org (ESRP Production) — production releases via ESRP (EsrpRelease@9) using MSAL-ESRP-AME SC |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,192 @@ | ||||||||||||||||||||||||||||||
| # template-pipeline-stages.yml | ||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||
| # Shared stages template for the msal Python package. | ||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||
| # Called from: | ||||||||||||||||||||||||||||||
| # pipeline-publish.yml — release build (runPublish: true) | ||||||||||||||||||||||||||||||
| # azure-pipelines.yml — PR gate and post-merge CI (runPublish: false) | ||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||
| # Parameters: | ||||||||||||||||||||||||||||||
| # packageVersion - Version to validate against msal/sku.py | ||||||||||||||||||||||||||||||
| # Required when runPublish is true; unused otherwise. | ||||||||||||||||||||||||||||||
| # runPublish - When true: also runs the Validate stage before CI. | ||||||||||||||||||||||||||||||
| # When false (PR / merge builds): only PreBuildCheck + CI run. | ||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||
| # Stage flow: | ||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||
| # runPublish: true → PreBuildCheck ─► Validate ─► CI | ||||||||||||||||||||||||||||||
| # runPublish: false → PreBuildCheck ─► CI (Validate is skipped) | ||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||
| # Build and Publish stages are defined in pipeline-publish.yml (not here), | ||||||||||||||||||||||||||||||
| # so that the PR build never references PyPI service connections. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| parameters: | ||||||||||||||||||||||||||||||
| - name: packageVersion | ||||||||||||||||||||||||||||||
| type: string | ||||||||||||||||||||||||||||||
| default: '' | ||||||||||||||||||||||||||||||
| - name: runPublish | ||||||||||||||||||||||||||||||
| type: boolean | ||||||||||||||||||||||||||||||
| default: false | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| stages: | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # ══════════════════════════════════════════════════════════════════════════════ | ||||||||||||||||||||||||||||||
| # Stage 0 · PreBuildCheck — SDL security scans (PoliCheck + CredScan) | ||||||||||||||||||||||||||||||
| # Always runs, mirrors MSAL.NET pre-build analysis. | ||||||||||||||||||||||||||||||
| # ══════════════════════════════════════════════════════════════════════════════ | ||||||||||||||||||||||||||||||
| - stage: PreBuildCheck | ||||||||||||||||||||||||||||||
| displayName: 'Pre-build security checks' | ||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||
| - job: SecurityScan | ||||||||||||||||||||||||||||||
| displayName: 'PoliCheck + CredScan' | ||||||||||||||||||||||||||||||
| pool: | ||||||||||||||||||||||||||||||
| vmImage: windows-latest | ||||||||||||||||||||||||||||||
| variables: | ||||||||||||||||||||||||||||||
| Codeql.SkipTaskAutoInjection: true | ||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||
| - task: NodeTool@0 | ||||||||||||||||||||||||||||||
| displayName: 'Install Node.js (includes npm)' | ||||||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||||||
| versionSpec: '20.x' | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| - task: securedevelopmentteam.vss-secure-development-tools.build-task-policheck.PoliCheck@2 | ||||||||||||||||||||||||||||||
| displayName: 'Run PoliCheck' | ||||||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||||||
| targetType: F | ||||||||||||||||||||||||||||||
| continueOnError: true | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| - task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@3 | ||||||||||||||||||||||||||||||
| displayName: 'Run CredScan' | ||||||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||||||
| suppressionsFile: '$(Build.SourcesDirectory)/.Pipelines/credscan-exclusion.json' | ||||||||||||||||||||||||||||||
| toolMajorVersion: V2 | ||||||||||||||||||||||||||||||
| debugMode: false | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| - task: securedevelopmentteam.vss-secure-development-tools.build-task-postanalysis.PostAnalysis@2 | ||||||||||||||||||||||||||||||
| displayName: 'Post Analysis' | ||||||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||||||
| GdnBreakGdnToolCredScan: true | ||||||||||||||||||||||||||||||
| GdnBreakGdnToolPoliCheck: true | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # ══════════════════════════════════════════════════════════════════════════════ | ||||||||||||||||||||||||||||||
| # Stage 1 · Validate — verify packageVersion matches msal/sku.py __version__ | ||||||||||||||||||||||||||||||
| # Skipped when runPublish is false (PR / merge builds). | ||||||||||||||||||||||||||||||
| # ══════════════════════════════════════════════════════════════════════════════ | ||||||||||||||||||||||||||||||
| - stage: Validate | ||||||||||||||||||||||||||||||
| displayName: 'Validate version' | ||||||||||||||||||||||||||||||
| dependsOn: PreBuildCheck | ||||||||||||||||||||||||||||||
| condition: and(${{ parameters.runPublish }}, eq(dependencies.PreBuildCheck.result, 'Succeeded')) | ||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||
| - job: ValidateVersion | ||||||||||||||||||||||||||||||
| displayName: 'Check version matches source' | ||||||||||||||||||||||||||||||
| pool: | ||||||||||||||||||||||||||||||
| vmImage: ubuntu-latest | ||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||
| - task: UsePythonVersion@0 | ||||||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||||||
| versionSpec: '3.12' | ||||||||||||||||||||||||||||||
| displayName: 'Set up Python' | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| - bash: | | ||||||||||||||||||||||||||||||
| PARAM_VER="${{ parameters.packageVersion }}" | ||||||||||||||||||||||||||||||
| SKU_VER=$(grep '__version__' msal/sku.py | sed 's/.*"\(.*\)".*/\1/') | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if [ -z "$PARAM_VER" ]; then | ||||||||||||||||||||||||||||||
| echo "##vso[task.logissue type=error]packageVersion is required. Enter the version to publish (must match msal/sku.py __version__)." | ||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||
| elif [ "$PARAM_VER" != "$SKU_VER" ]; then | ||||||||||||||||||||||||||||||
| echo "##vso[task.logissue type=error]Version mismatch: parameter '$PARAM_VER' != msal/sku.py '$SKU_VER'" | ||||||||||||||||||||||||||||||
| echo "Update msal/sku.py __version__ to match the packageVersion parameter, or correct the parameter." | ||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||
| echo "Version validated: $PARAM_VER" | ||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||
| displayName: 'Verify version parameter matches msal/sku.py' | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # ══════════════════════════════════════════════════════════════════════════════ | ||||||||||||||||||||||||||||||
| # Stage 2 · CI — run the full test matrix across all supported Python versions. | ||||||||||||||||||||||||||||||
| # Always runs. Waits for Validate when runPublish is true; | ||||||||||||||||||||||||||||||
| # runs immediately when Validate is skipped (PR / merge builds). | ||||||||||||||||||||||||||||||
| # ══════════════════════════════════════════════════════════════════════════════ | ||||||||||||||||||||||||||||||
| - stage: CI | ||||||||||||||||||||||||||||||
| displayName: 'Run tests' | ||||||||||||||||||||||||||||||
| dependsOn: | ||||||||||||||||||||||||||||||
| - PreBuildCheck | ||||||||||||||||||||||||||||||
| - Validate | ||||||||||||||||||||||||||||||
| condition: | | ||||||||||||||||||||||||||||||
| and( | ||||||||||||||||||||||||||||||
| eq(dependencies.PreBuildCheck.result, 'Succeeded'), | ||||||||||||||||||||||||||||||
| in(dependencies.Validate.result, 'Succeeded', 'Skipped') | ||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||
| - job: Test | ||||||||||||||||||||||||||||||
| displayName: 'Run unit tests' | ||||||||||||||||||||||||||||||
| pool: | ||||||||||||||||||||||||||||||
| vmImage: ubuntu-latest | ||||||||||||||||||||||||||||||
| strategy: | ||||||||||||||||||||||||||||||
| matrix: | ||||||||||||||||||||||||||||||
| Python39: | ||||||||||||||||||||||||||||||
| python.version: '3.9' | ||||||||||||||||||||||||||||||
| Python310: | ||||||||||||||||||||||||||||||
| python.version: '3.10' | ||||||||||||||||||||||||||||||
| Python311: | ||||||||||||||||||||||||||||||
| python.version: '3.11' | ||||||||||||||||||||||||||||||
| Python312: | ||||||||||||||||||||||||||||||
| python.version: '3.12' | ||||||||||||||||||||||||||||||
| Python313: | ||||||||||||||||||||||||||||||
| python.version: '3.13' | ||||||||||||||||||||||||||||||
| Python314: | ||||||||||||||||||||||||||||||
| python.version: '3.14' | ||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||
| # Retrieve the MSID Lab certificate from Key Vault (via AuthSdkResourceManager SC). | ||||||||||||||||||||||||||||||
| # Matches the pattern used by MSAL.js (install-keyvault-secrets.yml) and MSAL Java. | ||||||||||||||||||||||||||||||
| - task: AzureKeyVault@2 | ||||||||||||||||||||||||||||||
| displayName: 'Retrieve lab certificate from Key Vault' | ||||||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||||||
| azureSubscription: 'AuthSdkResourceManager' | ||||||||||||||||||||||||||||||
| KeyVaultName: 'msidlabs' | ||||||||||||||||||||||||||||||
| SecretsFilter: 'LabAuth' | ||||||||||||||||||||||||||||||
| RunAsPreJob: false | ||||||||||||||||||||||||||||||
|
Comment on lines
+143
to
+149
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| - bash: | | ||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||
| CERT_PATH="$(Agent.TempDirectory)/lab-auth.pfx" | ||||||||||||||||||||||||||||||
| printf '%s' "$(LabAuth)" | base64 -d > "$CERT_PATH" | ||||||||||||||||||||||||||||||
| echo "##vso[task.setvariable variable=LAB_APP_CLIENT_CERT_PFX_PATH]$CERT_PATH" | ||||||||||||||||||||||||||||||
| echo "Lab cert written to: $CERT_PATH ($(wc -c < "$CERT_PATH") bytes)" | ||||||||||||||||||||||||||||||
| displayName: 'Write lab certificate to disk' | ||||||||||||||||||||||||||||||
|
Comment on lines
+154
to
+157
|
||||||||||||||||||||||||||||||
| printf '%s' "$(LabAuth)" | base64 -d > "$CERT_PATH" | |
| echo "##vso[task.setvariable variable=LAB_APP_CLIENT_CERT_PFX_PATH]$CERT_PATH" | |
| echo "Lab cert written to: $CERT_PATH ($(wc -c < "$CERT_PATH") bytes)" | |
| displayName: 'Write lab certificate to disk' | |
| if [ -z "${LABAUTH:-}" ] || [ "$LABAUTH" = '$(LabAuth)' ]; then | |
| echo "Error: LabAuth secret is not set or is invalid. Ensure the LabAuth secret is defined in Azure Pipelines/Key Vault." | |
| exit 1 | |
| fi | |
| printf '%s' "$LABAUTH" | base64 -d > "$CERT_PATH" | |
| echo "##vso[task.setvariable variable=LAB_APP_CLIENT_CERT_PFX_PATH]$CERT_PATH" | |
| echo "Lab cert written to: $CERT_PATH ($(wc -c < "$CERT_PATH") bytes)" | |
| displayName: 'Write lab certificate to disk' | |
| env: | |
| LABAUTH: $(LabAuth) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These suppression entries won’t match the actual repo paths: the files live under tests/ (tests/certificate-with-password.pfx and tests/test_mi.py). Update the "file" values to the correct relative paths so CredScan suppression works as intended.