(t *testing.T)
| 102 | } |
| 103 | |
| 104 | func TestServiceCreateDigestPinning(t *testing.T) { |
| 105 | dgst := "sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96" |
| 106 | dgstAlt := "sha256:37ffbf3f7497c07584dc9637ffbf3f7497c0758c0537ffbf3f7497c0c88e2bb7" |
| 107 | serviceCreateImage := "" |
| 108 | pinByDigestTests := []struct { |
| 109 | img string // input image provided by the user |
| 110 | expected string // expected image after digest pinning |
| 111 | }{ |
| 112 | // default registry returns familiar string |
| 113 | {"docker.io/library/alpine", "alpine:latest@" + dgst}, |
| 114 | // provided tag is preserved and digest added |
| 115 | {"alpine:edge", "alpine:edge@" + dgst}, |
| 116 | // image with provided alternative digest remains unchanged |
| 117 | {"alpine@" + dgstAlt, "alpine@" + dgstAlt}, |
| 118 | // image with provided tag and alternative digest remains unchanged |
| 119 | {"alpine:edge@" + dgstAlt, "alpine:edge@" + dgstAlt}, |
| 120 | // image on alternative registry does not result in familiar string |
| 121 | {"alternate.registry/library/alpine", "alternate.registry/library/alpine:latest@" + dgst}, |
| 122 | // unresolvable image does not get a digest |
| 123 | {"cannotresolve", "cannotresolve:latest"}, |
| 124 | } |
| 125 | |
| 126 | client, err := New(WithMockClient(func(req *http.Request) (*http.Response, error) { |
| 127 | if strings.HasPrefix(req.URL.Path, defaultAPIPath+"/services/create") { |
| 128 | // reset and set image received by the service create endpoint |
| 129 | serviceCreateImage = "" |
| 130 | var service swarm.ServiceSpec |
| 131 | if err := json.NewDecoder(req.Body).Decode(&service); err != nil { |
| 132 | return nil, errors.New("could not parse service create request") |
| 133 | } |
| 134 | serviceCreateImage = service.TaskTemplate.ContainerSpec.Image |
| 135 | |
| 136 | return mockJSONResponse(http.StatusOK, nil, swarm.ServiceCreateResponse{ |
| 137 | ID: "service_id", |
| 138 | })(req) |
| 139 | } else if strings.HasPrefix(req.URL.Path, defaultAPIPath+"/distribution/cannotresolve") { |
| 140 | // unresolvable image |
| 141 | return nil, errors.New("cannot resolve image") |
| 142 | } else if strings.HasPrefix(req.URL.Path, defaultAPIPath+"/distribution/") { |
| 143 | // resolvable images |
| 144 | return mockJSONResponse(http.StatusOK, nil, registrytypes.DistributionInspect{ |
| 145 | Descriptor: ocispec.Descriptor{ |
| 146 | Digest: digest.Digest(dgst), |
| 147 | }, |
| 148 | })(req) |
| 149 | } |
| 150 | return nil, fmt.Errorf("unexpected URL '%s'", req.URL.Path) |
| 151 | })) |
| 152 | assert.NilError(t, err) |
| 153 | |
| 154 | // run pin by digest tests |
| 155 | for _, p := range pinByDigestTests { |
| 156 | r, err := client.ServiceCreate(t.Context(), ServiceCreateOptions{ |
| 157 | Spec: swarm.ServiceSpec{ |
| 158 | TaskTemplate: swarm.TaskSpec{ |
| 159 | ContainerSpec: &swarm.ContainerSpec{ |
| 160 | Image: p.img, |
| 161 | }, |
nothing calls this directly
no test coverage detected
searching dependent graphs…