-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.example.toml
More file actions
215 lines (185 loc) · 8.72 KB
/
Copy pathconfig.example.toml
File metadata and controls
215 lines (185 loc) · 8.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
[github]
# Authentication: personal access token OR GitHub App credentials.
# Use one approach - if app_id is set, it takes priority over token.
# token = "ghp_your_token_here"
# GitHub App authentication (recommended):
# app_id = 123456
# installation_id = 789012
# private_key_path = "/path/to/app.pem"
# Organization or user that owns the repos
owner = "your-org"
# Repos to register runners for (optional).
# If omitted, registers org-level runners available to all repos in the org.
# repos = ["repo1", "repo2"]
# OPTIONAL dispatch allowlist (defense-in-depth). This does NOT replace GitHub's
# "Require approval for all outside collaborators" setting, which is the primary
# control against fork-PR abuse of self-hosted runners — keep that enabled.
# Both fields default to empty (no restriction = today's behavior).
# [github.dispatch_policy]
# allowed_repos = ["repo1"] # only dispatch for these repos
# required_labels = ["ephemerd"] # a job must carry one of these labels to dispatch
[webhook]
# Webhook-mode reconcile sweep: how often ephemerd re-runs the catch-up poll
# as a LAST-RESORT backstop for genuinely dropped webhook deliveries. The
# common stranding case (fungible-runner churn) is healed event-drivenly on
# runner exit, so this runs at a low frequency. Default 30m; "0s" disables.
# reconcile_interval = "30m"
# By default, ephemerd polls the GitHub API every 10s for new jobs.
# No inbound ports or tunnels required.
# To use localtunnel for instant webhook delivery:
# tunnel = "localtunnel"
# tunnel_url = "http://tunnels.example.com" # self-hosted server (recommended)
# To use ngrok instead (requires free account):
# tunnel = "ngrok"
# ngrok_authtoken = "your_ngrok_token" # or set NGROK_AUTHTOKEN env var
# To use a Cloudflare Tunnel (requires a Cloudflare zone):
# Create the tunnel + DNS route in the Cloudflare dashboard (or via API),
# then give ephemerd the tunnel token and the public hostname. Ephemerd
# downloads the cloudflared binary into its data dir, runs it as a managed
# subprocess bound to ephemerd's lifetime, and auto-registers the GitHub
# webhook at https://<hostname>/webhook/github.
# tunnel = "cloudflared"
# cloudflared_token = "eyJhIjoi..." # or set CLOUDFLARE_TUNNEL_TOKEN env var
# cloudflared_hostname = "ci.example.com" # public FQDN routed to the tunnel
# cloudflared_version = "2026.6.1" # optional; pinned download version
# To use direct TLS instead of a tunnel (VPS with a public IP):
# tunnel = "none"
# tls_cert = "/etc/ephemerd/tls.crt"
# tls_key = "/etc/ephemerd/tls.key"
# secret = "your_webhook_secret" # must be stable when not using a tunnel
# port = 8080
# To use an externally-managed tunnel (e.g. a Cloudflare tunnel on another host
# that forwards a public hostname to this port). ephemerd serves the webhook
# receiver and disables polling but does not create a tunnel:
# tunnel = "external"
# secret = "your_webhook_secret" # required; must match the hook's secret
# external_url = "https://mac.tricorder.cc" # optional: public base URL of the
# # external tunnel. When set, ephemerd auto-registers each tracked repo's
# # webhook to <external_url>/webhook/<provider> on startup (idempotently) so
# # you don't have to hand-add a hook per repo. External hooks are NOT
# # removed on shutdown. Leave unset to add the hooks manually.
# port = 8080
# Pool mode: multiple ephemerd nodes sharing one public webhook URL (e.g.
# tunnel replicas behind one hostname). Registration adopts an existing
# same-URL hook instead of duplicating it, shutdown leaves the shared hook
# in place for pool-mates, and the startup stale-hook sweep is skipped.
# Every member MUST use the same explicit secret.
# pool = true
# secret = "shared_across_all_pool_members"
[network]
# Container subnet. Ephemerd auto-picks a free subnet if this conflicts with
# an existing network (e.g. Podman, Docker). You don't need to change this.
# subnet = "10.88.0.0/16"
# Bridge MTU. Auto-detected from the host's default interface.
# Override if containers have connectivity issues on unusual networks.
# mtu = 1500
[runner]
# Max concurrent jobs
max_concurrent = 4
# Default container image for jobs that don't specify `container:` in the workflow.
# Leave blank to auto-detect:
# Linux → ghcr.io/actions/actions-runner:latest
# Windows → mcr.microsoft.com/windows/servercore:ltsc20XX (matched to host OS)
# default_image = ""
# Extra labels applied to all runners (in addition to self-hosted, os, arch)
extra_labels = []
# Max time a job can run before forced teardown
job_timeout = "2h"
# Time to wait for running jobs during graceful shutdown
shutdown_timeout = "5m"
# Claim retry queue.
#
# GitHub does not re-deliver workflow_job webhooks. When ephemerd's
# initial claim/provision attempt fails for a transient reason
# (rate-limit exhausted, transient 5xx, network blip), the job would
# otherwise be lost. The retry queue schedules re-attempts on a
# jittered exponential backoff ladder and gives up after max_age.
#
# When the last GitHub API response reported remaining=0 with a known
# reset time, the next attempt is snapped to just after reset instead
# of falling through the ladder, so we do not burn attempts against a
# provably-exhausted budget.
#
# Enabled by default. Set enabled = false to restore the pre-existing
# "log and drop" behavior.
# [runner.claim_retry]
# enabled = true
# max_age = "90m"
# schedule = ["30s", "1m", "2m", "5m", "10m"]
# jitter = 0.2
# Orphaned-runner sweep.
#
# ephemerd registers one just-in-time runner per queued job, but GitHub
# assigns a registered runner to ANY queued job with matching labels.
# Runner teardown therefore follows the assignment GitHub reports in
# workflow_job webhooks (runner_name), not the job the runner was
# dispatched for. A runner whose intended job was picked up elsewhere
# and that never received a job of its own is destroyed and
# deregistered after the grace window.
#
# Only active in webhook mode (polling mode has no in_progress events
# to observe assignments with). Enabled by default.
# [runner.orphan_sweep]
# enabled = true
# grace = "10m"
# macOS job routing and native-runner hardening.
#
# macOS jobs can run either in a per-job VM (default, strongest isolation) or
# natively on the host inside a sandbox-exec profile (faster, weaker boundary).
# [runner.macos]
# mode = "vm" # default mode: "vm" or "native"
# max_native = 4 # max concurrent native jobs
# user = "ciuser" # optional existing user for native runners
#
# max_processes: ulimit -u applied to each native job BEFORE the runner execs,
# for fork-bomb / runaway-fork defense. Default 2048 (generous — clang/php fork
# heavily). Set 0 for unlimited.
#
# NOTE: macOS has no cgroups, so RAM and disk CANNOT be hard-capped on the
# native path. max_processes is fork-bomb/CPU defense only; use mode = "vm"
# for untrusted memory/disk DoS resistance.
# max_processes = 2048
#
# sandbox_strict: switch the native sandbox from allow-by-default (deny-list)
# to deny-by-default (allow-list). Much stronger, but the allow-list is not
# guaranteed to cover every toolchain — OPT-IN and default false. Live-smoke-
# test on your host before enabling; missing paths/services surface as sandbox
# denials in the system log and can be added to the strict allow-list.
# sandbox_strict = false
#
# [runner.macos.repos]
# "ephpm/*" = "native" # all repos in org run native
# "ephpm/secret-repo" = "vm" # except this one (exact match wins)
[vm.linux]
# Enable a Linux VM for running Linux jobs on Windows/macOS hosts.
# On Windows: creates a WSL2 distro with an embedded ephemerd binary.
# The distro is destroyed on shutdown. Requires WSL2 to be installed.
# enabled = false
# cpus = 2
# memory_mb = 2048
[metrics]
# Enable Prometheus metrics endpoint. Disabled by default.
# enabled = true
# port = 9090
# path = "/metrics"
# Bind address. The metrics endpoint is UNAUTHENTICATED, so it binds to
# 127.0.0.1 (loopback only) by default. To scrape from another host, set this
# to "0.0.0.0" and firewall the port and/or enable TLS below.
# bind_addr = "127.0.0.1"
# Optional TLS for the metrics endpoint
# tls_cert = "/etc/ephemerd/metrics.crt"
# tls_key = "/etc/ephemerd/metrics.key"
# [dispatch] configures the host<->VM gRPC dispatch channel used on Windows
# (Hyper-V) and macOS (Vz) hosts to run Linux jobs inside a VM. A shared bearer
# token authenticates every RPC. Leave unset: ephemerd auto-generates a token
# on first run and persists it here. Set explicitly only to pin/rotate it.
# [dispatch]
# token = "..."
[log]
# Log level: debug, info, warn, error
level = "info"
# Log format: text or json
format = "text"
# How long to keep job log files before automatic cleanup.
# Supports Go durations (e.g. "168h") and a "d" shorthand (e.g. "7d").
# log_retention = "7d"