Skip to content

Conversation

@omgitsads
Copy link
Member

@omgitsads omgitsads commented Feb 11, 2026

Summary

So that I can setup the scopes of a token before it is authed, separate the TokenScopes from the TokenInfo contexts. In the remote MCP server, by the time ExtractUserToken happens, we already know that

Why

Gives us greater flexibility for handling authentication in a gateway and pre-populating token scopes.

What changed

  • Store scopes in a Seperate context window.

MCP impact

  • No tool or API changes
  • Tool schema or behavior changed
  • New tool added

Prompts tested (tool changes only)

Security / limits

  • No security or limits impact
  • Auth / permissions considered
  • Data exposure, filtering, or token/size limits considered

Tool renaming

  • I am renaming tools as part of this PR (e.g. a part of a consolidation effort)
    • I have added the new tool aliases in deprecated_tool_aliases.go
  • I am not renaming tools as part of this PR

Note: if you're renaming tools, you must add the tool aliases. For more information on how to do so, please refer to the official docs.

Lint & tests

  • Linted locally with ./script/lint
  • Tested locally with ./script/test

Docs

  • Not needed
  • Updated (README / docs / examples)

This allows us to provide scopes seperately in the remote server, where
we have scopes before we do the auth.
This is to avoid redundant token extraction in remote setup where token info may have already been extracted earlier in the request lifecycle.
Copilot AI review requested due to automatic review settings February 11, 2026 14:30
@omgitsads omgitsads requested a review from a team as a code owner February 11, 2026 14:30
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 separates OAuth/PAT scope storage from TokenInfo by introducing a dedicated “token scopes” context value, enabling upstream/remote deployments to pre-populate scopes and avoid redundant GitHub API calls.

Changes:

  • Add WithTokenScopes / GetTokenScopes context helpers and remove scope fields from TokenInfo.
  • Update HTTP middleware and inventory filtering to read/write scopes via the new context value.
  • Update PAT scope middleware tests to assert scopes are stored in context.

Reviewed changes

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

Show a summary per file
File Description
pkg/http/middleware/token.go Skip token extraction when TokenInfo is already present in request context.
pkg/http/middleware/scope_challenge.go Prefer scopes from context; fetch from GitHub only when absent; store scopes back into context.
pkg/http/middleware/pat_scope.go Prefer scopes from context; otherwise fetch and store into context.
pkg/http/middleware/pat_scope_test.go Update tests to validate scopes are stored/retrieved via the new context helpers.
pkg/http/handler.go Update PAT tool filtering to read scopes from context (or fetch if missing).
pkg/context/token.go Remove scopes from TokenInfo; add dedicated context storage for token scopes.

Comment on lines +97 to 110
// Get OAuth scopes for Token. First check if scopes are already in context, then fetch from GitHub if not present.
// This allows Remote Server to pass scope info to avoid redundant GitHub API calls.
activeScopes, ok := ghcontext.GetTokenScopes(ctx)
if !ok {
activeScopes, err = scopeFetcher.FetchTokenScopes(ctx, tokenInfo.Token)
if err != nil {
next.ServeHTTP(w, r)
return
}
}

// Store active scopes in context for downstream use
tokenInfo.Scopes = activeScopes
tokenInfo.ScopesFetched = true
ctx = ghcontext.WithTokenInfo(ctx, tokenInfo)
ctx = ghcontext.WithTokenScopes(ctx, activeScopes)
r = r.WithContext(ctx)
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

New behavior reads scopes from context to avoid redundant GitHub API calls, but there’s no unit test coverage for (1) scopes already present in context skipping FetchTokenScopes, and (2) scopes being stored back into context for downstream use. Adding a table-driven test with a mock fetcher would prevent regressions here.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +18 to +24
// Check if token info already exists in context, if it does, skip extraction.
// In remote setup, we may have already extracted token info earlier.
if _, ok := ghcontext.GetTokenInfo(ctx); ok {
// Token info already exists in context, skip extraction
next.ServeHTTP(w, r)
return
}
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

This middleware now short-circuits when TokenInfo is already present in context, but token_test.go doesn’t cover the new branch. Add a test that pre-populates TokenInfo in the request context and asserts the middleware does not overwrite it and does not require an Authorization header.

Copilot generated this review using guidance from repository custom instructions.
ScopesFetched bool
Scopes []string
Token string
TokenType utils.TokenType
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

TokenInfo is an exported struct in a public package (pkg/context). Removing the Scopes/ScopesFetched fields is a breaking API change for any external consumers importing this module. Consider keeping the fields (possibly deprecated) or introducing a new context value/type for scopes while maintaining backward compatibility.

Suggested change
TokenType utils.TokenType
TokenType utils.TokenType
// Deprecated: Scopes are now stored separately in the context using WithTokenScopes/GetTokenScopes.
Scopes []string
// Deprecated: ScopesFetched is no longer used; scopes are managed via TokenScopesKey in the context.
ScopesFetched bool

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +39
type TokenScopesKey tokenCtx

var tokenScopesKey TokenScopesKey = "tokenscopesctx"

// WithTokenScopes adds token scopes to the context
func WithTokenScopes(ctx context.Context, scopes []string) context.Context {
return context.WithValue(ctx, tokenScopesKey, scopes)
}
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

The new token-scopes context key uses an exported key type (TokenScopesKey) with a string underlying value. This allows other packages to create the same key type/value and accidentally collide, and it’s inconsistent with the repo’s common struct{}-typed unexported context keys (e.g. readonlyCtxKey{} in pkg/context/request.go). Prefer an unexported struct{} key type for scopes as well.

Copilot uses AI. Check for mistakes.
if tokenInfo.TokenType == utils.TokenTypePersonalAccessToken {
existingScopes, ok := ghcontext.GetTokenScopes(ctx)
if ok {
logger.Debug("using existing scopes from context", "scopes", existingScopes)
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

This logs the full scope list. Token scopes can reveal granted permissions and may be sensitive in some environments even at debug level. Consider logging only the count, or gating the detailed list behind an explicit opt-in / trace-level log.

Suggested change
logger.Debug("using existing scopes from context", "scopes", existingScopes)
logger.Debug("using existing scopes from context", "scope_count", len(existingScopes))

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant