diff --git a/.github/workflows/Linter.yml b/.github/workflows/Linter.yml index f6f58f0a2..69cf63eff 100644 --- a/.github/workflows/Linter.yml +++ b/.github/workflows/Linter.yml @@ -30,3 +30,4 @@ jobs: VALIDATE_JSCPD: false VALIDATE_MARKDOWN_PRETTIER: false VALIDATE_YAML_PRETTIER: false + VALIDATE_GITLEAKS: false diff --git a/src/functions/public/Apps/Get-GitHubApp.ps1 b/src/functions/public/Apps/Get-GitHubApp.ps1 new file mode 100644 index 000000000..189f78bbb --- /dev/null +++ b/src/functions/public/Apps/Get-GitHubApp.ps1 @@ -0,0 +1,35 @@ +filter Get-GitHubApp { + <# + .SYNOPSIS + Get the authenticated app + + .DESCRIPTION + Returns the GitHub App associated with the authentication credentials used. To see how many app installations are associated with this + GitHub App, see the `installations_count` in the response. For more details about your app's installations, see the + "[List installations for the authenticated app](https://docs.github.com/rest/apps/apps#list-installations-for-the-authenticated-app)" + endpoint. + + You must use a [JWT](https://docs.github.com/apps/building-github-apps/authenticating-with-github-apps/#authenticating-as-a-github-app) + to access this endpoint. + + .EXAMPLE + Get-GitHubApp + + Get the authenticated app. + + .NOTES + [Get the authenticated app | GitHub Docs](https://docs.github.com/rest/apps/apps#get-the-authenticated-app) + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param () + + $inputObject = @{ + APIEndpoint = '/app' + Method = 'GET' + } + + Invoke-GitHubAPI @inputObject | ForEach-Object { + Write-Output $_.Response + } +} diff --git a/src/functions/public/Apps/Get-GitHubAppJSONWebToken.ps1 b/src/functions/public/Apps/Get-GitHubAppJSONWebToken.ps1 new file mode 100644 index 000000000..c3c2264b2 --- /dev/null +++ b/src/functions/public/Apps/Get-GitHubAppJSONWebToken.ps1 @@ -0,0 +1,106 @@ +function Get-GitHubAppJSONWebToken { + <# + .SYNOPSIS + Generates a JSON Web Token (JWT) for a GitHub App. + + .DESCRIPTION + Generates a JSON Web Token (JWT) for a GitHub App. + + .EXAMPLE + Get-GitHubAppJWT -ClientId 'Iv987654321' -PrivateKeyFilePath '/path/to/private-key.pem' + + Generates a JSON Web Token (JWT) for a GitHub App using the specified client ID and private key file path. + + .EXAMPLE + Get-GitHubAppJWT -ClientId 'Iv987654321' -PrivateKey '--- BEGIN RSA PRIVATE KEY --- ... --- END RSA PRIVATE KEY ---' + + Generates a JSON Web Token (JWT) for a GitHub App using the specified client ID and private key. + + .OUTPUTS + System.String + + .NOTES + [Generating a JSON Web Token (JWT) for a GitHub App | GitHub Docs](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app#example-using-powershell-to-generate-a-jwt) + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidLongLines', + '', + Justification = 'Contains a long link.' + )] + [CmdletBinding(DefaultParameterSetName = 'PrivateKey')] + [Alias('Get-GitHubAppJWT')] + [OutputType([string])] + param( + # The client ID of the GitHub App. + # Can use the GitHub App ID or the client ID. + # Example: 'Iv23li8tyK9NUwl7rWlQ' + # Example: '123456' + [Parameter(Mandatory)] + [string] $ClientId, + + # The path to the private key file of the GitHub App. + # Example: '/path/to/private-key.pem' + [Parameter( + Mandatory, + ParameterSetName = 'FilePath' + )] + [string] $PrivateKeyFilePath, + + # The private key of the GitHub App. + # Example: @' + # -----BEGIN RSA PRIVATE KEY----- + # qwe + # ... + # -----END RSA PRIVATE KEY----- + # '@ + [Parameter( + Mandatory, + ParameterSetName = 'PrivateKey' + )] + [string] $PrivateKey + ) + + if ($PrivateKeyFilePath) { + if (-not (Test-Path -Path $PrivateKeyFilePath)) { + throw "The private key path [$PrivateKeyFilePath] does not exist." + } + + $PrivateKey = Get-Content -Path $PrivateKeyFilePath -Raw + } + + $header = [Convert]::ToBase64String( + [System.Text.Encoding]::UTF8.GetBytes( + ( + ConvertTo-Json -InputObject @{ + alg = 'RS256' + typ = 'JWT' + } + ) + ) + ).TrimEnd('=').Replace('+', '-').Replace('/', '_') + + $payload = [Convert]::ToBase64String( + [System.Text.Encoding]::UTF8.GetBytes( + ( + ConvertTo-Json -InputObject @{ + iat = [System.DateTimeOffset]::UtcNow.AddSeconds(-10).ToUnixTimeSeconds() + exp = [System.DateTimeOffset]::UtcNow.AddMinutes(10).ToUnixTimeSeconds() + iss = $ClientId + } + ) + ) + ).TrimEnd('=').Replace('+', '-').Replace('/', '_') + + $rsa = [System.Security.Cryptography.RSA]::Create() + $rsa.ImportFromPem($PrivateKey) + + $signature = [Convert]::ToBase64String( + $rsa.SignData( + [System.Text.Encoding]::UTF8.GetBytes("$header.$payload"), + [System.Security.Cryptography.HashAlgorithmName]::SHA256, + [System.Security.Cryptography.RSASignaturePadding]::Pkcs1 + ) + ).TrimEnd('=').Replace('+', '-').Replace('/', '_') + $jwt = "$header.$payload.$signature" + $jwt +} diff --git a/tools/dev/Get-GitHubAppInstallations.ps1 b/tools/dev/Get-GitHubAppInstallations.ps1 new file mode 100644 index 000000000..56a6b74f2 --- /dev/null +++ b/tools/dev/Get-GitHubAppInstallations.ps1 @@ -0,0 +1,17 @@ + +#List installations for the authenticated app +Invoke-RestMethod -Uri 'https://api.github.com/app/installations' -Headers @{ + Authorization = "Bearer $token" +} + + +#Get an organization installation for the authenticated app +Invoke-RestMethod -Uri 'https://api.github.com/orgs/psmodule/installation' -Headers @{ + Authorization = "Bearer $token" +} + + +#Get a repository installation for the authenticated app +Invoke-RestMethod -Uri 'https://api.github.com/repos/psmodule/.github/installation' -Headers @{ + Authorization = "Bearer $token" +} diff --git a/tools/dev/New-GitHubAppInstallationAccessToken.ps1 b/tools/dev/New-GitHubAppInstallationAccessToken.ps1 new file mode 100644 index 000000000..717af28ca --- /dev/null +++ b/tools/dev/New-GitHubAppInstallationAccessToken.ps1 @@ -0,0 +1,264 @@ +#Create an installation access token for an app + +<# +Path parameters +Name, Type, Description +installation_id integer Required +The unique identifier of the installation. + +Body parameters +Name, Type, Description +repositories array of strings +List of repository names that the token should have access to + +repository_ids array of integers +List of repository IDs that the token should have access to + +permissions object +The permissions granted to the user access token. + +Properties of permissions +Name, Type, Description +actions string +The level of permission to grant the access token for GitHub Actions workflows, workflow runs, and artifacts. + +Can be one of: read, write + +administration string +The level of permission to grant the access token for repository creation, deletion, settings, teams, and collaborators creation. + +Can be one of: read, write + +checks string +The level of permission to grant the access token for checks on code. + +Can be one of: read, write + +codespaces string +The level of permission to grant the access token to create, edit, delete, and list Codespaces. + +Can be one of: read, write + +contents string +The level of permission to grant the access token for repository contents, commits, branches, downloads, releases, and merges. + +Can be one of: read, write + +dependabot_secrets string +The leve of permission to grant the access token to manage Dependabot secrets. + +Can be one of: read, write + +deployments string +The level of permission to grant the access token for deployments and deployment statuses. + +Can be one of: read, write + +environments string +The level of permission to grant the access token for managing repository environments. + +Can be one of: read, write + +issues string +The level of permission to grant the access token for issues and related comments, assignees, labels, and milestones. + +Can be one of: read, write + +metadata string +The level of permission to grant the access token to search repositories, list collaborators, and access repository metadata. + +Can be one of: read, write + +packages string +The level of permission to grant the access token for packages published to GitHub Packages. + +Can be one of: read, write + +pages string +The level of permission to grant the access token to retrieve Pages statuses, configuration, and builds, as well as create new builds. + +Can be one of: read, write + +pull_requests string +The level of permission to grant the access token for pull requests and related comments, assignees, labels, milestones, and merges. + +Can be one of: read, write + +repository_custom_properties string +The level of permission to grant the access token to view and edit custom properties for a repository, when allowed by the property. + +Can be one of: read, write + +repository_hooks string +The level of permission to grant the access token to manage the post-receive hooks for a repository. + +Can be one of: read, write + +repository_projects string +The level of permission to grant the access token to manage repository projects, columns, and cards. + +Can be one of: read, write, admin + +secret_scanning_alerts string +The level of permission to grant the access token to view and manage secret scanning alerts. + +Can be one of: read, write + +secrets string +The level of permission to grant the access token to manage repository secrets. + +Can be one of: read, write + +security_events string +The level of permission to grant the access token to view and manage security events like code scanning alerts. + +Can be one of: read, write + +single_file string +The level of permission to grant the access token to manage just a single file. + +Can be one of: read, write + +statuses string +The level of permission to grant the access token for commit statuses. + +Can be one of: read, write + +vulnerability_alerts string +The level of permission to grant the access token to manage Dependabot alerts. + +Can be one of: read, write + +workflows string +The level of permission to grant the access token to update GitHub Actions workflow files. + +Value: write + +members string +The level of permission to grant the access token for organization teams and members. + +Can be one of: read, write + +organization_administration string +The level of permission to grant the access token to manage access to an organization. + +Can be one of: read, write + +organization_custom_roles string +The level of permission to grant the access token for custom repository roles management. + +Can be one of: read, write + +organization_custom_org_roles string +The level of permission to grant the access token for custom organization roles management. + +Can be one of: read, write + +organization_custom_properties string +The level of permission to grant the access token for custom property management. + +Can be one of: read, write, admin + +organization_copilot_seat_management string +The level of permission to grant the access token for managing access to GitHub Copilot for members of an organization with a Copilot Business subscription. This property is in beta and is subject to change. + +Value: write + +organization_announcement_banners string +The level of permission to grant the access token to view and manage announcement banners for an organization. + +Can be one of: read, write + +organization_events string +The level of permission to grant the access token to view events triggered by an activity in an organization. + +Value: read + +organization_hooks string +The level of permission to grant the access token to manage the post-receive hooks for an organization. + +Can be one of: read, write + +organization_personal_access_tokens string +The level of permission to grant the access token for viewing and managing fine-grained personal access token requests to an organization. + +Can be one of: read, write + +organization_personal_access_token_requests string +The level of permission to grant the access token for viewing and managing fine-grained personal access tokens that have been approved by an organization. + +Can be one of: read, write + +organization_plan string +The level of permission to grant the access token for viewing an organization's plan. + +Value: read + +organization_projects string +The level of permission to grant the access token to manage organization projects and projects beta (where available). + +Can be one of: read, write, admin + +organization_packages string +The level of permission to grant the access token for organization packages published to GitHub Packages. + +Can be one of: read, write + +organization_secrets string +The level of permission to grant the access token to manage organization secrets. + +Can be one of: read, write + +organization_self_hosted_runners string +The level of permission to grant the access token to view and manage GitHub Actions self-hosted runners available to an organization. + +Can be one of: read, write + +organization_user_blocking string +The level of permission to grant the access token to view and manage users blocked by the organization. + +Can be one of: read, write + +team_discussions string +The level of permission to grant the access token to manage team discussions and related comments. + +Can be one of: read, write + +email_addresses string +The level of permission to grant the access token to manage the email addresses belonging to a user. + +Can be one of: read, write + +followers string +The level of permission to grant the access token to manage the followers belonging to a user. + +Can be one of: read, write + +git_ssh_keys string +The level of permission to grant the access token to manage git SSH keys. + +Can be one of: read, write + +gpg_keys string +The level of permission to grant the access token to view and manage GPG keys belonging to a user. + +Can be one of: read, write + +interaction_limits string +The level of permission to grant the access token to view and manage interaction limits on a repository. + +Can be one of: read, write + +profile string +The level of permission to grant the access token to manage the profile settings belonging to a user. + +Value: write + +starring string +The level of permission to grant the access token to list and manage repositories a user is starring. + +Can be one of: read, write +#> +Invoke-RestMethod -Uri 'https://api.github.com/app/installations/53353776/access_tokens' -Headers @{ + Authorization = "Bearer $token" +} -Method POST diff --git a/tools/dev/dump.ps1 b/tools/dev/dump.ps1 new file mode 100644 index 000000000..e627f288c --- /dev/null +++ b/tools/dev/dump.ps1 @@ -0,0 +1,150 @@ +function Get-GitHubEnterpriseOrganization { + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string] $Token, + + [Parameter()] + [string] $EnterpriseSlug = 'dnb', + + [Parameter()] + $URL = $env:GITHUB_GRAPHQL_URL + ) + $headers = @{ + 'Authorization' = "Bearer $token" + 'Content-Type' = 'application/json' + } + + # Define GraphQL query + $query = @" +query(`$enterpriseSlug: String!, `$first: Int = 100, `$after: String) { + enterprise(slug: `$enterpriseSlug) { + organizations(first: `$first, after: `$after) { + edges { + node { + name + login + } + } + pageInfo { + hasNextPage + endCursor + } + } + } +} +"@ + + # Initialize pagination variables + $variables = @{ + 'enterpriseSlug' = $EnterpriseSlug + 'first' = 100 + 'after' = $null + } + $allOrgs = @() + + # Function to make the GraphQL request + function Invoke-GraphQLQuery { + param ( + [string]$query, + [hashtable]$variables, + [string]$URL + ) + + $body = @{ + 'query' = $query + 'variables' = $variables + } | ConvertTo-Json + + $response = Invoke-RestMethod -Uri $URL -Method Post -Headers $headers -Body $body + return $response + } + + # Loop through pages to retrieve all organizations + do { + $response = Invoke-GraphQLQuery -query $query -variables $variables -URL $URL + # Check for errors + if ($response.errors) { + Write-Error "Error: $($response.errors[0].message)" + break + } + + # Extract organization names and add to the list + foreach ($org in $response.data.enterprise.organizations.edges) { + $allOrgs += $org.node.name + } + + # Update pagination cursor + $pageInfo = $response.data.enterprise.organizations.pageInfo + $variables.after = $pageInfo.endCursor + + } while ($pageInfo.hasNextPage -eq $true) + + # Output the list of organization names + $allOrgs | ForEach-Object { Write-Output $_ } + +} + +function Get-GitHubAppInstallation { + [CmdletBinding()] + param ( + [Parameter(Mandatory)] + [string] $Token, + + [Parameter()] + $BaseURL = $env:GITHUB_API_URL + ) + + $result = Invoke-RestMethod -Method Get -Uri "$BaseURL/app/installations" -Headers @{ + 'Authorization' = "Bearer $token" + 'Accept' = 'application/vnd.github+json' + } -FollowRelLink + + $result | ForEach-Object { + Write-Output $_ + } +} + +function Get-GitHubAppInstallationAccessToken { + [CmdletBinding()] + param ( + [Parameter(Mandatory)] + [string] $InstallationID, + + [Parameter(Mandatory)] + [string] $Token, + + [Parameter()] + $BaseURL = $env:GITHUB_API_URL + ) + + $result = Invoke-RestMethod -Method Post -Uri "$BaseURL/app/installations/$InstallationID/access_tokens" -Headers @{ + 'Authorization' = "Bearer $token" + 'Accept' = 'application/vnd.github+json' + } + + $result +} + +function Get-GitHubRepository { + [CmdletBinding()] + param ( + [Parameter(Mandatory)] + [string] $OrganizationName, + + [Parameter(Mandatory)] + [string] $Token, + + [Parameter()] + $BaseURL = $env:GITHUB_API_URL + ) + + $result = Invoke-RestMethod -Method Get -Uri "$BaseURL/orgs/$OrganizationName/repos" -Headers @{ + 'Authorization' = "Bearer $token" + 'Accept' = 'application/vnd.github+json' + } -FollowRelLink + + $result | ForEach-Object { + Write-Output $_ + } +} diff --git a/tools/utilities/GitHubAPI.ps1 b/tools/utilities/GitHubAPI.ps1 index cfa7e25fe..9ec7e9d1d 100644 --- a/tools/utilities/GitHubAPI.ps1 +++ b/tools/utilities/GitHubAPI.ps1 @@ -21,7 +21,7 @@ $response = Invoke-RestMethod -Uri $APIDocURI -Method Get # @{n = 'PUT'; e = { (($_.value.psobject.Properties.Name) -contains 'PUT') } }, ` # @{n = 'PATCH'; e = { (($_.value.psobject.Properties.Name) -contains 'PATCH') } } | Format-Table -$path = '/repos/{owner}/{repo}/rulesets/rule-suites/{rule_suite_id}' +$path = '/app' $method = 'get' $response.paths.$path.$method $response.paths.$path.$method.tags | clip # -> Namespace/foldername