Skip to content

ci: retire safe-to-test gate, make skipped Unity checks visible - #1308

Merged
Scriptwonder merged 1 commit into
CoplayDev:betafrom
Scriptwonder:fix/ci-fork-pr-signal
Aug 2, 2026
Merged

ci: retire safe-to-test gate, make skipped Unity checks visible#1308
Scriptwonder merged 1 commit into
CoplayDev:betafrom
Scriptwonder:fix/ci-fork-pr-signal

Conversation

@Scriptwonder

@Scriptwonder Scriptwonder commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Problem

Fork PRs touching MCPForUnity/** get green Unity checks that verified nothing.

Observed on #1250 (a one-file C# change). Three green checks totalling 22 seconds, none of which compiled a line of the changed code:

3. Detect Unity license secrets -> success
4. Skip Unity tests (missing license secrets) -> success
6. Run domain reload tests -> skipped
7. Run tests -> skipped
8. Check test results -> skipped

Mechanism: GitHub withholds repository secrets from pull_request runs originating in a fork, so Detect Unity license secrets writes unity_ok=false and every real step is gated off. Step-level if: produces a step conclusion of skipped, which contributes nothing to the job conclusion — the job reports success having done nothing. There is no path to failure, because the only step that can exit 1 (Check test results) is itself gated.

e2e-bridge is worse: even the checkout is gated, so it concludes green in ~4s having run exactly one step.

A reviewer reading gh pr checks sees green and reasonably assumes the code compiled. It did not.

The safe-to-test escape hatch is broken

unity-tests.yml had a pull_request_target: types: [labeled] trigger so a maintainer could apply safe-to-test and get a real run. Applying it now fails:

Refusing to check out fork pull request code from a 'pull_request_target' workflow. […] To opt in, review the risks at https://gh.io/securely-using-pull_request_target and set 'allow-unsafe-pr-checkout: true' on the actions/checkout step.

Nothing in this repo changed. actions/checkout@v4 is a floating tag that has since rolled forward to v4.4.0, which added this guardrail. Both checkouts pass github.event.pull_request.head.sha, so both are blocked.

What this PR does

1. Makes the skip unmissable. Both workflows now emit ::warning:: plus a $GITHUB_STEP_SUMMARY block stating plainly that no C# was compiled and no test ran, and that the green check is not a pass. unity-tests previously logged only a plain echo; e2e-bridge had a warning but nothing on the run page.

2. Retires safe-to-test rather than repairing it. Repairing means allow-unsafe-pr-checkout: true, and the warning is accurate for this workflow specifically: after checkout, the job runs game-ci/unity-test-runner, which executes arbitrary fork-authored C# — any [InitializeOnLoad] editor script is enough — in a process with UNITY_LICENSE, UNITY_EMAIL, UNITY_PASSWORD and UNITY_SERIAL in its environment. persist-credentials: false and permissions: contents: read already limit GITHUB_TOKEN exposure, so the prize for an attacker is the Unity credentials, and a label was the only thing in the way. The gate was never used in practice.

Removing the trigger makes both job-level if: gates dead code — each began with github.event_name != 'pull_request_target' ||, unconditionally true once the trigger is gone — so they go too. Net +39 / −50.

To test a fork PR going forward: review the diff, then push its branch into this repo. The existing push trigger (branches-ignore: [beta, main]) runs the full licensed suite in a genuinely trusted context, against a repo-owned ref, with no opt-in flag.

Known tradeoff

The full-matrix label used to re-trigger a run when applied to an open PR — that was types: [labeled] doing the work. It now takes effect on the next push instead. The label logic itself is unchanged and still works. If on-demand re-runs are wanted back, adding labeled to the pull_request trigger's types gets it safely (no secrets for forks, secrets for same-repo) and is a one-line follow-up.

Deliberately not included

  • No SHA pinning. There is no .github/dependabot.yml, so a lone pinned SHA would go stale with no update path while every other action stayed floating. v4 resolves to v4.4.0 today, so pinning to it changes nothing functionally.
  • No license-free compile job. That is the actual fix for "fork PRs get no signal", and it deserves its own PR. Sketch: extract UnityEngine.*/UnityEditor.* DLLs at CI time from the public unityci/editor image (the pull needs no Unity credentials), cache the ~100 MB subset populated from a beta push, compile Runtime then Editor with csc. Fork PRs can read base-branch caches but not write them. Cost is real — the Editor asmdef resolves to 219 references and 110 DefineConstants, and that define list must be captured from a licensed run and re-captured when defaultVersion bumps.

This PR does not give fork PRs real signal. It stops the absence of signal from looking like success.

Verification

Both workflows parse (yaml.safe_load). unity-tests.yml triggers are now workflow_dispatch, workflow_call, push, pull_request; jobs matrix and testAllModes are unchanged apart from the removed dead gates. The only surviving mention of pull_request_target is the comment explaining why there deliberately isn't one.

Since this PR modifies .github/workflows/unity-tests.yml, it matches that workflow's own paths filter — so its checks should exercise the new skip messaging directly.

Summary by CodeRabbit

  • New Features

    • Added clear workflow warnings and summaries when Unity credentials are unavailable or tests are skipped.
    • Fork pull requests now run safely without secrets and explicitly report skipped Unity tests.
    • Full test-matrix selection is supported for labeled pull requests.
  • Documentation

    • Improved workflow messages to clarify that skipped checks do not validate the E2E bridge.

Fork PRs touching MCPForUnity/** get green Unity checks that verified
nothing. GitHub withholds secrets from pull_request runs originating in
a fork, so the detect step writes unity_ok=false and every real step is
gated off. Step-level `if:` produces step-conclusion `skipped`, which
contributes nothing to the job conclusion, so the job reports success
having compiled and tested nothing.

Make the skip unmissable: both workflows now emit ::warning:: and a
$GITHUB_STEP_SUMMARY block stating the check is not a pass.

Retire the safe-to-test label gate. It was the intended escape hatch but
never worked in practice -- actions/checkout's floating v4 tag has since
rolled forward to v4.4.0, which refuses to check out fork code under
pull_request_target without allow-unsafe-pr-checkout: true. Repairing it
would mean running fork-authored C# through game-ci/unity-test-runner
with UNITY_* secrets in scope, which is the classic pwn-request shape.
Removing the trigger makes both job-level `if:` gates dead code (each
began with `github.event_name != 'pull_request_target' ||`), so they go
too. To test a fork PR, review the diff and push its branch into this
repo; the push trigger runs the full suite in a trusted context.

Known tradeoff: the full-matrix label now takes effect on the next push
rather than on application, since nothing re-triggers on `labeled`.

This does not give fork PRs real signal -- it stops the absence of
signal from looking like success. A license-free compile job is the
follow-up.
Copilot AI review requested due to automatic review settings August 2, 2026 16:23
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The workflows remove pull_request_target handling and label-based secret gates. Pull requests without Unity license secrets now skip Unity execution and report that the green check does not validate the tests or bridge.

Changes

Workflow safety and skip reporting

Layer / File(s) Summary
Pull-request trigger and execution gates
.github/workflows/unity-tests.yml
The Unity test workflow removes pull_request_target, updates full-matrix selection for labeled pull_request events, removes related job gates, and clarifies workflow-command escaping.
Missing-secret skip reporting
.github/workflows/e2e-bridge.yml, .github/workflows/unity-tests.yml
The workflows warn when Unity secrets are unavailable and write step summaries that identify the skipped execution and its non-validating green check.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: copilot, dsarno

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main CI changes: removing the safe-to-test gate and making skipped Unity checks visible.
Description check ✅ Passed The description clearly explains the problem, implementation, security rationale, tradeoffs, exclusions, and verification.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Unity-related GitHub Actions workflows to prevent fork PR runs (which lack Unity license secrets) from presenting “green” checks that can be misread as having compiled/tested code. It removes the broken safe-to-test/pull_request_target escape hatch and instead makes the “skipped due to missing secrets” outcome highly visible via warnings and run-page summaries.

Changes:

  • Remove the pull_request_target + safe-to-test gate from unity-tests.yml (and the now-dead job-level gating logic).
  • Add explicit ::warning:: output plus $GITHUB_STEP_SUMMARY blocks to clearly state when Unity tests/E2E smoke were skipped and did not compile/test/boot anything.
  • Adjust the full-matrix label logic comment/behavior expectations (label is read only at workflow trigger time; applying it requires a subsequent push).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
.github/workflows/unity-tests.yml Removes pull_request_target safe-to-test gate and adds prominent skip messaging so “green” doesn’t imply compiled/tested for fork PRs.
.github/workflows/e2e-bridge.yml Adds run-page step summary + warning when license secrets are absent so the no-op green check is clearly labeled as skipped.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/unity-tests.yml (1)

200-234: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Protect raw failure details from workflow-command injection.

esc_data() protects the annotation fields, but msg and stack are printed unescaped during raw XML failure output. A value containing a line starting with :: can still create unwanted workflow commands inside the group. Output a unique ::stop-commands:: token before printing these details, and reset command parsing after ::endgroup::.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/unity-tests.yml around lines 200 - 234, Update the
failure-detail loop around msg and stack to emit a unique ::stop-commands::
token before printing raw XML content, preventing lines beginning with :: from
being interpreted as workflow commands. After closing the group with
::endgroup::, emit the matching token to resume command parsing, while
preserving the existing annotation and full message/stack output.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/unity-tests.yml:
- Around line 200-234: Update the failure-detail loop around msg and stack to
emit a unique ::stop-commands:: token before printing raw XML content,
preventing lines beginning with :: from being interpreted as workflow commands.
After closing the group with ::endgroup::, emit the matching token to resume
command parsing, while preserving the existing annotation and full message/stack
output.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 121ba45f-5e7f-4351-bc90-d3f0d7cd71f6

📥 Commits

Reviewing files that changed from the base of the PR and between 32428e8 and 0b1f50d.

📒 Files selected for processing (2)
  • .github/workflows/e2e-bridge.yml
  • .github/workflows/unity-tests.yml

@Scriptwonder
Scriptwonder merged commit 25e5f7e into CoplayDev:beta Aug 2, 2026
4 checks passed
@Scriptwonder
Scriptwonder deleted the fix/ci-fork-pr-signal branch August 2, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants