mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-19 16:27:37 +00:00
Fix release asset validation workflow gates
This commit is contained in:
parent
c8e24f06d7
commit
011d288cb4
6 changed files with 60 additions and 6 deletions
18
.github/workflows/create-release.yml
vendored
18
.github/workflows/create-release.yml
vendored
|
|
@ -773,6 +773,21 @@ jobs:
|
|||
RELEASE_URL=$(echo "$RELEASE_JSON" | jq -r '.html_url')
|
||||
fi
|
||||
|
||||
RELEASE_JSON=$(gh api "repos/${{ github.repository }}/releases/${RELEASE_ID}")
|
||||
ACTUAL_RELEASE_TAG=$(echo "$RELEASE_JSON" | jq -r '.tag_name // empty')
|
||||
ACTUAL_TARGET_COMMITISH=$(echo "$RELEASE_JSON" | jq -r '.target_commitish // empty')
|
||||
RELEASE_URL=$(echo "$RELEASE_JSON" | jq -r '.html_url')
|
||||
|
||||
if [ "$ACTUAL_RELEASE_TAG" != "$TAG" ]; then
|
||||
echo "::error::Draft release ${RELEASE_ID} is bound to tag ${ACTUAL_RELEASE_TAG}, expected ${TAG}."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$ACTUAL_TARGET_COMMITISH" != "$HEAD_SHA" ]; then
|
||||
echo "::error::Draft release ${RELEASE_ID} target_commitish is ${ACTUAL_TARGET_COMMITISH}, expected ${HEAD_SHA}."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f "$NOTES_FILE"
|
||||
|
||||
echo "release_url=${RELEASE_URL}" >> $GITHUB_OUTPUT
|
||||
|
|
@ -939,10 +954,11 @@ jobs:
|
|||
needs:
|
||||
- prepare
|
||||
- create_release
|
||||
if: ${{ needs.prepare.outputs.historical_asset_backfill_only != 'true' }}
|
||||
if: ${{ always() && needs.prepare.result == 'success' && needs.create_release.result == 'success' && needs.prepare.outputs.historical_asset_backfill_only != 'true' }}
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
statuses: write
|
||||
uses: ./.github/workflows/validate-release-assets.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ jobs:
|
|||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
statuses: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
|
@ -242,7 +243,7 @@ jobs:
|
|||
- name: Set commit status - Success
|
||||
if: steps.context.outputs.should_run == 'true' && steps.validate.outputs.validation_passed == 'true'
|
||||
run: |
|
||||
curl -X POST \
|
||||
curl --fail-with-body --silent --show-error -X POST \
|
||||
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/statuses/${{ steps.context.outputs.target_commitish }}" \
|
||||
|
|
@ -313,7 +314,7 @@ jobs:
|
|||
- name: Set commit status - Failure
|
||||
if: steps.context.outputs.should_run == 'true' && (failure() || steps.validate.outputs.validation_passed == 'false')
|
||||
run: |
|
||||
curl -X POST \
|
||||
curl --fail-with-body --silent --show-error -X POST \
|
||||
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/statuses/${{ steps.context.outputs.target_commitish }}" \
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ server-side update execution surfaces.
|
|||
13. `.github/workflows/publish-helm-chart.yml`
|
||||
14. `.github/workflows/release-dry-run.yml`
|
||||
15. `.github/workflows/update-demo-server.yml`
|
||||
16. `.github/workflows/validate-release-assets.yml`
|
||||
16. `.github/ISSUE_TEMPLATE/v6_rc_feedback.yml`
|
||||
17. `docs/RELEASE_NOTES.md`
|
||||
18. `docs/releases/`
|
||||
|
|
@ -113,7 +114,7 @@ server-side update execution surfaces.
|
|||
## Extension Points
|
||||
|
||||
1. Add or change deployment-type detection, update planning, or apply behavior through `internal/updates/`
|
||||
2. Add or change release-build metadata injection, Docker build-context allowlists, release artifact assembly, governed promotion metadata resolution, the canonical version file, operator-facing release packet content, prerelease feedback intake wording, historical published-release integrity backfill, download endpoint checksum/signature header proof, or the canonical in-repo v6 upgrade guide through `scripts/build-release.sh`, `scripts/release_asset_common.sh`, `scripts/backfill-release-assets.sh`, `scripts/release_ldflags.sh`, `scripts/check-workflow-dispatch-inputs.py`, `scripts/release_control/render_release_body.py`, `scripts/release_control/resolve_release_promotion.py`, `scripts/release_control/record_rc_to_ga_rehearsal.py`, `scripts/release_control/internal/record_rc_to_ga_rehearsal.py`, `scripts/release_control/release_promotion_policy_support.py`, `.dockerignore`, `Dockerfile`, `.github/ISSUE_TEMPLATE/v6_rc_feedback.yml`, `docs/RELEASE_NOTES.md`, `docs/releases/`, `docs/UPGRADE_v6.md`, `docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md`, `docs/release-control/v6/internal/PRE_RELEASE_CHECKLIST.md`, `docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md`, `scripts/validate-release.sh`, `scripts/validate-published-release.sh`, the operator dispatch helpers `scripts/trigger-release.sh` and `scripts/trigger-release-dry-run.sh`, and the governed release workflows `.github/workflows/backfill-release-assets.yml`, `.github/workflows/create-release.yml`, `.github/workflows/deploy-demo-server.yml`, `.github/workflows/helm-pages.yml`, `.github/workflows/publish-docker.yml`, `.github/workflows/publish-helm-chart.yml`, `.github/workflows/promote-floating-tags.yml`, `.github/workflows/release-dry-run.yml`, and `.github/workflows/update-demo-server.yml`
|
||||
2. Add or change release-build metadata injection, Docker build-context allowlists, release artifact assembly, governed promotion metadata resolution, the canonical version file, operator-facing release packet content, prerelease feedback intake wording, historical published-release integrity backfill, release asset validation status publication, download endpoint checksum/signature header proof, or the canonical in-repo v6 upgrade guide through `scripts/build-release.sh`, `scripts/release_asset_common.sh`, `scripts/backfill-release-assets.sh`, `scripts/release_ldflags.sh`, `scripts/check-workflow-dispatch-inputs.py`, `scripts/release_control/render_release_body.py`, `scripts/release_control/resolve_release_promotion.py`, `scripts/release_control/record_rc_to_ga_rehearsal.py`, `scripts/release_control/internal/record_rc_to_ga_rehearsal.py`, `scripts/release_control/release_promotion_policy_support.py`, `.dockerignore`, `Dockerfile`, `.github/ISSUE_TEMPLATE/v6_rc_feedback.yml`, `docs/RELEASE_NOTES.md`, `docs/releases/`, `docs/UPGRADE_v6.md`, `docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md`, `docs/release-control/v6/internal/PRE_RELEASE_CHECKLIST.md`, `docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md`, `scripts/validate-release.sh`, `scripts/validate-published-release.sh`, the operator dispatch helpers `scripts/trigger-release.sh` and `scripts/trigger-release-dry-run.sh`, and the governed release workflows `.github/workflows/backfill-release-assets.yml`, `.github/workflows/create-release.yml`, `.github/workflows/deploy-demo-server.yml`, `.github/workflows/helm-pages.yml`, `.github/workflows/publish-docker.yml`, `.github/workflows/publish-helm-chart.yml`, `.github/workflows/promote-floating-tags.yml`, `.github/workflows/release-dry-run.yml`, `.github/workflows/update-demo-server.yml`, and `.github/workflows/validate-release-assets.yml`
|
||||
3. Add or change shell installer, Docker bootstrap installer, Windows installer, container-agent installer, repo-root compose defaults, or auto-update script behavior through `scripts/install.sh`, `scripts/install-docker.sh`, `scripts/install.ps1`, `scripts/install-container-agent.sh`, `docker-compose.yml`, and `scripts/pulse-auto-update.sh`
|
||||
4. Add or change server update transport through `internal/api/updates.go` and `frontend-modern/src/api/updates.ts`
|
||||
5. Add or change local dev-runtime orchestration, managed ownership, browser-runtime proof wiring, frontend/backend coherence diagnostics, canonical developer entry wrappers, dependency manifest floors, frontend build chunking, or dev-runtime helper control surfaces through `scripts/hot-dev.sh`, `scripts/hot-dev-bg.sh`, `scripts/dev-deploy-agent.sh`, `Makefile`, `package.json`, `package-lock.json`, `frontend-modern/package.json`, `frontend-modern/package-lock.json`, `frontend-modern/vite.config.ts`, `go.mod`, `go.sum`, `scripts/dev-check.sh`, `scripts/toggle-mock.sh`, `scripts/clean-mock-alerts.sh`, `scripts/dev-launchd-setup.sh`, `scripts/dev-launchd-wrapper.sh`, `scripts/run_demo_public_browser_smoke.sh`, `scripts/demo_public_browser_smoke.cjs`, `scripts/com.pulse.hot-dev.plist.template`, `tests/integration/scripts/managed-dev-runtime.mjs`, `tests/integration/playwright.config.ts`, `tests/integration/tests/helpers.ts`, `tests/integration/tests/runtime-defaults.ts`, `tests/integration/README.md`, and `tests/integration/QUICK_START.md`
|
||||
|
|
|
|||
|
|
@ -2655,6 +2655,7 @@
|
|||
".github/workflows/publish-helm-chart.yml",
|
||||
".github/workflows/release-dry-run.yml",
|
||||
".github/workflows/update-demo-server.yml",
|
||||
".github/workflows/validate-release-assets.yml",
|
||||
"cmd/pulse-control-plane/main.go",
|
||||
"docker-compose.yml",
|
||||
"Dockerfile",
|
||||
|
|
@ -2784,6 +2785,7 @@
|
|||
".github/workflows/publish-helm-chart.yml",
|
||||
".github/workflows/release-dry-run.yml",
|
||||
".github/workflows/update-demo-server.yml",
|
||||
".github/workflows/validate-release-assets.yml",
|
||||
"docs/release-control/v6/internal/PRE_RELEASE_CHECKLIST.md",
|
||||
"docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md",
|
||||
"docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md",
|
||||
|
|
|
|||
|
|
@ -100,8 +100,13 @@ func TestCreateReleaseUploadsPowerShellInstaller(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("read create-release.yml: %v", err)
|
||||
}
|
||||
validationContent, err := os.ReadFile(repoFile(".github", "workflows", "validate-release-assets.yml"))
|
||||
if err != nil {
|
||||
t.Fatalf("read validate-release-assets.yml: %v", err)
|
||||
}
|
||||
|
||||
workflow := string(content)
|
||||
validationWorkflow := string(validationContent)
|
||||
required := []string{
|
||||
`historical_asset_backfill_only:`,
|
||||
`description: 'Repair an already-published release packet in place without rebuilding binaries'`,
|
||||
|
|
@ -131,10 +136,15 @@ func TestCreateReleaseUploadsPowerShellInstaller(t *testing.T) {
|
|||
`git push origin "refs/tags/${TAG}" --force`,
|
||||
`-F target_commitish="${HEAD_SHA}"`,
|
||||
`historical_asset_backfill_only=${HISTORICAL_ASSET_BACKFILL_ONLY}`,
|
||||
`if: ${{ needs.prepare.outputs.historical_asset_backfill_only != 'true' }}`,
|
||||
`if: ${{ always() && needs.prepare.result == 'success' && needs.create_release.result == 'success' && needs.prepare.outputs.historical_asset_backfill_only != 'true' }}`,
|
||||
`if: ${{ needs.prepare.outputs.historical_asset_backfill_only == 'true' }}`,
|
||||
`permissions:`,
|
||||
`issues: write`,
|
||||
`statuses: write`,
|
||||
`ACTUAL_RELEASE_TAG=$(echo "$RELEASE_JSON" | jq -r '.tag_name // empty')`,
|
||||
`ACTUAL_TARGET_COMMITISH=$(echo "$RELEASE_JSON" | jq -r '.target_commitish // empty')`,
|
||||
`Draft release ${RELEASE_ID} is bound to tag ${ACTUAL_RELEASE_TAG}, expected ${TAG}.`,
|
||||
`Draft release ${RELEASE_ID} target_commitish is ${ACTUAL_TARGET_COMMITISH}, expected ${HEAD_SHA}.`,
|
||||
`./scripts/backfill-release-assets.sh --tag "${{ needs.prepare.outputs.tag }}" --repo "${{ github.repository }}"`,
|
||||
`./scripts/validate-published-release.sh "${{ needs.prepare.outputs.tag }}" "${{ github.repository }}"`,
|
||||
}
|
||||
|
|
@ -150,6 +160,17 @@ func TestCreateReleaseUploadsPowerShellInstaller(t *testing.T) {
|
|||
if strings.Contains(workflow, `provenance: false`) {
|
||||
t.Fatal("create-release.yml must not disable release-image provenance")
|
||||
}
|
||||
|
||||
validationRequired := []string{
|
||||
`statuses: write`,
|
||||
`curl --fail-with-body --silent --show-error -X POST`,
|
||||
`"context": "Release Asset Validation"`,
|
||||
}
|
||||
for _, needle := range validationRequired {
|
||||
if !strings.Contains(validationWorkflow, needle) {
|
||||
t.Fatalf("validate-release-assets.yml missing required status publication contract: %s", needle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackfillReleaseWorkflowRepairsPublishedAssetsWithoutRebuilds(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -327,6 +327,7 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
|||
|
||||
def test_release_workflow_enforces_rc_lineage_soak_and_v5_notice(self) -> None:
|
||||
content = read(".github/workflows/create-release.yml")
|
||||
validation_workflow = read(".github/workflows/validate-release-assets.yml")
|
||||
helper = read("scripts/trigger-release.sh")
|
||||
renderer = read("scripts/release_control/render_release_body.py")
|
||||
policy = read("docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md")
|
||||
|
|
@ -373,9 +374,21 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
|||
self.assertIn('Retargeting existing draft tag ${TAG}', content)
|
||||
self.assertIn('-F target_commitish="${HEAD_SHA}"', content)
|
||||
self.assertIn('historical_asset_backfill_only=${HISTORICAL_ASSET_BACKFILL_ONLY}', content)
|
||||
self.assertIn("if: ${{ needs.prepare.outputs.historical_asset_backfill_only != 'true' }}", content)
|
||||
self.assertIn(
|
||||
"if: ${{ always() && needs.prepare.result == 'success' && needs.create_release.result == 'success' && needs.prepare.outputs.historical_asset_backfill_only != 'true' }}",
|
||||
content,
|
||||
)
|
||||
self.assertIn("if: ${{ needs.prepare.outputs.historical_asset_backfill_only == 'true' }}", content)
|
||||
self.assertIn("issues: write", content)
|
||||
self.assertIn("statuses: write", content)
|
||||
self.assertIn("statuses: write", validation_workflow)
|
||||
self.assertIn("curl --fail-with-body --silent --show-error -X POST", validation_workflow)
|
||||
self.assertIn('"context": "Release Asset Validation"', validation_workflow)
|
||||
self.assertIn('ACTUAL_RELEASE_TAG=$(echo "$RELEASE_JSON" | jq -r \'.tag_name // empty\')', content)
|
||||
self.assertIn(
|
||||
'ACTUAL_TARGET_COMMITISH=$(echo "$RELEASE_JSON" | jq -r \'.target_commitish // empty\')',
|
||||
content,
|
||||
)
|
||||
self.assertIn('./scripts/backfill-release-assets.sh --tag "${{ needs.prepare.outputs.tag }}" --repo "${{ github.repository }}"', content)
|
||||
self.assertIn('./scripts/validate-published-release.sh "${{ needs.prepare.outputs.tag }}" "${{ github.repository }}"', content)
|
||||
self.assertIn("PULSE_UPDATE_SIGNING_KEY: ${{ secrets.PULSE_UPDATE_SIGNING_KEY }}", content)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue