Resolve runtime dependency platform digests
This commit is contained in:
@@ -195,18 +195,33 @@ jobs:
|
||||
WEB_DIGEST="sha256:$(sha256sum runtime-output/web-index.json | cut -d' ' -f1)"
|
||||
python tools/release/resolve-oci-platforms.py --repository git.add-ideas.de/govoplan/runtime-api --index-digest "$API_DIGEST" --index runtime-output/api-index.json --output runtime-output/api-metadata.json
|
||||
python tools/release/resolve-oci-platforms.py --repository git.add-ideas.de/govoplan/runtime-web --index-digest "$WEB_DIGEST" --index runtime-output/web-index.json --output runtime-output/web-metadata.json
|
||||
- name: Exercise amd64 and arm64 runtime images
|
||||
- name: Resolve managed dependency platform images
|
||||
working-directory: govoplan
|
||||
env:
|
||||
POSTGRES_IMAGE: ${{ inputs.postgres_image }}
|
||||
REDIS_IMAGE: ${{ inputs.redis_image }}
|
||||
run: |
|
||||
docker buildx imagetools inspect "$POSTGRES_IMAGE" --raw > runtime-output/postgres-index.json
|
||||
docker buildx imagetools inspect "$REDIS_IMAGE" --raw > runtime-output/redis-index.json
|
||||
python tools/release/resolve-oci-platforms.py \
|
||||
--repository "${POSTGRES_IMAGE%@*}" \
|
||||
--index-digest "${POSTGRES_IMAGE##*@}" \
|
||||
--index runtime-output/postgres-index.json \
|
||||
--output runtime-output/postgres-metadata.json
|
||||
python tools/release/resolve-oci-platforms.py \
|
||||
--repository "${REDIS_IMAGE%@*}" \
|
||||
--index-digest "${REDIS_IMAGE##*@}" \
|
||||
--index runtime-output/redis-index.json \
|
||||
--output runtime-output/redis-metadata.json
|
||||
- name: Exercise amd64 and arm64 runtime images
|
||||
working-directory: govoplan
|
||||
run: |
|
||||
for ARCH in amd64 arm64; do
|
||||
.runtime-build/bin/python tools/checks/runtime-image-smoke.py \
|
||||
--api-metadata runtime-output/api-metadata.json \
|
||||
--web-metadata runtime-output/web-metadata.json \
|
||||
--postgres-image "$POSTGRES_IMAGE" \
|
||||
--redis-image "$REDIS_IMAGE" \
|
||||
--postgres-metadata runtime-output/postgres-metadata.json \
|
||||
--redis-metadata runtime-output/redis-metadata.json \
|
||||
--platform "linux/$ARCH" \
|
||||
--output "runtime-output/evidence/runtime-smoke-$ARCH.json"
|
||||
done
|
||||
|
||||
@@ -157,6 +157,9 @@ migrations against the pinned PostgreSQL image, reach API and WebUI readiness
|
||||
as non-root/read-only processes, and complete a task through the pinned Redis
|
||||
image and packaged worker. Sanitized per-platform smoke receipts are retained
|
||||
as immutable release assets.
|
||||
PostgreSQL and Redis indexes are resolved to untagged platform-child digests
|
||||
before each smoke run. This keeps the evidence architecture-specific and
|
||||
avoids retargeting one local Docker tag between incompatible platforms.
|
||||
The smoke also proves a bounded post-migration table contract and aborts as
|
||||
soon as a required container exits, rather than allowing a dead process to
|
||||
consume the full readiness timeout.
|
||||
|
||||
@@ -145,6 +145,9 @@ class RuntimeDistributionBuildTests(unittest.TestCase):
|
||||
|
||||
self.assertIn('for ARCH in amd64 arm64; do', workflow)
|
||||
self.assertIn("tools/checks/runtime-image-smoke.py", workflow)
|
||||
self.assertIn("Resolve managed dependency platform images", workflow)
|
||||
self.assertIn("--postgres-metadata", workflow)
|
||||
self.assertIn("--redis-metadata", workflow)
|
||||
self.assertIn("runtime-smoke-amd64.json", workflow)
|
||||
self.assertIn("runtime-smoke-arm64.json", workflow)
|
||||
|
||||
@@ -244,6 +247,15 @@ class RuntimeDistributionBuildTests(unittest.TestCase):
|
||||
"registry.example/govoplan/api@sha256:" + "1" * 64,
|
||||
metadata["platforms"]["linux/amd64"],
|
||||
)
|
||||
dependency_metadata = OCI.resolve_platforms(
|
||||
index,
|
||||
repository="registry.example:5000/library/postgres:16-alpine",
|
||||
index_digest="sha256:" + "a" * 64,
|
||||
)
|
||||
self.assertEqual(
|
||||
"registry.example:5000/library/postgres@sha256:" + "2" * 64,
|
||||
dependency_metadata["platforms"]["linux/arm64"],
|
||||
)
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="govoplan-runtime-finalize-") as value:
|
||||
root = Path(value)
|
||||
|
||||
@@ -41,8 +41,8 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--api-metadata", type=Path, required=True)
|
||||
parser.add_argument("--web-metadata", type=Path, required=True)
|
||||
parser.add_argument("--postgres-image", required=True)
|
||||
parser.add_argument("--redis-image", required=True)
|
||||
parser.add_argument("--postgres-metadata", type=Path, required=True)
|
||||
parser.add_argument("--redis-metadata", type=Path, required=True)
|
||||
parser.add_argument("--platform", choices=sorted(PLATFORMS), required=True)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("--timeout-seconds", type=float, default=600.0)
|
||||
@@ -625,11 +625,17 @@ def main() -> int:
|
||||
try:
|
||||
api_image = platform_image(args.api_metadata, args.platform, "API")
|
||||
web_image = platform_image(args.web_metadata, args.platform, "Web")
|
||||
postgres_image = platform_image(
|
||||
args.postgres_metadata,
|
||||
args.platform,
|
||||
"PostgreSQL",
|
||||
)
|
||||
redis_image = platform_image(args.redis_metadata, args.platform, "Redis")
|
||||
evidence = run_smoke(
|
||||
api_image=api_image,
|
||||
web_image=web_image,
|
||||
postgres_image=args.postgres_image,
|
||||
redis_image=args.redis_image,
|
||||
postgres_image=postgres_image,
|
||||
redis_image=redis_image,
|
||||
platform=args.platform,
|
||||
timeout=args.timeout_seconds,
|
||||
)
|
||||
|
||||
@@ -21,6 +21,12 @@ def resolve_platforms(
|
||||
) -> dict[str, object]:
|
||||
if not repository or "@" in repository or any(value.isspace() for value in repository):
|
||||
raise ValueError("repository must be an unpinned OCI repository name")
|
||||
last_slash = repository.rfind("/")
|
||||
last_colon = repository.rfind(":")
|
||||
if last_colon > last_slash:
|
||||
repository = repository[:last_colon]
|
||||
if not repository:
|
||||
raise ValueError("repository must be an unpinned OCI repository name")
|
||||
if DIGEST.fullmatch(index_digest) is None:
|
||||
raise ValueError("index digest must be sha256:<hex>")
|
||||
if not isinstance(payload, dict) or not isinstance(payload.get("manifests"), list):
|
||||
|
||||
Reference in New Issue
Block a user