Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tags as versions for acceptable task rules #787

Merged
merged 1 commit into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
219 changes: 173 additions & 46 deletions policy/lib/bundles.rego
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import data.lib.image
import data.lib.refs
import data.lib.time as time_lib

# Return the bundle reference as is
bundle(task) := refs.task_ref(task).bundle
zregvart marked this conversation as resolved.
Show resolved Hide resolved

# Returns a subset of tasks that do not use a bundle reference.
disallowed_task_reference(tasks) := {task |
some task in tasks
not refs.task_ref(task).bundle
not bundle(task)
}

# Returns a subset of tasks that use an empty bundle reference.
Expand All @@ -26,73 +29,197 @@ unpinned_task_bundle(tasks) := {task |
ref.digest == ""
}

# Returns if the required task-bundles data is missing
default missing_task_bundles_data := false

missing_task_bundles_data if {
count(data["task-bundles"]) == 0
}

# Returns a subset of tasks that use an acceptable bundle reference, but
# an updated bundle reference exists.
out_of_date_task_bundle(tasks) := {task |
some task in tasks
ref := image.parse(bundle(task))
collection := _collection(ref)

some match_index, out_of_date in collection
is_equal(out_of_date, ref)
match_index > 0
ref := image.parse(_bundle_ref(task, data["task-bundles"]))

_newer_version_exists(ref)
not _is_unacceptable(ref)
}

# Returns a subset of tasks that do not use an acceptable bundle reference.
zregvart marked this conversation as resolved.
Show resolved Hide resolved
unacceptable_task_bundle(tasks) := {task |
some task in tasks
ref := image.parse(bundle(task))
collection := _collection(ref)

matches := [record |
some record in collection
is_equal(record, ref)
]
ref := image.parse(_bundle_ref(task, data["task-bundles"]))

count(matches) == 0
_is_unacceptable(ref)
}

# Returns if the required task-bundles data is missing
default missing_task_bundles_data := false
_is_unacceptable(ref) if {
not _record_exists(ref)
}

missing_task_bundles_data if {
count(data["task-bundles"]) == 0
_is_unacceptable(ref) if {
_newer_in_effect_version_exists(ref)
}

# Returns true if the provided bundle reference is acceptable
is_acceptable(bundle_ref) if {
ref := image.parse(bundle_ref)
collection := _collection(ref)
matches := [r |
some r in collection
is_equal(r, ref)
]
# Returns true if the provided bundle reference is recorded within the
# acceptable bundles data
_record_exists(ref) if {
# all records in acceptable task bundles for the given repository
records := data["task-bundles"][ref.repo]

some record in records

count(matches) > 0
# an acceptable task bundle reference is one that is recorded in the
# acceptable task bundles, this is done by matching it's digest; note no
# care is given to the expiry or freshness
record.digest == ref.digest
}

# Returns whether or not the ref matches the digest of the record.
is_equal(record, ref) := match if {
ref.digest != ""
match := record.digest == ref.digest
# Evaluates to true if the tasks bundle reference is found in the acceptable
# task bundles data, but also in the data there is a newer version of the task
# and it is effective, i.e. has a effective_on that is newer than the provided
# reference's effective_on and older or equal to the current effective time; two
# references are considered belonging to the same version if they have the same
# tag.
_newer_in_effect_version_exists(ref) if {
# all records in acceptable task bundles for the given repository
records := data["task-bundles"][ref.repo]

some record in records

# consider all records, if a match is found via exact digest and there
# exists a newer record for the same tag but it is newer, i.e. has greater
# effective_on value
record.digest == ref.digest

some other in records

# other record must be effective to be considered
time.parse_rfc3339_ns(other.effective_on) <= time_lib.effective_current_time_ns()

record.tag == other.tag

time.parse_rfc3339_ns(other.effective_on) > time.parse_rfc3339_ns(record.effective_on)
}

# Returns whether or not the ref matches the tag of the record as a fallback
# in case the digest is blank for the ref. This is a weaker comparison as,
# unlike digests, tags are not immutable entities. It is expected that a
# missing digest results in a warning whenever possible.
is_equal(record, ref) := match if {
ref.digest == ""
match := record.tag == ref.tag
# Evaluates to true if the tasks bundle reference is found in the acceptable
# task bundles data, but also there are no records in acceptable task bundles
# data with the same tag and at least one record is newer and it is effective,
# i.e. has a effective_on that is newer than the provided reference's
# effective_on and older or equal to the current effective time. In this case we
# cannot rely on the tags to signal versions so we take all records for a
# specific reference to belong to the same version.
_newer_in_effect_version_exists(ref) if {
# all records in acceptable task bundles for the given repository
records := data["task-bundles"][ref.repo]

some record in records

# consider all records, if a match is found via exact digest and there
# exists a newer record for the same tag but it is newer, i.e. has greater
# effective_on value
record.digest == ref.digest

# No other record in acceptable bundles matches the tag from the record
# matched by the digest to the reference
count([other |
some other in records
record.digest != other.digest # not the same record
record.tag == other.tag # we found at least one other tag equal to the one we want to compare with
]) == 0

# There are newer records
count([newer |
some newer in records
time.parse_rfc3339_ns(newer.effective_on) <= time_lib.effective_current_time_ns()
time.parse_rfc3339_ns(newer.effective_on) > time.parse_rfc3339_ns(record.effective_on)
]) > 0
}

bundle(task) := refs.task_ref(task).bundle
# Evaluates to true if the tasks bundle reference is found in the acceptable
# task bundles data, but also there are no records in acceptable task bundles
# data with the same tag and at least one record is newer, regardless of it's
# effective on date, i.e. has a effective_on that is newer than the provided
# reference's effective_on. Two references are considered belonging to the same
# version if they have the same tag.
_newer_version_exists(ref) if {
# all records in acceptable task bundles for the given repository
records := data["task-bundles"][ref.repo]

some record in records

# _collection returns an array representing the full list of records to
# be taken into consideration when evaluating policy rules for bundle
# references. Any irrelevant records are filtered out from the array.
# (The else condition is for when data["task-bundles"][ref.repo] doesn't exist.)
_collection(ref) := items if {
full_collection := data["task-bundles"][ref.repo]
items := time_lib.acceptable_items(full_collection)
} else := []
# consider all records, if a match is found via exact digest and there
# exists a newer record for the same tag but it is newer, i.e. has greater
# effective_on value
record.digest == ref.digest

some other in records

record.tag == other.tag
zregvart marked this conversation as resolved.
Show resolved Hide resolved

time.parse_rfc3339_ns(other.effective_on) > time.parse_rfc3339_ns(record.effective_on)
}

# Evaluates to true if the tasks bundle reference is found in the acceptable
# task bundles data, but also there are no records in acceptable task bundles
# data with the same tag and at least one record is newer, regardless of it's
# effective on date, i.e. has a effective_on that is newer than the provided
# reference's effective_on. In this case we cannot rely on the tags to signal
# versions so we take all records for a specific reference to belong to the same
# version.
_newer_version_exists(ref) if {
# all records in acceptable task bundles for the given repository
records := data["task-bundles"][ref.repo]

some record in records

# consider all records, if a match is found via exact digest and there
# exists a newer record for the same tag but it is newer, i.e. has greater
# effective_on value
record.digest == ref.digest

# No other record in acceptable bundles matches the tag from the record
# matched by the digest to the reference
count([other |
some other in records
record.digest != other.digest # not the same record
record.tag == other.tag # we found at least one other tag equal to the one we want to compare with
]) == 0

# There are newer records
count([newer |
some newer in records
time.parse_rfc3339_ns(newer.effective_on) > time.parse_rfc3339_ns(record.effective_on)
]) > 0
}

# Determine the image reference of the task bundle, if the provided task bundle
# image reference doesn't have the tag within it try to lookup the tag from the
# acceptable task bundles data
_bundle_ref(task, acceptable) := ref if {
ref := bundle(task)
img := image.parse(ref)
img.tag != ""
} else := ref if {
ref_no_tag := bundle(task)
img := image.parse(ref_no_tag)
img.tag == ""

# try to find the tag for the reference based on it's digest
records := acceptable[img.repo]

some record in records
record.digest == img.digest
record.tag != ""

ref := image.str({
"digest": img.digest,
"repo": img.repo,
"tag": record.tag,
})
} else := ref_no_tag if {
ref_no_tag := bundle(task)
}
Loading