Skip to content

Commit f4b357b

Browse files
authored
Merge pull request #3077 from joejstuart/volatile-poc
add policy spec and component name to Rego input
2 parents 1abca92 + 05db3c2 commit f4b357b

File tree

6 files changed

+364
-7
lines changed

6 files changed

+364
-7
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Policy to validate volatile config schema contract between ec-cli and ec-policies.
2+
# This serves as an integration test to ensure the input schema is correctly populated.
3+
# The warning patterns here align with policy/release/volatile_config/volatile_config.rego
4+
package main
5+
6+
import rego.v1
7+
8+
# Warn for volatile rules pending activation (effectiveOn in future)
9+
warn contains result if {
10+
some source in input.policy_spec.sources
11+
some config in source.volatileConfig.exclude
12+
config.effectiveOn
13+
_is_future_date(config.effectiveOn)
14+
result := {
15+
"msg": sprintf("Volatile exclude rule '%s' is pending activation (effective on: %s)", [config.value, config.effectiveOn]),
16+
}
17+
}
18+
19+
# Warn for volatile rules that will expire (effectiveUntil in future)
20+
warn contains result if {
21+
some source in input.policy_spec.sources
22+
some config in source.volatileConfig.exclude
23+
config.effectiveUntil
24+
not _is_past_date(config.effectiveUntil)
25+
result := {
26+
"msg": sprintf("Volatile exclude rule '%s' will expire (effective until: %s)", [config.value, config.effectiveUntil]),
27+
}
28+
}
29+
30+
# Warn for volatile rules with no expiration date
31+
warn contains result if {
32+
some source in input.policy_spec.sources
33+
some config in source.volatileConfig.exclude
34+
not config.effectiveUntil
35+
not config.effectiveOn
36+
result := {
37+
"msg": sprintf("Volatile exclude rule '%s' has no expiration date set", [config.value]),
38+
}
39+
}
40+
41+
# Warn for volatile rules scoped to component names (proves componentNames is accessible)
42+
warn contains result if {
43+
some source in input.policy_spec.sources
44+
some config in source.volatileConfig.exclude
45+
count(config.componentNames) > 0
46+
some name in config.componentNames
47+
name == input.component_name
48+
result := {
49+
"msg": sprintf("Volatile exclude rule '%s' is scoped to component '%s'", [config.value, input.component_name]),
50+
}
51+
}
52+
53+
# Helper to check if date is in the future
54+
_is_future_date(date_str) if {
55+
date_str != ""
56+
date_ns := time.parse_rfc3339_ns(date_str)
57+
now_ns := time.now_ns()
58+
date_ns > now_ns
59+
}
60+
61+
# Helper to check if date is in the past
62+
_is_past_date(date_str) if {
63+
date_str != ""
64+
date_ns := time.parse_rfc3339_ns(date_str)
65+
now_ns := time.now_ns()
66+
date_ns < now_ns
67+
}

features/__snapshots__/validate_image.snap

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2784,6 +2784,18 @@ ${__________known_PUBLIC_KEY}
27842784
}
27852785
],
27862786
"artifacts": {}
2787+
},
2788+
"component_name": "Unnamed",
2789+
"policy_spec": {
2790+
"sources": [
2791+
{
2792+
"policy": [
2793+
"git::${GITHOST}/git/policy-input-output-policy.git?ref=${LATEST_COMMIT}"
2794+
]
2795+
}
2796+
],
2797+
"rekorUrl": "${REKOR}",
2798+
"publicKey": "${known_PUBLIC_KEY}"
27872799
}
27882800
}
27892801
---
@@ -3147,6 +3159,17 @@ Error: success criteria not met
31473159
}
31483160
],
31493161
"artifacts": {}
3162+
},
3163+
"component_name": "Unnamed",
3164+
"policy_spec": {
3165+
"sources": [
3166+
{
3167+
"policy": [
3168+
"git::${GITHOST}/git/olm-manifests.git?ref=${LATEST_COMMIT}"
3169+
]
3170+
}
3171+
],
3172+
"publicKey": "${known_PUBLIC_KEY}"
31503173
}
31513174
}
31523175
---
@@ -5351,3 +5374,92 @@ Error: success criteria not met
53515374
[SLSA v1 attestation support:stderr - 1]
53525375

53535376
---
5377+
5378+
[volatile config warnings schema contract:stdout - 1]
5379+
{
5380+
"success": true,
5381+
"components": [
5382+
{
5383+
"name": "Unnamed",
5384+
"containerImage": "${REGISTRY}/acceptance/volatile-config-test@sha256:${REGISTRY_acceptance/volatile-config-test:latest_DIGEST}",
5385+
"source": {},
5386+
"warnings": [
5387+
{
5388+
"msg": "Volatile exclude rule 'test.component_scoped_rule' has no expiration date set"
5389+
},
5390+
{
5391+
"msg": "Volatile exclude rule 'test.component_scoped_rule' is scoped to component 'Unnamed'"
5392+
},
5393+
{
5394+
"msg": "Volatile exclude rule 'test.rule_expiring_soon' will expire (effective until: ${TIMESTAMP})"
5395+
},
5396+
{
5397+
"msg": "Volatile exclude rule 'test.rule_pending_activation' is pending activation (effective on: ${TIMESTAMP})"
5398+
},
5399+
{
5400+
"msg": "Volatile exclude rule 'test.rule_with_no_expiration' has no expiration date set"
5401+
}
5402+
],
5403+
"success": true,
5404+
"signatures": [
5405+
{
5406+
"keyid": "",
5407+
"sig": "${IMAGE_SIGNATURE_acceptance/volatile-config-test}"
5408+
}
5409+
],
5410+
"attestations": [
5411+
{
5412+
"type": "https://in-toto.io/Statement/v0.1",
5413+
"predicateType": "https://slsa.dev/provenance/v0.2",
5414+
"predicateBuildType": "https://tekton.dev/attestations/chains/pipelinerun@v2",
5415+
"signatures": [
5416+
{
5417+
"keyid": "",
5418+
"sig": "${ATTESTATION_SIGNATURE_acceptance/volatile-config-test}"
5419+
}
5420+
]
5421+
}
5422+
]
5423+
}
5424+
],
5425+
"key": "${known_PUBLIC_KEY_JSON}",
5426+
"policy": {
5427+
"sources": [
5428+
{
5429+
"name": "volatile-test-source",
5430+
"policy": [
5431+
"git::${GITHOST}/git/volatile-config-policy.git?ref=${LATEST_COMMIT}"
5432+
],
5433+
"volatileConfig": {
5434+
"exclude": [
5435+
{
5436+
"value": "test.rule_with_no_expiration"
5437+
},
5438+
{
5439+
"value": "test.rule_expiring_soon",
5440+
"effectiveUntil": "${TIMESTAMP}"
5441+
},
5442+
{
5443+
"value": "test.rule_pending_activation",
5444+
"effectiveOn": "${TIMESTAMP}"
5445+
},
5446+
{
5447+
"value": "test.component_scoped_rule",
5448+
"componentNames": [
5449+
"Unnamed"
5450+
]
5451+
}
5452+
]
5453+
}
5454+
}
5455+
],
5456+
"publicKey": "${known_PUBLIC_KEY}"
5457+
},
5458+
"ec-version": "${EC_VERSION}",
5459+
"effective-time": "${TIMESTAMP}"
5460+
}
5461+
---
5462+
5463+
[volatile config warnings schema contract:stderr - 1]
5464+
5465+
---

features/validate_image.feature

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,49 @@ Feature: evaluate enterprise contract
958958
And the output should match the snapshot
959959
And the "${TMPDIR}/input.json" file should match the snapshot
960960

961+
Scenario: volatile config warnings schema contract
962+
Given a key pair named "known"
963+
Given an image named "acceptance/volatile-config-test"
964+
Given a valid image signature of "acceptance/volatile-config-test" image signed by the "known" key
965+
Given a valid attestation of "acceptance/volatile-config-test" signed by the "known" key
966+
Given a git repository named "volatile-config-policy" with
967+
| main.rego | examples/volatile_config_warnings.rego |
968+
Given policy configuration named "ec-policy" with specification
969+
"""
970+
{
971+
"sources": [
972+
{
973+
"name": "volatile-test-source",
974+
"policy": [
975+
"git::https://${GITHOST}/git/volatile-config-policy.git"
976+
],
977+
"volatileConfig": {
978+
"exclude": [
979+
{
980+
"value": "test.rule_with_no_expiration"
981+
},
982+
{
983+
"value": "test.rule_expiring_soon",
984+
"effectiveUntil": "2099-12-31T23:59:59Z"
985+
},
986+
{
987+
"value": "test.rule_pending_activation",
988+
"effectiveOn": "2099-01-01T00:00:00Z"
989+
},
990+
{
991+
"value": "test.component_scoped_rule",
992+
"componentNames": ["Unnamed"]
993+
}
994+
]
995+
}
996+
}
997+
]
998+
}
999+
"""
1000+
When ec command is run with "validate image --image ${REGISTRY}/acceptance/volatile-config-test --policy acceptance/ec-policy --public-key ${known_PUBLIC_KEY} --ignore-rekor --output json"
1001+
Then the exit status should be 0
1002+
Then the output should match the snapshot
1003+
9611004
Scenario: Unsupported policies
9621005
Given a key pair named "known"
9631006
Given an image named "acceptance/image"

internal/evaluation_target/application_snapshot_image/__snapshots__/application_snapshot_image_test.snap

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"ref": "registry.io/repository/image:tag",
3636
"source": {}
3737
},
38+
"policy_spec": {},
3839
"snapshot": {
3940
"application": "",
4041
"artifacts": {},
@@ -94,6 +95,7 @@
9495
"ref": "registry.io/repository/image:tag",
9596
"source": {}
9697
},
98+
"policy_spec": {},
9799
"snapshot": {
98100
"application": "",
99101
"artifacts": {},
@@ -151,6 +153,7 @@
151153
],
152154
"source": {}
153155
},
156+
"policy_spec": {},
154157
"snapshot": {
155158
"application": "",
156159
"artifacts": {},
@@ -182,6 +185,7 @@
182185
"ref": "registry.io/repository/image:tag",
183186
"source": {}
184187
},
188+
"policy_spec": {},
185189
"snapshot": {
186190
"application": "",
187191
"artifacts": {},
@@ -216,6 +220,7 @@
216220
"ref": "registry.io/repository/image:tag",
217221
"source": {}
218222
},
223+
"policy_spec": {},
219224
"snapshot": {
220225
"application": "",
221226
"artifacts": {},
@@ -275,6 +280,7 @@
275280
"ref": "registry.io/repository/image:tag",
276281
"source": {}
277282
},
283+
"policy_spec": {},
278284
"snapshot": {
279285
"application": "",
280286
"artifacts": {},
@@ -318,6 +324,7 @@
318324
"ref": "registry.io/repository/image:tag",
319325
"source": {}
320326
},
327+
"policy_spec": {},
321328
"snapshot": {
322329
"application": "",
323330
"artifacts": {},
@@ -349,6 +356,84 @@
349356
}
350357
}
351358
},
359+
"policy_spec": {},
360+
"snapshot": {
361+
"application": "",
362+
"artifacts": {},
363+
"components": [
364+
{
365+
"containerImage": "registry.io/repository/image:tag",
366+
"name": "",
367+
"source": {}
368+
},
369+
{
370+
"containerImage": "registry.io/other-repository/image2:tag",
371+
"name": "",
372+
"source": {}
373+
}
374+
]
375+
}
376+
}
377+
---
378+
379+
[TestWriteInputFile/component_name_in_input - 1]
380+
{
381+
"attestations": null,
382+
"component_name": "my-component",
383+
"image": {
384+
"ref": "registry.io/repository/image:tag",
385+
"source": {}
386+
},
387+
"policy_spec": {},
388+
"snapshot": {
389+
"application": "",
390+
"artifacts": {},
391+
"components": [
392+
{
393+
"containerImage": "registry.io/repository/image:tag",
394+
"name": "",
395+
"source": {}
396+
},
397+
{
398+
"containerImage": "registry.io/other-repository/image2:tag",
399+
"name": "",
400+
"source": {}
401+
}
402+
]
403+
}
404+
}
405+
---
406+
407+
[TestWriteInputFile/policy_spec_with_volatile_config - 1]
408+
{
409+
"attestations": null,
410+
"component_name": "test-component",
411+
"image": {
412+
"ref": "registry.io/repository/image:tag",
413+
"source": {}
414+
},
415+
"policy_spec": {
416+
"sources": [
417+
{
418+
"name": "test-source",
419+
"volatileConfig": {
420+
"exclude": [
421+
{
422+
"imageDigest": "sha256:abc123",
423+
"value": "test.rule"
424+
}
425+
],
426+
"include": [
427+
{
428+
"effectiveOn": "2024-01-01T00:00:00Z",
429+
"effectiveUntil": "2025-12-31T23:59:59Z",
430+
"value": "tasks.required_tasks_found:clamav-scan"
431+
}
432+
]
433+
}
434+
}
435+
]
436+
},
352437
"snapshot": {
353438
"application": "",
354439
"artifacts": {},

0 commit comments

Comments
 (0)