Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions library/general/jfrog-evidence/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
resources:
- template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: jfrogcheckevidence
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constraint kind does not match the expected naming convention. Since the ConstraintTemplate should be named "k8sjfrogcheckevidence" (following codebase conventions), this kind should also be "k8sjfrogcheckevidence" instead of "jfrogcheckevidence".

Copilot uses AI. Check for mistakes.
metadata:
name: jfrog-check-evidence
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
checkedRegistries: ["my-jfrog-registry.jfrog.io"]
# add whitelist for repositories, uncomment to enable
# checkedRepositories: ["docker-local"]
checkedPredicateTypes: ["https://slsa.dev/provenance/v1"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: Pod
metadata:
name: your-jfrog-testing-pod
spec:
containers:
- name: testing
image: my-jfrog-registry.jfrog.io/docker-local/your-valid-testing-image:1.0.0
imagePullPolicy: Always
imagePullSecrets:
- name: jfrog-secret
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: Pod
metadata:
name: your-jfrog-testing-pod
spec:
containers:
- name: testing
image: my-jfrog-registry.jfrog.io/docker-local/your-invalid-testing-image:1.0.0
imagePullPolicy: Always
imagePullSecrets:
- name: jfrog-secret
18 changes: 18 additions & 0 deletions library/general/jfrog-evidence/suite.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
kind: Suite
apiVersion: test.gatekeeper.sh/v1alpha1
metadata:
name: replicalimits
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suite metadata name is incorrect. It should be "jfrogcheckevidence" (or preferably "k8sjfrogcheckevidence" to follow conventions) instead of "replicalimits", which appears to be copy-pasted from another test suite.

Suggested change
name: replicalimits
name: k8sjfrogcheckevidence

Copilot uses AI. Check for mistakes.
tests:
- name: replica-limit
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name is incorrect. It should relate to jfrog evidence checking instead of "replica-limit", which appears to be copy-pasted from another test suite.

Suggested change
- name: replica-limit
- name: jfrog-evidence-check

Copilot uses AI. Check for mistakes.
template: template.yaml
constraint: samples/jfrogcheckevidence/constraint.yaml
cases:
- name: example-allowed
object: samples/jfrogcheckevidence/example_allowed.yaml
assertions:
- violations: no
- name: example-disallowed
object: samples/jfrogcheckevidence/example_disallowed.yaml
assertions:
- violations: yes

100 changes: 100 additions & 0 deletions library/general/jfrog-evidence/template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: jfrogcheckevidence
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The metadata name does not follow the established codebase convention. All constraint templates use the "k8s" prefix in their names. This should be "k8sjfrogcheckevidence" instead of "jfrogcheckevidence".

Copilot uses AI. Check for mistakes.
annotations:
metadata.gatekeeper.sh/title: "Check JFrog Evidence"
metadata.gatekeeper.sh/version: 1.0.0
description: >-
Checks if the images in a pod comply with regulations or corporate policies by validating they have required verified evidence.
This policy is based on the JFrog OPA provider. To deploy JFrog OPA Provider, please visit: https://github.com/jfrog/jfrog-opa-policy
spec:
crd:
spec:
names:
kind: jfrogcheckevidence
Comment thread
carmithersh marked this conversation as resolved.
Outdated
validation:
openAPIV3Schema:
type: object
properties:
checkedPredicateTypes:
type: array
items:
type: string
checkedRegistries:
type: array
items:
type: string
checkedRepositories:
Comment on lines +20 to +30
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The property descriptions are missing for checkedPredicateTypes, checkedRegistries, and checkedRepositories. Following the pattern seen in other constraint templates, each property should have a description explaining its purpose and format.

Suggested change
checkedPredicateTypes:
type: array
items:
type: string
checkedRegistries:
type: array
items:
type: string
checkedRepositories:
checkedPredicateTypes:
description: >-
List of predicate types to check for each image. Each entry is
a string that will be concatenated into a comma-separated
value and passed as part of the key set to the JFrog evidence
OPA provider.
type: array
items:
type: string
checkedRegistries:
description: >-
List of container registry prefixes to include in the check.
Only images whose names start with one of these prefixes will
be evaluated by this constraint.
type: array
items:
type: string
checkedRepositories:
description: >-
List of repository path substrings to include in the check.
Only images whose names contain one of these substrings will
be evaluated by this constraint.

Copilot uses AI. Check for mistakes.
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
code:
- engine: Rego
source:
rego: |
package jfrogcheckevidence
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package name does not follow the established codebase convention. All policies in src/general use the "k8s" prefix in their package names. This package should be named "k8sjfrogcheckevidence" instead of "jfrogcheckevidence" for consistency.

Copilot uses AI. Check for mistakes.
import data.lib.filter_images
import future.keywords.in
import future.keywords.contains
# get all images
all_images := [img | img = input.review.object.spec.containers[_].image]
target_images := [img | img = all_images[_]
filter_images.is_checked_registry(img)
filter_images.is_checked_repository(img)
]
# get init images
init_images := [img | img = input.review.object.spec.initContainers[_].image]
target_init_images := [img | img = init_images[_]
filter_images.is_checked_registry(img)
filter_images.is_checked_repository(img)
]

# append target_images, target_init_images
checked_images := array.concat(target_images, target_init_images)
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The policy does not check ephemeralContainers for images, which could be a security gap. Other similar policies like imagedigests check containers, initContainers, and ephemeralContainers. Consider adding a check for ephemeralContainers to ensure comprehensive coverage.

Suggested change
# append target_images, target_init_images
checked_images := array.concat(target_images, target_init_images)
# get ephemeral container images
ephemeral_images := [img | img = input.review.object.spec.ephemeralContainers[_].image]
target_ephemeral_images := [img | img = ephemeral_images[_]
filter_images.is_checked_registry(img)
filter_images.is_checked_repository(img)
]
# append target_images, target_init_images, target_ephemeral_images
tmp_checked_images := array.concat(target_images, target_init_images)
checked_images := array.concat(tmp_checked_images, target_ephemeral_images)

Copilot uses AI. Check for mistakes.
# convert arreay input.parameters.checkedPredicateTypes to string
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains a typo. "arreay" should be "array".

Suggested change
# convert arreay input.parameters.checkedPredicateTypes to string
# convert array input.parameters.checkedPredicateTypes to string

Copilot uses AI. Check for mistakes.
types := concat(",", input.parameters.checkedPredicateTypes)
typesArray := [types]
Comment thread
carmithersh marked this conversation as resolved.
Outdated

checked_keys := array.concat(typesArray, checked_images)
violation[{"msg": msg}] {
count(checked_images) > 0
response := external_data({"provider": "jfrog-evidence-opa-provider", "keys": checked_keys})
any_issues_found(response)

msg := sprintf("TARGET IMAGES: %v, RESPONSE: %v", [checked_images, response])
Comment thread
carmithersh marked this conversation as resolved.
Outdated
}

any_issues_found(response) {
count(response.errors) > 0
} else {
response.system_error != ""
} else {
response_has_invalid(response)
}

response_has_invalid(response) {
some item in response.responses
count(item) == 2
item[1] == "_invalid"
}

has_check_registry_images_parameter {
input.parameters.checkedRegistries != null
}
Comment thread
carmithersh marked this conversation as resolved.
Outdated
libs:
- |
package lib.filter_images
import future.keywords.in
is_checked_registry(img) {
checked_registries := object.get(object.get(input, "parameters", {}), "checkedRegistries", [])
some registry in checked_registries
startswith(img, registry)
}
is_checked_repository(img) {
checked_repositories := object.get(object.get(input, "parameters", {}), "checkedRepositories", ["/"])
some repository in checked_repositories
contains(img, repository)
}
38 changes: 38 additions & 0 deletions src/general/jfrog-evidence/constraint.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: jfrogcheckevidence
Comment thread
carmithersh marked this conversation as resolved.
Outdated
annotations:
metadata.gatekeeper.sh/title: "Check JFrog Evidence"
metadata.gatekeeper.sh/version: 1.0.0
description: >-
Checks if the images in a pod comply with regulations or corporate policies by validating they have required verified evidence.
This policy is based on the JFrog OPA provider. To deploy JFrog OPA Provider, please visit: https://github.com/jfrog/jfrog-opa-policy
spec:
crd:
spec:
names:
kind: jfrogcheckevidence
Comment thread
carmithersh marked this conversation as resolved.
Outdated
validation:
openAPIV3Schema:
type: object
properties:
checkedPredicateTypes:
type: array
items:
type: string
checkedRegistries:
type: array
items:
type: string
checkedRepositories:
type: array
Comment thread
carmithersh marked this conversation as resolved.
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
code:
- engine: Rego
source:
rego: |
Comment thread
carmithersh marked this conversation as resolved.
Outdated
{{ file.Read "src/general/jfrog-evidence/src.rego" | strings.Indent 8 | strings.TrimSuffix "\n" }}
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constraint template is reading src.rego which contains a YAML "libs:" section (lines 50-63 in src.rego). This will result in invalid Rego code being embedded in the template. The libs section should be removed from src.rego and instead be defined in the constraint template after the rego source, similar to how it's done in other policies. The library code (lines 52-63 in src.rego) should be in a separate file like "lib_filter_images.rego" and referenced in the constraint template's libs section. See example: src/general/imagedigests/constraint.tmpl:39-41.

Suggested change
{{ file.Read "src/general/jfrog-evidence/src.rego" | strings.Indent 8 | strings.TrimSuffix "\n" }}
{{ file.Read "src/general/jfrog-evidence/src.rego" | strings.Indent 8 | strings.TrimSuffix "\n" }}
libs:
- rego: |
{{ file.Read "src/general/jfrog-evidence/lib_filter_images.rego" | strings.Indent 8 | strings.TrimSuffix "\n" }}

Copilot uses AI. Check for mistakes.
63 changes: 63 additions & 0 deletions src/general/jfrog-evidence/src.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package jfrogcheckevidence
Comment thread
carmithersh marked this conversation as resolved.
Outdated
import data.lib.filter_images
import future.keywords.in
import future.keywords.contains
# get all images
all_images := [img | img = input.review.object.spec.containers[_].image]
target_images := [img | img = all_images[_]
filter_images.is_checked_registry(img)
filter_images.is_checked_repository(img)
]
# get init images
init_images := [img | img = input.review.object.spec.initContainers[_].image]
target_init_images := [img | img = init_images[_]
filter_images.is_checked_registry(img)
filter_images.is_checked_repository(img)
]

# append target_images, target_init_images
checked_images := array.concat(target_images, target_init_images)
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The policy does not check ephemeralContainers for images, which could be a security gap. Other similar policies like imagedigests check containers, initContainers, and ephemeralContainers. Consider adding a check for ephemeralContainers to ensure comprehensive coverage. See example: src/general/imagedigests/src.rego:19-24.

Suggested change
# append target_images, target_init_images
checked_images := array.concat(target_images, target_init_images)
# get ephemeral container images
ephemeral_images := [img | img = input.review.object.spec.ephemeralContainers[_].image]
target_ephemeral_images := [img | img = ephemeral_images[_]
filter_images.is_checked_registry(img)
filter_images.is_checked_repository(img)
]
# append target_images, target_init_images, target_ephemeral_images
checked_images := array.concat(target_images, array.concat(target_init_images, target_ephemeral_images))

Copilot uses AI. Check for mistakes.
# convert arreay input.parameters.checkedPredicateTypes to string
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains a typo. "arreay" should be "array".

Suggested change
# convert arreay input.parameters.checkedPredicateTypes to string
# convert array input.parameters.checkedPredicateTypes to string

Copilot uses AI. Check for mistakes.
types := concat(",", input.parameters.checkedPredicateTypes)
typesArray := [types]

Comment on lines +33 to +36
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the checkedPredicateTypes parameter is an empty array, the concat function will produce an empty string, which may not be the intended behavior when communicating with the JFrog provider. Consider adding validation to ensure checkedPredicateTypes is not empty, or handle the empty case explicitly to avoid unexpected behavior from the external provider.

Suggested change
# convert arreay input.parameters.checkedPredicateTypes to string
types := concat(",", input.parameters.checkedPredicateTypes)
typesArray := [types]
# build typesArray from input.parameters.checkedPredicateTypes only when non-empty
typesArray := [types] {
params := object.get(input, "parameters", {})
checked_predicate_types := object.get(params, "checkedPredicateTypes", [])
count(checked_predicate_types) > 0
types := concat(",", checked_predicate_types)
}
default typesArray := []

Copilot uses AI. Check for mistakes.
checked_keys := array.concat(typesArray, checked_images)
violation[{"msg": msg}] {
count(checked_images) > 0
response := external_data({"provider": "jfrog-evidence-opa-provider", "keys": checked_keys})
any_issues_found(response)

msg := sprintf("TARGET IMAGES: %v, RESPONSE: %v", [checked_images, response])
Comment thread
carmithersh marked this conversation as resolved.
Outdated
}

any_issues_found(response) {
count(response.errors) > 0
} else {
response.system_error != ""
} else {
response_has_invalid(response)
}

response_has_invalid(response) {
some item in response.responses
count(item) == 2
item[1] == "_invalid"
}

has_check_registry_images_parameter {
input.parameters.checkedRegistries != null
}
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function "has_check_registry_images_parameter" is defined but never used in the policy. This unused code should be removed to improve maintainability.

Suggested change
has_check_registry_images_parameter {
input.parameters.checkedRegistries != null
}

Copilot uses AI. Check for mistakes.
libs:
- |
package lib.filter_images
import future.keywords.in
is_checked_registry(img) {
checked_registries := object.get(object.get(input, "parameters", {}), "checkedRegistries", [])
some registry in checked_registries
startswith(img, registry)
}
is_checked_repository(img) {
checked_repositories := object.get(object.get(input, "parameters", {}), "checkedRepositories", ["/"])
some repository in checked_repositories
contains(img, repository)
}
Comment on lines +66 to +79
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "libs:" section should not be in the src.rego file. Based on codebase conventions, the libs should be defined in the constraint.tmpl file. See examples: src/general/imagedigests/constraint.tmpl:39-41, src/general/containerresources/constraint.tmpl:52-54. The library code should be in a separate file and referenced in the constraint template.

Copilot uses AI. Check for mistakes.
Loading