mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-03 12:47:49 +00:00
Merge candidate 20260911T204017Z-core-runtime
Change-source: pulse-maintainer
This commit is contained in:
commit
34ba9a5ed9
3 changed files with 85 additions and 0 deletions
11
.github/workflows/create-release.yml
vendored
11
.github/workflows/create-release.yml
vendored
|
|
@ -993,12 +993,14 @@ jobs:
|
|||
RELEASE_ID=$(echo "$EXISTING_RELEASE" | jq -r '.id // empty')
|
||||
RELEASE_URL=$(echo "$EXISTING_RELEASE" | jq -r '.html_url // empty')
|
||||
RELEASE_IS_DRAFT=$(echo "$EXISTING_RELEASE" | jq -r '.draft // false')
|
||||
RELEASE_TARGET_COMMITISH=$(echo "$EXISTING_RELEASE" | jq -r '.target_commitish // empty')
|
||||
RELEASE_PUBLISHED_AT=$(echo "$EXISTING_RELEASE" | jq -r '.published_at // empty')
|
||||
RELEASE_ACTIVATION_COMMITTED=$(echo "$EXISTING_RELEASE" | jq -r 'any(.assets[]?; .name == "release-activation.json")')
|
||||
|
||||
python3 scripts/write_github_output.py release_id "${RELEASE_ID}"
|
||||
python3 scripts/write_github_output.py release_url "${RELEASE_URL}"
|
||||
python3 scripts/write_github_output.py release_is_draft "${RELEASE_IS_DRAFT}"
|
||||
python3 scripts/write_github_output.py release_target_commitish "${RELEASE_TARGET_COMMITISH}"
|
||||
python3 scripts/write_github_output.py release_published_at "${RELEASE_PUBLISHED_AT}"
|
||||
python3 scripts/write_github_output.py release_activation_committed "${RELEASE_ACTIVATION_COMMITTED}"
|
||||
|
||||
|
|
@ -1032,6 +1034,7 @@ jobs:
|
|||
WORKFLOW_OUTPUT_6: ${{ steps.existing_release.outputs.release_is_draft }}
|
||||
WORKFLOW_OUTPUT_7: ${{ steps.existing_release.outputs.release_published_at }}
|
||||
WORKFLOW_OUTPUT_8: ${{ steps.existing_release.outputs.release_activation_committed }}
|
||||
WORKFLOW_OUTPUT_10: ${{ steps.existing_release.outputs.release_target_commitish }}
|
||||
WORKFLOW_OUTPUT_9: ${{ needs.prepare.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
|
@ -1045,6 +1048,7 @@ jobs:
|
|||
IS_DRAFT="${WORKFLOW_OUTPUT_6}"
|
||||
PUBLISHED_AT="${WORKFLOW_OUTPUT_7}"
|
||||
ACTIVATION_COMMITTED="${WORKFLOW_OUTPUT_8}"
|
||||
PREVIOUS_TARGET_COMMITISH="${WORKFLOW_OUTPUT_10}"
|
||||
RELEASE_PAYLOAD=$(mktemp)
|
||||
RELEASE_JSON_FILE=$(mktemp)
|
||||
ACTUAL_BODY_FILE=$(mktemp)
|
||||
|
|
@ -1068,6 +1072,13 @@ jobs:
|
|||
if [ -n "$RELEASE_ID" ]; then
|
||||
if [ "$IS_DRAFT" = "true" ] && [ "$ACTIVATION_COMMITTED" != "true" ]; then
|
||||
if [ -n "$PUBLISHED_AT" ]; then
|
||||
# Deleting a public tag does not make its version reusable.
|
||||
# Only an exact retained commit proves same-identity recovery;
|
||||
# a missing target or moving branch name is not such proof.
|
||||
if [ "$PREVIOUS_TARGET_COMMITISH" != "$HEAD_SHA" ]; then
|
||||
echo "::error::Previously published release ${TAG} identifies ${PREVIOUS_TARGET_COMMITISH:-unknown}, not HEAD (${HEAD_SHA}); use a new version."
|
||||
exit 1
|
||||
fi
|
||||
echo "Resuming quarantined draft release for ${TAG}; GitHub retained historical published_at=${PUBLISHED_AT}."
|
||||
fi
|
||||
echo "Updating existing draft release for ${TAG}"
|
||||
|
|
|
|||
|
|
@ -5452,3 +5452,20 @@ must not alter permissions, environments, source identity, rollback, signing
|
|||
backend selection or release qualification. Local contract success does not
|
||||
establish hosted action execution, signature acceptance, image publication or
|
||||
production deployment.
|
||||
|
||||
### Quarantined release identity after tag deletion
|
||||
|
||||
Draft preparation retains the existing release's target_commitish. A historical
|
||||
published_at is evidence that the version was exposed even if its Git tag is
|
||||
now absent. Before PATCH, such a draft must retain an exact target equal to the
|
||||
admitted checkout SHA; changed, absent and branch-name targets fail closed.
|
||||
Same-SHA quarantined recovery remains available unless the activation marker
|
||||
has committed the packet. Never-published private drafts remain replaceable.
|
||||
This guard complements, rather than replaces, PR2056's immutable public-tag
|
||||
check and qualification-first Git, Docker and Helm writers.
|
||||
|
||||
The executable release policy regression runs the actual absent-tag check and
|
||||
draft shell with recording fake APIs. It must reject changed/unknown/branch
|
||||
historical targets before any API mutation, admit same-identity recovery and
|
||||
private replacement, and preserve activated/published refusals. This is local
|
||||
workflow proof, not publication or installed acceptance.
|
||||
|
|
|
|||
|
|
@ -303,6 +303,63 @@ STAGED_GOVERNANCE_INPUT_ERRORS = (
|
|||
|
||||
class ReleasePromotionPolicyTest(unittest.TestCase):
|
||||
|
||||
def test_quarantined_draft_identity_before_patch(self):
|
||||
workflow = yaml.safe_load(read(".github/workflows/create-release.yml"))
|
||||
steps = workflow["jobs"]["create_release"]["steps"]
|
||||
create = next(step for step in steps if step.get("name") == "Create draft release")
|
||||
locate = next(step for step in steps if step.get("id") == "existing_release")
|
||||
self.assertIn(".target_commitish // empty", locate["run"])
|
||||
self.assertIn('write_github_output.py release_target_commitish "${RELEASE_TARGET_COMMITISH}"',
|
||||
locate["run"])
|
||||
self.assertEqual(create["env"]["WORKFLOW_OUTPUT_10"],
|
||||
"${{ steps.existing_release.outputs.release_target_commitish }}")
|
||||
check = next(step for step in steps
|
||||
if step.get("name") == "Check existing public tag without changing it")
|
||||
self.assertLess(steps.index(check), steps.index(create))
|
||||
script = (check["run"] + "\n" + create["run"]).replace(
|
||||
"${{ github.repository }}", "fixture/pulse")
|
||||
# Execute the actual draft shell with an absent-tag fake Git and a
|
||||
# recording API sentinel. No network or public writer is available.
|
||||
head = "a" * 40
|
||||
cases = [
|
||||
("different", "b" * 40, "2026-09-01T00:00:00Z", "true", "false", False),
|
||||
("unknown", "", "2026-09-01T00:00:00Z", "true", "false", False),
|
||||
("branch", "main", "2026-09-01T00:00:00Z", "true", "false", False),
|
||||
("same", head, "2026-09-01T00:00:00Z", "true", "false", True),
|
||||
("private", "b" * 40, "", "true", "false", True),
|
||||
("activated", head, "2026-09-01T00:00:00Z", "true", "true", False),
|
||||
("published", head, "2026-09-01T00:00:00Z", "false", "false", False),
|
||||
]
|
||||
for label, target, published, draft, activated, allowed in cases:
|
||||
with self.subTest(label=label), tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
(root / "notes").write_text("Fixture notes")
|
||||
(root / "git").write_text(
|
||||
"#!/bin/bash\n"
|
||||
'if [ "$*" = "rev-parse HEAD" ]; then echo ' + head + '; exit 0; fi\n'
|
||||
'if [ "$1" = "ls-remote" ]; then exit 0; fi\nexit 98\n'
|
||||
)
|
||||
(root / "gh").write_text(
|
||||
"#!/bin/bash\nprintf '%s\\n' \"$*\" >> \"$CALLS\"\nexit 73\n"
|
||||
)
|
||||
for name in ("git", "gh"):
|
||||
(root / name).chmod(0o755)
|
||||
env = dict(os.environ, PATH=f"{root}:/usr/bin:/bin", TMPDIR=tmp,
|
||||
CALLS=str(root / "calls"), TAG="v6.4.4-beta.4")
|
||||
values = ["v6.4.4-beta.4", str(root / "notes"), "true", "123",
|
||||
"https://example.invalid/release", draft, published, activated,
|
||||
"6.4.4-beta.4", target]
|
||||
env.update({f"WORKFLOW_OUTPUT_{i}": v for i, v in enumerate(values, 1)})
|
||||
result = subprocess.run(["bash", "-euo", "pipefail", "-c", script],
|
||||
cwd=root, env=env, text=True, capture_output=True)
|
||||
calls = (root / "calls").read_text() if (root / "calls").exists() else ""
|
||||
if allowed:
|
||||
self.assertEqual(result.returncode, 73, result.stdout + result.stderr)
|
||||
self.assertIn("-X PATCH", calls)
|
||||
else:
|
||||
self.assertEqual(result.returncode, 1, result.stdout + result.stderr)
|
||||
self.assertEqual(calls, "", "refusal must precede API mutation")
|
||||
|
||||
def test_reviewed_action_manifests_cover_all_release_consumers(self) -> None:
|
||||
# Snapshot is derived from each immutable upstream action.yml, not from
|
||||
# our consumers: unknown inputs therefore fail rather than being blessed.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue