mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-05-04 04:31:49 +02:00
90 lines
2.9 KiB
Python
90 lines
2.9 KiB
Python
import subprocess
|
|
from tempfile import NamedTemporaryFile
|
|
|
|
from . import cosign
|
|
|
|
# NOTE: You can grab the SLSA attestation for an image/tag pair with the following
|
|
# commands:
|
|
#
|
|
# IMAGE=ghcr.io/apyrgio/dangerzone/dangerzone
|
|
# TAG=20250129-0.8.0-149-gbf2f5ac
|
|
# DIGEST=$(crane digest ${IMAGE?}:${TAG?})
|
|
# ATT_MANIFEST=${IMAGE?}:${DIGEST/:/-}.att
|
|
# ATT_BLOB=${IMAGE?}@$(crane manifest ${ATT_MANIFEST?} | jq -r '.layers[0].digest')
|
|
# crane blob ${ATT_BLOB?} | jq -r '.payload' | base64 -d | jq
|
|
CUE_POLICY = r"""
|
|
// The predicateType field must match this string
|
|
predicateType: "https://slsa.dev/provenance/v0.2"
|
|
|
|
predicate: {{
|
|
// This condition verifies that the builder is the builder we
|
|
// expect and trust. The following condition can be used
|
|
// unmodified. It verifies that the builder is the container
|
|
// workflow.
|
|
builder: {{
|
|
id: =~"^https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v[0-9]+.[0-9]+.[0-9]+$"
|
|
}}
|
|
invocation: {{
|
|
configSource: {{
|
|
// This condition verifies the entrypoint of the workflow.
|
|
// Replace with the relative path to your workflow in your
|
|
// repository.
|
|
entryPoint: "{workflow}"
|
|
|
|
// This condition verifies that the image was generated from
|
|
// the source repository we expect. Replace this with your
|
|
// repository.
|
|
uri: =~"^git\\+https://github.com/{repository}@refs/heads/{branch}"
|
|
// Add a condition to check for a specific commit hash
|
|
digest: {{
|
|
sha1: "{commit}"
|
|
}}
|
|
}}
|
|
}}
|
|
}}
|
|
"""
|
|
|
|
|
|
def verify(
|
|
image_name: str,
|
|
branch: str,
|
|
commit: str,
|
|
repository: str,
|
|
workflow: str,
|
|
) -> bool:
|
|
"""
|
|
Look up the image attestation to see if the image has been built
|
|
on Github runners, and from a given repository.
|
|
"""
|
|
cosign.ensure_installed()
|
|
policy = CUE_POLICY.format(
|
|
repository=repository, workflow=workflow, commit=commit, branch=branch
|
|
)
|
|
|
|
# Put the value in files and verify with cosign
|
|
with (
|
|
NamedTemporaryFile(mode="w", suffix=".cue") as policy_f,
|
|
):
|
|
policy_f.write(policy)
|
|
policy_f.flush()
|
|
|
|
# Call cosign with the temporary file paths
|
|
cmd = [
|
|
"cosign",
|
|
"verify-attestation",
|
|
"--type",
|
|
"slsaprovenance",
|
|
"--policy",
|
|
policy_f.name,
|
|
"--certificate-oidc-issuer",
|
|
"https://token.actions.githubusercontent.com",
|
|
"--certificate-identity-regexp",
|
|
"^https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v[0-9]+.[0-9]+.[0-9]+$",
|
|
image_name,
|
|
]
|
|
|
|
result = subprocess.run(cmd, capture_output=True)
|
|
if result.returncode != 0:
|
|
error = result.stderr.decode()
|
|
raise Exception(f"Attestation cannot be verified. {error}")
|
|
return True
|