Repository: notaryproject/notation (go)

Issue:
Making `NOTATION_USERNAME` and `NOTATION_PASSWORD` secure
### What is the areas you would like to add the new feature to?

Notation CLI

### Is your feature request related to a problem?

The environment variables `NOTATION_USERNAME` and `NOTATION_PASSWORD` are considered as insecure and not suitable for production since it is possible to leak them to its child processes like plugins.

### What solution do you propose?

Remove those environment variables when spawning child process (i.e. plugin process) while keeping other environment variables.

### What alternatives have you considered?

It is always good to configure a credential store.

### Any additional context?

_No response_

Pull request:
fix: unset NOTATION_USERNAME and NOTATION_PASSWORD to avoid leaking credentials to plugin
Fix:
- unset credentials env after read the value

Resolves #709 
Signed-off-by: Junjie Gao <junjiegao@microsoft.com>

Patch:
diff --git a/.github/workflows/add-to-project.yml b/.github/workflows/add-to-project.yml
index a06395d..ae1bc39 100644
--- a/.github/workflows/add-to-project.yml
+++ b/.github/workflows/add-to-project.yml
@@ -24,7 +24,7 @@ jobs:
     name: Add issue to project
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/add-to-project@0da8e46333d7b6e01d0e857452a1e99cb47be205 # main
+      - uses: actions/add-to-project@31b3f3ccdc584546fc445612dec3f38ff5edb41c # v0.5.0
         with:
           project-url: https://github.com/orgs/notaryproject/projects/10
-          github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
\ No newline at end of file
+          github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 84331ca..ff54e90 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -45,8 +45,8 @@ jobs:
           go-version: ${{ matrix.go-version }}
           check-latest: true
       - name: Initialize CodeQL
-        uses: github/codeql-action/init@f6e388ebf0efc915c6c5b165b019ee61a6746a38 # v2.20.1
+        uses: github/codeql-action/init@489225d82a57396c6f426a40e66d461b16b3461d # v2.20.4
         with:
           languages: go
       - name: Perform CodeQL Analysis
-        uses: github/codeql-action/analyze@f6e388ebf0efc915c6c5b165b019ee61a6746a38 # v2.20.1
+        uses: github/codeql-action/analyze@489225d82a57396c6f426a40e66d461b16b3461d # v2.20.4
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
index 8631561..30bc3c0 100644
--- a/.github/workflows/scorecard.yml
+++ b/.github/workflows/scorecard.yml
@@ -59,6 +59,6 @@ jobs:
           retention-days: 5
       
       - name: "Upload to code-scanning"
-        uses: github/codeql-action/upload-sarif@4c8f13758e748234abaa6a831d6f53981844a524 # tag=v2.1.26
+        uses: github/codeql-action/upload-sarif@489225d82a57396c6f426a40e66d461b16b3461d # v2.20.4
         with:
           sarif_file: results.sarif
diff --git a/cmd/notation/main.go b/cmd/notation/main.go
index 3ea4219..feb103a 100644
--- a/cmd/notation/main.go
+++ b/cmd/notation/main.go
@@ -26,6 +26,12 @@ func main() {
 		Use:          "notation",
 		Short:        "Notation - a tool to sign and verify artifacts",
 		SilenceUsage: true,
+		PersistentPreRun: func(cmd *cobra.Command, args []string) {
+			// unset registry credentials after read the value from environment
+			// to avoid leaking credentials
+			os.Unsetenv(defaultUsernameEnv)
+			os.Unsetenv(defaultPasswordEnv)
+		},
 	}
 	cmd.AddCommand(
 		signCommand(nil),


Test patch:
diff --git a/cmd/notation/main_test.go b/cmd/notation/main_test.go
new file mode 100644
index 0000000..6c7722a
--- /dev/null
+++ b/cmd/notation/main_test.go
@@ -0,0 +1,39 @@
+// Copyright The Notary Project Authors.
+// 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 main
+
+import (
+	"os"
+	"testing"
+)
+
+func Test_UnsetEnvCredential(t *testing.T) {
+	const notationUsername = "NOTATION_USERNAME"
+	const notationPassword = "NOTATION_PASSWORD"
+	// Set environment variables for testing
+	os.Setenv(notationUsername, "testuser")
+	os.Setenv(notationPassword, "testpassword")
+	os.Args = []string{"notation", "version"}
+
+	main()
+
+	// check credentials environment variables are unset
+	if os.Getenv(notationUsername) != "" {
+		t.Errorf("expected %s to be unset", notationUsername)
+	}
+
+	if os.Getenv(notationPassword) != "" {
+		t.Errorf("expected %s to be unset", notationPassword)
+	}
+}
diff --git a/test/e2e/plugin/main.go b/test/e2e/plugin/main.go
index 03d3967..622cb97 100644
--- a/test/e2e/plugin/main.go
+++ b/test/e2e/plugin/main.go
@@ -15,16 +15,31 @@ package main
 
 import (
 	"encoding/json"
+	"errors"
 	"os"
 
+	"github.com/notaryproject/notation-go/plugin/proto"
 	"github.com/spf13/cobra"
 )
 
+const NOTATION_USERNAME = "NOTATION_USERNAME"
+const NOTATION_PASSWORD = "NOTATION_PASSWORD"
+
 func main() {
 	cmd := &cobra.Command{
 		Use:           "plugin for Notation E2E test",
 		SilenceUsage:  true,
 		SilenceErrors: true,
+		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+			// check registry credentials are eliminated
+			if os.Getenv(NOTATION_USERNAME) != "" || os.Getenv(NOTATION_PASSWORD) != "" {
+				return &proto.RequestError{
+					Code: proto.ErrorCodeValidation,
+					Err:  errors.New("registry credentials are not eliminated"),
+				}
+			}
+			return nil
+		},
 	}
 
 	cmd.AddCommand(