Skip to content

Commit 284a39e

Browse files
committed
add notes and godoc about registering algorithms
Signed-off-by: Sebastiaan van Stijn <[email protected]>
1 parent ff14faf commit 284a39e

File tree

3 files changed

+89
-11
lines changed

3 files changed

+89
-11
lines changed

normalize.go

+34-4
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,20 @@ type normalizedNamed interface {
4949
Familiar() Named
5050
}
5151

52-
// ParseNormalizedNamed parses a string into a named reference
53-
// transforming a familiar name from Docker UI to a fully
54-
// qualified reference. If the value may be an identifier
55-
// use ParseAnyReference.
52+
// ParseNormalizedNamed parses a string into a [Named] reference transforming a
53+
// familiar name from Docker UI to a fully qualified reference. If the value may
54+
// be an identifier, use [ParseAnyReference] instead. It returns a nil reference
55+
// if an error occurs.
56+
//
57+
// An error is returned when parsing a reference that contains a digest with an
58+
// algorithm that is not registered. Implementations must register the algorithm
59+
// by importing the appropriate implementation.
60+
//
61+
// For example, to register the sha256 algorithm implementation from Go's stdlib:
62+
//
63+
// import (
64+
// _ "crypto/sha256"
65+
// )
5666
func ParseNormalizedNamed(s string) (Named, error) {
5767
if ok := anchoredIdentifierRegexp.MatchString(s); ok {
5868
return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s)
@@ -104,6 +114,16 @@ type namedTaggedDigested interface {
104114
//
105115
// // Already a named reference
106116
// docker.io/library/busybox:latest
117+
//
118+
// An error is returned when parsing a reference that contains a digest with an
119+
// algorithm that is not registered. Implementations must register the algorithm
120+
// by importing the appropriate implementation.
121+
//
122+
// For example, to register the sha256 algorithm implementation from Go's stdlib:
123+
//
124+
// import (
125+
// _ "crypto/sha256"
126+
// )
107127
func ParseDockerRef(ref string) (Named, error) {
108128
named, err := ParseNormalizedNamed(ref)
109129
if err != nil {
@@ -243,6 +263,16 @@ func TagNameOnly(ref Named) Named {
243263

244264
// ParseAnyReference parses a reference string as a possible identifier,
245265
// full digest, or familiar name.
266+
//
267+
// An error is returned when parsing a reference that contains a digest with an
268+
// algorithm that is not registered. Implementations must register the algorithm
269+
// by importing the appropriate implementation.
270+
//
271+
// For example, to register the sha256 algorithm implementation from Go's stdlib:
272+
//
273+
// import (
274+
// _ "crypto/sha256"
275+
// )
246276
func ParseAnyReference(ref string) (Reference, error) {
247277
if ok := anchoredIdentifierRegexp.MatchString(ref); ok {
248278
return digestReference("sha256:" + ref), nil

reference.go

+47-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Package reference provides a general type to represent any way of referencing images within the registry.
22
// Its main purpose is to abstract tags and digests (content-addressable hash).
33
//
4-
// Grammar
4+
// # Grammar
55
//
66
// reference := name [ ":" tag ] [ "@" digest ]
77
// name := [domain '/'] remote-name
@@ -24,6 +24,29 @@
2424
// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
2525
//
2626
// identifier := /[a-f0-9]{64}/
27+
//
28+
// # Supported algorithms
29+
//
30+
// Implementations must register the algorithms they want to support for digests
31+
// by importing the appropriate implementation in a non-test file.
32+
//
33+
// For example, to register the sha256 algorithm implementation from Go's stdlib:
34+
//
35+
// import (
36+
// _ "crypto/sha256"
37+
// )
38+
//
39+
// Even though digests may be assemblable as a string, always verify your input
40+
// with [digest.Parse] or use [digest.Digest.Validate] when accepting untrusted
41+
// input. While there are measures to avoid common problems, this ensures you
42+
// have valid digests in the rest of your application.
43+
//
44+
// While alternative encodings of hash values (digests) are possible (for example,
45+
// base64), this package deals exclusively with hex-encoded digests. Refer to
46+
// the [OCI image specification] for algorithms that are defined as part of the
47+
// specification.
48+
//
49+
// [OCI image specification]: https://github.com/opencontainers/image-spec/blob/v1.0.2/descriptor.md#registered-algorithms
2750
package reference
2851

2952
import (
@@ -102,6 +125,16 @@ func (f Field) MarshalText() (p []byte, err error) {
102125
// UnmarshalText parses text bytes by invoking the
103126
// reference parser to ensure the appropriately
104127
// typed reference object is wrapped by field.
128+
//
129+
// An error is returned when unmarshaling a reference that contains a digest with an
130+
// algorithm that is not registered. Implementations must register the algorithm
131+
// by importing the appropriate implementation.
132+
//
133+
// For example, to register the sha256 algorithm implementation from Go's stdlib:
134+
//
135+
// import (
136+
// _ "crypto/sha256"
137+
// )
105138
func (f *Field) UnmarshalText(p []byte) error {
106139
r, err := Parse(string(p))
107140
if err != nil {
@@ -181,8 +214,19 @@ func splitDomain(name string) (string, string) {
181214
return match[1], match[2]
182215
}
183216

184-
// Parse parses s and returns a syntactically valid Reference.
185-
// If an error was encountered it is returned, along with a nil Reference.
217+
// Parse parses s and returns a syntactically valid [Reference]. It returns a
218+
// nil Reference if an error occurs. When parsing a reference that contains a
219+
// digest, an error is returned if the digest's algorithm that is not registered.
220+
//
221+
// An error is returned when parsing a reference that contains a digest with an
222+
// algorithm that is not registered. Implementations must register the algorithm
223+
// by importing the appropriate implementation.
224+
//
225+
// For example, to register the sha256 algorithm implementation from Go's stdlib:
226+
//
227+
// import (
228+
// _ "crypto/sha256"
229+
// )
186230
func Parse(s string) (Reference, error) {
187231
matches := ReferenceRegexp.FindStringSubmatch(s)
188232
if matches == nil {

reference_test.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package reference
22

33
import (
4-
_ "crypto/sha256"
5-
_ "crypto/sha512"
4+
_ "crypto/sha256" // make sure the sha256 algorithm is registered, as it's used in tests.
65
"encoding/json"
76
"errors"
87
"strings"
@@ -98,6 +97,11 @@ func TestReferenceParse(t *testing.T) {
9897
input: "validname@invaliddigest:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
9998
err: digest.ErrDigestUnsupported,
10099
},
100+
{
101+
// sha512 is valid, but not registered by default ("crypto/sha512" is not imported)
102+
input: "validname@sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
103+
err: digest.ErrDigestUnsupported,
104+
},
101105
{
102106
input: "Uppercase:tag",
103107
err: ErrNameContainsUppercase,
@@ -155,11 +159,11 @@ func TestReferenceParse(t *testing.T) {
155159
tag: "xn--n3h.com",
156160
},
157161
{
158-
input: "xn--7o8h.com/myimage:xn--7o8h.com@sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // 🐳.com in punycode
162+
input: "xn--7o8h.com/myimage:xn--7o8h.com@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // 🐳.com in punycode
159163
domain: "xn--7o8h.com",
160164
repository: "xn--7o8h.com/myimage",
161165
tag: "xn--7o8h.com",
162-
digest: "sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
166+
digest: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
163167
},
164168
{
165169
input: "foo_bar.com:8080",

0 commit comments

Comments
 (0)