Skip to content

Commit 05bc518

Browse files
add skip-permissions-validation flag (#671)
* add skip-permissions-validation flag and auto skip for fine-grained token * fix bbs validate check * if using new fine-grained token throw and error to use skip permission flag * if using new fine-grained token throw and error to use skip permission flag * bump * wip * auto skip permissions validation for upgrade and uninstall * auto skip permissions validation for upgrade and uninstall * mark flag hidden * bump * resolve conflicts
1 parent f1ac2ab commit 05bc518

File tree

9 files changed

+126
-16
lines changed

9 files changed

+126
-16
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.30
1+
VERSION=v0.1.31
22

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

cmd/commands/common.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ func getValueFromUserInput(label, defaultValue string, validate promptui.Validat
280280
}
281281

282282
// ensureGitRuntimeToken gets the runtime token from the user (if !silent), and verifys it with he provider (if available)
283-
func ensureGitRuntimeToken(cmd *cobra.Command, gitProvider cfgit.Provider, cloneOpts *apgit.CloneOptions) error {
283+
func ensureGitRuntimeToken(cmd *cobra.Command, gitProvider cfgit.Provider, cloneOpts *apgit.CloneOptions, skipPermissionsValidation bool) error {
284284
ctx := cmd.Context()
285285
errMessage := "Value stored in environment variable GIT_TOKEN is invalid; enter a valid runtime token: %w"
286286
if cloneOpts.Auth.Password == "" && !store.Get().Silent {
@@ -292,7 +292,12 @@ func ensureGitRuntimeToken(cmd *cobra.Command, gitProvider cfgit.Provider, clone
292292
}
293293

294294
if gitProvider != nil {
295-
err := gitProvider.VerifyRuntimeToken(ctx, cloneOpts.Auth)
295+
var err error
296+
if skipPermissionsValidation {
297+
err = gitProvider.ValidateToken(ctx, cloneOpts.Auth)
298+
} else {
299+
err = gitProvider.VerifyRuntimeToken(ctx, cloneOpts.Auth)
300+
}
296301
if err != nil {
297302
// in case when we get invalid value from env variable TOKEN we clean
298303
cloneOpts.Auth.Password = ""

cmd/commands/runtime.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ func runtimeUninstallCommandPreRunHandler(cmd *cobra.Command, args []string, opt
187187
}
188188

189189
if !opts.Managed {
190-
err = ensureGitRuntimeToken(cmd, nil, opts.CloneOpts)
190+
err = ensureGitRuntimeToken(cmd, nil, opts.CloneOpts, true)
191191
}
192192

193193
handleCliStep(reporter.UninstallStepPreCheckEnsureGitToken, "Getting git token", err, true, false)
@@ -230,7 +230,7 @@ func runtimeUpgradeCommandPreRunHandler(cmd *cobra.Command, args []string, opts
230230
return err
231231
}
232232

233-
err = ensureGitRuntimeToken(cmd, nil, opts.CloneOpts)
233+
err = ensureGitRuntimeToken(cmd, nil, opts.CloneOpts, true)
234234
handleCliStep(reporter.UpgradeStepPreCheckEnsureGitToken, "Getting git token", err, true, false)
235235
if err != nil {
236236
return err

cmd/commands/runtime_install.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,14 @@ type (
111111
SkipIngress bool
112112
BypassIngressClassCheck bool
113113

114-
versionStr string
115-
kubeContext string
116-
kubeconfig string
117-
gitProvider cfgit.Provider
118-
useGatewayAPI bool
119-
featuresToInstall []runtime.InstallFeature
120-
runtimeDef string
114+
versionStr string
115+
kubeContext string
116+
kubeconfig string
117+
gitProvider cfgit.Provider
118+
useGatewayAPI bool
119+
featuresToInstall []runtime.InstallFeature
120+
runtimeDef string
121+
SkipPermissionsValidation bool
121122
}
122123

123124
CreateIngressOptions struct {
@@ -278,6 +279,7 @@ func NewRuntimeInstallCommand() *cobra.Command {
278279
cmd.Flags().StringVar(&installationOpts.TunnelRegisterHost, "tunnel-register-host", "register-tunnels.cf-cd.com", "The host name for registering a new tunnel")
279280
cmd.Flags().StringVar(&installationOpts.TunnelDomain, "tunnel-domain", "tunnels.cf-cd.com", "The base domain for the tunnels")
280281
cmd.Flags().StringVar(&installationOpts.IpsAllowList, "ips-allow-list", "", "lists the rules to configure which IP addresses (IPv4/IPv6) and subnet masks can access your client (e.g \"192.168.0.0/16, FE80:CD00:0000:0CDE:1257::/64\")")
282+
cmd.Flags().BoolVar(&installationOpts.SkipPermissionsValidation, "skip-permissions-validation", false, "Skip personal access token permissions validation (default: false)")
281283

282284
installationOpts.InsCloneOpts = apu.AddCloneFlags(cmd, &apu.CloneFlagsOptions{
283285
CreateIfNotExist: true,
@@ -299,6 +301,7 @@ func NewRuntimeInstallCommand() *cobra.Command {
299301
util.Die(cmd.Flags().MarkHidden("ips-allow-list"))
300302
util.Die(cmd.Flags().MarkHidden("runtime-def"))
301303
util.Die(cmd.Flags().MarkHidden("set-default-resources"))
304+
util.Die(cmd.Flags().MarkHidden("skip-permissions-validation"))
302305
cmd.MarkFlagsMutuallyExclusive("runtime-def", "version")
303306
cmd.MarkFlagsMutuallyExclusive("runtime-def", "set-default-resources")
304307

@@ -467,10 +470,10 @@ func getGitToken(cmd *cobra.Command, opts *RuntimeInstallOptions) error {
467470
var err error
468471

469472
if store.Get().Silent {
470-
err = ensureGitRuntimeToken(cmd, opts.gitProvider, opts.InsCloneOpts)
473+
err = ensureGitRuntimeToken(cmd, opts.gitProvider, opts.InsCloneOpts, opts.SkipPermissionsValidation)
471474
} else {
472475
handleValidationFailsWithRepeat(func() error {
473-
err = ensureGitRuntimeToken(cmd, opts.gitProvider, opts.InsCloneOpts)
476+
err = ensureGitRuntimeToken(cmd, opts.gitProvider, opts.InsCloneOpts, opts.SkipPermissionsValidation)
474477
if isValidationError(err) {
475478
fmt.Println(err)
476479
return err
@@ -1548,6 +1551,7 @@ func configureAppProxy(ctx context.Context, opts *RuntimeInstallOptions, rt *run
15481551
fmt.Sprintf("cfHost=%s", cfConfig.GetCurrentContext().URL),
15491552
fmt.Sprintf("cors=%s", cfConfig.GetCurrentContext().URL),
15501553
"env=production",
1554+
fmt.Sprintf("skipPermissionsValidation=%v", opts.SkipPermissionsValidation),
15511555
}
15521556

15531557
// configure codefresh host

pkg/git/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type (
4242
Type() ProviderType
4343
VerifyRuntimeToken(ctx context.Context, auth apgit.Auth) error
4444
VerifyUserToken(ctx context.Context, auth apgit.Auth) error
45+
ValidateToken(ctx context.Context, auth apgit.Auth) error
4546
}
4647
)
4748

pkg/git/provider_bitbucket-server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ func (bbs *bitbucketServer) Type() ProviderType {
7272
return bbs.providerType
7373
}
7474

75+
func (bbs *bitbucketServer) ValidateToken(ctx context.Context, auth apgit.Auth) error {
76+
_, err := bbs.getCurrentUsername(ctx, auth.Password)
77+
if err != nil {
78+
return fmt.Errorf("failed validate token: %w", err)
79+
}
80+
81+
return nil
82+
}
83+
7584
func (bbs *bitbucketServer) VerifyRuntimeToken(ctx context.Context, auth apgit.Auth) error {
7685
return bbs.checkProjectAdminPermission(ctx, auth.Password)
7786
}

pkg/git/provider_bitbucket.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,24 @@ func (bb *bitbucket) VerifyUserToken(ctx context.Context, auth apgit.Auth) error
110110
return bb.verifyToken(ctx, auth.Password, auth.Username, patScopes)
111111
}
112112

113+
func (bb *bitbucket) ValidateToken(ctx context.Context, auth apgit.Auth) error {
114+
if auth.Username == "" {
115+
return fmt.Errorf("user name is require for bitbucket cloud request")
116+
}
117+
118+
res, err := bb.request(ctx, auth.Username, auth.Password, http.MethodHead, "user", nil)
119+
if err != nil {
120+
return fmt.Errorf("failed getting current user: %w", err)
121+
}
122+
123+
defer res.Body.Close()
124+
125+
if res.StatusCode == 401 {
126+
return fmt.Errorf("invalid token")
127+
}
128+
return nil
129+
}
130+
113131
func (bb *bitbucket) verifyToken(ctx context.Context, token string, username string, requiredScopes [][]string) error {
114132
scopes, err := bb.getCurrentUserScopes(ctx, token, username)
115133
if err != nil {

pkg/git/provider_github.go

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,16 @@ func (g *github) Type() ProviderType {
8585
}
8686

8787
func (g *github) VerifyRuntimeToken(ctx context.Context, auth apgit.Auth) error {
88-
err := g.verifyToken(ctx, auth.Password, runtime_token_scopes)
88+
tokenType, err := g.getTokenType(auth.Password)
89+
if err != nil {
90+
return fmt.Errorf("failed getting token type: %w", err)
91+
}
92+
93+
if tokenType == "fine-grained" {
94+
return fmt.Errorf("validation for github fine-grained PAT is not supported yet, please retry with --skip-permissions-validation or use a classic token")
95+
}
96+
97+
err = g.verifyToken(ctx, auth.Password, runtime_token_scopes)
8998
if err != nil {
9099
return fmt.Errorf("git-token invalid: %w", err)
91100
}
@@ -94,14 +103,59 @@ func (g *github) VerifyRuntimeToken(ctx context.Context, auth apgit.Auth) error
94103
}
95104

96105
func (g *github) VerifyUserToken(ctx context.Context, auth apgit.Auth) error {
97-
err := g.verifyToken(ctx, auth.Password, user_token_scopes)
106+
tokenType, err := g.getTokenType(auth.Password)
107+
if err != nil {
108+
return fmt.Errorf("failed getting token type: %w", err)
109+
}
110+
111+
if tokenType == "fine-grained" {
112+
return fmt.Errorf("validation for github fine-grained PAT is not supported yet, please retry with --skip-permissions-validation or use a classic token")
113+
}
114+
115+
err = g.verifyToken(ctx, auth.Password, user_token_scopes)
98116
if err != nil {
99117
return fmt.Errorf("personal-git-token invalid: %w", err)
100118
}
101119

102120
return nil
103121
}
104122

123+
func (g *github) ValidateToken(ctx context.Context, auth apgit.Auth) error {
124+
if auth.Password == "" {
125+
return fmt.Errorf("user name is require for bitbucket cloud request")
126+
}
127+
128+
reqHeaders := map[string]string{
129+
"Authorization": "token " + auth.Password,
130+
}
131+
req, err := httputil.NewRequest(ctx, http.MethodHead, g.apiURL.String(), reqHeaders, nil)
132+
if err != nil {
133+
return err
134+
}
135+
136+
res, err := g.c.Do(req)
137+
if err != nil {
138+
return err
139+
}
140+
defer res.Body.Close()
141+
142+
if res.StatusCode == 401 {
143+
return fmt.Errorf("invalid token")
144+
}
145+
return nil
146+
147+
}
148+
149+
func (g *github) getTokenType(token string) (string, error) {
150+
if token == "" {
151+
return "", errors.New("missing token")
152+
}
153+
if strings.HasPrefix(token, "github_pat") {
154+
return "fine-grained", nil
155+
}
156+
return "classic", nil
157+
}
158+
105159
func (g *github) verifyToken(ctx context.Context, token string, requiredScopes []string) error {
106160
reqHeaders := map[string]string{
107161
"Authorization": "token " + token,

pkg/git/provider_gitlab.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,25 @@ func (g *gitlab) VerifyUserToken(ctx context.Context, auth apgit.Auth) error {
8585
return g.checkReadRepositoryScope(ctx, auth.Password)
8686
}
8787

88+
func (g *gitlab) ValidateToken(ctx context.Context, auth apgit.Auth) error {
89+
if auth.Password == "" {
90+
return fmt.Errorf("user name is require for bitbucket cloud request")
91+
}
92+
93+
res, err := g.request(ctx, auth.Password, http.MethodHead, "user")
94+
95+
if err != nil {
96+
return fmt.Errorf("failed getting user: %w", err)
97+
}
98+
99+
defer res.Body.Close()
100+
101+
if res.StatusCode == 401 {
102+
return fmt.Errorf("invalid token")
103+
}
104+
return nil
105+
}
106+
88107
// POST to projects without a body.
89108
// if it returns 400 - the token has "api" scope
90109
// otherwise - the token does not have the scope

0 commit comments

Comments
 (0)