From 7ca0014da2adcc18498ecd8258a23cdb8a0759b8 Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 15:12:42 +0800 Subject: [PATCH 01/12] =?UTF-8?q?fix(ci):=20Validate=20job=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=8B=AC=E7=AB=8BPG=E5=AE=B9=E5=99=A8=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8Dalembic=E8=BF=81=E7=A7=BB=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5\n\n=E6=A0=B9=E5=9B=A0=EF=BC=9Aalembic=20upgr?= =?UTF-8?q?ade=20head=20--sql=E9=9C=80=E8=A6=81=E8=BF=9E=E6=8E=A5=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E8=AF=BB=E5=8F=96alembic=5Fversion=E8=A1=A8?= =?UTF-8?q?=EF=BC=8C\n=E4=BD=86Validate=20job=E6=B2=A1=E6=9C=89=E5=90=AF?= =?UTF-8?q?=E5=8A=A8PostgreSQL=E5=AE=B9=E5=99=A8=EF=BC=8CDATABASE=5FURL?= =?UTF-8?q?=E6=8C=87=E5=90=91=E4=B8=8D=E5=AD=98=E5=9C=A8=E7=9A=84=E7=AB=AF?= =?UTF-8?q?=E5=8F=A3=E3=80=82\n\n=E4=BF=AE=E5=A4=8D=EF=BC=9A=E5=9C=A8Valid?= =?UTF-8?q?ate=20Alembic=20migrations=E6=AD=A5=E9=AA=A4=E5=89=8D=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E4=B8=80=E4=B8=AA=E7=8B=AC=E7=AB=8BPG=E5=AE=B9?= =?UTF-8?q?=E5=99=A8=EF=BC=8C\n=E7=94=A8=E9=9A=8F=E6=9C=BA=E7=AB=AF?= =?UTF-8?q?=E5=8F=A3=E6=98=A0=E5=B0=84=EF=BC=8C=E9=80=9A=E8=BF=87GITHUB=5F?= =?UTF-8?q?ENV=E6=9B=B4=E6=96=B0DATABASE=5FURL=E3=80=82\n=E6=AD=A5?= =?UTF-8?q?=E9=AA=A4=E7=BB=93=E6=9D=9F=E5=90=8E=E8=87=AA=E5=8A=A8=E6=B8=85?= =?UTF-8?q?=E7=90=86=E5=AE=B9=E5=99=A8=EF=BC=88always()=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E4=B9=9F=E6=B8=85=E7=90=86=EF=BC=89=E3=80=82?= =?UTF-8?q?\n\n=E5=8F=82=E8=80=83PR=20#399=E7=9A=84=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=EF=BC=8C=E6=9C=80=E5=B0=8F=E6=94=B9=E5=8A=A8=E7=89=88=E6=9C=AC?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E6=8B=86=E5=88=86job=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/ci-cd.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 421d63385..d915f7f52 100755 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -129,6 +129,10 @@ jobs: bash -n scripts/init_production_env.sh ' + - name: Start PostgreSQL for validate (isolated container) + shell: sh + run: "set -eu\nPG_CONTAINER=\"ci-pg-validate-${GITHUB_RUN_ID:-$$}\"\necho \"PG_CONTAINER=$PG_CONTAINER\" >> \"$GITHUB_ENV\"\ndocker rm -f \"$PG_CONTAINER\" 2>/dev/null || true\ndocker run -d --name \"$PG_CONTAINER\" \\\n --shm-size=256m \\\n -e POSTGRES_USER=postgres \\\n -e POSTGRES_PASSWORD=postgres \\\n -e POSTGRES_DB=xiaoxia_saas \\\n -P \\\n --health-cmd \"pg_isready -U postgres\" \\\n --health-interval 3s \\\n --health-timeout 3s \\\n --health-retries 20 \\\n postgres:16-alpine\nPG_PORT=$(docker port \"$PG_CONTAINER\" 5432/tcp | cut -d: -f2)\necho \"PostgreSQL port: $PG_PORT\"\necho \"DATABASE_URL=postgresql+psycopg://postgres:postgres@127.0.0.1:$PG_PORT/xiaoxia_saas\" >> \"$GITHUB_ENV\"\nfor i in $(seq 1 30); do\n if docker inspect --format='{{.State.Health.Status}}' \"$PG_CONTAINER\" 2>/dev/null | grep -q healthy; then\n echo \"PostgreSQL is ready on port $PG_PORT\"\n break\n fi\n echo \"Waiting for PostgreSQL... ($i/30)\"\n sleep 2\ndone\ndocker inspect --format='{{.State.Health.Status}}' \"$PG_CONTAINER\" | grep -q healthy\n" + - name: Validate Alembic migrations shell: sh run: 'set -eu @@ -147,6 +151,14 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} run: "set -eu\npython3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/develop\n" + - name: Cleanup PostgreSQL (validate) + if: always() + shell: sh + run: 'set +e + docker rm -f "${PG_CONTAINER:-ci-pg-validate}" 2>/dev/null || true + echo "PostgreSQL container cleaned up" + ' + - name: Job duration summary if: always() shell: sh -- 2.54.0 From 31aa3fbb86afd838160cb3f93ab3d292d2ad1d89 Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 15:35:58 +0800 Subject: [PATCH 02/12] =?UTF-8?q?fix(ci):=20=E4=BF=AE=E5=A4=8Ddevelop?= =?UTF-8?q?=E5=88=86=E6=94=AF=E9=81=97=E7=95=99=E7=9A=84isort=20import?= =?UTF-8?q?=E6=8E=92=E5=BA=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复edit_plans_clips.py和edit_plans_clips_batch.py的import排序, 确保全量isort扫描通过。 --- apps/api/app/api/routes/edit_plans_clips.py | 7 +++++-- apps/api/app/api/routes/edit_plans_clips_batch.py | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/api/app/api/routes/edit_plans_clips.py b/apps/api/app/api/routes/edit_plans_clips.py index 544ec6d46..81342a132 100755 --- a/apps/api/app/api/routes/edit_plans_clips.py +++ b/apps/api/app/api/routes/edit_plans_clips.py @@ -52,7 +52,9 @@ class EditPlanClipListResponse(BaseModel): class EditPlanClipCreateRequest(BaseModel): """创建剪辑片段请求体""" - clip_type: str = Field(..., min_length=1, max_length=50, description="片段类型: main/intro/outro/overlay/background/b_roll 等") + clip_type: str = Field( + ..., min_length=1, max_length=50, description="片段类型: main/intro/outro/overlay/background/b_roll 等" + ) order: int = Field(..., ge=0, description="排序序号") asset_id: str = Field(default="", max_length=64, description="关联素材 ID") text_content: str = Field(default="", max_length=5000, description="文本内容(字幕/配音等)") @@ -86,9 +88,10 @@ def _check_plan_access(plan_id: str, user_id: str, project_repository: Any, db: """验证用户是否有权限访问该剪辑计划(通过项目关联)。 返回 plan 对象供后续使用,避免重复查询。 """ - from ._helpers import check_project_access from app.services.edit_plan_service import EditPlanService + from ._helpers import check_project_access + svc = EditPlanService(db) plan = svc.get_plan(plan_id) if plan is None: diff --git a/apps/api/app/api/routes/edit_plans_clips_batch.py b/apps/api/app/api/routes/edit_plans_clips_batch.py index 29af9cf20..bb4a1fb7b 100755 --- a/apps/api/app/api/routes/edit_plans_clips_batch.py +++ b/apps/api/app/api/routes/edit_plans_clips_batch.py @@ -75,9 +75,10 @@ class ClipsFromAssetsResponse(BaseModel): def _check_plan_access(plan_id: str, user_id: str, project_repository: Any, db: Session) -> Any: """验证用户是否有权限访问该剪辑计划,返回 plan 对象。""" - from ._helpers import check_project_access from app.services.edit_plan_service import EditPlanService + from ._helpers import check_project_access + svc = EditPlanService(db) plan = svc.get_plan(plan_id) if plan is None: -- 2.54.0 From f4b7bec0cb6a5ac38932c26a5a32f13ae6e2691f Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 16:07:21 +0800 Subject: [PATCH 03/12] =?UTF-8?q?fix(ci):=20PG=E5=90=AF=E5=8A=A8+alembic?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=B8=BA=E5=8D=95=E6=AD=A5=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DGITHUB=5FENV=E4=BC=A0=E5=8F=82=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/ci-cd.yml | 52 +++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index d915f7f52..5cc5f1006 100755 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -129,35 +129,35 @@ jobs: bash -n scripts/init_production_env.sh ' - - name: Start PostgreSQL for validate (isolated container) - shell: sh - run: "set -eu\nPG_CONTAINER=\"ci-pg-validate-${GITHUB_RUN_ID:-$$}\"\necho \"PG_CONTAINER=$PG_CONTAINER\" >> \"$GITHUB_ENV\"\ndocker rm -f \"$PG_CONTAINER\" 2>/dev/null || true\ndocker run -d --name \"$PG_CONTAINER\" \\\n --shm-size=256m \\\n -e POSTGRES_USER=postgres \\\n -e POSTGRES_PASSWORD=postgres \\\n -e POSTGRES_DB=xiaoxia_saas \\\n -P \\\n --health-cmd \"pg_isready -U postgres\" \\\n --health-interval 3s \\\n --health-timeout 3s \\\n --health-retries 20 \\\n postgres:16-alpine\nPG_PORT=$(docker port \"$PG_CONTAINER\" 5432/tcp | cut -d: -f2)\necho \"PostgreSQL port: $PG_PORT\"\necho \"DATABASE_URL=postgresql+psycopg://postgres:postgres@127.0.0.1:$PG_PORT/xiaoxia_saas\" >> \"$GITHUB_ENV\"\nfor i in $(seq 1 30); do\n if docker inspect --format='{{.State.Health.Status}}' \"$PG_CONTAINER\" 2>/dev/null | grep -q healthy; then\n echo \"PostgreSQL is ready on port $PG_PORT\"\n break\n fi\n echo \"Waiting for PostgreSQL... ($i/30)\"\n sleep 2\ndone\ndocker inspect --format='{{.State.Health.Status}}' \"$PG_CONTAINER\" | grep -q healthy\n" - - - name: Validate Alembic migrations - shell: sh - run: 'set -eu - - python3 -m alembic upgrade head --sql > /tmp/alembic-upgrade.sql - - test -s /tmp/alembic-upgrade.sql - - grep -q "Running upgrade" /tmp/alembic-upgrade.sql - - python3 scripts/check_schema_metadata.py - - ' - - name: Check migration safety + - name: Validate Alembic migrations (with isolated PG) shell: sh env: GITHUB_TOKEN: ${{ github.token }} - run: "set -eu\npython3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/develop\n" - - name: Cleanup PostgreSQL (validate) - if: always() - shell: sh - run: 'set +e - docker rm -f "${PG_CONTAINER:-ci-pg-validate}" 2>/dev/null || true - echo "PostgreSQL container cleaned up" - ' + run: "set -eu +PG_CONTAINER=ci-pg-validate-${GITHUB_RUN_ID:-$$} +docker rm -f "$PG_CONTAINER" 2>/dev/null || true +docker run -d --name "$PG_CONTAINER" \\n --shm-size=256m \\n -e POSTGRES_USER=postgres \\n -e POSTGRES_PASSWORD=postgres \\n -e POSTGRES_DB=xiaoxia_saas \\n -P \\n --health-cmd "pg_isready -U postgres" \\n --health-interval 3s \\n --health-timeout 3s \\n --health-retries 20 \\n postgres:16-alpine +PG_PORT=$(docker port "$PG_CONTAINER" 5432/tcp | cut -d: -f2) +echo "PostgreSQL port: $PG_PORT" +export DATABASE_URL=postgresql+psycopg://postgres:postgres@127.0.0.1:$PG_PORT/xiaoxia_saas +for i in $(seq 1 30); do + if docker inspect --format="{{.State.Health.Status}}" "$PG_CONTAINER" 2>/dev/null | grep -q healthy; then + echo "PostgreSQL is ready on port $PG_PORT" + break + fi + echo "Waiting for PostgreSQL... ($i/30)" + sleep 2 +done +docker inspect --format="{{.State.Health.Status}}" "$PG_CONTAINER" | grep -q healthy +python3 -m alembic upgrade head --sql > /tmp/alembic-upgrade.sql +test -s /tmp/alembic-upgrade.sql +grep -q "Running upgrade" /tmp/alembic-upgrade.sql +python3 scripts/check_schema_metadata.py +python3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/develop +docker rm -f "$PG_CONTAINER" 2>/dev/null || true +echo "PostgreSQL container cleaned up" +" + - name: Job duration summary if: always() -- 2.54.0 From 6f0bb8c25e840316272a4209cffc2e515bed7345 Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 16:08:38 +0800 Subject: [PATCH 04/12] chore: trigger CI re-run -- 2.54.0 From ee6034b5fdca0b79ee67e78fd5c6fa1ca0a83b47 Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 16:11:35 +0800 Subject: [PATCH 05/12] =?UTF-8?q?fix(ci):=20=E4=BF=AE=E5=A4=8DYAML?= =?UTF-8?q?=E8=AF=AD=E6=B3=95=EF=BC=8Calembic=E6=AD=A5=E9=AA=A4=E6=94=B9?= =?UTF-8?q?=E7=94=A8literal=20block=20scalar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/ci-cd.yml | 59 ++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 5cc5f1006..0df624371 100755 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -133,31 +133,40 @@ jobs: shell: sh env: GITHUB_TOKEN: ${{ github.token }} - run: "set -eu -PG_CONTAINER=ci-pg-validate-${GITHUB_RUN_ID:-$$} -docker rm -f "$PG_CONTAINER" 2>/dev/null || true -docker run -d --name "$PG_CONTAINER" \\n --shm-size=256m \\n -e POSTGRES_USER=postgres \\n -e POSTGRES_PASSWORD=postgres \\n -e POSTGRES_DB=xiaoxia_saas \\n -P \\n --health-cmd "pg_isready -U postgres" \\n --health-interval 3s \\n --health-timeout 3s \\n --health-retries 20 \\n postgres:16-alpine -PG_PORT=$(docker port "$PG_CONTAINER" 5432/tcp | cut -d: -f2) -echo "PostgreSQL port: $PG_PORT" -export DATABASE_URL=postgresql+psycopg://postgres:postgres@127.0.0.1:$PG_PORT/xiaoxia_saas -for i in $(seq 1 30); do - if docker inspect --format="{{.State.Health.Status}}" "$PG_CONTAINER" 2>/dev/null | grep -q healthy; then - echo "PostgreSQL is ready on port $PG_PORT" - break - fi - echo "Waiting for PostgreSQL... ($i/30)" - sleep 2 -done -docker inspect --format="{{.State.Health.Status}}" "$PG_CONTAINER" | grep -q healthy -python3 -m alembic upgrade head --sql > /tmp/alembic-upgrade.sql -test -s /tmp/alembic-upgrade.sql -grep -q "Running upgrade" /tmp/alembic-upgrade.sql -python3 scripts/check_schema_metadata.py -python3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/develop -docker rm -f "$PG_CONTAINER" 2>/dev/null || true -echo "PostgreSQL container cleaned up" -" - + run: | + set -eu + PG_CONTAINER=ci-pg-validate-${GITHUB_RUN_ID:-$$} + docker rm -f "$PG_CONTAINER" 2>/dev/null || true + docker run -d --name "$PG_CONTAINER" \ + --shm-size=256m \ + -e POSTGRES_USER=postgres \ + -e POSTGRES_PASSWORD=postgres \ + -e POSTGRES_DB=xiaoxia_saas \ + -P \ + --health-cmd "pg_isready -U postgres" \ + --health-interval 3s \ + --health-timeout 3s \ + --health-retries 20 \ + postgres:16-alpine + PG_PORT=$(docker port "$PG_CONTAINER" 5432/tcp | cut -d: -f2) + echo "PostgreSQL port: $PG_PORT" + export DATABASE_URL=postgresql+psycopg://postgres:postgres@127.0.0.1:$PG_PORT/xiaoxia_saas + for i in $(seq 1 30); do + if docker inspect --format='{{.State.Health.Status}}' "$PG_CONTAINER" 2>/dev/null | grep -q healthy; then + echo "PostgreSQL is ready on port $PG_PORT" + break + fi + echo "Waiting for PostgreSQL... ($i/30)" + sleep 2 + done + docker inspect --format='{{.State.Health.Status}}' "$PG_CONTAINER" | grep -q healthy + python3 -m alembic upgrade head --sql > /tmp/alembic-upgrade.sql + test -s /tmp/alembic-upgrade.sql + grep -q "Running upgrade" /tmp/alembic-upgrade.sql + python3 scripts/check_schema_metadata.py + python3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/develop + docker rm -f "$PG_CONTAINER" 2>/dev/null || true + echo "PostgreSQL container cleaned up" - name: Job duration summary if: always() -- 2.54.0 From 715e663f8b581f1683f9b4056d1a34b67527d6d6 Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 16:45:57 +0800 Subject: [PATCH 06/12] ci: reduce detect-secrets stdout output to avoid log truncation --- .gitea/workflows/ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 0df624371..2326d70ce 100755 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -90,7 +90,7 @@ jobs: ' - name: Secret detection (detect-secrets) shell: sh - run: "set -eu\necho \"=== Installing detect-secrets ===\"\npython3 -m pip install -q detect-secrets\ndetect-secrets --version\necho \"\"\necho \"=== Running secret scan ===\"\ndetect-secrets scan \\\n --all-files \\\n --exclude-files '(^|/)(tests|test|e2e|__tests__|spec|docs|node_modules|site-packages|migrations|alembic|.gitea|.git|.pytest_cache|.next|dist|build)/' \\\n --exclude-files '\\.(md|rst|txt|lock|example|sample|min\\.js|min\\.css|spec\\.ts|test\\.ts|test\\.py)$' \\\n --exclude-files '(package-lock|yarn\\.lock|poetry\\.lock|Pipfile\\.lock)$' \\\n --disable-plugin Base64HighEntropyString \\\n --disable-plugin HexHighEntropyString \\\n --disable-plugin BasicAuthDetector \\\n --disable-plugin KeywordDetector \\\n --disable-plugin IPPublicDetector \\\n 2>&1 | tee /tmp/secrets-scan.json\n\nFOUND=$(python3 -c \"\nimport json\ntry:\n with open('/tmp/secrets-scan.json') as f:\n data = json.load(f)\n results = data.get('results', {})\n total = sum(len(v) for\ + run: "set -eu\necho \"=== Installing detect-secrets ===\"\npython3 -m pip install -q detect-secrets\ndetect-secrets --version\necho \"\"\necho \"=== Running secret scan ===\"\ndetect-secrets scan \\\n --all-files \\\n --exclude-files '(^|/)(tests|test|e2e|__tests__|spec|docs|node_modules|site-packages|migrations|alembic|.gitea|.git|.pytest_cache|.next|dist|build)/' \\\n --exclude-files '\\.(md|rst|txt|lock|example|sample|min\\.js|min\\.css|spec\\.ts|test\\.ts|test\\.py)$' \\\n --exclude-files '(package-lock|yarn\\.lock|poetry\\.lock|Pipfile\\.lock)$' \\\n --disable-plugin Base64HighEntropyString \\\n --disable-plugin HexHighEntropyString \\\n --disable-plugin BasicAuthDetector \\\n --disable-plugin KeywordDetector \\\n --disable-plugin IPPublicDetector \\\n > /tmp/secrets-scan.json 2>&1\n\nFOUND=$(python3 -c \"\nimport json\ntry:\n with open('/tmp/secrets-scan.json') as f:\n data = json.load(f)\n results = data.get('results', {})\n total = sum(len(v) for\ \ v in results.values())\n print(total)\nexcept Exception:\n print('error')\n\")\necho \"\"\necho \"Secrets detected: $FOUND\"\nif [ \"$FOUND\" != \"0\" ] && [ \"$FOUND\" != \"error\" ]; then\n echo \"\"\n echo \"=== Secret details ===\"\n python3 -c \"\nimport json\nwith open('/tmp/secrets-scan.json') as f:\n data = json.load(f)\nfor fpath, items in data.get('results', {}).items():\n for item in items:\n line = item.get('line_number', '?')\n stype = item.get('type', '?')\n hashed = item.get('hashed_secret', '')[:16]\n print(f' {fpath}:{line} [{stype}] {hashed}...')\n\"\n echo \"\"\n echo \"ERROR: Potential secrets detected in code!\"\n echo \"If these are false positives, add exclusions in the CI workflow.\"\n exit 1\nfi\necho \"Secret scan completed - no secrets detected\"\n" - name: Calculate changed Python files (incremental scan) shell: sh -- 2.54.0 From 2a6c7d408696a13b6a77787af1aa488441013949 Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 17:43:24 +0800 Subject: [PATCH 07/12] ci: silence detect-secrets stdout to preserve log output --- .gitea/workflows/ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 2326d70ce..4388346be 100755 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -90,7 +90,7 @@ jobs: ' - name: Secret detection (detect-secrets) shell: sh - run: "set -eu\necho \"=== Installing detect-secrets ===\"\npython3 -m pip install -q detect-secrets\ndetect-secrets --version\necho \"\"\necho \"=== Running secret scan ===\"\ndetect-secrets scan \\\n --all-files \\\n --exclude-files '(^|/)(tests|test|e2e|__tests__|spec|docs|node_modules|site-packages|migrations|alembic|.gitea|.git|.pytest_cache|.next|dist|build)/' \\\n --exclude-files '\\.(md|rst|txt|lock|example|sample|min\\.js|min\\.css|spec\\.ts|test\\.ts|test\\.py)$' \\\n --exclude-files '(package-lock|yarn\\.lock|poetry\\.lock|Pipfile\\.lock)$' \\\n --disable-plugin Base64HighEntropyString \\\n --disable-plugin HexHighEntropyString \\\n --disable-plugin BasicAuthDetector \\\n --disable-plugin KeywordDetector \\\n --disable-plugin IPPublicDetector \\\n > /tmp/secrets-scan.json 2>&1\n\nFOUND=$(python3 -c \"\nimport json\ntry:\n with open('/tmp/secrets-scan.json') as f:\n data = json.load(f)\n results = data.get('results', {})\n total = sum(len(v) for\ + run: "set -eu\necho \"=== Installing detect-secrets ===\"\npython3 -m pip install -q detect-secrets\ndetect-secrets --version\necho \"\"\necho \"=== Running secret scan ===\"\ndetect-secrets scan \\\n --all-files \\\n --exclude-files '(^|/)(tests|test|e2e|__tests__|spec|docs|node_modules|site-packages|migrations|alembic|.gitea|.git|.pytest_cache|.next|dist|build)/' \\\n --exclude-files '\\.(md|rst|txt|lock|example|sample|min\\.js|min\\.css|spec\\.ts|test\\.ts|test\\.py)$' \\\n --exclude-files '(package-lock|yarn\\.lock|poetry\\.lock|Pipfile\\.lock)$' \\\n --disable-plugin Base64HighEntropyString \\\n --disable-plugin HexHighEntropyString \\\n --disable-plugin BasicAuthDetector \\\n --disable-plugin KeywordDetector \\\n --disable-plugin IPPublicDetector \\\n --quiet --json 2>/tmp/secrets-scan-err.log > /tmp/secrets-scan.json\n\nFOUND=$(python3 -c \"\nimport json\ntry:\n with open('/tmp/secrets-scan.json') as f:\n data = json.load(f)\n results = data.get('results', {})\n total = sum(len(v) for\ \ v in results.values())\n print(total)\nexcept Exception:\n print('error')\n\")\necho \"\"\necho \"Secrets detected: $FOUND\"\nif [ \"$FOUND\" != \"0\" ] && [ \"$FOUND\" != \"error\" ]; then\n echo \"\"\n echo \"=== Secret details ===\"\n python3 -c \"\nimport json\nwith open('/tmp/secrets-scan.json') as f:\n data = json.load(f)\nfor fpath, items in data.get('results', {}).items():\n for item in items:\n line = item.get('line_number', '?')\n stype = item.get('type', '?')\n hashed = item.get('hashed_secret', '')[:16]\n print(f' {fpath}:{line} [{stype}] {hashed}...')\n\"\n echo \"\"\n echo \"ERROR: Potential secrets detected in code!\"\n echo \"If these are false positives, add exclusions in the CI workflow.\"\n exit 1\nfi\necho \"Secret scan completed - no secrets detected\"\n" - name: Calculate changed Python files (incremental scan) shell: sh -- 2.54.0 From 188fec52c6d49c19274cb279bb55996abf2cebbd Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 17:49:42 +0800 Subject: [PATCH 08/12] ci: revert detect-secrets args, use simple redirect --- .gitea/workflows/ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 4388346be..2326d70ce 100755 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -90,7 +90,7 @@ jobs: ' - name: Secret detection (detect-secrets) shell: sh - run: "set -eu\necho \"=== Installing detect-secrets ===\"\npython3 -m pip install -q detect-secrets\ndetect-secrets --version\necho \"\"\necho \"=== Running secret scan ===\"\ndetect-secrets scan \\\n --all-files \\\n --exclude-files '(^|/)(tests|test|e2e|__tests__|spec|docs|node_modules|site-packages|migrations|alembic|.gitea|.git|.pytest_cache|.next|dist|build)/' \\\n --exclude-files '\\.(md|rst|txt|lock|example|sample|min\\.js|min\\.css|spec\\.ts|test\\.ts|test\\.py)$' \\\n --exclude-files '(package-lock|yarn\\.lock|poetry\\.lock|Pipfile\\.lock)$' \\\n --disable-plugin Base64HighEntropyString \\\n --disable-plugin HexHighEntropyString \\\n --disable-plugin BasicAuthDetector \\\n --disable-plugin KeywordDetector \\\n --disable-plugin IPPublicDetector \\\n --quiet --json 2>/tmp/secrets-scan-err.log > /tmp/secrets-scan.json\n\nFOUND=$(python3 -c \"\nimport json\ntry:\n with open('/tmp/secrets-scan.json') as f:\n data = json.load(f)\n results = data.get('results', {})\n total = sum(len(v) for\ + run: "set -eu\necho \"=== Installing detect-secrets ===\"\npython3 -m pip install -q detect-secrets\ndetect-secrets --version\necho \"\"\necho \"=== Running secret scan ===\"\ndetect-secrets scan \\\n --all-files \\\n --exclude-files '(^|/)(tests|test|e2e|__tests__|spec|docs|node_modules|site-packages|migrations|alembic|.gitea|.git|.pytest_cache|.next|dist|build)/' \\\n --exclude-files '\\.(md|rst|txt|lock|example|sample|min\\.js|min\\.css|spec\\.ts|test\\.ts|test\\.py)$' \\\n --exclude-files '(package-lock|yarn\\.lock|poetry\\.lock|Pipfile\\.lock)$' \\\n --disable-plugin Base64HighEntropyString \\\n --disable-plugin HexHighEntropyString \\\n --disable-plugin BasicAuthDetector \\\n --disable-plugin KeywordDetector \\\n --disable-plugin IPPublicDetector \\\n > /tmp/secrets-scan.json 2>&1\n\nFOUND=$(python3 -c \"\nimport json\ntry:\n with open('/tmp/secrets-scan.json') as f:\n data = json.load(f)\n results = data.get('results', {})\n total = sum(len(v) for\ \ v in results.values())\n print(total)\nexcept Exception:\n print('error')\n\")\necho \"\"\necho \"Secrets detected: $FOUND\"\nif [ \"$FOUND\" != \"0\" ] && [ \"$FOUND\" != \"error\" ]; then\n echo \"\"\n echo \"=== Secret details ===\"\n python3 -c \"\nimport json\nwith open('/tmp/secrets-scan.json') as f:\n data = json.load(f)\nfor fpath, items in data.get('results', {}).items():\n for item in items:\n line = item.get('line_number', '?')\n stype = item.get('type', '?')\n hashed = item.get('hashed_secret', '')[:16]\n print(f' {fpath}:{line} [{stype}] {hashed}...')\n\"\n echo \"\"\n echo \"ERROR: Potential secrets detected in code!\"\n echo \"If these are false positives, add exclusions in the CI workflow.\"\n exit 1\nfi\necho \"Secret scan completed - no secrets detected\"\n" - name: Calculate changed Python files (incremental scan) shell: sh -- 2.54.0 From cf6b625ffb3acecc906886c3791db1fc87398290 Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 18:03:35 +0800 Subject: [PATCH 09/12] ci: init git repo before migration safety check for diff support --- .gitea/workflows/ci-cd.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 2326d70ce..b4f00c958 100755 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -164,6 +164,10 @@ jobs: test -s /tmp/alembic-upgrade.sql grep -q "Running upgrade" /tmp/alembic-upgrade.sql python3 scripts/check_schema_metadata.py + # Initialize git for migration safety diff (CI checkout is tar.gz without .git) + git init > /dev/null 2>&1 + git remote add origin https://git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas.git > /dev/null 2>&1 + git fetch origin develop --depth=1 > /dev/null 2>&1 python3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/develop docker rm -f "$PG_CONTAINER" 2>/dev/null || true echo "PostgreSQL container cleaned up" -- 2.54.0 From e8e492806238ca10e350a75cbe84361747f185e5 Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 18:25:28 +0800 Subject: [PATCH 10/12] ci: fix migration safety check for tar.gz checkout environment --- .gitea/workflows/ci-cd.yml | 4 +++- scripts/check_migration_safety.py | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index b4f00c958..14e687eea 100755 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -167,7 +167,9 @@ jobs: # Initialize git for migration safety diff (CI checkout is tar.gz without .git) git init > /dev/null 2>&1 git remote add origin https://git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas.git > /dev/null 2>&1 - git fetch origin develop --depth=1 > /dev/null 2>&1 + git fetch origin develop --depth=100 > /dev/null 2>&1 + git add -A > /dev/null 2>&1 + git -c user.email=ci@local -c user.name=CI commit -m "ci-tmp" > /dev/null 2>&1 python3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/develop docker rm -f "$PG_CONTAINER" 2>/dev/null || true echo "PostgreSQL container cleaned up" diff --git a/scripts/check_migration_safety.py b/scripts/check_migration_safety.py index 805180c48..17649b270 100644 --- a/scripts/check_migration_safety.py +++ b/scripts/check_migration_safety.py @@ -195,16 +195,28 @@ def get_new_migrations_via_git(diff_target: str) -> List[Path] | None: timeout=30, ) + # 优先使用三点diff(找合并基线),失败时回退到两点diff(兼容tar.gz checkout + git init的CI环境) + diff_args = ["git", "diff", "--name-only", "--diff-filter=A", f"{diff_target}...HEAD"] result = subprocess.run( - ["git", "diff", "--name-only", "--diff-filter=A", f"{diff_target}...HEAD"], + diff_args, capture_output=True, text=True, cwd=str(REPO_ROOT), timeout=10, ) if result.returncode != 0: - print(f" (git diff 失败:{result.stderr.strip()})") - return None + # fallback: 两点diff(无需共同祖先) + diff_args_2 = ["git", "diff", "--name-only", "--diff-filter=A", diff_target, "HEAD"] + result = subprocess.run( + diff_args_2, + capture_output=True, + text=True, + cwd=str(REPO_ROOT), + timeout=10, + ) + if result.returncode != 0: + print(f" (git diff 失败:{result.stderr.strip()})") + return None new_migrations = [] for line in result.stdout.strip().split("\n"): -- 2.54.0 From a3df4fb32445cfe2d823187180085f4cc8c1231e Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 18:43:56 +0800 Subject: [PATCH 11/12] ci: use refspec to create origin/develop remote branch after fetch --- .gitea/workflows/ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 14e687eea..d50dc24d2 100755 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -167,7 +167,7 @@ jobs: # Initialize git for migration safety diff (CI checkout is tar.gz without .git) git init > /dev/null 2>&1 git remote add origin https://git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas.git > /dev/null 2>&1 - git fetch origin develop --depth=100 > /dev/null 2>&1 + git fetch origin develop:refs/remotes/origin/develop --depth=100 > /dev/null 2>&1 git add -A > /dev/null 2>&1 git -c user.email=ci@local -c user.name=CI commit -m "ci-tmp" > /dev/null 2>&1 python3 scripts/check_migration_safety.py --allow-medium-risk --diff-against origin/develop -- 2.54.0 From 71d1a8e78d021a7fdb50f2e91a7dc426ec427a7b Mon Sep 17 00:00:00 2001 From: XiaoXia Bot Date: Thu, 16 Jul 2026 19:57:28 +0800 Subject: [PATCH 12/12] test: trigger CI to validate runner log fix -- 2.54.0