ci: add native ARM64 build and publishing - #10
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The newly added workflow tests rely on PyYAML’s on:→True parsing quirk, making them brittle across YAML parser behavior and potentially causing false positives/negatives.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR updates CI to enforce a clearer trust boundary: pull requests are validated only on GitHub-hosted runners, while self-hosted runners are reserved for trusted main runs, and adds a native ARM64 (Spark/GPU) build/test/publish pipeline.
Changes:
- Add a dedicated
pull_requestvalidation workflow that runs only onubuntu-24.04and checks Docker/workflow contracts. - Remove
pull_requesttriggers from self-hosted workflows and constrain existing self-hosted jobs to[self-hosted, Linux, X64]. - Add a main-only native ARM64 workflow that validates gates (GPU/CUDA/imports/Remesher checks) before publishing ARM64 image tags.
File summaries
| File | Description |
|---|---|
| tests/test_arm64_workflow.py | New tests enforcing runner-label and trigger trust-boundary rules for workflows and ARM64 publication gates. |
| .github/workflows/validate-pull-request.yml | New GitHub-hosted PR validation workflow to avoid running PR code on self-hosted runners. |
| .github/workflows/health-check.yml | Constrains the self-hosted health-check job to explicit Linux/X64 runner labels. |
| .github/workflows/deploy.yml | Removes PR trigger and constrains self-hosted deploy jobs to Linux/X64 runner labels. |
| .github/workflows/deploy-nightly.yml | Constrains nightly self-hosted jobs to Linux/X64 runner labels. |
| .github/workflows/deploy-arm64.yml | New native ARM64 build/test/publish workflow gated to trusted main runs on labeled Spark/GPU ARM64 runners. |
| .github/actionlint.yaml | Adds actionlint config declaring additional self-hosted labels (spark, gpu). |
Review details
Suppressed comments (2)
tests/test_arm64_workflow.py:31
- This test currently uses
workflow.get(True, {})/validation[True]/workflow[True]to read theon:section, which will fail (or silently skip) if the YAML loader returns an explicit"on"key instead ofTrue. Use the helper_on_section()so the assertions remain stable across YAML parser behavior.
def test_pull_requests_never_run_on_self_hosted_runners():
for path in [*WORKFLOWS.glob("*.yml"), *WORKFLOWS.glob("*.yaml")]:
workflow = yaml.safe_load(path.read_text())
if "pull_request" not in workflow.get(True, {}):
continue
tests/test_arm64_workflow.py:59
- These assertions also read the
on:section viaworkflow[True], which depends on PyYAML parsingonas a boolean. Prefer_on_section(workflow)and assert against that mapping instead.
assert workflow["name"] == "Build and Publish Native ARM64 Image"
assert "pull_request" not in workflow[True]
assert "push" in workflow[True]
assert workflow[True]["push"]["branches"] == ["main"]
- Files reviewed: 7/7 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| def _runner_labels(runs_on): | ||
| return [runs_on] if isinstance(runs_on, str) else list(runs_on) | ||
|
|
There was a problem hiding this comment.
🔵 Needs a closer look
It introduces and modifies high-impact CI/CD publishing workflows (including self-hosted ARM64 + Docker Hub publication), which warrants final human validation of the runner and registry behavior.
Review details
Suppressed comments (4)
Previously missed (2) — in code that hasn't changed since the last review.
.github/workflows/deploy.yml:88
- This self-hosted job still uses an unpinned
actions/checkout@v4. On persistent self-hosted runners, pinning actions to a full commit SHA reduces supply-chain risk and aligns with the new pinned workflows in this PR.
This issue also appears on line 158 of the same file.
runs-on: [self-hosted, Linux, X64]
timeout-minutes: 300
steps:
- name: Checkout repository
uses: actions/checkout@v4
.github/workflows/deploy-nightly.yml:25
- This self-hosted job still uses an unpinned
actions/checkout@v4. On persistent self-hosted runners, pinning actions to a full commit SHA reduces supply-chain risk and matches the pinning approach used in the new workflows added by this PR.
This issue also appears on line 61 of the same file.
runs-on: [self-hosted, Linux, X64]
timeout-minutes: 120
steps:
- name: Checkout repository
uses: actions/checkout@v4
.github/workflows/deploy.yml:169
- This self-hosted publish job uses
docker/login-action@v3as a floating tag. For the same trust-boundary reasons asactions/checkout, consider pinning this action to a commit SHA to reduce exposure to upstream action changes.
runs-on: [self-hosted, Linux, X64]
timeout-minutes: 60
strategy:
matrix:
cuda:
- tag_suffix: cuda12.8
latest: false
- tag_suffix: cuda13.0
latest: true
steps:
- name: Log in to Docker Hub
uses: docker/login-action@v3
.github/workflows/deploy-nightly.yml:61
- This self-hosted publish job uses
docker/login-action@v3as a floating tag. Pinning third-party actions to commit SHAs helps protect persistent self-hosted runners from supply-chain updates.
runs-on: [self-hosted, Linux, X64]
- Files reviewed: 7/7 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🟢 Approval recommended
The workflow triggers, runner constraints, and action pinning align with the stated trust boundary and are enforced by added contract tests.
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 0 new
- Review effort level: Lite
Summary
pull_requesttriggers from every workflow that can target persistent self-hosted runnersarm64,arm64-<commit>, and<ComfyUI-version>-arm64tags without changinglatestTrust boundary
ubuntu-24.04pull_requesttriggerrefs/heads/main, including manual dispatchactions/checkoutis pinned in the new workflows[self-hosted, Linux, X64][self-hosted, Linux, ARM64, spark, gpu]Native gates
aarch64bpyreports 5.2.1/object_infoPublication and cleanup
linux/arm64arm64image ID is removed only after displacement and only when it has no remaining tagsarm64cache tag and any independently tagged image are retainedLocal verification
4 passed--check: pass, zero warningsgit diff --check: passarm64cache retained