Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43714047be | ||
|
|
5601927dc8 |
@@ -92,9 +92,11 @@ func main() {
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/mcp", mcp.OriginAllowlist(cfg.OriginAllowlist)(
|
||||
auth.PassthroughMiddleware(giteaClient, mcpSrv,
|
||||
chassisauth.BearerMiddleware(cfg.StaticToken, jwtValidator, "gitea", resourceMetadataURL,
|
||||
auth.CallerMiddleware(logger, mcpSrv),
|
||||
),
|
||||
),
|
||||
))
|
||||
mux.Handle("/healthz", newHealthzHandler(cfg.DexIssuerURL != "", jwtValidator != nil, jwtInitErr))
|
||||
if cfg.DexIssuerURL != "" {
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package allowlist
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"git.d-ma.be/mathias/gitea-mcp/internal/gitea"
|
||||
)
|
||||
|
||||
type Allowlist struct {
|
||||
owners map[string]struct{}
|
||||
@@ -14,10 +19,17 @@ func New(owners []string) *Allowlist {
|
||||
return &Allowlist{owners: m}
|
||||
}
|
||||
|
||||
func (a *Allowlist) Check(owner string) error {
|
||||
// Check gates owner access to the static list — except for a caller
|
||||
// authenticated with their own Gitea PAT (pass-through, gitea-mcp#59), whose
|
||||
// access Gitea's own permission model already gates more precisely than a
|
||||
// coarse owner name list ever could.
|
||||
func (a *Allowlist) Check(ctx context.Context, owner string) error {
|
||||
if owner == "" {
|
||||
return fmt.Errorf("owner required")
|
||||
}
|
||||
if _, ok := gitea.TokenFromContext(ctx); ok {
|
||||
return nil
|
||||
}
|
||||
if _, ok := a.owners[owner]; !ok {
|
||||
return fmt.Errorf("owner %q not in allowlist", owner)
|
||||
}
|
||||
|
||||
@@ -1,16 +1,36 @@
|
||||
package allowlist_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"git.d-ma.be/mathias/gitea-mcp/internal/allowlist"
|
||||
"git.d-ma.be/mathias/gitea-mcp/internal/gitea"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAllowlistCheck(t *testing.T) {
|
||||
a := allowlist.New([]string{"mathias", "acme"})
|
||||
assert.NoError(t, a.Check("mathias"))
|
||||
assert.NoError(t, a.Check("acme"))
|
||||
assert.Error(t, a.Check("evil"))
|
||||
assert.Error(t, a.Check(""))
|
||||
ctx := context.Background()
|
||||
assert.NoError(t, a.Check(ctx, "mathias"))
|
||||
assert.NoError(t, a.Check(ctx, "acme"))
|
||||
assert.Error(t, a.Check(ctx, "evil"))
|
||||
assert.Error(t, a.Check(ctx, ""))
|
||||
}
|
||||
|
||||
// A caller authenticated with their own Gitea PAT (pass-through, gitea-mcp#59)
|
||||
// is gated by Gitea's own permission model, not the MCP's static owner list —
|
||||
// otherwise a legitimate second user could never touch their own repos.
|
||||
func TestAllowlistCheckTrustsPassthroughAuthenticatedCaller(t *testing.T) {
|
||||
a := allowlist.New([]string{"mathias"})
|
||||
ctx := gitea.WithToken(context.Background(), "someone-elses-pat")
|
||||
assert.NoError(t, a.Check(ctx, "someone-else"))
|
||||
}
|
||||
|
||||
// Empty owner is a structural input error, not an authz question — still
|
||||
// rejected even on the pass-through path.
|
||||
func TestAllowlistCheckStillRejectsEmptyOwnerOnPassthrough(t *testing.T) {
|
||||
a := allowlist.New([]string{"mathias"})
|
||||
ctx := gitea.WithToken(context.Background(), "someone-elses-pat")
|
||||
assert.Error(t, a.Check(ctx, ""))
|
||||
}
|
||||
|
||||
@@ -36,11 +36,14 @@ func CallerMiddleware(logger *slog.Logger, next http.Handler) http.Handler {
|
||||
"x_forwarded_user", fwdUser)
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), ctxKey{}, user)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
next.ServeHTTP(w, r.WithContext(withCaller(r.Context(), user)))
|
||||
})
|
||||
}
|
||||
|
||||
func withCaller(ctx context.Context, user string) context.Context {
|
||||
return context.WithValue(ctx, ctxKey{}, user)
|
||||
}
|
||||
|
||||
func Caller(ctx context.Context) string {
|
||||
if v, ok := ctx.Value(ctxKey{}).(string); ok {
|
||||
return v
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.d-ma.be/mathias/gitea-mcp/internal/gitea"
|
||||
)
|
||||
|
||||
// TokenValidator asks the upstream service who a bearer token belongs to.
|
||||
type TokenValidator interface {
|
||||
ValidateToken(ctx context.Context, token string) (username string, ok bool)
|
||||
}
|
||||
|
||||
// PassthroughMiddleware lets a caller authenticate with their own Gitea PAT:
|
||||
// if the request's bearer token validates directly against Gitea, it's used
|
||||
// as-is for every upstream call this request makes (gitea-mcp#59), instead of
|
||||
// the server's shared default token. Any other bearer (static token, JWT, or
|
||||
// none) falls through to fallback unchanged — this only adds a capability, it
|
||||
// never removes the existing auth paths.
|
||||
func PassthroughMiddleware(validator TokenValidator, onValid, fallback http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
authz := r.Header.Get("Authorization")
|
||||
token, hasBearer := strings.CutPrefix(authz, "Bearer ")
|
||||
if hasBearer && token != "" {
|
||||
if login, ok := validator.ValidateToken(r.Context(), token); ok {
|
||||
ctx := withCaller(r.Context(), login)
|
||||
ctx = gitea.WithToken(ctx, token)
|
||||
onValid.ServeHTTP(w, r.WithContext(ctx))
|
||||
return
|
||||
}
|
||||
}
|
||||
fallback.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package auth_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"git.d-ma.be/mathias/gitea-mcp/internal/auth"
|
||||
"git.d-ma.be/mathias/gitea-mcp/internal/gitea"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type fakeValidator struct {
|
||||
login string
|
||||
ok bool
|
||||
calls int
|
||||
}
|
||||
|
||||
func (f *fakeValidator) ValidateToken(_ context.Context, _ string) (string, bool) {
|
||||
f.calls++
|
||||
return f.login, f.ok
|
||||
}
|
||||
|
||||
func TestPassthroughMiddleware_ValidPATGoesStraightToOnValid(t *testing.T) {
|
||||
validator := &fakeValidator{login: "alice", ok: true}
|
||||
var gotCaller string
|
||||
var gotToken string
|
||||
var gotOK bool
|
||||
onValid := http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
|
||||
gotCaller = auth.Caller(r.Context())
|
||||
gotToken, gotOK = gitea.TokenFromContext(r.Context())
|
||||
})
|
||||
fallback := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
|
||||
t.Fatal("fallback should not be called for a valid PAT")
|
||||
})
|
||||
|
||||
h := auth.PassthroughMiddleware(validator, onValid, fallback)
|
||||
req := httptest.NewRequest(http.MethodPost, "/mcp", nil)
|
||||
req.Header.Set("Authorization", "Bearer alices-pat")
|
||||
h.ServeHTTP(httptest.NewRecorder(), req)
|
||||
|
||||
assert.Equal(t, "alice", gotCaller)
|
||||
assert.True(t, gotOK)
|
||||
assert.Equal(t, "alices-pat", gotToken)
|
||||
}
|
||||
|
||||
func TestPassthroughMiddleware_InvalidTokenFallsThrough(t *testing.T) {
|
||||
validator := &fakeValidator{ok: false}
|
||||
fallbackCalled := false
|
||||
onValid := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
|
||||
t.Fatal("onValid should not be called for an invalid token")
|
||||
})
|
||||
fallback := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
|
||||
fallbackCalled = true
|
||||
})
|
||||
|
||||
h := auth.PassthroughMiddleware(validator, onValid, fallback)
|
||||
req := httptest.NewRequest(http.MethodPost, "/mcp", nil)
|
||||
req.Header.Set("Authorization", "Bearer not-a-gitea-pat")
|
||||
h.ServeHTTP(httptest.NewRecorder(), req)
|
||||
|
||||
assert.True(t, fallbackCalled)
|
||||
}
|
||||
|
||||
func TestPassthroughMiddleware_NoBearerFallsThroughWithoutCallingValidator(t *testing.T) {
|
||||
validator := &fakeValidator{ok: true, login: "alice"}
|
||||
fallbackCalled := false
|
||||
onValid := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
|
||||
t.Fatal("onValid should not be called with no Authorization header")
|
||||
})
|
||||
fallback := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
|
||||
fallbackCalled = true
|
||||
})
|
||||
|
||||
h := auth.PassthroughMiddleware(validator, onValid, fallback)
|
||||
req := httptest.NewRequest(http.MethodPost, "/mcp", nil)
|
||||
h.ServeHTTP(httptest.NewRecorder(), req)
|
||||
|
||||
assert.True(t, fallbackCalled)
|
||||
assert.Equal(t, 0, validator.calls, "validator should not be invoked when there's no bearer to check")
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package gitea
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -19,6 +20,21 @@ type Client struct {
|
||||
branchCache *expirable.LRU[string, string]
|
||||
}
|
||||
|
||||
type ctxTokenKey struct{}
|
||||
|
||||
// WithToken overrides the token used for upstream Gitea calls made with the
|
||||
// returned context, taking precedence over the Client's configured default
|
||||
// token. Used for per-caller PAT pass-through (gitea-mcp#59).
|
||||
func WithToken(ctx context.Context, token string) context.Context {
|
||||
return context.WithValue(ctx, ctxTokenKey{}, token)
|
||||
}
|
||||
|
||||
// TokenFromContext returns the token set by WithToken, if any.
|
||||
func TokenFromContext(ctx context.Context) (string, bool) {
|
||||
v, ok := ctx.Value(ctxTokenKey{}).(string)
|
||||
return v, ok
|
||||
}
|
||||
|
||||
func NewClient(baseURL, token string) *Client {
|
||||
return &Client{
|
||||
baseURL: baseURL,
|
||||
@@ -28,6 +44,23 @@ func NewClient(baseURL, token string) *Client {
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateToken asks Gitea who a given token belongs to (GET /api/v1/user
|
||||
// using that token, not the client's configured default token) and returns
|
||||
// its login name. Used for per-caller PAT pass-through (gitea-mcp#59).
|
||||
func (c *Client) ValidateToken(ctx context.Context, token string) (string, bool) {
|
||||
body, status, err := c.doOnce(WithToken(ctx, token), http.MethodGet, "/api/v1/user", nil)
|
||||
if err != nil || status != http.StatusOK {
|
||||
return "", false
|
||||
}
|
||||
var user struct {
|
||||
Login string `json:"login"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &user); err != nil || user.Login == "" {
|
||||
return "", false
|
||||
}
|
||||
return user.Login, true
|
||||
}
|
||||
|
||||
// DefaultBranch returns the default branch for a repo. Cached for 60s.
|
||||
func (c *Client) DefaultBranch(ctx context.Context, owner, name string) (string, error) {
|
||||
key := owner + "/" + name
|
||||
@@ -66,6 +99,9 @@ func (c *Client) doOnce(ctx context.Context, method, path string, body []byte) (
|
||||
return nil, 0, err
|
||||
}
|
||||
token := c.token
|
||||
if override, ok := TokenFromContext(ctx); ok {
|
||||
token = override
|
||||
}
|
||||
if token != "" {
|
||||
req.Header.Set("Authorization", "token "+token)
|
||||
}
|
||||
@@ -135,6 +171,9 @@ func (c *Client) doRaw(ctx context.Context, method, path string, body []byte) (*
|
||||
return nil, err
|
||||
}
|
||||
token := c.token
|
||||
if override, ok := TokenFromContext(ctx); ok {
|
||||
token = override
|
||||
}
|
||||
if token != "" {
|
||||
req.Header.Set("Authorization", "token "+token)
|
||||
}
|
||||
|
||||
@@ -50,6 +50,49 @@ func TestRetryOn5xxGetSucceedsOnSecondAttempt(t *testing.T) {
|
||||
assert.Equal(t, int32(2), atomic.LoadInt32(&attempts))
|
||||
}
|
||||
|
||||
func TestClientPrefersTokenFromContextOverDefaultToken(t *testing.T) {
|
||||
var gotAuth string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotAuth = r.Header.Get("Authorization")
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"ok":true}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
c := gitea.NewClient(srv.URL, "default-token")
|
||||
ctx := gitea.WithToken(context.Background(), "caller-token")
|
||||
_, status, err := c.GetJSON(ctx, "/api/v1/user")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 200, status)
|
||||
assert.Equal(t, "token caller-token", gotAuth)
|
||||
}
|
||||
|
||||
func TestValidateTokenReturnsLoginOnSuccess(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "token candidate-token", r.Header.Get("Authorization"))
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"login":"alice"}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
c := gitea.NewClient(srv.URL, "default-token")
|
||||
login, ok := c.ValidateToken(context.Background(), "candidate-token")
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "alice", login)
|
||||
}
|
||||
|
||||
func TestValidateTokenReturnsFalseOn401(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
c := gitea.NewClient(srv.URL, "default-token")
|
||||
login, ok := c.ValidateToken(context.Background(), "bad-token")
|
||||
assert.False(t, ok)
|
||||
assert.Empty(t, login)
|
||||
}
|
||||
|
||||
func TestRetryOnPostNotRetried(t *testing.T) {
|
||||
var attempts int32
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
|
||||
@@ -46,7 +46,7 @@ func (t *BranchDelete) Call(ctx context.Context, raw json.RawMessage) (json.RawM
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Branch == "" {
|
||||
|
||||
@@ -47,7 +47,7 @@ func (t *BranchList) Call(ctx context.Context, raw json.RawMessage) (json.RawMes
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ func (t *BranchProtectionGet) Call(ctx context.Context, raw json.RawMessage) (js
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ func (t *CodeSearch) Call(ctx context.Context, raw json.RawMessage) (json.RawMes
|
||||
if args.Q == "" {
|
||||
return nil, fmt.Errorf("q is required: %w", gitea.ErrValidation)
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Page < 1 {
|
||||
|
||||
@@ -111,7 +111,7 @@ func (t *CreateProjectFromTemplate) Call(ctx context.Context, raw json.RawMessag
|
||||
}
|
||||
|
||||
// Allowlist check first.
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ func (t *DirList) Call(ctx context.Context, raw json.RawMessage) (json.RawMessag
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ func (t *FileDelete) Call(ctx context.Context, raw json.RawMessage) (json.RawMes
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Sha == "" {
|
||||
|
||||
@@ -51,7 +51,7 @@ func (t *FileRead) Call(ctx context.Context, raw json.RawMessage) (json.RawMessa
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ func (t *FileWriteBranch) Call(ctx context.Context, raw json.RawMessage) (json.R
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Branch == "" {
|
||||
|
||||
@@ -45,7 +45,7 @@ func (t *IssueClose) Call(ctx context.Context, raw json.RawMessage) (json.RawMes
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iss, err := t.c.SetIssueState(ctx, args.Owner, args.Repo, args.Number, "closed")
|
||||
|
||||
@@ -50,7 +50,7 @@ func (t *IssueComment) Call(ctx context.Context, raw json.RawMessage) (json.RawM
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Number < 1 {
|
||||
|
||||
@@ -56,7 +56,7 @@ func (t *IssueCreate) Call(ctx context.Context, raw json.RawMessage) (json.RawMe
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Title == "" {
|
||||
|
||||
@@ -53,7 +53,7 @@ func (t *IssueEdit) Call(ctx context.Context, raw json.RawMessage) (json.RawMess
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Number < 1 {
|
||||
|
||||
@@ -43,7 +43,7 @@ func (t *IssueGet) Call(ctx context.Context, raw json.RawMessage) (json.RawMessa
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iss, err := t.c.GetIssue(ctx, args.Owner, args.Repo, args.Number)
|
||||
|
||||
@@ -50,7 +50,7 @@ func (t *IssueLabel) Call(ctx context.Context, raw json.RawMessage) (json.RawMes
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Number < 1 {
|
||||
|
||||
@@ -53,7 +53,7 @@ func (t *IssueList) Call(ctx context.Context, raw json.RawMessage) (json.RawMess
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.State == "" {
|
||||
|
||||
@@ -45,7 +45,7 @@ func (t *IssueListComments) Call(ctx context.Context, raw json.RawMessage) (json
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
comments, err := t.c.ListIssueComments(ctx, args.Owner, args.Repo, args.Number)
|
||||
|
||||
@@ -45,7 +45,7 @@ func (t *IssueReopen) Call(ctx context.Context, raw json.RawMessage) (json.RawMe
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iss, err := t.c.SetIssueState(ctx, args.Owner, args.Repo, args.Number, "open")
|
||||
|
||||
@@ -43,7 +43,7 @@ func (t *LabelList) Call(ctx context.Context, raw json.RawMessage) (json.RawMess
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
labels, err := t.c.ListLabels(ctx, args.Owner, args.Repo)
|
||||
|
||||
@@ -50,7 +50,7 @@ func (t *PRComment) Call(ctx context.Context, raw json.RawMessage) (json.RawMess
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Number < 1 {
|
||||
|
||||
@@ -56,7 +56,7 @@ func (t *PRCreate) Call(ctx context.Context, raw json.RawMessage) (json.RawMessa
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Title == "" {
|
||||
|
||||
@@ -63,7 +63,7 @@ func (t *PRFilesDiff) Call(ctx context.Context, raw json.RawMessage) (json.RawMe
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Number < 1 {
|
||||
|
||||
@@ -44,7 +44,7 @@ func (t *PRGet) Call(ctx context.Context, raw json.RawMessage) (json.RawMessage,
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Number < 1 {
|
||||
|
||||
@@ -51,7 +51,7 @@ func (t *PRList) Call(ctx context.Context, raw json.RawMessage) (json.RawMessage
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state := args.State
|
||||
|
||||
@@ -52,7 +52,7 @@ func (t *PRMerge) Call(ctx context.Context, raw json.RawMessage) (json.RawMessag
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Number < 1 {
|
||||
|
||||
@@ -55,7 +55,7 @@ func (t *ReleaseCreate) Call(ctx context.Context, raw json.RawMessage) (json.Raw
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rel, err := t.c.CreateRelease(ctx, args.Owner, args.Repo, gitea.CreateReleaseArgs{
|
||||
|
||||
@@ -53,7 +53,7 @@ func (t *RepoCreate) Call(ctx context.Context, raw json.RawMessage) (json.RawMes
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createArgs := gitea.CreateRepoArgs{
|
||||
|
||||
@@ -46,7 +46,7 @@ func (t *RepoDelete) Call(ctx context.Context, raw json.RawMessage) (json.RawMes
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Confirm != args.Repo {
|
||||
|
||||
@@ -38,7 +38,7 @@ func (t *RepoGet) Call(ctx context.Context, raw json.RawMessage) (json.RawMessag
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := t.c.GetRepo(ctx, args.Owner, args.Repo)
|
||||
|
||||
@@ -45,7 +45,7 @@ func (t *RepoList) Call(ctx context.Context, raw json.RawMessage) (json.RawMessa
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args.Limit = capLimit(args.Limit, 30)
|
||||
|
||||
@@ -96,7 +96,7 @@ func (t *RepoMirrorPush) Call(ctx context.Context, raw json.RawMessage) (json.Ra
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch args.Action {
|
||||
|
||||
@@ -53,7 +53,7 @@ func (t *RepoSearch) Call(ctx context.Context, raw json.RawMessage) (json.RawMes
|
||||
return nil, fmt.Errorf("q is required: %w", gitea.ErrValidation)
|
||||
}
|
||||
if args.Owner != "" {
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func (t *RepoSearch) Call(ctx context.Context, raw json.RawMessage) (json.RawMes
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
if t.a.Check(parts[0]) == nil {
|
||||
if t.a.Check(ctx, parts[0]) == nil {
|
||||
filtered = append(filtered, r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func (t *RepoStatus) Call(ctx context.Context, raw json.RawMessage) (json.RawMes
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ func (t *RepoTopicsUpdate) Call(ctx context.Context, raw json.RawMessage) (json.
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.c.UpdateTopics(ctx, args.Owner, args.Repo, args.Topics); err != nil {
|
||||
|
||||
@@ -45,7 +45,7 @@ func (t *RepoTree) Call(ctx context.Context, raw json.RawMessage) (json.RawMessa
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tree, err := t.c.GetTree(ctx, args.Owner, args.Repo, args.Ref, true)
|
||||
|
||||
@@ -60,7 +60,7 @@ func (t *RepoUpdate) Call(ctx context.Context, raw json.RawMessage) (json.RawMes
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ func (t *TagCreate) Call(ctx context.Context, raw json.RawMessage) (json.RawMess
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Tag == "" {
|
||||
|
||||
@@ -145,7 +145,7 @@ func (t *TBDShip) Call(ctx context.Context, raw json.RawMessage) (json.RawMessag
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Path == "" || args.Content == "" || args.Message == "" {
|
||||
|
||||
@@ -57,7 +57,7 @@ func (t *WorkflowRunList) Call(ctx context.Context, raw json.RawMessage) (json.R
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args.Limit = capLimit(args.Limit, 10)
|
||||
|
||||
@@ -47,7 +47,7 @@ func (t *WorkflowRunStatus) Call(ctx context.Context, raw json.RawMessage) (json
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.RunID < 1 {
|
||||
|
||||
@@ -62,7 +62,7 @@ func (t *WorkflowRunTrigger) Call(ctx context.Context, raw json.RawMessage) (jso
|
||||
if err := parseArgs(raw, &args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.a.Check(args.Owner); err != nil {
|
||||
if err := t.a.Check(ctx, args.Owner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if args.Workflow == "" {
|
||||
|
||||
Reference in New Issue
Block a user