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
2 changes: 1 addition & 1 deletion .github/workflows/audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ concurrency:
jobs:
audit:
name: audit
runs-on: [self-hosted, gittensory]
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
Expand Down
28 changes: 10 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,14 @@ jobs:
- 'review-enrichment/**'
- '.github/workflows/ci.yml'

# Path-aware validation. Keep this as one self-hosted job so a PR uses one
# runner slot and one dependency install instead of fanning out into several
# competing installs on the same VPS. Fork PRs still run on GitHub-hosted
# runners because their code is untrusted.
# Path-aware validation. Keep this as one job so a PR uses one dependency
# install and one coverage upload. Run on GitHub-hosted runners while the
# self-hosted review stack is CPU constrained.
validate-code:
name: validate-code
needs: changes
if: ${{ github.event_name == 'push' || needs.changes.outputs.backend == 'true' || needs.changes.outputs.mcp == 'true' || needs.changes.outputs.rees == 'true' || needs.changes.outputs.ui == 'true' }}
runs-on: ${{ fromJSON((github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true) && '["ubuntu-latest"]' || '["self-hosted","gittensory"]') }}
runs-on: ubuntu-latest
timeout-minutes: 45
env:
VITE_GITTENSORY_API_ORIGIN: https://gittensory-api.aethereal.dev
Expand All @@ -142,14 +141,10 @@ jobs:
# actions/checkout wipes node_modules (git clean -ffdx) on every run regardless of the self-hosted
# runner's own persistence, and npm ci always deletes+reinstalls node_modules by design -- so
# neither the runner nor npm ci gives node_modules any real cross-run reuse on its own. This
# explicit restore/save pair (via GitHub's own cache service, not the wiped local disk) fills that
# gap: an exact manifest+lockfile match skips npm ci entirely. Keyed separately per fork/trusted
# (see the runs-on expression above) because self-hosted's Docker image and GitHub's ubuntu-latest
# image are not guaranteed binary-compatible for native modules (sharp, workerd, fsevents, ...) --
# crossing them could load an incompatible native binary. Fork PRs get read-only cache tokens (a
# documented actions/cache behavior), so a "fork"-keyed entry can never actually be written; that's
# fine, it just means fork PRs keep doing a full npm ci exactly as before -- no regression, no risk
# on the highest-stakes (no-retry) population.
# explicit restore/save pair (via GitHub's own cache service, not local disk) fills that gap: an
# exact manifest+lockfile match skips npm ci entirely. Keep fork/trusted keys separate even though
# both run on ubuntu-latest: fork PRs get read-only cache tokens, so a fork-keyed entry can never
# actually be written; trusted PRs keep their reusable cache without crossing trust boundaries.
- name: Restore node_modules cache
id: node-modules-cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
Expand Down Expand Up @@ -220,11 +215,8 @@ jobs:
# above) didn't change. mcp-output-schemas.test.ts is never in the exclude list -- see that filter's
# comment for why it can't be safely narrowed.
SKIP_MCP_CLI_HARNESS: ${{ github.event_name == 'pull_request' && needs.changes.outputs.mcpCliHarness != 'true' }}
# Pinned to the self-hosted runner's actual Docker CPU quota (4), not "100%": Node's os.cpus()
# reports the HOST's full core count inside the container, ignoring the cgroup CPU limit, so
# --maxWorkers=100% oversubscribed the worker pool far past what the runner can actually execute
# in parallel, causing thrashing. A GitHub-hosted fork-PR runner has no such limit, but the
# standard 4-core GitHub runner makes 4 the right number there too.
# Pinned to the standard GitHub-hosted runner's effective CPU budget; keeping this explicit avoids
# accidental worker-pool thrash if os.cpus() reports a larger host in a future runner image.
run: |
EXCLUDE_ARGS=()
if [ "$SKIP_MCP_CLI_HARNESS" = "true" ]; then
Expand Down
19 changes: 6 additions & 13 deletions .github/workflows/self-host-nightly.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
# Nightly maintenance on the self-hosted runner (gittensory channel). Deliberately NOT wired into PR CI: this
# repo's gate auto-closes PRs with red required checks, so a self-hosted runner being offline must never be able
# to fail-close a PR. This runs on a schedule + on demand only, and keeps the local RAG index fresh.
#
# Setup: this repo needs a self-hosted runner labelled `gittensory` (the self-host stack provides one), and
# optionally an INTERNAL_JOB_TOKEN repo secret (Settings → Secrets → Actions) to trigger the RAG re-index.
name: self-host nightly
# Manual maintenance hook for an externally reachable self-host stack. This is deliberately not scheduled while
# the review stack is running without colocated GitHub Actions runners.
name: self-host maintenance

on:
schedule:
- cron: "0 4 * * *" # 04:00 UTC daily
workflow_dispatch: {}

permissions:
Expand All @@ -20,12 +14,11 @@ concurrency:

jobs:
maintenance:
runs-on: [self-hosted, gittensory]
if: ${{ vars.SELF_HOST_URL != '' }}
runs-on: ubuntu-latest
timeout-minutes: 30
env:
# The runner shares the stack's Docker network, so it reaches the engine by service name. Override with a
# repo variable SELF_HOST_URL if your runner is elsewhere (e.g. a published port / Tailscale address).
SELF_HOST_URL: ${{ vars.SELF_HOST_URL || 'http://gittensory:8787' }}
SELF_HOST_URL: ${{ vars.SELF_HOST_URL }}
INTERNAL_JOB_TOKEN: ${{ secrets.INTERNAL_JOB_TOKEN }}
steps:
- name: Self-host health
Expand Down
Loading