diff --git a/.azuredevops/ci.yml b/.azuredevops/ci.yml index 8fbfe1d..f5a79be 100644 --- a/.azuredevops/ci.yml +++ b/.azuredevops/ci.yml @@ -4,6 +4,8 @@ variables: value: "production" readonly: true +pr: none + trigger: branches: include: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e23e608 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,328 @@ +name: Release + +on: + workflow_dispatch: + inputs: + version: + description: 'Version' + required: true + type: string + # We use SemVer, anything before 1.0.0 is a pre-release, but this could also include versions like 1.1.0-beta. + prerelease: + description: 'Prerelease' + required: true + default: true + type: boolean + +jobs: + # Special request from @kyle-rader and @goagain, so no one can create an invalid release. + validate: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Validate version + run: echo ${{ github.event.inputs.version }} | python ./bin/version.py + + build: + permissions: + actions: read + contents: read + security-events: write + statuses: write + id-token: write + + runs-on: ${{ matrix.os }} + needs: [validate] + strategy: + matrix: + # We build on Linux, but don't yet ship Linux because we can't easily sign those releases. + runtime: [osx-x64, osx-arm64, win10-x64] + include: + # macos-latest (currently 14) breaks this flow. Refer https://github.com/actions/runner-images/issues/9766. + - runtime: osx-x64 + os: macos-13 + - runtime: osx-arm64 + os: macos-13 + - runtime: win10-x64 + os: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Get Azure DevOps Access Token + id: getToken + uses: "./.github/actions/get-ado-token" + with: + client-id: ${{ secrets.AZURE_RELEASE_WORKFLOW_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_RELEASE_WORKFLOW_TENANT_ID }} + organization: ${{ secrets.ADO_ORGANIZATION }} + + - name: Setup .NET 6 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 6.0.x + + - name: Install dependencies + run: dotnet restore --runtime ${{ matrix.runtime }} + env: + ADO_TOKEN: ${{ steps.getToken.outputs.token }} + - name: Test + run: dotnet test --no-restore --configuration release + + - name: Build artifacts + run: dotnet publish src/AzureAuth/AzureAuth.csproj -p:Version=${{ github.event.inputs.version }} --configuration release --self-contained true --runtime ${{ matrix.runtime }} --output dist/${{ matrix.runtime }} + env: + ADO_TOKEN: ${{ steps.getToken.outputs.token }} + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: azureauth-${{ github.event.inputs.version }}-${{ matrix.runtime }} + path: dist/${{ matrix.runtime }} + + analyze: + runs-on: ubuntu-latest + permissions: + security-events: write + id-token: write + needs: [validate] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Get Azure DevOps Access Token + id: getToken + uses: "./.github/actions/get-ado-token" + with: + client-id: ${{ secrets.AZURE_RELEASE_WORKFLOW_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_RELEASE_WORKFLOW_TENANT_ID }} + organization: ${{ secrets.ADO_ORGANIZATION }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: csharp + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + env: + ADO_TOKEN: ${{ steps.getToken.outputs.token }} + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:csharp" + + sign: + # This step has to run on Windows because ESRPClient.exe is currently only available for that platform. + runs-on: windows-latest + needs: [build, analyze] + strategy: + matrix: + runtime: [osx-x64, osx-arm64, win10-x64] + permissions: + id-token: write + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Setup NuGet + uses: NuGet/setup-nuget@v1 + with: + nuget-version: '5.x' + - name: Get Azure DevOps Access Token + id: getToken + uses: "./.github/actions/get-ado-token" + with: + client-id: ${{ secrets.AZURE_RELEASE_WORKFLOW_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_RELEASE_WORKFLOW_TENANT_ID }} + organization: ${{ secrets.ADO_ORGANIZATION }} + - name: Download ESRPClient.exe + env: + ESRP_VERSION: ${{ secrets.ESRP_VERSION }} + NUGET_CREDENTIALS: ${{ steps.getToken.outputs.token }} + run: | + nuget sources add -Name esrp -Username esrp-downloader -Password $env:NUGET_CREDENTIALS -Source https://pkgs.dev.azure.com/office/_packaging/Office/nuget/v3/index.json + nuget install Microsoft.EsrpClient -Version "$env:ESRP_VERSION" -OutputDirectory .\esrp -Source https://pkgs.dev.azure.com/office/_packaging/Office/nuget/v3/index.json + - name: Login to Azure + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + # We need these certificates installed so that we can run ESRPClient.exe. + - name: Install certificates + env: + AZURE_SUBSCRIPTION: ${{ secrets.AZURE_SUBSCRIPTION }} + AZURE_VAULT: ${{ secrets.AZURE_VAULT }} + ESRP_AAD_CERT_NAME: ${{ secrets.AZURE_VAULT_ESRP_AAD_CERT_NAME }} + ESRP_REQ_CERT_NAME: ${{ secrets.AZURE_VAULT_ESRP_REQ_CERT_NAME }} + run: | + az keyvault secret download --subscription "$env:AZURE_SUBSCRIPTION" --vault-name "$env:AZURE_VAULT" --name "$env:ESRP_AAD_CERT_NAME" -f cert.pfx + certutil -f -importpfx cert.pfx + Remove-Item cert.pfx + + az keyvault secret download --subscription "$env:AZURE_SUBSCRIPTION" --vault-name "$env:AZURE_VAULT" --name "$env:ESRP_REQ_CERT_NAME" -f cert.pfx + certutil -f -importpfx cert.pfx + Remove-Item cert.pfx + # We download all artifacts and overwrite them with signed files, but only upload ones which we can properly sign. + - name: Download all artifacts + uses: actions/download-artifact@v3 + - name: Sign artifacts + env: + SIGNING_AAD_ID: ${{ secrets.SIGNING_AAD_ID }} + SIGNING_TENANT_ID: ${{ secrets.SIGNING_TENANT_ID }} + SIGNING_KEY_CODE_AUTHENTICODE: ${{ secrets.SIGNING_KEY_CODE_AUTHENTICODE }} + SIGNING_KEY_CODE_MAC: ${{ secrets.SIGNING_KEY_CODE_MAC }} + SIGNING_KEY_CODE_LINUX: ${{ secrets.SIGNING_KEY_CODE_LINUX }} + SIGNING_CUSTOMER_CORRELATION_ID: ${{ secrets.SIGNING_CUSTOMER_CORRELATION_ID }} + ESRP_CLIENT_EXE: ".\\esrp\\Microsoft.EsrpClient.${{ secrets.ESRP_VERSION }}\\tools\\EsrpClient.exe" + run: python .\bin\sign.py "$env:ESRP_CLIENT_EXE" --runtime=${{ matrix.runtime }} --source=azureauth-${{ github.event.inputs.version }}-${{ matrix.runtime }} + - name: Upload signed artifacts + uses: actions/upload-artifact@v3 + with: + name: azureauth-${{ github.event.inputs.version }}-${{ matrix.runtime }} + path: azureauth-${{ github.event.inputs.version }}-${{ matrix.runtime }} + + # Build and sign Linux binaries on Azure DevOps and publish them to GitHub and packages.microsoft.com. + linux_release: + runs-on: ubuntu-latest + needs: [validate] + env: + ADO_LINUX_ARTIFACT_DOWNLOAD_PATH: dist/linux + ADO_LINUX_ARTIFACT_NAME: ${{ vars.ADO_LINUX_ARTIFACT_NAME }} + DEBIAN_REVISION: 1 + permissions: + id-token: write + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Get Azure DevOps Access Token + id: getToken + uses: "./.github/actions/get-ado-token" + with: + client-id: ${{ secrets.AZURE_RELEASE_WORKFLOW_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_RELEASE_WORKFLOW_TENANT_ID }} + organization: ${{ secrets.ADO_ORGANIZATION }} + - name: Build, Sign and Download Linux Binaries + run: | + pip install -r bin/requirements.txt + python ./bin/trigger_azure_pipelines.py + env: + AZURE_DEVOPS_ACCESS_TOKEN: ${{ steps.getToken.outputs.token }} + ADO_ORGANIZATION: ${{ secrets.ADO_ORGANIZATION }} + ADO_PROJECT: ${{ secrets.ADO_PROJECT}} + ADO_AZUREAUTH_LINUX_PIPELINE_ID: ${{ secrets.ADO_AZUREAUTH_LINUX_PIPELINE_ID }} + ADO_AZUREAUTH_LINUX_STAGE_ID: ${{ vars.ADO_AZUREAUTH_LINUX_STAGE_ID }} + VERSION: ${{ github.event.inputs.version }} + + - name: Rename linux artifact + env: + DEB_AMD64_SOURCE: ${{ env.ADO_LINUX_ARTIFACT_DOWNLOAD_PATH }}/${{ env.ADO_LINUX_ARTIFACT_NAME }}/azureauth_${{ github.event.inputs.version }}-${{ env.DEBIAN_REVISION }}_amd64.deb + DEB_AMD64_TARGET: azureauth-${{ github.event.inputs.version }}-linux-x64.deb + DEB_ARM64_SOURCE: ${{ env.ADO_LINUX_ARTIFACT_DOWNLOAD_PATH }}/${{ env.ADO_LINUX_ARTIFACT_NAME }}/azureauth_${{ github.event.inputs.version }}-${{ env.DEBIAN_REVISION }}_arm64.deb + DEB_ARM64_TARGET: azureauth-${{ github.event.inputs.version }}-linux-arm64.deb + run: | + mv ${{ env.DEB_AMD64_SOURCE }} ${{ env.DEB_AMD64_TARGET }} + mv ${{ env.DEB_ARM64_SOURCE }} ${{ env.DEB_ARM64_TARGET }} + + - name: Upload linux artifact + uses: actions/upload-artifact@v3 + with: + name: azureauth-linux + path: | + azureauth-${{ github.event.inputs.version }}-linux-x64.deb + azureauth-${{ github.event.inputs.version }}-linux-arm64.deb + + # Currently we package artifacts into the most commonly accessible archive format for their respective platforms. + package: + runs-on: ubuntu-latest + needs: [sign] + steps: + - name: Download all artifacts + uses: actions/download-artifact@v3 + - name: Install Zip + run: sudo apt install -y zip + - name: Create win10-x64 archive + run: | + cd azureauth-${{ github.event.inputs.version }}-win10-x64 + zip ../azureauth-${{ github.event.inputs.version }}-win10-x64.zip * + - name: Upload win10-x64 artifact + uses: actions/upload-artifact@v3 + with: + name: azureauth-${{ github.event.inputs.version }}-win10-x64.zip + path: azureauth-${{ github.event.inputs.version }}-win10-x64.zip + - name: Create osx-x64 archive + run: | + cd azureauth-${{ github.event.inputs.version }}-osx-x64 + chmod +x azureauth createdump *.dylib + tar -czf ../azureauth-${{ github.event.inputs.version }}-osx-x64.tar.gz * + - name: Upload osx-x64 artifact + uses: actions/upload-artifact@v3 + with: + name: azureauth-${{ github.event.inputs.version }}-osx-x64.tar.gz + path: azureauth-${{ github.event.inputs.version }}-osx-x64.tar.gz + - name: Create osx-arm64 archive + run: | + cd azureauth-${{ github.event.inputs.version }}-osx-arm64 + chmod +x azureauth createdump *.dylib + tar -czf ../azureauth-${{ github.event.inputs.version }}-osx-arm64.tar.gz * + - name: Upload osx-arm64 artifact + uses: actions/upload-artifact@v3 + with: + name: azureauth-${{ github.event.inputs.version }}-osx-arm64.tar.gz + path: azureauth-${{ github.event.inputs.version }}-osx-arm64.tar.gz + + release: + runs-on: ubuntu-latest + needs: [package, linux_release] + # The 'release' environment is what requires reviews before creating the release. + environment: + name: release + # These permissions are required in order to use `softprops/action-gh-release` to upload. + permissions: + contents: write + steps: + - name: Download win10-x64 artifact + uses: actions/download-artifact@v3 + with: + name: azureauth-${{ github.event.inputs.version }}-win10-x64.zip + - name: Download osx-x64 artifact + uses: actions/download-artifact@v3 + with: + name: azureauth-${{ github.event.inputs.version }}-osx-x64.tar.gz + - name: Download osx-arm64 artifact + uses: actions/download-artifact@v3 + with: + name: azureauth-${{ github.event.inputs.version }}-osx-arm64.tar.gz + - name: Download linux-x64 artifact + uses: actions/download-artifact@v3 + with: + name: azureauth-linux + + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + name: ${{ github.event.inputs.version }} + body: "Release ${{ github.event.inputs.version }}. See [`CHANGELOG.md`](https://github.com/AzureAD/microsoft-authentication-cli/blob/${{ github.event.inputs.version }}/CHANGELOG.md) for updates." + tag_name: ${{ github.event.inputs.version }} + prerelease: ${{ github.event.inputs.prerelease }} + files: | + azureauth-${{ github.event.inputs.version }}-win10-x64.zip + azureauth-${{ github.event.inputs.version }}-osx-x64.tar.gz + azureauth-${{ github.event.inputs.version }}-osx-arm64.tar.gz + azureauth-${{ github.event.inputs.version }}-linux-x64.deb + azureauth-${{ github.event.inputs.version }}-linux-arm64.deb