github.com/containerd/nerdctl@v1.7.7/pkg/signutil/notationutil.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package signutil 18 19 import ( 20 "bufio" 21 "context" 22 "os" 23 "os/exec" 24 "strings" 25 26 "github.com/containerd/log" 27 "github.com/containerd/nerdctl/pkg/imgutil" 28 ) 29 30 // SignNotation signs an image(`rawRef`) using a notation key name (`keyNameRef`) 31 func SignNotation(rawRef string, keyNameRef string) error { 32 notationExecutable, err := exec.LookPath("notation") 33 if err != nil { 34 log.L.WithError(err).Error("notation executable not found in path $PATH") 35 log.L.Info("you might consider installing notation from: https://notaryproject.dev/docs/installation/cli/") 36 return err 37 } 38 39 notationCmd := exec.Command(notationExecutable, []string{"sign"}...) 40 notationCmd.Env = os.Environ() 41 42 // If keyNameRef is empty, don't append --key to notation command. This will cause using the notation default key. 43 if keyNameRef != "" { 44 notationCmd.Args = append(notationCmd.Args, "--key", keyNameRef) 45 } 46 47 notationCmd.Args = append(notationCmd.Args, rawRef) 48 49 log.L.Debugf("running %s %v", notationExecutable, notationCmd.Args) 50 51 err = processNotationIO(notationCmd) 52 if err != nil { 53 return err 54 } 55 56 return notationCmd.Wait() 57 } 58 59 // VerifyNotation verifies an image(`rawRef`) with the pre-configured notation trust policy 60 // `hostsDirs` are used to resolve image `rawRef` 61 func VerifyNotation(ctx context.Context, rawRef string, hostsDirs []string) (string, error) { 62 digest, err := imgutil.ResolveDigest(ctx, rawRef, false, hostsDirs) 63 if err != nil { 64 log.G(ctx).WithError(err).Errorf("unable to resolve digest for an image %s: %v", rawRef, err) 65 return rawRef, err 66 } 67 ref := rawRef 68 if !strings.Contains(ref, "@") { 69 ref += "@" + digest 70 } 71 72 log.G(ctx).Debugf("verifying image: %s", ref) 73 74 notationExecutable, err := exec.LookPath("notation") 75 if err != nil { 76 log.G(ctx).WithError(err).Error("notation executable not found in path $PATH") 77 log.G(ctx).Info("you might consider installing notation from: https://notaryproject.dev/docs/installation/cli/") 78 return ref, err 79 } 80 81 notationCmd := exec.Command(notationExecutable, []string{"verify"}...) 82 notationCmd.Env = os.Environ() 83 84 notationCmd.Args = append(notationCmd.Args, ref) 85 86 log.G(ctx).Debugf("running %s %v", notationExecutable, notationCmd.Args) 87 88 err = processNotationIO(notationCmd) 89 if err != nil { 90 return ref, err 91 } 92 if err := notationCmd.Wait(); err != nil { 93 return ref, err 94 } 95 96 return ref, nil 97 } 98 99 func processNotationIO(notationCmd *exec.Cmd) error { 100 stdout, err := notationCmd.StdoutPipe() 101 if err != nil { 102 log.L.Warn("notation: " + err.Error()) 103 } 104 stderr, err := notationCmd.StderrPipe() 105 if err != nil { 106 log.L.Warn("notation: " + err.Error()) 107 } 108 if err := notationCmd.Start(); err != nil { 109 // only return err if it's critical (notation start failed.) 110 return err 111 } 112 113 scanner := bufio.NewScanner(stdout) 114 for scanner.Scan() { 115 log.L.Info("notation: " + scanner.Text()) 116 } 117 if err := scanner.Err(); err != nil { 118 log.L.Warn("notation: " + err.Error()) 119 } 120 121 errScanner := bufio.NewScanner(stderr) 122 for errScanner.Scan() { 123 log.L.Info("notation: " + errScanner.Text()) 124 } 125 if err := errScanner.Err(); err != nil { 126 log.L.Warn("notation: " + err.Error()) 127 } 128 129 return nil 130 }