diff --git a/build/azure-pipeline.npm.yml b/build/azure-pipeline.npm.yml index 387d748d..3e459f81 100644 --- a/build/azure-pipeline.npm.yml +++ b/build/azure-pipeline.npm.yml @@ -56,6 +56,14 @@ variables: value: next ${{ else }}: value: latest + - name: AzureArtifactsFeedUrl + value: 'https://pkgs.dev.azure.com/azure-public/vside/_packaging/python-environments/npm/registry/' + # Same URL without the https:// prefix (used in .npmrc auth lines) + - name: AzureArtifactsFeedUrlNoProtocol + value: 'pkgs.dev.azure.com/azure-public/vside/_packaging/python-environments/npm/registry/' + # Managed Identity service connection for Azure Artifacts auth (shared with Pylance) + - name: AzureServiceConnection + value: 'PylanceSecureVsIdePublishWithManagedIdentity' extends: template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate @@ -97,30 +105,66 @@ extends: targetFolder: $(Build.ArtifactStagingDirectory) - stage: Publish - displayName: Publish to npm + displayName: Publish to Azure Artifacts dependsOn: Build condition: and(succeeded(), eq('${{ parameters.publishPackage }}', 'true')) jobs: - job: PublishPackage displayName: Publish $(PackageName) - steps: - - task: DownloadPipelineArtifact@2 - displayName: Download build artifact - inputs: + templateContext: + type: releaseJob + isProduction: true + inputs: + - input: pipelineArtifact artifactName: npm-package - targetPath: $(Build.ArtifactStagingDirectory)/npm-package + targetPath: $(Pipeline.Workspace)/npm-package + steps: + - checkout: none - task: NodeTool@0 inputs: versionSpec: '22.21.1' displayName: Select Node version - - bash: echo '//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}' > .npmrc - workingDirectory: $(Build.SourcesDirectory)/pythonEnvironmentsApi - displayName: Configure npm auth - - - bash: npm publish $(Build.ArtifactStagingDirectory)/npm-package/*.tgz --tag $(npmTag) --access public --ignore-scripts - displayName: Publish to npm (${{ parameters.quality }}) - workingDirectory: $(Build.SourcesDirectory)/pythonEnvironmentsApi + # Acquire a short-lived AAD token via Managed Identity (no stored secrets) + # SEE https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/1es-security-configuration/configuration-guides/pat-burndown-guidance + - task: AzureCLI@2 + displayName: Acquire AAD token via Managed Identity + inputs: + azureSubscription: '$(AzureServiceConnection)' + scriptType: 'pscore' + scriptLocation: 'inlineScript' + inlineScript: | + $token = az account get-access-token --query accessToken --resource 499b84ac-1321-427f-aa17-267ca6975798 -o tsv + Write-Host "##vso[task.setvariable variable=AzdoToken;issecret=true]$token" + + - powershell: | + @" + registry=$(AzureArtifactsFeedUrl) + always-auth=true + "@ | Out-File -FilePath .npmrc + + @" + ; begin auth token + //$(AzureArtifactsFeedUrlNoProtocol):username=VssSessionToken + //$(AzureArtifactsFeedUrlNoProtocol):_authToken=$env:AZDO_TOKEN + //$(AzureArtifactsFeedUrlNoProtocol):email=not-used@example.com + ; end auth token + "@ | Out-File -FilePath $HOME/.npmrc env: - NODE_AUTH_TOKEN: $(NpmAuthToken) + AZDO_TOKEN: $(AzdoToken) + displayName: Create .npmrc files + + - powershell: | + $tgz = Get-ChildItem "$(Pipeline.Workspace)/npm-package/*.tgz" | Select-Object -First 1 + if (-not $tgz) { + Write-Error "No .tgz file found in $(Pipeline.Workspace)/npm-package/" + exit 1 + } + Write-Host "Publishing: $($tgz.FullName)" + if ("$(npmTag)" -eq "next") { + npm publish $tgz.FullName --registry $(AzureArtifactsFeedUrl) --tag next --ignore-scripts + } else { + npm publish $tgz.FullName --registry $(AzureArtifactsFeedUrl) --ignore-scripts + } + displayName: npm publish (${{ parameters.quality }})