Add GitHub personal access token validity check

What does this MR do and why?

This adds a validity check for classic GitHub personal access tokens (starting with prefix ghp_).

A user can then tell whether the exposed credential is still live rather than only that it was leaked.

Implementation

This follows ADR-006 and uses the registry directly to map the token straight to the verifier class/client, i.e. GithubClient.

The verifier calls GET https://api.github.com/user with the token as a Bearer credential.

We map the responses to the following statuses/outcomes:

Response Outcome
200 active
401 inactive
403, 429 RateLimitError
500, 502, 503, 504 NetworkError
anything else unknown

Please note that aside from 401, no other status falls to inactive.

Reporting a live token as dead is worse than reporting nothing, so unmapped statuses are always unknown.

Stack Position

We have 8 MRs for all new validity checks generated during Sec Challenge #6, with the base targeting master.

Each MR in the stack adds exactly one validity check: the client class, its spec, the registry entry, and the rate limit rule.

Stack (in review order)
# Check Token type
1 GitHub PAT Github Personal Access Token
2 OpenAI project key OpenAiProjectKey
3 Anthropic API key anthropic_key
4 Slack access tokens Slack token
5 Stripe live secret key StripeLiveSecretKey
6 Datadog API key DataDogAPIKey
7 SendGrid API token Sendgrid API token
8 Heroku API key Heroku API Key

Notes

How to set up and validate locally

  1. Run the specs:

    bundle exec rspec ee/spec/lib/security/secret_detection/partner_tokens/github_client_spec.rb \
      ee/spec/services/security/secret_detection/partner_tokens/registry_spec.rb
  2. Confirm the registry resolves the token type and that the rate limit rule exists:

    Security::SecretDetection::PartnerTokens::Registry.client_for('Github Personal Access Token')
    # => #<Security::SecretDetection::PartnerTokens::GithubClient>
    Gitlab::ApplicationRateLimiter.period_for(:partner_github_api)
    # => 3600 seconds
  3. Optional, with a real credential — a revoked token should come back inactive and a live one active:

    Security::SecretDetection::PartnerTokens::Registry
      .client_for('Github Personal Access Token').verify_token(ENV['TOKEN']).status

MR acceptance checklist

I have evaluated this MR against the MR acceptance checklist.

Edited by Ahmed Hemdan

Merge request reports

Loading
Loading