From 15db414dc279f291b8020e141dd6f185409ba00b Mon Sep 17 00:00:00 2001 From: ilia Date: Fri, 29 May 2026 16:19:15 -0500 Subject: [PATCH 1/6] ci: add homelab Gitea Actions workflow (ci-node.yml) --- .gitea/workflows/ci.yml | 259 ++++++---------------------------------- 1 file changed, 36 insertions(+), 223 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index fad2e5c..f53f526 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,3 +1,5 @@ +--- +# Homelab CI โ€” Node/pages lane (git-ci-01) + secret scan (git-ci-02) name: CI on: @@ -7,245 +9,56 @@ on: types: [opened, synchronize, reopened] jobs: - # Check if CI should be skipped based on branch name or commit message skip-ci-check: - runs-on: ubuntu-latest + runs-on: [homelab, self-hosted, linux] outputs: should-skip: ${{ steps.check.outputs.skip }} steps: - - name: Check out code (for commit message) - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: fetch-depth: 1 - - - name: Check if CI should be skipped - id: check + - id: check run: | - # Simple skip pattern: @skipci (case-insensitive) - SKIP_PATTERN="@skipci" - - # Get branch name (works for both push and PR) - BRANCH_NAME="${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" - - # Get commit message (works for both push and PR) - COMMIT_MSG="${GITHUB_EVENT_HEAD_COMMIT_MESSAGE:-}" - if [ -z "$COMMIT_MSG" ]; then - COMMIT_MSG="${GITHUB_EVENT_PULL_REQUEST_HEAD_COMMIT_MESSAGE:-}" - fi - if [ -z "$COMMIT_MSG" ]; then - COMMIT_MSG=$(git log -1 --pretty=%B 2>/dev/null || echo "") - fi - SKIP=0 - - # Check branch name (case-insensitive) - if echo "$BRANCH_NAME" | grep -qiF "$SKIP_PATTERN"; then - echo "Skipping CI: branch name contains '$SKIP_PATTERN'" - SKIP=1 - fi - - # Check commit message (case-insensitive) - if [ $SKIP -eq 0 ] && [ -n "$COMMIT_MSG" ]; then - if echo "$COMMIT_MSG" | grep -qiF "$SKIP_PATTERN"; then - echo "Skipping CI: commit message contains '$SKIP_PATTERN'" - SKIP=1 - fi - fi - + BRANCH="${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" + MSG="${GITHUB_EVENT_HEAD_COMMIT_MESSAGE:-$(git log -1 --pretty=%B 2>/dev/null || true)}" + echo "$BRANCH" "$MSG" | grep -qi '@skipci' && SKIP=1 echo "skip=$SKIP" >> $GITHUB_OUTPUT - echo "Branch: $BRANCH_NAME" - echo "Commit: ${COMMIT_MSG:0:50}..." - echo "Skip CI: $SKIP" - lint-and-type-check: - needs: skip-ci-check - runs-on: ubuntu-latest - if: needs.skip-ci-check.outputs.should-skip != '1' - container: - image: node:20-bullseye - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Install dependencies - run: npm ci - - - name: Run ESLint - run: npm run lint - - - name: Type check - run: npm run type-check - - test: - needs: skip-ci-check - runs-on: ubuntu-latest - if: needs.skip-ci-check.outputs.should-skip != '1' - container: - image: node:20-bullseye - services: - postgres: - image: postgres:15 - env: - POSTGRES_PASSWORD: postgres - POSTGRES_DB: mirrormatch_test - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - env: - DATABASE_URL: postgresql://postgres:postgres@postgres:5432/mirrormatch_test?schema=public - NEXTAUTH_SECRET: test-secret-key-for-ci - NEXTAUTH_URL: http://localhost:3000 - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Install dependencies - run: npm ci - - - name: Generate Prisma Client - run: npm run db:generate - - - name: Run database migrations - run: npm run db:push - - - name: Run tests - run: npm run test:ci - - - name: Upload coverage reports - uses: codecov/codecov-action@v4 - with: - files: ./coverage/coverage-final.json - flags: unittests - name: codecov-umbrella - fail_ci_if_error: false - continue-on-error: true - - build: - needs: skip-ci-check - runs-on: ubuntu-latest - if: needs.skip-ci-check.outputs.should-skip != '1' - container: - image: node:20-bullseye - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Install dependencies - run: npm ci - - - name: Generate Prisma Client - run: npm run db:generate - - - name: Build application - run: npm run build - env: - DATABASE_URL: postgresql://postgres:postgres@localhost:5432/mirrormatch?schema=public - NEXTAUTH_SECRET: test-secret-key-for-ci - NEXTAUTH_URL: http://localhost:3000 - - secret-scanning: + node-ci: needs: skip-ci-check if: needs.skip-ci-check.outputs.should-skip != '1' - runs-on: ubuntu-latest + runs-on: [homelab, self-hosted, linux, node] container: - image: zricethezav/gitleaks:latest + image: node:20-bookworm steps: - - name: Install Node.js for checkout action + - uses: actions/checkout@v4 + + - name: npm ci run: | - apk add --no-cache nodejs npm curl + if [ -f package-lock.json ]; then npm ci; elif [ -f package.json ]; then npm install; else exit 0; fi - - name: Check out code - uses: actions/checkout@v4 + - name: Lint + run: npm run lint --if-present + + - name: Test + run: npm test --if-present + + - name: Build + run: npm run build --if-present + + - name: npm audit (advisory) + run: npm audit --audit-level=high || true + + secret-scan: + needs: skip-ci-check + if: needs.skip-ci-check.outputs.should-skip != '1' + runs-on: [homelab, self-hosted, linux, heavy] + steps: + - uses: actions/checkout@v4 with: fetch-depth: 0 - - - name: Scan for secrets - run: gitleaks detect --source . --no-banner --redact --exit-code 0 - continue-on-error: true - - dependency-scan: - needs: skip-ci-check - if: needs.skip-ci-check.outputs.should-skip != '1' - runs-on: ubuntu-latest - container: - image: aquasec/trivy:latest - steps: - - name: Install Node.js for checkout action + - name: Gitleaks run: | - apk add --no-cache nodejs npm curl - - - name: Check out code - uses: actions/checkout@v4 - - - name: Dependency vulnerability scan (Trivy) - run: | - trivy fs \ - --scanners vuln \ - --severity HIGH,CRITICAL \ - --ignore-unfixed \ - --timeout 10m \ - --skip-dirs .git,node_modules \ - --exit-code 0 \ - . - - - name: Secret scan (Trivy) - run: | - trivy fs \ - --scanners secret \ - --timeout 10m \ - --skip-dirs .git,node_modules \ - --exit-code 0 \ - . - - sast-scan: - needs: skip-ci-check - if: needs.skip-ci-check.outputs.should-skip != '1' - runs-on: ubuntu-latest - container: - image: ubuntu:22.04 - steps: - - name: Install Node.js for checkout action - run: | - apt-get update && apt-get install -y curl - curl -fsSL https://deb.nodesource.com/setup_20.x | bash - - apt-get install -y nodejs - - - name: Check out code - uses: actions/checkout@v4 - - - name: Install Semgrep - run: | - apt-get update && apt-get install -y python3 python3-pip - pip3 install semgrep - - - name: Run Semgrep scan - run: semgrep --config=auto --error - continue-on-error: true - - workflow-summary: - runs-on: ubuntu-latest - needs: [lint-and-type-check, test, build, secret-scanning, dependency-scan, sast-scan] - if: always() - steps: - - name: Generate workflow summary - run: | - echo "## ๐Ÿ” CI Workflow Summary" >> $GITHUB_STEP_SUMMARY || true - echo "" >> $GITHUB_STEP_SUMMARY || true - echo "### Job Results" >> $GITHUB_STEP_SUMMARY || true - echo "" >> $GITHUB_STEP_SUMMARY || true - echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY || true - echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY || true - echo "| ๐Ÿ“ Lint & Type Check | ${{ needs.lint-and-type-check.result }} |" >> $GITHUB_STEP_SUMMARY || true - echo "| ๐Ÿงช Tests | ${{ needs.test.result }} |" >> $GITHUB_STEP_SUMMARY || true - echo "| ๐Ÿ—๏ธ Build | ${{ needs.build.result }} |" >> $GITHUB_STEP_SUMMARY || true - echo "| ๐Ÿ” Secret Scanning | ${{ needs.secret-scanning.result }} |" >> $GITHUB_STEP_SUMMARY || true - echo "| ๐Ÿ“ฆ Dependency Scan | ${{ needs.dependency-scan.result }} |" >> $GITHUB_STEP_SUMMARY || true - echo "| ๐Ÿ” SAST Scan | ${{ needs.sast-scan.result }} |" >> $GITHUB_STEP_SUMMARY || true - echo "" >> $GITHUB_STEP_SUMMARY || true - echo "### ๐Ÿ“Š Summary" >> $GITHUB_STEP_SUMMARY || true - echo "" >> $GITHUB_STEP_SUMMARY || true - echo "All security and validation checks have completed." >> $GITHUB_STEP_SUMMARY || true + docker run --rm -v "$PWD:/repo" ghcr.io/gitleaks/gitleaks:latest \ + detect --source /repo --no-banner --redact From 06616a4d9a351a19eb5760fc1c361e2363ceda2b Mon Sep 17 00:00:00 2001 From: ilia Date: Fri, 29 May 2026 20:14:49 -0500 Subject: [PATCH 2/6] ci: sync workflow template (node container + host fixes) --- .gitea/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index f53f526..cf36397 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -11,6 +11,8 @@ on: jobs: skip-ci-check: runs-on: [homelab, self-hosted, linux] + container: + image: node:20-bookworm outputs: should-skip: ${{ steps.check.outputs.skip }} steps: From 5d32f35d68b543c132f0c526eee89a9d17d3b3ff Mon Sep 17 00:00:00 2001 From: ilia Date: Fri, 29 May 2026 20:20:29 -0500 Subject: [PATCH 3/6] ci: refresh workflow (re-run pipelines) --- .gitea/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index cf36397..41e14a0 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,4 +1,5 @@ --- +# ci-sync: 2026-05-30T01:20:35Z # Homelab CI โ€” Node/pages lane (git-ci-01) + secret scan (git-ci-02) name: CI From a6cd900c388f94d609d06b45e0d57800dd219bff Mon Sep 17 00:00:00 2001 From: ilia Date: Fri, 29 May 2026 20:25:59 -0500 Subject: [PATCH 4/6] ci: sync workflow template --- .gitea/workflows/ci.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 41e14a0..4793707 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,5 +1,4 @@ --- -# ci-sync: 2026-05-30T01:20:35Z # Homelab CI โ€” Node/pages lane (git-ci-01) + secret scan (git-ci-02) name: CI @@ -41,6 +40,15 @@ jobs: run: | if [ -f package-lock.json ]; then npm ci; elif [ -f package.json ]; then npm install; else exit 0; fi + - name: Playwright browsers + run: | + if [ -f playwright.config.ts ] || [ -f playwright.config.js ] || [ -f playwright.config.mjs ] \ + || grep -q '@playwright/test' package.json 2>/dev/null; then + npx playwright install --with-deps chromium + else + echo "No Playwright โ€” skip browser install" + fi + - name: Lint run: npm run lint --if-present From b4464b417183fa6f8a2898aa48aa49d988549cb6 Mon Sep 17 00:00:00 2001 From: ilia Date: Fri, 29 May 2026 20:28:22 -0500 Subject: [PATCH 5/6] ci: refresh workflow (re-run pipelines) --- .gitea/workflows/ci.yml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 4793707..746af4d 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,4 +1,5 @@ --- +# ci-sync: 2026-05-30T01:28:29Z # Homelab CI โ€” Node/pages lane (git-ci-01) + secret scan (git-ci-02) name: CI @@ -56,7 +57,20 @@ jobs: run: npm test --if-present - name: Build - run: npm run build --if-present + env: + NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }} + NEXTAUTH_URL: ${{ secrets.NEXTAUTH_URL }} + AUTH_SECRET: ${{ secrets.AUTH_SECRET }} + DATABASE_URL: ${{ secrets.DATABASE_URL }} + run: | + export CI=true + # Placeholders so Next.js/NextAuth can compile in CI without real secrets. + # Override via Gitea repo Actions secrets when you need production-like builds. + export NEXTAUTH_SECRET="${NEXTAUTH_SECRET:-ci-build-placeholder-not-for-production}" + export AUTH_SECRET="${AUTH_SECRET:-$NEXTAUTH_SECRET}" + export NEXTAUTH_URL="${NEXTAUTH_URL:-http://localhost:3000}" + export DATABASE_URL="${DATABASE_URL:-postgresql://ci:ci@127.0.0.1:5432/ci?schema=public}" + npm run build --if-present - name: npm audit (advisory) run: npm audit --audit-level=high || true From f552ba0ae72c118955a8cf74dd242192004a5018 Mon Sep 17 00:00:00 2001 From: ilia Date: Fri, 29 May 2026 20:30:44 -0500 Subject: [PATCH 6/6] ci: refresh workflow (re-run pipelines) --- .gitea/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 746af4d..7bdc2c9 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,5 +1,5 @@ --- -# ci-sync: 2026-05-30T01:28:29Z +# ci-sync: 2026-05-30T01:30:48Z # Homelab CI โ€” Node/pages lane (git-ci-01) + secret scan (git-ci-02) name: CI