Skip to content

Commit 54a830d

Browse files
authored
Merge pull request #524 from Acepresso/add-reference-field-EC-1246
Add "reference" field to volatileConfig
2 parents 34d635e + f35c607 commit 54a830d

6 files changed

Lines changed: 136 additions & 0 deletions

api/config/appstudio.redhat.com_enterprisecontractpolicies.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ spec:
179179
description: ImageUrl is used to specify an image by its URL without a tag.
180180
pattern: ^[a-z0-9][a-z0-9.-]*[a-z0-9](?:\/[a-z0-9][a-z0-9-]*[a-z0-9]){2,}$
181181
type: string
182+
reference:
183+
description: Reference is used to include a link to related information such as a Jira issue URL.
184+
type: string
182185
value:
183186
type: string
184187
required:
@@ -212,6 +215,9 @@ spec:
212215
description: ImageUrl is used to specify an image by its URL without a tag.
213216
pattern: ^[a-z0-9][a-z0-9.-]*[a-z0-9](?:\/[a-z0-9][a-z0-9-]*[a-z0-9]){2,}$
214217
type: string
218+
reference:
219+
description: Reference is used to include a link to related information such as a Jira issue URL.
220+
type: string
215221
value:
216222
type: string
217223
required:

api/v1alpha1/enterprisecontractpolicy_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ type VolatileCriteria struct {
115115
// +optional
116116
// +kubebuilder:validation:Pattern=`^[a-z0-9][a-z0-9.-]*[a-z0-9](?:\/[a-z0-9][a-z0-9-]*[a-z0-9]){2,}$`
117117
ImageUrl string `json:"imageUrl,omitempty"`
118+
119+
// Reference is used to include a link to related information such as a Jira issue URL.
120+
// +optional
121+
Reference string `json:"reference,omitempty"`
118122
}
119123

120124
// VolatileSourceConfig specifies volatile configuration for a policy source.

api/v1alpha1/enterprisecontractpolicy_types_test.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,118 @@ func TestImageUrlPattern(t *testing.T) {
281281
})
282282
}
283283
}
284+
285+
286+
func TestReferenceField(t *testing.T) {
287+
tests := []struct {
288+
name string
289+
reference string
290+
wantValid bool
291+
omitField bool // true if the field should be omitted entirely
292+
}{
293+
// Valid cases
294+
{"URL", "https://issues.redhat.com/browse/EC-1246", true, false},
295+
{"Multiline URL", "https://issues.redhat.com/browse/EC-1246\nhttps://issues.redhat.com/browse/EC-1101", true, false},
296+
{"With whitespaces", "string with whitespaces", true, false},
297+
{"Long String", strings.Repeat("A", 1000), true, false},
298+
{"Empty String", "", true, false},
299+
{"Omitted field", "", true, true}, // Field is omitted entirely
300+
}
301+
302+
for _, tt := range tests {
303+
t.Run(tt.name, func(t *testing.T) {
304+
// Create a policy with the test URL
305+
policy := EnterpriseContractPolicy{
306+
Spec: EnterpriseContractPolicySpec{
307+
Sources: []Source{
308+
{
309+
VolatileConfig: &VolatileSourceConfig{
310+
Exclude: []VolatileCriteria{
311+
{
312+
Value: "test-rule",
313+
},
314+
},
315+
},
316+
},
317+
},
318+
},
319+
}
320+
if !tt.omitField {
321+
policy.Spec.Sources[0].VolatileConfig.Exclude[0].Reference = tt.reference
322+
}
323+
324+
// Create a CRD validation schema
325+
crd := v1.CustomResourceDefinition{}
326+
bytes, err := os.ReadFile("../../config/crd/bases/appstudio.redhat.com_enterprisecontractpolicies.yaml")
327+
if err != nil {
328+
t.Fatalf("unexpected error reading CRD: %s", err)
329+
}
330+
if err := yaml.Unmarshal(bytes, &crd); err != nil {
331+
t.Fatalf("unexpected error when decoding schema: %s", err)
332+
}
333+
334+
crdv := apiextensions.CustomResourceValidation{}
335+
if err := v1.Convert_v1_CustomResourceValidation_To_apiextensions_CustomResourceValidation(crd.Spec.Versions[0].Schema, &crdv, nil); err != nil {
336+
t.Fatalf("failed in CRD validation conversion: %s", err)
337+
}
338+
339+
s, err := schema.NewStructural(crdv.OpenAPIV3Schema)
340+
if err != nil {
341+
t.Fatalf("unexpected error when creating structural: %s", err)
342+
}
343+
344+
v := validation.NewSchemaValidatorFromOpenAPI(s.ToKubeOpenAPI())
345+
346+
// Convert policy to unstructured for validation
347+
obj := unstructured.Unstructured{}
348+
obj.SetUnstructuredContent(map[string]interface{}{
349+
"apiVersion": "appstudio.redhat.com/v1alpha1",
350+
"kind": "EnterpriseContractPolicy",
351+
"spec": map[string]interface{}{
352+
"sources": []interface{}{
353+
map[string]interface{}{
354+
"volatileConfig": map[string]interface{}{
355+
"exclude": []interface{}{
356+
func() map[string]interface{} {
357+
m := map[string]interface{}{
358+
"value": "test-rule",
359+
}
360+
if !tt.omitField {
361+
m["reference"] = tt.reference
362+
}
363+
return m
364+
}(),
365+
},
366+
},
367+
},
368+
},
369+
},
370+
})
371+
372+
// Validate the object
373+
result := v.Validate(&obj)
374+
isValid := result.IsValid()
375+
376+
if isValid != tt.wantValid {
377+
t.Errorf("Validation for %q = %v, want %v. Errors: %v", tt.reference, isValid, tt.wantValid, result.Errors)
378+
}
379+
380+
// Also validate the actual policy object
381+
policyObj := unstructured.Unstructured{}
382+
policyBytes, err := json.Marshal(policy)
383+
if err != nil {
384+
t.Fatalf("unexpected error marshaling policy: %s", err)
385+
}
386+
if err := json.Unmarshal(policyBytes, &policyObj.Object); err != nil {
387+
t.Fatalf("unexpected error unmarshaling policy: %s", err)
388+
}
389+
390+
policyResult := v.Validate(&policyObj)
391+
policyIsValid := policyResult.IsValid()
392+
393+
if policyIsValid != tt.wantValid {
394+
t.Errorf("Policy validation for %q = %v, want %v. Errors: %v", tt.reference, policyIsValid, tt.wantValid, policyResult.Errors)
395+
}
396+
})
397+
}
398+
}

api/v1alpha1/policy_spec.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@
179179
"imageUrl": {
180180
"type": "string",
181181
"description": "ImageUrl is used to specify an image by its URL without a tag.\n+optional\n+kubebuilder:validation:Pattern=`^[a-z0-9][a-z0-9.-]*[a-z0-9](?:\\/[a-z0-9][a-z0-9-]*[a-z0-9]){2,}$`"
182+
},
183+
"reference": {
184+
"type": "string",
185+
"description": "Reference is used to include a link to related information such as a Jira issue URL.\n+optional"
182186
}
183187
},
184188
"additionalProperties": false,

config/crd/bases/appstudio.redhat.com_enterprisecontractpolicies.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ spec:
179179
description: ImageUrl is used to specify an image by its URL without a tag.
180180
pattern: ^[a-z0-9][a-z0-9.-]*[a-z0-9](?:\/[a-z0-9][a-z0-9-]*[a-z0-9]){2,}$
181181
type: string
182+
reference:
183+
description: Reference is used to include a link to related information such as a Jira issue URL.
184+
type: string
182185
value:
183186
type: string
184187
required:
@@ -212,6 +215,9 @@ spec:
212215
description: ImageUrl is used to specify an image by its URL without a tag.
213216
pattern: ^[a-z0-9][a-z0-9.-]*[a-z0-9](?:\/[a-z0-9][a-z0-9-]*[a-z0-9]){2,}$
214217
type: string
218+
reference:
219+
description: Reference is used to include a link to related information such as a Jira issue URL.
220+
type: string
215221
value:
216222
type: string
217223
required:

docs/modules/ROOT/pages/reference.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ Appears In: xref:{anchor_prefix}-github-com-enterprise-contract-enterprise-contr
205205
ImageRef is used to specify an image by its digest. +
206206
| *`imageDigest`* __string__ | ImageDigest is used to specify an image by its digest. +
207207
| *`imageUrl`* __string__ | ImageUrl is used to specify an image by its URL without a tag. +
208+
| *`reference`* __string__ | Reference is used to include a link to related information such as a Jira issue URL. +
208209
|===
209210

210211

0 commit comments

Comments
 (0)