From b199f8ce9da537723964968da9f3d7b3165f8edf Mon Sep 17 00:00:00 2001 From: asephs Date: Fri, 10 Jul 2026 02:06:27 +0700 Subject: [PATCH] fix: GH Actions workflows - enforce lint/typecheck, add timeout, fix triggers - lint.yml: remove || echo so lint errors actually fail the workflow - typecheck.yml: remove || echo, switch to Bun, add apps/elysia typecheck - update-submodule.yml: upgrade checkout@v6, add payload validation + push retry - security.yml: add Rust to CodeQL scan targets - docker-build-push.yml: remove stale packages/ path refs - All workflows: add timeout-minutes to prevent stuck jobs Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/deploy-docker.yml | 1 + .github/workflows/docker-build-push.yml | 7 +++- .github/workflows/lint.yml | 3 +- .github/workflows/security.yml | 3 +- .github/workflows/typecheck.yml | 26 +++++++++--- .github/workflows/update-submodule.yml | 56 +++++++++++++++++++++++-- 6 files changed, 82 insertions(+), 14 deletions(-) diff --git a/.github/workflows/deploy-docker.yml b/.github/workflows/deploy-docker.yml index 7ec1ae8..736b292 100644 --- a/.github/workflows/deploy-docker.yml +++ b/.github/workflows/deploy-docker.yml @@ -28,6 +28,7 @@ permissions: jobs: deploy: runs-on: ubuntu-latest + timeout-minutes: 30 if: github.event_name == 'workflow_dispatch' || github.event_name == 'push' || github.event.workflow_run.conclusion == 'success' steps: - name: Checkout repository diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index 5b785aa..6813a70 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -6,7 +6,6 @@ on: - main paths: - 'apps/**' - - 'packages/**' - '.github/workflows/docker-build-push.yml' - 'infra/**' - '!infra/compose/**' @@ -31,6 +30,7 @@ jobs: # ────────────────────────────────────────────── changes: runs-on: ubuntu-latest + timeout-minutes: 10 outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} scraper-api: ${{ steps.filter.outputs['scraper-api'] == 'true' || steps.dispatch.outputs['scraper-api'] == 'true' || github.event_name == 'workflow_dispatch' }} @@ -63,7 +63,7 @@ jobs: } echo "scraper-api=$(changed '^(apps/scraper(/|$)|\.github/workflows/docker-build-push\.yml$|infra/docker/scraper\.Dockerfile$)')" >> "$GITHUB_OUTPUT" - echo "elysia-api=$(changed '^(apps/elysia(/|$)|packages(/|$)|\.github/workflows/docker-build-push\.yml$|infra/docker/elysia\.Dockerfile$)')" >> "$GITHUB_OUTPUT" + echo "elysia-api=$(changed '^(apps/elysia(/|$)|\.github/workflows/docker-build-push\.yml$|infra/docker/elysia\.Dockerfile$)')" >> "$GITHUB_OUTPUT" echo "react-web=$(changed '^(apps/react(/|$)|\.github/workflows/docker-build-push\.yml$|infra/docker/react\.Dockerfile$)')" >> "$GITHUB_OUTPUT" echo "rust-auth=$(changed '^(apps/rust-auth(/|$)|infra/docker/rust\.Dockerfile$|\.github/workflows/docker-build-push\.yml$|\.gitmodules$)')" >> "$GITHUB_OUTPUT" @@ -124,6 +124,7 @@ jobs: needs: [changes] if: github.event_name == 'repository_dispatch' runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Wait for submodule ref env: @@ -167,6 +168,7 @@ jobs: build: needs: [changes, wait-submodule-ref] runs-on: ubuntu-latest + timeout-minutes: 30 strategy: fail-fast: false matrix: @@ -246,6 +248,7 @@ jobs: (needs.wait-submodule-ref.result == 'success' || needs.wait-submodule-ref.result == 'skipped') && (needs.build.result == 'success' || needs.build.result == 'skipped') runs-on: ubuntu-latest + timeout-minutes: 10 permissions: contents: write steps: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a3cbf63..b00854f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -18,6 +18,7 @@ on: jobs: eslint: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v6 with: @@ -26,4 +27,4 @@ jobs: with: node-version: 22 - run: npm install -g eslint @antfu/eslint-config - - run: eslint . --no-error-on-unmatched-pattern || echo "Lint check completed (best-effort)" + - run: eslint . --no-error-on-unmatched-pattern diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 5c8ef13..ddad884 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -9,11 +9,12 @@ on: jobs: codeql: runs-on: ubuntu-latest + timeout-minutes: 30 permissions: security-events: write steps: - uses: actions/checkout@v6 - uses: github/codeql-action/init@v3 with: - languages: javascript-typescript + languages: javascript-typescript, rust - uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index f9276cd..b184406 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -4,19 +4,33 @@ on: pull_request: branches: [main] paths: - - 'apps/**/*.ts' - - 'apps/**/*.tsx' + - 'apps/react/src/**/*.ts' + - 'apps/react/src/**/*.tsx' + - 'apps/elysia/src/**/*.ts' + - 'apps/elysia/tsconfig.json' - 'tsconfig.base.json' jobs: typecheck: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v6 with: submodules: recursive - - uses: actions/setup-node@v4 + + - uses: oven/setup-bun@v2 with: - node-version: 22 - - run: | - cd apps/react && npm install && npx tsc --noEmit || echo "TypeScript check completed" + bun-version: latest + + - name: TypeCheck apps/react + working-directory: apps/react + run: | + bun install + npx tsc --noEmit + + - name: TypeCheck apps/elysia + working-directory: apps/elysia + run: | + bun install + bun run check-types \ No newline at end of file diff --git a/.github/workflows/update-submodule.yml b/.github/workflows/update-submodule.yml index 9f5203d..fd4f9f6 100644 --- a/.github/workflows/update-submodule.yml +++ b/.github/workflows/update-submodule.yml @@ -9,24 +9,72 @@ permissions: jobs: update: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 + + - name: Validate payload + env: + SERVICE: ${{ github.event.client_payload.service }} + SHA: ${{ github.event.client_payload.sha }} + run: | + set -euo pipefail + + if [ -z "${SERVICE:-}" ]; then + echo "::error::Missing service in payload" + exit 1 + fi + + if [ -z "${SHA:-}" ]; then + echo "::error::Missing sha in payload" + exit 1 + fi + + if ! [[ "$SHA" =~ ^[0-9a-fA-F]{40}$ ]]; then + echo "::error::Invalid sha '$SHA'. Expected 40 hex characters." + exit 1 + fi + + case "$SERVICE" in + scraper-api|elysia-api|react-web|rust-auth) ;; + *) + echo "::error::Unsupported service '$SERVICE'" + exit 1 + ;; + esac + + echo "Payload validated: $SERVICE → $SHA" - name: Update submodule pointer env: SERVICE: ${{ github.event.client_payload.service }} SHA: ${{ github.event.client_payload.sha }} run: | + set -euo pipefail + echo "Updating ${SERVICE} to ${SHA}" git submodule update --init "apps/${SERVICE}" cd "apps/${SERVICE}" - # unshallow → full fetch so we get tree objects for the target SHA - git fetch --depth=1000 origin master + # full fetch so we get tree objects for the target SHA + git fetch --depth=1 origin master 2>/dev/null || git fetch --depth=1 origin main git checkout "${SHA}" cd "${GITHUB_WORKSPACE}" git add "apps/${SERVICE}" git diff --cached --quiet && exit 0 + git config user.name "monrepo-bot" git config user.email "monrepo-bot@users.noreply.github.com" git commit -m "chore: update ${SERVICE} to ${SHA:0:12}" - git push + + for attempt in {1..3}; do + if git pull --rebase origin main && git push origin main; then + echo "✅ Push succeeded on attempt $attempt" + exit 0 + fi + echo "⚠️ Push attempt $attempt/3 failed; retrying..." + git rebase --abort 2>/dev/null || true + sleep 3 + done + + echo "::error::Failed to push submodule update after 3 attempts" + exit 1