diff --git a/eng/common/actions/login-to-github/action.yml b/eng/common/actions/login-to-github/action.yml new file mode 100644 index 0000000000..679be38280 --- /dev/null +++ b/eng/common/actions/login-to-github/action.yml @@ -0,0 +1,102 @@ +# Login to GitHub - Composite Action +# +# Mints a GitHub App installation access token using Azure Key Vault signing. +# This action wraps eng/common/scripts/login-to-github.ps1 for use in GitHub +# Actions workflows. The same script is used by Azure DevOps pipelines via +# eng/common/pipelines/templates/steps/login-to-github.yml. +# +# IMPORTANT: This action requires Azure CLI to be pre-authenticated. +# You must call azure/login BEFORE this action in your workflow. +# This is because composite actions cannot call azure/login internally. +# +# Usage (single owner): +# jobs: +# my-job: +# # An environment is required for OIDC (federated credential) login. +# # Work with EngSys to configure the environment with the federated +# # credential for the AzureSDKEngKeyVault Secrets service connection. +# environment: AzureSDKEngKeyVault +# permissions: +# id-token: write # Required for azure/login OIDC +# steps: +# # Step 1: Authenticate to Azure (required before this action) +# - uses: azure/login@v2 +# with: +# client-id: 5786d1fb-187e-4ca9-9a81-ab89ea278986 +# tenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 +# subscription-id: a18897a6-7e44-457d-9260-f2854c0aca42 +# +# # Step 2: Mint GitHub App token +# - uses: ./eng/common/actions/login-to-github +# with: +# token-owners: Azure +# +# # Step 3: Use the token (available as env var in all subsequent steps) +# - run: gh pr list --repo Azure/azure-sdk-tools +# env: +# GH_TOKEN: ${{ env.GH_TOKEN }} +# +# Usage (multiple owners): +# - uses: ./eng/common/actions/login-to-github +# with: +# token-owners: Azure,azure-sdk,MicrosoftDocs +# +# - run: gh pr list --repo Azure/azure-sdk-tools +# env: +# GH_TOKEN: ${{ env.GH_TOKEN_Azure }} +# +# Tokens are exported to GITHUB_ENV so all subsequent steps can reference +# them as ${{ env.GH_TOKEN }} (single owner) or ${{ env.GH_TOKEN_ }} +# (multiple owners). This matches the Azure DevOps behavior where tokens +# are set as pipeline variables. + +name: 'Login to GitHub' +description: 'Mint a GitHub App installation token via Azure Key Vault signing' + +inputs: + token-owners: + description: > + Comma-separated list of GitHub organizations or users for which to + obtain installation tokens (e.g. "Azure" or "Azure,azure-sdk"). + required: false + default: 'Azure' + variable-name-prefix: + description: > + Prefix for the exported variable name. With a single owner the + variable is named exactly this (default GH_TOKEN). With multiple + owners each variable is named _. + required: false + default: 'GH_TOKEN' + key-vault-name: + description: 'Azure Key Vault name containing the signing key' + required: false + default: 'azuresdkengkeyvault' + key-name: + description: 'Name of the RSA key in Key Vault' + required: false + default: 'azure-sdk-automation' + app-id: + description: 'GitHub App numeric ID' + required: false + default: '1086291' + +runs: + using: 'composite' + steps: + - shell: pwsh + env: + INPUT_TOKEN_OWNERS: ${{ inputs.token-owners }} + INPUT_VARIABLE_NAME_PREFIX: ${{ inputs.variable-name-prefix }} + INPUT_KEY_VAULT_NAME: ${{ inputs.key-vault-name }} + INPUT_KEY_NAME: ${{ inputs.key-name }} + INPUT_APP_ID: ${{ inputs.app-id }} + ACTION_PATH: ${{ github.action_path }} + run: | + $scriptPath = Join-Path $env:ACTION_PATH ".." ".." "scripts" "login-to-github.ps1" + $owners = $env:INPUT_TOKEN_OWNERS -split ',' | ForEach-Object { $_.Trim() } + & $scriptPath ` + -KeyVaultName $env:INPUT_KEY_VAULT_NAME ` + -KeyName $env:INPUT_KEY_NAME ` + -GitHubAppId $env:INPUT_APP_ID ` + -InstallationTokenOwners $owners ` + -VariableNamePrefix $env:INPUT_VARIABLE_NAME_PREFIX diff --git a/eng/common/scripts/login-to-github.ps1 b/eng/common/scripts/login-to-github.ps1 index e911f31eb1..129946a409 100644 --- a/eng/common/scripts/login-to-github.ps1 +++ b/eng/common/scripts/login-to-github.ps1 @@ -3,6 +3,9 @@ Mints a GitHub App installation access token using Azure Key Vault 'sign' (non-exportable key), and logs in the GitHub CLI by setting GH_TOKEN. + Works in both Azure DevOps pipelines and GitHub Actions workflows. + Requires Azure CLI to be pre-authenticated (via AzureCLI@2 in ADO, or azure/login in GH Actions). + .PARAMETER KeyVaultName Name of the Azure Key Vault containing the non-exportable RSA key. @@ -16,10 +19,13 @@ List of GitHub organizations or users for which to obtain installation tokens. .PARAMETER VariableNamePrefix - Name of the ADO variable to set when -SetPipelineVariable is used (default: GH_TOKEN). + Prefix for the exported variable name (default: GH_TOKEN). + With a single owner, exports as GH_TOKEN. With multiple owners, exports as GH_TOKEN_. .OUTPUTS - Writes minimal info to stdout. Token is placed in $env:GH_TOKEN if there is only one owner otherwise $env:GH_TOKEN_ for each owner. + Sets environment variables in the current process and exports them to the CI system: + - Azure DevOps: sets secret pipeline variables via ##vso logging commands + - GitHub Actions: writes to GITHUB_ENV and masks the token #> [CmdletBinding()] @@ -98,7 +104,7 @@ function New-GitHubAppJwt { --digest $Base64Value | ConvertFrom-Json if ($LASTEXITCODE -ne 0) { - throw "Failed to sign JWT with Azure Key Vault. Error: $SignResult" + throw "Failed to sign JWT with Azure Key Vault. Error: $($SignResultJson | ConvertTo-Json -Compress)" } if (!$SignResultJson.signature) { @@ -167,12 +173,19 @@ foreach ($InstallationTokenOwner in $InstallationTokenOwners) # Export for gh CLI & git Write-Host "$variableName has been set in the current process." - # Optionally set an Azure DevOps secret variable (so later tasks can reuse it) + # Azure DevOps: set secret pipeline variable (so later tasks can reuse it) if ($null -ne $env:SYSTEM_TEAMPROJECTID) { Write-Host "##vso[task.setvariable variable=$variableName;issecret=true]$installationToken" Write-Host "Azure DevOps variable '$variableName' has been set (secret)." } + # GitHub Actions: mask the token and export to GITHUB_ENV + if ($env:GITHUB_ACTIONS -eq 'true') { + Write-Host "::add-mask::$installationToken" + Add-Content -Path $env:GITHUB_ENV -Value "$variableName=$installationToken" + Write-Host "GitHub Actions env variable '$variableName' has been exported." + } + try { Write-Host "`n--- gh auth status ---" $gh_token_value_before = $env:GH_TOKEN