feat(release): require versioned locked publication
This commit is contained in:
@@ -64,18 +64,50 @@ def _artifact(tmp_path: Path) -> tuple[Path, Path, Path]:
|
||||
|
||||
|
||||
def test_release_tags_are_deterministic_and_never_latest():
|
||||
main = image_release.release_tags(COMMIT, "refs/heads/main")
|
||||
release = image_release.release_tags(COMMIT, "refs/tags/v1.2.3")
|
||||
release = image_release.release_tags(COMMIT, "push", "refs/tags/v1.2.3")
|
||||
|
||||
assert main == [f"{image_release.IMAGE}:{COMMIT[:12]}"]
|
||||
assert release == [*main, f"{image_release.IMAGE}:v1.2.3"]
|
||||
assert all(not tag.endswith(":latest") for tag in main + release)
|
||||
assert release == [
|
||||
f"{image_release.IMAGE}:{COMMIT[:12]}",
|
||||
f"{image_release.IMAGE}:v1.2.3",
|
||||
]
|
||||
assert all(not tag.endswith(":latest") for tag in release)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("ref", ["refs/tags/v0.0.0", "refs/tags/v10.20.30"])
|
||||
def test_strict_version_tags_accept_zero_and_nonzero_decimal_components(ref):
|
||||
assert image_release.validate_publication_trigger("push", ref) == ref.removeprefix(
|
||||
"refs/tags/"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("event_name", "ref"),
|
||||
[
|
||||
("workflow_dispatch", "refs/tags/v1.2.3"),
|
||||
("pull_request", "refs/tags/v1.2.3"),
|
||||
("push", "refs/heads/main"),
|
||||
("push", "refs/heads/release"),
|
||||
("push", "refs/tags/1.2.3"),
|
||||
("push", "refs/tags/v1.2"),
|
||||
("push", "refs/tags/v1.2.3.4"),
|
||||
("push", "refs/tags/v01.2.3"),
|
||||
("push", "refs/tags/v1.02.3"),
|
||||
("push", "refs/tags/v1.2.03"),
|
||||
("push", "refs/tags/v1.2.3-rc.1"),
|
||||
("push", "refs/tags/v1.2.3+build.1"),
|
||||
("push", "refs/tags/v-1.2.3"),
|
||||
("push", "refs/tags/v1.a.3"),
|
||||
],
|
||||
)
|
||||
def test_non_push_branch_and_malformed_version_triggers_are_rejected(event_name, ref):
|
||||
with pytest.raises(ValueError):
|
||||
image_release.validate_publication_trigger(event_name, ref)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("commit", ["A" * 40, "a" * 39, "g" * 40, ""])
|
||||
def test_invalid_source_commit_is_rejected(commit):
|
||||
with pytest.raises(ValueError):
|
||||
image_release.release_tags(commit, "refs/heads/main")
|
||||
image_release.release_tags(commit, "push", "refs/tags/v1.2.3")
|
||||
|
||||
|
||||
def test_smoke_uses_exact_isolated_probes_and_cleans_containers():
|
||||
@@ -156,7 +188,38 @@ def test_mutated_archive_stops_before_load_or_registry(tmp_path):
|
||||
image_id=image_id,
|
||||
local_image=f"trex-core-ci:{COMMIT}",
|
||||
commit=COMMIT,
|
||||
ref="refs/heads/main",
|
||||
event_name="push",
|
||||
ref="refs/tags/v1.2.3",
|
||||
actor="actor",
|
||||
token="fake-token",
|
||||
runner=runner,
|
||||
)
|
||||
assert runner.commands == []
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("event_name", "ref"),
|
||||
[
|
||||
("workflow_dispatch", "refs/tags/v1.2.3"),
|
||||
("push", "refs/heads/main"),
|
||||
("push", "refs/tags/v01.2.3"),
|
||||
("push", "refs/tags/v1.2.3-rc.1"),
|
||||
],
|
||||
)
|
||||
def test_invalid_publication_trigger_stops_before_artifact_load_or_registry(
|
||||
tmp_path, event_name, ref
|
||||
):
|
||||
runner = RecordingRunner()
|
||||
|
||||
with pytest.raises(ValueError, match="publication"):
|
||||
image_release.publish_image(
|
||||
archive=tmp_path / "missing.tar",
|
||||
checksum=tmp_path / "missing.sha256",
|
||||
image_id=tmp_path / "missing.id",
|
||||
local_image=f"trex-core-ci:{COMMIT}",
|
||||
commit=COMMIT,
|
||||
event_name=event_name,
|
||||
ref=ref,
|
||||
actor="actor",
|
||||
token="fake-token",
|
||||
runner=runner,
|
||||
@@ -175,7 +238,8 @@ def test_load_failure_stops_before_login_and_push(tmp_path):
|
||||
image_id=image_id,
|
||||
local_image=f"trex-core-ci:{COMMIT}",
|
||||
commit=COMMIT,
|
||||
ref="refs/heads/main",
|
||||
event_name="push",
|
||||
ref="refs/tags/v1.2.3",
|
||||
actor="actor",
|
||||
token="fake-token",
|
||||
runner=runner,
|
||||
@@ -194,7 +258,8 @@ def test_revision_mismatch_stops_before_login_and_push(tmp_path):
|
||||
image_id=image_id,
|
||||
local_image=f"trex-core-ci:{COMMIT}",
|
||||
commit=COMMIT,
|
||||
ref="refs/heads/main",
|
||||
event_name="push",
|
||||
ref="refs/tags/v1.2.3",
|
||||
actor="actor",
|
||||
token="fake-token",
|
||||
runner=runner,
|
||||
@@ -213,7 +278,8 @@ def test_expected_image_id_mismatch_stops_before_credentials_tags_or_push(tmp_pa
|
||||
image_id=image_id,
|
||||
local_image=f"trex-core-ci:{COMMIT}",
|
||||
commit=COMMIT,
|
||||
ref="refs/heads/main",
|
||||
event_name="push",
|
||||
ref="refs/tags/v1.2.3",
|
||||
actor="actor",
|
||||
token="fake-token",
|
||||
runner=runner,
|
||||
@@ -235,7 +301,8 @@ def test_unrelated_load_output_cannot_use_stale_expected_local_tag(tmp_path):
|
||||
image_id=image_id,
|
||||
local_image=f"trex-core-ci:{COMMIT}",
|
||||
commit=COMMIT,
|
||||
ref="refs/heads/main",
|
||||
event_name="push",
|
||||
ref="refs/tags/v1.2.3",
|
||||
actor="actor",
|
||||
token="fake-token",
|
||||
runner=runner,
|
||||
@@ -262,7 +329,8 @@ def test_invalid_tested_image_id_stops_before_load(tmp_path, invalid_id):
|
||||
image_id=image_id,
|
||||
local_image=f"trex-core-ci:{COMMIT}",
|
||||
commit=COMMIT,
|
||||
ref="refs/heads/main",
|
||||
event_name="push",
|
||||
ref="refs/tags/v1.2.3",
|
||||
actor="actor",
|
||||
token="fake-token",
|
||||
runner=runner,
|
||||
@@ -292,6 +360,7 @@ def test_valid_publish_records_digest_only_after_push(tmp_path):
|
||||
image_id=image_id,
|
||||
local_image=f"trex-core-ci:{COMMIT}",
|
||||
commit=COMMIT,
|
||||
event_name="push",
|
||||
ref="refs/tags/v2.0.0",
|
||||
actor="actor",
|
||||
token="fake-token",
|
||||
@@ -323,7 +392,8 @@ def test_invalid_post_push_digest_emits_no_success_evidence(tmp_path, bad_digest
|
||||
image_id=image_id,
|
||||
local_image=f"trex-core-ci:{COMMIT}",
|
||||
commit=COMMIT,
|
||||
ref="refs/heads/main",
|
||||
event_name="push",
|
||||
ref="refs/tags/v1.2.3",
|
||||
actor="actor",
|
||||
token="fake-token",
|
||||
runner=runner,
|
||||
@@ -356,6 +426,7 @@ def test_release_second_push_failure_preserves_nonzero_without_success_evidence(
|
||||
image_id=image_id,
|
||||
local_image=f"trex-core-ci:{COMMIT}",
|
||||
commit=COMMIT,
|
||||
event_name="push",
|
||||
ref="refs/tags/v2.0.0",
|
||||
actor="actor",
|
||||
token="fake-token",
|
||||
|
||||
Reference in New Issue
Block a user