diff --git a/app/gitspace/orchestrator/git/git_impl.go b/app/gitspace/orchestrator/git/git_impl.go index a271d4d6b..5fb9fe1dc 100644 --- a/app/gitspace/orchestrator/git/git_impl.go +++ b/app/gitspace/orchestrator/git/git_impl.go @@ -71,7 +71,7 @@ func (g *ServiceImpl) SetupCredentials( ) error { script, err := template.GenerateScriptFromTemplate( templateSetupGitCredentials, &template.SetupGitCredentialsPayload{ - CloneURLWithCreds: resolvedRepoDetails.CloneURL, + CloneURLWithCreds: resolvedRepoDetails.CloneURL.Value(), }) if err != nil { return fmt.Errorf( @@ -94,7 +94,7 @@ func (g *ServiceImpl) CloneCode( defaultBaseImage string, gitspaceLogger types.GitspaceLogger, ) error { - cloneURL, err := url.Parse(resolvedRepoDetails.CloneURL) + cloneURL, err := url.Parse(resolvedRepoDetails.CloneURL.Value()) if err != nil { return fmt.Errorf( "failed to parse clone url %s: %w", resolvedRepoDetails.CloneURL, err) @@ -108,7 +108,7 @@ func (g *ServiceImpl) CloneCode( } if resolvedRepoDetails.ResolvedCredentials.Credentials != nil { data.Email = resolvedRepoDetails.Credentials.Email - data.Name = resolvedRepoDetails.Credentials.Name + data.Name = resolvedRepoDetails.Credentials.Name.Value() } script, err := template.GenerateScriptFromTemplate( templateCloneCode, data) diff --git a/app/gitspace/scm/gitness_scm.go b/app/gitspace/scm/gitness_scm.go index 203f810e0..c29a959b6 100644 --- a/app/gitspace/scm/gitness_scm.go +++ b/app/gitspace/scm/gitness_scm.go @@ -196,11 +196,11 @@ func (s *GitnessSCM) ResolveCredentials( } userInfo := url.UserPassword("harness", jwtToken) modifiedURL.User = userInfo - resolvedCredentails.CloneURL = modifiedURL.String() + resolvedCredentails.CloneURL = types.NewMaskSecret(modifiedURL.String()) credentials := &Credentials{ Email: user.Email, - Name: user.DisplayName, - Password: jwtToken, + Name: types.NewMaskSecret(user.DisplayName), + Password: types.NewMaskSecret(jwtToken), } resolvedCredentails.Credentials = credentials return resolvedCredentails, nil diff --git a/app/gitspace/scm/public_scm.go b/app/gitspace/scm/public_scm.go index 64b63b69d..8ddac7fd5 100644 --- a/app/gitspace/scm/public_scm.go +++ b/app/gitspace/scm/public_scm.go @@ -126,7 +126,7 @@ func (s *GenericSCM) ResolveCredentials( ) (*ResolvedCredentials, error) { var resolvedCredentials = &ResolvedCredentials{ Branch: gitspaceConfig.Branch, - CloneURL: gitspaceConfig.CodeRepo.URL, + CloneURL: types.NewMaskSecret(gitspaceConfig.CodeRepo.URL), } repoURL, err := url.Parse(gitspaceConfig.CodeRepo.URL) if err != nil { diff --git a/app/gitspace/scm/scm.go b/app/gitspace/scm/scm.go index 21fc4d852..f9c245b35 100644 --- a/app/gitspace/scm/scm.go +++ b/app/gitspace/scm/scm.go @@ -70,7 +70,7 @@ func (s *SCM) CheckValidCodeRepo( return nil, fmt.Errorf("failed to resolve repo credentials and URL: %w", err) } - if branch, err = s.detectBranch(ctx, resolvedCreds.CloneURL); err == nil { + if branch, err = s.detectBranch(ctx, resolvedCreds.CloneURL.Value()); err == nil { codeRepositoryResponse.Branch = branch } return codeRepositoryResponse, nil diff --git a/app/gitspace/scm/types.go b/app/gitspace/scm/types.go index d5ac4104b..d64801e30 100644 --- a/app/gitspace/scm/types.go +++ b/app/gitspace/scm/types.go @@ -43,13 +43,14 @@ type ( // by an automated login process. Credentials struct { Email string - Name string - Password string + Name *types.MaskSecret + Password *types.MaskSecret } ResolvedCredentials struct { - Branch string - CloneURL string + Branch string + // CloneURL contains credentials for private repositories in url prefix + CloneURL *types.MaskSecret Credentials *Credentials RepoName string } diff --git a/types/mask_secret.go b/types/mask_secret.go new file mode 100644 index 000000000..50e71ec96 --- /dev/null +++ b/types/mask_secret.go @@ -0,0 +1,73 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package types + +import ( + "crypto/sha256" + "encoding/json" + "fmt" +) + +const maxTruncatedLen = 8 + +// MaskSecret is a wrapper to store decrypted secrets in memory. This is help to prevent them +// from getting prints in logs and fmt. +type MaskSecret struct { + value string + hashedValue string +} + +func NewMaskSecret(val string) *MaskSecret { + hash := sha256.New() + hash.Write([]byte(val)) + + hashedValueStr := fmt.Sprintf("%x", hash.Sum(nil)) + + return &MaskSecret{ + value: val, + hashedValue: hashedValueStr[:maxTruncatedLen], + } +} + +// Value returns the unmasked value of the MaskSecret. +// Use cautiously to avoid exposing sensitive data. +func (s *MaskSecret) Value() string { + if s == nil { + return "" + } + return s.value +} + +func (s *MaskSecret) String() string { + if s == nil { + return "" + } + + return s.hashedValue +} + +func (s *MaskSecret) MarshalJSON() ([]byte, error) { + return json.Marshal(s.value) +} + +func (s *MaskSecret) UnmarshalJSON(data []byte) error { + var input string + if err := json.Unmarshal(data, &input); err != nil { + return err + } + + s.value = input + return nil +} diff --git a/types/platform_connector.go b/types/platform_connector.go index 9734d7df1..e993484de 100644 --- a/types/platform_connector.go +++ b/types/platform_connector.go @@ -81,10 +81,10 @@ type PlatformConnectorSpec struct { type PlatformConnectorAuthSpec struct { AuthType PlatformConnectorAuthType // userName can be empty when userName is encrypted. - UserName string + UserName *MaskSecret // UserNameRef can be empty when userName is not encrypted UserNameRef string - Password string + Password *MaskSecret PasswordRef string } @@ -103,7 +103,7 @@ func (c PlatformConnectorSpec) ExtractRegistryURL() string { func (c PlatformConnectorAuthSpec) ExtractUserName() string { if c.AuthType == UserNamePasswordPlatformConnectorAuthType { - return c.UserName + return c.UserName.Value() } return "" @@ -127,7 +127,7 @@ func (c PlatformConnectorAuthSpec) ExtractPasswordRef() string { func (c PlatformConnectorAuthSpec) ExtractPassword() string { if c.AuthType == UserNamePasswordPlatformConnectorAuthType { - return c.Password + return c.Password.Value() } return ""