Which is an array of signatures with mostly opaque data. There are
two mandatory fields of each signature:
- Type - the only supported value for now is "atomic"
- Content - opaque binary string
There's one known signature type "atomic" with two mandatory
and one optional attributes:
- ImageHash - hash of a signed image
- ImageIdentity - signed claim representing an origin of the image
- Created - optional; the time of signarure's creation
Following attributes are added for future signing extensions:
- SignedClaims - a map of interesting signed claims that maybe added
later to the signature format but not that important
to become first-class fields
- IssuedBy - issuer of signing certificate if any
- IssuedTo - subject of signing certificate or an image signer
Signed-off-by: Michal Minar <miminar@redhat.com>
... | ... |
@@ -21059,6 +21059,13 @@ |
21059 | 21059 |
"$ref": "v1.ImageLayer" |
21060 | 21060 |
}, |
21061 | 21061 |
"description": "DockerImageLayers represents the layers in the image. May not be set if the image does not define that data." |
21062 |
+ }, |
|
21063 |
+ "signatures": { |
|
21064 |
+ "type": "array", |
|
21065 |
+ "items": { |
|
21066 |
+ "$ref": "v1.ImageSignature" |
|
21067 |
+ }, |
|
21068 |
+ "description": "Signatures holds all signatures of the image." |
|
21062 | 21069 |
} |
21063 | 21070 |
} |
21064 | 21071 |
}, |
... | ... |
@@ -21081,6 +21088,123 @@ |
21081 | 21081 |
} |
21082 | 21082 |
} |
21083 | 21083 |
}, |
21084 |
+ "v1.ImageSignature": { |
|
21085 |
+ "id": "v1.ImageSignature", |
|
21086 |
+ "description": "ImageSignature holds a signature of an image. It allows to verify image identity and possibly other claims as long as the signature is trusted. Based on this information it is possible to restrict runnable images to those matching cluster-wide policy. There are two mandatory fields provided by client: Type and Content. They should be parsed by clients doing image verification. The others are parsed from signature's content by the server. They serve just an informative purpose.", |
|
21087 |
+ "required": [ |
|
21088 |
+ "type", |
|
21089 |
+ "content" |
|
21090 |
+ ], |
|
21091 |
+ "properties": { |
|
21092 |
+ "type": { |
|
21093 |
+ "type": "string", |
|
21094 |
+ "description": "Required: Describes a type of stored blob." |
|
21095 |
+ }, |
|
21096 |
+ "content": { |
|
21097 |
+ "type": "array", |
|
21098 |
+ "items": { |
|
21099 |
+ "$ref": "integer" |
|
21100 |
+ }, |
|
21101 |
+ "description": "Required: An opaque binary string which is an image's signature." |
|
21102 |
+ }, |
|
21103 |
+ "conditions": { |
|
21104 |
+ "type": "array", |
|
21105 |
+ "items": { |
|
21106 |
+ "$ref": "v1.SignatureCondition" |
|
21107 |
+ }, |
|
21108 |
+ "description": "Conditions represent the latest available observations of a signature's current state." |
|
21109 |
+ }, |
|
21110 |
+ "imageIdentity": { |
|
21111 |
+ "type": "string", |
|
21112 |
+ "description": "A human readable string representing image's identity. It could be a product name and version, or an image pull spec (e.g. \"registry.access.redhat.com/rhel7/rhel:7.2\")." |
|
21113 |
+ }, |
|
21114 |
+ "signedClaims": { |
|
21115 |
+ "type": "any", |
|
21116 |
+ "description": "Contains claims from the signature." |
|
21117 |
+ }, |
|
21118 |
+ "created": { |
|
21119 |
+ "type": "string", |
|
21120 |
+ "description": "If specified, it is the time of signature's creation." |
|
21121 |
+ }, |
|
21122 |
+ "issuedBy": { |
|
21123 |
+ "$ref": "v1.SignatureIssuer", |
|
21124 |
+ "description": "If specified, it holds information about an issuer of signing certificate or key (a person or entity who signed the signing certificate or key)." |
|
21125 |
+ }, |
|
21126 |
+ "issuedTo": { |
|
21127 |
+ "$ref": "v1.SignatureSubject", |
|
21128 |
+ "description": "If specified, it holds information about a subject of signing certificate or key (a person or entity who signed the image)." |
|
21129 |
+ } |
|
21130 |
+ } |
|
21131 |
+ }, |
|
21132 |
+ "v1.SignatureCondition": { |
|
21133 |
+ "id": "v1.SignatureCondition", |
|
21134 |
+ "description": "SignatureCondition describes an image signature condition of particular kind at particular probe time.", |
|
21135 |
+ "required": [ |
|
21136 |
+ "type", |
|
21137 |
+ "status" |
|
21138 |
+ ], |
|
21139 |
+ "properties": { |
|
21140 |
+ "type": { |
|
21141 |
+ "type": "string", |
|
21142 |
+ "description": "Type of job condition, Complete or Failed." |
|
21143 |
+ }, |
|
21144 |
+ "status": { |
|
21145 |
+ "type": "string", |
|
21146 |
+ "description": "Status of the condition, one of True, False, Unknown." |
|
21147 |
+ }, |
|
21148 |
+ "lastProbeTime": { |
|
21149 |
+ "type": "string", |
|
21150 |
+ "description": "Last time the condition was checked." |
|
21151 |
+ }, |
|
21152 |
+ "lastTransitionTime": { |
|
21153 |
+ "type": "string", |
|
21154 |
+ "description": "Last time the condition transit from one status to another." |
|
21155 |
+ }, |
|
21156 |
+ "reason": { |
|
21157 |
+ "type": "string", |
|
21158 |
+ "description": "(brief) reason for the condition's last transition." |
|
21159 |
+ }, |
|
21160 |
+ "message": { |
|
21161 |
+ "type": "string", |
|
21162 |
+ "description": "Human readable message indicating details about last transition." |
|
21163 |
+ } |
|
21164 |
+ } |
|
21165 |
+ }, |
|
21166 |
+ "v1.SignatureIssuer": { |
|
21167 |
+ "id": "v1.SignatureIssuer", |
|
21168 |
+ "description": "SignatureIssuer holds information about an issuer of signing certificate or key.", |
|
21169 |
+ "properties": { |
|
21170 |
+ "organization": { |
|
21171 |
+ "type": "string", |
|
21172 |
+ "description": "Organization name." |
|
21173 |
+ }, |
|
21174 |
+ "commonName": { |
|
21175 |
+ "type": "string", |
|
21176 |
+ "description": "Common name (e.g. openshift-signing-service)." |
|
21177 |
+ } |
|
21178 |
+ } |
|
21179 |
+ }, |
|
21180 |
+ "v1.SignatureSubject": { |
|
21181 |
+ "id": "v1.SignatureSubject", |
|
21182 |
+ "description": "SignatureSubject holds information about a person or entity who created the signature.", |
|
21183 |
+ "required": [ |
|
21184 |
+ "publicKeyID" |
|
21185 |
+ ], |
|
21186 |
+ "properties": { |
|
21187 |
+ "organization": { |
|
21188 |
+ "type": "string", |
|
21189 |
+ "description": "Organization name." |
|
21190 |
+ }, |
|
21191 |
+ "commonName": { |
|
21192 |
+ "type": "string", |
|
21193 |
+ "description": "Common name (e.g. openshift-signing-service)." |
|
21194 |
+ }, |
|
21195 |
+ "publicKeyID": { |
|
21196 |
+ "type": "string", |
|
21197 |
+ "description": "If present, it is a human readable key id of public key belonging to the subject used to verify image signature. It should contain at least 64 lowest bits of public key's fingerprint (e.g. 0x685ebe62bf278440)." |
|
21198 |
+ } |
|
21199 |
+ } |
|
21200 |
+ }, |
|
21084 | 21201 |
"v1.ImageStreamImage": { |
21085 | 21202 |
"id": "v1.ImageStreamImage", |
21086 | 21203 |
"description": "ImageStreamImage represents an Image that is retrieved by image name from an ImageStream.", |
... | ... |
@@ -26,6 +26,7 @@ func init() { |
26 | 26 |
DeepCopy_api_ImageImportStatus, |
27 | 27 |
DeepCopy_api_ImageLayer, |
28 | 28 |
DeepCopy_api_ImageList, |
29 |
+ DeepCopy_api_ImageSignature, |
|
29 | 30 |
DeepCopy_api_ImageStream, |
30 | 31 |
DeepCopy_api_ImageStreamImage, |
31 | 32 |
DeepCopy_api_ImageStreamImport, |
... | ... |
@@ -39,6 +40,10 @@ func init() { |
39 | 39 |
DeepCopy_api_ImageStreamTagList, |
40 | 40 |
DeepCopy_api_RepositoryImportSpec, |
41 | 41 |
DeepCopy_api_RepositoryImportStatus, |
42 |
+ DeepCopy_api_SignatureCondition, |
|
43 |
+ DeepCopy_api_SignatureGenericEntity, |
|
44 |
+ DeepCopy_api_SignatureIssuer, |
|
45 |
+ DeepCopy_api_SignatureSubject, |
|
42 | 46 |
DeepCopy_api_TagEvent, |
43 | 47 |
DeepCopy_api_TagEventCondition, |
44 | 48 |
DeepCopy_api_TagEventList, |
... | ... |
@@ -312,6 +317,17 @@ func DeepCopy_api_Image(in Image, out *Image, c *conversion.Cloner) error { |
312 | 312 |
} else { |
313 | 313 |
out.DockerImageLayers = nil |
314 | 314 |
} |
315 |
+ if in.Signatures != nil { |
|
316 |
+ in, out := in.Signatures, &out.Signatures |
|
317 |
+ *out = make([]ImageSignature, len(in)) |
|
318 |
+ for i := range in { |
|
319 |
+ if err := DeepCopy_api_ImageSignature(in[i], &(*out)[i], c); err != nil { |
|
320 |
+ return err |
|
321 |
+ } |
|
322 |
+ } |
|
323 |
+ } else { |
|
324 |
+ out.Signatures = nil |
|
325 |
+ } |
|
315 | 326 |
return nil |
316 | 327 |
} |
317 | 328 |
|
... | ... |
@@ -379,6 +395,66 @@ func DeepCopy_api_ImageList(in ImageList, out *ImageList, c *conversion.Cloner) |
379 | 379 |
return nil |
380 | 380 |
} |
381 | 381 |
|
382 |
+func DeepCopy_api_ImageSignature(in ImageSignature, out *ImageSignature, c *conversion.Cloner) error { |
|
383 |
+ out.Type = in.Type |
|
384 |
+ if in.Content != nil { |
|
385 |
+ in, out := in.Content, &out.Content |
|
386 |
+ *out = make([]byte, len(in)) |
|
387 |
+ copy(*out, in) |
|
388 |
+ } else { |
|
389 |
+ out.Content = nil |
|
390 |
+ } |
|
391 |
+ if in.Conditions != nil { |
|
392 |
+ in, out := in.Conditions, &out.Conditions |
|
393 |
+ *out = make([]SignatureCondition, len(in)) |
|
394 |
+ for i := range in { |
|
395 |
+ if err := DeepCopy_api_SignatureCondition(in[i], &(*out)[i], c); err != nil { |
|
396 |
+ return err |
|
397 |
+ } |
|
398 |
+ } |
|
399 |
+ } else { |
|
400 |
+ out.Conditions = nil |
|
401 |
+ } |
|
402 |
+ out.ImageIdentity = in.ImageIdentity |
|
403 |
+ if in.SignedClaims != nil { |
|
404 |
+ in, out := in.SignedClaims, &out.SignedClaims |
|
405 |
+ *out = make(map[string]string) |
|
406 |
+ for key, val := range in { |
|
407 |
+ (*out)[key] = val |
|
408 |
+ } |
|
409 |
+ } else { |
|
410 |
+ out.SignedClaims = nil |
|
411 |
+ } |
|
412 |
+ if in.Created != nil { |
|
413 |
+ in, out := in.Created, &out.Created |
|
414 |
+ *out = new(unversioned.Time) |
|
415 |
+ if err := unversioned.DeepCopy_unversioned_Time(*in, *out, c); err != nil { |
|
416 |
+ return err |
|
417 |
+ } |
|
418 |
+ } else { |
|
419 |
+ out.Created = nil |
|
420 |
+ } |
|
421 |
+ if in.IssuedBy != nil { |
|
422 |
+ in, out := in.IssuedBy, &out.IssuedBy |
|
423 |
+ *out = new(SignatureIssuer) |
|
424 |
+ if err := DeepCopy_api_SignatureIssuer(*in, *out, c); err != nil { |
|
425 |
+ return err |
|
426 |
+ } |
|
427 |
+ } else { |
|
428 |
+ out.IssuedBy = nil |
|
429 |
+ } |
|
430 |
+ if in.IssuedTo != nil { |
|
431 |
+ in, out := in.IssuedTo, &out.IssuedTo |
|
432 |
+ *out = new(SignatureSubject) |
|
433 |
+ if err := DeepCopy_api_SignatureSubject(*in, *out, c); err != nil { |
|
434 |
+ return err |
|
435 |
+ } |
|
436 |
+ } else { |
|
437 |
+ out.IssuedTo = nil |
|
438 |
+ } |
|
439 |
+ return nil |
|
440 |
+} |
|
441 |
+ |
|
382 | 442 |
func DeepCopy_api_ImageStream(in ImageStream, out *ImageStream, c *conversion.Cloner) error { |
383 | 443 |
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil { |
384 | 444 |
return err |
... | ... |
@@ -645,6 +721,41 @@ func DeepCopy_api_RepositoryImportStatus(in RepositoryImportStatus, out *Reposit |
645 | 645 |
return nil |
646 | 646 |
} |
647 | 647 |
|
648 |
+func DeepCopy_api_SignatureCondition(in SignatureCondition, out *SignatureCondition, c *conversion.Cloner) error { |
|
649 |
+ out.Type = in.Type |
|
650 |
+ out.Status = in.Status |
|
651 |
+ if err := unversioned.DeepCopy_unversioned_Time(in.LastProbeTime, &out.LastProbeTime, c); err != nil { |
|
652 |
+ return err |
|
653 |
+ } |
|
654 |
+ if err := unversioned.DeepCopy_unversioned_Time(in.LastTransitionTime, &out.LastTransitionTime, c); err != nil { |
|
655 |
+ return err |
|
656 |
+ } |
|
657 |
+ out.Reason = in.Reason |
|
658 |
+ out.Message = in.Message |
|
659 |
+ return nil |
|
660 |
+} |
|
661 |
+ |
|
662 |
+func DeepCopy_api_SignatureGenericEntity(in SignatureGenericEntity, out *SignatureGenericEntity, c *conversion.Cloner) error { |
|
663 |
+ out.Organization = in.Organization |
|
664 |
+ out.CommonName = in.CommonName |
|
665 |
+ return nil |
|
666 |
+} |
|
667 |
+ |
|
668 |
+func DeepCopy_api_SignatureIssuer(in SignatureIssuer, out *SignatureIssuer, c *conversion.Cloner) error { |
|
669 |
+ if err := DeepCopy_api_SignatureGenericEntity(in.SignatureGenericEntity, &out.SignatureGenericEntity, c); err != nil { |
|
670 |
+ return err |
|
671 |
+ } |
|
672 |
+ return nil |
|
673 |
+} |
|
674 |
+ |
|
675 |
+func DeepCopy_api_SignatureSubject(in SignatureSubject, out *SignatureSubject, c *conversion.Cloner) error { |
|
676 |
+ if err := DeepCopy_api_SignatureGenericEntity(in.SignatureGenericEntity, &out.SignatureGenericEntity, c); err != nil { |
|
677 |
+ return err |
|
678 |
+ } |
|
679 |
+ out.PublicKeyID = in.PublicKeyID |
|
680 |
+ return nil |
|
681 |
+} |
|
682 |
+ |
|
648 | 683 |
func DeepCopy_api_TagEvent(in TagEvent, out *TagEvent, c *conversion.Cloner) error { |
649 | 684 |
if err := unversioned.DeepCopy_unversioned_Time(in.Created, &out.Created, c); err != nil { |
650 | 685 |
return err |
... | ... |
@@ -66,6 +66,8 @@ type Image struct { |
66 | 66 |
DockerImageManifest string |
67 | 67 |
// DockerImageLayers represents the layers in the image. May not be set if the image does not define that data. |
68 | 68 |
DockerImageLayers []ImageLayer |
69 |
+ // Signatures holds all signatures of the image. |
|
70 |
+ Signatures []ImageSignature |
|
69 | 71 |
} |
70 | 72 |
|
71 | 73 |
// ImageLayer represents a single layer of the image. Some images may have multiple layers. Some may have none. |
... | ... |
@@ -76,6 +78,99 @@ type ImageLayer struct { |
76 | 76 |
Size int64 |
77 | 77 |
} |
78 | 78 |
|
79 |
+const ( |
|
80 |
+ // The supported type of image signature. |
|
81 |
+ ImageSignatureTypeAtomicImageV1 string = "AtomicImageV1" |
|
82 |
+) |
|
83 |
+ |
|
84 |
+// ImageSignature holds a signature of an image. It allows to verify image identity and possibly other claims |
|
85 |
+// as long as the signature is trusted. Based on this information it is possible to restrict runnable images |
|
86 |
+// to those matching cluster-wide policy. |
|
87 |
+// There are two mandatory fields provided by client: Type and Content. They should be parsed by clients doing |
|
88 |
+// image verification. The others are parsed from signature's content by the server. They serve just an |
|
89 |
+// informative purpose. |
|
90 |
+type ImageSignature struct { |
|
91 |
+ // Required: Describes a type of stored blob. |
|
92 |
+ Type string |
|
93 |
+ // Required: An opaque binary string which is an image's signature. |
|
94 |
+ Content []byte |
|
95 |
+ // Conditions represent the latest available observations of a signature's current state. |
|
96 |
+ Conditions []SignatureCondition |
|
97 |
+ |
|
98 |
+ // Following metadata fields will be set by server if the signature content is successfully parsed and |
|
99 |
+ // the information available. |
|
100 |
+ |
|
101 |
+ // A human readable string representing image's identity. It could be a product name and version, or an |
|
102 |
+ // image pull spec (e.g. "registry.access.redhat.com/rhel7/rhel:7.2"). |
|
103 |
+ ImageIdentity string |
|
104 |
+ // Contains claims from the signature. |
|
105 |
+ SignedClaims map[string]string |
|
106 |
+ // If specified, it is the time of signature's creation. |
|
107 |
+ Created *unversioned.Time |
|
108 |
+ // If specified, it holds information about an issuer of signing certificate or key (a person or entity |
|
109 |
+ // who signed the signing certificate or key). |
|
110 |
+ IssuedBy *SignatureIssuer |
|
111 |
+ // If specified, it holds information about a subject of signing certificate or key (a person or entity |
|
112 |
+ // who signed the image). |
|
113 |
+ IssuedTo *SignatureSubject |
|
114 |
+} |
|
115 |
+ |
|
116 |
+// These are valid conditions of an image signature. |
|
117 |
+const ( |
|
118 |
+ // SignatureTrusted means the signing key or certificate was valid and the signature matched the image at |
|
119 |
+ // the probe time. |
|
120 |
+ SignatureTrusted = "Trusted" |
|
121 |
+ // SignatureForImage means the signature matches image object containing it. |
|
122 |
+ SignatureForImage = "ForImage" |
|
123 |
+ // SignatureExpired means the signature or its signing key or certificate had been expired at the probe |
|
124 |
+ // time. |
|
125 |
+ SignatureExpired = "Expired" |
|
126 |
+ // SignatureRevoked means the signature or its signing key or certificate has been revoked. |
|
127 |
+ SignatureRevoked = "Revoked" |
|
128 |
+) |
|
129 |
+ |
|
130 |
+/// SignatureConditionType is a type of image signature condition. |
|
131 |
+type SignatureConditionType string |
|
132 |
+ |
|
133 |
+// SignatureCondition describes an image signature condition of particular kind at particular probe time. |
|
134 |
+type SignatureCondition struct { |
|
135 |
+ // Type of job condition, Complete or Failed. |
|
136 |
+ Type SignatureConditionType |
|
137 |
+ // Status of the condition, one of True, False, Unknown. |
|
138 |
+ Status kapi.ConditionStatus |
|
139 |
+ // Last time the condition was checked. |
|
140 |
+ LastProbeTime unversioned.Time |
|
141 |
+ // Last time the condition transit from one status to another. |
|
142 |
+ LastTransitionTime unversioned.Time |
|
143 |
+ // (brief) reason for the condition's last transition. |
|
144 |
+ Reason string |
|
145 |
+ // Human readable message indicating details about last transition. |
|
146 |
+ Message string |
|
147 |
+} |
|
148 |
+ |
|
149 |
+// SignatureGenericEntity holds a generic information about a person or entity who is an issuer or a subject |
|
150 |
+// of signing certificate or key. |
|
151 |
+type SignatureGenericEntity struct { |
|
152 |
+ // Organization name. |
|
153 |
+ Organization string |
|
154 |
+ // Common name (e.g. openshift-signing-service). |
|
155 |
+ CommonName string |
|
156 |
+} |
|
157 |
+ |
|
158 |
+// SignatureIssuer holds information about an issuer of signing certificate or key. |
|
159 |
+type SignatureIssuer struct { |
|
160 |
+ SignatureGenericEntity |
|
161 |
+} |
|
162 |
+ |
|
163 |
+// SignatureSubject holds information about a person or entity who created the signature. |
|
164 |
+type SignatureSubject struct { |
|
165 |
+ SignatureGenericEntity |
|
166 |
+ // If present, it is a human readable key id of public key belonging to the subject used to verify image |
|
167 |
+ // signature. It should contain at least 64 lowest bits of public key's fingerprint (e.g. |
|
168 |
+ // 0x685ebe62bf278440). |
|
169 |
+ PublicKeyID string |
|
170 |
+} |
|
171 |
+ |
|
79 | 172 |
// ImageStreamList is a list of ImageStream objects. |
80 | 173 |
type ImageStreamList struct { |
81 | 174 |
unversioned.TypeMeta |
... | ... |
@@ -52,6 +52,17 @@ func Convert_api_Image_To_v1_Image(in *newer.Image, out *Image, s conversion.Sco |
52 | 52 |
out.DockerImageLayers = nil |
53 | 53 |
} |
54 | 54 |
|
55 |
+ if in.Signatures != nil { |
|
56 |
+ out.Signatures = make([]ImageSignature, len(in.Signatures)) |
|
57 |
+ for i := range in.Signatures { |
|
58 |
+ if err := s.Convert(&in.Signatures[i], &out.Signatures[i], 0); err != nil { |
|
59 |
+ return err |
|
60 |
+ } |
|
61 |
+ } |
|
62 |
+ } else { |
|
63 |
+ out.Signatures = nil |
|
64 |
+ } |
|
65 |
+ |
|
55 | 66 |
return nil |
56 | 67 |
} |
57 | 68 |
|
... | ... |
@@ -92,6 +103,17 @@ func Convert_v1_Image_To_api_Image(in *Image, out *newer.Image, s conversion.Sco |
92 | 92 |
out.DockerImageLayers = nil |
93 | 93 |
} |
94 | 94 |
|
95 |
+ if in.Signatures != nil { |
|
96 |
+ out.Signatures = make([]newer.ImageSignature, len(in.Signatures)) |
|
97 |
+ for i := range in.Signatures { |
|
98 |
+ if err := s.Convert(&in.Signatures[i], &out.Signatures[i], 0); err != nil { |
|
99 |
+ return err |
|
100 |
+ } |
|
101 |
+ } |
|
102 |
+ } else { |
|
103 |
+ out.Signatures = nil |
|
104 |
+ } |
|
105 |
+ |
|
95 | 106 |
return nil |
96 | 107 |
} |
97 | 108 |
|
... | ... |
@@ -7,6 +7,7 @@ package v1 |
7 | 7 |
import ( |
8 | 8 |
image_api "github.com/openshift/origin/pkg/image/api" |
9 | 9 |
api "k8s.io/kubernetes/pkg/api" |
10 |
+ unversioned "k8s.io/kubernetes/pkg/api/unversioned" |
|
10 | 11 |
api_v1 "k8s.io/kubernetes/pkg/api/v1" |
11 | 12 |
conversion "k8s.io/kubernetes/pkg/conversion" |
12 | 13 |
reflect "reflect" |
... | ... |
@@ -26,6 +27,8 @@ func init() { |
26 | 26 |
Convert_api_ImageLayer_To_v1_ImageLayer, |
27 | 27 |
Convert_v1_ImageList_To_api_ImageList, |
28 | 28 |
Convert_api_ImageList_To_v1_ImageList, |
29 |
+ Convert_v1_ImageSignature_To_api_ImageSignature, |
|
30 |
+ Convert_api_ImageSignature_To_v1_ImageSignature, |
|
29 | 31 |
Convert_v1_ImageStream_To_api_ImageStream, |
30 | 32 |
Convert_api_ImageStream_To_v1_ImageStream, |
31 | 33 |
Convert_v1_ImageStreamImage_To_api_ImageStreamImage, |
... | ... |
@@ -52,6 +55,14 @@ func init() { |
52 | 52 |
Convert_api_RepositoryImportSpec_To_v1_RepositoryImportSpec, |
53 | 53 |
Convert_v1_RepositoryImportStatus_To_api_RepositoryImportStatus, |
54 | 54 |
Convert_api_RepositoryImportStatus_To_v1_RepositoryImportStatus, |
55 |
+ Convert_v1_SignatureCondition_To_api_SignatureCondition, |
|
56 |
+ Convert_api_SignatureCondition_To_v1_SignatureCondition, |
|
57 |
+ Convert_v1_SignatureGenericEntity_To_api_SignatureGenericEntity, |
|
58 |
+ Convert_api_SignatureGenericEntity_To_v1_SignatureGenericEntity, |
|
59 |
+ Convert_v1_SignatureIssuer_To_api_SignatureIssuer, |
|
60 |
+ Convert_api_SignatureIssuer_To_v1_SignatureIssuer, |
|
61 |
+ Convert_v1_SignatureSubject_To_api_SignatureSubject, |
|
62 |
+ Convert_api_SignatureSubject_To_v1_SignatureSubject, |
|
55 | 63 |
Convert_v1_TagEvent_To_api_TagEvent, |
56 | 64 |
Convert_api_TagEvent_To_v1_TagEvent, |
57 | 65 |
Convert_v1_TagEventCondition_To_api_TagEventCondition, |
... | ... |
@@ -288,6 +299,132 @@ func Convert_api_ImageList_To_v1_ImageList(in *image_api.ImageList, out *ImageLi |
288 | 288 |
return autoConvert_api_ImageList_To_v1_ImageList(in, out, s) |
289 | 289 |
} |
290 | 290 |
|
291 |
+func autoConvert_v1_ImageSignature_To_api_ImageSignature(in *ImageSignature, out *image_api.ImageSignature, s conversion.Scope) error { |
|
292 |
+ if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
|
293 |
+ defaulting.(func(*ImageSignature))(in) |
|
294 |
+ } |
|
295 |
+ out.Type = in.Type |
|
296 |
+ if err := conversion.Convert_Slice_byte_To_Slice_byte(&in.Content, &out.Content, s); err != nil { |
|
297 |
+ return err |
|
298 |
+ } |
|
299 |
+ if in.Conditions != nil { |
|
300 |
+ in, out := &in.Conditions, &out.Conditions |
|
301 |
+ *out = make([]image_api.SignatureCondition, len(*in)) |
|
302 |
+ for i := range *in { |
|
303 |
+ if err := Convert_v1_SignatureCondition_To_api_SignatureCondition(&(*in)[i], &(*out)[i], s); err != nil { |
|
304 |
+ return err |
|
305 |
+ } |
|
306 |
+ } |
|
307 |
+ } else { |
|
308 |
+ out.Conditions = nil |
|
309 |
+ } |
|
310 |
+ out.ImageIdentity = in.ImageIdentity |
|
311 |
+ if in.SignedClaims != nil { |
|
312 |
+ in, out := &in.SignedClaims, &out.SignedClaims |
|
313 |
+ *out = make(map[string]string, len(*in)) |
|
314 |
+ for key, val := range *in { |
|
315 |
+ (*out)[key] = val |
|
316 |
+ } |
|
317 |
+ } else { |
|
318 |
+ out.SignedClaims = nil |
|
319 |
+ } |
|
320 |
+ if in.Created != nil { |
|
321 |
+ in, out := &in.Created, &out.Created |
|
322 |
+ *out = new(unversioned.Time) |
|
323 |
+ if err := api.Convert_unversioned_Time_To_unversioned_Time(*in, *out, s); err != nil { |
|
324 |
+ return err |
|
325 |
+ } |
|
326 |
+ } else { |
|
327 |
+ out.Created = nil |
|
328 |
+ } |
|
329 |
+ if in.IssuedBy != nil { |
|
330 |
+ in, out := &in.IssuedBy, &out.IssuedBy |
|
331 |
+ *out = new(image_api.SignatureIssuer) |
|
332 |
+ if err := Convert_v1_SignatureIssuer_To_api_SignatureIssuer(*in, *out, s); err != nil { |
|
333 |
+ return err |
|
334 |
+ } |
|
335 |
+ } else { |
|
336 |
+ out.IssuedBy = nil |
|
337 |
+ } |
|
338 |
+ if in.IssuedTo != nil { |
|
339 |
+ in, out := &in.IssuedTo, &out.IssuedTo |
|
340 |
+ *out = new(image_api.SignatureSubject) |
|
341 |
+ if err := Convert_v1_SignatureSubject_To_api_SignatureSubject(*in, *out, s); err != nil { |
|
342 |
+ return err |
|
343 |
+ } |
|
344 |
+ } else { |
|
345 |
+ out.IssuedTo = nil |
|
346 |
+ } |
|
347 |
+ return nil |
|
348 |
+} |
|
349 |
+ |
|
350 |
+func Convert_v1_ImageSignature_To_api_ImageSignature(in *ImageSignature, out *image_api.ImageSignature, s conversion.Scope) error { |
|
351 |
+ return autoConvert_v1_ImageSignature_To_api_ImageSignature(in, out, s) |
|
352 |
+} |
|
353 |
+ |
|
354 |
+func autoConvert_api_ImageSignature_To_v1_ImageSignature(in *image_api.ImageSignature, out *ImageSignature, s conversion.Scope) error { |
|
355 |
+ if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
|
356 |
+ defaulting.(func(*image_api.ImageSignature))(in) |
|
357 |
+ } |
|
358 |
+ out.Type = in.Type |
|
359 |
+ if err := conversion.Convert_Slice_byte_To_Slice_byte(&in.Content, &out.Content, s); err != nil { |
|
360 |
+ return err |
|
361 |
+ } |
|
362 |
+ if in.Conditions != nil { |
|
363 |
+ in, out := &in.Conditions, &out.Conditions |
|
364 |
+ *out = make([]SignatureCondition, len(*in)) |
|
365 |
+ for i := range *in { |
|
366 |
+ if err := Convert_api_SignatureCondition_To_v1_SignatureCondition(&(*in)[i], &(*out)[i], s); err != nil { |
|
367 |
+ return err |
|
368 |
+ } |
|
369 |
+ } |
|
370 |
+ } else { |
|
371 |
+ out.Conditions = nil |
|
372 |
+ } |
|
373 |
+ out.ImageIdentity = in.ImageIdentity |
|
374 |
+ if in.SignedClaims != nil { |
|
375 |
+ in, out := &in.SignedClaims, &out.SignedClaims |
|
376 |
+ *out = make(map[string]string, len(*in)) |
|
377 |
+ for key, val := range *in { |
|
378 |
+ (*out)[key] = val |
|
379 |
+ } |
|
380 |
+ } else { |
|
381 |
+ out.SignedClaims = nil |
|
382 |
+ } |
|
383 |
+ if in.Created != nil { |
|
384 |
+ in, out := &in.Created, &out.Created |
|
385 |
+ *out = new(unversioned.Time) |
|
386 |
+ if err := api.Convert_unversioned_Time_To_unversioned_Time(*in, *out, s); err != nil { |
|
387 |
+ return err |
|
388 |
+ } |
|
389 |
+ } else { |
|
390 |
+ out.Created = nil |
|
391 |
+ } |
|
392 |
+ if in.IssuedBy != nil { |
|
393 |
+ in, out := &in.IssuedBy, &out.IssuedBy |
|
394 |
+ *out = new(SignatureIssuer) |
|
395 |
+ if err := Convert_api_SignatureIssuer_To_v1_SignatureIssuer(*in, *out, s); err != nil { |
|
396 |
+ return err |
|
397 |
+ } |
|
398 |
+ } else { |
|
399 |
+ out.IssuedBy = nil |
|
400 |
+ } |
|
401 |
+ if in.IssuedTo != nil { |
|
402 |
+ in, out := &in.IssuedTo, &out.IssuedTo |
|
403 |
+ *out = new(SignatureSubject) |
|
404 |
+ if err := Convert_api_SignatureSubject_To_v1_SignatureSubject(*in, *out, s); err != nil { |
|
405 |
+ return err |
|
406 |
+ } |
|
407 |
+ } else { |
|
408 |
+ out.IssuedTo = nil |
|
409 |
+ } |
|
410 |
+ return nil |
|
411 |
+} |
|
412 |
+ |
|
413 |
+func Convert_api_ImageSignature_To_v1_ImageSignature(in *image_api.ImageSignature, out *ImageSignature, s conversion.Scope) error { |
|
414 |
+ return autoConvert_api_ImageSignature_To_v1_ImageSignature(in, out, s) |
|
415 |
+} |
|
416 |
+ |
|
291 | 417 |
func autoConvert_v1_ImageStream_To_api_ImageStream(in *ImageStream, out *image_api.ImageStream, s conversion.Scope) error { |
292 | 418 |
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
293 | 419 |
defaulting.(func(*ImageStream))(in) |
... | ... |
@@ -888,6 +1025,132 @@ func Convert_api_RepositoryImportStatus_To_v1_RepositoryImportStatus(in *image_a |
888 | 888 |
return autoConvert_api_RepositoryImportStatus_To_v1_RepositoryImportStatus(in, out, s) |
889 | 889 |
} |
890 | 890 |
|
891 |
+func autoConvert_v1_SignatureCondition_To_api_SignatureCondition(in *SignatureCondition, out *image_api.SignatureCondition, s conversion.Scope) error { |
|
892 |
+ if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
|
893 |
+ defaulting.(func(*SignatureCondition))(in) |
|
894 |
+ } |
|
895 |
+ out.Type = image_api.SignatureConditionType(in.Type) |
|
896 |
+ out.Status = api.ConditionStatus(in.Status) |
|
897 |
+ if err := api.Convert_unversioned_Time_To_unversioned_Time(&in.LastProbeTime, &out.LastProbeTime, s); err != nil { |
|
898 |
+ return err |
|
899 |
+ } |
|
900 |
+ if err := api.Convert_unversioned_Time_To_unversioned_Time(&in.LastTransitionTime, &out.LastTransitionTime, s); err != nil { |
|
901 |
+ return err |
|
902 |
+ } |
|
903 |
+ out.Reason = in.Reason |
|
904 |
+ out.Message = in.Message |
|
905 |
+ return nil |
|
906 |
+} |
|
907 |
+ |
|
908 |
+func Convert_v1_SignatureCondition_To_api_SignatureCondition(in *SignatureCondition, out *image_api.SignatureCondition, s conversion.Scope) error { |
|
909 |
+ return autoConvert_v1_SignatureCondition_To_api_SignatureCondition(in, out, s) |
|
910 |
+} |
|
911 |
+ |
|
912 |
+func autoConvert_api_SignatureCondition_To_v1_SignatureCondition(in *image_api.SignatureCondition, out *SignatureCondition, s conversion.Scope) error { |
|
913 |
+ if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
|
914 |
+ defaulting.(func(*image_api.SignatureCondition))(in) |
|
915 |
+ } |
|
916 |
+ out.Type = SignatureConditionType(in.Type) |
|
917 |
+ out.Status = api_v1.ConditionStatus(in.Status) |
|
918 |
+ if err := api.Convert_unversioned_Time_To_unversioned_Time(&in.LastProbeTime, &out.LastProbeTime, s); err != nil { |
|
919 |
+ return err |
|
920 |
+ } |
|
921 |
+ if err := api.Convert_unversioned_Time_To_unversioned_Time(&in.LastTransitionTime, &out.LastTransitionTime, s); err != nil { |
|
922 |
+ return err |
|
923 |
+ } |
|
924 |
+ out.Reason = in.Reason |
|
925 |
+ out.Message = in.Message |
|
926 |
+ return nil |
|
927 |
+} |
|
928 |
+ |
|
929 |
+func Convert_api_SignatureCondition_To_v1_SignatureCondition(in *image_api.SignatureCondition, out *SignatureCondition, s conversion.Scope) error { |
|
930 |
+ return autoConvert_api_SignatureCondition_To_v1_SignatureCondition(in, out, s) |
|
931 |
+} |
|
932 |
+ |
|
933 |
+func autoConvert_v1_SignatureGenericEntity_To_api_SignatureGenericEntity(in *SignatureGenericEntity, out *image_api.SignatureGenericEntity, s conversion.Scope) error { |
|
934 |
+ if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
|
935 |
+ defaulting.(func(*SignatureGenericEntity))(in) |
|
936 |
+ } |
|
937 |
+ out.Organization = in.Organization |
|
938 |
+ out.CommonName = in.CommonName |
|
939 |
+ return nil |
|
940 |
+} |
|
941 |
+ |
|
942 |
+func Convert_v1_SignatureGenericEntity_To_api_SignatureGenericEntity(in *SignatureGenericEntity, out *image_api.SignatureGenericEntity, s conversion.Scope) error { |
|
943 |
+ return autoConvert_v1_SignatureGenericEntity_To_api_SignatureGenericEntity(in, out, s) |
|
944 |
+} |
|
945 |
+ |
|
946 |
+func autoConvert_api_SignatureGenericEntity_To_v1_SignatureGenericEntity(in *image_api.SignatureGenericEntity, out *SignatureGenericEntity, s conversion.Scope) error { |
|
947 |
+ if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
|
948 |
+ defaulting.(func(*image_api.SignatureGenericEntity))(in) |
|
949 |
+ } |
|
950 |
+ out.Organization = in.Organization |
|
951 |
+ out.CommonName = in.CommonName |
|
952 |
+ return nil |
|
953 |
+} |
|
954 |
+ |
|
955 |
+func Convert_api_SignatureGenericEntity_To_v1_SignatureGenericEntity(in *image_api.SignatureGenericEntity, out *SignatureGenericEntity, s conversion.Scope) error { |
|
956 |
+ return autoConvert_api_SignatureGenericEntity_To_v1_SignatureGenericEntity(in, out, s) |
|
957 |
+} |
|
958 |
+ |
|
959 |
+func autoConvert_v1_SignatureIssuer_To_api_SignatureIssuer(in *SignatureIssuer, out *image_api.SignatureIssuer, s conversion.Scope) error { |
|
960 |
+ if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
|
961 |
+ defaulting.(func(*SignatureIssuer))(in) |
|
962 |
+ } |
|
963 |
+ if err := Convert_v1_SignatureGenericEntity_To_api_SignatureGenericEntity(&in.SignatureGenericEntity, &out.SignatureGenericEntity, s); err != nil { |
|
964 |
+ return err |
|
965 |
+ } |
|
966 |
+ return nil |
|
967 |
+} |
|
968 |
+ |
|
969 |
+func Convert_v1_SignatureIssuer_To_api_SignatureIssuer(in *SignatureIssuer, out *image_api.SignatureIssuer, s conversion.Scope) error { |
|
970 |
+ return autoConvert_v1_SignatureIssuer_To_api_SignatureIssuer(in, out, s) |
|
971 |
+} |
|
972 |
+ |
|
973 |
+func autoConvert_api_SignatureIssuer_To_v1_SignatureIssuer(in *image_api.SignatureIssuer, out *SignatureIssuer, s conversion.Scope) error { |
|
974 |
+ if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
|
975 |
+ defaulting.(func(*image_api.SignatureIssuer))(in) |
|
976 |
+ } |
|
977 |
+ if err := Convert_api_SignatureGenericEntity_To_v1_SignatureGenericEntity(&in.SignatureGenericEntity, &out.SignatureGenericEntity, s); err != nil { |
|
978 |
+ return err |
|
979 |
+ } |
|
980 |
+ return nil |
|
981 |
+} |
|
982 |
+ |
|
983 |
+func Convert_api_SignatureIssuer_To_v1_SignatureIssuer(in *image_api.SignatureIssuer, out *SignatureIssuer, s conversion.Scope) error { |
|
984 |
+ return autoConvert_api_SignatureIssuer_To_v1_SignatureIssuer(in, out, s) |
|
985 |
+} |
|
986 |
+ |
|
987 |
+func autoConvert_v1_SignatureSubject_To_api_SignatureSubject(in *SignatureSubject, out *image_api.SignatureSubject, s conversion.Scope) error { |
|
988 |
+ if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
|
989 |
+ defaulting.(func(*SignatureSubject))(in) |
|
990 |
+ } |
|
991 |
+ if err := Convert_v1_SignatureGenericEntity_To_api_SignatureGenericEntity(&in.SignatureGenericEntity, &out.SignatureGenericEntity, s); err != nil { |
|
992 |
+ return err |
|
993 |
+ } |
|
994 |
+ out.PublicKeyID = in.PublicKeyID |
|
995 |
+ return nil |
|
996 |
+} |
|
997 |
+ |
|
998 |
+func Convert_v1_SignatureSubject_To_api_SignatureSubject(in *SignatureSubject, out *image_api.SignatureSubject, s conversion.Scope) error { |
|
999 |
+ return autoConvert_v1_SignatureSubject_To_api_SignatureSubject(in, out, s) |
|
1000 |
+} |
|
1001 |
+ |
|
1002 |
+func autoConvert_api_SignatureSubject_To_v1_SignatureSubject(in *image_api.SignatureSubject, out *SignatureSubject, s conversion.Scope) error { |
|
1003 |
+ if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
|
1004 |
+ defaulting.(func(*image_api.SignatureSubject))(in) |
|
1005 |
+ } |
|
1006 |
+ if err := Convert_api_SignatureGenericEntity_To_v1_SignatureGenericEntity(&in.SignatureGenericEntity, &out.SignatureGenericEntity, s); err != nil { |
|
1007 |
+ return err |
|
1008 |
+ } |
|
1009 |
+ out.PublicKeyID = in.PublicKeyID |
|
1010 |
+ return nil |
|
1011 |
+} |
|
1012 |
+ |
|
1013 |
+func Convert_api_SignatureSubject_To_v1_SignatureSubject(in *image_api.SignatureSubject, out *SignatureSubject, s conversion.Scope) error { |
|
1014 |
+ return autoConvert_api_SignatureSubject_To_v1_SignatureSubject(in, out, s) |
|
1015 |
+} |
|
1016 |
+ |
|
891 | 1017 |
func autoConvert_v1_TagEvent_To_api_TagEvent(in *TagEvent, out *image_api.TagEvent, s conversion.Scope) error { |
892 | 1018 |
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found { |
893 | 1019 |
defaulting.(func(*TagEvent))(in) |
... | ... |
@@ -20,6 +20,7 @@ func init() { |
20 | 20 |
DeepCopy_v1_ImageImportStatus, |
21 | 21 |
DeepCopy_v1_ImageLayer, |
22 | 22 |
DeepCopy_v1_ImageList, |
23 |
+ DeepCopy_v1_ImageSignature, |
|
23 | 24 |
DeepCopy_v1_ImageStream, |
24 | 25 |
DeepCopy_v1_ImageStreamImage, |
25 | 26 |
DeepCopy_v1_ImageStreamImport, |
... | ... |
@@ -34,6 +35,10 @@ func init() { |
34 | 34 |
DeepCopy_v1_NamedTagEventList, |
35 | 35 |
DeepCopy_v1_RepositoryImportSpec, |
36 | 36 |
DeepCopy_v1_RepositoryImportStatus, |
37 |
+ DeepCopy_v1_SignatureCondition, |
|
38 |
+ DeepCopy_v1_SignatureGenericEntity, |
|
39 |
+ DeepCopy_v1_SignatureIssuer, |
|
40 |
+ DeepCopy_v1_SignatureSubject, |
|
37 | 41 |
DeepCopy_v1_TagEvent, |
38 | 42 |
DeepCopy_v1_TagEventCondition, |
39 | 43 |
DeepCopy_v1_TagImportPolicy, |
... | ... |
@@ -77,6 +82,17 @@ func DeepCopy_v1_Image(in Image, out *Image, c *conversion.Cloner) error { |
77 | 77 |
} else { |
78 | 78 |
out.DockerImageLayers = nil |
79 | 79 |
} |
80 |
+ if in.Signatures != nil { |
|
81 |
+ in, out := in.Signatures, &out.Signatures |
|
82 |
+ *out = make([]ImageSignature, len(in)) |
|
83 |
+ for i := range in { |
|
84 |
+ if err := DeepCopy_v1_ImageSignature(in[i], &(*out)[i], c); err != nil { |
|
85 |
+ return err |
|
86 |
+ } |
|
87 |
+ } |
|
88 |
+ } else { |
|
89 |
+ out.Signatures = nil |
|
90 |
+ } |
|
80 | 91 |
return nil |
81 | 92 |
} |
82 | 93 |
|
... | ... |
@@ -144,6 +160,66 @@ func DeepCopy_v1_ImageList(in ImageList, out *ImageList, c *conversion.Cloner) e |
144 | 144 |
return nil |
145 | 145 |
} |
146 | 146 |
|
147 |
+func DeepCopy_v1_ImageSignature(in ImageSignature, out *ImageSignature, c *conversion.Cloner) error { |
|
148 |
+ out.Type = in.Type |
|
149 |
+ if in.Content != nil { |
|
150 |
+ in, out := in.Content, &out.Content |
|
151 |
+ *out = make([]byte, len(in)) |
|
152 |
+ copy(*out, in) |
|
153 |
+ } else { |
|
154 |
+ out.Content = nil |
|
155 |
+ } |
|
156 |
+ if in.Conditions != nil { |
|
157 |
+ in, out := in.Conditions, &out.Conditions |
|
158 |
+ *out = make([]SignatureCondition, len(in)) |
|
159 |
+ for i := range in { |
|
160 |
+ if err := DeepCopy_v1_SignatureCondition(in[i], &(*out)[i], c); err != nil { |
|
161 |
+ return err |
|
162 |
+ } |
|
163 |
+ } |
|
164 |
+ } else { |
|
165 |
+ out.Conditions = nil |
|
166 |
+ } |
|
167 |
+ out.ImageIdentity = in.ImageIdentity |
|
168 |
+ if in.SignedClaims != nil { |
|
169 |
+ in, out := in.SignedClaims, &out.SignedClaims |
|
170 |
+ *out = make(map[string]string) |
|
171 |
+ for key, val := range in { |
|
172 |
+ (*out)[key] = val |
|
173 |
+ } |
|
174 |
+ } else { |
|
175 |
+ out.SignedClaims = nil |
|
176 |
+ } |
|
177 |
+ if in.Created != nil { |
|
178 |
+ in, out := in.Created, &out.Created |
|
179 |
+ *out = new(unversioned.Time) |
|
180 |
+ if err := unversioned.DeepCopy_unversioned_Time(*in, *out, c); err != nil { |
|
181 |
+ return err |
|
182 |
+ } |
|
183 |
+ } else { |
|
184 |
+ out.Created = nil |
|
185 |
+ } |
|
186 |
+ if in.IssuedBy != nil { |
|
187 |
+ in, out := in.IssuedBy, &out.IssuedBy |
|
188 |
+ *out = new(SignatureIssuer) |
|
189 |
+ if err := DeepCopy_v1_SignatureIssuer(*in, *out, c); err != nil { |
|
190 |
+ return err |
|
191 |
+ } |
|
192 |
+ } else { |
|
193 |
+ out.IssuedBy = nil |
|
194 |
+ } |
|
195 |
+ if in.IssuedTo != nil { |
|
196 |
+ in, out := in.IssuedTo, &out.IssuedTo |
|
197 |
+ *out = new(SignatureSubject) |
|
198 |
+ if err := DeepCopy_v1_SignatureSubject(*in, *out, c); err != nil { |
|
199 |
+ return err |
|
200 |
+ } |
|
201 |
+ } else { |
|
202 |
+ out.IssuedTo = nil |
|
203 |
+ } |
|
204 |
+ return nil |
|
205 |
+} |
|
206 |
+ |
|
147 | 207 |
func DeepCopy_v1_ImageStream(in ImageStream, out *ImageStream, c *conversion.Cloner) error { |
148 | 208 |
if err := unversioned.DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil { |
149 | 209 |
return err |
... | ... |
@@ -432,6 +508,41 @@ func DeepCopy_v1_RepositoryImportStatus(in RepositoryImportStatus, out *Reposito |
432 | 432 |
return nil |
433 | 433 |
} |
434 | 434 |
|
435 |
+func DeepCopy_v1_SignatureCondition(in SignatureCondition, out *SignatureCondition, c *conversion.Cloner) error { |
|
436 |
+ out.Type = in.Type |
|
437 |
+ out.Status = in.Status |
|
438 |
+ if err := unversioned.DeepCopy_unversioned_Time(in.LastProbeTime, &out.LastProbeTime, c); err != nil { |
|
439 |
+ return err |
|
440 |
+ } |
|
441 |
+ if err := unversioned.DeepCopy_unversioned_Time(in.LastTransitionTime, &out.LastTransitionTime, c); err != nil { |
|
442 |
+ return err |
|
443 |
+ } |
|
444 |
+ out.Reason = in.Reason |
|
445 |
+ out.Message = in.Message |
|
446 |
+ return nil |
|
447 |
+} |
|
448 |
+ |
|
449 |
+func DeepCopy_v1_SignatureGenericEntity(in SignatureGenericEntity, out *SignatureGenericEntity, c *conversion.Cloner) error { |
|
450 |
+ out.Organization = in.Organization |
|
451 |
+ out.CommonName = in.CommonName |
|
452 |
+ return nil |
|
453 |
+} |
|
454 |
+ |
|
455 |
+func DeepCopy_v1_SignatureIssuer(in SignatureIssuer, out *SignatureIssuer, c *conversion.Cloner) error { |
|
456 |
+ if err := DeepCopy_v1_SignatureGenericEntity(in.SignatureGenericEntity, &out.SignatureGenericEntity, c); err != nil { |
|
457 |
+ return err |
|
458 |
+ } |
|
459 |
+ return nil |
|
460 |
+} |
|
461 |
+ |
|
462 |
+func DeepCopy_v1_SignatureSubject(in SignatureSubject, out *SignatureSubject, c *conversion.Cloner) error { |
|
463 |
+ if err := DeepCopy_v1_SignatureGenericEntity(in.SignatureGenericEntity, &out.SignatureGenericEntity, c); err != nil { |
|
464 |
+ return err |
|
465 |
+ } |
|
466 |
+ out.PublicKeyID = in.PublicKeyID |
|
467 |
+ return nil |
|
468 |
+} |
|
469 |
+ |
|
435 | 470 |
func DeepCopy_v1_TagEvent(in TagEvent, out *TagEvent, c *conversion.Cloner) error { |
436 | 471 |
if err := unversioned.DeepCopy_unversioned_Time(in.Created, &out.Created, c); err != nil { |
437 | 472 |
return err |
... | ... |
@@ -26,6 +26,7 @@ var map_Image = map[string]string{ |
26 | 26 |
"dockerImageMetadataVersion": "DockerImageMetadataVersion conveys the version of the object, which if empty defaults to \"1.0\"", |
27 | 27 |
"dockerImageManifest": "DockerImageManifest is the raw JSON of the manifest", |
28 | 28 |
"dockerImageLayers": "DockerImageLayers represents the layers in the image. May not be set if the image does not define that data.", |
29 |
+ "signatures": "Signatures holds all signatures of the image.", |
|
29 | 30 |
} |
30 | 31 |
|
31 | 32 |
func (Image) SwaggerDoc() map[string]string { |
... | ... |
@@ -75,6 +76,22 @@ func (ImageList) SwaggerDoc() map[string]string { |
75 | 75 |
return map_ImageList |
76 | 76 |
} |
77 | 77 |
|
78 |
+var map_ImageSignature = map[string]string{ |
|
79 |
+ "": "ImageSignature holds a signature of an image. It allows to verify image identity and possibly other claims as long as the signature is trusted. Based on this information it is possible to restrict runnable images to those matching cluster-wide policy. There are two mandatory fields provided by client: Type and Content. They should be parsed by clients doing image verification. The others are parsed from signature's content by the server. They serve just an informative purpose.", |
|
80 |
+ "type": "Required: Describes a type of stored blob.", |
|
81 |
+ "content": "Required: An opaque binary string which is an image's signature.", |
|
82 |
+ "conditions": "Conditions represent the latest available observations of a signature's current state.", |
|
83 |
+ "imageIdentity": "A human readable string representing image's identity. It could be a product name and version, or an image pull spec (e.g. \"registry.access.redhat.com/rhel7/rhel:7.2\").", |
|
84 |
+ "signedClaims": "Contains claims from the signature.", |
|
85 |
+ "created": "If specified, it is the time of signature's creation.", |
|
86 |
+ "issuedBy": "If specified, it holds information about an issuer of signing certificate or key (a person or entity who signed the signing certificate or key).", |
|
87 |
+ "issuedTo": "If specified, it holds information about a subject of signing certificate or key (a person or entity who signed the image).", |
|
88 |
+} |
|
89 |
+ |
|
90 |
+func (ImageSignature) SwaggerDoc() map[string]string { |
|
91 |
+ return map_ImageSignature |
|
92 |
+} |
|
93 |
+ |
|
78 | 94 |
var map_ImageStream = map[string]string{ |
79 | 95 |
"": "ImageStream stores a mapping of tags to images, metadata overrides that are applied when images are tagged in a stream, and an optional reference to a Docker image repository on a registry.", |
80 | 96 |
"metadata": "Standard object's metadata.", |
... | ... |
@@ -226,6 +243,47 @@ func (RepositoryImportStatus) SwaggerDoc() map[string]string { |
226 | 226 |
return map_RepositoryImportStatus |
227 | 227 |
} |
228 | 228 |
|
229 |
+var map_SignatureCondition = map[string]string{ |
|
230 |
+ "": "SignatureCondition describes an image signature condition of particular kind at particular probe time.", |
|
231 |
+ "type": "Type of job condition, Complete or Failed.", |
|
232 |
+ "status": "Status of the condition, one of True, False, Unknown.", |
|
233 |
+ "lastProbeTime": "Last time the condition was checked.", |
|
234 |
+ "lastTransitionTime": "Last time the condition transit from one status to another.", |
|
235 |
+ "reason": "(brief) reason for the condition's last transition.", |
|
236 |
+ "message": "Human readable message indicating details about last transition.", |
|
237 |
+} |
|
238 |
+ |
|
239 |
+func (SignatureCondition) SwaggerDoc() map[string]string { |
|
240 |
+ return map_SignatureCondition |
|
241 |
+} |
|
242 |
+ |
|
243 |
+var map_SignatureGenericEntity = map[string]string{ |
|
244 |
+ "": "SignatureGenericEntity holds a generic information about a person or entity who is an issuer or a subject of signing certificate or key.", |
|
245 |
+ "organization": "Organization name.", |
|
246 |
+ "commonName": "Common name (e.g. openshift-signing-service).", |
|
247 |
+} |
|
248 |
+ |
|
249 |
+func (SignatureGenericEntity) SwaggerDoc() map[string]string { |
|
250 |
+ return map_SignatureGenericEntity |
|
251 |
+} |
|
252 |
+ |
|
253 |
+var map_SignatureIssuer = map[string]string{ |
|
254 |
+ "": "SignatureIssuer holds information about an issuer of signing certificate or key.", |
|
255 |
+} |
|
256 |
+ |
|
257 |
+func (SignatureIssuer) SwaggerDoc() map[string]string { |
|
258 |
+ return map_SignatureIssuer |
|
259 |
+} |
|
260 |
+ |
|
261 |
+var map_SignatureSubject = map[string]string{ |
|
262 |
+ "": "SignatureSubject holds information about a person or entity who created the signature.", |
|
263 |
+ "publicKeyID": "If present, it is a human readable key id of public key belonging to the subject used to verify image signature. It should contain at least 64 lowest bits of public key's fingerprint (e.g. 0x685ebe62bf278440).", |
|
264 |
+} |
|
265 |
+ |
|
266 |
+func (SignatureSubject) SwaggerDoc() map[string]string { |
|
267 |
+ return map_SignatureSubject |
|
268 |
+} |
|
269 |
+ |
|
229 | 270 |
var map_TagEvent = map[string]string{ |
230 | 271 |
"": "TagEvent is used by ImageStreamStatus to keep a historical record of images associated with a tag.", |
231 | 272 |
"created": "Created holds the time the TagEvent was created", |
... | ... |
@@ -32,6 +32,8 @@ type Image struct { |
32 | 32 |
DockerImageManifest string `json:"dockerImageManifest,omitempty"` |
33 | 33 |
// DockerImageLayers represents the layers in the image. May not be set if the image does not define that data. |
34 | 34 |
DockerImageLayers []ImageLayer `json:"dockerImageLayers"` |
35 |
+ // Signatures holds all signatures of the image. |
|
36 |
+ Signatures []ImageSignature `json:"signatures,omitempty"` |
|
35 | 37 |
} |
36 | 38 |
|
37 | 39 |
// ImageLayer represents a single layer of the image. Some images may have multiple layers. Some may have none. |
... | ... |
@@ -42,6 +44,80 @@ type ImageLayer struct { |
42 | 42 |
Size int64 `json:"size"` |
43 | 43 |
} |
44 | 44 |
|
45 |
+// ImageSignature holds a signature of an image. It allows to verify image identity and possibly other claims |
|
46 |
+// as long as the signature is trusted. Based on this information it is possible to restrict runnable images |
|
47 |
+// to those matching cluster-wide policy. |
|
48 |
+// There are two mandatory fields provided by client: Type and Content. They should be parsed by clients doing |
|
49 |
+// image verification. The others are parsed from signature's content by the server. They serve just an |
|
50 |
+// informative purpose. |
|
51 |
+type ImageSignature struct { |
|
52 |
+ // Required: Describes a type of stored blob. |
|
53 |
+ Type string `json:"type"` |
|
54 |
+ // Required: An opaque binary string which is an image's signature. |
|
55 |
+ Content []byte `json:"content"` |
|
56 |
+ // Conditions represent the latest available observations of a signature's current state. |
|
57 |
+ Conditions []SignatureCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` |
|
58 |
+ |
|
59 |
+ // Following metadata fields will be set by server if the signature content is successfully parsed and |
|
60 |
+ // the information available. |
|
61 |
+ |
|
62 |
+ // A human readable string representing image's identity. It could be a product name and version, or an |
|
63 |
+ // image pull spec (e.g. "registry.access.redhat.com/rhel7/rhel:7.2"). |
|
64 |
+ ImageIdentity string `json:"imageIdentity,omitempty"` |
|
65 |
+ // Contains claims from the signature. |
|
66 |
+ SignedClaims map[string]string `json:"signedClaims,omitempty"` |
|
67 |
+ // If specified, it is the time of signature's creation. |
|
68 |
+ Created *unversioned.Time `json:"created,omitempty"` |
|
69 |
+ // If specified, it holds information about an issuer of signing certificate or key (a person or entity |
|
70 |
+ // who signed the signing certificate or key). |
|
71 |
+ IssuedBy *SignatureIssuer `json:"issuedBy,omitempty"` |
|
72 |
+ // If specified, it holds information about a subject of signing certificate or key (a person or entity |
|
73 |
+ // who signed the image). |
|
74 |
+ IssuedTo *SignatureSubject `json:"issuedTo,omitempty"` |
|
75 |
+} |
|
76 |
+ |
|
77 |
+/// SignatureConditionType is a type of image signature condition. |
|
78 |
+type SignatureConditionType string |
|
79 |
+ |
|
80 |
+// SignatureCondition describes an image signature condition of particular kind at particular probe time. |
|
81 |
+type SignatureCondition struct { |
|
82 |
+ // Type of job condition, Complete or Failed. |
|
83 |
+ Type SignatureConditionType `json:"type"` |
|
84 |
+ // Status of the condition, one of True, False, Unknown. |
|
85 |
+ Status kapi.ConditionStatus `json:"status"` |
|
86 |
+ // Last time the condition was checked. |
|
87 |
+ LastProbeTime unversioned.Time `json:"lastProbeTime,omitempty"` |
|
88 |
+ // Last time the condition transit from one status to another. |
|
89 |
+ LastTransitionTime unversioned.Time `json:"lastTransitionTime,omitempty"` |
|
90 |
+ // (brief) reason for the condition's last transition. |
|
91 |
+ Reason string `json:"reason,omitempty"` |
|
92 |
+ // Human readable message indicating details about last transition. |
|
93 |
+ Message string `json:"message,omitempty"` |
|
94 |
+} |
|
95 |
+ |
|
96 |
+// SignatureGenericEntity holds a generic information about a person or entity who is an issuer or a subject |
|
97 |
+// of signing certificate or key. |
|
98 |
+type SignatureGenericEntity struct { |
|
99 |
+ // Organization name. |
|
100 |
+ Organization string `json:"organization,omitempty"` |
|
101 |
+ // Common name (e.g. openshift-signing-service). |
|
102 |
+ CommonName string `json:"commonName,omitempty"` |
|
103 |
+} |
|
104 |
+ |
|
105 |
+// SignatureIssuer holds information about an issuer of signing certificate or key. |
|
106 |
+type SignatureIssuer struct { |
|
107 |
+ SignatureGenericEntity `json:",inline"` |
|
108 |
+} |
|
109 |
+ |
|
110 |
+// SignatureSubject holds information about a person or entity who created the signature. |
|
111 |
+type SignatureSubject struct { |
|
112 |
+ SignatureGenericEntity `json:",inline"` |
|
113 |
+ // If present, it is a human readable key id of public key belonging to the subject used to verify image |
|
114 |
+ // signature. It should contain at least 64 lowest bits of public key's fingerprint (e.g. |
|
115 |
+ // 0x685ebe62bf278440). |
|
116 |
+ PublicKeyID string `json:"publicKeyID"` |
|
117 |
+} |
|
118 |
+ |
|
45 | 119 |
// ImageStreamList is a list of ImageStream objects. |
46 | 120 |
type ImageStreamList struct { |
47 | 121 |
unversioned.TypeMeta `json:",inline"` |
... | ... |
@@ -29,6 +29,8 @@ type Image struct { |
29 | 29 |
DockerImageManifest string `json:"dockerImageManifest,omitempty"` |
30 | 30 |
// DockerImageLayers represents the layers in the image. May not be set if the image does not define that data. |
31 | 31 |
DockerImageLayers []ImageLayer `json:"dockerImageLayers"` |
32 |
+ // Signatures holds all signatures of the image. |
|
33 |
+ Signatures []ImageSignature |
|
32 | 34 |
} |
33 | 35 |
|
34 | 36 |
// ImageLayer represents a single layer of the image. Some images may have multiple layers. Some may have none. |
... | ... |
@@ -39,6 +41,80 @@ type ImageLayer struct { |
39 | 39 |
Size int64 `json:"size"` |
40 | 40 |
} |
41 | 41 |
|
42 |
+// ImageSignature holds a signature of an image. It allows to verify image identity and possibly other claims |
|
43 |
+// as long as the signature is trusted. Based on this information it is possible to restrict runnable images |
|
44 |
+// to those matching cluster-wide policy. |
|
45 |
+// There are two mandatory fields provided by client: Type and Content. They should be parsed by clients doing |
|
46 |
+// image verification. The others are parsed from signature's content by the server. They serve just an |
|
47 |
+// informative purpose. |
|
48 |
+type ImageSignature struct { |
|
49 |
+ // Required: Describes a type of stored blob. |
|
50 |
+ Type string `json:"type"` |
|
51 |
+ // Required: An opaque binary string which is an image's signature. |
|
52 |
+ Content []byte `json:"content"` |
|
53 |
+ // Conditions represent the latest available observations of a signature's current state. |
|
54 |
+ Conditions []SignatureCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` |
|
55 |
+ |
|
56 |
+ // Following metadata fields will be set by server if the signature content is successfully parsed and |
|
57 |
+ // the information available. |
|
58 |
+ |
|
59 |
+ // A human readable string representing image's identity. It could be a product name and version, or an |
|
60 |
+ // image pull spec (e.g. "registry.access.redhat.com/rhel7/rhel:7.2"). |
|
61 |
+ ImageIdentity string `json:"imageIdentity,omitempty"` |
|
62 |
+ // Contains claims from the signature. |
|
63 |
+ SignedClaims map[string]string `json:"signedClaims,omitempty"` |
|
64 |
+ // If specified, it is the time of signature's creation. |
|
65 |
+ Created *unversioned.Time `json:"created,omitempty"` |
|
66 |
+ // If specified, it holds information about an issuer of signing certificate or key (a person or entity |
|
67 |
+ // who signed the signing certificate or key). |
|
68 |
+ IssuedBy *SignatureIssuer `json:"issuedBy,omitempty"` |
|
69 |
+ // If specified, it holds information about a subject of signing certificate or key (a person or entity |
|
70 |
+ // who signed the image). |
|
71 |
+ IssuedTo *SignatureSubject `json:"issuedTo,omitempty"` |
|
72 |
+} |
|
73 |
+ |
|
74 |
+/// SignatureConditionType is a type of image signature condition. |
|
75 |
+type SignatureConditionType string |
|
76 |
+ |
|
77 |
+// SignatureCondition describes an image signature condition of particular kind at particular probe time. |
|
78 |
+type SignatureCondition struct { |
|
79 |
+ // Type of job condition, Complete or Failed. |
|
80 |
+ Type SignatureConditionType `json:"type"` |
|
81 |
+ // Status of the condition, one of True, False, Unknown. |
|
82 |
+ Status kapi.ConditionStatus `json:"status"` |
|
83 |
+ // Last time the condition was checked. |
|
84 |
+ LastProbeTime unversioned.Time `json:"lastProbeTime,omitempty"` |
|
85 |
+ // Last time the condition transit from one status to another. |
|
86 |
+ LastTransitionTime unversioned.Time `json:"lastTransitionTime,omitempty"` |
|
87 |
+ // (brief) reason for the condition's last transition. |
|
88 |
+ Reason string `json:"reason,omitempty"` |
|
89 |
+ // Human readable message indicating details about last transition. |
|
90 |
+ Message string `json:"message,omitempty"` |
|
91 |
+} |
|
92 |
+ |
|
93 |
+// SignatureGenericEntity holds a generic information about a person or entity who is an issuer or a subject |
|
94 |
+// of signing certificate or key. |
|
95 |
+type SignatureGenericEntity struct { |
|
96 |
+ // Organization name. |
|
97 |
+ Organization string `json:"organization,omitempty"` |
|
98 |
+ // Common name (e.g. openshift-signing-service). |
|
99 |
+ CommonName string `json:"commonName,omitempty"` |
|
100 |
+} |
|
101 |
+ |
|
102 |
+// SignatureIssuer holds information about an issuer of signing certificate or key. |
|
103 |
+type SignatureIssuer struct { |
|
104 |
+ SignatureGenericEntity `json:",inline"` |
|
105 |
+} |
|
106 |
+ |
|
107 |
+// SignatureSubject holds information about a person or entity who created the signature. |
|
108 |
+type SignatureSubject struct { |
|
109 |
+ SignatureGenericEntity `json:",inline"` |
|
110 |
+ // If present, it is a human readable key id of public key belonging to the subject used to verify image |
|
111 |
+ // signature. It should contain at least 64 lowest bits of public key's fingerprint (e.g. |
|
112 |
+ // 0x685ebe62bf278440). |
|
113 |
+ PublicKeyID string `json:"publicKeyID"` |
|
114 |
+} |
|
115 |
+ |
|
42 | 116 |
// ImageStreamList is a list of ImageStream objects. |
43 | 117 |
type ImageStreamList struct { |
44 | 118 |
unversioned.TypeMeta `json:",inline"` |
... | ... |
@@ -59,9 +59,59 @@ func validateImage(image *api.Image, fldPath *field.Path) field.ErrorList { |
59 | 59 |
} |
60 | 60 |
} |
61 | 61 |
|
62 |
+ for i, sig := range image.Signatures { |
|
63 |
+ result = append(result, validateImageSignature(&sig, fldPath.Child("signatures").Index(i))...) |
|
64 |
+ } |
|
65 |
+ |
|
62 | 66 |
return result |
63 | 67 |
} |
64 | 68 |
|
69 |
+func validateImageSignature(signature *api.ImageSignature, fldPath *field.Path) field.ErrorList { |
|
70 |
+ allErrs := field.ErrorList{} |
|
71 |
+ |
|
72 |
+ if len(signature.Type) == 0 { |
|
73 |
+ allErrs = append(allErrs, field.Required(fldPath.Child("type"), "")) |
|
74 |
+ } |
|
75 |
+ if len(signature.Content) == 0 { |
|
76 |
+ allErrs = append(allErrs, field.Required(fldPath.Child("content"), "")) |
|
77 |
+ } |
|
78 |
+ |
|
79 |
+ var trustedCondition, forImageCondition *api.SignatureCondition |
|
80 |
+ for i := range signature.Conditions { |
|
81 |
+ cond := &signature.Conditions[i] |
|
82 |
+ if cond.Type == api.SignatureTrusted && (trustedCondition == nil || !cond.LastProbeTime.Before(trustedCondition.LastProbeTime)) { |
|
83 |
+ trustedCondition = cond |
|
84 |
+ } else if cond.Type == api.SignatureForImage && forImageCondition == nil || !cond.LastProbeTime.Before(forImageCondition.LastProbeTime) { |
|
85 |
+ forImageCondition = cond |
|
86 |
+ } |
|
87 |
+ } |
|
88 |
+ |
|
89 |
+ if trustedCondition != nil && forImageCondition == nil { |
|
90 |
+ msg := fmt.Sprintf("missing %q condition type", api.SignatureForImage) |
|
91 |
+ allErrs = append(allErrs, field.Invalid(fldPath.Child("conditions"), signature.Conditions, msg)) |
|
92 |
+ } else if forImageCondition != nil && trustedCondition == nil { |
|
93 |
+ msg := fmt.Sprintf("missing %q condition type", api.SignatureTrusted) |
|
94 |
+ allErrs = append(allErrs, field.Invalid(fldPath.Child("conditions"), signature.Conditions, msg)) |
|
95 |
+ } |
|
96 |
+ |
|
97 |
+ if trustedCondition == nil || trustedCondition.Status == kapi.ConditionUnknown { |
|
98 |
+ if len(signature.ImageIdentity) != 0 { |
|
99 |
+ allErrs = append(allErrs, field.Invalid(fldPath.Child("imageIdentity"), signature.ImageIdentity, "must be unset for unknown signature state")) |
|
100 |
+ } |
|
101 |
+ if len(signature.SignedClaims) != 0 { |
|
102 |
+ allErrs = append(allErrs, field.Invalid(fldPath.Child("signedClaims"), signature.SignedClaims, "must be unset for unknown signature state")) |
|
103 |
+ } |
|
104 |
+ if signature.IssuedBy != nil { |
|
105 |
+ allErrs = append(allErrs, field.Invalid(fldPath.Child("issuedBy"), signature.IssuedBy, "must be unset for unknown signature state")) |
|
106 |
+ } |
|
107 |
+ if signature.IssuedTo != nil { |
|
108 |
+ allErrs = append(allErrs, field.Invalid(fldPath.Child("issuedTo"), signature.IssuedTo, "must be unset for unknown signature state")) |
|
109 |
+ } |
|
110 |
+ } |
|
111 |
+ |
|
112 |
+ return allErrs |
|
113 |
+} |
|
114 |
+ |
|
65 | 115 |
func ValidateImageUpdate(newImage, oldImage *api.Image) field.ErrorList { |
66 | 116 |
result := validation.ValidateObjectMetaUpdate(&newImage.ObjectMeta, &oldImage.ObjectMeta, field.NewPath("metadata")) |
67 | 117 |
result = append(result, ValidateImage(newImage)...) |
... | ... |
@@ -1,14 +1,16 @@ |
1 | 1 |
package validation |
2 | 2 |
|
3 | 3 |
import ( |
4 |
+ "fmt" |
|
4 | 5 |
"reflect" |
5 | 6 |
"strings" |
6 | 7 |
"testing" |
7 | 8 |
|
8 |
- "github.com/openshift/origin/pkg/image/api" |
|
9 | 9 |
kapi "k8s.io/kubernetes/pkg/api" |
10 | 10 |
"k8s.io/kubernetes/pkg/util/diff" |
11 | 11 |
"k8s.io/kubernetes/pkg/util/validation/field" |
12 |
+ |
|
13 |
+ "github.com/openshift/origin/pkg/image/api" |
|
12 | 14 |
) |
13 | 15 |
|
14 | 16 |
func TestValidateImageOK(t *testing.T) { |
... | ... |
@@ -68,6 +70,149 @@ func TestValidateImageMissingFields(t *testing.T) { |
68 | 68 |
} |
69 | 69 |
} |
70 | 70 |
|
71 |
+func TestValidateImageSignature(t *testing.T) { |
|
72 |
+ for _, tc := range []struct { |
|
73 |
+ name string |
|
74 |
+ signature api.ImageSignature |
|
75 |
+ expected field.ErrorList |
|
76 |
+ }{ |
|
77 |
+ { |
|
78 |
+ name: "valid", |
|
79 |
+ signature: api.ImageSignature{ |
|
80 |
+ Type: "valid", |
|
81 |
+ Content: []byte("blob"), |
|
82 |
+ }, |
|
83 |
+ expected: field.ErrorList{}, |
|
84 |
+ }, |
|
85 |
+ |
|
86 |
+ { |
|
87 |
+ name: "valid trusted", |
|
88 |
+ signature: api.ImageSignature{ |
|
89 |
+ Type: "valid", |
|
90 |
+ Content: []byte("blob"), |
|
91 |
+ Conditions: []api.SignatureCondition{ |
|
92 |
+ { |
|
93 |
+ Type: api.SignatureTrusted, |
|
94 |
+ Status: kapi.ConditionTrue, |
|
95 |
+ }, |
|
96 |
+ { |
|
97 |
+ Type: api.SignatureForImage, |
|
98 |
+ Status: kapi.ConditionTrue, |
|
99 |
+ }, |
|
100 |
+ }, |
|
101 |
+ ImageIdentity: "registry.company.ltd/app/core:v1.2", |
|
102 |
+ }, |
|
103 |
+ expected: field.ErrorList{}, |
|
104 |
+ }, |
|
105 |
+ |
|
106 |
+ { |
|
107 |
+ name: "valid untrusted", |
|
108 |
+ signature: api.ImageSignature{ |
|
109 |
+ Type: "valid", |
|
110 |
+ Content: []byte("blob"), |
|
111 |
+ Conditions: []api.SignatureCondition{ |
|
112 |
+ { |
|
113 |
+ Type: api.SignatureTrusted, |
|
114 |
+ Status: kapi.ConditionTrue, |
|
115 |
+ }, |
|
116 |
+ { |
|
117 |
+ Type: api.SignatureForImage, |
|
118 |
+ Status: kapi.ConditionFalse, |
|
119 |
+ }, |
|
120 |
+ // compare the latest condition |
|
121 |
+ { |
|
122 |
+ Type: api.SignatureTrusted, |
|
123 |
+ Status: kapi.ConditionFalse, |
|
124 |
+ }, |
|
125 |
+ }, |
|
126 |
+ ImageIdentity: "registry.company.ltd/app/core:v1.2", |
|
127 |
+ }, |
|
128 |
+ expected: field.ErrorList{}, |
|
129 |
+ }, |
|
130 |
+ |
|
131 |
+ { |
|
132 |
+ name: "missing type", |
|
133 |
+ signature: api.ImageSignature{ |
|
134 |
+ Content: []byte("blob"), |
|
135 |
+ }, |
|
136 |
+ expected: field.ErrorList{ |
|
137 |
+ field.Required(field.NewPath("type"), ""), |
|
138 |
+ }, |
|
139 |
+ }, |
|
140 |
+ |
|
141 |
+ { |
|
142 |
+ name: "missing content", |
|
143 |
+ signature: api.ImageSignature{ |
|
144 |
+ Type: "invalid", |
|
145 |
+ }, |
|
146 |
+ expected: field.ErrorList{ |
|
147 |
+ field.Required(field.NewPath("content"), ""), |
|
148 |
+ }, |
|
149 |
+ }, |
|
150 |
+ |
|
151 |
+ { |
|
152 |
+ name: "missing ForImage condition", |
|
153 |
+ signature: api.ImageSignature{ |
|
154 |
+ Type: "invalid", |
|
155 |
+ Content: []byte("blob"), |
|
156 |
+ Conditions: []api.SignatureCondition{ |
|
157 |
+ { |
|
158 |
+ Type: api.SignatureTrusted, |
|
159 |
+ Status: kapi.ConditionTrue, |
|
160 |
+ }, |
|
161 |
+ }, |
|
162 |
+ ImageIdentity: "registry.company.ltd/app/core:v1.2", |
|
163 |
+ }, |
|
164 |
+ expected: field.ErrorList{field.Invalid(field.NewPath("conditions"), |
|
165 |
+ []api.SignatureCondition{ |
|
166 |
+ { |
|
167 |
+ Type: api.SignatureTrusted, |
|
168 |
+ Status: kapi.ConditionTrue, |
|
169 |
+ }, |
|
170 |
+ }, |
|
171 |
+ fmt.Sprintf("missing %q condition type", api.SignatureForImage))}, |
|
172 |
+ }, |
|
173 |
+ |
|
174 |
+ { |
|
175 |
+ name: "filled metadata for unknown signature state", |
|
176 |
+ signature: api.ImageSignature{ |
|
177 |
+ Type: "invalid", |
|
178 |
+ Content: []byte("blob"), |
|
179 |
+ Conditions: []api.SignatureCondition{ |
|
180 |
+ { |
|
181 |
+ Type: api.SignatureTrusted, |
|
182 |
+ Status: kapi.ConditionUnknown, |
|
183 |
+ }, |
|
184 |
+ { |
|
185 |
+ Type: api.SignatureForImage, |
|
186 |
+ Status: kapi.ConditionUnknown, |
|
187 |
+ }, |
|
188 |
+ }, |
|
189 |
+ ImageIdentity: "registry.company.ltd/app/core:v1.2", |
|
190 |
+ SignedClaims: map[string]string{"claim": "value"}, |
|
191 |
+ IssuedBy: &api.SignatureIssuer{ |
|
192 |
+ SignatureGenericEntity: api.SignatureGenericEntity{Organization: "org"}, |
|
193 |
+ }, |
|
194 |
+ IssuedTo: &api.SignatureSubject{PublicKeyID: "id"}, |
|
195 |
+ }, |
|
196 |
+ expected: field.ErrorList{ |
|
197 |
+ field.Invalid(field.NewPath("imageIdentity"), "registry.company.ltd/app/core:v1.2", "must be unset for unknown signature state"), |
|
198 |
+ field.Invalid(field.NewPath("signedClaims"), map[string]string{"claim": "value"}, "must be unset for unknown signature state"), |
|
199 |
+ field.Invalid(field.NewPath("issuedBy"), &api.SignatureIssuer{ |
|
200 |
+ SignatureGenericEntity: api.SignatureGenericEntity{Organization: "org"}, |
|
201 |
+ }, "must be unset for unknown signature state"), |
|
202 |
+ field.Invalid(field.NewPath("issuedTo"), &api.SignatureSubject{PublicKeyID: "id"}, "must be unset for unknown signature state"), |
|
203 |
+ }, |
|
204 |
+ }, |
|
205 |
+ } { |
|
206 |
+ errs := validateImageSignature(&tc.signature, nil) |
|
207 |
+ if e, a := tc.expected, errs; !reflect.DeepEqual(a, e) { |
|
208 |
+ t.Errorf("[%s] unexpected errors: %s", tc.name, diff.ObjectDiff(e, a)) |
|
209 |
+ } |
|
210 |
+ } |
|
211 |
+ |
|
212 |
+} |
|
213 |
+ |
|
71 | 214 |
func TestValidateImageStreamMappingNotOK(t *testing.T) { |
72 | 215 |
errorCases := map[string]struct { |
73 | 216 |
I api.ImageStreamMapping |
... | ... |
@@ -32,12 +32,14 @@ func (imageStrategy) NamespaceScoped() bool { |
32 | 32 |
|
33 | 33 |
// PrepareForCreate clears fields that are not allowed to be set by end users on creation. |
34 | 34 |
// It extracts the latest information from the manifest (if available) and sets that onto the object. |
35 |
-func (imageStrategy) PrepareForCreate(obj runtime.Object) { |
|
35 |
+func (s imageStrategy) PrepareForCreate(obj runtime.Object) { |
|
36 | 36 |
newImage := obj.(*api.Image) |
37 | 37 |
// ignore errors, change in place |
38 | 38 |
if err := api.ImageWithMetadata(newImage); err != nil { |
39 | 39 |
utilruntime.HandleError(fmt.Errorf("Unable to update image metadata for %q: %v", newImage.Name, err)) |
40 | 40 |
} |
41 |
+ |
|
42 |
+ s.clearSignatureDetails(newImage) |
|
41 | 43 |
} |
42 | 44 |
|
43 | 45 |
// Validate validates a new image. |
... | ... |
@@ -72,6 +74,7 @@ func (imageStrategy) PrepareForUpdate(obj, old runtime.Object) { |
72 | 72 |
newImage.DockerImageMetadata = oldImage.DockerImageMetadata |
73 | 73 |
newImage.DockerImageMetadataVersion = oldImage.DockerImageMetadataVersion |
74 | 74 |
newImage.DockerImageLayers = oldImage.DockerImageLayers |
75 |
+ newImage.Signatures = oldImage.Signatures |
|
75 | 76 |
|
76 | 77 |
// allow an image update that results in the manifest matching the digest (the name) |
77 | 78 |
newManifest := newImage.DockerImageManifest |
... | ... |
@@ -95,6 +98,20 @@ func (imageStrategy) ValidateUpdate(ctx kapi.Context, obj, old runtime.Object) f |
95 | 95 |
return validation.ValidateImageUpdate(old.(*api.Image), obj.(*api.Image)) |
96 | 96 |
} |
97 | 97 |
|
98 |
+// clearSignatureDetails removes signature details from all the signatures of given image. It also clear all |
|
99 |
+// the validation data. These data will be set by the server once the signature parsing support is added. |
|
100 |
+func (imageStrategy) clearSignatureDetails(image *api.Image) { |
|
101 |
+ for i := range image.Signatures { |
|
102 |
+ signature := &image.Signatures[i] |
|
103 |
+ signature.Conditions = nil |
|
104 |
+ signature.ImageIdentity = "" |
|
105 |
+ signature.SignedClaims = nil |
|
106 |
+ signature.Created = nil |
|
107 |
+ signature.IssuedBy = nil |
|
108 |
+ signature.IssuedTo = nil |
|
109 |
+ } |
|
110 |
+} |
|
111 |
+ |
|
98 | 112 |
// MatchImage returns a generic matcher for a given label and field selector. |
99 | 113 |
func MatchImage(label labels.Selector, field fields.Selector) generic.Matcher { |
100 | 114 |
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { |