Skip to content

Commit cd578fb

Browse files
committed
Expiration timestamp sometimes in a different format
1 parent ee295c6 commit cd578fb

File tree

1 file changed

+18
-8
lines changed

1 file changed

+18
-8
lines changed

main.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ import (
2424
sdkTrace "go.opentelemetry.io/otel/sdk/trace"
2525
)
2626

27-
const expirationLayout = "2006-01-02 15:04:05 MST"
27+
const (
28+
// Sometimes Github returns an abbreviated timezone name, sometimes a numeric offset 🙄
29+
abbrevLayout = "2006-01-02 15:04:05 MST"
30+
offsetLayout = "2006-01-02 15:04:05 -0700"
31+
)
2832

2933
var flags struct {
3034
TokenEnvVars string `name:"token-env-vars" help:"Comma-separated list of token env var(s)"`
@@ -154,33 +158,31 @@ func checkToken(ctx context.Context, name, token string) (happy bool, err error)
154158
}
155159
span.End()
156160
}()
161+
157162
fmt.Printf("Checking %q...\n", name)
158163

164+
// Make request to e.g. 'https://api.github.com/user' with token
159165
userURL := flags.BaseURL.JoinPath("user").String()
160-
161166
req, err := http.NewRequestWithContext(ctx, "GET", userURL, nil)
162167
if err != nil {
163168
return false, fmt.Errorf("new request: %w", err)
164169
}
165-
166170
req.Header.Set("Authorization", "Bearer "+token)
167-
168171
resp, err := http.DefaultClient.Do(req)
169172
if err != nil {
170173
return false, fmt.Errorf("do request: %w", err)
171174
}
172175
defer resp.Body.Close()
173-
174176
body, err := io.ReadAll(resp.Body)
175177
if err != nil {
176178
return false, fmt.Errorf("reading body: %w", err)
177179
}
178-
179180
if resp.StatusCode != 200 {
180181
span.SetAttributes(attribute.String("ghtokmon.error_body", strconv.QuoteToASCII(string(body[:1024]))))
181182
return false, fmt.Errorf("got status code %d != 200", resp.StatusCode)
182183
}
183184

185+
// Parse user login
184186
var user struct {
185187
Login string `json:"login"`
186188
}
@@ -193,20 +195,26 @@ func checkToken(ctx context.Context, name, token string) (happy bool, err error)
193195

194196
happy = true
195197

198+
// Check token expiration
196199
expirationValue := resp.Header.Get("github-authentication-token-expiration")
197200
if expirationValue == "" {
198201
fmt.Println("Token expiration: NONE")
199202
} else {
200203
span.SetAttributes(attribute.String("ghtokmon.token.expiration", expirationValue))
201-
expiration, err := time.Parse(expirationLayout, expirationValue)
204+
205+
// Parse expiration timestamp
206+
expiration, err := time.Parse(abbrevLayout, expirationValue)
207+
if err != nil {
208+
expiration, err = time.Parse(offsetLayout, expirationValue)
209+
}
202210
if err != nil {
203211
return false, fmt.Errorf("invalid expiration header value %q: %w", expirationValue, err)
204212
}
205213
fmt.Printf("Token expiration: %s", expiration)
206214

215+
// Calculate time until expiration
207216
expirationDuration := time.Until(expiration)
208217
span.SetAttributes(attribute.Float64("ghtokmon.token.expiration_duration", expirationDuration.Seconds()))
209-
210218
fmt.Printf(" (%.1f days)\n", expirationDuration.Hours()/24)
211219
if expirationDuration < flags.ExpirationThreshold {
212220
fmt.Println("WARNING: Expiring soon!")
@@ -216,6 +224,7 @@ func checkToken(ctx context.Context, name, token string) (happy bool, err error)
216224

217225
}
218226

227+
// Check rate limit usage
219228
rateLimitLimit, _ := strconv.Atoi(resp.Header.Get("x-ratelimit-limit"))
220229
if rateLimitLimit != 0 {
221230
rateLimitUsed, _ := strconv.Atoi(resp.Header.Get("x-ratelimit-used"))
@@ -230,6 +239,7 @@ func checkToken(ctx context.Context, name, token string) (happy bool, err error)
230239
}
231240
}
232241

242+
// Get token permissions (sometimes helpful when rotating)
233243
oAuthScopes := resp.Header.Get("x-oauth-scopes")
234244
span.SetAttributes(attribute.String("ghtokmon.token.oauth_scopes", oAuthScopes))
235245
fmt.Printf("OAuth scopes: %s\n\n", oAuthScopes)

0 commit comments

Comments
 (0)