Skip to content
Merged
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
102 changes: 102 additions & 0 deletions eng/common/actions/login-to-github/action.yml
Original file line number Diff line number Diff line change
@@ -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_<Owner> }}
# (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 <prefix>_<owner>.
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
21 changes: 17 additions & 4 deletions eng/common/scripts/login-to-github.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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_<Owner>.

.OUTPUTS
Writes minimal info to stdout. Token is placed in $env:GH_TOKEN if there is only one owner otherwise $env:GH_TOKEN_<Owner> 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()]
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
Loading