feat(release): require versioned locked publication
This commit is contained in:
+16
-13
@@ -20,6 +20,7 @@ CANARY = b"TREX_SECRET_CANARY_DO_NOT_SHIP"
|
||||
COMMIT_RE = re.compile(r"^[0-9a-f]{40}$")
|
||||
DIGEST_RE = re.compile(r"(?:^|\s)digest:\s*(sha256:[0-9a-f]{64})(?:\s|$)")
|
||||
IMAGE_ID_RE = re.compile(r"^sha256:[0-9a-f]{64}$")
|
||||
VERSION_TAG_RE = re.compile(r"^refs/tags/v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$")
|
||||
DEFAULT_MIGRATION_DIR = (
|
||||
Path(__file__).resolve().parents[1] / "trex_core" / "adapters" / "persistence" / "sql"
|
||||
)
|
||||
@@ -100,19 +101,18 @@ def validate_commit(commit: str) -> str:
|
||||
return commit
|
||||
|
||||
|
||||
def release_tags(commit: str, ref: str) -> list[str]:
|
||||
def validate_publication_trigger(event_name: str, ref: str) -> str:
|
||||
if event_name != "push":
|
||||
raise ValueError("publication event must be a push")
|
||||
if not VERSION_TAG_RE.fullmatch(ref):
|
||||
raise ValueError("publication ref must be a strict vX.Y.Z tag")
|
||||
return ref.removeprefix("refs/tags/")
|
||||
|
||||
|
||||
def release_tags(commit: str, event_name: str, ref: str) -> list[str]:
|
||||
validate_commit(commit)
|
||||
tags = [f"{IMAGE}:{commit[:12]}"]
|
||||
if ref == "refs/heads/main":
|
||||
return tags
|
||||
prefix = "refs/tags/"
|
||||
if ref.startswith(prefix) and ref.removeprefix(prefix).startswith("v"):
|
||||
release = ref.removeprefix(prefix)
|
||||
if not re.fullmatch(r"v[A-Za-z0-9._-]*", release):
|
||||
raise ValueError("release ref contains unsupported tag characters")
|
||||
tags.append(f"{IMAGE}:{release}")
|
||||
return tags
|
||||
raise ValueError("publication ref must be main or a v* tag")
|
||||
release = validate_publication_trigger(event_name, ref)
|
||||
return [f"{IMAGE}:{commit[:12]}", f"{IMAGE}:{release}"]
|
||||
|
||||
|
||||
def sha256_file(path: Path) -> str:
|
||||
@@ -359,6 +359,7 @@ def publish_image(
|
||||
image_id: Path,
|
||||
local_image: str,
|
||||
commit: str,
|
||||
event_name: str,
|
||||
ref: str,
|
||||
actor: str,
|
||||
token: str,
|
||||
@@ -366,7 +367,7 @@ def publish_image(
|
||||
output_path: Path | None = None,
|
||||
summary_path: Path | None = None,
|
||||
) -> str:
|
||||
tags = release_tags(commit, ref)
|
||||
tags = release_tags(commit, event_name, ref)
|
||||
verify_checksum(archive, checksum)
|
||||
expected_image_id = read_image_id(image_id)
|
||||
loaded = runner.run(["docker", "load", "--input", str(archive)])
|
||||
@@ -450,6 +451,7 @@ def _parser() -> argparse.ArgumentParser:
|
||||
publish.add_argument("--image-id", type=Path, required=True)
|
||||
publish.add_argument("--local-image", required=True)
|
||||
publish.add_argument("--commit", required=True)
|
||||
publish.add_argument("--event-name", required=True)
|
||||
publish.add_argument("--ref", required=True)
|
||||
return parser
|
||||
|
||||
@@ -476,6 +478,7 @@ def main(argv: Sequence[str] | None = None) -> int:
|
||||
image_id=args.image_id,
|
||||
local_image=args.local_image,
|
||||
commit=args.commit,
|
||||
event_name=args.event_name,
|
||||
ref=args.ref,
|
||||
actor=os.environ.get("GITHUB_ACTOR", ""),
|
||||
token=os.environ.get("REGISTRY_TOKEN", ""),
|
||||
|
||||
Reference in New Issue
Block a user