Skip to content

Commit 544fc43

Browse files
authored
Merge pull request #11 from solutionforest/develop
Release v0.2.1: merge develop into main
2 parents b721d85 + 23bb836 commit 544fc43

105 files changed

Lines changed: 9089 additions & 562 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Bug report
2+
description: Report reproducible behavior that differs from the documentation or expected result.
3+
title: "bug: "
4+
labels:
5+
- bug
6+
body:
7+
- type: markdown
8+
attributes:
9+
value: |
10+
Thank you for reporting a bug. Do not include credentials, private keys, tokens, or other secrets. For a security vulnerability, use the private reporting path in docs/security.md instead.
11+
- type: textarea
12+
id: summary
13+
attributes:
14+
label: What happened?
15+
description: Describe the observed behavior and the expected result.
16+
validations:
17+
required: true
18+
- type: textarea
19+
id: reproduction
20+
attributes:
21+
label: Steps to reproduce
22+
description: Include the smallest safe configuration and commands needed to reproduce the issue.
23+
placeholder: |
24+
1. ...
25+
2. ...
26+
3. ...
27+
validations:
28+
required: true
29+
- type: textarea
30+
id: environment
31+
attributes:
32+
label: Environment
33+
description: Include EPAR version or commit, provider, host operating system, and Docker or WSL version when relevant.
34+
validations:
35+
required: true
36+
- type: textarea
37+
id: logs
38+
attributes:
39+
label: Sanitized logs
40+
description: Include relevant logs after removing secrets and private infrastructure details.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Feature request
2+
description: Suggest an improvement to EPAR.
3+
title: "feature: "
4+
labels:
5+
- enhancement
6+
body:
7+
- type: textarea
8+
id: problem
9+
attributes:
10+
label: What problem does this solve?
11+
description: Describe the workflow or limitation you are trying to address.
12+
validations:
13+
required: true
14+
- type: textarea
15+
id: proposal
16+
attributes:
17+
label: Proposed solution
18+
description: Explain the change you would like to see and any alternatives you considered.
19+
validations:
20+
required: true
21+
- type: textarea
22+
id: context
23+
attributes:
24+
label: Additional context
25+
description: Include relevant provider, operating-system, or GitHub Actions details.

‎.github/PULL_REQUEST_TEMPLATE.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## Summary
2+
3+
<!-- What problem does this pull request solve, and what changed? -->
4+
5+
## Validation
6+
7+
<!-- List the commands, workflow runs, or manual checks you performed. -->
8+
9+
## Checklist
10+
11+
- [ ] I kept credentials, private keys, tokens, and machine-specific configuration out of this pull request.
12+
- [ ] I added or updated tests where behavior changed.
13+
- [ ] I updated relevant documentation.
14+
- [ ] I read and followed the contributing guide and code of conduct.

‎.github/workflows/core-runner-verification.yml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ on:
99
branches:
1010
- develop
1111
- main
12+
workflow_dispatch:
1213

1314
permissions:
1415
contents: read
@@ -20,6 +21,7 @@ concurrency:
2021
jobs:
2122
controller:
2223
name: Core runner controller
24+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
2325
runs-on: ubuntu-latest
2426
environment: epar-live-ci
2527
# Leaves time for a cold image build and bounded cleanup around the
@@ -83,6 +85,7 @@ jobs:
8385
8486
canary-1:
8587
name: Core canary 1
88+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
8689
runs-on:
8790
group: epar-ci-canary
8891
labels: epar-core-${{ github.run_id }}-${{ github.run_attempt }}
@@ -128,6 +131,7 @@ jobs:
128131
canary-2:
129132
name: Core canary 2
130133
needs: canary-1
134+
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
131135
runs-on:
132136
group: epar-ci-canary
133137
labels: epar-core-${{ github.run_id }}-${{ github.run_attempt }}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
name: Hosted runner Docker architecture proof
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- develop
7+
- main
8+
paths:
9+
- .github/workflows/hosted-runner-docker-architecture.yml
10+
workflow_dispatch:
11+
12+
permissions:
13+
contents: read
14+
15+
concurrency:
16+
group: hosted-docker-architecture-${{ github.workflow }}-${{ github.ref }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
capability:
21+
name: Capability (${{ matrix.runner }})
22+
runs-on: ${{ matrix.runner }}
23+
timeout-minutes: 10
24+
strategy:
25+
fail-fast: false
26+
matrix:
27+
runner:
28+
- ubuntu-latest
29+
- ubuntu-24.04-arm
30+
- windows-latest
31+
- windows-11-arm
32+
- macos-latest
33+
- macos-15-intel
34+
35+
steps:
36+
- name: Record host and Docker capability
37+
shell: pwsh
38+
run: |
39+
$ErrorActionPreference = 'Continue'
40+
$summary = [System.Collections.Generic.List[string]]::new()
41+
$summary.Add("## $env:RUNNER_OS/$env:RUNNER_ARCH on ``${{ matrix.runner }}``")
42+
$summary.Add('')
43+
$summary.Add("- Runner OS: ``$env:RUNNER_OS``")
44+
$summary.Add("- Runner architecture: ``$env:RUNNER_ARCH``")
45+
46+
$dockerCommand = Get-Command docker -ErrorAction SilentlyContinue
47+
if (-not $dockerCommand) {
48+
$summary.Add('- Docker CLI: not installed')
49+
$summary.Add('- Linux container test: unavailable')
50+
} else {
51+
$summary.Add("- Docker CLI: ``$($dockerCommand.Source)``")
52+
$versionOutput = (& docker version 2>&1 | Out-String).Trim()
53+
$versionStatus = $LASTEXITCODE
54+
$summary.Add("- Docker daemon reachable: ``$($versionStatus -eq 0)``")
55+
56+
if ($versionStatus -eq 0) {
57+
$serverOS = (& docker info --format '{{.OSType}}' 2>&1 | Out-String).Trim()
58+
$serverArchitecture = (& docker info --format '{{.Architecture}}' 2>&1 | Out-String).Trim()
59+
$summary.Add("- Docker server: ``$serverOS/$serverArchitecture``")
60+
if ($serverOS -eq 'linux') {
61+
$summary.Add('- Linux container test: available')
62+
} else {
63+
$summary.Add('- Linux container test: unavailable because the reachable daemon is not a Linux daemon')
64+
}
65+
} else {
66+
$summary.Add('- Linux container test: unavailable because no Docker daemon is reachable')
67+
$summary.Add('')
68+
$summary.Add('<details><summary>docker version diagnostic</summary>')
69+
$summary.Add('')
70+
$summary.Add('```text')
71+
$summary.Add($versionOutput)
72+
$summary.Add('```')
73+
$summary.Add('</details>')
74+
}
75+
}
76+
77+
$summary | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Encoding utf8 -Append
78+
$summary | ForEach-Object { Write-Host $_ }
79+
80+
linux-cross-architecture:
81+
name: Linux ${{ matrix.native }} runs ${{ matrix.foreign }} with explicit QEMU
82+
runs-on: ${{ matrix.runner }}
83+
timeout-minutes: 15
84+
strategy:
85+
fail-fast: false
86+
matrix:
87+
include:
88+
- runner: ubuntu-latest
89+
native: amd64
90+
native_platform: linux/amd64
91+
native_output: x86_64
92+
foreign: arm64
93+
foreign_platform: linux/arm64
94+
foreign_output: aarch64
95+
- runner: ubuntu-24.04-arm
96+
native: arm64
97+
native_platform: linux/arm64
98+
native_output: aarch64
99+
foreign: amd64
100+
foreign_platform: linux/amd64
101+
foreign_output: x86_64
102+
103+
steps:
104+
- name: Verify native container execution
105+
shell: bash
106+
run: |
107+
set -euo pipefail
108+
docker info --format 'Docker server: {{.OSType}}/{{.Architecture}}'
109+
native_architecture="$(docker run --rm --platform '${{ matrix.native_platform }}' alpine:3.22 uname -m)"
110+
echo "Native container reported: ${native_architecture}"
111+
[[ "${native_architecture}" == '${{ matrix.native_output }}' ]]
112+
113+
- name: Observe foreign-architecture behavior before explicit QEMU setup
114+
id: baseline
115+
shell: bash
116+
run: |
117+
set -euo pipefail
118+
set +e
119+
baseline_output="$(docker run --rm --platform '${{ matrix.foreign_platform }}' alpine:3.22 uname -m 2>&1)"
120+
baseline_status=$?
121+
set -e
122+
123+
printf '%s\n' "${baseline_output}"
124+
{
125+
echo '## ${{ matrix.foreign }} container before explicit QEMU setup'
126+
echo
127+
echo "- Exit status: \`${baseline_status}\`"
128+
echo
129+
echo '```text'
130+
printf '%s\n' "${baseline_output}"
131+
echo '```'
132+
} >>"${GITHUB_STEP_SUMMARY}"
133+
134+
if [[ ${baseline_status} -eq 0 ]]; then
135+
[[ "${baseline_output}" == *'${{ matrix.foreign_output }}'* ]]
136+
echo 'This hosted image already had a compatible foreign-architecture execution path before the workflow configured QEMU.' >>"${GITHUB_STEP_SUMMARY}"
137+
elif [[ "${baseline_output}" == *"exec format error"* ]]; then
138+
echo 'The baseline failed with the expected missing-emulation error.' >>"${GITHUB_STEP_SUMMARY}"
139+
else
140+
echo 'The baseline failed for a reason other than a recognized architecture mismatch.' >&2
141+
exit 1
142+
fi
143+
144+
- name: Set up foreign-architecture container emulation
145+
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4
146+
with:
147+
image: docker.io/tonistiigi/binfmt@sha256:400a4873b838d1b89194d982c45e5fb3cda4593fbfd7e08a02e76b03b21166f0
148+
platforms: ${{ matrix.foreign }}
149+
150+
- name: Verify foreign-architecture container execution after QEMU setup
151+
shell: bash
152+
run: |
153+
set -euo pipefail
154+
foreign_architecture="$(docker run --rm --platform '${{ matrix.foreign_platform }}' alpine:3.22 uname -m)"
155+
echo "Emulated container reported: ${foreign_architecture}"
156+
[[ "${foreign_architecture}" == '${{ matrix.foreign_output }}' ]]
157+
{
158+
echo '## ${{ matrix.foreign }} container after explicit QEMU setup'
159+
echo
160+
echo "- Reported architecture: \`${foreign_architecture}\`"
161+
echo '- Result: success'
162+
} >>"${GITHUB_STEP_SUMMARY}"

‎CODE_OF_CONDUCT.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Code of Conduct
2+
3+
We are committed to a welcoming, respectful, and constructive community.
4+
5+
## Expected Behavior
6+
7+
- Be respectful and professional in issues, pull requests, discussions, and reviews.
8+
- Focus feedback on ideas and technical work rather than people.
9+
- Welcome good-faith questions and contributions from people with different backgrounds and experience levels.
10+
11+
## Unacceptable Behavior
12+
13+
Harassment, discrimination, personal attacks, threats, deliberate disruption, and sharing another person's private information without permission are not acceptable.
14+
15+
## Reporting
16+
17+
Report conduct concerns privately to a repository maintainer through GitHub. Do not open a public issue for a conduct report. Maintainers will review reports promptly and may remove content, limit participation, or take other action needed to protect the community.

‎CONTRIBUTING.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Contributing to EPAR
2+
3+
Thanks for taking the time to contribute.
4+
5+
## Before You Start
6+
7+
- Use GitHub issues to discuss bugs, documentation gaps, and proposed changes before starting substantial work.
8+
- Do not report security vulnerabilities in public issues. Follow [Security](docs/security.md) instead.
9+
- EPAR runs GitHub Actions jobs on trusted infrastructure. Changes that affect runners, credentials, container privileges, workflow permissions, or cleanup boundaries need clear security reasoning and tests.
10+
11+
## Development Workflow
12+
13+
1. Fork the repository and create a focused branch from `develop`.
14+
2. Keep the change small and document any operational or security behavior that it changes.
15+
3. Run the relevant tests locally. The baseline Go test suite is `go test ./...`.
16+
4. Open a pull request targeting `develop` and complete the pull-request template.
17+
18+
Fork pull requests run the safe hosted verification workflow. The live EPAR canary is reserved for branches in this repository because it uses a protected environment and disposable privileged containers.
19+
20+
## Pull Request Expectations
21+
22+
- Explain the problem, the approach, and how you tested it.
23+
- Add or update tests when behavior changes.
24+
- Keep credentials, private keys, tokens, and machine-specific configuration out of commits.
25+
- Update the relevant documentation when a user-visible or operational behavior changes.
26+
27+
By contributing, you agree to follow the [Code of Conduct](CODE_OF_CONDUCT.md).

‎README.md‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ That's it.
7575

7676
#### What Happens
7777

78-
EPAR initializes `.local/config.yml` for you if it does not exist. Docker-DinD is the default. The wizard asks whether new Docker-DinD runners should inherit the host's trusted TLS roots and defaults to yes. On native Windows, it also offers WSL2 when `wsl.exe --status` confirms default version 2; press Enter to keep Docker-DinD. Existing configs do not enable host trust inheritance automatically. You can customize the config afterward; see [Configuration](docs/configuration.md).
78+
EPAR initializes `.local/config.yml` for you if it does not exist. Docker-DinD is the default. The wizard asks whether new Docker-DinD runners should inherit the host's trusted TLS roots and defaults to yes. On native Windows, it also offers WSL2 when `wsl.exe --status` confirms default version 2. On macOS, it offers experimental Tart mode when `tart --version` succeeds. Press Enter to keep Docker-DinD. Existing configs do not enable host trust inheritance automatically. You can customize the config afterward; see [Configuration](docs/configuration.md).
7979

8080
Then EPAR checks the configured runner image, builds or replaces it when needed, and starts the configured number of runners. The default config uses `pool.instances: 1`.
8181

@@ -117,10 +117,12 @@ Docker-DinD is the default first choice. Other providers are available when they
117117
| --- | --- |
118118
| Docker-DinD | You have a Docker-compatible daemon on Windows, macOS, or Linux, and want a private Docker daemon per runner. |
119119
| WSL2 | You are on Windows and want runners as disposable WSL distros. |
120-
| Tart | You are on Apple Silicon macOS and want Linux VM runners; consider Docker-DinD first for Docker-heavy jobs because virtualization limits can affect compatibility. |
120+
| Tart (experimental) | You are on Apple Silicon macOS and want to experiment with native ARM64 Linux VMs. The default Tart image is a basic Ubuntu OS image and does not include the normal GitHub-hosted runner dependency set. |
121121

122122
WSL2 also defaults to Catthehacker's full Ubuntu runner image, but it converts that Docker image into a WSL rootfs during `image build`.
123123

124+
Tart is not a ready-made substitute for GitHub's hosted Ubuntu runners. If you need that environment, build and maintain your own bootable Tart runner image by adapting the scripts from [actions/runner-images](https://github.com/actions/runner-images), then configure EPAR to use it. EPAR does not automate that conversion.
125+
124126
See [Usage](docs/usage.md) for WSL, Tart, source builds, custom configs, and advanced options.
125127

126128
## FAQ
@@ -154,12 +156,15 @@ GitHub also warns against using self-hosted runners with public repositories tha
154156
- [GitHub App Setup](docs/github-app.md): required GitHub App permissions and fields.
155157
- [Docker-DinD Provider](docs/providers/docker-dind.md): default Docker runner mode.
156158
- [WSL Provider](docs/providers/wsl.md): Windows WSL2 runners.
157-
- [Tart Provider](docs/providers/tart.md): Apple Silicon Linux VM runners.
159+
- [Tart Provider (experimental)](docs/providers/tart.md): Apple Silicon ARM64 Linux VM runners and Rosetta compatibility limits.
158160
- [Image Build](docs/image-build.md): image internals and customization.
159161
- [Operations](docs/operations.md): logs, cleanup, and troubleshooting.
160162
- [Troubleshooting](docs/troubleshooting.md): symptom-first diagnostics by host and provider.
163+
- [Support](SUPPORT.md): where to start, what diagnostic information to collect, and where to ask for help.
161164
- [Windows Startup](docs/advanced/windows-startup.md): start EPAR after Windows login.
162165
- [macOS Startup](docs/advanced/macos-startup.md): start EPAR after macOS login.
163166
- [Running EPAR Without Installing Go](docs/advanced/no-go-install.md): run from source with no local Go install.
164-
- [Security](docs/security.md): trust boundaries and secret handling.
167+
- [Security](docs/security.md): trust boundaries, secret handling, and private vulnerability reporting.
168+
- [Contributing](CONTRIBUTING.md): how to propose and validate changes.
169+
- [Code of Conduct](CODE_OF_CONDUCT.md): community expectations and reporting concerns.
165170
- [Level 1 Core Runner Verification](docs/core-runner-verification.md): trusted live CI setup, canary behavior, and cleanup.

‎SUPPORT.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Support
2+
3+
Start with the [troubleshooting guide](docs/troubleshooting.md). It provides symptom-first diagnostics for Docker-DinD, WSL, Tart, host trust, image builds, storage, and cross-architecture containers.
4+
5+
Before asking for help, search the repository's existing [issues](https://github.com/solutionforest/ephemeral-action-runner/issues) and collect:
6+
7+
- the EPAR version or commit;
8+
- the host operating system and architecture;
9+
- the selected provider and runner image;
10+
- the relevant configuration with credentials, private keys, tokens, certificate contents, organization names, and other sensitive values removed;
11+
- the smallest reproducible workflow or command;
12+
- the relevant controller, image-build, and guest logs with secrets removed.
13+
14+
For a reproducible bug or documentation gap, open a [GitHub issue](https://github.com/solutionforest/ephemeral-action-runner/issues/new/choose). For usage questions, include what you expected, what happened, and the diagnostics above so another contributor can reproduce the environment.
15+
16+
Do not report security vulnerabilities in a public issue. Follow the private reporting instructions in the [security policy](docs/security.md).
17+
18+
Community support is provided on a best-effort basis; there is no guaranteed response time or service-level agreement.

0 commit comments

Comments
 (0)