Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7a5c139
Initial plan
Copilot Dec 29, 2025
85fd3af
Modify types and format to display Unknown for PAT tokens
Copilot Dec 29, 2025
55834ee
Add tests for TokenExpiresIn behavior for PAT and IAT tokens
Copilot Dec 29, 2025
41e27c8
Fix test to handle GITHUB_TOKEN without expiration
Copilot Dec 30, 2025
5aabf79
Add comprehensive test coverage for all token types
Copilot Dec 30, 2025
ece5961
Clarify comment about GITHUB_TOKEN being IAT in GitHub Actions
Copilot Dec 30, 2025
219edec
Remove unnecessary comments from tests
Copilot Dec 30, 2025
e22f84a
Fix test by resetting to App context before Connect-GitHubApp call
Copilot Jan 1, 2026
075b804
Remove unused variable from test
Copilot Jan 1, 2026
8d14441
Remove comment from test
Copilot Jan 1, 2026
80b3847
Simplify context reset by removing unnecessary PassThru
Copilot Jan 1, 2026
f9fcda4
Remove redundant Connect-GitHubAccount calls and use Get-GitHubContext
Copilot Jan 1, 2026
acb07c8
Fix test by passing App context explicitly to Connect-GitHubApp
Copilot Jan 2, 2026
860d4f5
Refactor Connect-GitHubAccount and Connect-GitHubApp tests to validat…
MariusStorhaug Jan 3, 2026
b76a5f1
Enhance tests for TokenExpiresAt and TokenExpiresIn properties in Con…
MariusStorhaug Jan 3, 2026
bddf285
Add BeforeAll block to initialize GitHub account context in Auth tests
MariusStorhaug Jan 4, 2026
6a58e0e
Remove redundant context assignment in Connect-GitHubAccount test
MariusStorhaug Jan 4, 2026
afd3bb3
Refactor TokenExpiresIn handling to return 'Unknown' when TokenExpire…
MariusStorhaug Jan 4, 2026
26b9724
Refactor GitHubContext types to include TokenExpiresIn and RefreshTok…
MariusStorhaug Jan 4, 2026
d3fceef
Update TokenExpiresAt comparison to use DateTime.Now for accurate tim…
MariusStorhaug Jan 5, 2026
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
66 changes: 41 additions & 25 deletions src/formats/GitHubContext.Format.ps1xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,39 +49,55 @@
<TableColumnItem>
<PropertyName>TokenType</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>TokenExpiresAt</PropertyName>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>
if ($null -eq $_.TokenExpiresIn) {
return
if ($null -ne $_.TokenExpiresAt) {
return $_.TokenExpiresAt
}

if ($_.TokenExpiresIn -le 0) {
$text = 'Expired'
} else {
$text = $_.TokenExpiresIn.ToString('hh\:mm\:ss')
$text = 'N/A'
if ($Host.UI.SupportsVirtualTerminal -and ($env:GITHUB_ACTIONS -ne 'true')) {
$gray = "`e[90m"
$reset = "`e[0m"
return "$gray$text$reset"
}
return $text
</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>
if ($null -ne $_.TokenExpiresIn) {
if ($_.TokenExpiresIn -le 0) {
$text = 'Expired'
} else {
$text = $_.TokenExpiresIn.ToString('hh\:mm\:ss')
}

if ($Host.UI.SupportsVirtualTerminal -and
($env:GITHUB_ACTIONS -ne 'true')) {
switch ($_.AuthType) {
'UAT' {
$maxValue = [TimeSpan]::FromHours(8)
}
'IAT' {
$maxValue = [TimeSpan]::FromHours(1)
}
'APP' {
$maxValue = [TimeSpan]::FromMinutes(10)
if ($Host.UI.SupportsVirtualTerminal -and ($env:GITHUB_ACTIONS -ne 'true')) {
switch ($_.AuthType) {
'UAT' {
$maxValue = [TimeSpan]::FromHours(8)
}
'IAT' {
$maxValue = [TimeSpan]::FromHours(1)
}
'APP' {
$maxValue = [TimeSpan]::FromMinutes(10)
}
}
$ratio = [Math]::Min(($_.TokenExpiresIn / $maxValue), 1)
return [GitHubFormatter]::FormatColorByRatio($ratio, $text)
}
return $text
}

$text = 'N/A'
if ($Host.UI.SupportsVirtualTerminal -and ($env:GITHUB_ACTIONS -ne 'true')) {
$gray = "`e[90m"
$reset = "`e[0m"
return "$gray$text$reset"
}
$ratio = [Math]::Min(($_.TokenExpiresIn / $maxValue), 1)
[GitHubFormatter]::FormatColorByRatio($ratio, $text)
} else {
$text
}
return $text
</ScriptBlock>
</TableColumnItem>
</TableColumnItems>
Expand Down
20 changes: 12 additions & 8 deletions src/types/GitHubContext.Types.ps1xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@
<ScriptProperty>
<Name>TokenExpiresIn</Name>
<GetScriptBlock>
if ($null -eq $this.TokenExpiresAt) { return [TimeSpan]::Zero }
$this.TokenExpiresAt - [DateTime]::Now
if ($null -ne $this.TokenExpiresAt) {
return $this.TokenExpiresAt - [DateTime]::Now
}
</GetScriptBlock>
</ScriptProperty>
<ScriptProperty>
<Name>RefreshTokenExpiresIn</Name>
<GetScriptBlock>
if ($null -eq $this.RefreshTokenExpiresAt) { return [TimeSpan]::Zero }
$this.RefreshTokenExpiresAt - [DateTime]::Now
if ($null -ne $this.RefreshTokenExpiresAt) {
return $this.RefreshTokenExpiresAt - [DateTime]::Now
}
</GetScriptBlock>
</ScriptProperty>
</Members>
Expand All @@ -25,8 +27,9 @@
<ScriptProperty>
<Name>TokenExpiresIn</Name>
<GetScriptBlock>
if ($null -eq $this.TokenExpiresAt) { return [TimeSpan]::Zero }
$this.TokenExpiresAt - [DateTime]::Now
if ($null -ne $this.TokenExpiresAt) {
return $this.TokenExpiresAt - [DateTime]::Now
}
</GetScriptBlock>
</ScriptProperty>
</Members>
Expand All @@ -37,8 +40,9 @@
<ScriptProperty>
<Name>TokenExpiresIn</Name>
<GetScriptBlock>
if ($null -eq $this.TokenExpiresAt) { return [TimeSpan]::Zero }
$this.TokenExpiresAt - [DateTime]::Now
if ($null -ne $this.TokenExpiresAt) {
return $this.TokenExpiresAt - [DateTime]::Now
}
</GetScriptBlock>
</ScriptProperty>
</Members>
Expand Down
7 changes: 5 additions & 2 deletions tests/Apps.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ Describe 'Apps' {
LogGroup 'Config' {
Write-Host "$($config | Format-List | Out-String)"
}
LogGroup "Installation" {
LogGroup 'Installation' {
Write-Host "$($installation | Format-List | Out-String)"
}
LogGroup 'Permissions' {
Expand Down Expand Up @@ -274,8 +274,11 @@ Describe 'Apps' {
$installationContext.Events | Should -BeOfType 'string'
}

It 'Connect-GitHubApp - TokenExpiresIn property should be calculated correctly' {
It 'Connect-GitHubApp - TokenExpiresAt and TokenExpiresIn properties should be calculated correctly' {
$installationContext.TokenExpiresAt | Should -BeOfType [DateTime]
$installationContext.TokenExpiresAt | Should -BeGreaterThan ([DateTime]::Now)
$installationContext.TokenExpiresIn | Should -BeOfType [TimeSpan]
$installationContext.TokenExpiresIn.TotalSeconds | Should -BeGreaterThan 0
$installationContext.TokenExpiresIn.TotalMinutes | Should -BeGreaterThan 0
$installationContext.TokenExpiresIn.TotalMinutes | Should -BeLessOrEqual 60
}
Expand Down
36 changes: 28 additions & 8 deletions tests/GitHub.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,19 @@ Describe 'Auth' {
$authCases = . "$PSScriptRoot/Data/AuthCases.ps1"

Context 'As <Type> using <Case> on <Target>' -ForEach $authCases {
BeforeAll {
$context = Connect-GitHubAccount @connectParams -PassThru -Silent
LogGroup 'Context' {
Write-Host ($context | Format-List | Out-String)
}
}

AfterAll {
Get-GitHubContext -ListAvailable | Disconnect-GitHubAccount -Silent
Write-Host ('-' * 60)
}

It 'Connect-GitHubAccount - Connects using the provided credentials' {
$context = Connect-GitHubAccount @connectParams -PassThru -Silent
LogGroup 'Context - Standard' {
Write-Host ($context | Out-String)
}
Expand All @@ -45,6 +51,22 @@ Describe 'Auth' {
$context | Should -Not -BeNullOrEmpty
}

It 'Connect-GitHubAccount - TokenExpiresAt and TokenExpiresIn validation' {
if ($AuthType -eq 'APP') {
$context.TokenExpiresAt | Should -Not -BeNullOrEmpty
$context.TokenExpiresAt | Should -BeOfType [DateTime]
$context.TokenExpiresAt | Should -BeGreaterThan ([DateTime]::Now)

$context.TokenExpiresIn | Should -Not -BeNullOrEmpty
$context.TokenExpiresIn | Should -BeOfType [TimeSpan]
$context.TokenExpiresIn.TotalMinutes | Should -BeGreaterThan 0
$context.TokenExpiresIn.TotalMinutes | Should -BeLessOrEqual 10
} else {
$context.TokenExpiresAt | Should -BeNullOrEmpty
$context.TokenExpiresIn | Should -BeNullOrEmpty
}
}

It 'Connect-GitHubAccount - Connects using the provided credentials - Double' {
$context = Connect-GitHubAccount @connectParams -PassThru -Silent
$context = Connect-GitHubAccount @connectParams -PassThru -Silent
Expand Down Expand Up @@ -80,8 +102,6 @@ Describe 'Auth' {
}
$context | Should -Not -BeNullOrEmpty
$context | Should -BeOfType [GitHubContext]
$context.TokenExpiresAt | Should -BeOfType [DateTime]
$context.TokenExpiresIn | Should -BeOfType [TimeSpan]
}

It 'Connect-GitHubApp - Connects as a GitHub App to <Owner>' -Skip:($AuthType -ne 'APP') {
Expand Down Expand Up @@ -109,18 +129,18 @@ Describe 'Auth' {
LogGroup 'Connect-GithubApp' {
$context
}
$context.TokenExpiresAt | Should -BeOfType [DateTime]
$context.TokenExpiresIn | Should -BeOfType [TimeSpan]
LogGroup 'Context' {
Write-Host ($context | Format-List | Out-String)
}
$context | Should -Not -BeNullOrEmpty
}

# Tests for runners goes here
if ($Type -eq 'GitHub Actions') {}
It 'Connect-GitHubApp - Installation tokens (IAT) should have correct auth type' -Skip:($AuthType -ne 'APP') {
$appContextToUse = Get-GitHubContext -ListAvailable | Where-Object { $_.AuthType -eq 'App' } | Select-Object -First 1
$appContext = Connect-GitHubApp @connectAppParams -PassThru -Silent -Context $appContextToUse
$appContext.AuthType | Should -Be 'IAT'
}

# Tests for IAT UAT and PAT goes here
It 'Connect-GitHubAccount - Connects to GitHub CLI on runners' {
[string]::IsNullOrEmpty($(gh auth token)) | Should -Be $false
}
Expand Down
Loading