Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions .github/workflows/platform-testnet-sync-status.yml
Original file line number Diff line number Diff line change
@@ -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
Comment on lines +7 to +36

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: workflow_dispatch lets any repo writer forge a sync status

The receiver exposes both repository_dispatch (driven by the operator-only worker credential) and workflow_dispatch with free-form status and target_sha inputs. The job carries statuses: write, so anyone with repo write access can manually publish 'Sync Passed' against any existing SHA without the worker ever running. If maintainers, branch protection, or merge automation treat the Latest public Core testnet sync context as evidence the testnet sync actually ran, this becomes a trust-laundering primitive that bypasses the operator-credential boundary the rest of the pipeline carefully maintains. Either drop the workflow_dispatch trigger, or gate it behind an environment with required reviewers so the manual path requires an operator approval distinct from generic repo write.

source: ['codex']

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this update — workflow_dispatch lets any repo writer forge a sync status no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.


permissions:
contents: read
statuses: write
Comment on lines +7 to +40

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: workflow_dispatch path can forge 'Platform testnet sync' commit statuses

The job is granted statuses: write and accepts workflow_dispatch input directly for status, target_sha, target_url, core_version, platform_sha, and completed_at. The only checks performed are the enum match on status, a 40-hex regex on the SHA, repos.getCommit (which only proves the SHA exists in the repo), and an origin restriction on target_url. None of those prove the external sync worker actually ran against that commit. Any account with workflow-dispatch privilege on this repo (broader than the operator credential the design intends) can therefore publish state=success, context='Platform testnet sync' on an arbitrary commit. If branch protection, dashboards, or release automation treat this context as authoritative — and docs/PLATFORM_TESTNET_SYNC.md presents it that way — this is a status-forgery path that bypasses the worker boundary. Either drop the workflow_dispatch trigger (rely on repository_dispatch from the operator-held credential only), or gate the manual path behind a protected environment with a required reviewer and a restricted actor allowlist. Note: per the file-handling constraint, suggestion field is null; do not interpret that as agreement to leave the trigger in place.

source: ['codex']


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 || '<empty>'}`);
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';
Comment thread
coderabbitai[bot] marked this conversation as resolved.
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);
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<p align="center">
<a href="https://github.com/dashpay/platform/actions/workflows/tests.yml"><img alt="CI" src="https://github.com/dashpay/platform/actions/workflows/tests.yml/badge.svg"></a>
<a href="https://github.com/dashpay/platform/blob/v3.1-dev/NIGHTLY_STATUS.md"><img alt="Nightly Tests" src="https://img.shields.io/github/actions/workflow/status/dashpay/platform/tests.yml?event=schedule&label=Nightly%20Tests" title="Nightly test status"></a>
<a href="https://github.com/dashpay/platform/blob/v3.1-dev/docs/PLATFORM_TESTNET_SYNC.md"><img alt="Platform Sync" src="https://img.shields.io/github/actions/workflow/status/dashpay/platform/platform-testnet-sync-status.yml?event=repository_dispatch&label=Platform%20Sync" title="Platform testnet sync status"></a>
<a href="https://codecov.io/gh/dashpay/platform"><img alt="codecov" src="https://codecov.io/gh/dashpay/platform/branch/v3.1-dev/graph/badge.svg"></a>
<a href="https://github.com/dashpay/platform/graphs/commit-activity"><img alt="commit activity" src="https://img.shields.io/github/commit-activity/m/dashpay/platform"></a>
<a href="https://github.com/dashpay/platform/commits"><img alt="last commit" src="https://img.shields.io/github/last-commit/dashpay/platform"></a>
Expand Down
66 changes: 66 additions & 0 deletions docs/PLATFORM_TESTNET_SYNC.md
Original file line number Diff line number Diff line change
@@ -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.
Loading