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
45 changes: 44 additions & 1 deletion .github/SMOKE_TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ PR that touches a greffon.

## Reading the spec

Each spec reads `process.env.<GREFFON>_URL`:
Most browser-facing specs read `process.env.<GREFFON>_URL`:

| Greffon | Env var |
|---|---|
Expand All @@ -29,6 +29,19 @@ Each spec reads `process.env.<GREFFON>_URL`:
| Plausible | `PLAUSIBLE_URL` |
| VS Code | `VSCODE_URL` |

The GitHub Actions Runner greffon is headless and does not expose an HTTP URL.
Its spec is skipped by default. To verify a deployed runner through GitHub's
API, set:

| Variable | Description |
|---|---|
| `GITHUB_RUNNER_SMOKE_TOKEN` | PAT that can list self-hosted runners for the target repo or org |
| `GITHUB_RUNNER_SMOKE_SCOPE` | `repo` or `org`; defaults to `repo` |
| `GITHUB_RUNNER_SMOKE_REPO` | `owner/repo`, required for repo scope |
| `GITHUB_RUNNER_SMOKE_ORG` | Organization name, required for org scope |
| `GITHUB_RUNNER_SMOKE_NAME_PREFIX` | Required unique runner name prefix for the deployment under test |
| `GITHUB_RUNNER_SMOKE_HOST` | GitHub host; defaults to `github.com` |

The local dev workflow (greffon root `scripts/setup-dev.sh` + the install
dialog or the API) deploys an instance, the greffer assigns a port, and
you set the env var to `https://127.0.0.1:<port>`.
Expand Down Expand Up @@ -71,6 +84,36 @@ npx playwright test
against a local deploy until it passes.
5. Add a row to the env-var table above.

## GitHub Actions Runner notes

Self-hosted GitHub Actions runners execute workflow code on your greffer host.
Only attach them to trusted private repositories or controlled organizations,
and avoid exposing them to untrusted pull requests.

The catalog entry uses one grouped install form so the UI can validate the
required auth and scope combinations before deployment. It supports two GitHub
auth modes:

- `RUNNER_TOKEN`: the short-lived registration token from GitHub's standard
`./config.sh --url ... --token ...` flow. This is convenient for manual
first-start testing, but it expires quickly and must be refreshed before a
later reconfigure or restart.
- `ACCESS_TOKEN`: a PAT used by the container to mint fresh registration
tokens automatically. This is the recommended mode for durable catalog
installs.

For repo scope PAT auto-registration, use a PAT from a user with admin access
to the repository; fine-grained PATs need repository Administration
read/write permission. Classic PATs typically need `repo` for private
repositories or `public_repo` for public repositories. For org scope, use an
organization owner/admin PAT with self-hosted runner management permission;
classic PATs typically need `admin:org`.

Runner jobs that use Docker are served by a Docker-in-Docker sidecar. The
catalog intentionally does not mount the host Docker socket because greffer
rewrites compose volumes and host socket mounts would also grant broad host
control to jobs.

## CI infrastructure note

The Integration Test job in `.github/workflows/validate-greffon.yml` checks
Expand Down
41 changes: 41 additions & 0 deletions github-runner/1.0/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
version: "3"

services:
github_runner:
image: myoung34/github-runner:2.333.1-ubuntu-noble
restart: unless-stopped
depends_on:
- docker
environment:
DOCKER_HOST: tcp://docker:2375
EPHEMERAL: "1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Re-enable runner updates for the pinned image

With the runner image pinned to 2.333.1-ubuntu-noble, setting DISABLE_AUTO_UPDATE leaves deployed instances permanently on that runner binary unless every deployment is manually recreated after each upstream release. GitHub's self-hosted runner reference states that when updates are disabled, the runner must be updated within 30 days of a new release and GitHub Actions stops queueing jobs afterward. Existing catalog installs will therefore become unusable after the next runner release ages past that window; allow automatic updates or add an actual image refresh mechanism.

Useful? React with 👍 / 👎.

DISABLE_AUTO_UPDATE: "1"
START_DOCKER_SERVICE: "false"
UNSET_CONFIG_VARS: "true"
RUN_AS_ROOT: "false"
RUNNER_WORKDIR: /runner/_work
RUNNER_SCOPE: repo
RUNNER_NAME_PREFIX: greffon-{{ instance_id }}
LABELS: greffon,self-hosted

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Recreate storage between ephemeral runner jobs

When this runner completes a job, EPHEMERAL causes it to exit, but Compose restarts the same container and preserves this named work volume; the Docker sidecar and its docker-data volume are preserved as well. As a result, later jobs can observe files, credentials, containers, and images left by earlier jobs even though the runner is configured as ephemeral. The upstream image's ephemeral-runner guidance requires a fresh container and no persistent RUNNER_WORKDIR mount to provide isolation. Recreate the runner and its per-job storage after each job, or avoid advertising this deployment as ephemeral.

Useful? React with 👍 / 👎.

GITHUB_HOST: github.com
volumes:
- runner-work:/runner/_work

docker:
image: docker:29.4.0-dind
restart: unless-stopped
privileged: true
environment:
DOCKER_TLS_CERTDIR: ""
command:
- dockerd
- --host=tcp://0.0.0.0:2375
- --host=unix:///var/run/docker.sock
- --tls=false
volumes:
- runner-work:/runner/_work
- docker-data:/var/lib/docker

volumes:
runner-work:
docker-data:
223 changes: 223 additions & 0 deletions github-runner/1.0/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
{
"name": "GitHub Actions Runner",
"logo": "https://github.githubassets.com/favicons/favicon.svg",
"description": "Self-hosted GitHub Actions runner with Docker-in-Docker support",
"categories": [
"ci",
"developer-tools"
],
"images": [],
"configurations": [
{
"title": "RUNNER_CONFIGURATION",
"schema": {
"type": "object",
"properties": {
"auth_type": {
"type": "string",
"title": "Authentication method",
"description": "Choose a durable PAT-based setup or a short-lived GitHub runner registration token.",
"enum": [
"access_token",
"runner_token"
],
"enumNames": [
"Personal access token (recommended)",
"Registration token"
]
},
"access_token": {
"type": "string",
"title": "GitHub PAT",
"description": "PAT used to request short-lived self-hosted runner registration tokens automatically.",
"writeOnly": true
},
"runner_token": {
"type": "string",
"title": "GitHub runner registration token",
"description": "Short-lived registration token from GitHub's standard ./config.sh flow.",
"writeOnly": true
},
"runner_scope": {
"type": "string",
"title": "Runner scope",
"description": "Use repo for one repository, or org for an organization-level runner.",
"enum": [
"repo",
"org"
]
},
"repo_url": {
"type": "string",
"title": "Repository URL",
"description": "Required when runner scope is repo, for example https://github.com/owner/repo."
},
"org_name": {
"type": "string",
"title": "Organization name",
"description": "Required when runner scope is org."
},
"runner_name_prefix": {
"type": "string",
"title": "Runner name prefix",
"description": "Prefix for the generated GitHub runner name."
},
"labels": {
"type": "string",
"title": "Runner labels",
"description": "Comma-separated labels added to this self-hosted runner."
},
"runner_group": {
"type": "string",
"title": "Runner group",
"description": "Optional runner group name. Leave blank to use GitHub's default runner group."
},
"github_host": {
"type": "string",
"title": "GitHub host",
"description": "GitHub host for GitHub Enterprise Server installations."
}
},
"dependencies": {
"auth_type": {
"oneOf": [
{
"properties": {
"auth_type": {
"enum": [
"access_token"
]
},
"access_token": {
"minLength": 1
}
},
"required": [
"access_token"
]
},
{
"properties": {
"auth_type": {
"enum": [
"runner_token"
]
},
"runner_token": {
"minLength": 1
}
},
"required": [
"runner_token"
]
}
]
},
"runner_scope": {
"oneOf": [
{
"properties": {
"runner_scope": {
"enum": [
"repo"
]
},
"repo_url": {
"minLength": 1
}
},
"required": [
"repo_url"
]
},
{
"properties": {
"runner_scope": {
"enum": [
"org"
]
},
"org_name": {
"minLength": 1
}
},
"required": [
"org_name"
]
}
]
}
}
},
"default_value": {
"auth_type": "access_token",
"access_token": "",
"runner_token": "",
"runner_scope": "repo",
"repo_url": "",
"org_name": "",
"runner_name_prefix": "greffon-{{ instance_id }}",
"labels": "greffon,self-hosted",
"runner_group": "",
"github_host": "github.com"
},
"destinations": [
{
"type": "env",
"container": "github_runner",
"key": "ACCESS_TOKEN",
"value_path": "access_token"
},
{
"type": "env",
"container": "github_runner",
"key": "RUNNER_TOKEN",
"value_path": "runner_token"
},
{
"type": "env",
"container": "github_runner",
"key": "RUNNER_SCOPE",
"value_path": "runner_scope"
},
{
"type": "env",
"container": "github_runner",
"key": "REPO_URL",
"value_path": "repo_url"
},
{
"type": "env",
"container": "github_runner",
"key": "ORG_NAME",
"value_path": "org_name"
},
{
"type": "env",
"container": "github_runner",
"key": "RUNNER_NAME_PREFIX",
"value_path": "runner_name_prefix"
},
{
"type": "env",
"container": "github_runner",
"key": "LABELS",
"value_path": "labels"
},
{
"type": "env",
"container": "github_runner",
"key": "RUNNER_GROUP",
"value_path": "runner_group"
},
{
"type": "env",
"container": "github_runner",
"key": "GITHUB_HOST",
"value_path": "github_host"
}
],
"x-greffon-allow-empty-secret": true
}
]
}
Loading
Loading