Skip to content

[test] Add tests for oidc.extractJWTExpiry#3939

Merged
lpcox merged 1 commit intomainfrom
test/oidc-extract-jwt-expiry-coverage-62d1c7f22aaf46eb
Apr 16, 2026
Merged

[test] Add tests for oidc.extractJWTExpiry#3939
lpcox merged 1 commit intomainfrom
test/oidc-extract-jwt-expiry-coverage-62d1c7f22aaf46eb

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

Test Coverage Improvement: oidc.extractJWTExpiry

Function Analyzed

  • Package: internal/oidc
  • Function: extractJWTExpiry (unexported)
  • Previous Coverage: Indirect only — exercised via Provider HTTP mock tests with a single fixed JWT token
  • New Coverage: All branches directly tested
  • Complexity: Medium — base64url padding normalization, JSON unmarshaling, multiple distinct error paths

Why This Function?

extractJWTExpiry is a private helper that parses the exp claim from a JWT without verifying its signature. It implements manual base64url padding logic (a common source of subtle bugs) and has four distinct error paths:

  1. Wrong JWT part count
  2. Invalid base64 in the payload segment
  3. Invalid JSON in the decoded payload
  4. Missing/zero exp claim

The existing provider_test.go (package oidc_test) tests these paths only indirectly through an HTTP mock server and uses a single fixed JWT payload whose raw base64 length happens to be divisible by 4 — leaving the case 2 ("==") and case 3 ("=") padding branches of the switch statement uncovered by any test.

Tests Added

  • base64 padding case 0 (mod4=0): {"exp":1} → 12-char raw payload, no padding needed
  • base64 padding case 2 (mod4=2): {"exp":12} → 14-char raw payload, "==" appended
  • base64 padding case 3 (mod4=3): {"exp":123} → 15-char raw payload, "=" appended
  • ✅ Realistic Unix timestamp expiry
  • ✅ Extra JWT claims (iss, sub, aud, iat) ignored
  • exp=0"JWT has no exp claim" error
  • ✅ Missing exp field → same error (zero-valued struct field)
  • ✅ Wrong part count (1, 2, 4, 5 parts via table-driven test)
  • ✅ Invalid base64url in payload segment
  • ✅ Valid base64 but invalid JSON payload
  • ✅ Empty JSON object {} payload → exp=0 error
  • ✅ Empty string token

Implementation Notes

The new test file uses package oidc (white-box test) to access the unexported function, following Go convention of using _test.go files in the same package for testing unexported code. The existing provider_test.go uses package oidc_test (black-box), which is why it cannot test extractJWTExpiry directly.

Two test helpers are introduced:

  • makeRawJWT(rawPayload) — assembles header.payload.sig with a dummy header/signature
  • encodePayloadRaw(json) — base64url-encodes JSON without padding (matching real JWT format)

Test File

internal/oidc/jwt_expiry_test.go — 12 test functions, 183 lines


Generated by Test Coverage Improver
Next run will target the next most complex under-tested function

Warning

⚠️ Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • proxy.golang.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "proxy.golang.org"

See Network Configuration for more information.

Generated by Test Coverage Improver · ● 6.5M ·

Directly tests all branches of the private extractJWTExpiry function
in package oidc. Previously this function was only exercised indirectly
through the HTTP-server-level Provider tests, which used a fixed JWT
payload that always produces a length%4==0 base64 string.

New unit tests cover:
- All three base64url padding cases (mod4=0, mod4=2→"==", mod4=3→"=")
- Realistic Unix timestamp expiry
- Extra JWT claims ignored (iss, sub, aud, iat)
- exp=0 returns error ("JWT has no exp claim")
- Missing exp field returns same error
- Wrong part count (1, 2, 4, 5 parts via table-driven test)
- Invalid base64 in payload segment
- Invalid JSON in payload (valid base64, bad JSON)
- Empty JSON object payload ({})
- Empty string token

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@lpcox lpcox marked this pull request as ready for review April 16, 2026 14:26
Copilot AI review requested due to automatic review settings April 16, 2026 14:26
@lpcox lpcox merged commit daa3c76 into main Apr 16, 2026
3 checks passed
@lpcox lpcox deleted the test/oidc-extract-jwt-expiry-coverage-62d1c7f22aaf46eb branch April 16, 2026 14:27
Copy link
Copy Markdown
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

Adds direct unit tests for internal/oidc.extractJWTExpiry to cover all branches and error paths, improving confidence in JWT exp parsing (including base64url padding normalization).

Changes:

  • Introduces a new white-box test file (package oidc) to directly exercise extractJWTExpiry.
  • Adds coverage for base64url padding cases (mod4=0/2/3) plus realistic timestamps and ignored extra claims.
  • Adds coverage for malformed tokens and payload decode/parse/claim-missing error paths.
Show a summary per file
File Description
internal/oidc/jwt_expiry_test.go New unit tests and helpers covering success/error branches of extractJWTExpiry.

Copilot's findings

Tip

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

Comments suppressed due to low confidence (1)

internal/oidc/jwt_expiry_test.go:171

  • This test payload is encoded with base64.URLEncoding (padded), while the helper/comment above describe JWT payloads as base64url without padding. Consider using encodePayloadRaw("{}") (or base64.RawURLEncoding) to keep the test token format aligned with JWTs and consistent with the rest of the file.
func TestExtractJWTExpiry_EmptyPayload(t *testing.T) {
	emptyPayload := base64.URLEncoding.EncodeToString([]byte(`{}`))
	token := fmt.Sprintf("header.%s.sig", emptyPayload)
  • Files reviewed: 1/1 changed files
  • Comments generated: 2

Comment on lines +21 to +22
func encodePayloadRaw(json string) string {
return base64.RawURLEncoding.EncodeToString([]byte(json))
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The parameter name json is easy to confuse with the conventional json package identifier and can become awkward if this file later imports encoding/json. Renaming it to something like payloadJSON (or claimsJSON) would make call sites clearer and avoid potential shadowing confusion.

Suggested change
func encodePayloadRaw(json string) string {
return base64.RawURLEncoding.EncodeToString([]byte(json))
func encodePayloadRaw(payloadJSON string) string {
return base64.RawURLEncoding.EncodeToString([]byte(payloadJSON))

Copilot uses AI. Check for mistakes.
Comment on lines +159 to +161
invalidJSON := base64.URLEncoding.EncodeToString([]byte(`{not valid json`))
token := fmt.Sprintf("header.%s.sig", invalidJSON)

Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

encodePayloadRaw is intended to generate standard JWT payload segments (base64url without padding), but this test uses base64.URLEncoding.EncodeToString, which adds = padding. Using encodePayloadRaw(...) (or base64.RawURLEncoding) here would keep the token format consistent with real JWTs and with the other tests in this file.

This issue also appears on line 169 of the same file.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants