@@ -3,34 +3,119 @@ package main
3
3
import (
4
4
"context"
5
5
"errors"
6
+ "fmt"
7
+ "os"
8
+ "strings"
9
+ "unicode"
6
10
7
11
"github.com/notaryproject/notation-go/log"
8
12
notationregistry "github.com/notaryproject/notation-go/registry"
13
+ notationerrors "github.com/notaryproject/notation/cmd/notation/internal/errors"
14
+ "github.com/opencontainers/go-digest"
9
15
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
10
16
"oras.land/oras-go/v2/registry"
11
17
)
12
18
13
- // getManifestDescriptor returns target artifact manifest descriptor and
14
- // registry.Reference given user input reference.
15
- func getManifestDescriptor (ctx context.Context , opts * SecureFlagOpts , reference string , sigRepo notationregistry.Repository ) (ocispec.Descriptor , registry.Reference , error ) {
16
- logger := log .GetLogger (ctx )
17
-
19
+ // resolveReference resolves user input reference based on user input type.
20
+ // Returns the resolved manifest descriptor and resolvedRef in digest
21
+ func resolveReference (ctx context.Context , inputType inputType , reference string , sigRepo notationregistry.Repository , fn func (string , ocispec.Descriptor )) (ocispec.Descriptor , string , error ) {
22
+ // sanity check
18
23
if reference == "" {
19
- return ocispec.Descriptor {}, registry.Reference {}, errors .New ("missing reference" )
24
+ return ocispec.Descriptor {}, "" , errors .New ("missing user input reference" )
25
+ }
26
+ var tagOrDigestRef string
27
+ var resolvedRef string
28
+ switch inputType {
29
+ case inputTypeRegistry :
30
+ ref , err := registry .ParseReference (reference )
31
+ if err != nil {
32
+ return ocispec.Descriptor {}, "" , fmt .Errorf ("failed to resolve user input reference: %w" , err )
33
+ }
34
+ tagOrDigestRef = ref .Reference
35
+ resolvedRef = ref .Registry + "/" + ref .Repository
36
+ case inputTypeOCILayout :
37
+ layoutPath , layoutReference , err := parseOCILayoutReference (reference )
38
+ if err != nil {
39
+ return ocispec.Descriptor {}, "" , fmt .Errorf ("failed to resolve user input reference: %w" , err )
40
+ }
41
+ layoutPathInfo , err := os .Stat (layoutPath )
42
+ if err != nil {
43
+ return ocispec.Descriptor {}, "" , fmt .Errorf ("failed to resolve user input reference: %w" , err )
44
+ }
45
+ if ! layoutPathInfo .IsDir () {
46
+ return ocispec.Descriptor {}, "" , errors .New ("failed to resolve user input reference: input path is not a dir" )
47
+ }
48
+ tagOrDigestRef = layoutReference
49
+ resolvedRef = layoutPath
50
+ default :
51
+ return ocispec.Descriptor {}, "" , fmt .Errorf ("unsupported user inputType: %d" , inputType )
20
52
}
21
- ref , err := registry .ParseReference (reference )
53
+
54
+ manifestDesc , err := getManifestDescriptor (ctx , tagOrDigestRef , sigRepo )
22
55
if err != nil {
23
- return ocispec.Descriptor {}, registry.Reference {}, err
56
+ return ocispec.Descriptor {}, "" , fmt .Errorf ("failed to get manifest descriptor: %w" , err )
57
+ }
58
+ resolvedRef = resolvedRef + "@" + manifestDesc .Digest .String ()
59
+ if _ , err := digest .Parse (tagOrDigestRef ); err == nil {
60
+ // tagOrDigestRef is a digest reference
61
+ return manifestDesc , resolvedRef , nil
24
62
}
25
- if ref .Reference == "" {
26
- return ocispec.Descriptor {}, registry.Reference {}, errors .New ("reference is missing digest or tag" )
63
+ // tagOrDigestRef is a tag reference
64
+ if fn != nil {
65
+ fn (tagOrDigestRef , manifestDesc )
27
66
}
67
+ return manifestDesc , resolvedRef , nil
68
+ }
28
69
29
- manifestDesc , err := sigRepo .Resolve (ctx , ref .Reference )
30
- if err != nil {
31
- return ocispec.Descriptor {}, registry.Reference {}, err
70
+ // resolveArtifactDigestReference creates reference in Verification given user input
71
+ // trust policy scope
72
+ func resolveArtifactDigestReference (reference , policyScope string ) string {
73
+ if policyScope != "" {
74
+ if _ , digest , ok := strings .Cut (reference , "@" ); ok {
75
+ return policyScope + "@" + digest
76
+ }
32
77
}
78
+ return reference
79
+ }
33
80
34
- logger .Infof ("Reference %s resolved to manifest descriptor: %+v" , ref .Reference , manifestDesc )
35
- return manifestDesc , ref , nil
81
+ // parseOCILayoutReference parses the raw in format of <path>[:<tag>|@<digest>].
82
+ // Returns the path to the OCI layout and the reference (tag or digest).
83
+ func parseOCILayoutReference (raw string ) (string , string , error ) {
84
+ var path string
85
+ var ref string
86
+ if idx := strings .LastIndex (raw , "@" ); idx != - 1 {
87
+ // `digest` found
88
+ path , ref = raw [:idx ], raw [idx + 1 :]
89
+ } else {
90
+ // find `tag`
91
+ idx := strings .LastIndex (raw , ":" )
92
+ if idx == - 1 || (idx == 1 && len (raw ) > 2 && unicode .IsLetter (rune (raw [0 ])) && raw [2 ] == '\\' ) {
93
+ return "" , "" , notationerrors.ErrorOCILayoutMissingReference {}
94
+ } else {
95
+ path , ref = raw [:idx ], raw [idx + 1 :]
96
+ }
97
+ }
98
+ if path == "" {
99
+ return "" , "" , fmt .Errorf ("found empty file path in %q" , raw )
100
+ }
101
+ if ref == "" {
102
+ return "" , "" , fmt .Errorf ("found empty reference in %q" , raw )
103
+ }
104
+ return path , ref , nil
105
+ }
106
+
107
+ // getManifestDescriptor returns target artifact manifest descriptor given
108
+ // reference (digest or tag) and Repository.
109
+ func getManifestDescriptor (ctx context.Context , reference string , sigRepo notationregistry.Repository ) (ocispec.Descriptor , error ) {
110
+ logger := log .GetLogger (ctx )
111
+
112
+ if reference == "" {
113
+ return ocispec.Descriptor {}, errors .New ("reference cannot be empty" )
114
+ }
115
+ manifestDesc , err := sigRepo .Resolve (ctx , reference )
116
+ if err != nil {
117
+ return ocispec.Descriptor {}, err
118
+ }
119
+ logger .Infof ("Reference %s resolved to manifest descriptor: %+v" , reference , manifestDesc )
120
+ return manifestDesc , nil
36
121
}
0 commit comments