Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/.codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ coverage:
status:
project:
default:
target: 70%
target: 70%
patch:
default:
target: 80%
5 changes: 1 addition & 4 deletions .github/workflows/license-checker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,4 @@ permissions:

jobs:
check-license:
permissions:
contents: write
pull-requests: write
uses: notaryproject/notation-core-go/.github/workflows/reusable-license-checker.yml@main
uses: notaryproject/notation-core-go/.github/workflows/reusable-license-checker.yml@main
9 changes: 7 additions & 2 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@ on:
schedule:
- cron: "30 1 * * *"

permissions:
contents: read

jobs:
stale:
permissions:
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
- uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0
with:
stale-issue-message: "This issue is stale because it has been opened for 60 days with no activity. Remove stale label or comment. Otherwise, it will be closed in 30 days."
stale-pr-message: "This PR is stale because it has been opened for 45 days with no activity. Remove stale label or comment. Otherwise, it will be closed in 30 days."
Expand All @@ -31,4 +37,3 @@ jobs:
days-before-issue-close: 30
days-before-pr-close: 30
exempt-all-milestones: true

27 changes: 27 additions & 0 deletions cmd/notation/internal/truststore/testdata/NotationTestRoot.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEizCCAvOgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzEL
MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEb
MBkGA1UEAxMSTm90YXRpb24gVGVzdCBSb290MCAXDTIwMDkwOTA3MDAwMFoYDzIx
MjIwOTA1MjAzODQ1WjBaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNV
BAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEbMBkGA1UEAxMSTm90YXRpb24g
VGVzdCBSb290MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAxxAZ8VZe
gqBUctz3BkwhObZKnW+KsN5/N1/u2vPLmEzHDj6xgd8Hn0JoughDaxeQCV66NC2o
bqPnPp4+68G/qZnxkXVXdFyqVodu4FgPUjiqcJjft7bh45BVgLFpOqSqDQ3ko30B
7gdGfIIkoBj/8gz3tHnmIvl3MywtOhDeGnlLNzBY52wVmhPIdKOaW/7WkMrXKFCk
LkNICGnIpWuyBtC+7RfM8hG6eRW1KCm5xrkRmn5ptonjxix/JTGj4me/NMkwdVkz
6wcCSAJnqTgHi2oqk73qqNu0LHsEMFBF8IGqmVkn2MOHkFamPBokzQ6HXXfvR4nb
cWQZCUgRinPTVg9CF0B6XSCEMCSH5kveZxTQtAFRB6NosbzuU5jDmJgpbDfauev7
Eg/6bZzphcugRkVuwulymzsake5Jbvs9Kyw3CNPYH2G3Kli1FNhfc46ugXHbIfXg
NQcou3xabcu+r6cFRqqK6NmV9ouMQRj8Ri95Gp2BUlpTEFhcvMb9d4nXAgMBAAGj
WjBYMA4GA1UdDwEB/wQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDAzASBgNVHRMB
Af8ECDAGAQH/AgEBMB0GA1UdDgQWBBS5FZjt9UsEPkcKrStrnjSpTq4kDTANBgkq
hkiG9w0BAQsFAAOCAYEAKtxfv12LzM85bxOMp5++pIDa6eMcBaurYbAM2yC9B6Lu
Hf0JGeFdNqt4Fw38Ajooj2vWMWBrARVEZRVqTC5+ZSN2meGBXBXlT4n8FdEdmv+0
5iwVYdmDFp8FKeoOZZZF23u+r2OrazJo1ufWmoSI2P0lEfZQQFQElltWu3QH+OLO
WXJmB7KbLKyheelGK5XhtAYYapRdW4sKJ398ybpv5C1oALCcTwoSmvH8wW5J4/gj
mhKICYh2goMauf0lesdxj+0His7E8blOWrUmfOB5dp73XawLKcd/UxHN8zAPC08L
DL9NMcihn3ZHKi7/dtkiV2iSaDPD1ChSGdqfXIysYqOhYoktgAfBZ43CWnqQhgB8
NezRKdOStYC3P2AGJW18irxxTRp2CO+gnXEcyhyr+cvyf0j8MkRSaHLXzjIrECu8
BUitB6sKughdN13fs5t5SIiO6foeFdvIpZFFKO8s+4oTOSDCos2WFoC+8TZS6r58
3OtFLmywl1HRgQkobGgw
-----END CERTIFICATE-----
1 change: 1 addition & 0 deletions cmd/notation/internal/truststore/testdata/invalid.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invalid test cert
20 changes: 20 additions & 0 deletions cmd/notation/internal/truststore/testdata/self-signed.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDPjCCAiagAwIBAgIBeTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEL
MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEP
MA0GA1UEAxMGYWxwaW5lMB4XDTIzMDUwOTA0NTUxMloXDTMzMDUxMDA0NTUxMlow
TjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8w
DQYDVQQKEwZOb3RhcnkxDzANBgNVBAMTBmFscGluZTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAK5hpq1229GGLjMK6i9KZhuUO+SV7rUFnWIDiIPO5yWx
YDkl+bGroeAvJYu6MVCMQ6FMRXD9jhnG6R+sAHwY7gVgcJ1OXak87PkLp/Ii1Cr7
XkkySZeD+Br1vSQzfxs3pFG+iBCeVVkeZdsg+xqwnAlqAILXwIbTGRyJP1Xiu9nw
OeuX1YmxPl2m29Pt1EtfVCL9COsVKt5LgOVyWP/9ISWevOBqSCU9bk35HFo9VTeU
f6+ffhSMjv0Y9uwkFFOKXpcV8Sa3ArqyBmgQlUfGg1iwYlqiDE0fTYxiB3gLgETA
lmTm50J+WB9LoDrnrQpbXFLoegm+JV+uSD8J8H7DL2sCAwEAAaMnMCUwDgYDVR0P
AQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IB
AQAt0Nvna1c4pPn8kzoN5VvmFmeIgdO/BJpmdhdg0WIQ9aeN/xPXXaVjPp1Mk7ed
XHAvBwQr0Gyzqyy7g/h0gdnAFG7f6blrRNzbrRBCq6cNqX8iwgK/9+2OYKxk1QWj
8Gx0cvu1DN1aXjPPGgQ2j3tHjJvJv32J/zuZa8gU40RPPSLaBlc5ZjpFmyi29sKl
TeeZ+F/Ssic51qXXw2CsYGGWK5yQ3xSCxbw6bb2G/s/YI7/KlWg9BktBJHzRu04Z
NR77W7/dyJ3Lj17PlW1XKmMOFHsQivagXeRCbmYZ43fX4ugFRFKL7KE0EgmGOWpJ
0xv+6ig93sqHzQ/0uv1YgFov
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDPjCCAiagAwIBAgIBeTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEL
MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEP
MA0GA1UEAxMGYWxwaW5lMB4XDTIzMDUwOTA0NTUxMloXDTMzMDUxMDA0NTUxMlow
TjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8w
DQYDVQQKEwZOb3RhcnkxDzANBgNVBAMTBmFscGluZTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAK5hpq1229GGLjMK6i9KZhuUO+SV7rUFnWIDiIPO5yWx
YDkl+bGroeAvJYu6MVCMQ6FMRXD9jhnG6R+sAHwY7gVgcJ1OXak87PkLp/Ii1Cr7
XkkySZeD+Br1vSQzfxs3pFG+iBCeVVkeZdsg+xqwnAlqAILXwIbTGRyJP1Xiu9nw
OeuX1YmxPl2m29Pt1EtfVCL9COsVKt5LgOVyWP/9ISWevOBqSCU9bk35HFo9VTeU
f6+ffhSMjv0Y9uwkFFOKXpcV8Sa3ArqyBmgQlUfGg1iwYlqiDE0fTYxiB3gLgETA
lmTm50J+WB9LoDrnrQpbXFLoegm+JV+uSD8J8H7DL2sCAwEAAaMnMCUwDgYDVR0P
AQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IB
AQAt0Nvna1c4pPn8kzoN5VvmFmeIgdO/BJpmdhdg0WIQ9aeN/xPXXaVjPp1Mk7ed
XHAvBwQr0Gyzqyy7g/h0gdnAFG7f6blrRNzbrRBCq6cNqX8iwgK/9+2OYKxk1QWj
8Gx0cvu1DN1aXjPPGgQ2j3tHjJvJv32J/zuZa8gU40RPPSLaBlc5ZjpFmyi29sKl
TeeZ+F/Ssic51qXXw2CsYGGWK5yQ3xSCxbw6bb2G/s/YI7/KlWg9BktBJHzRu04Z
NR77W7/dyJ3Lj17PlW1XKmMOFHsQivagXeRCbmYZ43fX4ugFRFKL7KE0EgmGOWpJ
0xv+6ig93sqHzQ/0uv1YgFov
-----END CERTIFICATE-----
2 changes: 1 addition & 1 deletion cmd/notation/internal/truststore/truststore.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func DeleteCert(storeType, namedStore, cert string, confirmed bool) error {
return nil
}

// CheckNonErrNotExistError returns nil when no err or err is fs.ErrNotExist
// CheckNonErrNotExistError returns nil when err is nil or err is fs.ErrNotExist
func CheckNonErrNotExistError(err error) error {
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return err
Expand Down
106 changes: 99 additions & 7 deletions cmd/notation/internal/truststore/truststore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,107 @@ package truststore

import (
"errors"
"os"
"path/filepath"
"runtime"
"strings"
"testing"

"github.com/notaryproject/notation-go/dir"
)

func TestEmptyCertFile(t *testing.T) {
path := filepath.FromSlash("../../../../internal/testdata/Empty.txt")
expectedErr := errors.New("no valid certificate found in the empty file")
err := AddCert(path, "ca", "test", false)
if err == nil || err.Error() != "no valid certificate found in the file" {
t.Fatalf("expected err: %v, got: %v", expectedErr, err)
}
func TestAddCert(t *testing.T) {
defer func(oldDir string) {
dir.UserConfigDir = oldDir
}(dir.UserConfigDir)

t.Run("empty store type", func(t *testing.T) {
expectedErrMsg := "store type cannot be empty"
err := AddCert("", "", "test", false)
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err)
}
})

t.Run("invalid store type", func(t *testing.T) {
expectedErrMsg := "unsupported store type: invalid"
err := AddCert("", "invalid", "test", false)
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err)
}
})

t.Run("invalid store name", func(t *testing.T) {
expectedErrMsg := "named store name needs to follow [a-zA-Z0-9_.-]+ format"
err := AddCert("", "ca", "test%", false)
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err)
}
})

t.Run("no valid certificate in file", func(t *testing.T) {
path := filepath.FromSlash("testdata/invalid.txt")
expectedErrMsg := "x509: malformed certificate"
err := AddCert(path, "ca", "test", false)
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err)
}
})

t.Run("cert already exists", func(t *testing.T) {
dir.UserConfigDir = "testdata"
path := filepath.FromSlash("testdata/self-signed.crt")
expectedErrMsg := "certificate already exists in the Trust Store"
err := AddCert(path, "ca", "test", false)
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err)
}
})

t.Run("empty file", func(t *testing.T) {
path := filepath.FromSlash("../../../../internal/testdata/Empty.txt")
expectedErr := errors.New("no valid certificate found in the empty file")
err := AddCert(path, "ca", "test", false)
if err == nil || err.Error() != "no valid certificate found in the file" {
t.Fatalf("expected err: %v, but got: %v", expectedErr, err)
}
})

t.Run("failed to add cert to store", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping test on Windows")
}

dir.UserConfigDir = t.TempDir()
if err := os.Chmod(dir.UserConfigDir, 0000); err != nil {
t.Fatal(err)
}
defer os.Chmod(dir.UserConfigDir, 0700)

path := filepath.FromSlash("testdata/NotationTestRoot.pem")
expectedErrMsg := "permission denied"
err := AddCert(path, "ca", "test", false)
if err == nil || !strings.Contains(err.Error(), expectedErrMsg) {
t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err)
}
})
}

func TestDeleteAllCerts(t *testing.T) {
defer func(oldDir string) {
dir.UserConfigDir = oldDir
}(dir.UserConfigDir)

t.Run("store does not exist", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping test on Windows")
}

dir.UserConfigDir = "testdata"
expectedErrMsg := `stat testdata/truststore/x509/tsa/test: no such file or directory`
err := DeleteAllCerts("tsa", "test", true)
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err)
}
})
}
2 changes: 1 addition & 1 deletion cmd/notation/plugin/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func install(command *cobra.Command, opts *pluginInstallOpts) error {
}
pluginURL, err := url.Parse(opts.pluginSource)
if err != nil {
return fmt.Errorf("failed to parse plugin download URL %s with error: %w", pluginURL, err)
return fmt.Errorf("failed to parse plugin download URL %s with error: %w", opts.pluginSource, err)
}
if pluginURL.Scheme != "https" {
return fmt.Errorf("failed to download plugin from URL: only the HTTPS scheme is supported, but got %s", pluginURL.Scheme)
Expand Down
96 changes: 96 additions & 0 deletions cmd/notation/plugin/install_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// 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 plugin

import (
"context"
"os"
"path/filepath"
"runtime"
"strings"
"testing"

notationplugin "github.com/notaryproject/notation/cmd/notation/internal/plugin"
"github.com/notaryproject/notation/internal/osutil"
"github.com/spf13/cobra"
)

func TestInstall(t *testing.T) {
t.Run("invalid plugin source url", func(t *testing.T) {
opts := &pluginInstallOpts{
pluginSourceType: notationplugin.PluginSourceTypeURL,
inputChecksum: "dummy",
pluginSource: "http://[::1]/%",
}
expectedErrMsg := `failed to parse plugin download URL http://[::1]/% with error: parse "http://[::1]/%": invalid URL escape "%"`
err := install(&cobra.Command{}, opts)
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected error %s, but got %s", expectedErrMsg, err)
}
})

t.Run("unknown plugin source type", func(t *testing.T) {
opts := &pluginInstallOpts{
pluginSourceType: -1,
}
expectedErrMsg := `plugin installation failed: unknown plugin source type`
err := install(&cobra.Command{}, opts)
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected error %s, but got %s", expectedErrMsg, err)
}
})
}

func TestInstallPlugin(t *testing.T) {
ctx := context.Background()
t.Run("input path does not exist", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping test on Windows")
}
expectedErrMsg := `stat invalid: no such file or directory`
err := installPlugin(ctx, "invalid", "", false)
if err == nil || err.Error() != expectedErrMsg {
t.Fatalf("expected error %s, but got %s", expectedErrMsg, err)
}
})

t.Run("failed to get file type", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping test on Windows")
}

tempDir := t.TempDir()
data := []byte("data")
filename := filepath.Join(tempDir, "a", "file.txt")
if err := osutil.WriteFile(filename, data); err != nil {
t.Fatal(err)
}
err := os.Chmod(tempDir, 0)
if err != nil {
t.Fatal(err)
}
defer func() {
err := os.Chmod(tempDir, 0700)
if err != nil {
t.Fatal(err)
}
}()

expectedErrMsg := `permission denied`
err = installPlugin(ctx, filename, "", false)
if err == nil || !strings.Contains(err.Error(), expectedErrMsg) {
t.Fatalf("expected permission denied error, but got %s", err)
}
})
}
1 change: 1 addition & 0 deletions internal/trace/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func WithLoggerLevel(ctx context.Context, level logrus.Level) context.Context {

// create logger
logger := logrus.New()
formatter.DisableQuote = true
logger.SetFormatter(&formatter)
logger.SetLevel(level)

Expand Down
Loading