From 8d8bddb454f2c7adda1b0e0afd57f29a6d2f4118 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Wed, 23 Sep 2026 14:51:38 +0700 Subject: [PATCH] =?UTF-8?q?ci(cd):=20turbo-=D0=BA=D1=8D=D1=88,=20=D0=B3?= =?UTF-8?q?=D0=B5=D0=B9=D1=82=D1=8B=20typecheck/lint,=20=D1=82=D0=B0=D0=B9?= =?UTF-8?q?=D0=BC=D0=B0=D1=83=D1=82=D1=8B,=20non-root=20=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .turbo в actions/cache (пересборки shared/db переиспользуются между прогонами) - typecheck в web/api джобах, lint бэкенда в api-джобе - убран пустой turbo test --filter=web (в web нет тестов) - timeout-minutes на все джобы - Dockerfile: USER node + --chown; прекомпрессия статики gzip+brotli на этапе сборки (Traefik не сжимает); compose: chown 1000:1000 data в инструкции --- .gitea/workflows/cd.yaml | 1 + .gitea/workflows/quality.yaml | 15 ++++++++++++--- deploy/docker-compose.traefik.yml | 1 + deploy/docker/authportal/Dockerfile | 11 +++++++++-- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index 610e8a3..1f83ccc 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -25,6 +25,7 @@ jobs: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') && needs.quality.result == 'success' runs-on: ubuntu-latest + timeout-minutes: 30 permissions: contents: write packages: write diff --git a/.gitea/workflows/quality.yaml b/.gitea/workflows/quality.yaml index 88b2d97..bce4251 100644 --- a/.gitea/workflows/quality.yaml +++ b/.gitea/workflows/quality.yaml @@ -33,6 +33,7 @@ permissions: jobs: changes: runs-on: ubuntu-latest + timeout-minutes: 5 outputs: web: ${{ steps.detect.outputs.web }} api: ${{ steps.detect.outputs.api }} @@ -148,6 +149,7 @@ jobs: needs: [changes] if: needs.changes.outputs.web == 'true' runs-on: ubuntu-latest + timeout-minutes: 15 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 @@ -163,6 +165,7 @@ jobs: path: | ${{ env.PNPM_STORE_DIR }} ${{ env.COREPACK_HOME }} + .turbo node_modules apps/web/node_modules apps/api/node_modules @@ -172,20 +175,21 @@ jobs: key: pnpm-${{ runner.os }}-${{ steps.pnpm-hash.outputs.key }} restore-keys: | pnpm-${{ runner.os }}- - - name: pnpm install, lint, test, build + - name: pnpm install, lint, typecheck, build env: PNPM_CACHE_HIT: ${{ steps.pnpm-cache.outputs.cache-hit }} run: | set -euxo pipefail sh scripts/ci/pnpm-ci.sh pnpm --filter web lint - pnpm exec turbo run test --filter=web + pnpm exec turbo run typecheck --filter=web pnpm exec turbo run build --filter=web api: needs: [changes] if: needs.changes.outputs.api == 'true' runs-on: ubuntu-latest + timeout-minutes: 15 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 @@ -201,6 +205,7 @@ jobs: path: | ${{ env.PNPM_STORE_DIR }} ${{ env.COREPACK_HOME }} + .turbo node_modules apps/web/node_modules apps/api/node_modules @@ -210,18 +215,21 @@ jobs: key: pnpm-${{ runner.os }}-${{ steps.pnpm-hash.outputs.key }} restore-keys: | pnpm-${{ runner.os }}- - - name: pnpm install, test, build + - name: pnpm install, lint, test, typecheck, build env: PNPM_CACHE_HIT: ${{ steps.pnpm-cache.outputs.cache-hit }} run: | set -euxo pipefail sh scripts/ci/pnpm-ci.sh + pnpm exec turbo run lint --filter=@authportal/api --filter=@authportal/db --filter=@authportal/shared pnpm exec turbo run test --filter=@authportal/api + pnpm exec turbo run typecheck --filter=@authportal/api pnpm exec turbo run build --filter=@authportal/api commitlint: if: inputs.is_pull_request runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: @@ -262,6 +270,7 @@ jobs: needs: [changes] if: inputs.is_pull_request && needs.changes.outputs.docker == 'true' runs-on: ubuntu-latest + timeout-minutes: 20 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 diff --git a/deploy/docker-compose.traefik.yml b/deploy/docker-compose.traefik.yml index 4d1d8a7..ab1b62a 100644 --- a/deploy/docker-compose.traefik.yml +++ b/deploy/docker-compose.traefik.yml @@ -3,6 +3,7 @@ # # On server: # mkdir -p /opt/auth-portal/data +# chown -R 1000:1000 /opt/auth-portal/data # container runs as non-root "node" # cp deploy/docker-compose.traefik.yml /opt/auth-portal/docker-compose.yml # cp deploy/env.traefik.example /opt/auth-portal/.env # fill secrets # docker login git.shx.one diff --git a/deploy/docker/authportal/Dockerfile b/deploy/docker/authportal/Dockerfile index 248dc59..97d7bda 100644 --- a/deploy/docker/authportal/Dockerfile +++ b/deploy/docker/authportal/Dockerfile @@ -16,6 +16,7 @@ RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ pnpm install --frozen-lockfile FROM deps AS build +RUN apk add --no-cache brotli COPY apps/web apps/web COPY apps/api apps/api COPY packages/ui packages/ui @@ -25,6 +26,8 @@ RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ pnpm turbo build --filter=web --filter=@authportal/api \ && pnpm --filter @authportal/api deploy --prod /out \ && cp -r apps/web/dist /out/static \ + && find /out/static -type f \( -name '*.js' -o -name '*.css' \) -exec sh -c \ + 'gzip -k9 "$1" && brotli -f -q 11 -o "$1.br" "$1"' _ {} \; \ && rm -rf /out/src /out/test /out/.turbo \ && rm -rf /out/node_modules/@authportal/db/src /out/node_modules/@authportal/db/scripts /out/node_modules/@authportal/db/.turbo \ && rm -rf /out/node_modules/@authportal/shared/src /out/node_modules/@authportal/shared/.turbo \ @@ -32,7 +35,10 @@ RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ FROM ${BASE_NODE} AS runtime WORKDIR /app -RUN apk add --no-cache ca-certificates +# Не-root runtime; /data — bind mount с хоста, на сервере нужен +# `chown -R 1000:1000 ./data` (см. deploy/docker-compose.traefik.yml). +RUN apk add --no-cache ca-certificates \ + && mkdir -p /data && chown node:node /data ARG VERSION=dev ARG GIT_SHA=unknown ARG BUILD_TIME= @@ -43,7 +49,8 @@ ENV NODE_ENV=production \ APP_VERSION=${VERSION} \ GIT_SHA=${GIT_SHA} \ BUILD_TIME=${BUILD_TIME} -COPY --from=build /out ./ +COPY --from=build --chown=node:node /out ./ +USER node EXPOSE 8080 VOLUME ["/data"] HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \