From c053b8de87dd27e8afc4a1f0b0ebc45cf257c7b8 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Sat, 18 Jul 2026 20:01:25 +0200 Subject: [PATCH] fix(deploy): reclaim www-data ownership before git reset Stale host sources survived reset when files were owned by www-data, leaving an old nitro editor with a removed Json type that failed typecheck. Co-authored-by: Cursor --- .gitea/workflows/deploy.yaml | 16 ++++++++++++++++ .../admin/import/furni/nitro-editor-dialog.tsx | 1 + src/lib/deploy-workflow-contract.test.ts | 10 ++++++++++ 3 files changed, 27 insertions(+) diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml index b795a530..33805c4c 100644 --- a/.gitea/workflows/deploy.yaml +++ b/.gitea/workflows/deploy.yaml @@ -33,6 +33,14 @@ jobs: # 2. Navigate to your website directory cd /var/www/atom-nexst/ + DEPLOY_USER="$(id -un)" + DEPLOY_GROUP="$(id -gn)" + + # CRITICAL: last deploy chowns the tree to www-data. Reclaim ownership + # BEFORE git reset, otherwise stale sources (e.g. old nitro editor with + # a removed Json type) can survive and break typecheck. + sudo chown -R "${DEPLOY_USER}:${DEPLOY_GROUP}" /var/www/atom-nexst/ + # CRITICAL: Prevent Git permission blocks caused by the www-data ownership change git config --global --add safe.directory /var/www/atom-nexst @@ -44,6 +52,8 @@ jobs: git reset --hard origin/main # Drop stray untracked sources left on the host (keep secrets/env). git clean -fd -e .env -e .env.local -e .env.production -e .env*.local -- src + # Force-refresh sources after reclaiming ownership (belt-and-suspenders). + git checkout -f HEAD -- src # Preserve .next/cache so Next.js can reuse its incremental build cache. rm -rf .output dist @@ -53,6 +63,12 @@ jobs: export NEXT_PUBLIC_APP_VERSION="${APP_VERSION}" echo "APP_VERSION=${APP_VERSION}" + # Fail fast if a host-local stale copy still has the removed Json type. + if grep -nE ':\s*Json\b|Json\s*\|' src/app/admin/import/furni/nitro-editor-dialog.tsx; then + echo "ERROR: nitro-editor-dialog.tsx still contains a Json type after checkout" >&2 + exit 1 + fi + # 4. Install — onlyBuiltDependencies comes from pnpm-workspace.yaml # (do not set a PNPM only-built-deps env override here). pnpm install --frozen-lockfile diff --git a/src/app/admin/import/furni/nitro-editor-dialog.tsx b/src/app/admin/import/furni/nitro-editor-dialog.tsx index 352b0fd7..c3068f93 100644 --- a/src/app/admin/import/furni/nitro-editor-dialog.tsx +++ b/src/app/admin/import/furni/nitro-editor-dialog.tsx @@ -39,6 +39,7 @@ interface NitroEditorDialogProps { onOpenChange: (open: boolean) => void; } +/** Nested metadata patch helpers (no ambient Json type — keep this file typecheck-clean). */ function updateNested( obj: Record, path: string, diff --git a/src/lib/deploy-workflow-contract.test.ts b/src/lib/deploy-workflow-contract.test.ts index 65c72c51..32593a96 100644 --- a/src/lib/deploy-workflow-contract.test.ts +++ b/src/lib/deploy-workflow-contract.test.ts @@ -15,6 +15,16 @@ describe("production deploy workflow", () => { expect(workflow).toContain("SKIP_ENV_VALIDATION=1"); }); + it("reclaims ownership before git reset so www-data files can be overwritten", () => { + expect(workflow).toContain('sudo chown -R "${DEPLOY_USER}:${DEPLOY_GROUP}"'); + const reclaimAt = workflow.indexOf( + 'sudo chown -R "${DEPLOY_USER}:${DEPLOY_GROUP}"', + ); + const resetAt = workflow.indexOf("git reset --hard origin/main"); + expect(reclaimAt).toBeGreaterThan(-1); + expect(resetAt).toBeGreaterThan(reclaimAt); + }); + it("does not override onlyBuiltDependencies (uses pnpm-workspace.yaml)", () => { expect(workflow).not.toContain("PNPM_CONFIG_ONLY_BUILT_DEPENDENCIES"); });