Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 29, 2025

This release improves how token expiration information is handled and displayed in the GitHub context. The changes ensure more accurate and user-friendly reporting of token expiration properties, enhance formatting in table views, and add comprehensive tests to validate these behaviors.

Token Expiration Calculation & Representation:

  • Updated the TokenExpiresIn and RefreshTokenExpiresIn script properties in GitHubContext.Types.ps1xml to only return a value when TokenExpiresAt or RefreshTokenExpiresAt is present, otherwise return nothing. This avoids returning a zero timespan when the expiration is not set.

Table Formatting & Display:

  • Improved the table formatting in GitHubContext.Format.ps1xml to:
    • Display TokenExpiresAt as 'N/A' (in gray if supported) when not present, instead of omitting the column.
    • Show TokenExpiresIn as 'N/A' (with similar formatting) when not available, and color the value based on time remaining when present.

Testing Enhancements:

  • Added and updated tests in GitHub.Tests.ps1 and Apps.Tests.ps1 to:
    • Validate both TokenExpiresAt and TokenExpiresIn properties for correctness, type, and logical values across different authentication types.
    • Check that installation tokens have the correct AuthType and that expiration properties behave as expected for both App and non-App contexts.

These changes make token expiration handling more robust, user-friendly, and well-tested throughout the module.

Test Coverage Summary:

Token Type AuthType Has Expiration? Test Coverage
Classic PAT (ghp) PAT No
Fine-grained PAT (github_pat) PAT No
GITHUB_TOKEN (in GitHub Actions) IAT No
GitHub App JWT APP Yes
GitHub App Installation IAT Yes

Token Expiration Behavior:

  • PAT tokens (both classic ghp and fine-grained github_pat): No expiration metadata → displays "Unknown"
  • GITHUB_TOKEN (IAT in GitHub Actions): No expiration metadata → displays "Unknown"
  • GitHub App Installation tokens (IAT from Connect-GitHubApp): Has expiration metadata → displays time remaining or "Expired"
  • UAT tokens (device flow): Has expiration metadata → displays time remaining or "Expired"
  • APP tokens (JWT): Has expiration metadata → displays time remaining or "Expired"

Example Output:

Before:

  * Name                     AuthType TokenType TokenExpiresAt TokenExpiresIn
  - ----                     -------- --------- -------------- --------------
  > github.com/psmodule-user PAT      ghp                      Expired

After:

  * Name                     AuthType TokenType TokenExpiresAt TokenExpiresIn
  - ----                     -------- --------- -------------- --------------
  > github.com/psmodule-user PAT      ghp       N/A            N/A

Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix token expiration handling for PAT tokens Display "Unknown" for PAT token expiration instead of "Expired" Dec 29, 2025
Copilot AI requested a review from MariusStorhaug December 29, 2025 18:04
@MariusStorhaug
Copy link
Member

@copilot Lets also make sure the same applies for Fine Grained PAT tokens.

Copy link
Contributor Author

Copilot AI commented Dec 29, 2025

@copilot Lets also make sure the same applies for Fine Grained PAT tokens.

Fine Grained PAT tokens are already covered by these changes. Both classic PATs (ghp prefix) and Fine Grained PATs (github_pat prefix) use AuthType = 'PAT' and don't set TokenExpiresAt, so they both display "Unknown" for TokenExpiresIn.

Verified with test showing both token types correctly display "Unknown":

* Name                 AuthType TokenType  TokenExpiresAt TokenExpiresIn
- ----                 -------- ---------  -------------- --------------
  github.com/test-user PAT      ghp                       Unknown
  github.com/test-user PAT      github_pat                Unknown

@MariusStorhaug
Copy link
Member

@copilot Lets update the tests to also do this for the applicable logon types.

Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Dec 29, 2025

@copilot Lets update the tests to also do this for the applicable logon types.

Added tests for TokenExpiresIn behavior for applicable logon types in commit 55834ee:

  • PAT tokens (both classic and fine-grained): Validates that TokenExpiresAt and TokenExpiresIn are null
  • IAT tokens (GitHub Actions): Validates that TokenExpiresAt is DateTime and TokenExpiresIn is TimeSpan
  • APP tokens: Already had existing test coverage validating DateTime and TimeSpan

Tests use Pester's -Skip parameter to run only for the applicable auth type in each test case.

@MariusStorhaug
Copy link
Member

@copilot think we need to update the GitHub.Tests.ps1 file to support that the GITHUB_TOKEN is allowed to have the Unknown value. From logs:

Context As GitHub Actions using GITHUB_TOKEN on this repository (GitHub)

...
Context - Full
  
  TokenExpiresIn   : 
  ClientID         : 
  InstallationID   : 
  Permissions      : {organization_administration, organization_api_insights, organization_user_blocking, organization_campaigns…}
  Events           : {}
  InstallationType : Organization
  InstallationName : PSModule
  ID               : github.com/github-actions/Organization/PSModule
  Name             : github.com/github-actions/Organization/PSModule
  DisplayName      : GitHub Actions
  Type             : Installation
  HostName         : github.com
  ApiBaseUri       : https://api.github.com/
  ApiVersion       : 2022-11-28
  AuthType         : IAT
  NodeID           : MDM6Qm90NDE4OTgyODI=
  DatabaseID       : 41898282
  UserName         : github-actions
  Token            : System.Security.SecureString
  TokenType        : ghs
  TokenExpiresAt   : 
  Enterprise       : msx
  Owner            : PSModule
  Repository       : GitHub
  HttpVersion      : 2.0
  PerPage          : 100
  
  
   [+] Connect-GitHubAccount - Connects using the provided credentials 14.61s (14.61s|1ms)
   [!] Connect-GitHubAccount - TokenExpiresIn should be null for PAT tokens 0ms (0ms|0ms)
Error: [-] Connect-GitHubAccount - TokenExpiresIn should be set for IAT tokens 14.31s (14.31s|1ms)
Message
  Expected the value to have type [datetime] or any of its subtypes, but got $null with type $null.
  at $context.TokenExpiresAt | Should -BeOfType [DateTime], /home/runner/work/GitHub/GitHub/tests/GitHub.Tests.ps1:56
  at <ScriptBlock>, /home/runner/work/GitHub/GitHub/tests/GitHub.Tests.ps1:56
  ``

Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Dec 30, 2025

@copilot think we need to update the GitHub.Tests.ps1 file to support that the GITHUB_TOKEN is allowed to have the Unknown value. From logs:

...

Fixed in commit 41e27c8. The test was incorrectly assuming all IAT tokens have expiration dates. GITHUB_TOKEN (IAT used in GitHub Actions) doesn't have expiration metadata, so it now correctly validates that TokenExpiresAt and TokenExpiresIn are null (displaying "Unknown").

The test now uses -Skip:($TokenType -ne 'GITHUB_TOKEN') instead of -Skip:($AuthType -ne 'IAT') to specifically target GITHUB_TOKEN behavior.

Note: GitHub App Installation tokens (also IAT but created via Connect-GitHubApp) do have expiration metadata and are covered by existing APP token tests.

@MariusStorhaug
Copy link
Member

@copilot Lets ensure we have tests that check the TokenExpiresIn and TokenExpiresAt for all token types. We do not expect GITHUB_TOKEN or PAT/Finegrained PAT to have this, however we expect IATs (except GITHUB_TOKEN) to have it.

Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Dec 30, 2025

@copilot Lets ensure we have tests that check the TokenExpiresIn and TokenExpiresAt for all token types. We do not expect GITHUB_TOKEN or PAT/Finegrained PAT to have this, however we expect IATs (exce...

Added comprehensive test coverage for all token types in commit 5aabf79:

Tokens WITHOUT expiration (null values):

  • PAT tokens (classic and fine-grained): Test at lines 54-58
  • GITHUB_TOKEN (IAT): Test at lines 60-64

Tokens WITH expiration (DateTime/TimeSpan):

  • GitHub App JWT tokens (APP): Test at lines 101-102
  • GitHub App Installation tokens (IAT): Tests at lines 125-131 and explicit validation at lines 138-145

Also added documentation comment (lines 48-52) explaining the expected behavior for each token type.

Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com>
@MariusStorhaug
Copy link
Member

@copilot I am now getting the following failures:

Error: [-] Connect-GitHubApp - Installation tokens (IAT) should have expiration set 16.17s (16.17s|1ms)
Message
  Exception: The context 'github.com/psmodule-org-app/Organization/psmodule-test-org' is of type [IAT] which does not match the requiredtypes [App] for [Connect-GitHubApp].
  at Assert-GitHubContext<Process>, C:\Users\runneradmin\Documents\PowerShell\Modules\GitHub\999.0.0\GitHub.psm1:6206
  at Connect-GitHubApp<Begin>, C:\Users\runneradmin\Documents\PowerShell\Modules\GitHub\999.0.0\GitHub.psm1:19631
  at <ScriptBlock>, D:\a\GitHub\GitHub\tests\GitHub.Tests.ps1:133

The failures come on the following contexts:

Context As a GitHub App from an Organization using JWT + IAT on organization account
Context As a GitHub App from an Enterprise using JWT + IAT on organization account
Context As a GitHub App from an Enterprise using JWT + IAT on enterprise account

Thinking we should rethink this test abit.

Lets make a single generic test, with no "skips" but have the test internally contain the logic that checks the correct status. This way we contain the behavior in a single location and makes it easier to find what we expect for outcome.

Co-authored-by: MariusStorhaug <17722253+MariusStorhaug@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 2, 2026

@copilot I am now getting the following failures:

...

Fixed in commit acb07c8. The issue occurred because the test at line 120 sets the default context to IAT using -Default, so when line 133 tries to call Connect-GitHubApp, the default context is IAT instead of App. The fix retrieves the App context explicitly using Get-GitHubContext -ListAvailable | Where-Object { $_.AuthType -eq 'App' } and passes it to Connect-GitHubApp via the -Context parameter.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 4, 2026

Module GitHub - 0.40.5-copilotsettokenexpiresintounknown001 published to the PowerShell Gallery.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 4, 2026

GitHub release for GitHub v0.40.5-copilotsettokenexpiresintounknown001 has been created.

…sAt is null and improve formatting for terminal support
…enExpiresIn properties with proper handling for null TokenExpiresAt values
@github-actions
Copy link
Contributor

github-actions bot commented Jan 5, 2026

Module GitHub - 0.40.5-copilotsettokenexpiresintounknown002 published to the PowerShell Gallery.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 5, 2026

GitHub release for GitHub v0.40.5-copilotsettokenexpiresintounknown002 has been created.

@MariusStorhaug MariusStorhaug changed the title Display "Unknown" for tokens without expiration metadata Display "N/A" for tokens without expiration metadata Jan 5, 2026
@MariusStorhaug MariusStorhaug marked this pull request as ready for review January 5, 2026 08:41
@MariusStorhaug MariusStorhaug requested a review from a team as a code owner January 5, 2026 08:41
Copilot AI review requested due to automatic review settings January 5, 2026 08:41
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves token expiration handling for GitHub contexts by displaying "N/A" for tokens without expiration metadata instead of showing "Expired" or zero values. The changes update script properties to return null instead of zero timespans, enhance table formatting with conditional "N/A" display, and add comprehensive validation tests for different authentication types.

Key Changes:

  • Modified TokenExpiresIn and RefreshTokenExpiresIn script properties to return null when expiration metadata is absent, rather than returning TimeSpan.Zero
  • Enhanced table formatting to display "N/A" (with gray color when supported) for tokens without expiration data
  • Added test validation to verify expiration properties are correctly populated for APP tokens and null for other auth types

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/types/GitHubContext.Types.ps1xml Updates script properties to return null instead of TimeSpan.Zero when expiration date is not set
src/formats/GitHubContext.Format.ps1xml Adds "N/A" display logic with color formatting for both TokenExpiresAt and TokenExpiresIn columns
tests/GitHub.Tests.ps1 Adds validation test for token expiration properties and new IAT auth type test; moves context creation to BeforeAll
tests/Apps.Tests.ps1 Enhances installation token expiration test to validate both TokenExpiresAt and TokenExpiresIn properties; fixes quote style

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@MariusStorhaug MariusStorhaug merged commit b592489 into main Jan 5, 2026
142 of 147 checks passed
@MariusStorhaug MariusStorhaug deleted the copilot/set-tokenexpiresin-to-unknown branch January 5, 2026 15:24
@github-project-automation github-project-automation bot moved this from Todo to Done in GitHub PowerShell Module Jan 5, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Jan 5, 2026

Module GitHub - 0.40.5 published to the PowerShell Gallery.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 5, 2026

GitHub release for GitHub v0.40.5 has been created.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

🩹 [Patch]: Set TokenExpiresIn to N/A for PAT tokens

2 participants