mirror of
https://github.com/flatpak/flatpak.git
synced 2026-01-26 06:07:56 +00:00
tests: Test signed OCI images
This commit is contained in:
parent
404aa33ce1
commit
f242199eca
@ -295,9 +295,32 @@ export FL_GPG_ID=7B0961FD
|
||||
export FL_GPG_ID2=B2314EFC
|
||||
export FL_GPGARGS="--gpg-homedir=${FL_GPG_HOMEDIR} --gpg-sign=${FL_GPG_ID}"
|
||||
export FL_GPGARGS2="--gpg-homedir=${FL_GPG_HOMEDIR2} --gpg-sign=${FL_GPG_ID2}"
|
||||
export FL_GPGCMDARGS="--homedir ${FL_GPG_HOMEDIR} -u ${FL_GPG_ID}"
|
||||
export FL_GPGCMDARGS2="--homedir ${FL_GPG_HOMEDIR2} -u ${FL_GPG_ID2}"
|
||||
export FL_GPG_BASE64="mQENBFbPBvoBCADWbz5O+XzuyN+dDExK81pci+gIzBNWB+7SsN0EgoJppKgwBCX+Bd6ERe9Yz0nJbJB/tjazRp7MnnoPnh6fXnhIbHA766/Eciy4sL5X8laqDmWmROCqCe79QZH/w6vYTKsDmoLQrw9eKRP1ilCvECNGcVdhIyfTDlNrU//uy5U4h2PVUz1/Al87lvaJnrj5423m5GnX+qpEG8mmpmcw52lvXNPuC95ykylPQJjI0WnOuaTcxzRhm5eHPkqKQ+nPIS+66iw1SFdobYuye/vg/rDiyp8uyQkh7FWXnzHxz4J8ovesnrCM7pKI4VEHCnZ4/sj2v9E3l0wJlqZxLTULaV3lABEBAAG0D1hkZy1hcHAgdGVzdGluZ4kBOAQTAQIAIgUCVs8G+gIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQE4sx4HsJYf2DiAf7BQ8anU3CgYpJjuO2rT8jQPO0jGRCNaPyaeAcBx8IjFkjf8daKMPCAt6gQioEpC8OhDig86Bl5piYOB7L7JSB53mgUrADJXhgC/dG4soCt7/U4wW30MseXdlXSOqHGApblF/bIs4B30OBGReBj3DcWIqyb48GraSKlPlaCpkZFySNEAcGUCeCqbbygxCQAM8MDq9FgVRk5oVrE/nAUm6oScEBhseoB7+CaHaRTmLoe/SBs0z2AJ7alIH1Sv4X3mQXpfsAIcWf3Zu2MZydF/Vuh8vTMROwPYtOVEtGxZvEBN3h5uc88dHSk928maqsop9T6oEwM43mBKCOu1gdAOw4OLkBDQRWzwb6AQgAx/XuEaQvdI3J2YYmOE6RY0jJZXLauXH46cJR4q70mlDev/OqYKTSLlo4q06D4ozCwzTYflppDak7kmjWMN224/u1koqFOtF76LsglAeLaQmweWmX0ecbPrzFYaX30kaQAqQ9Wk0PRe0+arRzWDWfUv3qX3y1decKUrBCuEC6WvVVwooWs+zX0cUBS8CROhazTjvXFAz36mhK0u+B3WCBlK+T2tIPOjLjlYgzYARw+X7/J6B3C798r2Hw/yXqCDcKLrq7WWUB33kv3buuG2G6LUamctdD8IsTBxi+nIjAvQITFqq4cPbbXAJGaAnWGuLOddQ9e/GhCOI4JjopRnnjOwARAQABiQEfBBgBAgAJBQJWzwb6AhsMAAoJEBOLMeB7CWH9TC8H/A6oreCxeiL8DPOWN29OaQ5sEw7Dg7bnLSZLu8aREgwfCiFSv0numOABjn/G89Y5M6NiEXFZZhUa+SXOALiBLUy98O84lyp9hlP9qGbWRgBXwe5vOAJERqtoUwR5bygpAw5Nc4y3wddPC4vH7upJ8ftU/eEFtPdI0cKrrAZDFdhXFp3RxdCC6fD62wbofE0mo1Ea1iD3xqVh2t7jfWN1RhMV308htHRGkkmWcEbbvHqugwL6dWZEvQmLYi6/7tQyA1KdG4AZksBP/MBi3t2hthRqQx1v52JwdCaZNuItuEe5rWXhfvoGxPoqYZt9ZPjna6yJfcfJwPbMfjNwX2LR4p4="
|
||||
export FL_GPG_BASE642="mQENBFkSyx4BCACq/8XFcF+NTpJKfoo8F6YyR8RQXww6kCV47zN78Dt7aCh43WSYLRUBRt1tW5MRT8R60pwCsGvKnFiNS2Vqe4T1IW4mDnFMZIZJXdNVwKUqVBPL/jzkIDnQ9NXtuPNH0qET6VhYnb9aykLo/MiBmx6q+4MvYd/qwiN8kstRifRIxjjZx6wsg+muY6yx9fZKxlgvhc3nsrl3oyDo7/+V+b3heYLtMCQFwlHRKz3Yf2X9H0aUSbDYcgTy6w3q94HVNCpJSqeiR+kBG175BQYKR2l7WYdaVPFf5LMEvAJh0SGnqu77X+8TYYRQiiBB5fYjGOeHfOh6uH5GAJRQymVIJwy/ABEBAAG0KkZsYXRwYWsgKFRlc3Qga2V5IDIpIDxmbGF0cGFrQGZsYXRwYWsub3JnPokBOAQTAQIAIgUCWRLLHgIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQdZ9f0LIxTvyeUQf/euAZpipXBkGWxeW4G10r1QRi2tZAWNeLpy8SB17eo9E6yB61SdH80jALborVs/plnZzKcFf+nLvjCn51FLMh6QPL3S+079WHsed//qtUWfbJ85hLevfCMTZMLktUmqwwUh238WW/gKtbUjYOqr1IZSMBoMiQtc0iOVBP7HUdhYigxTKvs/MBEGHANeQkY07ZnX9oFXElOo+EIPAHScwEOSwEVrXUVHpQODzIfjOoPUHWAZtM1yJT+iWmVHe4HtU8CyBnPyUcnTmTWKr92QmgfWkb1T7ugT5gXt/6ZlYAaZGnr9yNuSk3MMhDMOyldtJBM5Zl8eScE9KBf7pRJoxnMLkBDQRZEsseAQgAvA29IyiJpB+jUHj3MOyVyTBOmvLme+0Ndhpt/mTh+swchJUvzb0IzQS9Le5yVAvn+ppAtDCMb+bV4Xh5zrbiH0Hu0qwK4Qk+KcIKRE8ImDiUM8NFE2SZoomZSsgZ1NBWbAdEyVpkBfrt3Dd8FssMrwPF6kqo02TZr7Pxng+BEHUZT6jPCxueqyXyv2cLbQMe1H0U7klsxPmnnIYUqdwOmPxUspVEYP9oJb5y123mx0yj5JuYdZMjWbP3cRLox1RKIlFWgQqOn2yJiEoWzpqdbtb7sE3ggnbZKJED0ZxUZIakjnyMhX+GAEA8ZMZ6+HfDt1iHV8qHcYiLW5A3AQTxZwARAQABiQEfBBgBAgAJBQJZEsseAhsMAAoJEHWfX9CyMU78Ns4IAJRQ5UJ9KkeZClHm1EjYlgsAq1UJr9wgbyBFKTEkGZ/CAvVmgg+BUXcN/SPAkELbEAOJZTyv8C5cuJC49iFHOxUbRZXZ5eN2SvhZzl+5gep2uHwVLdqRIxFDTHbLWnmtHxPeU7IRA9u86q3wV1N0pD7kreNN7BWKY3/tI33hY2/XVVFy0MN5sutPn+lVK66MqAHqtode5xqqz9Z8LmS7LlqokQkAytcGd6Xqsx99NTk8kk3bnk9HWsAvDO8tRZroeseKeRNmbhGvCNUxPSB6bpYBJLvQtjA9ZVv6sNm0E+SuiXKizZkBGO5AH50pDoy0+MCGoOhwwXeY5+1kZAOzkMI="
|
||||
|
||||
make_oci_signature () {
|
||||
DIGEST="$1"
|
||||
REFERENCE="$2"
|
||||
GPGARGS="${3:-${FL_GPGCMDARGS}}"
|
||||
|
||||
gpg ${GPGARGS} --sign - <<EOF
|
||||
{
|
||||
"critical": {
|
||||
"type": "atomic container signature",
|
||||
"image": {
|
||||
"docker-manifest-digest": "$DIGEST"
|
||||
},
|
||||
"identity": {
|
||||
"docker-reference": "$REFERENCE"
|
||||
}
|
||||
},
|
||||
"optional": {}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
make_runtime () {
|
||||
REPONAME="$1"
|
||||
COLLECTION_ID="$2"
|
||||
|
||||
@ -54,6 +54,34 @@ def run_delete(args):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def run_add_sig(args):
|
||||
params = {"s": args.signature}
|
||||
query = urllib.parse.urlencode(params)
|
||||
conn = get_conn(args)
|
||||
path = "/testing-sig/{repo}/{digest}?{query}".format(
|
||||
repo=args.repo, digest=args.digest, query=query
|
||||
)
|
||||
conn.request("POST", path)
|
||||
response = conn.getresponse()
|
||||
if response.status != 200:
|
||||
print(response.read(), file=sys.stderr)
|
||||
print("Failed: status={}".format(response.status), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def run_delete_sig(args):
|
||||
conn = get_conn(args)
|
||||
path = "/testing-sig/{repo}/{digest}".format(
|
||||
repo=args.repo, digest=args.digest
|
||||
)
|
||||
conn.request("DELETE", path)
|
||||
response = conn.getresponse()
|
||||
if response.status != 200:
|
||||
print(response.read(), file=sys.stderr)
|
||||
print("Failed: status={}".format(response.status), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--url", required=True)
|
||||
parser.add_argument("--cacert")
|
||||
@ -75,5 +103,16 @@ delete_parser.add_argument("repo")
|
||||
delete_parser.add_argument("ref")
|
||||
delete_parser.set_defaults(func=run_delete)
|
||||
|
||||
add_sig_parser = subparsers.add_parser("add-signature")
|
||||
add_sig_parser.add_argument("repo")
|
||||
add_sig_parser.add_argument("digest")
|
||||
add_sig_parser.add_argument("signature")
|
||||
add_sig_parser.set_defaults(func=run_add_sig)
|
||||
|
||||
delete_sig_parser = subparsers.add_parser("delete-signature")
|
||||
delete_sig_parser.add_argument("repo")
|
||||
delete_sig_parser.add_argument("digest")
|
||||
delete_sig_parser.set_defaults(func=run_delete_sig)
|
||||
|
||||
args = parser.parse_args()
|
||||
args.func(args)
|
||||
|
||||
@ -13,6 +13,7 @@ import http.server as http_server
|
||||
|
||||
repositories = {}
|
||||
icons = {}
|
||||
signatures = {}
|
||||
|
||||
|
||||
def get_index():
|
||||
@ -116,6 +117,15 @@ class RequestHandler(http_server.BaseHTTPRequestHandler):
|
||||
response = 200
|
||||
response_string = icons[self.matches["filename"]]
|
||||
response_content_type = "image/png"
|
||||
elif self.check_route("/sig-lookaside/@ref/@sig"):
|
||||
ref = self.matches["ref"]
|
||||
sig = self.matches["sig"]
|
||||
index = int(sig.removeprefix("signature-")) - 1
|
||||
try:
|
||||
response = 200
|
||||
response_string = signatures[ref][index]
|
||||
except (KeyError, IndexError):
|
||||
response = 404
|
||||
|
||||
assert isinstance(response, int)
|
||||
assert isinstance(response_string, bytes)
|
||||
@ -212,6 +222,20 @@ class RequestHandler(http_server.BaseHTTPRequestHandler):
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
return
|
||||
elif self.check_route("/testing-sig/@repo_name/@digest"):
|
||||
repo_name = self.matches["repo_name"]
|
||||
digest = self.matches["digest"]
|
||||
s = self.query["s"][0]
|
||||
|
||||
with open(s, "rb") as f:
|
||||
signature_bytes = f.read()
|
||||
|
||||
digest = digest.replace(":", "=")
|
||||
ref = f"{repo_name}@{digest}"
|
||||
sigs = signatures.setdefault(ref, [])
|
||||
sigs.append(signature_bytes)
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
else:
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
@ -244,6 +268,16 @@ class RequestHandler(http_server.BaseHTTPRequestHandler):
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
return
|
||||
elif self.check_route("/testing-sig/@repo_name/@digest"):
|
||||
repo_name = self.matches["repo_name"]
|
||||
digest = self.matches["digest"]
|
||||
|
||||
digest = digest.replace(":", "=")
|
||||
ref = f"{repo_name}@{digest}"
|
||||
signatures[ref] = list()
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
return
|
||||
else:
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
|
||||
@ -23,7 +23,7 @@ set -euo pipefail
|
||||
|
||||
skip_without_bwrap
|
||||
|
||||
echo "1..17"
|
||||
echo "1..18"
|
||||
|
||||
# Start the fake registry server
|
||||
|
||||
@ -361,3 +361,66 @@ if false && [ x${USE_SYSTEMDIR-} != xyes ]; then
|
||||
else
|
||||
ok "install image from registry # skip Not supported"
|
||||
fi
|
||||
|
||||
# Test OCI signing
|
||||
|
||||
${FLATPAK} build-bundle --runtime --oci "${FL_GPGARGS}" repos/oci oci/platform-image org.test.Platform >&2
|
||||
digest=$(jq -r '.manifests[0].digest' "$(pwd)/oci/platform-image/index.json")
|
||||
make_oci_signature "${digest}" "127.0.0.1:${port}/platform:latest" > "$(pwd)/oci/platform-image-signature-1"
|
||||
make_oci_signature "${digest}" "127.0.0.1:${port}/platform:latest" "${FL_GPGCMDARGS2}"> "$(pwd)/oci/platform-image-signature-2"
|
||||
|
||||
$client add platform latest "$(pwd)/oci/platform-image"
|
||||
$client add-signature platform "${digest}" "$(pwd)/oci/platform-image-signature-1"
|
||||
|
||||
${FLATPAK} build-bundle --oci "${FL_GPGARGS}" repos/oci oci/app-image org.test.Hello >&2
|
||||
digest=$(jq -r '.manifests[0].digest' "$(pwd)/oci/app-image/index.json")
|
||||
make_oci_signature "${digest}" "127.0.0.1:${port}/hello:latest" > "$(pwd)/oci/app-image-signature-1"
|
||||
make_oci_signature "${digest}" "127.0.0.1:${port}/hello:latest" "$FL_GPGCMDARGS2" > "$(pwd)/oci/app-image-signature-2"
|
||||
|
||||
$client add hello latest "$(pwd)/oci/app-image"
|
||||
|
||||
${FLATPAK} ${U} remote-add oci-registry-sig "oci+${scheme}://127.0.0.1:${port}" \
|
||||
--signature-lookaside "${scheme}://127.0.0.1:${port}/sig-lookaside" \
|
||||
--gpg-import=${FL_GPG_HOMEDIR}/pubring.gpg >&2
|
||||
|
||||
if ${FLATPAK} ${U} install -y oci-registry-sig org.test.Hello >&2; then
|
||||
assert_not_reached "Should fail install due to missing signature key"
|
||||
fi
|
||||
|
||||
$client add-signature hello "${digest}" "$(pwd)/oci/app-image-signature-2"
|
||||
if ${FLATPAK} ${U} install -y oci-registry-sig org.test.Hello >&2; then
|
||||
assert_not_reached "Should fail install due to wrong signature key"
|
||||
fi
|
||||
|
||||
$client add-signature hello "${digest}" "$(pwd)/oci/app-image-signature-1"
|
||||
${FLATPAK} ${U} install -y oci-registry-sig org.test.Hello >&2
|
||||
|
||||
${FLATPAK} build-bundle --oci "${FL_GPGARGS}" repos/oci oci/app-image org.test.Hello >&2
|
||||
digest=$(jq -r '.manifests[0].digest' "$(pwd)/oci/app-image/index.json")
|
||||
make_oci_signature "${digest}" "127.0.0.1:${port}/hello:latest" > "$(pwd)/oci/app-image-signature-1"
|
||||
make_oci_signature "${digest}" "127.0.0.1:${port}/hello:latest" "$FL_GPGCMDARGS2" > "$(pwd)/oci/app-image-signature-2"
|
||||
|
||||
$client add hello latest "$(pwd)/oci/app-image"
|
||||
if ${FLATPAK} update -y org.test.Hello >&2; then
|
||||
assert_not_reached "Should fail install due to outdated signature key"
|
||||
fi
|
||||
|
||||
$client add-signature hello "${digest}" "$(pwd)/oci/app-image-signature-1"
|
||||
${FLATPAK} update -y org.test.Hello >&2
|
||||
|
||||
${FLATPAK} uninstall -y org.test.Hello >&2
|
||||
|
||||
${FLATPAK} ${U} remote-delete --force oci-registry-sig >&2
|
||||
${FLATPAK} ${U} remote-add oci-registry-sig "oci+${scheme}://127.0.0.1:${port}" \
|
||||
--signature-lookaside "${scheme}://127.0.0.1:${port}/sig-lookaside" \
|
||||
--gpg-import=${FL_GPG_HOMEDIR2}/pubring.gpg >&2
|
||||
|
||||
if ${FLATPAK} ${U} install -y oci-registry-sig org.test.Hello >&2; then
|
||||
assert_not_reached "Should fail install due to locally changed trusted key"
|
||||
fi
|
||||
|
||||
$client add-signature hello "${digest}" "$(pwd)/oci/app-image-signature-2"
|
||||
|
||||
${FLATPAK} ${U} install -y oci-registry-sig org.test.Hello >&2
|
||||
|
||||
ok "signed images"
|
||||
Loading…
x
Reference in New Issue
Block a user