From 8d1b1d9913bfd3659d6e8cd2d0ebbe49cfc49b80 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 21:27:16 +0000 Subject: [PATCH 1/6] Initial plan From 5484bfe965fae9b0d69329543bb5f9905c78bf40 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 21:32:29 +0000 Subject: [PATCH 2/6] Add OIDC subject claim customization support for organizations and repositories Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com> --- ...-GitHubOidcSubjectClaimForOrganization.ps1 | 54 +++++++++ ...et-GitHubOidcSubjectClaimForRepository.ps1 | 58 +++++++++ ...-GitHubOidcSubjectClaimForOrganization.ps1 | 63 ++++++++++ ...et-GitHubOidcSubjectClaimForRepository.ps1 | 81 +++++++++++++ .../Actions/OIDC/Get-GitHubOidcClaim.ps1 | 76 ++++++++++++ .../OIDC/Get-GitHubOidcSubjectClaim.ps1 | 85 +++++++++++++ .../OIDC/Set-GitHubOidcSubjectClaim.ps1 | 113 ++++++++++++++++++ .../public/Actions/OIDC/completers.ps1 | 18 +++ tests/Actions.Tests.ps1 | 106 ++++++++++++++++ 9 files changed, 654 insertions(+) create mode 100644 src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForOrganization.ps1 create mode 100644 src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForRepository.ps1 create mode 100644 src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForOrganization.ps1 create mode 100644 src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForRepository.ps1 create mode 100644 src/functions/public/Actions/OIDC/Get-GitHubOidcClaim.ps1 create mode 100644 src/functions/public/Actions/OIDC/Get-GitHubOidcSubjectClaim.ps1 create mode 100644 src/functions/public/Actions/OIDC/Set-GitHubOidcSubjectClaim.ps1 create mode 100644 src/functions/public/Actions/OIDC/completers.ps1 create mode 100644 tests/Actions.Tests.ps1 diff --git a/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForOrganization.ps1 b/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForOrganization.ps1 new file mode 100644 index 000000000..3076a783c --- /dev/null +++ b/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForOrganization.ps1 @@ -0,0 +1,54 @@ +function Get-GitHubOidcSubjectClaimForOrganization { + <# + .SYNOPSIS + Get the customization template for an OIDC subject claim for an organization + + .DESCRIPTION + Gets the customization template for an OpenID Connect (OIDC) subject claim for an organization. + + .EXAMPLE + ```powershell + Get-GitHubOidcSubjectClaimForOrganization -Organization 'PSModule' -Context $GitHubContext + ``` + + Gets the OIDC subject claim customization template for the 'PSModule' organization. + + .NOTES + [Get the customization template for an OIDC subject claim for an organization](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#get-the-customization-template-for-an-oidc-subject-claim-for-an-organization) + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param( + # The organization name. The name is not case sensitive. + [Parameter(Mandatory)] + [string] $Organization, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter(Mandatory)] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + # Required permissions: Administration org (read) or read:org + } + + process { + $apiParams = @{ + Method = 'GET' + APIEndpoint = "/orgs/$Organization/actions/oidc/customization/sub" + Context = $Context + } + + Invoke-GitHubAPI @apiParams | ForEach-Object { + Write-Output $_.Response + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForRepository.ps1 b/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForRepository.ps1 new file mode 100644 index 000000000..223ca98b9 --- /dev/null +++ b/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForRepository.ps1 @@ -0,0 +1,58 @@ +function Get-GitHubOidcSubjectClaimForRepository { + <# + .SYNOPSIS + Get the customization template for an OIDC subject claim for a repository + + .DESCRIPTION + Gets the customization template for an OpenID Connect (OIDC) subject claim for a repository. + + .EXAMPLE + ```powershell + Get-GitHubOidcSubjectClaimForRepository -Owner 'PSModule' -Repository 'GitHub' -Context $GitHubContext + ``` + + Gets the OIDC subject claim customization template for the 'GitHub' repository. + + .NOTES + [Get the customization template for an OIDC subject claim for a repository](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#get-the-customization-template-for-an-oidc-subject-claim-for-a-repository) + #> + [OutputType([pscustomobject])] + [CmdletBinding()] + param( + # The account owner of the repository. The name is not case sensitive. + [Parameter(Mandatory)] + [string] $Owner, + + # The name of the repository without the .git extension. The name is not case sensitive. + [Parameter(Mandatory)] + [string] $Repository, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter(Mandatory)] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + # Required permissions: Actions repo (read) or repo + } + + process { + $apiParams = @{ + Method = 'GET' + APIEndpoint = "/repos/$Owner/$Repository/actions/oidc/customization/sub" + Context = $Context + } + + Invoke-GitHubAPI @apiParams | ForEach-Object { + Write-Output $_.Response + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForOrganization.ps1 b/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForOrganization.ps1 new file mode 100644 index 000000000..0fd99e7a8 --- /dev/null +++ b/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForOrganization.ps1 @@ -0,0 +1,63 @@ +function Set-GitHubOidcSubjectClaimForOrganization { + <# + .SYNOPSIS + Set the customization template for an OIDC subject claim for an organization + + .DESCRIPTION + Creates or updates the customization template for an OpenID Connect (OIDC) subject claim for an organization. + + .EXAMPLE + ```powershell + Set-GitHubOidcSubjectClaimForOrganization -Organization 'PSModule' -IncludeClaimKeys @('repo', 'context') -Context $GitHubContext + ``` + + Sets the OIDC subject claim customization template for the 'PSModule' organization. + + .NOTES + [Set the customization template for an OIDC subject claim for an organization](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#set-the-customization-template-for-an-oidc-subject-claim-for-an-organization) + #> + [OutputType([void])] + [CmdletBinding(SupportsShouldProcess)] + param( + # The organization name. The name is not case sensitive. + [Parameter(Mandatory)] + [string] $Organization, + + # Array of unique strings. Each claim key can only contain alphanumeric characters and underscores. + [Parameter(Mandatory)] + [string[]] $IncludeClaimKeys, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter(Mandatory)] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + # Required permissions: Administration org (write) or write:org + } + + process { + $body = @{ + include_claim_keys = $IncludeClaimKeys + } + + $apiParams = @{ + Method = 'PUT' + APIEndpoint = "/orgs/$Organization/actions/oidc/customization/sub" + Body = $body + Context = $Context + } + + if ($PSCmdlet.ShouldProcess("OIDC subject claim for organization [$Organization]", 'Set')) { + $null = Invoke-GitHubAPI @apiParams + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForRepository.ps1 b/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForRepository.ps1 new file mode 100644 index 000000000..8e2697ea0 --- /dev/null +++ b/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForRepository.ps1 @@ -0,0 +1,81 @@ +function Set-GitHubOidcSubjectClaimForRepository { + <# + .SYNOPSIS + Set the customization template for an OIDC subject claim for a repository + + .DESCRIPTION + Creates or updates the customization template for an OpenID Connect (OIDC) subject claim for a repository. + When UseDefault is true, the include_claim_keys are ignored by the API. + + .EXAMPLE + ```powershell + Set-GitHubOidcSubjectClaimForRepository -Owner 'PSModule' -Repository 'GitHub' -IncludeClaimKeys @('repo', 'context') -Context $GitHubContext + ``` + + Sets the OIDC subject claim customization template for the 'GitHub' repository. + + .EXAMPLE + ```powershell + Set-GitHubOidcSubjectClaimForRepository -Owner 'PSModule' -Repository 'GitHub' -UseDefault -IncludeClaimKeys @('repo') -Context $GitHubContext + ``` + + Resets the OIDC subject claim customization for the 'GitHub' repository to use the default template. + + .NOTES + [Set the customization template for an OIDC subject claim for a repository](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#set-the-customization-template-for-an-oidc-subject-claim-for-a-repository) + #> + [OutputType([void])] + [CmdletBinding(SupportsShouldProcess)] + param( + # The account owner of the repository. The name is not case sensitive. + [Parameter(Mandatory)] + [string] $Owner, + + # The name of the repository without the .git extension. The name is not case sensitive. + [Parameter(Mandatory)] + [string] $Repository, + + # Whether to use the default subject claim template. + # When true, the include_claim_keys are ignored by the API. + [Parameter(Mandatory)] + [bool] $UseDefault, + + # Array of unique strings. Each claim key can only contain alphanumeric characters and underscores. + [Parameter(Mandatory)] + [string[]] $IncludeClaimKeys, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter(Mandatory)] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + # Required permissions: Actions repo (write) or repo + } + + process { + $body = @{ + use_default = $UseDefault + include_claim_keys = $IncludeClaimKeys + } + + $apiParams = @{ + Method = 'PUT' + APIEndpoint = "/repos/$Owner/$Repository/actions/oidc/customization/sub" + Body = $body + Context = $Context + } + + if ($PSCmdlet.ShouldProcess("OIDC subject claim for repository [$Owner/$Repository]", 'Set')) { + $null = Invoke-GitHubAPI @apiParams + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/public/Actions/OIDC/Get-GitHubOidcClaim.ps1 b/src/functions/public/Actions/OIDC/Get-GitHubOidcClaim.ps1 new file mode 100644 index 000000000..38df17307 --- /dev/null +++ b/src/functions/public/Actions/OIDC/Get-GitHubOidcClaim.ps1 @@ -0,0 +1,76 @@ +function Get-GitHubOidcClaim { + <# + .SYNOPSIS + Get the supported OIDC claim keys for a GitHub instance + + .DESCRIPTION + Retrieves the list of supported OpenID Connect (OIDC) claim keys from the OIDC discovery endpoint + of a GitHub instance. This endpoint is public and requires no authentication. + + The claim keys returned can be used with Set-GitHubOidcSubjectClaim to customize the OIDC + subject claim template for organizations and repositories. + + .EXAMPLE + ```powershell + Get-GitHubOidcClaim + ``` + + Gets the supported OIDC claim keys for github.com. + + .EXAMPLE + ```powershell + Get-GitHubOidcClaim -Context $GitHubContext + ``` + + Gets the supported OIDC claim keys for the GitHub instance associated with the given context. + + .NOTES + [OpenID Connect Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) + + .LINK + https://psmodule.io/GitHub/Functions/Actions/OIDC/Get-GitHubOidcClaim + #> + [OutputType([string[]])] + [CmdletBinding()] + param( + # The context to run the command in. Used to determine the GitHub instance hostname. + # When not provided, defaults to github.com. + [Parameter()] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + } + + process { + $hostName = 'github.com' + if ($Context) { + if ($Context -is [string]) { + $resolved = Get-GitHubContext -Context $Context -ErrorAction SilentlyContinue + if ($resolved) { + $hostName = $resolved.HostName + } + } elseif ($Context.HostName) { + $hostName = $Context.HostName + } + } + + $issuerHost = if ($hostName -eq 'github.com') { + 'token.actions.githubusercontent.com' + } else { + "token.actions.$hostName" + } + + $discoveryUri = "https://$issuerHost/.well-known/openid-configuration" + Write-Debug "[$stackPath] - Discovery URI: [$discoveryUri]" + + $response = Invoke-RestMethod -Uri $discoveryUri -Method Get + $response.claims_supported + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/public/Actions/OIDC/Get-GitHubOidcSubjectClaim.ps1 b/src/functions/public/Actions/OIDC/Get-GitHubOidcSubjectClaim.ps1 new file mode 100644 index 000000000..45a0a6e5e --- /dev/null +++ b/src/functions/public/Actions/OIDC/Get-GitHubOidcSubjectClaim.ps1 @@ -0,0 +1,85 @@ +function Get-GitHubOidcSubjectClaim { + <# + .SYNOPSIS + Get the customization template for an OIDC subject claim + + .DESCRIPTION + Gets the customization template for an OpenID Connect (OIDC) subject claim for an organization + or repository. + + .EXAMPLE + ```powershell + Get-GitHubOidcSubjectClaim -Owner 'PSModule' + ``` + + Gets the OIDC subject claim customization template for the 'PSModule' organization. + + .EXAMPLE + ```powershell + Get-GitHubOidcSubjectClaim -Owner 'PSModule' -Repository 'GitHub' + ``` + + Gets the OIDC subject claim customization template for the 'GitHub' repository. + + .OUTPUTS + System.Management.Automation.PSCustomObject + + .NOTES + [Get the customization template for an OIDC subject claim for an organization](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#get-the-customization-template-for-an-oidc-subject-claim-for-an-organization) + [Get the customization template for an OIDC subject claim for a repository](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#get-the-customization-template-for-an-oidc-subject-claim-for-a-repository) + + .LINK + https://psmodule.io/GitHub/Functions/Actions/OIDC/Get-GitHubOidcSubjectClaim + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains a long link.')] + [OutputType([pscustomobject])] + [CmdletBinding(DefaultParameterSetName = 'Get the customization template for an OIDC subject claim for an organization')] + param( + # The account owner of the repository or the organization name. The name is not case sensitive. + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('Organization')] + [Alias('User')] + [string] $Owner, + + # The name of the repository without the .git extension. The name is not case sensitive. + [Parameter(Mandatory, ParameterSetName = 'Get the customization template for an OIDC subject claim for a repository', + ValueFromPipelineByPropertyName)] + [string] $Repository, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter()] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + $Context = Resolve-GitHubContext -Context $Context + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + } + + process { + $params = @{ + Context = $Context + } + + switch ($PSCmdlet.ParameterSetName) { + 'Get the customization template for an OIDC subject claim for an organization' { + $params['Organization'] = $Owner + Get-GitHubOidcSubjectClaimForOrganization @params + break + } + 'Get the customization template for an OIDC subject claim for a repository' { + $params['Owner'] = $Owner + $params['Repository'] = $Repository + Get-GitHubOidcSubjectClaimForRepository @params + break + } + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/public/Actions/OIDC/Set-GitHubOidcSubjectClaim.ps1 b/src/functions/public/Actions/OIDC/Set-GitHubOidcSubjectClaim.ps1 new file mode 100644 index 000000000..b8a2b0453 --- /dev/null +++ b/src/functions/public/Actions/OIDC/Set-GitHubOidcSubjectClaim.ps1 @@ -0,0 +1,113 @@ +function Set-GitHubOidcSubjectClaim { + <# + .SYNOPSIS + Set the customization template for an OIDC subject claim + + .DESCRIPTION + Creates or updates the customization template for an OpenID Connect (OIDC) subject claim for an + organization or repository. + + For repositories, when UseDefault is true, the IncludeClaimKeys are ignored by the API. + + .EXAMPLE + ```powershell + Set-GitHubOidcSubjectClaim -Owner 'PSModule' -IncludeClaimKeys @('repo', 'context') + ``` + + Sets the OIDC subject claim customization template for the 'PSModule' organization. + + .EXAMPLE + ```powershell + Set-GitHubOidcSubjectClaim -Owner 'PSModule' -Repository 'GitHub' -IncludeClaimKeys @('repo', 'context') + ``` + + Sets the OIDC subject claim customization template for the 'GitHub' repository with custom claim keys. + + .EXAMPLE + ```powershell + Set-GitHubOidcSubjectClaim -Owner 'PSModule' -Repository 'GitHub' -UseDefault -IncludeClaimKeys @('repo') + ``` + + Resets the OIDC subject claim customization for the 'GitHub' repository to use the default template. + + .OUTPUTS + System.Void + + .NOTES + [Set the customization template for an OIDC subject claim for an organization](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#set-the-customization-template-for-an-oidc-subject-claim-for-an-organization) + [Set the customization template for an OIDC subject claim for a repository](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#set-the-customization-template-for-an-oidc-subject-claim-for-a-repository) + + .LINK + https://psmodule.io/GitHub/Functions/Actions/OIDC/Set-GitHubOidcSubjectClaim + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains a long link.')] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSShouldProcess', '', Scope = 'Function', + Justification = 'This check is performed in the private functions.' + )] + [OutputType([void])] + [CmdletBinding( + SupportsShouldProcess, + DefaultParameterSetName = 'Set the customization template for an OIDC subject claim for an organization' + )] + param( + # The account owner of the repository or the organization name. The name is not case sensitive. + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('Organization')] + [Alias('User')] + [string] $Owner, + + # The name of the repository without the .git extension. The name is not case sensitive. + [Parameter(Mandatory, ParameterSetName = 'Set the customization template for an OIDC subject claim for a repository', + ValueFromPipelineByPropertyName)] + [string] $Repository, + + # Array of unique strings. Each claim key can only contain alphanumeric characters and underscores. + [Parameter(Mandatory)] + [string[]] $IncludeClaimKeys, + + # Whether to use the default subject claim template for the repository. + # When true, the IncludeClaimKeys are ignored by the API. + [Parameter(ParameterSetName = 'Set the customization template for an OIDC subject claim for a repository')] + [switch] $UseDefault, + + # The context to run the command in. Used to get the details for the API call. + # Can be either a string or a GitHubContext object. + [Parameter()] + [object] $Context + ) + + begin { + $stackPath = Get-PSCallStackPath + Write-Debug "[$stackPath] - Start" + $Context = Resolve-GitHubContext -Context $Context + Assert-GitHubContext -Context $Context -AuthType IAT, PAT, UAT + } + + process { + $params = @{ + Context = $Context + } + + switch ($PSCmdlet.ParameterSetName) { + 'Set the customization template for an OIDC subject claim for an organization' { + $params['Organization'] = $Owner + $params['IncludeClaimKeys'] = $IncludeClaimKeys + Set-GitHubOidcSubjectClaimForOrganization @params + break + } + 'Set the customization template for an OIDC subject claim for a repository' { + $params['Owner'] = $Owner + $params['Repository'] = $Repository + $params['IncludeClaimKeys'] = $IncludeClaimKeys + $params['UseDefault'] = $UseDefault.IsPresent + Set-GitHubOidcSubjectClaimForRepository @params + break + } + } + } + + end { + Write-Debug "[$stackPath] - End" + } +} diff --git a/src/functions/public/Actions/OIDC/completers.ps1 b/src/functions/public/Actions/OIDC/completers.ps1 new file mode 100644 index 000000000..bc7e3a503 --- /dev/null +++ b/src/functions/public/Actions/OIDC/completers.ps1 @@ -0,0 +1,18 @@ +Register-ArgumentCompleter -CommandName Set-GitHubOidcSubjectClaim -ParameterName IncludeClaimKeys -ScriptBlock { + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) + $null = $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters + $pattern = switch (Get-GitHubConfig -Name CompletionMode) { 'Contains' { "*$wordToComplete*" } default { "$wordToComplete*" } } + $params = @{ + Context = $fakeBoundParameters.Context + Verbose = $false + Debug = $false + } + $params | Remove-HashtableEntry -NullOrEmptyValues + $filteredOptions = Get-GitHubOidcClaim @params | Where-Object { $_ -like $pattern } + if (-not $filteredOptions) { + return $null + } + $filteredOptions | ForEach-Object { + [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) + } +} diff --git a/tests/Actions.Tests.ps1 b/tests/Actions.Tests.ps1 new file mode 100644 index 000000000..ee041c153 --- /dev/null +++ b/tests/Actions.Tests.ps1 @@ -0,0 +1,106 @@ +#Requires -Modules @{ ModuleName = 'Pester'; RequiredVersion = '5.7.1' } + +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSUseDeclaredVarsMoreThanAssignments', '', + Justification = 'Pester grouping syntax: known issue.' +)] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidUsingWriteHost', '', + Justification = 'Log outputs to GitHub Actions logs.' +)] +[Diagnostics.CodeAnalysis.SuppressMessageAttribute( + 'PSAvoidLongLines', '', + Justification = 'Long test descriptions and skip switches' +)] +[CmdletBinding()] +param() + +Describe 'Actions' { + $authCases = . "$PSScriptRoot/Data/AuthCases.ps1" + + Context 'OIDC' { + Context 'Get-GitHubOidcClaim' { + It 'Get-GitHubOidcClaim - No context - Returns claim keys for github.com' { + $result = Get-GitHubOidcClaim + LogGroup 'Result' { + Write-Host ($result | Out-String) + } + $result | Should -Not -BeNullOrEmpty + $result | Should -Contain 'sub' + $result | Should -Contain 'repository' + $result | Should -BeOfType [string] + } + } + } + + Context 'As using on ' -ForEach $authCases { + BeforeAll { + $context = Connect-GitHubAccount @connectParams -PassThru -Silent + LogGroup 'Context' { + Write-Host ($context | Format-List | Out-String) + } + if ($AuthType -eq 'APP') { + LogGroup 'Context - Installation' { + $context = Connect-GitHubApp @connectAppParams -PassThru -Default -Silent + Write-Host ($context | Format-List | Out-String) + } + } + $Owner = $env:GITHUB_REPOSITORY_OWNER + $Repository = $env:GITHUB_REPOSITORY_NAME + } + + AfterAll { + Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent + Write-Host ('-' * 60) + } + + Context 'OIDC' { + It 'Get-GitHubOidcClaim - With context - Returns claim keys' { + $result = Get-GitHubOidcClaim -Context $context + LogGroup 'Result' { + Write-Host ($result | Out-String) + } + $result | Should -Not -BeNullOrEmpty + $result | Should -Contain 'sub' + $result | Should -BeOfType [string] + } + + It 'Get-GitHubOidcSubjectClaim - Organization - Returns template' { + $result = Get-GitHubOidcSubjectClaim -Owner $Owner -Context $context + LogGroup 'Result' { + Write-Host ($result | Format-List | Out-String) + } + $result | Should -Not -BeNullOrEmpty + $result.include_claim_keys | Should -Not -BeNullOrEmpty + } + + It 'Get-GitHubOidcSubjectClaim - Repository - Returns template' { + $result = Get-GitHubOidcSubjectClaim -Owner $Owner -Repository $Repository -Context $context + LogGroup 'Result' { + Write-Host ($result | Format-List | Out-String) + } + $result | Should -Not -BeNullOrEmpty + } + + It 'Set-GitHubOidcSubjectClaim - Organization - Sets template' -Skip:($OwnerType -ne 'organization') { + { + Set-GitHubOidcSubjectClaim -Owner $Owner -IncludeClaimKeys @('repo', 'context') -Context $context + } | Should -Not -Throw + } + + It 'Set-GitHubOidcSubjectClaim - Repository - Sets template with custom keys' { + { + Set-GitHubOidcSubjectClaim -Owner $Owner -Repository $Repository ` + -IncludeClaimKeys @('repo', 'ref') -Context $context + } | Should -Not -Throw + } + + It 'Set-GitHubOidcSubjectClaim - Repository - Sets template with UseDefault' { + { + Set-GitHubOidcSubjectClaim -Owner $Owner -Repository $Repository ` + -IncludeClaimKeys @('repo') -UseDefault -Context $context + } | Should -Not -Throw + } + } + } +} From 7f5c8568db3f7b80067b74a78601b6eece56919c Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 26 Feb 2026 14:29:59 +0100 Subject: [PATCH 3/6] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Update=20OIDC=20s?= =?UTF-8?q?ubject=20claim=20documentation=20links=20for=20consistency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Actions/OIDC/Get-GitHubOidcSubjectClaimForOrganization.ps1 | 3 ++- .../Actions/OIDC/Get-GitHubOidcSubjectClaimForRepository.ps1 | 3 ++- .../Actions/OIDC/Set-GitHubOidcSubjectClaimForOrganization.ps1 | 3 ++- .../Actions/OIDC/Set-GitHubOidcSubjectClaimForRepository.ps1 | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForOrganization.ps1 b/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForOrganization.ps1 index 3076a783c..ba478faca 100644 --- a/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForOrganization.ps1 +++ b/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForOrganization.ps1 @@ -14,7 +14,8 @@ Gets the OIDC subject claim customization template for the 'PSModule' organization. .NOTES - [Get the customization template for an OIDC subject claim for an organization](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#get-the-customization-template-for-an-oidc-subject-claim-for-an-organization) + [Get the customization template for an OIDC subject claim for an organization] + (https://docs.github.com/rest/actions/oidc#get-the-customization-template-for-an-oidc-subject-claim-for-an-organization) #> [OutputType([pscustomobject])] [CmdletBinding()] diff --git a/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForRepository.ps1 b/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForRepository.ps1 index 223ca98b9..2bc1d3753 100644 --- a/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForRepository.ps1 +++ b/src/functions/private/Actions/OIDC/Get-GitHubOidcSubjectClaimForRepository.ps1 @@ -14,7 +14,8 @@ Gets the OIDC subject claim customization template for the 'GitHub' repository. .NOTES - [Get the customization template for an OIDC subject claim for a repository](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#get-the-customization-template-for-an-oidc-subject-claim-for-a-repository) + [Get the customization template for an OIDC subject claim for a repository] + (https://docs.github.com/rest/actions/oidc#get-the-customization-template-for-an-oidc-subject-claim-for-a-repository) #> [OutputType([pscustomobject])] [CmdletBinding()] diff --git a/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForOrganization.ps1 b/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForOrganization.ps1 index 0fd99e7a8..08bc51b84 100644 --- a/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForOrganization.ps1 +++ b/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForOrganization.ps1 @@ -14,7 +14,8 @@ Sets the OIDC subject claim customization template for the 'PSModule' organization. .NOTES - [Set the customization template for an OIDC subject claim for an organization](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#set-the-customization-template-for-an-oidc-subject-claim-for-an-organization) + [Set the customization template for an OIDC subject claim for an organization] + (https://docs.github.com/rest/actions/oidc#set-the-customization-template-for-an-oidc-subject-claim-for-an-organization) #> [OutputType([void])] [CmdletBinding(SupportsShouldProcess)] diff --git a/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForRepository.ps1 b/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForRepository.ps1 index 8e2697ea0..70a1ff781 100644 --- a/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForRepository.ps1 +++ b/src/functions/private/Actions/OIDC/Set-GitHubOidcSubjectClaimForRepository.ps1 @@ -22,7 +22,8 @@ Resets the OIDC subject claim customization for the 'GitHub' repository to use the default template. .NOTES - [Set the customization template for an OIDC subject claim for a repository](https://docs.github.com/en/rest/actions/oidc?apiVersion=2022-11-28#set-the-customization-template-for-an-oidc-subject-claim-for-a-repository) + [Set the customization template for an OIDC subject claim for a repository] + (https://docs.github.com/rest/actions/oidc#set-the-customization-template-for-an-oidc-subject-claim-for-a-repository) #> [OutputType([void])] [CmdletBinding(SupportsShouldProcess)] From 78af5303c87d0c6f1c51143492c96b64d94d877f Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 26 Feb 2026 15:43:58 +0100 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Refactor=20OIDC?= =?UTF-8?q?=20tests=20to=20improve=20context=20handling=20and=20repository?= =?UTF-8?q?=20management?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/Actions.Tests.ps1 | 58 ++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/tests/Actions.Tests.ps1 b/tests/Actions.Tests.ps1 index ee041c153..e1fe8e6a0 100644 --- a/tests/Actions.Tests.ps1 +++ b/tests/Actions.Tests.ps1 @@ -15,11 +15,17 @@ [CmdletBinding()] param() +BeforeAll { + $testName = 'ActionsTests' + $os = $env:RUNNER_OS + $guid = [guid]::NewGuid().ToString() +} + Describe 'Actions' { $authCases = . "$PSScriptRoot/Data/AuthCases.ps1" - Context 'OIDC' { - Context 'Get-GitHubOidcClaim' { + Get-Context 'OIDC' { + Get-Context 'Get-GitHubOidcClaim' { It 'Get-GitHubOidcClaim - No context - Returns claim keys for github.com' { $result = Get-GitHubOidcClaim LogGroup 'Result' { @@ -33,7 +39,7 @@ Describe 'Actions' { } } - Context 'As using on ' -ForEach $authCases { + Get-Context 'As using on ' -ForEach $authCases { BeforeAll { $context = Connect-GitHubAccount @connectParams -PassThru -Silent LogGroup 'Context' { @@ -45,16 +51,42 @@ Describe 'Actions' { Write-Host ($context | Format-List | Out-String) } } - $Owner = $env:GITHUB_REPOSITORY_OWNER - $Repository = $env:GITHUB_REPOSITORY_NAME + $repoPrefix = "$testName-$os-$TokenType" + $repoName = "$repoPrefix-$guid" + + switch ($OwnerType) { + 'user' { + Get-GitHubRepository | Where-Object { $_.Name -like "$repoPrefix*" } | + Remove-GitHubRepository -Confirm:$false + $repo = New-GitHubRepository -Name $repoName -Confirm:$false + } + 'organization' { + Get-GitHubRepository -Organization $Owner | Where-Object { $_.Name -like "$repoPrefix*" } | + Remove-GitHubRepository -Confirm:$false + $repo = New-GitHubRepository -Organization $Owner -Name $repoName -Confirm:$false + } + } + LogGroup "Repository - [$repoName]" { + Write-Host ($repo | Select-Object * | Out-String) + } } AfterAll { + switch ($OwnerType) { + 'user' { + Get-GitHubRepository | Where-Object { $_.Name -like "$repoPrefix*" } | + Remove-GitHubRepository -Confirm:$false + } + 'organization' { + Get-GitHubRepository -Organization $Owner | Where-Object { $_.Name -like "$repoPrefix*" } | + Remove-GitHubRepository -Confirm:$false + } + } Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent Write-Host ('-' * 60) } - Context 'OIDC' { + Get-Context 'OIDC' { It 'Get-GitHubOidcClaim - With context - Returns claim keys' { $result = Get-GitHubOidcClaim -Context $context LogGroup 'Result' { @@ -65,7 +97,7 @@ Describe 'Actions' { $result | Should -BeOfType [string] } - It 'Get-GitHubOidcSubjectClaim - Organization - Returns template' { + It 'Get-GitHubOidcSubjectClaim - Organization - Returns template' -Skip:($OwnerType -ne 'organization') { $result = Get-GitHubOidcSubjectClaim -Owner $Owner -Context $context LogGroup 'Result' { Write-Host ($result | Format-List | Out-String) @@ -74,8 +106,8 @@ Describe 'Actions' { $result.include_claim_keys | Should -Not -BeNullOrEmpty } - It 'Get-GitHubOidcSubjectClaim - Repository - Returns template' { - $result = Get-GitHubOidcSubjectClaim -Owner $Owner -Repository $Repository -Context $context + It 'Get-GitHubOidcSubjectClaim - Repository - Returns template' -Skip:($OwnerType -in ('repository', 'enterprise')) { + $result = Get-GitHubOidcSubjectClaim -Owner $Owner -Repository $repoName -Context $context LogGroup 'Result' { Write-Host ($result | Format-List | Out-String) } @@ -88,16 +120,16 @@ Describe 'Actions' { } | Should -Not -Throw } - It 'Set-GitHubOidcSubjectClaim - Repository - Sets template with custom keys' { + It 'Set-GitHubOidcSubjectClaim - Repository - Sets template with custom keys' -Skip:($OwnerType -in ('repository', 'enterprise')) { { - Set-GitHubOidcSubjectClaim -Owner $Owner -Repository $Repository ` + Set-GitHubOidcSubjectClaim -Owner $Owner -Repository $repoName ` -IncludeClaimKeys @('repo', 'ref') -Context $context } | Should -Not -Throw } - It 'Set-GitHubOidcSubjectClaim - Repository - Sets template with UseDefault' { + It 'Set-GitHubOidcSubjectClaim - Repository - Sets template with UseDefault' -Skip:($OwnerType -in ('repository', 'enterprise')) { { - Set-GitHubOidcSubjectClaim -Owner $Owner -Repository $Repository ` + Set-GitHubOidcSubjectClaim -Owner $Owner -Repository $repoName ` -IncludeClaimKeys @('repo') -UseDefault -Context $context } | Should -Not -Throw } From 8bd1d8e3dcbdb453cb2375749914d817deb3ae01 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 26 Feb 2026 23:10:18 +0100 Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=A9=B9=20[Patch]:=20Add=20new=20fine-?= =?UTF-8?q?grained=20permissions=20for=20artifact=20metadata,=20custom=20p?= =?UTF-8?q?roperties,=20and=20enterprise=20controls?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/public/GitHubPermission.ps1 | 155 ++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/src/classes/public/GitHubPermission.ps1 b/src/classes/public/GitHubPermission.ps1 index c3f07529d..c1c8628cc 100644 --- a/src/classes/public/GitHubPermission.ps1 +++ b/src/classes/public/GitHubPermission.ps1 @@ -487,6 +487,19 @@ 'Fine-grained', 'Repository' ), + [GitHubPermission]::new( + 'artifact_metadata', + 'Artifact metadata', + 'Manage artifact attestation metadata for a repository.', + 'https://docs.github.com/rest/overview/permissions-required-for-github-apps' + + '#repository-permissions-for-artifact-metadata', + @( + 'read', + 'write' + ), + 'Fine-grained', + 'Repository' + ), # ------------------------------ # Organization Fine-Grained Permission Definitions @@ -569,6 +582,19 @@ 'Fine-grained', 'Organization' ), + [GitHubPermission]::new( + 'custom_properties_for_organizations', + 'Custom properties for organizations', + 'Read and write custom properties for organizations.', + 'https://docs.github.com/rest/overview/permissions-required-for-github-apps' + + '#organization-permissions-for-custom-properties-for-organizations', + @( + 'read', + 'write' + ), + 'Fine-grained', + 'Organization' + ), [GitHubPermission]::new( 'organization_custom_roles', 'Custom repository roles', @@ -607,6 +633,31 @@ 'Fine-grained', 'Organization' ), + [GitHubPermission]::new( + 'organization_copilot_metrics', + 'Copilot metrics', + 'View Copilot usage metrics for an organization.', + 'https://docs.github.com/rest/overview/permissions-required-for-github-apps' + + '#organization-permissions-for-copilot-metrics', + @( + 'read' + ), + 'Fine-grained', + 'Organization' + ), + [GitHubPermission]::new( + 'organization_credentials', + 'Organization credentials', + 'Manage credentials for an organization.', + 'https://docs.github.com/rest/overview/permissions-required-for-github-apps' + + '#organization-permissions-for-organization-credentials', + @( + 'read', + 'write' + ), + 'Fine-grained', + 'Organization' + ), [GitHubPermission]::new( 'issue_fields', 'Issue Fields', @@ -762,6 +813,19 @@ 'Fine-grained', 'Organization' ), + [GitHubPermission]::new( + 'organization_dependabot_dismissal_requests', + 'Organization Dependabot dismissal requests', + 'Review and manage Dependabot alert dismissal requests for an organization.', + 'https://docs.github.com/rest/overview/permissions-required-for-github-apps' + + '#organization-permissions-for-organization-dependabot-dismissal-requests', + @( + 'read', + 'write' + ), + 'Fine-grained', + 'Organization' + ), [GitHubPermission]::new( 'organization_code_scanning_dismissal_requests', 'Organization dismissal requests for code scanning', @@ -879,6 +943,19 @@ 'Fine-grained', 'Organization' ), + [GitHubPermission]::new( + 'organization_runner_custom_images', + 'Runner custom images', + 'View and manage custom images for self-hosted runners available to an organization.', + 'https://docs.github.com/rest/overview/permissions-required-for-github-apps' + + '#organization-permissions-for-runner-custom-images', + @( + 'read', + 'write' + ), + 'Fine-grained', + 'Organization' + ), [GitHubPermission]::new( 'team_discussions', 'Team discussions', @@ -1259,6 +1336,84 @@ ), 'Fine-grained', 'Enterprise' + ), + [GitHubPermission]::new( + 'enterprise_ai_controls', + 'Enterprise AI controls', + 'Manage AI controls at the enterprise level.', + 'https://docs.github.com/enterprise-cloud@latest/rest/overview/permissions-required-for-github-apps' + + '#enterprise-permissions-for-enterprise-ai-controls', + @( + 'read', + 'write' + ), + 'Fine-grained', + 'Enterprise' + ), + [GitHubPermission]::new( + 'enterprise_copilot_metrics', + 'Enterprise Copilot metrics', + 'View Copilot usage metrics at the enterprise level.', + 'https://docs.github.com/enterprise-cloud@latest/rest/overview/permissions-required-for-github-apps' + + '#enterprise-permissions-for-enterprise-copilot-metrics', + @( + 'read' + ), + 'Fine-grained', + 'Enterprise' + ), + [GitHubPermission]::new( + 'enterprise_credentials', + 'Enterprise credentials', + 'Manage credentials at the enterprise level.', + 'https://docs.github.com/enterprise-cloud@latest/rest/overview/permissions-required-for-github-apps' + + '#enterprise-permissions-for-enterprise-credentials', + @( + 'read', + 'write' + ), + 'Fine-grained', + 'Enterprise' + ), + [GitHubPermission]::new( + 'enterprise_custom_enterprise_roles', + 'Custom enterprise roles', + 'Create, edit, delete and list custom enterprise roles.', + 'https://docs.github.com/enterprise-cloud@latest/rest/overview/permissions-required-for-github-apps' + + '#enterprise-permissions-for-custom-enterprise-roles', + @( + 'read', + 'write' + ), + 'Fine-grained', + 'Enterprise' + ), + [GitHubPermission]::new( + 'enterprise_custom_properties_for_organizations', + 'Custom properties for organizations', + 'View repository custom properties and administer definitions for enterprise organizations.', + 'https://docs.github.com/enterprise-cloud@latest/rest/overview/permissions-required-for-github-apps' + + '#enterprise-permissions-for-custom-properties-for-organizations', + @( + 'read', + 'write', + 'admin' + ), + 'Fine-grained', + 'Enterprise' + ), + [GitHubPermission]::new( + 'enterprise_teams', + 'Enterprise teams', + 'Manage teams at the enterprise level.', + 'https://docs.github.com/enterprise-cloud@latest/rest/overview/permissions-required-for-github-apps' + + '#enterprise-permissions-for-enterprise-teams', + @( + 'read', + 'write' + ), + 'Fine-grained', + 'Enterprise' ) ) } From d159e59e6276cb5a309221a4147aca516c8f3914 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Thu, 26 Feb 2026 23:35:33 +0100 Subject: [PATCH 6/6] Refactor OIDC test context usage for improved readability and consistency --- tests/Actions.Tests.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Actions.Tests.ps1 b/tests/Actions.Tests.ps1 index e1fe8e6a0..299e14f0c 100644 --- a/tests/Actions.Tests.ps1 +++ b/tests/Actions.Tests.ps1 @@ -24,8 +24,8 @@ BeforeAll { Describe 'Actions' { $authCases = . "$PSScriptRoot/Data/AuthCases.ps1" - Get-Context 'OIDC' { - Get-Context 'Get-GitHubOidcClaim' { + Context 'OIDC' { + Context 'Get-GitHubOidcClaim' { It 'Get-GitHubOidcClaim - No context - Returns claim keys for github.com' { $result = Get-GitHubOidcClaim LogGroup 'Result' { @@ -39,7 +39,7 @@ Describe 'Actions' { } } - Get-Context 'As using on ' -ForEach $authCases { + Context 'As using on ' -ForEach $authCases { BeforeAll { $context = Connect-GitHubAccount @connectParams -PassThru -Silent LogGroup 'Context' { @@ -86,7 +86,7 @@ Describe 'Actions' { Write-Host ('-' * 60) } - Get-Context 'OIDC' { + Context 'OIDC' { It 'Get-GitHubOidcClaim - With context - Returns claim keys' { $result = Get-GitHubOidcClaim -Context $context LogGroup 'Result' {