diff --git a/.github/workflows/platform-testnet-sync-status.yml b/.github/workflows/platform-testnet-sync-status.yml new file mode 100644 index 00000000000..f7433268b45 --- /dev/null +++ b/.github/workflows/platform-testnet-sync-status.yml @@ -0,0 +1,135 @@ +name: "Platform testnet sync status" + +"on": + repository_dispatch: + types: + - platform-testnet-sync-completed + workflow_dispatch: + inputs: + status: + description: Final completed run status + required: true + type: choice + options: + - sync_passed + - build_failed + - sync_failed + target_sha: + description: Platform commit SHA to report against + required: false + type: string + target_url: + description: URL for run logs or status details + required: false + type: string + core_version: + description: Public Core version used by the run + required: false + type: string + platform_sha: + description: Platform commit SHA built and synced + required: false + type: string + completed_at: + description: Completion timestamp, preferably ISO 8601 UTC + required: false + type: string + +permissions: + contents: read + statuses: write + +jobs: + report: + name: Report latest completed sync status + runs-on: ubuntu-24.04 + steps: + - name: Publish commit status + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 + env: + CLIENT_PAYLOAD: ${{ toJson(github.event.client_payload) }} + with: + script: | + const dispatchPayload = JSON.parse(process.env.CLIENT_PAYLOAD || '{}'); + const payload = context.eventName === 'workflow_dispatch' + ? context.payload.inputs + : dispatchPayload; + + if (!payload || typeof payload !== 'object' || Array.isArray(payload)) { + core.setFailed('Missing repository_dispatch client_payload'); + return; + } + + const status = payload.status; + const labels = { + sync_passed: 'Sync Passed', + build_failed: 'Build Failed', + sync_failed: 'Sync Failed', + }; + + if (!Object.prototype.hasOwnProperty.call(labels, status)) { + core.setFailed(`Unsupported status: ${status || ''}`); + return; + } + + const targetSha = String(payload.target_sha || payload.platform_sha || '').trim(); + if (!/^[0-9a-f]{40}$/i.test(targetSha)) { + core.setFailed('target_sha or platform_sha must be an explicit 40-character commit SHA'); + return; + } + + await github.rest.repos.getCommit({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: targetSha, + }); + + let targetUrl; + if (payload.target_url) { + let parsedUrl; + try { + parsedUrl = new URL(payload.target_url); + } catch (error) { + core.setFailed(`target_url must be a valid URL: ${error.message}`); + return; + } + + if (parsedUrl.origin !== 'https://github.com') { + core.setFailed('target_url must use the https://github.com origin'); + return; + } + targetUrl = parsedUrl.toString(); + } + + const state = status === 'sync_passed' ? 'success' : 'failure'; + const label = labels[status]; + const details = [ + payload.core_version, + payload.platform_sha ? payload.platform_sha.slice(0, 12) : null, + payload.completed_at, + ].filter(Boolean).join(' '); + const description = `${label}${details ? ` - ${details}` : ''}`.slice(0, 140); + + await github.rest.repos.createCommitStatus({ + owner: context.repo.owner, + repo: context.repo.repo, + sha: targetSha, + state, + context: 'Platform testnet sync', + description, + target_url: targetUrl || undefined, + }); + + await core.summary + .addHeading('Platform testnet sync') + .addRaw(`Status: ${label}\n\n`) + .addRaw(`Target SHA: ${targetSha}\n\n`) + .addRaw(`Core version: ${payload.core_version || 'not provided'}\n\n`) + .addRaw(`Platform SHA: ${payload.platform_sha || targetSha}\n\n`) + .addRaw(`Completed at: ${payload.completed_at || 'not provided'}\n\n`) + .addRaw(`Details: ${targetUrl || 'not provided'}\n`) + .write(); + + if (status !== 'sync_passed') { + core.setFailed(label); + } diff --git a/README.md b/README.md index 0335eceed4f..c644db833d7 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@

CI Nightly Tests + Platform Sync codecov commit activity last commit diff --git a/docs/PLATFORM_TESTNET_SYNC.md b/docs/PLATFORM_TESTNET_SYNC.md new file mode 100644 index 00000000000..117f3b622bf --- /dev/null +++ b/docs/PLATFORM_TESTNET_SYNC.md @@ -0,0 +1,66 @@ +# Platform Testnet Sync + +This document defines the repo-side reporting contract for Platform sync against the latest public Dash Core release on testnet. + +The Platform sync worker and server infrastructure live outside this repository. This repository only owns the public status surface: + +- the `Platform Sync` README badge +- the `Platform testnet sync status` workflow +- the `Platform testnet sync` commit status context + +## Visible Status + +The visible status is intentionally the last completed run only. A currently running build or sync must not replace the useful completed result with a running state. + +The external worker reports one final completed status for the tested Platform commit: + +- Context: `Platform testnet sync` +- Success state: + - `Sync Passed` +- Failure states: + - `Build Failed` + - `Sync Failed` + +Detailed build, baseline, and sync logs belong behind the status `target_url`, not in the status description. + +## Reporting Flow + +When a run completes, the external worker sends a `repository_dispatch` event to `dashpay/platform`: + +```json +{ + "event_type": "platform-testnet-sync-completed", + "client_payload": { + "status": "sync_passed", + "target_sha": "0000000000000000000000000000000000000000", + "target_url": "https://github.com/dashpay/platform/actions/runs/0000000000", + "core_version": "vX.Y.Z", + "platform_sha": "0000000000000000000000000000000000000000", + "completed_at": "2026-06-24T05:30:00Z" + } +} +``` + +Allowed `status` values: + +- `sync_passed` +- `build_failed` +- `sync_failed` + +The workflow validates the target commit SHA, writes the `Platform testnet sync` commit status, and fails the workflow run for `build_failed` and `sync_failed` so the README badge reflects the final outcome. + +Manual status testing is available through the `Platform testnet sync status` workflow's `workflow_dispatch` trigger with the same fields. + +## Expectations For The External Worker + +The worker should: + +- maintain or consume a synced latest-public-Core testnet baseline +- build Platform for the target `dashpay/platform` commit +- run Platform sync against that baseline +- report only the final completed result to this repository +- keep detailed logs and diagnostics outside this repository, linked through `target_url` + +The dispatch credential should be held only by the external worker/operator account. The status workflow requires an explicit 40-character commit SHA that exists in `dashpay/platform`, and workflow-provided `target_url` values are limited to the `https://github.com` origin. + +The GitHub status description stays short so the repo panel remains readable.