From f8bd621f181aa2a2d6ed07531168150fd3deea13 Mon Sep 17 00:00:00 2001 From: Nomads_Reach <144523850+NomadsReach@users.noreply.github.com> Date: Mon, 17 Aug 2026 15:51:31 -0400 Subject: [PATCH 1/7] Route acceptance to isolated CO-SERVER runner --- .github/workflows/acceptance.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index 6405d9b..3eef26c 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -1,11 +1,5 @@ name: Acceptance (end-to-end TCP) -# Issue #15 acceptance matrix, executed end-to-end: stands up the real -# AuthoritativeServer behind the real TCP transport on a loopback port and drives -# real client sockets through it. If the runner cannot bind a loopback listener, -# the harness prints SKIP and exits 0 (it still runs for real on dev machines and -# the NAS runner). - on: push: paths: @@ -17,17 +11,22 @@ on: - ".github/workflows/acceptance.yml" workflow_dispatch: +permissions: + contents: read + jobs: acceptance: name: End-to-end TCP acceptance - runs-on: [self-hosted, Linux, X64] + runs-on: [self-hosted, Linux, X64, co-server] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 + with: + persist-credentials: false - name: Enforce repository runtime policy run: bash server/scripts/verify-no-legacy-runtime.sh - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 env: DOTNET_INSTALL_DIR: ${{ runner.tool_cache }}/dotnet with: From e1d894e8280f82f58b7bbb68e9cda8fee00384b1 Mon Sep 17 00:00:00 2001 From: Nomads_Reach <144523850+NomadsReach@users.noreply.github.com> Date: Mon, 17 Aug 2026 15:51:40 -0400 Subject: [PATCH 2/7] Harden CO-SERVER build runner selection --- .github/workflows/csharp-server.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/csharp-server.yml b/.github/workflows/csharp-server.yml index 396449b..98c195e 100644 --- a/.github/workflows/csharp-server.yml +++ b/.github/workflows/csharp-server.yml @@ -5,20 +5,22 @@ on: pull_request: workflow_dispatch: +permissions: + contents: read + jobs: build-and-test: name: Repository policy, C# build and test - runs-on: [self-hosted, Linux, X64] + runs-on: [self-hosted, Linux, X64, co-server] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 + with: + persist-credentials: false - name: Enforce repository runtime policy run: bash server/scripts/verify-no-legacy-runtime.sh - - uses: actions/setup-dotnet@v4 - # The runner user cannot write to system /usr/share/dotnet; install the - # pinned SDK into a runner-writable, cached path instead. runner.* context - # is only valid at step scope, not job-level env. + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 env: DOTNET_INSTALL_DIR: ${{ runner.tool_cache }}/dotnet with: From 6f1e7d8f99edb907ff25a5446bb903585b9ff8d0 Mon Sep 17 00:00:00 2001 From: Nomads_Reach <144523850+NomadsReach@users.noreply.github.com> Date: Mon, 17 Aug 2026 15:51:49 -0400 Subject: [PATCH 3/7] Route GNS build to isolated CO-SERVER runner --- .github/workflows/gns-transport.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gns-transport.yml b/.github/workflows/gns-transport.yml index b63b596..02692b5 100644 --- a/.github/workflows/gns-transport.yml +++ b/.github/workflows/gns-transport.yml @@ -10,14 +10,19 @@ on: - "server/native_transport/**" - ".github/workflows/gns-transport.yml" +permissions: + contents: read + jobs: linux: name: Linux native GNS bridge - runs-on: [self-hosted, Linux, X64] + runs-on: [self-hosted, Linux, X64, co-server] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 + with: + persist-credentials: false - - name: Verify build dependencies (pre-provisioned on the self-hosted runner) + - name: Verify build dependencies run: | missing=0 for tool in cmake ninja protoc; do From 3353726aef78a99232bad302bb59df34fabf8a34 Mon Sep 17 00:00:00 2001 From: Nomads_Reach <144523850+NomadsReach@users.noreply.github.com> Date: Mon, 17 Aug 2026 15:51:56 -0400 Subject: [PATCH 4/7] Harden CO-SERVER host build runner --- .github/workflows/host.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/host.yml b/.github/workflows/host.yml index 5960cca..babcabb 100644 --- a/.github/workflows/host.yml +++ b/.github/workflows/host.yml @@ -11,16 +11,19 @@ on: - ".github/workflows/host.yml" workflow_dispatch: +permissions: + contents: read + jobs: build: name: Build Avalonia host - runs-on: [self-hosted, Linux, X64] + runs-on: [self-hosted, Linux, X64, co-server] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 + with: + persist-credentials: false - - uses: actions/setup-dotnet@v4 - # The runner user cannot write to system /usr/share/dotnet; install the - # pinned SDK into a runner-writable, cached path instead. + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 env: DOTNET_INSTALL_DIR: ${{ runner.tool_cache }}/dotnet with: From 7b4acf61d53a458692a4d098ea08b730694f8c0b Mon Sep 17 00:00:00 2001 From: Nomads_Reach <144523850+NomadsReach@users.noreply.github.com> Date: Mon, 17 Aug 2026 15:52:05 -0400 Subject: [PATCH 5/7] Pin CO-SERVER publish actions and reduce artifact retention --- .github/workflows/publish-host.yml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/workflows/publish-host.yml b/.github/workflows/publish-host.yml index cce5438..e770328 100644 --- a/.github/workflows/publish-host.yml +++ b/.github/workflows/publish-host.yml @@ -1,37 +1,34 @@ name: Publish Host (Avalonia) -# Produces self-contained, single-file Server Host binaries for Windows and -# Linux. No .NET runtime is required on the target machine. Runs on demand and -# on version tags; each build is uploaded as a workflow artifact. - on: workflow_dispatch: push: tags: - "host-v*" +permissions: + contents: read + jobs: publish: name: Publish ${{ matrix.rid }} - runs-on: [self-hosted, Linux, X64] + runs-on: [self-hosted, Linux, X64, co-server] strategy: fail-fast: false matrix: rid: [win-x64, linux-x64] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 + with: + persist-credentials: false - - uses: actions/setup-dotnet@v4 - # The runner user cannot write to system /usr/share/dotnet; install the - # pinned SDK into a runner-writable, cached path instead. + - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 env: DOTNET_INSTALL_DIR: ${{ runner.tool_cache }}/dotnet with: dotnet-version: "8.0.x" - name: Publish single-file self-contained - # Untrimmed on purpose: the host uses reflection-based Avalonia bindings, - # which the trimmer would strip. run: > dotnet publish host/CommonwealthOnline.Host.csproj -c Release @@ -44,8 +41,9 @@ jobs: --nologo - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: CommonwealthOnline.Host-${{ matrix.rid }} path: out/${{ matrix.rid }}/ if-no-files-found: error + retention-days: 7 From 30142c97061c6b51d4aae20dfec06be9ad058e0c Mon Sep 17 00:00:00 2001 From: Nomads_Reach <144523850+NomadsReach@users.noreply.github.com> Date: Mon, 17 Aug 2026 15:52:19 -0400 Subject: [PATCH 6/7] Move Gitea sync to isolated trusted runner and stop persisting token --- .github/workflows/open-gitea-pr.yml | 70 +++++++++++++++++------------ 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/.github/workflows/open-gitea-pr.yml b/.github/workflows/open-gitea-pr.yml index bc4c4d7..e2d579d 100644 --- a/.github/workflows/open-gitea-pr.yml +++ b/.github/workflows/open-gitea-pr.yml @@ -1,9 +1,5 @@ name: Open Gitea PR on merge to main -# When main changes on GitHub (i.e. after a PR is merged here), push those -# commits to a branch on Gitea and open a pull request there, so the same -# change can be reviewed and landed on the Gitea side. One-way: GitHub -> Gitea. - on: push: branches: [main] @@ -14,15 +10,12 @@ permissions: jobs: open-gitea-pr: - # GitHub-hosted runners are billing-blocked for this org, so the hosted job - # never started. Run on the self-hosted runner, which also has LAN access to - # the Gitea host. This workflow only fires on push to main (never on PRs from - # forks), so it is safe on the private runner. - runs-on: [self-hosted, Linux, X64] + runs-on: [self-hosted, Linux, X64, co-server-sync] steps: - - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with: fetch-depth: 0 + persist-credentials: false - name: Push main to Gitea and open a pull request env: @@ -33,38 +26,59 @@ jobs: SYNC_BRANCH: sync/from-github run: | set -euo pipefail + umask 077 + if [ -z "${GITEA_TOKEN:-}" ]; then - echo "::error::Missing GITEA_TOKEN secret. Add a Gitea access token as a" - echo "::error::repository secret named GITEA_TOKEN (Settings -> Secrets and" - echo "::error::variables -> Actions -> New repository secret)." + echo "::error::Missing GITEA_TOKEN repository secret." exit 1 fi - git config user.name "github-sync" - git config user.email "github-sync@users.noreply.github.com" + askpass="${RUNNER_TEMP}/gitea-askpass-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}.sh" + header_file="${RUNNER_TEMP}/gitea-header-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" + response_file="${RUNNER_TEMP}/gitea-pr-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}.json" - # Mirror the current main onto a dedicated Gitea branch. Force is safe: - # this branch is owned by the automation and only ever tracks GitHub main. - git remote add gitea "https://${GITEA_USER}:${GITEA_TOKEN}@${GITEA_HOST}/${GITEA_REPO}.git" + cleanup() { + git remote remove gitea >/dev/null 2>&1 || true + rm -f -- "$askpass" "$header_file" "$response_file" + } + trap cleanup EXIT + + cat > "$askpass" <<'EOF' + #!/usr/bin/env bash + case "$1" in + *Username*) printf '%s\n' "${GITEA_USER:?}" ;; + *Password*) printf '%s\n' "${GITEA_TOKEN:?}" ;; + *) exit 1 ;; + esac + EOF + chmod 700 "$askpass" + printf 'Authorization: token %s\n' "$GITEA_TOKEN" > "$header_file" + chmod 600 "$header_file" + + export GIT_ASKPASS="$askpass" + export GIT_TERMINAL_PROMPT=0 + + git config user.name "github-sync" + git config user.email "github-sync@users.noreply.github.com" + git remote remove gitea >/dev/null 2>&1 || true + git remote add gitea "https://${GITEA_HOST}/${GITEA_REPO}.git" git push -f gitea "HEAD:refs/heads/${SYNC_BRANCH}" - # Open a PR on Gitea: sync/from-github -> main. If one is already open, - # the push above has already updated it, so a 409 is success too. - http_code=$(curl -sS -o /tmp/gitea_pr.json -w "%{http_code}" -X POST \ + http_code=$(curl -sS -o "$response_file" -w "%{http_code}" -X POST \ "https://${GITEA_HOST}/api/v1/repos/${GITEA_REPO}/pulls" \ - -H "Authorization: token ${GITEA_TOKEN}" \ + -H "@${header_file}" \ -H "Content-Type: application/json" \ - -d "{\"title\":\"Sync from GitHub main\",\"head\":\"${SYNC_BRANCH}\",\"base\":\"main\",\"body\":\"Automated: GitHub main was updated. Review and merge to land it on Gitea.\"}") + -d "{\"title\":\"Sync from GitHub main\",\"head\":\"${SYNC_BRANCH}\",\"base\":\"main\",\"body\":\"GitHub main was updated. Review and merge to land it on Gitea.\"}") echo "Gitea pulls API returned HTTP ${http_code}" - cat /tmp/gitea_pr.json || true + cat "$response_file" || true echo - if [ "${http_code}" = "201" ]; then + if [ "$http_code" = "201" ]; then echo "Opened a new Gitea pull request." - elif [ "${http_code}" = "409" ] || grep -qiE "already exist|issue_exist" /tmp/gitea_pr.json; then + elif [ "$http_code" = "409" ] || grep -qiE "already exist|issue_exist" "$response_file"; then echo "A Gitea PR from ${SYNC_BRANCH} is already open; it now has the latest commits." else - echo "::warning::Unexpected Gitea response (${http_code}). The branch was pushed;" - echo "::warning::open the PR manually on Gitea if it did not appear." + echo "::error::Unexpected Gitea response (${http_code})." + exit 1 fi From 9c5c16caf87f39394b2542105956e2afa81ebf2e Mon Sep 17 00:00:00 2001 From: Nomads_Reach <144523850+NomadsReach@users.noreply.github.com> Date: Mon, 17 Aug 2026 16:02:56 -0400 Subject: [PATCH 7/7] Disable Git credential helpers during Gitea sync --- .github/workflows/open-gitea-pr.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/open-gitea-pr.yml b/.github/workflows/open-gitea-pr.yml index e2d579d..78ff0d5 100644 --- a/.github/workflows/open-gitea-pr.yml +++ b/.github/workflows/open-gitea-pr.yml @@ -62,7 +62,8 @@ jobs: git config user.email "github-sync@users.noreply.github.com" git remote remove gitea >/dev/null 2>&1 || true git remote add gitea "https://${GITEA_HOST}/${GITEA_REPO}.git" - git push -f gitea "HEAD:refs/heads/${SYNC_BRANCH}" + git -c credential.helper= -c credential.useHttpPath=true \ + push -f gitea "HEAD:refs/heads/${SYNC_BRANCH}" http_code=$(curl -sS -o "$response_file" -w "%{http_code}" -X POST \ "https://${GITEA_HOST}/api/v1/repos/${GITEA_REPO}/pulls" \