Skip to content

Commit

Permalink
Merge pull request #23 from rajbos/updates
Browse files Browse the repository at this point in the history
Updates to use GitHub app if needed (debugging)
  • Loading branch information
rajbos authored Apr 27, 2024
2 parents 6c13347 + 37a9d99 commit 576323e
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 50 deletions.
5 changes: 5 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM mcr.microsoft.com/devcontainers/base:focal

# Install Node.js using apt-get
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends nodejs npm
38 changes: 38 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
{
"name": "devcontainer",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"dockerFile": "Dockerfile",
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/azure-cli:1": {},
"ghcr.io/devcontainers-contrib/features/powershell:1": {},
},
"customizations": {
"vscode": {
"extensions": [
"GitHub.copilot",
"ms-vscode.azurecli",
"ms-vscode.PowerShell"
],
"settings": {
"terminal.integrated.shell.linux": "/usr/local/lib/pwsh",
"powershell.powerShellAdditionalExePaths": {
"pwsh": "/usr/local/lib/pwsh/pwsh"
},
"editor.trimAutoWhitespace": true,
"files.trimTrailingWhitespace": true
}
}
},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "pwsh -Command { ./devcontainer/postCreateCommand.ps1; }"

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
87 changes: 42 additions & 45 deletions .github/workflows/library.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ function GetRateLimitInfo {
if ($access_token -ne $access_token_destination) {
# check the ratelimit for the destination token as well:
$response2 = ApiCall -method GET -url $url -access_token $access_token_destination
Write-Message -message "Access token destination ratelimit info: $($response2.rate | ConvertTo-Json)" -logToSummary $true
Write-Message -message "Access token destination ratelimit info: $($response2.rate | ConvertTo-Json -Depth 5)" -logToSummary $true
}

if ($response.rate.limit -eq 60) {
Expand Down Expand Up @@ -867,55 +867,52 @@ function GetForkedActionRepos {
return ($status, $failedForks)
}

function Get-GitHubAppToken {

<#
.DESCRIPTION
Get-TokenFromApp uses the paramsas credentials
for the GitHub App to load an aceess token with. Be aware that this token is only valid for an hour.
Note: this token has only access to the repositories that the App has been installed to.
We cannot use this token to create new repositories or install the app in a repo.
#>
function Get-TokenFromApp {
param (
[string] $appId,
[string] $installationId,
[string] $pemKey
)
$jwt = New-Jwt -appId $appId -pemKey $pemKey
$token = Get-AppToken -jwt $jwt -installationId $installationId
return $token
}
# get a temporary jwt token from the key file and app id (hardcoded in the file:)
$generated_jwt = $(bash ./github-app-jwt.sh $appId $pemKey)
$github_api_url = "https://api.github.com/app"

#Write-Host "Loaded jwt token: [$($generated_jwt)]"
$github_api_url="https://api.github.com/app/installations"
Write-Debug "Calling [${github_api_url}]"
$installationId = ""
try {
$response = Invoke-RestMethod -Uri $github_api_url -Headers @{Authorization = "Bearer $generated_jwt" } -ContentType "application/json" -Method Get

function New-Jwt {
param (
[string] $appId,
[string] $pemKey
)
$now = [System.DateTime]::UtcNow
$payload = @{
iat = [math]::floor($now.Subtract((New-Object DateTime 1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind::Utc)).TotalSeconds)
exp = [math]::floor($now.AddMinutes(10).Subtract((New-Object DateTime 1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind::Utc)).TotalSeconds)
iss = $appId
}
$header = @{
alg = "RS256"
typ = "JWT"
}
$headerJson = $header | ConvertTo-Json -Compress
$payloadJson = $payload | ConvertTo-Json -Compress
$headerBase64 = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($headerJson))
$payloadBase64 = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($payloadJson))
$data = "$headerBase64.$payloadBase64"
$rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider
$rsa.ImportParameters((New-Object System.Security.Cryptography.RSAParameters))
$rsa.FromXmlString($pemKey)
$signature = $rsa.SignData([System.Text.Encoding]::UTF8.GetBytes($data), "SHA256")
$signatureBase64 = [Convert]::ToBase64String($signature)
return "$data.$signatureBase64"
}
Write-Debug "Found installationId: [$($response[0].id)]"
$installationId = $response[0].id
}
catch
{
Write-Error "Error in finding the app installations: $($_)"
}

function Get-AppToken {
param (
[string] $jwt,
[string] $installationId
)
$uri = "https://api.github.com/app/installations/$installationId/access_tokens"
$headers = @{
"Authorization" = "Bearer $jwt"
"Accept" = "application/vnd.github.v3+json"
$github_api_url="https://api.github.com/app/installations/$installationId/access_tokens"
Write-Host "Calling [${github_api_url}]"
$token = ""
try {
$response = Invoke-RestMethod -Uri $github_api_url -Headers @{Authorization = "Bearer $generated_jwt" } -ContentType "application/json" -Method POST -Body "{}"
$token = $response.token
Write-Host "Got an access token that will expire at: [$($response.expires_at)]"
}
$response = Invoke-RestMethod -Uri $uri -Method POST -Headers $headers
return $response.token
}
catch
{
Write-Error "Error in getting an access token: $($_)"
}

Write-Host "Found token with [$($token.length)]"
return $token
}
2 changes: 1 addition & 1 deletion .github/workflows/repo-info.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ on:
workflow_dispatch:

env:
numberOfReposToDo: 1000
numberOfReposToDo: 100

jobs:
get-repo-information:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/repoInfo.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ if ($env:APP_PEM_KEY) {
$env:APP_ID = 264650
$env:INSTALLATION_ID = 31486141
# get a token to use from the app
$accessToken = Get-GitHubAppToken -appId $env:APP_ID -installationId $env:INSTALLATION_ID -pemKey $env:APP_PEM_KEY
$accessToken = Get-TokenFromApp -appId $env:APP_ID -installationId $env:INSTALLATION_ID -pemKey $env:APP_PEM_KEY
}

Test-AccessTokens -accessToken $accessToken -access_token_destination $access_token_destination -numberOfReposToDo $numberOfReposToDo
Expand Down
51 changes: 51 additions & 0 deletions github-app-jwt.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash

# Generate JWT for Github App
#
# Found at https://gist.github.com/carestad/bed9cb8140d28fe05e67e15f667d98ad from Alexander Karlstad:
#
# Inspired by implementation by Will Haley at:
# http://willhaley.com/blog/generate-jwt-with-bash/
# From:
# https://stackoverflow.com/questions/46657001/how-do-you-create-an-rs256-jwt-assertion-with-bash-shell-scripting

thisdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
set -o pipefail

# Change these variables:
app_id=$1
app_private_key="$2"

# Shared content to use as template
header='{
"alg": "RS256",
"typ": "JWT"
}'
payload_template='{}'

build_payload() {
jq -c \
--arg iat_str "$(date +%s)" \
--arg app_id "${app_id}" \
'
($iat_str | tonumber) as $iat
| .iat = $iat
| .exp = ($iat + 300)
| .iss = ($app_id | tonumber)
' <<< "${payload_template}" | tr -d '\n'
}

b64enc() { openssl enc -base64 -A | tr '+/' '-_' | tr -d '='; }
json() { jq -c . | LC_CTYPE=C tr -d '\n'; }
rs256_sign() { openssl dgst -binary -sha256 -sign <(printf '%s\n' "$1"); }

sign() {
local algo payload sig
algo=${1:-RS256}; algo=${algo^^}
payload=$(build_payload) || return
signed_content="$(json <<<"$header" | b64enc).$(json <<<"$payload" | b64enc)"
sig=$(printf %s "$signed_content" | rs256_sign "$app_private_key" | b64enc)
printf '%s.%s\n' "${signed_content}" "${sig}"
}

sign
15 changes: 12 additions & 3 deletions local-run.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@

GetRateLimitInfo -access_token $env:GITHUB_TOKEN

if ($null -ne $env:APP_PEM_KEY) {
Write-Host "GitHub App information found, using GitHub App"
# todo: move into codespace variable
$env:APP_ID = 264650
$env:INSTALLATION_ID = 31486141
# get a token to use from the app
$accessToken = Get-TokenFromApp -appId $env:APP_ID -installationId $env:INSTALLATION_ID -pemKey $env:APP_PEM_KEY
}

# to add: how to refresh the actions.json from the storage account?

$actionsFile = "actions.json"
Expand All @@ -15,7 +24,7 @@ else {
$numberofReposToDo = 10

#./.github/workflows/functions.ps1 -actions $actions -numberofReposToDo $numberofReposToDo
#./.github/workflows/repoInfo.ps1 -actions $actions -numberofReposToDo $numberofReposToDo
./.github/workflows/repoInfo.ps1 -actions $actions -numberofReposToDo $numberofReposToDo -access_token $accessToken -access_token_destination $accessToken

$statusFile = "status.json"
if ((Test-Path $statusFile)) {
Expand All @@ -30,6 +39,6 @@ else {
#./.github/workflows/dependabot-updates.ps1 -actions $status -numberOfReposToDo $numberofReposToDo
#./.github/workflows/ossf-scan.ps1 -actions $actions -numberofReposToDo $numberofReposToDo

. ./.github/workflows/dependents.ps1
#. ./.github/workflows/dependents.ps1
#GetDependentsForRepo -owner "pozil" -repo "auto-assign-issue"
GetDependentsForRepo -owner "devops-action" -repo "get-tag"
#GetDependentsForRepo -owner "devops-action" -repo "get-tag"

0 comments on commit 576323e

Please sign in to comment.