Skip to content

Commit 82617db

Browse files
committed
fix: accept opaque GitHub tokens
1 parent 494b35f commit 82617db

2 files changed

Lines changed: 34 additions & 11 deletions

File tree

‎internal/config/config.go‎

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"path/filepath"
88
"regexp"
99
"strings"
10+
"unicode"
1011

1112
"github.com/compozy/releasepr/internal/logger"
1213
"github.com/go-git/go-git/v5"
@@ -209,18 +210,16 @@ func (c *Config) ValidateForGitHubOperations() error {
209210
return c.Validate()
210211
}
211212

212-
// ValidateGitHubToken validates GitHub token format (exported for reuse).
213+
// ValidateGitHubToken validates that an opaque GitHub token is safe to pass to clients.
213214
func ValidateGitHubToken(token string) error {
214-
token = strings.TrimSpace(token)
215-
classicPAT := regexp.MustCompile(`^[a-fA-F0-9]{40}$`)
216-
fineGrainedPAT := regexp.MustCompile(`^github_pat_[a-zA-Z0-9_]{82}$`)
217-
appToken := regexp.MustCompile(`^ghs_[a-zA-Z0-9]{36}$`)
218-
oauthToken := regexp.MustCompile(`^gho_[a-zA-Z0-9]{36}$`)
219-
if !classicPAT.MatchString(token) &&
220-
!fineGrainedPAT.MatchString(token) &&
221-
!appToken.MatchString(token) &&
222-
!oauthToken.MatchString(token) {
223-
return fmt.Errorf("invalid token format")
215+
if strings.TrimSpace(token) == "" {
216+
return fmt.Errorf("token cannot be empty")
217+
}
218+
containsUnsafeCharacter := strings.IndexFunc(token, func(character rune) bool {
219+
return unicode.IsSpace(character) || unicode.IsControl(character)
220+
}) >= 0
221+
if containsUnsafeCharacter {
222+
return fmt.Errorf("token contains whitespace or control characters")
224223
}
225224
return nil
226225
}

‎internal/config/config_test.go‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,27 @@ func TestConfigValidateReleaseArtifacts(t *testing.T) {
119119
require.Contains(t, err.Error(), "command must be one of")
120120
})
121121
}
122+
123+
func TestValidateGitHubToken(t *testing.T) {
124+
t.Run("Should accept opaque token values", func(t *testing.T) {
125+
tokens := []string{
126+
"ghs_1234567890_header.payload.signature",
127+
"github-enterprise-token-value",
128+
}
129+
for _, token := range tokens {
130+
require.NoError(t, ValidateGitHubToken(token))
131+
}
132+
})
133+
134+
t.Run("Should reject empty tokens", func(t *testing.T) {
135+
require.ErrorContains(t, ValidateGitHubToken(""), "token cannot be empty")
136+
require.ErrorContains(t, ValidateGitHubToken(" "), "token cannot be empty")
137+
})
138+
139+
t.Run("Should reject whitespace and control characters", func(t *testing.T) {
140+
tokens := []string{"token with space", "token\nvalue", "token\x00value"}
141+
for _, token := range tokens {
142+
require.ErrorContains(t, ValidateGitHubToken(token), "whitespace or control characters")
143+
}
144+
})
145+
}

0 commit comments

Comments
 (0)