Skip to content

Commit d333159

Browse files
CR-15777 (#666)
* check token type (project is invalid) * bump * lint * fix-test * use autopilot v0.4.10 * resolve comments * wip * wip
1 parent 9161d8d commit d333159

File tree

5 files changed

+103
-5
lines changed

5 files changed

+103
-5
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION=v0.1.26
1+
VERSION=v0.1.27
22

33
OUT_DIR=dist
44
YEAR?=$(shell date +"%Y")

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.19
44

55
require (
66
github.com/Masterminds/semver/v3 v3.1.1
7-
github.com/argoproj-labs/argocd-autopilot v0.4.9
7+
github.com/argoproj-labs/argocd-autopilot v0.4.10
88
github.com/argoproj/argo-cd/v2 v2.5.2
99
github.com/argoproj/argo-events v0.17.1-0.20220327045437-70eaafe9afec
1010
github.com/argoproj/argo-workflows/v3 v3.3.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,8 @@ github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmH
179179
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
180180
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
181181
github.com/appscode/go v0.0.0-20190808133642-1d4ef1f1c1e0/go.mod h1:iy07dV61Z7QQdCKJCIvUoDL21u6AIceRhZzyleh2ymc=
182-
github.com/argoproj-labs/argocd-autopilot v0.4.9 h1:mXptimJTxZhpgq2lRZTQLO4OHyGyNZpsIxYPdWmdnOY=
183-
github.com/argoproj-labs/argocd-autopilot v0.4.9/go.mod h1:iR9JosRv7UBOQBSDR64Rrg1qs1DURhR+kx8zK2GEap4=
182+
github.com/argoproj-labs/argocd-autopilot v0.4.10 h1:0I0U28wvwoZkh2/ECKEgMDFw71Dzh6WCSAU4TkWuxY8=
183+
github.com/argoproj-labs/argocd-autopilot v0.4.10/go.mod h1:iR9JosRv7UBOQBSDR64Rrg1qs1DURhR+kx8zK2GEap4=
184184
github.com/argoproj/argo-cd/v2 v2.5.2 h1:hyPi8NFXW3tG2yURslIMI20GfCdTN1/BDnt4+v5lpoA=
185185
github.com/argoproj/argo-cd/v2 v2.5.2/go.mod h1:3ToENm286PFVlZKNMutBzOwNyhevz4fw9dcgyiq3FIY=
186186
github.com/argoproj/argo-events v0.17.1-0.20220327045437-70eaafe9afec h1:95S2LPUUdPO2jYxuR5z1uk1GL2m/u+ud2iFAr5gK6VI=

pkg/git/provider_gitlab.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ package git
1616

1717
import (
1818
"context"
19+
"encoding/json"
1920
"errors"
2021
"fmt"
22+
"io"
2123
"net/http"
2224
"net/url"
2325
"path"
26+
"strings"
2427

2528
apgit "github.com/argoproj-labs/argocd-autopilot/pkg/git"
2629
httputil "github.com/codefresh-io/cli-v2/pkg/util/http"
@@ -32,6 +35,11 @@ type (
3235
apiURL *url.URL
3336
c *http.Client
3437
}
38+
39+
gitlabUserResponse struct {
40+
Username string `json:"username"`
41+
Bot bool `json:"bot"`
42+
}
3543
)
3644

3745
const (
@@ -81,6 +89,16 @@ func (g *gitlab) VerifyUserToken(ctx context.Context, auth apgit.Auth) error {
8189
// if it returns 400 - the token has "api" scope
8290
// otherwise - the token does not have the scope
8391
func (g *gitlab) checkApiScope(ctx context.Context, token string) error {
92+
93+
tokenType, err := g.checkTokenType(token, ctx)
94+
if err != nil {
95+
return fmt.Errorf("failed checking api scope: %w", err)
96+
}
97+
98+
if tokenType == "project" {
99+
return errors.New("runtime git-token is invalid, project token is not exceptable")
100+
}
101+
84102
res, err := g.request(ctx, token, http.MethodPost, "projects")
85103
if err != nil {
86104
return fmt.Errorf("failed checking api scope: %w", err)
@@ -94,6 +112,35 @@ func (g *gitlab) checkApiScope(ctx context.Context, token string) error {
94112
return nil
95113
}
96114

115+
func (g *gitlab) checkTokenType(token string, ctx context.Context) (string, error) {
116+
userRes, err := g.request(ctx, token, http.MethodGet, "user")
117+
118+
if err != nil {
119+
return "", fmt.Errorf("failed getting user: %w", err)
120+
}
121+
122+
defer userRes.Body.Close()
123+
124+
bodyBytes, err := io.ReadAll(userRes.Body)
125+
if err != nil {
126+
return "", fmt.Errorf("failed reading user body: %w", err)
127+
}
128+
129+
var user gitlabUserResponse
130+
err = json.Unmarshal(bodyBytes, &user)
131+
if err != nil {
132+
return "", fmt.Errorf("failed parse user body: %w", err)
133+
}
134+
if user.Bot {
135+
if strings.HasPrefix(user.Username, "project") {
136+
return "project", nil
137+
}
138+
return "group", nil
139+
}
140+
141+
return "personal", nil
142+
}
143+
97144
// HEAD to projects.
98145
// if it returns 200 - the token has "repo_read" scope
99146
// otherwise - the token does not have the scope

pkg/git/provider_gitlab_test.go

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ package git
1616

1717
import (
1818
"context"
19+
"encoding/json"
1920
"errors"
21+
"io"
2022
"net/http"
23+
"strings"
2124
"testing"
2225

2326
"github.com/codefresh-io/cli-v2/pkg/git/mocks"
@@ -38,22 +41,70 @@ func Test_gitlab_checkApiScope(t *testing.T) {
3841
wantErr string
3942
beforeFn func(t *testing.T, c *mocks.MockRoundTripper)
4043
}{
41-
"Should fail if POST fails": {
44+
"Should fail if POST projects fails": {
4245
wantErr: "failed checking api scope: Post \"https://some.server/api/v4/projects\": some error",
46+
beforeFn: func(_ *testing.T, c *mocks.MockRoundTripper) {
47+
c.EXPECT().RoundTrip(gomock.AssignableToTypeOf(&http.Request{})).Times(1).DoAndReturn(func(req *http.Request) (*http.Response, error) {
48+
assert.Equal(t, "GET", req.Method)
49+
assert.Equal(t, "https://some.server/api/v4/user", req.URL.String())
50+
body, _ := json.Marshal(&gitlabUserResponse{
51+
Username: "username",
52+
Bot: false,
53+
})
54+
bodyReader := io.NopCloser(strings.NewReader(string(body[:])))
55+
res := &http.Response{
56+
StatusCode: 200,
57+
Body: bodyReader,
58+
}
59+
return res, nil
60+
})
61+
c.EXPECT().RoundTrip(gomock.AssignableToTypeOf(&http.Request{})).Return(nil, errors.New("some error"))
62+
},
63+
},
64+
"Should fail if GET user fails": {
65+
wantErr: "failed checking api scope: failed getting user: Get \"https://some.server/api/v4/user\": some error",
4366
beforeFn: func(_ *testing.T, c *mocks.MockRoundTripper) {
4467
c.EXPECT().RoundTrip(gomock.AssignableToTypeOf(&http.Request{})).Return(nil, errors.New("some error"))
4568
},
4669
},
4770
"Should fail if POST fails with 403": {
4871
wantErr: "git-token is invalid or missing required \"api\" scope",
4972
beforeFn: func(_ *testing.T, c *mocks.MockRoundTripper) {
73+
c.EXPECT().RoundTrip(gomock.AssignableToTypeOf(&http.Request{})).Times(1).DoAndReturn(func(req *http.Request) (*http.Response, error) {
74+
assert.Equal(t, "GET", req.Method)
75+
assert.Equal(t, "https://some.server/api/v4/user", req.URL.String())
76+
body, _ := json.Marshal(&gitlabUserResponse{
77+
Username: "username",
78+
Bot: false,
79+
})
80+
bodyReader := io.NopCloser(strings.NewReader(string(body[:])))
81+
res := &http.Response{
82+
StatusCode: 200,
83+
Body: bodyReader,
84+
}
85+
return res, nil
86+
})
5087
c.EXPECT().RoundTrip(gomock.AssignableToTypeOf(&http.Request{})).Times(1).Return(&http.Response{
5188
StatusCode: http.StatusForbidden,
5289
}, nil)
5390
},
5491
},
5592
"Should succeed if POST returns 400": {
5693
beforeFn: func(t *testing.T, c *mocks.MockRoundTripper) {
94+
c.EXPECT().RoundTrip(gomock.AssignableToTypeOf(&http.Request{})).Times(1).DoAndReturn(func(req *http.Request) (*http.Response, error) {
95+
assert.Equal(t, "GET", req.Method)
96+
assert.Equal(t, "https://some.server/api/v4/user", req.URL.String())
97+
body, _ := json.Marshal(&gitlabUserResponse{
98+
Username: "username",
99+
Bot: false,
100+
})
101+
bodyReader := io.NopCloser(strings.NewReader(string(body[:])))
102+
res := &http.Response{
103+
StatusCode: 200,
104+
Body: bodyReader,
105+
}
106+
return res, nil
107+
})
57108
c.EXPECT().RoundTrip(gomock.AssignableToTypeOf(&http.Request{})).Times(1).DoAndReturn(func(req *http.Request) (*http.Response, error) {
58109
assert.Equal(t, "POST", req.Method)
59110
assert.Equal(t, "https://some.server/api/v4/projects", req.URL.String())

0 commit comments

Comments
 (0)