Skip to content
Merged
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
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ concurrency:
jobs:
# docker-build needs a Docker daemon, and cordon-exec has none (Docker on our host is root). So the
# image job runs on GitHub's runners, on every push to the default branch and on a PR that
# changes what the image is built from: the Dockerfile, .dockerignore, the package files,
# changes what the image is built from: the Dockerfile, .dockerignore or Dockerfile.dockerignore, the package files,
# tsconfig.json, src/, or this file. The required check docker-build runs on our runner and passes only when that
# job passed or was not owed, so a PR that changes none of them never waits on GitHub's queue.
docker-build-inputs:
runs-on: ${{ github.event.pull_request && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.user.login == 'dependabot[bot]') && 'ubuntu-latest' || fromJSON('["self-hosted","cordon-exec"]') }}
runs-on: ${{ (github.repository != 'askalf/cordon' || github.event.pull_request && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.user.login == 'dependabot[bot]')) && 'ubuntu-latest' || fromJSON('["self-hosted","cordon-exec"]') }}
timeout-minutes: 5
outputs:
changed: ${{ steps.diff.outputs.changed }}
Expand Down Expand Up @@ -57,7 +57,7 @@ jobs:
while IFS= read -r -d '' f; do
printf '%s\n' "$f"
case "$f" in
Dockerfile|.dockerignore|package.json|package-lock.json|tsconfig.json|src/*|.github/workflows/build.yml)
Dockerfile|.dockerignore|Dockerfile.dockerignore|package.json|package-lock.json|tsconfig.json|src/*|.github/workflows/build.yml)
changed=true ;;
esac
done < "$list"
Expand Down Expand Up @@ -118,7 +118,7 @@ jobs:
docker-build:
needs: [docker-build-inputs, docker-build-image]
if: always()
runs-on: ${{ github.event.pull_request && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.user.login == 'dependabot[bot]') && 'ubuntu-latest' || fromJSON('["self-hosted","cordon-exec"]') }}
runs-on: ${{ (github.repository != 'askalf/cordon' || github.event.pull_request && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.user.login == 'dependabot[bot]')) && 'ubuntu-latest' || fromJSON('["self-hosted","cordon-exec"]') }}
timeout-minutes: 5
steps:
- name: the image job passed, or no change owed one
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ concurrency:

jobs:
test:
# Our own code (pushes, same-repo PRs, schedules, dispatches) runs on cordon-exec, the
# non-root one-job runners on our host, so GitHub's hosted
# queue going down does not hold our PRs. A fork's PR and a Dependabot PR run code nobody
# here wrote, so they stay on GitHub's runners.
runs-on: ${{ github.event.pull_request && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.user.login == 'dependabot[bot]') && 'ubuntu-latest' || fromJSON('["self-hosted","cordon-exec"]') }}
# Our own code (pushes, same-repo PRs, schedules, dispatches) runs on cordon-exec, our non-root
# one-job runners, so GitHub's hosted queue going down does not hold our PRs. A fork's PR
# and a Dependabot PR run code nobody here wrote, and a fork repository has no cordon-exec
# runners, so those stay on GitHub's runners.
runs-on: ${{ (github.repository != 'askalf/cordon' || github.event.pull_request && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.user.login == 'dependabot[bot]')) && 'ubuntu-latest' || fromJSON('["self-hosted","cordon-exec"]') }}
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down
14 changes: 3 additions & 11 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@ concurrency:
jobs:
analyze:
name: analyze (${{ matrix.language }})
# Our own code (pushes, same-repo PRs, schedules, dispatches) runs on cordon-exec, the
# non-root one-job runners on our host, so GitHub's hosted
# queue going down does not hold our PRs. A fork's PR and a Dependabot PR run code nobody
# here wrote, so they stay on GitHub's runners.
runs-on: ${{ github.event.pull_request && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.user.login == 'dependabot[bot]') && 'ubuntu-latest' || fromJSON('["self-hosted","cordon-exec"]') }}
# CodeQL runs on GitHub's runners: it sizes itself to the machine, and the exec runners of
# every repo share one host, so concurrent analyses would exhaust its memory.
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
actions: read
Expand All @@ -36,16 +34,10 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# CodeQL sizes itself to the machine's RAM and cores; on our host every exec runner shares
# one memory ceiling, so on our runner it gets 2G and two threads, on GitHub's its defaults.
- uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
with:
languages: ${{ matrix.language }}
queries: security-and-quality
ram: ${{ runner.environment == 'self-hosted' && '2048' || '' }}
threads: ${{ runner.environment == 'self-hosted' && '2' || '' }}
- uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
with:
category: "/language:${{ matrix.language }}"
ram: ${{ runner.environment == 'self-hosted' && '2048' || '' }}
threads: ${{ runner.environment == 'self-hosted' && '2' || '' }}
3 changes: 2 additions & 1 deletion .github/workflows/fleet-status-backfill.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ jobs:
backfill:
# Our own script on its own trigger, never PR code: on our runner, so GitHub's hosted
# queue going down does not stop it.
runs-on: [self-hosted, cordon-exec]
# A fork repository has no cordon-exec runners, so there it runs on GitHub's.
runs-on: ${{ github.repository == 'askalf/cordon' && fromJSON('["self-hosted","cordon-exec"]') || 'ubuntu-latest' }}
timeout-minutes: 10
permissions:
contents: read
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/fleet-status-self-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ permissions: {}

jobs:
self-test:
# Our own code (pushes, same-repo PRs, schedules, dispatches) runs on cordon-exec, the
# non-root one-job runners on our host, so GitHub's hosted
# queue going down does not hold our PRs. A fork's PR and a Dependabot PR run code nobody
# here wrote, so they stay on GitHub's runners.
runs-on: ${{ github.event.pull_request && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.user.login == 'dependabot[bot]') && 'ubuntu-latest' || fromJSON('["self-hosted","cordon-exec"]') }}
# Our own code (pushes, same-repo PRs, schedules, dispatches) runs on cordon-exec, our non-root
# one-job runners, so GitHub's hosted queue going down does not hold our PRs. A fork's PR
# and a Dependabot PR run code nobody here wrote, and a fork repository has no cordon-exec
# runners, so those stay on GitHub's runners.
runs-on: ${{ (github.repository != 'askalf/cordon' || github.event.pull_request && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.user.login == 'dependabot[bot]')) && 'ubuntu-latest' || fromJSON('["self-hosted","cordon-exec"]') }}
timeout-minutes: 5
permissions:
contents: read
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/fleet-status.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ jobs:
# On our runner for every event, a fork's included: the job runs the default branch's script
# and never PR code (see above), so GitHub's hosted queue going down does not hold the
# fleet/verify and fleet/review statuses a merge waits on.
runs-on: [self-hosted, cordon-exec]
# A fork repository has no cordon-exec runners, so there it runs on GitHub's.
runs-on: ${{ github.repository == 'askalf/cordon' && fromJSON('["self-hosted","cordon-exec"]') || 'ubuntu-latest' }}
timeout-minutes: 5
permissions:
contents: read
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ permissions:
jobs:
manifest:
name: manifest matches the repo
# Our own code (pushes, same-repo PRs, schedules, dispatches) runs on cordon-exec, the
# non-root one-job runners on our host, so GitHub's hosted
# queue going down does not hold our PRs. A fork's PR and a Dependabot PR run code nobody
# here wrote, so they stay on GitHub's runners.
runs-on: ${{ github.event.pull_request && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.user.login == 'dependabot[bot]') && 'ubuntu-latest' || fromJSON('["self-hosted","cordon-exec"]') }}
# Our own code (pushes, same-repo PRs, schedules, dispatches) runs on cordon-exec, our non-root
# one-job runners, so GitHub's hosted queue going down does not hold our PRs. A fork's PR
# and a Dependabot PR run code nobody here wrote, and a fork repository has no cordon-exec
# runners, so those stay on GitHub's runners.
runs-on: ${{ (github.repository != 'askalf/cordon' || github.event.pull_request && (github.event.pull_request.head.repo.full_name != github.repository || github.event.pull_request.user.login == 'dependabot[bot]')) && 'ubuntu-latest' || fromJSON('["self-hosted","cordon-exec"]') }}
timeout-minutes: 3
permissions:
contents: read
Expand Down
45 changes: 27 additions & 18 deletions scripts/fleet-status.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -514,40 +514,49 @@ console.log('\n fleet-status.yml: which events run the job for a fork');
&& checkouts.every((m) => /ref: \$\{\{ github\.event\.repository\.default_branch \}\}/.test(m[1])));
check('no step reads the PR head ref or sha', !/(pull_request\.head\.(ref|sha)|workflow_run\.head_sha)/.test(own));

// Our own code runs on cordon-exec, our host's runners; code nobody here wrote never does. A
// runs-on expression sends a fork's PR and a Dependabot PR to GitHub's runners and everything
// else to ours. A literal cordon-exec on a pull_request workflow needs a job if: that keeps forks off
// it, or a job that never runs PR code (fleet-status, checked above).
// Our own code runs on cordon-exec, our host's runners; code nobody here wrote never does, and a fork
// repository, which has no cordon-exec runners, never waits for one. The own-code expression sends a
// fork's PR, a Dependabot PR and any run in a fork repository to GitHub's runners and everything
// else to ours. The repository-only expression, for jobs that never run PR code, sends everything
// here to ours. A literal cordon-exec needs a job if: that keeps it to this repository's own code.
const OWN_RE = /^\s+runs-on: \$\{\{ (.+) \}\}$/;
const exprs = [];
const HOME_REPO = 'askalf/cordon';
const ownExprs = [];
const repoOnly = [];
const literal = [];
for (const f of readdirSync(dir).filter((x) => /\.ya?ml$/.test(x))) {
const y = readFileSync(join(dir, f), 'utf8');
for (const line of y.split('\n')) {
const m = OWN_RE.exec(line);
if (m && m[1].includes('cordon-exec')) exprs.push({ f, e: m[1] });
else if (/^\s+runs-on: \[self-hosted, cordon-exec\]/.test(line)) literal.push(f);
if (m && m[1].includes('cordon-exec')) (m[1].includes('github.event.pull_request') ? ownExprs : repoOnly).push({ f, e: m[1] });
else if (/^\s+runs-on: \[self-hosted, cordon\-exec\]/.test(line)) literal.push(f);
}
}
check('the own-code runs-on expression is in use', exprs.length >= 6);
const hosted = (e, github) => evalIf(`(${e}) == 'ubuntu-latest'`, { github: { repository: REPO, ...github } });
check('the own-code runs-on expression is in use', ownExprs.length >= 5);
const hosted = (e, github, repository = HOME_REPO) => evalIf(`(${e}) == 'ubuntu-latest'`, { github: { repository, ...github } });
const prFrom = (event_name, headRepo, login = 'askalf') =>
({ event_name, event: { pull_request: { head: { repo: { full_name: headRepo } }, user: { login } } } });
for (const { f, e } of exprs) {
const EVENTS = [{ event_name: 'push', event: {} }, { event_name: 'schedule', event: {} }, { event_name: 'workflow_dispatch', event: {} }];
const FORK_REPO = 'someone/cordon';
for (const { f, e } of ownExprs) {
check(`${f}: a fork's pull_request runs on GitHub's runners`, hosted(e, prFrom('pull_request', FORKED)));
check(`${f}: a fork's pull_request_review runs on GitHub's runners`, hosted(e, prFrom('pull_request_review', FORKED)));
check(`${f}: a Dependabot PR runs on GitHub's runners`, hosted(e, prFrom('pull_request', REPO, 'dependabot[bot]')));
check(`${f}: a same-repo PR runs on ours`, !hosted(e, prFrom('pull_request', REPO)));
check(`${f}: a push, schedule or dispatch runs on ours`,
!hosted(e, { event_name: 'push', event: {} }) && !hosted(e, { event_name: 'schedule', event: {} })
&& !hosted(e, { event_name: 'workflow_dispatch', event: {} }));
check(`${f}: a Dependabot PR runs on GitHub's runners`, hosted(e, prFrom('pull_request', HOME_REPO, 'dependabot[bot]')));
check(`${f}: a same-repo PR runs on ours`, !hosted(e, prFrom('pull_request', HOME_REPO)));
check(`${f}: a push, schedule or dispatch runs on ours`, EVENTS.every((ev) => !hosted(e, ev)));
check(`${f}: in a fork repository every event runs on GitHub's runners`,
EVENTS.every((ev) => hosted(e, ev, FORK_REPO)) && hosted(e, prFrom('pull_request', FORK_REPO), FORK_REPO));
check(`${f}: the expression names exactly our label`, e.includes(`fromJSON('["self-hosted","cordon-exec"]')`));
}
for (const { f, e } of repoOnly) {
check(`${f}: every event here runs on ours`, EVENTS.every((ev) => !hosted(e, ev)) && !hosted(e, prFrom('pull_request', FORKED)));
check(`${f}: in a fork repository it runs on GitHub's runners`, EVENTS.every((ev) => hosted(e, ev, FORK_REPO)));
check(`${f}: only a job that never runs PR code uses it`, ['fleet-status.yml', 'fleet-status-backfill.yml'].includes(f));
}
for (const f of literal) {
const y = readFileSync(join(dir, f), 'utf8');
const prTriggered = /\bpull_request(_target|_review)?\b/.test(onBlockOf(y));
check(`${f}: a literal cordon-exec is on a workflow no fork can run, or keeps forks off it`,
!prTriggered || f === 'fleet-status.yml' || /head\.repo\.full_name == github\.repository/.test(y));
check(`${f}: a literal cordon-exec job runs only in this repository, or only on its own PRs`,
y.includes(`github.repository == '${HOME_REPO}'`) || /head\.repo\.full_name == github\.repository/.test(y));
}

let relay = '';
Expand Down
Loading