#!/usr/bin/env node import { readFileSync } from 'node:fs'; const checks = [ { file: 'package.json', includes: '"check:rustfmt": "cargo fmt --all --manifest-path server-rs/Cargo.toml -- --check"', reason: '仓库必须保留统一、只读的 Rust workspace 格式检查入口。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'npm run check:rustfmt', reason: 'API 生产构建必须在编译前执行 Rust 格式检查。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'npm run check:server-rs-ddd', reason: 'API 生产构建必须执行 server-rs DDD/schema/runtime-access 门禁。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'cargo check -p api-server --all-targets --manifest-path server-rs/Cargo.toml', reason: 'API 生产构建必须执行 api-server 全 target 编译检查。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', includes: 'npm run check:rustfmt', reason: 'Stdb module 生产构建必须在编译前执行 Rust 格式检查。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', includes: 'npm run check:server-rs-ddd', reason: 'Stdb module 生产构建必须执行 DDD/schema/runtime-access 门禁。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', includes: 'npm run check:admin-account-procedures', reason: 'Stdb module 生产构建必须执行管理员 procedure smoke。', }, { file: 'jenkins/Jenkinsfile.production-web-build', includes: 'npm run check:production-ops', reason: 'Web 生产构建必须执行生产运维静态门禁。', }, { file: 'jenkins/Jenkinsfile.production-web-build', includes: 'npm run lint:eslint', reason: 'Web 生产构建必须执行 ESLint 门禁。', }, { file: 'jenkins/Jenkinsfile.production-web-build', includes: 'npm run typecheck', reason: 'Web 生产构建必须执行主站类型检查。', }, { file: 'jenkins/Jenkinsfile.production-web-build', includes: 'npm run admin-web:typecheck', reason: 'Web 生产构建必须执行后台类型检查。', }, { file: 'jenkins/Jenkinsfile.production-web-build', includes: 'npm run test', reason: 'Web 生产构建必须执行当前维护范围内的 Vitest。', }, { file: 'server-rs/crates/spacetime-module/src/migration.rs', includes: 'option_env!("GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET_SHA256")', reason: '可下载的 SpacetimeDB WASM 只能嵌入 bootstrap secret 摘要。', }, { file: 'server-rs/crates/spacetime-module/src/migration.rs', excludes: 'option_env!("GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET")', reason: 'SpacetimeDB WASM 不得嵌入原始 bootstrap secret。', }, { file: 'server-rs/crates/spacetime-module/src/migration.rs', includes: 'secret.len() == MIGRATION_BOOTSTRAP_SECRET_HEX_LEN', reason: '模块授权入口必须拒绝非 64 位十六进制 bootstrap secret。', }, { file: 'scripts/build-production-release.sh', includes: 'GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET_SHA256', reason: '生产模块构建前必须把受保护 secret 转换为 SHA-256 摘要。', }, { file: 'scripts/build-production-release.sh', excludes: "path: 'migration-bootstrap-secret.txt'", reason: '生产发布清单不得包含原始 bootstrap secret artifact。', }, { file: 'scripts/build-production-release.sh', includes: 'migration_bootstrap_secret_sha256:', reason: 'Stdb release manifest 必须记录非敏感 bootstrap secret 摘要。', }, { file: 'scripts/deploy-rust-remote.sh', includes: 'GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET_SHA256', reason: '远程 Rust 模块构建也只能向 rustc 传递 bootstrap secret 摘要。', }, { file: 'scripts/deploy-rust-remote.sh', includes: 'server-rs/.spacetimedb/build-secrets', reason: '旧 Ubuntu 直传入口也必须把原始 bootstrap secret 留在发布包外的受保护 sidecar。', }, { file: 'scripts/deploy-rust-remote.sh', excludes: '"${TARGET_DIR}/migration-bootstrap-secret.txt"', reason: '旧 Ubuntu 发布包目录不得再次包含原始 bootstrap secret。', }, { file: 'scripts/deploy-rust-remote.sh', includes: '<"${MIGRATION_BOOTSTRAP_SECRET_OUTPUT_FILE}"', reason: '远端所需原始 secret 必须通过独立 SSH 标准输入交付,不得进入命令参数或发布包。', }, { file: 'scripts/deploy-rust-remote.sh', includes: '--migration-bootstrap-secret-file)', reason: '手工直传入口只能从受保护文件读取 bootstrap secret。', }, { file: 'scripts/deploy-rust-remote.sh', excludes: '--migration-bootstrap-secret)', reason: 'bootstrap secret 明文不得出现在进程命令参数中。', }, { file: 'scripts/deploy-rust-remote.sh', includes: '[[ ! "${MIGRATION_BOOTSTRAP_SECRET}" =~ ^[0-9a-fA-F]{64}$ ]]', reason: '旧 Ubuntu 手工直传入口必须拒绝非 64 位十六进制 bootstrap secret。', }, { file: 'scripts/deploy-rust-remote.sh', excludes: "tr -d '\\r\\n'", reason: '旧 Ubuntu 手工直传入口不得把 secret 文件内部换行静默拼接。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: 'install -o root -g genarrative -m 0440', reason: '生产 Stdb publish 必须把运行时 bootstrap secret 安装成 root 持有、服务组只读的文件。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: 'restart_runtime_services_after_bootstrap_secret_install', reason: '替换运行时 bootstrap secret 后必须重启已运行的 API、worker 和 controller,避免进程继续持有旧值。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: 'get_runtime_service_active_state', reason: '生产 Stdb publish 必须区分 systemctl 明确返回的非 active 状态与查询错误,查询错误不得静默跳过服务重启。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: '"${exit_code}" -eq 3', reason: '生产 Stdb publish 只能把 systemctl 明确的非 active 返回码作为可跳过状态,其他错误必须阻断。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: 'if worker_units_output="$(', reason: '生产 Stdb publish 必须直接检查 worker list-units 的退出状态,不能用会吞掉失败的进程替换管道。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: '查询 active worker 服务失败,阻断退出维护模式', reason: '生产 Stdb publish 无法枚举 active worker 时必须阻断,不能在未知 worker 状态下退出维护模式。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: 'restart_runtime_service_and_require_active', reason: '生产 Stdb publish 必须确认重启前 active 的 API、controller 和 worker 在重启后恢复 active。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: 'if ! restart_runtime_service_and_require_active genarrative-api.service; then', reason: '生产 Stdb publish 必须显式传播 API 重启或验活失败,不能依赖调用上下文中的 set -e。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: 'restart_runtime_services_after_bootstrap_secret_install\nwait_for_api_healthz_ready\n\n"${SCRIPT_DIR}/maintenance-off.sh"', reason: '生产 Stdb publish 在 API 原本 active 时必须先通过本机 /healthz readiness 再退出维护模式。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: 'ensure_runtime_bootstrap_secret_env_file "${API_ENV_FILE}" true', reason: 'Stdb 先于 API 发布时必须先补齐 api-server env 的 FILE 路径,保证首次 rollout 重启即可读取 secret。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: 'stop_runtime_services_for_rollout_gate', reason: 'Stdb 与 API 之间需要人工维护时,必须停止旧 API/controller/worker,不能只保留网关维护文件。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: '按参数保持维护模式和旧运行时服务停止状态', reason: '受控维护发布成功后不得自动重启旧运行时或退出维护模式。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'ensure_runtime_bootstrap_secret_file_env', reason: '生产 API/worker env 必须统一指向 Stdb publish 写入的受保护 bootstrap secret 文件。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '继承已有维护模式;部署失败时不得误退出上游维护窗口', reason: 'API deploy 必须区分自己打开的维护模式与 Stdb gate 继承的维护模式。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '--keep-maintenance-mode)', reason: 'API deploy 必须允许成功发布后按显式参数保留维护模式。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'readiness 通过,按参数保持维护模式', reason: 'API deploy 保留维护模式时必须在 readiness 通过后给出明确状态。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'curl -fsS --max-time 2 "${HEALTH_URL}"', reason: 'API readiness 单次请求必须有超时,避免端口已建立但服务尚未响应时绕过重试上限无限挂起。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: "booleanParam(name: 'KEEP_MAINTENANCE_MODE', defaultValue: false", reason: 'API Deploy Job 必须向独立发布和 Full 编排暴露成功后保持维护的参数。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'maintenance_deploy_args+=(--keep-maintenance-mode)', reason: 'API Deploy Job 必须把保持维护参数传给发布产物内的部署脚本。', }, { file: 'scripts/jenkins-server-provision.sh', includes: 'ensure_runtime_bootstrap_secret_file_env', reason: 'Server-Provision 必须为新建及存量 API/worker env 补齐 bootstrap secret FILE 配置。', }, { file: 'deploy/env/api-server.env.example', includes: 'GENARRATIVE_SPACETIME_RUNTIME_SERVICE_BOOTSTRAP_SECRET_FILE=/var/lib/genarrative/spacetime/runtime-service-bootstrap-secret.txt', reason: '生产 API env 示例只能登记 bootstrap secret 的固定 FILE 路径。', }, { file: 'deploy/env/api-server.env.example', includes: 'WECHAT_PAY_REFUND_RECONCILIATION_ENABLED=true', reason: '真实微信支付 release 必须在生产 env 示例中显式开启退款主动对账。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'validate_real_wechat_pay_refund_reconciliation', reason: 'API deploy 必须在 current 切换前复核真实微信支付退款 reconciliation。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-publish', includes: "file(credentialsId: params.MIGRATION_BOOTSTRAP_SECRET_CREDENTIAL_ID.trim(), variable: 'MIGRATION_BOOTSTRAP_SECRET_FILE')", reason: 'Stdb Publish 必须从 Jenkins Secret File credential 受保护地取得与 wasm 匹配的 bootstrap secret。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-publish', excludes: 'migration-bootstrap-secret.txt', reason: 'Stdb Publish 不得通过普通 Jenkins artifact 或工作区副本交付 bootstrap secret。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-publish', includes: 'MIGRATION_BOOTSTRAP_SECRET_FILE:?MIGRATION_BOOTSTRAP_SECRET_FILE 不能为空', reason: 'Stdb Publish 必须把受保护文件直接传给发布脚本,且不能展开明文。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', includes: "file(credentialsId: params.MIGRATION_BOOTSTRAP_SECRET_CREDENTIAL_ID.trim(), variable: 'MIGRATION_BOOTSTRAP_SECRET_FILE')", reason: 'Stdb Build 必须用 Jenkins Secret File credential 为 option_env! 提供受控编译输入。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', excludes: 'archiveArtifacts artifacts: "build/${env.EFFECTIVE_BUILD_VERSION}/migration-bootstrap-secret.txt"', reason: 'bootstrap secret 不得作为普通、可下载的 Jenkins archive artifact。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', includes: 'GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET_SHA256', reason: 'Stdb Build 只能把 File credential 的 SHA-256 摘要传给 Rust 编译。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', includes: "string(name: 'MIGRATION_BOOTSTRAP_SECRET_CREDENTIAL_ID', defaultValue: 'genarrative-spacetime-bootstrap-secret-dev-file'", reason: 'Stdb Build 的 Secret File credential ID 必须由仓库 Jenkinsfile 固定默认值。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', excludes: 'export GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET=', reason: 'Jenkins Stdb Build 不得把原始 bootstrap secret 导出给 Rust 编译进程。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: '--migration-bootstrap-secret-file', reason: '生产 Stdb publish 必须只接受受保护的 bootstrap secret FILE。', }, { file: 'scripts/deploy/production-stdb-publish.sh', excludes: '${SOURCE_DIR}/migration-bootstrap-secret.txt', reason: '生产 Stdb publish 不得从可下载的构建 artifact 读取 bootstrap secret。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: 'EXPECTED_MIGRATION_BOOTSTRAP_SECRET_SHA256=', reason: '生产 Stdb publish 必须读取 release manifest 中的 bootstrap secret 摘要。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: 'Secret File 与构建 WASM 的 bootstrap secret 摘要不一致', reason: '生产 Stdb publish 必须阻断 Secret File 与构建 WASM 摘要不一致。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: '--delete-data=never', reason: '生产 Stdb publish 必须显式禁止 schema 冲突时删除数据。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: '--yes=migrate,break-clients', reason: '生产 Stdb publish 只能跳过迁移与客户端断开确认,不能使用等价 delete-data 的裸 --yes。', }, { file: 'scripts/deploy/production-stdb-publish.sh', excludes: '--clear-database', reason: '生产 Stdb publish 普通入口不得保留清库参数。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-publish', excludes: 'CLEAR_DATABASE', reason: 'Stdb 发布流水线不得向普通构建参数暴露清库开关。', }, { file: 'scripts/deploy/production-stdb-publish.sh', includes: '[[ ! "${MIGRATION_BOOTSTRAP_SECRET}" =~ ^[0-9a-fA-F]{64}$ ]]', reason: '生产 Stdb publish 必须拒绝非 64 位十六进制 Secret File。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', includes: '[[ ! "${migration_bootstrap_secret}" =~ ^[0-9a-fA-F]{64}$ ]]', reason: 'Stdb Build 必须在计算摘要前拒绝非 64 位十六进制 Secret File。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', excludes: 'tr -d "\\\\r\\\\n"', reason: 'Stdb Build 不得把 Secret File 内部换行静默拼接。', }, { file: 'scripts/spacetime-migration-common.mjs', includes: "if (!/^[0-9a-f]{64}$/iu.test(secret))", reason: '迁移脚本 FILE 入口必须拒绝非 64 位十六进制 bootstrap secret。', }, { file: 'scripts/dev.mjs', includes: 'const BOOTSTRAP_SECRET_PATTERN = /^[0-9a-fA-F]{64}$/u;', reason: '本地 dev 构建与运行服务必须共用严格的 64 位十六进制 secret 规则。', }, { file: 'scripts/deploy/production-runtime-writer-identity-rotate.mjs', includes: 'rotate_editor_generation_runtime_service_identity_and_return', reason: 'runtime writer identity rotation 必须复用模块的受审计 procedure。', }, { file: 'scripts/deploy/production-runtime-writer-identity-rotate.mjs', includes: '--confirm-next-writer-identity', reason: 'runtime writer identity rotation 必须要求 operator 二次确认目标 identity。', }, { file: 'scripts/deploy/production-runtime-writer-identity-rotate.mjs', includes: 'runtime writer identity 不能设为 migration operator identity', reason: 'rotation 入口不能把 migration operator 自动或直接设为 runtime writer。', }, { file: 'server-rs/crates/spacetime-module/src/editor_project_storage.rs', includes: 'crate::migration::is_database_migration_operator(ctx, next_writer_identity)', reason: 'rotation procedure 必须按数据库中的完整 migration operator 集合校验目标 identity。', }, { file: 'scripts/deploy/production-runtime-writer-identity-rotate.mjs', includes: "spawn('spacetime', ['login', 'show']", reason: 'rotation 入口必须校验声明的 operator identity 与当前 CLI 登录 identity 一致。', }, { file: 'scripts/deploy/production-runtime-writer-identity-rotate.mjs', excludes: 'GENARRATIVE_SPACETIME_MIGRATION_BOOTSTRAP_SECRET', reason: 'runtime writer identity rotation 不得读取或传递 migration bootstrap secret。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-publish', includes: '--worker-env-file "${params.WORKER_ENV_FILE}"', reason: 'Stdb Publish 必须把 worker env 路径传给随包发布脚本。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-publish', includes: "string(name: 'MIGRATION_BOOTSTRAP_SECRET_CREDENTIAL_ID', defaultValue: 'genarrative-spacetime-bootstrap-secret-dev-file'", reason: 'Stdb Publish 的 Secret File credential ID 必须由仓库 Jenkinsfile 固定默认值。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "string(name: 'WORKER_ENV_FILE', value: params.WORKER_ENV_FILE", reason: '全量发布必须向 Stdb 与 API 两段透传同一 worker env 路径。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "error('MIGRATION_BOOTSTRAP_SECRET_CREDENTIAL_ID 必须引用受保护的 Jenkins Secret File 凭据。')", reason: '全量构建必须在启动并行子流水线前拒绝缺失的 Secret File 凭据。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "string(name: 'MIGRATION_BOOTSTRAP_SECRET_CREDENTIAL_ID', defaultValue: 'genarrative-spacetime-bootstrap-secret-dev-file'", reason: 'Full Build 的 Secret File credential ID 必须由仓库 Jenkinsfile 固定默认值。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "string(name: 'MIGRATION_BOOTSTRAP_SECRET_CREDENTIAL_ID', value: params.MIGRATION_BOOTSTRAP_SECRET_CREDENTIAL_ID)", reason: '全量发布必须把与 wasm 构建一致的 Secret File 凭据透传给 Stdb Publish。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "choice(name: 'STDB_API_ROLLOUT_MODE', choices: ['normal', 'pause-after-stdb']", reason: 'Full Build 的 04:00 定时任务必须默认 normal 完整发布仅供开发使用的 dev 服务器。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "choice(name: 'DATABASE_BACKUP_MODE', choices: ['async', 'sync', 'skip']", reason: 'Full Build 必须显式暴露 Stdb publish 的备份策略。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "string(name: 'DATABASE_BACKUP_MODE', value: params.DATABASE_BACKUP_MODE)", reason: 'Full Build 必须把备份策略透传给 Stdb Publish,不得静默回退为 async。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "booleanParam(name: 'KEEP_MAINTENANCE_MODE', value: true)", reason: 'Full Build 必须让 Stdb 与 API Deploy 全程保持维护,直到 Web Deploy 结束。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "booleanParam(name: 'EXIT_MAINTENANCE_MODE_AFTER_COMPLETION', defaultValue: true", reason: 'Full Build 必须显式提供完整发布成功后是否退出维护模式的选项。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: '确认 API runtime identity 未被授权为 migration operator 后再继续部署 API', reason: 'Stdb/API 人工 gate 必须提醒审批人保持 migration operator 与运行时服务 identity 互斥。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "stage('Exit Maintenance')", reason: 'Full Build 必须在 Web Deploy 之后用独立阶段决定是否退出维护。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: 'expression { return params.EXIT_MAINTENANCE_MODE_AFTER_COMPLETION != false }', reason: 'Full Build 只有在显式允许时才执行最终维护退出阶段。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: 'maintenance_script="/opt/genarrative/current/scripts/deploy/maintenance-off.sh"', reason: 'Full Build 必须使用本次 current release 随包维护脚本退出维护。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "timeout(time: 4, unit: 'HOURS')", reason: 'Stdb/API 人工门禁必须有超时,不能永久占用 disableConcurrentBuilds 锁。', }, { file: 'jenkins/Jenkinsfile.production-full-build-and-deploy', includes: "submitter: params.STDB_API_ROLLOUT_APPROVERS.trim()", reason: 'Stdb/API 人工门禁必须限制指定 Jenkins 用户或组放行。', }, { file: 'scripts/spacetime-maintain-external-generation-jobs.mjs', includes: '!options.apply && (result.has_more || pendingApplyCount > 0)', reason: '历史维护最后一批即使 has_more=false,只要 dry-run 仍命中数据也必须提示同 cursor apply。', }, { file: 'scripts/spacetime-maintain-external-generation-jobs.mjs', includes: 'cursor_job_id: encodeSpacetimeCliOption(options.cursorJobId || null)', reason: '历史维护续批游标必须编码为 CLI SATS Option,不能把非空字符串直接传给 procedure。', }, { file: 'scripts/spacetime-maintain-external-generation-jobs.mjs', includes: 'completed_before_micros: encodeSpacetimeCliOption(', reason: '历史 payload 截止时间必须编码为 CLI SATS Option,确保事故时间过滤可调用。', }, { file: 'scripts/spacetime-migrate-editor-canvas-layout.mjs', includes: 'dry_run: !options.apply', reason: '图片画布存量迁移必须默认 dry-run,只有显式 --apply 才写入。', }, { file: 'scripts/spacetime-repair-editor-canvas-resources.mjs', includes: 'buildProcedureInput(canvas, updatedAtMicros, !options.apply)', reason: '图片画布资源修复必须默认 dry-run,只有显式 --apply 才写入。', }, { file: 'scripts/spacetime-repair-editor-canvas-resources.mjs', includes: '--confirm-plan-sha256', reason: '图片画布资源修复 apply 必须绑定同一份 dry-run plan 摘要。', }, { file: 'scripts/spacetime-repair-editor-canvas-resources.mjs', includes: '(metadata.mode & 0o777) !== 0o600', reason: '包含真实资源 ID 的修复 plan 必须使用仓库外 0600 文件。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', includes: 'scripts/spacetime-migrate-editor-canvas-layout.mjs', reason: 'Stdb Build 必须归档图片画布存量迁移脚本。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-publish', includes: 'scripts/spacetime-migrate-editor-canvas-layout.mjs', reason: 'Stdb Publish 必须从同一上游制品复制图片画布存量迁移脚本。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-build', includes: 'scripts/spacetime-repair-editor-canvas-resources.mjs', reason: 'Stdb Build 必须归档图片画布资源修复脚本。', }, { file: 'jenkins/Jenkinsfile.production-stdb-module-publish', includes: 'scripts/spacetime-repair-editor-canvas-resources.mjs', reason: 'Stdb Publish 必须从同一上游制品复制图片画布资源修复脚本。', }, { file: 'scripts/deploy-rust-remote.sh', excludes: 'echo "[deploy:rust] 迁移引导密钥: ${MIGRATION_BOOTSTRAP_SECRET}"', reason: '发布包构建日志不得输出 bootstrap secret 明文。', }, { file: 'scripts/dev.mjs', excludes: '[dev:spacetime] 迁移引导密钥: ${', reason: '本地 dev 日志不得输出 bootstrap secret 明文。', }, { file: 'deploy/systemd/genarrative-database-backup.service', includes: '--restart-service-after genarrative-api.service', reason: '生产冷备份恢复 SpacetimeDB 后必须显式拉起依赖它的 API 服务。', }, { file: 'deploy/systemd/genarrative-database-backup.service', includes: '--restart-service-after genarrative-external-generation-worker@1.service', reason: '生产冷备份恢复 SpacetimeDB 后必须显式拉起保底外部生成 worker。', }, { file: 'deploy/systemd/genarrative-database-backup.service', includes: '--restart-service-after genarrative-external-generation-controller.service', reason: '生产冷备份恢复 SpacetimeDB 后必须显式拉起外部生成 worker controller。', }, { file: 'deploy/systemd/genarrative-api.service', includes: 'Wants=network-online.target genarrative-external-generation-controller.service', reason: '生产 API service 启动时必须弱依赖拉起外部生成 worker controller,避免只恢复 API 后队列无人消费。', }, { file: 'deploy/systemd/genarrative-database-backup.service', includes: 'ExecStart=/usr/bin/node -- /opt/genarrative/current/scripts/database-backup-to-oss.mjs --env-file', reason: '生产冷备份 service 必须用 node -- 分隔脚本参数,避免 Node 22 抢占业务 --env-file。', }, { file: 'deploy/systemd/genarrative-database-backup.service', excludes: '--storage-format files', reason: '生产数据库备份主 service 必须继续保持 archive full 默认行为。', }, { file: 'deploy/systemd/genarrative-database-backup-files-history.conf', includes: 'ExecStart=\nExecStart=/usr/bin/node -- /opt/genarrative/current/scripts/database-backup-to-oss.mjs --env-file', reason: 'files-history drop-in 必须先清空主 service 的 ExecStart,并使用 current release 脚本。', }, { file: 'deploy/systemd/genarrative-database-backup-files-history.conf', includes: '--storage-format files --mode history --work-dir /var/lib/genarrative/database-backups/files-history', reason: 'files-history drop-in 必须只执行逐文件历史归档,并复用已建立基线的独立 work-dir。', }, { file: 'deploy/systemd/genarrative-database-backup-files-history.conf', excludes: '--stop-service', reason: 'files-history 在线归档不可停止 SpacetimeDB。', }, { file: 'deploy/systemd/genarrative-database-backup-files-history.conf', excludes: '--database', reason: 'files-history drop-in 不得写死数据库名,必须从环境文件读取。', }, { file: 'deploy/systemd/genarrative-database-backup-files-history.conf', excludes: '--bucket', reason: 'files-history drop-in 不得写死 OSS bucket,必须从环境文件读取。', }, { file: 'scripts/jenkins-server-provision.sh', includes: 'DATABASE_BACKUP_PROFILE="${DATABASE_BACKUP_PROFILE:-archive-full}"', reason: 'Server-Provision 的数据库备份 profile 必须默认保持 archive-full。', }, { file: 'scripts/jenkins-server-provision.sh', includes: 'archive-full|files-history)', reason: 'Server-Provision 必须拒绝未知数据库备份 profile。', }, { file: 'scripts/jenkins-server-provision.sh', includes: '--storage-format files --mode history --work-dir', reason: 'Server-Provision 启用 files-history 前必须用真实 current release 脚本执行只读 baseline 预检。', }, { file: 'scripts/jenkins-server-provision.sh', includes: 'run_cmd rm -f "${DATABASE_BACKUP_FILES_HISTORY_DROP_IN}" "${DATABASE_BACKUP_LEGACY_DEV_DROP_IN}"', reason: 'Server-Provision 切回 archive-full 时必须移除托管及现场遗留的 history drop-in。', }, { file: 'scripts/jenkins-server-provision.sh', includes: 'install_file "${rendered_drop_in}" "${DATABASE_BACKUP_FILES_HISTORY_DROP_IN}" 0644', reason: 'Server-Provision 必须从仓库模板安装托管的 files-history drop-in。', }, { file: 'jenkins/Jenkinsfile.production-server-provision', includes: "choice(name: 'DATABASE_BACKUP_PROFILE', choices: ['archive-full', 'files-history']", reason: 'Server-Provision Job 必须显式暴露 archive-first 的数据库备份 profile。', }, { file: 'jenkins/Jenkinsfile.production-server-provision', includes: "string(name: 'DATABASE_BACKUP_FILES_HISTORY_WORK_DIR', defaultValue: '/var/lib/genarrative/database-backups/files-history'", reason: 'Server-Provision Job 必须允许 dev/release 为 files-history 选择各自的 baseline state 目录。', }, { file: 'jenkins/Jenkinsfile.production-server-provision', excludes: "params.DEPLOY_TARGET == 'release' && databaseBackupProfile == 'files-history'", reason: 'release 必须能在显式选择 profile 且 baseline 预检通过后启用 files-history。', }, { file: 'scripts/database-backup-to-oss.mjs', includes: 'assertSufficientWorkDirSpace({dataDir, workDir, args, env})', reason: '生产冷备份必须先做工作目录剩余空间预检,避免停库后写满磁盘。', }, { file: 'scripts/database-backup-to-oss.mjs', includes: 'restoreServicesAfterBackup({stopService, serviceStopped, restartServicesAfter})', reason: '生产冷备份打包失败时也必须恢复 SpacetimeDB 及依赖服务。', }, { file: 'package.json', includes: '"check:database-backup": "node scripts/check-database-backup-to-oss.mjs"', reason: '数据库冷备份事故路径必须有本地 smoke 检查入口。', }, { file: 'scripts/check-database-backup-to-oss.mjs', includes: 'assertArchiveFailureStillRestoresDependentServices', reason: '数据库冷备份 smoke 必须覆盖 tar 失败后恢复依赖服务。', }, { file: 'scripts/check-database-backup-to-oss.mjs', includes: 'assertInsufficientSpaceStopsBeforeServiceChanges', reason: '数据库冷备份 smoke 必须覆盖空间不足时不触碰 systemctl。', }, { file: 'deploy/systemd/genarrative-health-patrol.service', includes: 'scripts/ops/production-health-patrol.mjs', reason: '健康巡检 systemd service 必须调用随 API release 发布的巡检脚本。', }, { file: 'deploy/env/health-patrol.env.example', includes: 'GENARRATIVE_HEALTH_PATROL_PINGORA_BASE_URL', reason: '健康巡检环境示例必须保留 Pingora shadow 可选巡检配置。', }, { file: 'deploy/env/health-patrol.env.example', includes: 'GENARRATIVE_HEALTH_PATROL_GATEWAY_MODE=nginx', reason: '健康巡检环境示例必须显式保留默认 Nginx 网关模式。', }, { file: 'deploy/env/health-patrol.env.example', includes: 'GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST=', reason: '健康巡检环境示例必须暴露公网 Host header 配置。', }, { file: 'scripts/ops/production-health-patrol.mjs', includes: 'pingora-direct', reason: '健康巡检必须支持 Pingora 直连模式,避免直连切换后误要求 Nginx active。', }, { file: 'scripts/ops/production-health-patrol.mjs', includes: 'genarrative-pingora-gateway.service', reason: 'Pingora 直连巡检模式必须检查 Pingora gateway service。', }, { file: 'scripts/ops/production-health-patrol.mjs', includes: 'GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST', reason: '健康巡检必须支持给 public probe 传正式域名 Host header。', }, { file: 'scripts/ops/production-health-patrol.mjs', includes: 'parseRequiredPositiveInt', reason: '健康巡检 timeout 和慢请求阈值必须严格校验,不能静默回默认值。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'current release 自包含能力', reason: 'Pingora current release 自审脚本必须说明它只检查发布包自包含能力。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'scripts/check-pingora-release-readiness.mjs', reason: 'Pingora current release 自审必须确认 release readiness 聚合门禁脚本已随包发布。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'scripts/ops/pingora-direct-rehearsal-status.mjs', reason: 'Pingora current release 自审必须确认直连彩排状态脚本已随包发布。', }, { file: 'scripts/ops/pingora-direct-rehearsal-status.mjs', includes: '该脚本只读采集', reason: 'Pingora 直连彩排状态脚本必须声明只读边界。', }, { file: 'scripts/ops/pingora-direct-rehearsal-status.mjs', includes: 'ss', reason: 'Pingora 直连彩排状态脚本必须读取端口监听状态。', }, { file: 'scripts/check-pingora-direct-rehearsal-status.mjs', includes: 'assertNginxPublicRealpathRehearsalPasses', reason: 'Pingora 直连彩排状态自测必须覆盖 Nginx 公网 + realpath canary 正例。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'scripts/check-pingora-canary-live.mjs', reason: 'Pingora current release 自审必须确认 canary live smoke 脚本已随包发布。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'scripts/deploy/pingora-realpath-canary-enable.sh', reason: 'Pingora current release 自审必须确认 realpath canary 启用脚本已随包发布。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'scripts/deploy/pingora-realpath-canary-disable.sh', reason: 'Pingora current release 自审必须确认 realpath canary 关闭脚本已随包发布。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: '--systemd-show', reason: 'Pingora current release 自审必须能核验 systemd ExecStart 指向 current release。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'pingora-gateway.sha256', reason: 'Pingora current release 自审必须校验 Pingora 网关 checksum。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'release-manifest.api-server.json', reason: 'Pingora current release 自审必须读取部署后的 API release manifest。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'release manifest 缺少 pingora-gateway artifact', reason: 'Pingora current release 自审必须阻断 manifest 未登记 Pingora 产物。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'parseRequiredPositiveInt', reason: 'Pingora current release 自审 timeout 参数必须严格校验,不能静默回默认值。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: '必须是布尔值 true/false 或 1/0', reason: 'Pingora current release 自审布尔 env 必须严格校验,避免拼写错误静默降级。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'isFilesystemRootPath', reason: 'Pingora current release 自审必须显式拒绝把 release root 指到 /。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: 'validateNoControlCharacters', reason: 'Pingora current release 自审必须在执行 systemctl 前拒绝带控制字符的路径和子命令参数。', }, { file: 'scripts/ops/pingora-current-release-audit.mjs', includes: '不能包含换行或 NUL 字符', reason: 'Pingora current release 自审必须明确拒绝带换行或 NUL 的路径和子命令参数。', }, { file: 'scripts/check-pingora-current-release-audit.mjs', includes: '完整 release 自审必须确认 canary live smoke 脚本存在', reason: 'Pingora current release 自审自测必须覆盖 canary live smoke 脚本随包存在。', }, { file: 'scripts/check-pingora-current-release-audit.mjs', includes: 'assertChecksumMismatchFails', reason: 'Pingora current release 自审自测必须覆盖 checksum 不匹配负例。', }, { file: 'scripts/check-pingora-current-release-audit.mjs', includes: 'assertManifestMustRegisterIncludedPingoraGateway', reason: 'Pingora current release 自审自测必须覆盖 manifest 未登记 Pingora 负例。', }, { file: 'scripts/check-pingora-current-release-audit.mjs', includes: 'assertRejectsInvalidTimeout', reason: 'Pingora current release 自审自测必须覆盖非法 timeout 参数和 env 负例。', }, { file: 'scripts/check-pingora-current-release-audit.mjs', includes: 'assertRejectsInvalidBoolEnv', reason: 'Pingora current release 自审自测必须覆盖非法布尔 env 负例。', }, { file: 'scripts/check-pingora-current-release-audit.mjs', includes: 'assertRejectsFilesystemRootReleaseRoot', reason: 'Pingora current release 自审自测必须覆盖 release root 指到 / 的负例。', }, { file: 'scripts/check-pingora-current-release-audit.mjs', includes: 'assertRejectsPathArgsWithControlCharacters', reason: 'Pingora current release 自审自测必须覆盖带控制字符路径参数在执行 systemctl 前失败。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'scripts/ops/pingora-current-release-audit.mjs', reason: 'Pingora 切换状态快照必须把 current release 自审脚本纳入随包依赖采集。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: '--fail-on-critical', reason: 'Pingora 切换状态快照必须能作为只读硬门禁运行。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: '--run-health-patrol', reason: 'Pingora 切换状态快照必须复用生产健康巡检作为证据。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'current-release-audit', reason: 'Pingora 切换状态快照必须执行 current release 自审。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'releaseManifest', reason: 'Pingora 切换状态快照必须收录 manifest 自审结果。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'collectSecretValuesFromEnv', reason: 'Pingora 切换状态快照必须从 env 中收集敏感值用于后续输出脱敏。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'delete healthPatrolEnv.secretValues', reason: 'Pingora 切换状态快照 JSON 不能输出 health patrol env 敏感值缓存。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'delete pingoraEnv.secretValues', reason: 'Pingora 切换状态快照 JSON 不能输出 Pingora env 敏感值缓存。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'redactSecrets', reason: 'Pingora 切换状态快照必须在收录子命令 stdout/stderr 前脱敏敏感值。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'parseRequiredPositiveInt', reason: 'Pingora 切换状态快照 timeout 参数必须严格校验,不能静默回默认值。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: '必须是布尔值 true/false 或 1/0', reason: 'Pingora 切换状态快照布尔 env 必须严格校验,避免 run/fail/require 开关拼写错误静默降级。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'isFilesystemRootPath', reason: 'Pingora 切换状态快照必须显式拒绝把 release root 指到 /。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'validateNoControlCharacters', reason: 'Pingora 切换状态快照必须在执行子命令前拒绝带控制字符的路径和子命令参数。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: '不能包含换行或 NUL 字符', reason: 'Pingora 切换状态快照必须明确拒绝带换行或 NUL 的路径和子命令参数。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: '--health-patrol-env-file 不能是文件系统根目录', reason: 'Pingora 切换状态快照必须拒绝把 health patrol env 文件指到 /。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: '--pingora-env-file 不能是文件系统根目录', reason: 'Pingora 切换状态快照必须拒绝把 Pingora env 文件指到 /。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'environmentFileMatchesPingoraEnvFile', reason: 'Pingora 切换状态快照必须确认 systemd EnvironmentFile 指向本次 pingora env。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: '--expected-pingora-env-mode', reason: 'Pingora 切换状态快照必须支持按阶段强制校验 active Pingora env 是 direct 或 shadow。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'summarizePingoraEnvPosture', reason: 'Pingora 切换状态快照必须输出 active Pingora env 的 shadow/direct 姿态摘要。', }, { file: 'scripts/ops/pingora-cutover-status-snapshot.mjs', includes: 'EnvironmentFile 未包含本次 --pingora-env-file', reason: 'Pingora 切换状态快照必须在 systemd EnvironmentFile 漂移时给出明确诊断。', }, { file: 'scripts/check-pingora-cutover-status-snapshot.mjs', includes: 'assertFailOnCriticalRejectsReleaseAuditFailure', reason: 'Pingora 状态快照自测必须覆盖 current release 自审失败负例。', }, { file: 'scripts/check-pingora-cutover-status-snapshot.mjs', includes: 'assertFailOnCriticalRejectsSystemdPingoraEnvDrift', reason: 'Pingora 状态快照自测必须覆盖 systemd 读取了另一份 Pingora env 的负例。', }, { file: 'scripts/check-pingora-cutover-status-snapshot.mjs', includes: 'assertSnapshotRejectsDirectPingoraEnvModeDrift', reason: 'Pingora 状态快照自测必须覆盖启用后 active env 仍是 shadow 的负例。', }, { file: 'scripts/check-pingora-cutover-status-snapshot.mjs', includes: 'assertSnapshotRejectsShadowPingoraEnvModeDrift', reason: 'Pingora 状态快照自测必须覆盖回退后 active env 仍残留 direct TLS 配置的负例。', }, { file: 'scripts/check-pingora-cutover-status-snapshot.mjs', includes: 'assertSnapshotRedactsEnvProbeTokens', reason: 'Pingora 状态快照自测必须确认 env probe token 不进入快照输出。', }, { file: 'scripts/check-pingora-cutover-status-snapshot.mjs', includes: 'assertRejectsInvalidTimeout', reason: 'Pingora 状态快照自测必须覆盖非法 timeout 参数和 env 负例。', }, { file: 'scripts/check-pingora-cutover-status-snapshot.mjs', includes: 'assertRejectsInvalidBoolEnv', reason: 'Pingora 状态快照自测必须覆盖非法布尔 env 负例。', }, { file: 'scripts/check-pingora-cutover-status-snapshot.mjs', includes: 'assertRejectsFilesystemRootReleaseRoot', reason: 'Pingora 状态快照自测必须覆盖 release root 指到 / 的负例。', }, { file: 'scripts/check-pingora-cutover-status-snapshot.mjs', includes: 'assertRejectsPathArgsWithControlCharacters', reason: 'Pingora 状态快照自测必须覆盖带控制字符路径参数在执行 systemctl 前失败。', }, { file: 'scripts/check-pingora-cutover-status-snapshot.mjs', includes: 'assertRejectsFilesystemRootEnvFiles', reason: 'Pingora 状态快照自测必须覆盖 env 文件参数指到 / 的负例。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'snapshot.stdout.txt', reason: 'Pingora 切换证据包必须保存状态快照 stdout 便于复盘。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'direct-live.stdout.txt', reason: 'Pingora 切换证据包必须保存 direct live stdout,保留 request_id / access log 复核证据。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'parseDirectLiveJson', reason: 'Pingora 切换证据包必须能从 direct live stdout 中提取 JSON 结果。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'pingoraEnvShadow', reason: 'Pingora 切换证据包必须把状态快照中的 Pingora env shadow 摘要提升到 manifest。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '--expected-pingora-env-mode', reason: 'Pingora 切换证据包必须把 active Pingora env 姿态要求透传给状态快照。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'tlsCertFile 应为空', reason: 'Pingora env shadow 摘要必须把 TLS 证书路径残留纳入回退证据诊断。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'snapshotParseError', reason: 'Pingora 切换证据包必须把 snapshot 解析失败文件纳入 manifest 和 stdout 索引。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'directLiveParseError', reason: 'Pingora 切换证据包必须把 direct live 解析失败文件纳入 manifest 和 stdout 索引。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '--run-direct-live', reason: 'Pingora 切换证据包必须提供显式 direct live 归档开关。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '--direct-pingora-access-log', reason: 'Pingora 切换证据包 direct live 归档必须接入 access log request_id 校验路径。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'SECRET_VALUE_FLAGS', reason: 'Pingora 切换证据包命令记录必须集中维护敏感参数脱敏列表。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '', reason: 'Pingora 切换证据包命令记录不能落盘 probe token 原文。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'args: redactSecretArgs', reason: 'Pingora 切换证据包命令记录必须保存结构化脱敏参数数组。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'validateEvidenceCommandArgs', reason: 'Pingora 切换证据包必须在执行状态快照或 direct live 前拒绝带控制字符的子命令参数。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'validateSafeAbsoluteFilePath', reason: 'Pingora 切换证据包 direct live 显式文件路径必须统一拒绝相对路径、根目录和控制字符。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '--direct-spacetime-database', reason: 'Pingora 切换证据包必须在配置层拒绝带控制字符的 direct SpacetimeDB 数据库名。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '--direct-probe-token', reason: 'Pingora 切换证据包必须在配置层拒绝带控制字符的 direct live probe token。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '不能包含换行或 NUL 字符', reason: 'Pingora 切换证据包必须明确拒绝带换行或 NUL 的状态快照 / direct live 参数。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: "createHash('sha256')", reason: 'Pingora 切换证据包 manifest 必须记录证据文件 sha256,便于归档后复核。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'sizeBytes', reason: 'Pingora 切换证据包 manifest 必须记录证据文件大小,便于归档后复核。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'snapshot-command.json 结构化参数数组必须保留快照参数', reason: 'Pingora 切换证据包自测必须覆盖结构化命令参数记录。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertManifestFileMetadata', reason: 'Pingora 切换证据包自测必须覆盖 manifest 文件大小与 sha256 元数据。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertBundleCanArchiveDirectLiveEvidence', reason: 'Pingora 切换证据包自测必须覆盖 direct live 证据归档成功路径。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertBundleSummarizesPingoraEnvShadow', reason: 'Pingora 切换证据包自测必须覆盖 Pingora env shadow 摘要成功路径。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertDirectLiveFailureStillWritesEvidenceAndFails', reason: 'Pingora 切换证据包自测必须覆盖 direct live 失败时保留证据并失败。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertDirectLiveParseFailureWritesParseErrorEvidence', reason: 'Pingora 切换证据包自测必须覆盖 direct live stdout 解析失败时保留 parse error 证据。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertSnapshotParseFailureWritesParseErrorEvidence', reason: 'Pingora 切换证据包自测必须覆盖 snapshot stdout 解析失败时保留 parse error 证据。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertRejectsSnapshotArgsWithControlCharacters', reason: 'Pingora 切换证据包自测必须覆盖带控制字符的状态快照参数在执行前失败。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertRejectsDirectLiveArgsWithControlCharacters', reason: 'Pingora 切换证据包自测必须覆盖带控制字符的 direct live 参数在执行前失败。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: '--direct-pingora-access-log 不能是文件系统根目录', reason: 'Pingora 切换证据包自测必须覆盖 direct live access log 指到 / 的负例。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: '--direct-access-log-since-lines 不能包含换行或 NUL 字符', reason: 'Pingora 切换证据包自测必须覆盖 direct live access log tail 行数带控制字符的负例。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'BUNDLE_DIR_MODE = 0o750', reason: 'Pingora 切换证据包目录必须显式限制为 owner/group 可读。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'EVIDENCE_FILE_MODE = 0o640', reason: 'Pingora 切换证据文件必须显式禁止 world-readable。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: "flag: 'wx'", reason: 'Pingora 切换证据包写文件必须避免覆盖既有证据。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'validatePhase(config.phase);', reason: 'Pingora 切换证据包必须拒绝不安全 phase,避免目录名和 manifest 阶段漂移。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'validateOutputRootForWriting(outputRoot);', reason: 'Pingora 切换证据包写入前必须复核 output-root 路径,避免写入软链或非目录。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '--output-root 不能是符号链接', reason: 'Pingora 切换证据包必须拒绝符号链接 output-root。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '--output-root 已存在但不是目录', reason: 'Pingora 切换证据包必须拒绝已存在但不是目录的 output-root。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '不能是文件系统根目录', reason: 'Pingora 切换证据包必须拒绝把显式路径参数指到 /。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'parseRequiredPositiveInt', reason: 'Pingora 切换证据包 timeout 参数必须严格校验,不能静默回默认值。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '必须是布尔值 true/false 或 1/0', reason: 'Pingora 切换证据包布尔 env 必须严格校验,避免证据生成开关拼写错误静默降级。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertRejectsUnsafePhase', reason: 'Pingora 切换证据包自测必须覆盖不安全 phase 负例。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertBundleRedactsProbeTokensFromArtifacts', reason: 'Pingora 切换证据包自测必须确认所有证据文件不落盘 probe token 原文。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertMode', reason: 'Pingora 切换证据包自测必须断言目录和文件权限。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertRejectsInvalidTimeout', reason: 'Pingora 切换证据包自测必须覆盖非法 timeout 参数和 env 负例。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertRejectsInvalidBoolEnv', reason: 'Pingora 切换证据包自测必须覆盖非法布尔 env 负例。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertRejectsSymlinkOutputRootBeforeSnapshot', reason: 'Pingora 切换证据包自测必须覆盖符号链接 output-root,且失败时不执行状态快照。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertRejectsFileOutputRootBeforeSnapshot', reason: 'Pingora 切换证据包自测必须覆盖非目录 output-root,且失败时不执行状态快照。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertRejectsFilesystemRootPaths', reason: 'Pingora 切换证据包自测必须覆盖显式路径参数指向文件系统根目录的负例。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '--require-pingora-gateway', reason: 'Pingora 切换证据包必须能透传发布物自审要求。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: '只写 --output-root 下的新证据目录', reason: 'Pingora 切换证据包必须明确不会修改 /etc、systemd、Nginx 或 Pingora。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: 'command.stdout.txt', reason: 'Pingora 切换命令证据脚本必须保存真实命令 stdout。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: 'command.stderr.txt', reason: 'Pingora 切换命令证据脚本必须保存真实命令 stderr。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: 'command-record.json', reason: 'Pingora 切换命令证据脚本必须保存结构化命令记录。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: "createHash('sha256')", reason: 'Pingora 切换命令证据 manifest 必须记录证据文件 sha256,便于归档后复核。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: 'sizeBytes', reason: 'Pingora 切换命令证据 manifest 必须记录证据文件大小,便于归档后复核。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: 'redactSecrets(text', reason: 'Pingora 切换命令证据脚本必须脱敏 stdout/stderr 中的 probe token。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: 'validateCommandPath(config.command);', reason: 'Pingora 切换命令证据脚本必须拒绝非绝对路径真实命令。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: 'path.resolve(command) === path.parse(path.resolve(command)).root', reason: 'Pingora 切换命令证据脚本必须拒绝文件系统根目录真实命令。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: '/[\\0\\r\\n]/u.test(command)', reason: 'Pingora 切换命令证据脚本必须拒绝带换行或 NUL 的真实命令。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: '真实命令参数不能包含换行或 NUL 字符', reason: 'Pingora 切换命令证据脚本必须拒绝带换行或 NUL 的真实命令参数。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: '--expected-executable', reason: 'Pingora 切换命令证据脚本必须支持绑定预期真实命令。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: "validateSafeExecutablePath(config.expectedExecutable, '--expected-executable')", reason: 'Pingora 切换命令证据生成端必须拒绝不安全 expected executable 路径。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: '--require-arg', reason: 'Pingora 切换命令证据脚本必须支持执行前校验真实命令必需参数。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: '真实命令与 --expected-executable 不一致', reason: 'Pingora 切换命令证据脚本必须拒绝挂错真实执行脚本。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: '真实命令参数缺少 --require-arg 要求', reason: 'Pingora 切换命令证据脚本必须在执行前拒绝缺少必需参数的真实命令。', }, { file: 'scripts/ops/pingora-cutover-command-evidence.mjs', includes: "validateNoControlCharacters(config.outputRoot, '--output-root')", reason: 'Pingora 切换命令证据脚本必须拒绝带换行或 NUL 的 output-root。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertCommandFailureStillWritesEvidenceAndFails', reason: 'Pingora 切换命令证据自测必须覆盖真实命令失败时仍保留证据。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertRejectsMissingRequiredArgBeforeCommand', reason: 'Pingora 切换命令证据自测必须覆盖缺少 --apply 时执行前失败。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertRejectsBareCommandName', reason: 'Pingora 切换命令证据自测必须覆盖 PATH 裸命令名被拒绝。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertRejectsFilesystemRootCommand', reason: 'Pingora 切换命令证据自测必须覆盖文件系统根目录真实命令被拒绝。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertRejectsOutputRootWithControlCharacters', reason: 'Pingora 切换命令证据自测必须覆盖 output-root 带控制字符的负例。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertRejectsCommandWithControlCharacters', reason: 'Pingora 切换命令证据自测必须覆盖带控制字符真实命令被拒绝。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertRejectsCommandArgWithControlCharacters', reason: 'Pingora 切换命令证据自测必须覆盖带控制字符真实命令参数被拒绝。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertRejectsFilesystemRootExpectedExecutable', reason: 'Pingora 切换命令证据自测必须覆盖 expected executable 指到 / 的负例。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertRejectsExpectedExecutableWithControlCharacters', reason: 'Pingora 切换命令证据自测必须覆盖 expected executable 带控制字符的负例。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertCommandEvidenceRedactsProbeTokensFromArtifacts', reason: 'Pingora 切换命令证据自测必须覆盖 token 不落盘。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertManifestFileMetadata', reason: 'Pingora 切换命令证据自测必须覆盖 manifest 文件大小与 sha256 元数据。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertRejectsSymlinkOutputRootBeforeCommand', reason: 'Pingora 切换命令证据自测必须覆盖符号链接 output-root 且失败时不执行真实命令。', }, { file: 'scripts/check-pingora-cutover-command-evidence.mjs', includes: 'assertRejectsMismatchedExpectedExecutableBeforeCommand', reason: 'Pingora 切换命令证据自测必须覆盖 expected executable 不匹配且失败时不执行真实命令。', }, { file: 'scripts/check-production-health-patrol.mjs', includes: 'assertPingoraDirectModeChecksPingoraServiceAndPublicHost', reason: '生产健康巡检动态烟测必须覆盖 Pingora 直连模式和 public Host header。', }, { file: 'scripts/check-production-health-patrol.mjs', includes: 'assertRejectsInvalidTimeoutAndSlowThreshold', reason: '生产健康巡检动态烟测必须覆盖非法 timeout 和慢请求阈值负例。', }, { file: 'scripts/ops/production-health-patrol.mjs', includes: '必须是布尔值 true/false 或 1/0', reason: '生产健康巡检布尔 env 必须严格校验,避免 fail-on-warning / skip-journal 拼写错误静默降级。', }, { file: 'scripts/check-production-health-patrol.mjs', includes: 'assertRejectsInvalidBoolEnv', reason: '生产健康巡检动态烟测必须覆盖非法布尔 env 负例。', }, { file: 'scripts/check-production-health-patrol-env.mjs', includes: 'Pingora direct 模式使用本机 public base URL 时必须配置 GENARRATIVE_HEALTH_PATROL_PUBLIC_HOST', reason: '生产健康巡检 env 复核必须阻断直连后本机探测缺少正式 Host 的配置。', }, { file: 'scripts/check-production-health-patrol-env.mjs', includes: '必须是布尔值 true/false 或 1/0', reason: '生产健康巡检 env 复核布尔 env 必须严格校验,避免 require-empty-public-host 拼写错误静默降级。', }, { file: 'scripts/check-production-health-patrol-env.mjs', includes: 'isFilesystemRootPath', reason: '生产健康巡检 env 复核必须显式拒绝把 env 文件指到 /。', }, { file: 'scripts/check-production-health-patrol-env-check.mjs', includes: 'assertRejectsPingoraDirectLoopbackWithoutHost', reason: '生产健康巡检 env 自测必须覆盖 Pingora direct loopback 缺 Host 负例。', }, { file: 'scripts/check-production-health-patrol-env-check.mjs', includes: 'assertRejectsInvalidBoolEnv', reason: '生产健康巡检 env 自测必须覆盖非法布尔 env 负例。', }, { file: 'scripts/check-production-health-patrol-env-check.mjs', includes: 'assertRejectsInvalidEnvFilePaths', reason: '生产健康巡检 env 自测必须覆盖相对路径和 / 路径负例。', }, { file: 'deploy/logrotate/genarrative-pingora-gateway', includes: '/var/log/genarrative/pingora-gateway.access.log', reason: 'Pingora access log 必须有 logrotate 模板,避免 canary 日志无限增长。', }, { file: 'deploy/systemd/genarrative-health-patrol.timer', includes: 'genarrative-health-patrol.service', reason: '健康巡检 timer 必须绑定巡检 service。', }, { file: 'deploy/systemd/genarrative-pingora-gateway.service', includes: '/var/log/genarrative', reason: 'Pingora systemd 沙箱必须允许写入 access log 目录。', }, { file: 'deploy/systemd/genarrative-pingora-gateway.service', includes: '影子网关只监听本机高端口', reason: 'Pingora 主 service 必须保持默认 shadow 口径,不能默认声明公网直连。', }, { file: 'deploy/systemd/genarrative-pingora-gateway.service', excludes: 'AmbientCapabilities=CAP_NET_BIND_SERVICE', reason: 'Pingora 主 service 不能默认带低端口 capability,直连只能通过显式 drop-in 启用。', }, { file: 'deploy/systemd/genarrative-pingora-gateway-direct-entry.conf', includes: 'AmbientCapabilities=CAP_NET_BIND_SERVICE', reason: 'Pingora 直连 80/443 时必须通过显式 drop-in 授予低端口绑定能力。', }, { file: 'deploy/systemd/genarrative-pingora-gateway-direct-entry.conf', includes: 'CapabilityBoundingSet=CAP_NET_BIND_SERVICE', reason: 'Pingora 直连 drop-in 必须把 capability 边界限制为低端口绑定。', }, { file: 'deploy/systemd/genarrative-pingora-gateway-direct-entry.conf', includes: '/etc/systemd/system/genarrative-pingora-gateway.service.d/direct-entry.conf', reason: 'Pingora 直连 drop-in 必须明确人工启用位置,不能被误认为默认生效。', }, { file: 'deploy/nginx/snippets/genarrative-pingora-canary.conf', includes: 'X-Genarrative-Nginx-Handoff', reason: 'Pingora canary snippet 必须带明确响应头,方便验证 Nginx 已经切到 Pingora handoff。', }, { file: 'deploy/nginx/snippets/genarrative-pingora-canary.conf', includes: 'deny all', reason: 'Pingora canary snippet 默认必须限制访问来源,避免误 include 后公开接流。', }, { file: 'deploy/nginx/snippets/genarrative-pingora-realpath-canary.conf', includes: 'listen 127.0.0.1:18083;', reason: 'Pingora 真实路径 canary 必须默认只监听本机端口,避免误 include 后公开接流。', }, { file: 'deploy/nginx/snippets/genarrative-pingora-realpath-canary.conf', includes: 'genarrative-pingora-realpath-canary.access.log', reason: 'Pingora 真实路径 canary 必须使用独立 Nginx access log,避免和生产真实路径请求混淆。', }, { file: 'deploy/nginx/snippets/genarrative-pingora-realpath-canary.conf', includes: 'pingora-realpath-canary', reason: 'Pingora 真实路径 canary 必须带独立 handoff 标识,方便区分前缀 canary。', }, { file: 'deploy/nginx/snippets/genarrative-pingora-realpath-canary.conf', includes: 'location = /api/assets/history', reason: 'Pingora 真实路径 canary 必须覆盖代表性 API 真实路径。', }, { file: 'deploy/nginx/README.md', includes: 'zz-genarrative-pingora-realpath-canary.conf', reason: 'Pingora 真实路径 canary 运维说明必须记录 conf.d 加载顺序,避免早于 log_format 定义加载。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'unknown log format "genarrative_upstream"', reason: 'Pingora 试点文档必须记录 realpath canary 的 Nginx log_format 加载顺序踩坑。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: 'Pingora realpath canary include 要晚于 log_format', reason: '团队共享踩坑必须记录 realpath canary 独立 server 在 conf.d 中的加载顺序要求。', }, { file: 'scripts/jenkins-server-provision.sh', includes: 'genarrative-health-patrol.timer', reason: 'Server-Provision 必须安装并启用健康巡检 timer。', }, { file: 'scripts/jenkins-server-provision.sh', includes: 'genarrative-pingora-canary.conf', reason: 'Server-Provision 必须安装 Pingora canary snippet,供人工启用 Nginx handoff。', }, { file: 'scripts/jenkins-server-provision.sh', includes: 'genarrative-pingora-realpath-canary.conf', reason: 'Server-Provision 必须安装 Pingora 真实路径 canary snippet,供人工启用直连前中间验证。', }, { file: 'scripts/jenkins-server-provision.sh', includes: 'genarrative-pingora-gateway', reason: 'Server-Provision 必须安装 Pingora access log 的 logrotate 配置。', }, { file: 'scripts/jenkins-server-provision.sh', includes: '/etc/genarrative/pingora/genarrative-pingora-gateway-direct-entry.conf', reason: 'Server-Provision 必须只把 Pingora 直连 drop-in 安装为人工启用模板。', }, { file: 'scripts/jenkins-server-provision.sh', includes: 'genarrative-external-generation-controller.service', reason: 'Server-Provision 必须安装并启用外部生成 worker controller。', }, { file: 'scripts/jenkins-server-provision.sh', includes: 'genarrative-external-generation-worker@1.service', reason: 'Server-Provision 必须启用外部生成保底 worker 实例。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'ensure_default_worker_service', reason: 'API Deploy 必须在缺少 worker 实例时补启动默认外部生成 worker。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'wait_for_worker_services', reason: 'API Deploy 必须等待外部生成 worker 实例 active。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'wait_for_worker_controller_service', reason: 'API Deploy 必须重启并验活外部生成 worker controller。', }, { file: 'deploy/systemd/genarrative-external-generation-worker@.service', includes: 'GENARRATIVE_PROCESS_ROLE=external-generation-worker', reason: '外部生成 worker 模板必须作为独立 worker 进程角色运行。', }, { file: 'deploy/systemd/genarrative-external-generation-controller.service', includes: 'GENARRATIVE_PROCESS_ROLE=external-generation-controller', reason: '外部生成 worker controller 必须作为独立进程角色运行。', }, { file: 'scripts/ops/production-health-patrol.mjs', includes: 'checkActiveWorkerInstances', reason: '生产健康巡检必须检查至少一个外部生成 worker 实例 active。', }, { file: 'scripts/build-production-release.sh', includes: 'production-health-patrol.mjs', reason: '生产 API release 必须携带健康巡检脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/ops/pingora-current-release-audit.mjs', reason: '生产 API release 必须携带 Pingora current release 自审脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/ops/pingora-direct-rehearsal-status.mjs', reason: '生产 API release 必须携带 Pingora 直连彩排状态脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/ops/pingora-cutover-status-snapshot.mjs', reason: '生产 API release 必须携带 Pingora 切换状态快照脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', reason: '生产 API release 必须携带 Pingora 切换证据包脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/ops/pingora-cutover-command-evidence.mjs', reason: '生产 API release 必须携带 Pingora 切换命令证据脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'check-production-health-patrol-env.mjs', reason: '生产 API release 必须携带健康巡检 env 复核脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'check-pingora-release-readiness.mjs', reason: '生产 API release 必须携带 Pingora release readiness 聚合门禁脚本,确保正式 runbook 不依赖源码 checkout。', }, { file: 'scripts/build-production-release.sh', includes: 'check-pingora-canary-live.mjs', reason: '生产 API release 必须携带 Pingora canary live smoke 脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'check-pingora-canary-access-log-parity.mjs', reason: '生产 API release 必须携带 Pingora canary access log 对账脚本。', }, { file: 'scripts/build-production-release.sh', includes: '--include-pingora-gateway', reason: 'Pingora 影子网关必须保持显式可选产物打包入口。', }, { file: 'scripts/build-production-release.sh', includes: 'require_pingora_build_toolchain', reason: '显式构建 Pingora 影子网关时必须先检查 cmake 和 C/C++ 编译器。', }, { file: 'scripts/build-production-release.sh', includes: 'require_command cmake', reason: 'Pingora release 构建必须对 cmake 缺失 fail-fast。', }, { file: 'scripts/build-production-release.sh', includes: 'require_any_command "C++ 编译器"', reason: 'Pingora release 构建必须对 C++ 编译器缺失 fail-fast。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/deploy/production-api-deploy.sh', reason: '生产 API release 必须携带随产物执行的 API deploy 脚本。', }, { file: 'scripts/build-production-release.sh', includes: '同目录的 \\`maintenance-on.sh\\` / \\`maintenance-off.sh\\` 必须来自同一发布包', reason: '生产 API release README 必须说明 deploy 同目录维护脚本来自同一发布包。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/deploy/maintenance-on.sh', reason: '生产 API release 必须在 deploy 脚本同目录携带 maintenance-on.sh。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/deploy/maintenance-off.sh', reason: '生产 API release 必须在 deploy 脚本同目录携带 maintenance-off.sh。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/deploy/pingora-direct-rollback.sh', reason: '生产 API release 必须携带 Pingora 直连回退脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/deploy/pingora-realpath-canary-enable.sh', reason: '生产 API release 必须携带 Pingora realpath canary 启用脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/deploy/pingora-realpath-canary-disable.sh', reason: '生产 API release 必须携带 Pingora realpath canary 关闭脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', reason: '生产 API release 必须携带 Pingora health patrol env 切换脚本。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--health-patrol-expected-public-base-url', reason: 'Pingora 直连回退脚本必须能复核 health patrol public base URL 已恢复为切换前记录值。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--health-patrol-expected-public-host', reason: 'Pingora 直连回退脚本必须能复核切换前存在的 health patrol public Host 覆盖。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/deploy/pingora-direct-enable.sh', reason: '生产 API release 必须携带 Pingora 直连启用脚本。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/check-pingora-direct-preflight.mjs', reason: '生产 API release 必须携带 Pingora 直连预检脚本,确保 current release 可独立执行直连启用。', }, { file: 'scripts/build-production-release.sh', includes: 'scripts/check-pingora-direct-live.mjs', reason: '生产 API release 必须携带 Pingora 直连 live smoke 脚本,确保启用脚本 apply 后可独立验收。', }, { file: 'scripts/build-production-release.sh', includes: 'deploy/pingora', reason: '生产 API release 必须携带 Pingora 配置目录,供直连预检读取 env 示例和路由矩阵。', }, { file: 'scripts/build-production-release.sh', includes: 'deploy/env', reason: '生产 API release 必须携带 env 示例目录,供健康巡检和 Pingora live smoke 复制配置。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'ENV_DEPLOY_DIR_SOURCE', reason: 'API deploy 必须从发布产物复制 env 示例目录到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'PINGORA_CANARY_LIVE_SCRIPT_SOURCE', reason: 'API deploy 必须从发布产物复制 Pingora canary live smoke 脚本到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'PINGORA_REALPATH_CANARY_ENABLE_SCRIPT_SOURCE', reason: 'API deploy 必须从发布产物复制 Pingora realpath canary 启用脚本到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'PINGORA_REALPATH_CANARY_DISABLE_SCRIPT_SOURCE', reason: 'API deploy 必须从发布产物复制 Pingora realpath canary 关闭脚本到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '发布产物缺少 Pingora realpath canary 启用脚本', reason: 'API deploy 缺少 realpath canary 启用脚本时必须 fail-fast。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '发布产物缺少 Pingora realpath canary 关闭脚本', reason: 'API deploy 缺少 realpath canary 关闭脚本时必须 fail-fast。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'PINGORA_CURRENT_RELEASE_AUDIT_SCRIPT_SOURCE', reason: 'API deploy 必须从发布产物复制 Pingora current release 自审脚本。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'PINGORA_DIRECT_REHEARSAL_STATUS_SCRIPT_SOURCE', reason: 'API deploy 必须从发布产物复制 Pingora 直连彩排状态脚本。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'PINGORA_CUTOVER_STATUS_SNAPSHOT_SCRIPT_SOURCE', reason: 'API deploy 必须从发布产物复制 Pingora 切换状态快照脚本。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'PINGORA_CUTOVER_EVIDENCE_BUNDLE_SCRIPT_SOURCE', reason: 'API deploy 必须从发布产物复制 Pingora 切换证据包脚本。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'PINGORA_CUTOVER_COMMAND_EVIDENCE_SCRIPT_SOURCE', reason: 'API deploy 必须从发布产物复制 Pingora 切换命令证据脚本。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'deploy/env/health-patrol.env.example', reason: 'API release 动态烟测必须断言健康巡检 env 示例随包发布。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/ops/pingora-current-release-audit.mjs', reason: 'API release 动态烟测必须断言 Pingora current release 自审脚本随包发布。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/ops/pingora-direct-rehearsal-status.mjs', reason: 'API release 动态烟测必须断言 Pingora 直连彩排状态脚本随包发布。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/ops/pingora-cutover-status-snapshot.mjs', reason: 'API release 动态烟测必须断言 Pingora 切换状态快照脚本随包发布。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', reason: 'API release 动态烟测必须断言 Pingora 切换证据包脚本随包发布。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/ops/pingora-cutover-command-evidence.mjs', reason: 'API release 动态烟测必须断言 Pingora 切换命令证据脚本随包发布。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/check-production-health-patrol-env.mjs', reason: 'API release 动态烟测必须断言健康巡检 env 复核脚本随包发布。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/deploy/pingora-realpath-canary-enable.sh', reason: 'API release 动态烟测必须断言 Pingora realpath canary 启用脚本随包发布。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/deploy/pingora-realpath-canary-disable.sh', reason: 'API release 动态烟测必须断言 Pingora realpath canary 关闭脚本随包发布。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'deploy/env/health-patrol.env.example', reason: 'API deploy 动态烟测必须断言健康巡检 env 示例复制到 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/ops/pingora-current-release-audit.mjs', reason: 'API deploy 动态烟测必须断言 Pingora current release 自审脚本复制到 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/ops/pingora-cutover-status-snapshot.mjs', reason: 'API deploy 动态烟测必须断言 Pingora 切换状态快照脚本复制到 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', reason: 'API deploy 动态烟测必须断言 Pingora 切换证据包脚本复制到 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/ops/pingora-cutover-command-evidence.mjs', reason: 'API deploy 动态烟测必须断言 Pingora 切换命令证据脚本复制到 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/deploy/pingora-realpath-canary-enable.sh', reason: 'API deploy 动态烟测必须断言 Pingora realpath canary 启用脚本复制到 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/deploy/pingora-realpath-canary-disable.sh', reason: 'API deploy 动态烟测必须断言 Pingora realpath canary 关闭脚本复制到 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertMissingPingoraRealpathCanaryEnableFails', reason: 'API deploy 动态烟测必须覆盖缺少 Pingora realpath canary 启用脚本时 fail-fast。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertMissingPingoraRealpathCanaryDisableFails', reason: 'API deploy 动态烟测必须覆盖缺少 Pingora realpath canary 关闭脚本时 fail-fast。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertMissingPingoraCutoverCommandEvidenceFails', reason: 'API deploy 动态烟测必须覆盖缺少 Pingora 切换命令证据脚本时 fail-fast。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertMissingHealthPatrolEnvCheckFails', reason: 'API deploy 动态烟测必须覆盖缺少健康巡检 env 复核脚本时 fail-fast。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertMissingEnvExamplesFails', reason: 'API deploy 动态烟测必须覆盖缺少 env 示例目录时 fail-fast。', }, { file: 'package.json', includes: 'deploy:pingora-direct-enable', reason: 'Pingora 直连启用必须保留可重复执行的 npm 入口。', }, { file: 'package.json', includes: 'check:pingora-realpath-canary-toggle', reason: 'Pingora realpath canary 启停脚本必须有本地自测入口。', }, { file: 'package.json', includes: 'deploy:pingora-realpath-canary-enable', reason: 'Pingora realpath canary 启用必须保留可重复执行的 npm 入口。', }, { file: 'package.json', includes: 'deploy:pingora-realpath-canary-disable', reason: 'Pingora realpath canary 关闭必须保留可重复执行的 npm 入口。', }, { file: 'package.json', includes: 'deploy:pingora-direct-rollback', reason: 'Pingora 直连回退必须保留可重复执行的 npm 入口。', }, { file: 'package.json', includes: 'check:pingora-gateway-smoke', reason: 'Pingora 网关必须保留可重复本地 smoke 入口。', }, { file: 'package.json', includes: 'check:nginx-pingora-canary', reason: 'Pingora Nginx canary snippet 必须保留可重复本地校验入口。', }, { file: 'package.json', includes: 'check:pingora-route-parity', reason: 'Pingora 与 Nginx 路由矩阵必须保留可重复本地校验入口。', }, { file: 'package.json', includes: 'check:pingora-canary-live', reason: 'Pingora Nginx 前缀 canary 必须保留启用后的真实入口 smoke。', }, { file: 'package.json', includes: 'check:pingora-direct-live', reason: 'Pingora 直连 HTTPS / HTTP redirect 必须保留目标机 live smoke。', }, { file: 'package.json', includes: 'check:pingora-direct-live-guard', reason: 'Pingora direct live 参数护栏必须保留单独 npm 入口,方便正式切换前聚合门禁和本地 focused 验证复用。', }, { file: 'package.json', includes: 'check:pingora-direct-preflight', reason: 'Pingora 直连切换前必须保留目标机 env / systemd / 端口预检入口。', }, { file: 'package.json', includes: 'check:pingora-direct-enable', reason: 'Pingora 直连启用必须保留可重复 dry-run 行为检查入口。', }, { file: 'package.json', includes: 'check:pingora-direct-rollback', reason: 'Pingora 直连回退必须保留可重复 dry-run 行为检查入口。', }, { file: 'package.json', includes: 'check:pingora-canary-docker', reason: 'Pingora Nginx handoff 必须保留本机 Docker 可复现 smoke。', }, { file: 'package.json', includes: 'check:pingora-production-release-build', reason: 'Pingora release 真实构建烟测必须保留可重复 npm 入口。', }, { file: 'package.json', includes: 'check:pingora-release-readiness', reason: 'Pingora 正式切换前必须保留聚合门禁入口。', }, { file: 'package.json', includes: 'plan:pingora-direct-cutover', reason: 'Pingora 直连切换必须保留可审阅 runbook 计划入口。', }, { file: 'package.json', includes: 'check:pingora-release-readiness-plan', reason: 'Pingora 聚合门禁计划必须有可重复自检入口。', }, { file: 'package.json', includes: 'check:production-api-release', reason: 'API release build 动态烟测必须保留可重复 npm 入口。', }, { file: 'package.json', includes: 'check:production-health-patrol', reason: '生产健康巡检动态烟测必须保留可重复 npm 入口。', }, { file: 'package.json', includes: 'check:production-health-patrol-env', reason: '生产健康巡检 env 复核动态烟测必须保留可重复 npm 入口。', }, { file: 'package.json', includes: 'check:pingora-health-patrol-env-switch', reason: 'Pingora health patrol env 切换脚本必须保留可重复 npm 自测入口。', }, { file: 'package.json', includes: 'check:pingora-gateway-env-shadow-switch', reason: 'Pingora gateway env shadow 切换脚本必须保留可重复 npm 自测入口。', }, { file: 'package.json', includes: 'check:pingora-current-release-audit', reason: 'Pingora current release 自审必须保留可重复 npm 自测入口。', }, { file: 'package.json', includes: 'check:pingora-direct-rehearsal-status', reason: 'Pingora 直连彩排状态脚本必须保留可重复 npm 自测入口。', }, { file: 'package.json', includes: 'check:pingora-cutover-status-snapshot', reason: 'Pingora 切换状态快照脚本必须保留可重复 npm 自测入口。', }, { file: 'package.json', includes: 'check:pingora-cutover-evidence-bundle', reason: 'Pingora 切换证据包必须保留可重复 npm 自测入口。', }, { file: 'package.json', includes: 'check:pingora-cutover-command-evidence', reason: 'Pingora 切换命令证据必须保留可重复 npm 自测入口。', }, { file: 'package.json', includes: 'check:pingora-canary-access-log-parity', reason: 'Pingora canary access log 对账必须保留可重复 npm 自测入口。', }, { file: 'package.json', includes: 'check:pingora-canary-live-guard', reason: 'Pingora canary live 参数护栏必须保留单独 npm 入口,方便正式切换前 focused 验证复用。', }, { file: 'package.json', includes: 'check:production-api-deploy', reason: 'API deploy 动态烟测必须保留可重复 npm 入口。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:production-api-release', reason: 'Pingora 聚合门禁必须执行 API release build 动态烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-production-release-build', reason: 'Pingora 聚合门禁必须执行真实 Pingora release 构建烟测。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'Pingora production release 真实构建烟测', reason: 'Pingora 聚合门禁计划自检必须覆盖真实 release 构建烟测。', }, { file: 'scripts/check-pingora-production-release-build.mjs', includes: '--include-pingora-gateway', reason: 'Pingora production release 构建烟测必须走真实 include 打包路径。', }, { file: 'scripts/check-pingora-production-release-build.mjs', includes: 'CARGO_TARGET_DIR', reason: 'Pingora production release 构建烟测必须使用临时 target,避免污染本地默认 target。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:production-api-deploy', reason: 'Pingora 聚合门禁必须执行 API deploy 动态烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'redactSecretArgs(args).join', reason: 'Pingora 聚合门禁真实执行日志必须隐藏 probe token 参数值。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertRunStepLogRedactsDirectProbeToken', reason: 'Pingora 聚合门禁计划自测必须覆盖真实执行日志 token 脱敏。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:production-health-patrol', reason: 'Pingora 聚合门禁必须执行生产健康巡检动态烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:production-health-patrol-env', reason: 'Pingora 聚合门禁必须执行生产健康巡检 env 动态烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-health-patrol-env-switch', reason: 'Pingora 聚合门禁必须执行 health patrol env 切换脚本烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-gateway-env-shadow-switch', reason: 'Pingora 聚合门禁必须执行 gateway env shadow 切换脚本烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-current-release-audit', reason: 'Pingora 聚合门禁必须执行 current release 自审烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-direct-rehearsal-status', reason: 'Pingora 聚合门禁必须执行直连彩排状态烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-cutover-status-snapshot', reason: 'Pingora 聚合门禁必须执行切换状态快照烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-cutover-evidence-bundle', reason: 'Pingora 聚合门禁必须执行切换证据包烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-cutover-command-evidence', reason: 'Pingora 聚合门禁必须执行切换命令证据烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'scripts/ops/pingora-cutover-command-evidence.mjs', reason: 'Pingora cutover runbook apply 步骤必须使用 current release 随包命令证据脚本。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--expected-executable', reason: 'Pingora cutover runbook apply 步骤必须把命令证据绑定到预期 current release 脚本。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--require-arg', reason: 'Pingora cutover runbook apply 步骤必须让命令证据脚本提前校验 --apply 参数。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'pingora-direct-rollback-apply', reason: 'Pingora runbook 自检必须确认 rollback apply 被命令证据脚本归档。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '必须在命令证据脚本中要求真实命令参数', reason: 'Pingora runbook 自检必须锁住命令证据脚本的 --apply 早失败参数。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'pingora-direct-enable-apply', reason: 'Pingora runbook 自检必须确认 enable apply 被命令证据脚本归档。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用命令证据 manifest 只读验真', reason: 'Pingora cutover runbook 必须在 enable apply 命令证据生成后立即验真 manifest。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '', reason: 'Pingora cutover runbook 必须提示用 enable apply 命令证据 bundleDir 执行即时验真。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--require-summary-ok', reason: 'Pingora cutover runbook 的即时证据验真必须要求 manifest.summary.status 为 OK。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '回退命令证据 manifest 只读验真', reason: 'Pingora cutover runbook 必须在 rollback apply 命令证据生成后立即验真 manifest。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '', reason: 'Pingora cutover runbook 必须提示用 rollback apply 命令证据 bundleDir 执行即时验真。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '启用命令证据验真必须使用 current release 随包 verifier', reason: 'Pingora runbook 自检必须锁住 enable apply 命令证据即时验真脚本来源。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '回退命令证据验真必须使用 current release 随包 verifier', reason: 'Pingora runbook 自检必须锁住 rollback apply 命令证据即时验真脚本来源。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover 必须先验真 enable apply 命令证据,再切换 health patrol 到 pingora-direct', reason: 'Pingora runbook 自检必须锁住 enable apply 命令证据即时验真的执行顺序。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover 必须先验真 rollback apply 命令证据,再执行回退后 env 复核', reason: 'Pingora runbook 自检必须锁住 rollback apply 命令证据即时验真的执行顺序。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-canary-access-log-parity', reason: 'Pingora 聚合门禁必须执行 canary access log 对账烟测。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'scripts/check-pingora-canary-live-guard.mjs', reason: 'Pingora 聚合门禁必须执行 canary live 参数护栏,避免正式切换前漏掉脚本输入污染负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'Pingora canary access log 对账烟测', reason: 'Pingora 聚合门禁计划自检必须覆盖 canary access log 对账烟测。', }, { file: 'scripts/check-pingora-health-patrol-env-switch.mjs', includes: '复核失败时 apply 不应写入真实 health patrol env 文件', reason: 'Pingora health patrol env 切换脚本自测必须覆盖复核失败不落盘。', }, { file: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', includes: '必须是布尔值 true/false 或 1/0', reason: 'Pingora health patrol env 切换脚本布尔 env 必须严格校验,避免 clear-public-host 拼写错误静默降级。', }, { file: 'scripts/check-pingora-health-patrol-env-switch.mjs', includes: 'assertRejectsInvalidBoolEnv', reason: 'Pingora health patrol env 切换脚本自测必须覆盖非法布尔 env 负例。', }, { file: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', includes: 'DRY_RUN_ENV_FILE_MODE = 0o600', reason: 'Pingora health patrol env 切换脚本的临时复核 env 必须显式限制为 0600。', }, { file: 'scripts/check-pingora-health-patrol-env-switch.mjs', includes: 'assertDryRunEnvFileModeIsPrivate', reason: 'Pingora health patrol env 切换脚本自测必须动态验证临时复核 env 权限。', }, { file: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', includes: 'runHealthPatrolEnvCheck(checkFile);', reason: 'Pingora health patrol env 切换脚本必须先复核临时目标 env。', }, { file: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', includes: 'writeEnvFileAtomically(config.envFile, nextText);', reason: 'Pingora health patrol env 切换脚本只能在复核通过后原子写入真实 env。', }, { file: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', includes: 'chownSync(tempFile, currentStat.uid, currentStat.gid);', reason: 'Pingora health patrol env 切换脚本原子替换真实 env 时必须保留 owner/group。', }, { file: 'scripts/check-pingora-health-patrol-env-switch.mjs', includes: 'assertApplyPreservesEnvFileModeAndOwnership', reason: 'Pingora health patrol env 切换脚本自测必须覆盖 apply 保留 mode 与 owner/group。', }, { file: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', includes: '--env-file 不能是符号链接', reason: 'Pingora health patrol env 切换脚本 apply 必须拒绝符号链接 env,避免替换链接或写入非预期目标。', }, { file: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', includes: 'isFilesystemRootPath', reason: 'Pingora health patrol env 切换脚本必须显式拒绝把路径参数指到 /。', }, { file: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', includes: '--check-script 不能是文件系统根目录', reason: 'Pingora health patrol env 切换脚本必须拒绝把复核脚本路径指到 /。', }, { file: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', includes: 'function validateNoControlCharacters(value, label)', reason: 'Pingora health patrol env 切换脚本必须拒绝 env 路径、check script、public URL 和 Host 中的换行 / NUL。', }, { file: 'scripts/check-pingora-health-patrol-env-switch.mjs', includes: 'assertApplyRejectsSymlinkEnvFileBeforeWrite', reason: 'Pingora health patrol env 切换脚本自测必须覆盖符号链接 env 被拒绝且不写目标文件。', }, { file: 'scripts/check-pingora-health-patrol-env-switch.mjs', includes: 'assertRejectsFilesystemRootPaths', reason: 'Pingora health patrol env 切换脚本自测必须覆盖路径参数指到 / 的负例。', }, { file: 'scripts/check-pingora-health-patrol-env-switch.mjs', includes: 'assertRejectsControlCharacterInputsBeforeWrite', reason: 'Pingora health patrol env 切换脚本自测必须覆盖控制字符参数在 apply 写入前失败。', }, { file: 'scripts/check-pingora-gateway-env-shadow-switch.mjs', includes: 'assertApplyRestoresShadowAndPreservesOtherKeys', reason: 'Pingora gateway env shadow 切换脚本自测必须覆盖恢复 shadow 并保留其它键。', }, { file: 'scripts/deploy/pingora-gateway-env-shadow-switch.mjs', includes: 'GENARRATIVE_PINGORA_GATEWAY_LISTEN: \'127.0.0.1:18081\'', reason: 'Pingora gateway env shadow 切换脚本必须固定恢复 shadow 高端口监听。', }, { file: 'scripts/deploy/pingora-gateway-env-shadow-switch.mjs', includes: 'GENARRATIVE_PINGORA_GATEWAY_TLS_LISTEN: \'\'', reason: 'Pingora gateway env shadow 切换脚本必须清空 TLS 低端口监听。', }, { file: 'scripts/deploy/pingora-gateway-env-shadow-switch.mjs', includes: 'GENARRATIVE_PINGORA_GATEWAY_HTTP_REDIRECT_LISTEN: \'\'', reason: 'Pingora gateway env shadow 切换脚本必须清空 HTTP redirect 低端口监听。', }, { file: 'scripts/deploy/pingora-gateway-env-shadow-switch.mjs', includes: 'GENARRATIVE_PINGORA_GATEWAY_TLS_CERT_FILE: \'\'', reason: 'Pingora gateway env shadow 切换脚本必须清空 TLS cert,避免回退后形成不完整 TLS 配置。', }, { file: 'scripts/deploy/pingora-gateway-env-shadow-switch.mjs', includes: 'GENARRATIVE_PINGORA_GATEWAY_TLS_KEY_FILE: \'\'', reason: 'Pingora gateway env shadow 切换脚本必须清空 TLS key,避免回退后形成不完整 TLS 配置。', }, { file: 'scripts/deploy/pingora-gateway-env-shadow-switch.mjs', includes: 'assertShadowEnv(checkFile);', reason: 'Pingora gateway env shadow 切换脚本必须先复核临时目标 env。', }, { file: 'scripts/deploy/pingora-gateway-env-shadow-switch.mjs', includes: 'writeEnvFileAtomically(config.envFile, nextText);', reason: 'Pingora gateway env shadow 切换脚本只能在复核通过后原子写入真实 env。', }, { file: 'scripts/check-pingora-gateway-env-shadow-switch.mjs', includes: 'assertRejectsSymlinkEnvFileBeforeWrite', reason: 'Pingora gateway env shadow 切换脚本自测必须覆盖符号链接 env 被拒绝。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--release-runtime-only', reason: 'Pingora release readiness 必须支持 current release 包内运行时复核模式,避免目标机依赖源码 checkout。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'buildReleaseRuntimeSteps', reason: 'Pingora release runtime-only 模式必须单独构建包内自包含检查步骤。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'releaseScriptPath', reason: 'Pingora release runtime-only 模式必须从 current release 解析随包脚本绝对路径。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--require-live', reason: 'Pingora 正式切换聚合门禁必须支持目标机 live canary 强制验收。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-live 时必须提供 --live-host', reason: 'Pingora 强制 live canary 门禁不能跳过正式域名 Host header 验证。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '目标 Nginx live canary access log 对账', reason: 'Pingora 强制 live canary 门禁必须在 live smoke 后执行真实 access log 对账。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--live-nginx-access-log', reason: 'Pingora 强制 live canary 门禁必须允许显式指定 Nginx access log。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--live-pingora-access-log', reason: 'Pingora 强制 live canary 门禁必须允许显式指定 Pingora access log。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'validateSafeAbsoluteFilePath(filePath, label);', reason: 'Pingora release readiness 的 live/direct 文件路径必须统一拒绝相对路径和文件系统根目录。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertReleaseRuntimeOnlyPlanUsesCurrentReleaseScripts', reason: 'Pingora release readiness plan 自测必须覆盖 runtime-only 使用 current release 随包脚本。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertReleaseRuntimeOnlyRejectsSourceOnlyFlags', reason: 'Pingora release readiness plan 自测必须覆盖 runtime-only 拒绝源码/本机依赖参数。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-live 计划必须在 live smoke 后包含 access log 对账', reason: 'Pingora 聚合门禁计划自检必须覆盖 live smoke 后真实日志对账。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-live 的 Nginx access log 不能接受相对路径', reason: 'Pingora 聚合门禁计划自检必须覆盖 live 日志路径负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertRequireLiveRejectsFilesystemRootAccessLog', reason: 'Pingora 聚合门禁计划自检必须覆盖 live 日志路径指向文件系统根目录的负例。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--require-direct', reason: 'Pingora 正式切换聚合门禁必须支持目标机直连入口强制验收。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--dry-run-cutover', reason: 'Pingora 正式直连切换必须支持只打印可审阅 runbook。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '切换 Host 一致性确认', reason: 'Pingora cutover runbook 必须输出 Host 一致性确认步骤。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'assertSameCutoverHostname', reason: 'Pingora cutover runbook 必须在生成阶段阻断 Host 漂移。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--rollback-pingora-shadow-probe-url', reason: 'Pingora cutover runbook 必须支持把可选 shadow probe 参数传给 rollback。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--rollback-health-patrol-public-base-url', reason: 'Pingora cutover runbook 必须显式声明回退后恢复的 Nginx public base URL。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '避免回退 runbook 覆盖现场原有 Nginx 巡检入口', reason: 'Pingora cutover runbook 不能把回退后的 health patrol public base URL 隐式写成仓库默认值。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '', reason: 'Pingora cutover runbook 输出不能泄露 probe token 原文。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'Pingora direct enable apply', reason: 'Pingora cutover runbook 必须显式列出 direct enable apply 步骤。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'Pingora direct rollback apply', reason: 'Pingora cutover runbook 必须显式列出失败回退 apply 步骤。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '切换后 health patrol 切到 Pingora direct', reason: 'Pingora cutover runbook 必须提醒直连启用后把健康巡检切到 pingora-direct。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '回退前 health patrol 预置回 Nginx', reason: 'Pingora cutover runbook 必须在 rollback apply 前提醒把健康巡检预置回 nginx。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '回退前 Pingora env 预置回 shadow', reason: 'Pingora cutover runbook 必须在 rollback apply 前提醒把 Pingora env 预置回 shadow。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'scripts/deploy/pingora-gateway-env-shadow-switch.mjs', reason: 'Pingora cutover runbook 必须用随包脚本恢复 Pingora shadow env。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover 回退前 Pingora gateway env shadow 切换必须显式带 --apply。', reason: 'Pingora runbook 自检必须锁住 rollback apply 前 Pingora shadow env 脚本化预置步骤。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'pingora-health-patrol-env-switch.mjs', reason: 'Pingora cutover runbook 必须使用随包脚本切换 health patrol env,不能只给手工编辑提示。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '切换前 current release 自包含自审', reason: 'Pingora cutover runbook 必须先审 current release 自包含能力。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '切换前状态快照', reason: 'Pingora cutover runbook 必须在启用前采集只读状态快照。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '切换前状态快照证据包', reason: 'Pingora cutover runbook 必须在启用前归档状态快照证据包。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--cutover-evidence-output-root', reason: 'Pingora cutover runbook 必须显式固定证据包输出根目录。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用后状态快照', reason: 'Pingora cutover runbook 必须在启用后采集只读状态快照。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--run-direct-live', reason: 'Pingora cutover runbook 启用后证据包必须归档 direct live 和 access log request_id 证据。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '启用后状态快照证据包必须归档 direct live smoke 证据', reason: 'Pingora runbook 自检必须锁住 post-enable 证据包的 direct live 归档。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '证据 manifest 只读验真', reason: 'Pingora cutover runbook 必须在每个证据包阶段后提示只读验真。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '证据验真必须使用 current release 随包 verifier', reason: 'Pingora runbook 自检必须锁住 current release 随包证据验真脚本。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '证据验真必须要求 manifest.summary.status=OK', reason: 'Pingora runbook 自检必须锁住即时证据验真的 summary OK 要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertDryRunCutoverPlanAvoidsManualEvidenceEscapeHatches', reason: 'Pingora runbook 自检必须确认正式切换计划不携带人工证据放行参数。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--allow-extra-root-entries', reason: 'Pingora runbook 自检必须显式覆盖证据根目录额外条目放行参数不得进入正式计划。', }, { file: 'scripts/ops/pingora-cutover-evidence-verify.mjs', includes: 'findExtraEvidenceEntries', reason: 'Pingora 证据验真脚本必须扫描 manifest.files 未登记的额外条目。', }, { file: 'scripts/ops/pingora-cutover-evidence-verify.mjs', includes: '--require-summary-ok', reason: 'Pingora 证据验真脚本必须支持正式 runbook 的 summary OK 强制模式。', }, { file: 'scripts/ops/pingora-cutover-evidence-verify.mjs', includes: 'manifest.summary.status is not OK', reason: 'Pingora 证据验真脚本必须在 summary 非 OK 时给出结构化失败原因。', }, { file: 'scripts/ops/pingora-cutover-evidence-verify.mjs', includes: 'extra file not registered in manifest.files', reason: 'Pingora 证据验真脚本必须默认拒绝未登记普通文件。', }, { file: 'scripts/ops/pingora-cutover-evidence-verify.mjs', includes: 'extra directory not registered in manifest.files', reason: 'Pingora 证据验真脚本必须默认拒绝未登记目录。', }, { file: 'scripts/ops/pingora-cutover-evidence-verify.mjs', includes: 'extra symlink not registered in manifest.files', reason: 'Pingora 证据验真脚本必须默认拒绝未登记符号链接。', }, { file: 'scripts/ops/pingora-cutover-evidence-verify.mjs', includes: '--allow-extra-files', reason: 'Pingora 证据验真脚本允许额外条目时必须显式使用例外开关。', }, { file: 'scripts/ops/pingora-cutover-evidence-verify.mjs', includes: '正式切换归档不应使用', reason: 'Pingora 证据验真脚本必须声明额外条目例外不属于正式归档口径。', }, { file: 'scripts/ops/pingora-cutover-evidence-verify.mjs', includes: 'validateNoControlCharacters', reason: 'Pingora 证据验真脚本必须拒绝带换行或 NUL 的入口路径和 manifest 文件名。', }, { file: 'scripts/ops/pingora-cutover-evidence-verify.mjs', includes: '不能包含换行或 NUL 字符', reason: 'Pingora 证据验真脚本必须对控制字符路径给出明确错误。', }, { file: 'scripts/check-pingora-cutover-evidence-verify.mjs', includes: 'assertExtraFileFailsByDefault', reason: 'Pingora 证据验真自测必须覆盖未登记普通文件默认失败。', }, { file: 'scripts/check-pingora-cutover-evidence-verify.mjs', includes: 'assertExtraDirectoryFailsByDefault', reason: 'Pingora 证据验真自测必须覆盖未登记目录默认失败。', }, { file: 'scripts/check-pingora-cutover-evidence-verify.mjs', includes: 'assertExtraSymlinkFailsByDefault', reason: 'Pingora 证据验真自测必须覆盖未登记符号链接默认失败。', }, { file: 'scripts/check-pingora-cutover-evidence-verify.mjs', includes: 'assertAllowExtraFilesOverrideSucceeds', reason: 'Pingora 证据验真自测必须覆盖显式允许额外条目的人工例外。', }, { file: 'scripts/check-pingora-cutover-evidence-verify.mjs', includes: 'assertRequireSummaryOkFailsForCriticalManifest', reason: 'Pingora 证据验真自测必须覆盖 summary 非 OK 时 --require-summary-ok 失败。', }, { file: 'scripts/check-pingora-cutover-evidence-verify.mjs', includes: 'assertRequireSummaryOkFailsWhenSummaryMissing', reason: 'Pingora 证据验真自测必须覆盖缺少 summary 时 --require-summary-ok 失败。', }, { file: 'scripts/check-pingora-cutover-evidence-verify.mjs', includes: 'assertRejectsEntryPathControlCharacters', reason: 'Pingora 证据验真自测必须覆盖入口路径带控制字符的负例。', }, { file: 'scripts/check-pingora-cutover-evidence-verify.mjs', includes: 'assertRejectsManifestFilePathControlCharacters', reason: 'Pingora 证据验真自测必须覆盖 manifest 文件 path 带控制字符的负例。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'manifest.files` 视为闭集', reason: 'Pingora 试点文档必须说明证据验真默认闭集归档口径。', }, { file: 'docs/【开发运维】本地开发验证与生产运维-2026-05-15.md', includes: 'manifest.files` 视为闭集', reason: '生产运维文档必须说明证据验真默认闭集归档口径。', }, { file: 'docs/project-memory/shared-memory/decision-log.md', includes: 'manifest.files` 视为闭集', reason: '团队共享决策必须记录 Pingora 证据验真闭集归档口径。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: 'manifest.files` 视为闭集', reason: '团队共享踩坑必须记录 Pingora 证据目录不能夹带未登记条目。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'pingora-gateway-env-shadow-switch.mjs --apply', reason: 'Pingora 试点文档必须记录 rollback apply 前用随包脚本恢复 Pingora shadow env。', }, { file: 'docs/【开发运维】本地开发验证与生产运维-2026-05-15.md', includes: 'pingora-gateway-env-shadow-switch.mjs --apply', reason: '生产运维文档必须记录 rollback apply 前用随包脚本恢复 Pingora shadow env。', }, { file: 'docs/project-memory/shared-memory/decision-log.md', includes: 'pingora-gateway-env-shadow-switch.mjs --apply', reason: '团队共享决策必须记录 rollback apply 前用随包脚本恢复 Pingora shadow env。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: 'pingora-gateway-env-shadow-switch.mjs --apply', reason: '团队共享踩坑必须记录 rollback apply 前用随包脚本恢复 Pingora shadow env。', }, { file: 'deploy/nginx/README.md', includes: 'scripts/deploy/pingora-gateway-env-shadow-switch.mjs', reason: 'Nginx README 的 API release 清单必须包含 Pingora gateway env shadow 切换脚本。', }, { file: 'deploy/nginx/README.md', includes: 'rollback apply 前必须先执行', reason: 'Nginx README 必须说明 rollback apply 前先恢复 Pingora gateway shadow env。', }, { file: 'deploy/nginx/README.md', includes: 'TLS_CERT_FILE', reason: 'Nginx README 必须说明 Pingora gateway shadow 回退会清空 TLS cert/key 路径。', }, { file: 'deploy/nginx/README.md', includes: '--expected-pingora-env-mode direct', reason: 'Nginx README 必须说明 post-enable 证据包会强制校验 Pingora env direct 姿态。', }, { file: 'deploy/nginx/README.md', includes: '--expected-pingora-env-mode shadow', reason: 'Nginx README 必须说明 post-rollback 证据包会强制校验 Pingora env shadow 姿态。', }, { file: 'deploy/nginx/README.md', includes: 'manifest.summary.pingoraEnvShadow', reason: 'Nginx README 必须说明证据 manifest 会提升 Pingora env shadow 摘要。', }, { file: 'deploy/nginx/README.md', includes: 'tlsCertFile', reason: 'Nginx README 必须说明 Pingora env shadow 摘要包含 TLS cert/key 残留字段。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'tlsCertFile', reason: 'Pingora 试点文档必须说明证据摘要包含 TLS cert/key 残留字段。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '切换证据根目录三阶段总审计', reason: 'Pingora cutover runbook 必须在三阶段证据后执行根目录总审计。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'enable-apply:pingora-direct-enable-apply', reason: 'Pingora cutover runbook 总审计必须要求 direct enable apply 命令证据。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'rollback-apply:pingora-direct-rollback-apply', reason: 'Pingora cutover runbook 总审计必须要求 direct rollback apply 命令证据。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'post-enable:pingora-health-patrol-direct-env-switch', reason: 'Pingora cutover runbook 总审计必须要求 health patrol 切到 direct 的命令证据。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'rollback-prep:pingora-gateway-shadow-env-switch', reason: 'Pingora cutover runbook 总审计必须要求回退前 Pingora gateway env shadow 切换命令证据。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'rollback-prep:pingora-health-patrol-nginx-env-switch', reason: 'Pingora cutover runbook 总审计必须要求回退前 health patrol 切回 Nginx 的命令证据。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--require-phase-pingora-env-shadow', reason: 'Pingora cutover runbook 总审计必须要求 post-rollback Pingora env shadow 证据。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '三阶段总审计必须使用 current release 随包 evidence audit 脚本', reason: 'Pingora runbook 自检必须锁住 current release 随包证据根目录审计脚本。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '三阶段总审计必须要求 post-rollback 阶段带 Pingora env shadow 摘要。', reason: 'Pingora runbook 自检必须锁住总审计里的 post-rollback shadow env 证据要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '三阶段总审计必须显式要求真实切换命令证据', reason: 'Pingora runbook 自检必须锁住总审计里的 enable / rollback 和 env 切换命令证据要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'post-enable:pingora-health-patrol-direct-env-switch:/opt/genarrative/current/scripts/deploy/pingora-health-patrol-env-switch.mjs', reason: 'Pingora runbook 自检必须锁住 health patrol direct env 切换命令的真实脚本身份。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'rollback-prep:pingora-gateway-shadow-env-switch:/opt/genarrative/current/scripts/deploy/pingora-gateway-env-shadow-switch.mjs', reason: 'Pingora runbook 自检必须锁住 Pingora gateway shadow env 切换命令的真实脚本身份。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'rollback-prep:pingora-health-patrol-nginx-env-switch:/opt/genarrative/current/scripts/deploy/pingora-health-patrol-env-switch.mjs', reason: 'Pingora runbook 自检必须锁住 health patrol nginx env 切换命令的真实脚本身份。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--require-command-executable', reason: 'Pingora cutover runbook 总审计必须要求真实切换命令证据的真实脚本身份。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '三阶段总审计必须显式要求真实切换脚本身份', reason: 'Pingora runbook 自检必须锁住总审计里的真实切换命令脚本身份要求。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--require-command-arg', reason: 'Pingora cutover runbook 总审计必须要求真实切换命令证据包含关键参数。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '三阶段总审计必须显式要求真实切换命令必需参数', reason: 'Pingora runbook 自检必须锁住总审计里的真实切换命令参数要求。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: "commandName: 'pingora-health-patrol-direct-env-switch'", reason: 'Pingora 证据根目录审计标准时间线必须包含 health patrol direct env 切换命令。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: "commandName: 'pingora-gateway-shadow-env-switch'", reason: 'Pingora 证据根目录审计标准时间线必须包含 Pingora gateway shadow env 切换命令。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: "commandName: 'pingora-health-patrol-nginx-env-switch'", reason: 'Pingora 证据根目录审计标准时间线必须包含 health patrol nginx env 切换命令。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: '完整切换时间线总审计必须检查三阶段和五条命令', reason: 'Pingora 证据根目录审计自测必须把完整时间线固定为三阶段和五条命令。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--cutover-run-id', reason: 'Pingora cutover runbook 必须公开并传递切换批次 ID。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--require-cutover-run-id', reason: 'Pingora cutover runbook 最终总审计必须要求同一切换批次 ID。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertDryRunCutoverPlanCarriesCutoverRunId', reason: 'Pingora runbook 自检必须覆盖切换批次 ID 贯穿所有证据步骤。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '不会修改证据目录', reason: 'Pingora 证据根目录审计脚本必须声明只读边界。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '--require-command :', reason: 'Pingora 证据根目录审计脚本必须支持强制审计切换命令证据。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '--require-command-executable ::', reason: 'Pingora 证据根目录审计脚本必须支持强制审计切换命令真实脚本身份。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '--require-command-executable executable 不能包含换行或 NUL 字符', reason: 'Pingora 证据根目录审计脚本必须拒绝带控制字符的命令脚本身份要求。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'validateNoControlCharacters', reason: 'Pingora 证据根目录审计脚本必须拒绝带换行或 NUL 的根目录和 verifier 路径。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '!/[\\0\\r\\n]/u.test(value)', reason: 'Pingora 证据根目录审计脚本必须拒绝 manifest 文件名里的控制字符。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'command executable 带控制字符必须失败', reason: 'Pingora 证据根目录审计自测必须覆盖命令脚本身份要求带控制字符的负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: '证据根目录带控制字符必须失败', reason: 'Pingora 证据根目录审计自测必须覆盖 evidence-root 控制字符负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'verifier 路径带控制字符必须失败', reason: 'Pingora 证据根目录审计自测必须覆盖 verify-script 控制字符负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertManifestFileNameControlCharacterFails', reason: 'Pingora 证据根目录审计自测必须覆盖 manifest 文件名控制字符负例。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '--require-command-arg ::', reason: 'Pingora 证据根目录审计脚本必须支持强制审计切换命令必需参数。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'mergeRequiredCommands', reason: 'Pingora 命令脚本身份要求必须隐式纳入命令证据审计,不能被静默忽略。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'manifest.expectedExecutable 必须是', reason: 'Pingora 证据根目录审计脚本必须阻断命令证据 expectedExecutable 漂移。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'command.executable 必须是', reason: 'Pingora 证据根目录审计脚本必须阻断命令证据真实 executable 漂移。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'readCommandRecord', reason: 'Pingora 证据根目录审计脚本必须读取独立 command-record.json 做语义复核。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'compareCommandRecords', reason: 'Pingora 证据根目录审计脚本必须阻断 manifest.command 与 command-record.json 漂移。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'stdoutPath', reason: 'Pingora 证据根目录审计脚本必须复核命令 stdout 文件引用一致性。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'stderrPath', reason: 'Pingora 证据根目录审计脚本必须复核命令 stderr 文件引用一致性。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'jsonValuesEqual', reason: 'Pingora 证据根目录审计脚本必须复核命令参数数组一致性。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'args 不能包含换行或 NUL 字符', reason: 'Pingora 证据根目录审计脚本必须拒绝被控制字符污染的命令参数证据。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'scalarFields', reason: 'Pingora 证据根目录审计脚本必须复核脱敏命令字符串一致性。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: "'command'", reason: 'Pingora 证据根目录审计脚本必须把脱敏命令字符串纳入一致性比较。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'checkCommandRecordTimes', reason: 'Pingora 证据根目录审计脚本必须校验命令记录 startedAt / finishedAt / durationMs。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: "'--require-summary-ok'", reason: 'Pingora 证据根目录审计脚本复用 verifier 时必须启用 strict summary 模式。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'manifest.summary.status 必须是 OK', reason: 'Pingora 证据根目录审计脚本必须阻断 summary 非 OK 的阶段或命令证据。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'candidate.commandName === null', reason: 'Pingora 证据根目录审计脚本必须防止命令证据冒充阶段证据。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'manifest.summary.exitCode 必须是 0', reason: 'Pingora 证据根目录审计脚本必须阻断退出码非 0 的命令证据。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'CUTOVER_TIMELINE_ORDER', reason: 'Pingora 证据根目录审计脚本必须内置标准直连切换时间线顺序。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '疑似混入不同切换窗口证据', reason: 'Pingora 证据根目录审计脚本必须阻断标准切换时间线倒序证据。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'DEFAULT_CUTOVER_TIMELINE_MAX_SPAN_MS = 24 * 60 * 60 * 1000', reason: 'Pingora 证据根目录审计脚本必须默认限制标准切换证据窗口为 24 小时。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '--timeline-max-span-ms', reason: 'Pingora 证据根目录审计脚本必须允许切换窗口显式覆盖最大时间跨度。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '--require-cutover-run-id', reason: 'Pingora 证据根目录审计脚本必须能按切换批次 ID 过滤证据。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'manifest.cutoverRunId', reason: 'Pingora 证据根目录审计脚本必须读取并校验 manifest.cutoverRunId。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '--allow-extra-root-entries', reason: 'Pingora 证据根目录审计脚本允许额外根目录条目时必须显式使用例外开关。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '正式切换归档不应使用', reason: 'Pingora 证据根目录审计脚本必须声明额外根目录条目例外不属于正式归档口径。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '证据根目录只能包含证据目录,发现普通文件', reason: 'Pingora 证据根目录审计脚本必须默认拒绝根目录普通文件。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '证据根目录只能包含带 manifest.json 的证据目录', reason: 'Pingora 证据根目录审计脚本必须默认拒绝无 manifest 的根目录子目录。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertExtraRootFileFailsByDefault', reason: 'Pingora 证据根目录审计自测必须覆盖根目录普通文件默认失败。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertExtraRootDirectoryFailsByDefault', reason: 'Pingora 证据根目录审计自测必须覆盖无 manifest 根目录子目录默认失败。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertExtraRootSymlinkFailsByDefault', reason: 'Pingora 证据根目录审计自测必须覆盖根目录符号链接默认失败。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertAllowExtraRootEntriesSucceeds', reason: 'Pingora 证据根目录审计自测必须覆盖显式允许额外根目录条目的人工例外。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertRequiredCommandExecutableImplicitlyRequiresCommand', reason: 'Pingora 证据根目录审计自测必须覆盖命令脚本身份参数隐式要求命令证据。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertRequiredCommandExecutableMismatchFails', reason: 'Pingora 证据根目录审计自测必须覆盖命令脚本身份漂移负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertRequiredCommandArgImplicitlyRequiresCommand', reason: 'Pingora 证据根目录审计自测必须覆盖命令必需参数隐式要求命令证据。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertRequiredCommandArgMissingFails', reason: 'Pingora 证据根目录审计自测必须覆盖命令证据缺少 --apply 参数负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertCommandRecordMismatchFails', reason: 'Pingora 证据根目录审计自测必须覆盖 command-record.json 与 manifest.command 漂移负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertCommandRecordTimelineMismatchFails', reason: 'Pingora 证据根目录审计自测必须覆盖命令记录时间线漂移负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertCommandRecordOutputPathMismatchFails', reason: 'Pingora 证据根目录审计自测必须覆盖 command-record.json 与 manifest.files 的 stdout/stderr 引用漂移负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertCommandRecordArgsMismatchFails', reason: 'Pingora 证据根目录审计自测必须覆盖 command-record.json 与 manifest.command 的参数漂移负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertCommandRecordArgsControlCharacterFails', reason: 'Pingora 证据根目录审计自测必须覆盖命令参数证据带控制字符的负例。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '时间跨度', reason: 'Pingora 证据根目录审计脚本必须阻断标准切换时间线跨度过大的证据。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertCriticalPhaseSummaryFails', reason: 'Pingora 证据根目录审计自测必须覆盖阶段证据 summary 非 OK 负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertCommandBundleCannotSatisfyPhaseRequirement', reason: 'Pingora 证据根目录审计自测必须覆盖命令证据不能满足阶段证据要求。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: '必须让 verifier 启用 --require-summary-ok', reason: 'Pingora 证据根目录审计自测必须覆盖总审计调用 verifier 的 strict summary 模式。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertFailedCommandSummaryFails', reason: 'Pingora 证据根目录审计自测必须覆盖命令证据退出失败负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertOutOfOrderCutoverTimelineFails', reason: 'Pingora 证据根目录审计自测必须覆盖标准切换时间线倒序负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertLongCutoverTimelineFails', reason: 'Pingora 证据根目录审计自测必须覆盖标准切换时间线跨度过大负例。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertCutoverRunIdMismatchFails', reason: 'Pingora 证据根目录审计自测必须覆盖切换批次 ID 不匹配负例。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--cutover-evidence-timeline-max-span-ms', reason: 'Pingora cutover runbook 必须公开证据时间线最大跨度参数。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '三阶段总审计必须显式传标准切换时间线最大跨度', reason: 'Pingora runbook 自检必须锁住总审计的时间线最大跨度参数。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '回退后状态快照', reason: 'Pingora cutover runbook 必须在回退后采集只读状态快照。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '回退后 health patrol env Nginx 模式复核', reason: 'Pingora cutover runbook 必须在回退后复核 health patrol env 已回到 Nginx 模式。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '/opt/genarrative/current/scripts/ops/pingora-current-release-audit.mjs', reason: 'Pingora runbook 自检必须覆盖 current release 随包自审脚本。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '/opt/genarrative/current/scripts/deploy/pingora-health-patrol-env-switch.mjs', reason: 'Pingora runbook 自检必须覆盖 current release 随包 health patrol env 切换脚本。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '/opt/genarrative/current/scripts/ops/pingora-cutover-status-snapshot.mjs', reason: 'Pingora runbook 自检必须覆盖 current release 随包切换状态快照脚本。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '/opt/genarrative/current/scripts/ops/pingora-cutover-evidence-bundle.mjs', reason: 'Pingora runbook 自检必须覆盖 current release 随包切换证据包脚本。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertDryRunCutoverRejectsRelativeEvidenceOutputRoot', reason: 'Pingora runbook 自检必须覆盖证据包输出根目录相对路径负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertDryRunCutoverRejectsFilesystemRootReleaseRoot', reason: 'Pingora runbook 自检必须覆盖 current release 根目录指向 / 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertDryRunCutoverRejectsFilesystemRootEvidenceOutputRoot', reason: 'Pingora runbook 自检必须覆盖证据包输出根目录指向 / 的负例。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'isFilesystemRootPath', reason: 'Pingora runbook 参数校验必须显式拒绝文件系统根目录。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertUsageCutoverExampleIncludesExplicitEvidenceOutputRoot', reason: 'Pingora runbook usage 示例必须显式展示证据包输出根目录,避免值班复制命令时依赖隐藏默认值。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertUsageExamplesIncludeDirectPingoraAccessLog', reason: 'Pingora release readiness usage 示例必须显式展示 direct access log 参数,避免值班复制命令后被 --require-direct 拦住。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--clear-public-host', reason: 'Pingora runbook 自检必须覆盖回退后清空 health patrol public Host。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover 必须包含回退后 health patrol env Nginx 模式复核', reason: 'Pingora runbook 自检必须覆盖回退后的健康巡检 env 机器复核步骤。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'cutoverReleaseRoot', reason: 'Pingora cutover runbook 必须允许固定 current release 根目录。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--direct-health-patrol-env-file', reason: 'Pingora 强制直连门禁必须允许指定 health patrol env 文件做复核。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '目标 health patrol env 直连模式复核', reason: 'Pingora 强制直连门禁必须复核 health patrol 已切到 direct 模式。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-health-patrol-env-file', reason: 'Pingora 强制直连门禁不能跳过 health patrol env 复核。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'scripts/check-pingora-direct-preflight.mjs', reason: 'Pingora 直连入口门禁必须先执行 direct-entry 预检。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--direct-preflight-env-file', reason: 'Pingora 直连入口门禁必须允许指定目标机 env 文件做预检。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-preflight-env-file', reason: 'Pingora 强制直连门禁不能跳过目标机 env 预检。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-preflight-systemd', reason: 'Pingora 强制直连门禁不能跳过 systemd drop-in 生效核验。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-preflight-check-cert-readable', reason: 'Pingora 强制直连门禁不能跳过 TLS 证书和私钥可读核验。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-preflight-check-service-env-file', reason: 'Pingora 强制直连门禁不能跳过 service EnvironmentFile 与 preflight env 一致性核验。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-preflight-check-service-user-cert-readable', reason: 'Pingora 强制直连门禁不能跳过 systemd 服务用户读取 TLS 证书和私钥核验。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-preflight-check-service-binary-executable', reason: 'Pingora 强制直连门禁不能跳过 current release service 二进制可执行核验。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --dry-run-cutover 时必须提供 --direct-preflight-check-ports-free', reason: 'Pingora 切换前 runbook 门禁不能跳过 80/443 端口释放核验;启用后直连复核不再要求端口空闲。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-http-base-url', reason: 'Pingora 强制直连门禁不能跳过 HTTP redirect / ACME live 验证。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-host', reason: 'Pingora 强制直连门禁不能跳过正式域名 Host header 和 TLS SNI 验证。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-redirect-host', reason: 'Pingora 强制直连门禁不能跳过 HTTP redirect Location host 验证。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-pingora-access-log', reason: 'Pingora 强制直连门禁不能跳过 direct access log 落盘校验。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: "validateSafeAbsoluteFilePath(\n result.directPingoraAccessLog,\n '--direct-pingora-access-log'", reason: 'Pingora 强制直连门禁必须拒绝相对 access log 路径和文件系统根目录。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--http-base-url', reason: 'Pingora 直连入口门禁必须把 HTTP redirect / ACME base URL 传给 direct live smoke。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--host', reason: 'Pingora 直连入口门禁必须把正式域名 Host/SNI 传给 direct live smoke。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--redirect-host', reason: 'Pingora 直连入口门禁必须把 redirect Location host 传给 direct live smoke。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--pingora-access-log', reason: 'Pingora 直连入口门禁必须把 access log 路径传给 direct live smoke。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--direct-preflight-systemd', reason: 'Pingora 直连入口门禁必须支持检查 systemd drop-in 是否生效。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--direct-preflight-check-service-user-cert-readable', reason: 'Pingora 直连入口门禁必须支持检查 systemd 服务用户可读证书。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--direct-preflight-check-service-env-file', reason: 'Pingora 直连入口门禁必须支持检查 service EnvironmentFile 与 preflight env 一致。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--direct-preflight-check-service-binary-executable', reason: 'Pingora 直连入口门禁必须支持检查 service ExecStart 二进制可执行。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--direct-preflight-check-ports-free', reason: 'Pingora 直连入口门禁必须支持检查 TLS/HTTP redirect 端口已释放。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--direct-spacetime-database', reason: 'Pingora 直连入口门禁必须允许指定 WSS subscribe 的目标 SpacetimeDB 库。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时必须提供 --direct-spacetime-database', reason: 'Pingora 强制直连门禁不能让 WSS subscribe 隐式使用默认数据库名。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时不能使用 --direct-skip-wss', reason: 'Pingora 强制直连门禁不能允许正式直连跳过 WSS subscribe。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '启用 --require-direct 时不能使用 --direct-insecure-tls', reason: 'Pingora 强制直连门禁不能允许生产直连跳过 TLS 信任校验。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--direct-require-wss-upgrade', reason: 'Pingora 直连入口门禁必须支持强制要求 WSS subscribe 返回 101。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'result.directRequireWssUpgrade = true', reason: 'Pingora --require-direct 硬门禁默认必须强制 WSS subscribe 返回 101。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'scripts/check-pingora-canary-docker.mjs', reason: 'Pingora 正式切换聚合门禁必须包含 Docker Nginx handoff smoke。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-route-parity', reason: 'Pingora 正式切换聚合门禁必须包含 Nginx / Pingora 路由 parity。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-direct-rollback', reason: 'Pingora 正式切换聚合门禁必须包含直连回退 dry-run 行为检查。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-direct-preflight', reason: 'Pingora 正式切换聚合门禁必须包含直连入口静态预检。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-direct-enable', reason: 'Pingora 正式切换聚合门禁必须包含直连启用 dry-run 行为检查。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'check:pingora-release-readiness-plan', reason: 'Pingora 正式切换聚合门禁必须自检关键计划语义。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 必须把 HTTP redirect / ACME 入口纳入 direct live smoke', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-direct 的 HTTP redirect / ACME 硬要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-live 必须把正式域名 Host 传给 live canary smoke', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-live 的正式域名 Host 硬要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover 必须包含 direct enable apply', reason: 'Pingora 聚合门禁计划自检必须覆盖直连启用 runbook。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover 必须包含 rollback apply', reason: 'Pingora 聚合门禁计划自检必须覆盖失败回退 runbook。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover 缺少 --require-direct 时必须失败', reason: 'Pingora cutover runbook 不能在缺少直连硬门禁参数时生成。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover 必须包含 Host 一致性确认步骤', reason: 'Pingora cutover runbook 必须显式展示 direct / health patrol / rollback Host 一致性。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover redirect Host 与 direct Host 不一致时必须失败', reason: 'Pingora cutover runbook 必须阻断 redirect Host 与正式入口 Host 漂移。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover rollback smoke Host 与 direct Host 不一致时必须失败', reason: 'Pingora cutover runbook 必须阻断 rollback smoke Host 与正式入口 Host 漂移。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover rollback 步骤必须传递 shadow probe URL', reason: 'Pingora cutover runbook 自检必须覆盖可选 rollback shadow probe 传递。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover JSON 不能泄露 shadow probe token 原文', reason: 'Pingora cutover runbook 自检必须覆盖 shadow probe token 脱敏。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run plan JSON 不能泄露 direct probe token 原文', reason: 'Pingora 聚合门禁计划自检必须覆盖 direct probe token 脱敏。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '启用后 release readiness 直连复核必须继续传递 direct probe token 参数', reason: 'Pingora cutover runbook 自检必须覆盖启用后 readiness 复核继续检查 direct probe。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover 启用前基础门禁必须使用 current release 包内运行时复核模式', reason: 'Pingora cutover runbook 自检必须覆盖启用前 readiness 使用 runtime-only 模式。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '启用后 release readiness 直连复核必须使用 current release 包内运行时复核模式', reason: 'Pingora cutover runbook 自检必须覆盖启用后 readiness 使用 runtime-only 模式。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '启用后 release readiness 直连复核必须使用 current release 随包 release readiness 聚合门禁脚本', reason: 'Pingora cutover runbook 自检必须覆盖启用后 readiness 从 current release 随包脚本执行。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover 启用前基础门禁必须使用 current release 随包 release readiness 聚合门禁脚本', reason: 'Pingora cutover runbook 自检必须覆盖启用前 readiness 从 current release 随包脚本执行。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover JSON 不能泄露 direct probe token 原文', reason: 'Pingora cutover runbook 自检必须覆盖 direct probe token 在切换计划中脱敏。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover rollback shadow probe URL 缺少 token 时必须失败', reason: 'Pingora cutover runbook 自检必须覆盖 shadow probe 参数成对出现。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 必须把正式域名 Host/SNI 传给 direct live smoke', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-direct 的正式域名 Host/SNI 硬要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 必须把显式 redirect Location host 传给 direct live smoke', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-direct 的 redirect Location host 硬要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 必须检查 systemd drop-in 最终生效配置', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-direct 的 systemd drop-in 硬要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 必须检查当前用户可读 TLS 证书和私钥', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-direct 的证书可读硬要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 必须检查 service EnvironmentFile 包含本次 env', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-direct 的 service env 一致性硬要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 必须检查 systemd 服务用户可读 TLS 证书和私钥', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-direct 的服务用户证书可读硬要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 必须检查 Pingora service ExecStart 二进制可执行', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-direct 的 service 二进制可执行硬要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover 启用前预检必须检查 80/443 端口释放', reason: 'Pingora 聚合门禁计划自检必须覆盖切换前端口释放硬要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 必须把显式 SpacetimeDB 数据库名传给 direct live smoke', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-direct 的显式 WSS 数据库名。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 必须把 Pingora access log 落盘校验传给 direct live smoke', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-direct 的 Pingora access log 硬要求。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 缺少 direct HTTP base URL 时必须失败', reason: 'Pingora 聚合门禁计划自检必须覆盖缺少 direct HTTP base URL 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-live 缺少 live Host 时必须失败', reason: 'Pingora 聚合门禁计划自检必须覆盖缺少 live Host 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-live 的 live Host 不能接受 URL 或路径', reason: 'Pingora 聚合门禁计划自检必须覆盖 live Host 格式负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 缺少 direct Host/SNI 时必须失败', reason: 'Pingora 聚合门禁计划自检必须覆盖缺少正式域名 Host/SNI 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 的 direct Host/SNI 不能接受 URL 或路径', reason: 'Pingora 聚合门禁计划自检必须覆盖 direct Host/SNI 格式负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 缺少 direct redirect Location host 时必须失败', reason: 'Pingora 聚合门禁计划自检必须覆盖缺少 redirect Location host 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 的 redirect Location host 不能接受 URL 或路径', reason: 'Pingora 聚合门禁计划自检必须覆盖 redirect Location host 格式负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 缺少 systemd preflight 时必须失败', reason: 'Pingora 聚合门禁计划自检必须覆盖缺少 systemd preflight 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 缺少证书可读 preflight 时必须失败', reason: 'Pingora 聚合门禁计划自检必须覆盖缺少证书可读 preflight 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 缺少 service EnvironmentFile preflight 时必须失败', reason: 'Pingora 聚合门禁计划自检必须覆盖缺少 service env 一致性 preflight 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 缺少服务用户证书可读 preflight 时必须失败', reason: 'Pingora 聚合门禁计划自检必须覆盖缺少服务用户证书可读 preflight 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 缺少 service 二进制可执行 preflight 时必须失败', reason: 'Pingora 聚合门禁计划自检必须覆盖缺少 service 二进制可执行 preflight 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct post-enable 复核不能要求 80/443 空闲', reason: 'Pingora 聚合门禁计划自检必须覆盖启用后直连复核不再要求端口空闲。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 缺少 SpacetimeDB 数据库名时必须失败', reason: 'Pingora 聚合门禁计划自检必须覆盖缺少显式 WSS 数据库名的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 缺少 direct Pingora access log 时必须失败', reason: 'Pingora 聚合门禁计划自检必须覆盖缺少 direct access log 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 不能允许跳过 WSS subscribe', reason: 'Pingora 聚合门禁计划自检必须覆盖 direct skip WSS 负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 不能允许 insecure TLS', reason: 'Pingora 聚合门禁计划自检必须覆盖 direct insecure TLS 负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '--require-direct 必须自动强制 WSS subscribe 返回 101', reason: 'Pingora 聚合门禁计划自检必须覆盖 --require-direct 的 WSS 101 硬要求。', }, { file: 'scripts/check-pingora-canary-docker.mjs', includes: '--require-docker', reason: 'Pingora Docker canary smoke 必须支持在 CI / 目标 agent 上强制执行。', }, { file: 'scripts/check-pingora-canary-docker.mjs', includes: 'scripts/check-pingora-canary-live.mjs', reason: 'Pingora Docker canary smoke 必须复用 live canary 断言,避免双套验收漂移。', }, { file: 'scripts/check-pingora-canary-docker.mjs', includes: '--realpath', reason: 'Pingora Docker canary smoke 必须覆盖真实路径 canary handoff。', }, { file: 'scripts/check-pingora-canary-docker.mjs', includes: 'genarrative-pingora-realpath-canary.conf', reason: 'Pingora Docker canary smoke 必须加载真实路径 canary snippet。', }, { file: 'scripts/check-pingora-canary-docker.mjs', includes: '--network', reason: 'Pingora Docker canary smoke 必须真实启动 Nginx 容器验证 handoff 链路。', }, { file: 'scripts/check-pingora-canary-docker.mjs', includes: 'log_format genarrative_upstream', reason: 'Pingora Docker canary smoke 必须按生产 Nginx access log 口径写 request_id。', }, { file: 'scripts/check-pingora-canary-docker.mjs', includes: 'scripts/check-pingora-canary-access-log-parity.mjs', reason: 'Pingora Docker canary smoke 必须复用真实 access log 对账脚本验证 handoff。', }, { file: 'scripts/check-pingora-canary-docker.mjs', includes: '/__genarrative_pingora_canary/api/assets/history', reason: 'Pingora Docker canary access log 对账必须覆盖代表性 API canary 路径。', }, { file: 'scripts/check-pingora-canary-docker.mjs', includes: '/__genarrative_pingora_canary/v1/identity', reason: 'Pingora Docker canary access log 对账必须覆盖 SpacetimeDB identity 路径。', }, { file: 'scripts/check-pingora-canary-docker.mjs', includes: '/__genarrative_pingora_canary/assets/app.js', reason: 'Pingora Docker canary access log 对账必须覆盖静态资源路径。', }, { file: 'scripts/check-pingora-canary-access-log-parity.mjs', includes: '该脚本只读比较 Nginx canary handoff access log 和 Pingora access log', reason: 'Pingora canary access log 对账脚本必须说明只读边界。', }, { file: 'scripts/check-pingora-canary-access-log-parity.mjs', includes: 'request_id', reason: 'Pingora canary access log 对账必须按 request_id 串联 Nginx 与 Pingora 日志。', }, { file: 'scripts/check-pingora-canary-access-log-parity.mjs', includes: 'realpath', reason: 'Pingora canary access log 对账必须支持真实路径 canary 模式。', }, { file: 'scripts/check-pingora-canary-access-log-parity.mjs', includes: '/__genarrative_pingora/healthz', reason: 'Pingora canary access log 对账必须覆盖 canary healthz 到 shadow healthz 的真实映射。', }, { file: 'scripts/check-pingora-canary-access-log-parity.mjs', includes: 'parseRequiredPositiveInt', reason: 'Pingora canary access log 对账 since-lines 必须严格校验,不能静默回默认值。', }, { file: 'scripts/check-pingora-canary-access-log-parity.mjs', includes: 'validateSafeAbsoluteFilePath(file, label);', reason: 'Pingora canary access log 对账必须拒绝相对日志路径和文件系统根目录。', }, { file: 'scripts/check-pingora-canary-access-log-parity.mjs', includes: 'function validateNoControlCharacters(value, label)', reason: 'Pingora canary access log 对账必须拒绝日志路径、前缀、必需路径和 since-lines 中的换行 / NUL。', }, { file: 'scripts/check-pingora-canary-access-log-parity-check.mjs', includes: 'assertRejectsFilesystemRootLogPaths', reason: 'Pingora canary access log 对账自测必须覆盖日志路径指到 / 的负例。', }, { file: 'scripts/check-pingora-canary-access-log-parity-check.mjs', includes: 'assertRejectsLogPathControlCharacters', reason: 'Pingora canary access log 对账自测必须覆盖日志路径带控制字符的负例。', }, { file: 'scripts/check-pingora-canary-access-log-parity-check.mjs', includes: 'assertRejectsPrefixAndPathControlCharacters', reason: 'Pingora canary access log 对账自测必须覆盖 canary prefix 和必需路径带控制字符的负例。', }, { file: 'scripts/check-pingora-canary-access-log-parity-check.mjs', includes: 'assertRejectsParsedLogPathControlCharacters', reason: 'Pingora canary access log 对账自测必须覆盖日志行解析出的 path 带控制字符的负例。', }, { file: 'scripts/check-pingora-canary-access-log-parity-check.mjs', includes: '缺少对应 Pingora access log', reason: 'Pingora canary access log 对账自测必须覆盖缺少 Pingora 日志的失败场景。', }, { file: 'scripts/check-pingora-canary-access-log-parity-check.mjs', includes: 'assertRejectsInvalidSinceLines', reason: 'Pingora canary access log 对账自测必须覆盖非法 since-lines 参数和 env 负例。', }, { file: 'deploy/env/pingora-canary-live.env.example', includes: 'GENARRATIVE_PINGORA_CANARY_BASE_URL', reason: 'Pingora canary live smoke 必须有可复制的环境变量示例。', }, { file: 'deploy/env/pingora-canary-live.env.example', includes: '不要填 https:// URL', reason: 'Pingora canary live smoke 环境示例必须提示 Host 只填 host。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: 'GENARRATIVE_PINGORA_DIRECT_HTTPS_BASE_URL', reason: 'Pingora direct live smoke 必须有可复制的环境变量示例。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: 'GENARRATIVE_PINGORA_DIRECT_HTTP_BASE_URL', reason: 'Pingora direct live smoke 环境示例必须暴露 HTTP redirect base URL。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: 'GENARRATIVE_PINGORA_DIRECT_REDIRECT_HOST', reason: 'Pingora direct live smoke 环境示例必须暴露 HTTP redirect Location host。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: 'GENARRATIVE_PINGORA_DIRECT_REDIRECT_BASE_URL', reason: 'Pingora direct live smoke 环境示例必须暴露高端口 rehearsal 的 redirect Location base URL 覆盖。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: '只填域名或 host:port', reason: 'Pingora direct live smoke 环境示例必须提示 Host 参数格式。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: 'GENARRATIVE_PINGORA_DIRECT_SPACETIME_DATABASE', reason: 'Pingora direct live smoke 环境示例必须暴露 WSS subscribe 使用的数据库名。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: 'GENARRATIVE_PINGORA_DIRECT_REQUIRE_WSS_UPGRADE', reason: 'Pingora direct live smoke 环境示例必须暴露 WSS 101 强制开关。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: 'GENARRATIVE_HEALTH_PATROL_GATEWAY_MODE=pingora-direct', reason: 'Pingora direct live env 示例必须提醒直连后切换健康巡检模式。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: 'current release 自审', reason: 'Pingora direct live env 示例必须提醒直连启用 apply 前先做 current release 自审。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: '--preflight-check-service-env-file', reason: 'Pingora direct live env 示例中的正式启用命令必须包含 service EnvironmentFile 一致性预检。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: '--preflight-check-service-user-cert-readable', reason: 'Pingora direct live env 示例中的正式启用命令必须包含服务用户证书可读预检。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: '--preflight-check-service-binary-executable', reason: 'Pingora direct live env 示例中的正式启用命令必须包含 service 二进制可执行预检。', }, { file: 'deploy/nginx/README.md', includes: 'plan:pingora-direct-cutover` 会在 JSON runbook 中列出 direct / nginx 两个方向的 env 切换脚本和 env 复核步骤', reason: 'Nginx / Pingora 运维文档必须说明 cutover runbook 包含健康巡检切换脚本与复核步骤。', }, { file: 'deploy/nginx/README.md', includes: '--rollback-health-patrol-public-base-url', reason: 'Nginx / Pingora 运维文档必须提醒 runbook 显式声明回退后的 Nginx 巡检入口。', }, { file: 'deploy/nginx/README.md', includes: '--preflight-check-service-env-file', reason: 'Nginx / Pingora 运维文档中的正式启用示例必须包含 service EnvironmentFile 一致性预检。', }, { file: 'deploy/nginx/README.md', includes: '--preflight-check-service-user-cert-readable', reason: 'Nginx / Pingora 运维文档中的正式启用示例必须包含服务用户证书可读预检。', }, { file: 'deploy/nginx/README.md', includes: '--preflight-check-service-binary-executable', reason: 'Nginx / Pingora 运维文档中的正式启用示例必须包含 service 二进制可执行预检。', }, { file: 'scripts/check-pingora-canary-live.mjs', includes: 'X-Genarrative-Nginx-Handoff', reason: 'Pingora canary live smoke 必须校验 Nginx handoff 响应头。', }, { file: 'scripts/check-pingora-canary-live.mjs', includes: '/__genarrative_pingora_canary', reason: 'Pingora canary live smoke 必须默认检查前缀 canary 入口。', }, { file: 'scripts/check-pingora-canary-live.mjs', includes: '/__genarrative_pingora_realpath_canary/healthz', reason: 'Pingora canary live smoke 必须支持真实路径 canary healthz 探针。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: '--require-realpath-live', reason: 'Pingora 聚合门禁必须支持把真实路径 canary 纳入目标机 live 复核。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: '目标 Nginx realpath canary access log 对账', reason: 'Pingora 聚合门禁计划自检必须覆盖真实路径 canary access log 对账。', }, { file: 'scripts/check-pingora-canary-live.mjs', includes: 'validateHostOption(result.host,', reason: 'Pingora canary live smoke 必须提前拒绝非法 Host header 参数。', }, { file: 'scripts/check-pingora-canary-live.mjs', includes: 'parseRequiredPositiveInt', reason: 'Pingora canary live smoke timeout 参数必须严格校验,不能静默回默认值。', }, { file: 'scripts/check-pingora-canary-live.mjs', includes: 'validateNoControlCharacters', reason: 'Pingora canary live smoke 必须在发起 canary 请求前拒绝带控制字符的 base URL、prefix、Host、path 和 timeout。', }, { file: 'scripts/check-pingora-canary-live.mjs', includes: '不能包含换行或 NUL 字符', reason: 'Pingora canary live smoke 必须对带换行或 NUL 的现场参数给出明确错误。', }, { file: 'scripts/check-pingora-canary-live-guard.mjs', includes: 'assertRejectsControlCharacter', reason: 'Pingora canary live guard 必须动态覆盖控制字符参数在发起 canary 请求前失败。', }, { file: 'scripts/check-pingora-canary-live-guard.mjs', includes: '--prefix', reason: 'Pingora canary live guard 必须覆盖 canary prefix 控制字符负例。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'X-Genarrative-Gateway', reason: 'Pingora direct live smoke 必须确认响应来自 Pingora 网关。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'http-api-redirect', reason: 'Pingora direct live smoke 必须覆盖 HTTP 到 HTTPS 重定向。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'https-http2-alpn', reason: 'Pingora direct live smoke 必须覆盖 HTTPS HTTP/2 ALPN。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'v2.bsatn.spacetimedb', reason: 'Pingora direct live smoke 必须覆盖 SpacetimeDB SDK 默认 WSS 子协议透传。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'wss-spacetime-subscribe', reason: 'Pingora direct live smoke 必须覆盖 WSS subscribe 握手。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: '--require-wss-upgrade', reason: 'Pingora direct live smoke 必须支持强制要求 WSS subscribe 返回 101。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'validateHostOption(result.redirectHost,', reason: 'Pingora direct live smoke 必须提前拒绝非法 redirect Location host 参数。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'validateHttpsBaseUrl(result.redirectBaseUrl,', reason: 'Pingora direct live smoke 必须提前拒绝非法 redirect Location base URL 参数。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'parseRequiredPositiveInt', reason: 'Pingora direct live smoke timeout 参数必须严格校验,不能静默回默认值。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'validateNoControlCharacters', reason: 'Pingora direct live smoke 必须在发起 HTTPS / HTTP / WSS 请求前拒绝带控制字符的 URL、Host、token、路径和日志参数。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: '不能包含换行或 NUL 字符', reason: 'Pingora direct live smoke 必须对带换行或 NUL 的现场参数给出明确错误。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'validateSafeAbsoluteFilePath', reason: 'Pingora direct live smoke 的 access log 路径必须统一复核绝对路径、根目录和控制字符。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: '必须是布尔值 true/false 或 1/0', reason: 'Pingora direct live smoke 布尔 env 必须严格校验,避免拼写错误静默降级。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: '不能是文件系统根目录', reason: 'Pingora direct live smoke 必须拒绝 Pingora access log 指向文件系统根目录。', }, { file: 'scripts/check-pingora-direct-live-guard.mjs', includes: 'assertRejectsControlCharacter', reason: 'Pingora direct live guard 必须动态覆盖控制字符参数在发起 live 请求前失败。', }, { file: 'scripts/check-pingora-direct-live-guard.mjs', includes: '--probe-token', reason: 'Pingora direct live guard 必须覆盖 probe token 控制字符负例。', }, { file: 'scripts/check-pingora-direct-live-guard.mjs', includes: '--pingora-access-log', reason: 'Pingora direct live guard 必须覆盖 access log 路径控制字符负例。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'scripts/check-pingora-direct-live-guard.mjs', reason: 'Pingora 聚合 readiness 必须执行 direct live 参数护栏,避免正式切换前漏掉脚本输入污染负例。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'readBoolEnv(', reason: 'Pingora release readiness 直连布尔 env 必须统一严格解析,避免拼写错误静默降级。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertDirectLiveRejectsInvalidBoolEnv', reason: 'Pingora release readiness plan 自测必须覆盖 direct live 非法布尔 env 负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertReleaseReadinessRejectsInvalidDirectBoolEnv', reason: 'Pingora release readiness plan 自测必须覆盖 release readiness 非法直连布尔 env 负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertRequireDirectRejectsFilesystemRootPingoraAccessLog', reason: 'Pingora release readiness plan 自测必须覆盖直连 Pingora access log 指到 / 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertRequireDirectRejectsFilesystemRootPreflightEnvFile', reason: 'Pingora release readiness plan 自测必须覆盖直连 preflight env 文件指到 / 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertRequireDirectRejectsFilesystemRootHealthPatrolEnvFile', reason: 'Pingora release readiness plan 自测必须覆盖直连 health patrol env 文件指到 / 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertDirectLiveRejectsFilesystemRootAccessLog', reason: 'Pingora release readiness plan 自测必须覆盖 direct live 单脚本日志路径指到 / 的负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertDirectPreflightRejectsInvalidBoolEnv', reason: 'Pingora release readiness plan 自测必须覆盖 direct preflight 非法布尔 env 负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'assertDirectPreflightRejectsUnconfirmedMultiInstanceProtection', reason: 'Pingora release readiness plan 自测必须覆盖未确认共享保护的多实例 direct preflight 负例。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: 'AmbientCapabilities=CAP_NET_BIND_SERVICE', reason: 'Pingora direct preflight 必须检查低端口 capability drop-in。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: '必须是布尔值 true/false 或 1/0', reason: 'Pingora direct preflight 布尔 env 必须严格校验,避免检查项拼写错误静默降级。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: 'GENARRATIVE_PINGORA_GATEWAY_TLS_LISTEN', reason: 'Pingora direct preflight 必须检查直连 TLS env。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: '--check-ports-free', reason: 'Pingora direct preflight 必须支持检查 80/443 是否已释放。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: '--check-service-user-cert-readable', reason: 'Pingora direct preflight 必须支持检查 systemd 服务用户可读证书。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: '--check-service-env-file', reason: 'Pingora direct preflight 必须支持检查 service EnvironmentFile 包含本次 env。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: '--check-service-binary-executable', reason: 'Pingora direct preflight 必须支持检查 service ExecStart 二进制可执行。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: 'assertProtectionInstanceBoundary', reason: 'Pingora direct preflight 必须检查多实例与进程内接流保护的边界。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: 'GENARRATIVE_PINGORA_GATEWAY_INSTANCE_COUNT>1', reason: 'Pingora direct preflight 多实例保护失败必须给出明确错误。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: 'ExecStart=', reason: 'Pingora direct preflight 必须从 systemd service ExecStart 推导 current release 二进制路径。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: 'sudo', reason: 'Pingora direct preflight 必须能以 systemd 服务用户身份验证 cert/key 可读性。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: 'fileURLToPath(import.meta.url)', reason: 'Pingora direct preflight 默认路径必须从脚本所在 release root 推导,不能依赖 Jenkins 工作区。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: 'validateNoControlCharacters', reason: 'Pingora direct preflight 必须在执行 systemctl 或 sudo 前拒绝带控制字符的路径和子命令参数。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: '不能包含换行或 NUL 字符', reason: 'Pingora direct preflight 必须明确拒绝带换行或 NUL 的路径和子命令参数。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: 'function runCommand(command, args)', reason: 'Pingora direct preflight 的 systemctl / sudo 子命令必须经统一执行前参数校验。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: "validateSafeAbsoluteFilePath(result.envFile, '--env-file')", reason: 'Pingora direct preflight 必须拒绝 --env-file 指向文件系统根目录。', }, { file: 'scripts/check-pingora-direct-preflight-guard.mjs', includes: 'assertRejectsEnvFileWithControlCharacters', reason: 'Pingora direct preflight 自测必须覆盖 --env-file 控制字符负例。', }, { file: 'scripts/check-pingora-direct-preflight-guard.mjs', includes: 'assertRejectsSystemdServiceWithControlCharactersBeforeSystemctl', reason: 'Pingora direct preflight 自测必须覆盖 systemd service 控制字符在执行 systemctl 前失败。', }, { file: 'package.json', includes: 'node scripts/check-pingora-direct-preflight-guard.mjs', reason: 'Pingora direct preflight npm 自测入口必须执行控制字符负例护栏。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: 'deploy/pingora/pingora-gateway.env.example', reason: 'Pingora direct preflight 必须能从 release root 读取 deploy/pingora 配置。', }, { file: 'scripts/check-pingora-direct-preflight.mjs', includes: '公网直连 Pingora 时 GENARRATIVE_PINGORA_GATEWAY_TRUST_X_FORWARDED_FOR 必须保持 false', reason: 'Pingora direct preflight 必须阻断公网直连时误信任 X-Forwarded-For。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'assertDirectPreflightRejectsPublicForwardedForTrust', reason: 'Pingora direct preflight 自测必须覆盖公网直连误信任 X-Forwarded-For 的负例。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--apply', reason: 'Pingora 直连回退脚本默认必须是 dry-run,只能显式 apply 修改系统。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--apply 必须同时提供 --reload-nginx', reason: 'Pingora 直连回退 apply 前必须强制 reload Nginx 并核验 active。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '${NGINX_BINARY} -t', reason: 'Pingora 直连回退 reload Nginx 前必须先执行 nginx -t。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'drop-in 目录不能是符号链接', reason: 'Pingora 直连回退脚本 apply 前必须拒绝符号链接 drop-in 目录,避免删除非预期 systemd 位置。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'drop-in 目标不能是符号链接', reason: 'Pingora 直连回退脚本 apply 前必须拒绝符号链接 drop-in 目标,避免误以为已回退真实 drop-in。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'drop-in 目标已存在但不是普通文件', reason: 'Pingora 直连回退脚本 apply 前必须拒绝非普通文件 drop-in 目标。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--apply 必须同时提供 --nginx-smoke-url', reason: 'Pingora 直连回退 apply 前必须强制 Nginx 入口 smoke。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--nginx-smoke-url 指向本机地址时必须同时提供 --nginx-smoke-host', reason: 'Pingora 直连回退本机 smoke 必须显式使用正式 Host,避免命中默认 vhost。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--nginx-smoke-expect-body', reason: 'Pingora 直连回退必须支持 Nginx smoke 响应体证据片段,避免 HTTP 200 命中错误入口。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'nginx smoke evidence matched expected body fragment', reason: 'Pingora 直连回退必须在 Nginx smoke 响应体匹配后输出证据摘要。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'Nginx smoke 响应缺少预期片段', reason: 'Pingora 直连回退必须拒绝 Nginx smoke 响应体漂移。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '只能是 host 或 host:port', reason: 'Pingora 直连回退必须拒绝非法 Nginx smoke Host。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--curl-binary', reason: 'Pingora 直连回退必须支持覆盖 curl 可执行文件,便于测试和特殊环境。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--health-patrol-env-file', reason: 'Pingora 直连回退必须支持可选复核 health patrol env 已切回 nginx。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--health-patrol-env-check-script', reason: 'Pingora 直连回退 health patrol env 复核必须能固定 current release 随包脚本。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'node -- "${health_patrol_args[@]}"', reason: 'Pingora 直连回退 health patrol env 复核必须用 node -- 分隔脚本参数,避免 Node 22 抢占业务 --env-file。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--require-empty-public-host', reason: 'Pingora 直连回退 health patrol env 复核必须阻断 direct Host 覆盖残留。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--pingora-shadow-probe-url', reason: 'Pingora 直连回退必须支持可选复核 shadow 高端口探针。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '--pingora-shadow-probe-token', reason: 'Pingora 直连回退 shadow 探针复核必须使用 probe token。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'X-Genarrative-Pingora-Probe: ', reason: 'Pingora 直连回退 shadow 探针命令日志必须隐藏 probe token。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'dry-run Pingora shadow probe 命令不应输出 probe token 原文', reason: 'Pingora 直连回退自测必须覆盖 shadow probe token 不进命令日志。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'gateway=pingora-shadow', reason: 'Pingora 直连回退 shadow 探针复核必须检查响应身份。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '${CURL_BINARY} --fail', reason: 'Pingora 直连回退 reload Nginx 后必须执行 smoke URL 验证。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'systemctl daemon-reload', reason: 'Pingora 直连回退移除 drop-in 后必须 reload systemd。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'genarrative-pingora-gateway.service', reason: 'Pingora 直连回退脚本必须默认重启 Pingora 网关服务。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'direct-entry.conf', reason: 'Pingora 直连回退脚本必须移除 direct-entry drop-in。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'systemctl cat ${SERVICE_NAME}', reason: 'Pingora 直连回退 apply 后必须核验 systemd drop-in 最终已移除。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '仍显示 AmbientCapabilities=CAP_NET_BIND_SERVICE', reason: 'Pingora 直连回退 apply 后必须拒绝 AmbientCapabilities 残留。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '仍显示 CapabilityBoundingSet=CAP_NET_BIND_SERVICE', reason: 'Pingora 直连回退 apply 后必须拒绝 CapabilityBoundingSet 残留。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'systemctl is-active ${NGINX_SERVICE}', reason: 'Pingora 直连回退 reload Nginx 后必须核验 Nginx active 状态。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'Nginx reload 后状态不是 active', reason: 'Pingora 直连回退必须拒绝 Nginx reload 后非 active 状态。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply', reason: 'Pingora 直连启用脚本默认必须是 dry-run,只能显式 apply 修改系统。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'systemctl daemon-reload', reason: 'Pingora 直连启用安装 drop-in 后必须 reload systemd。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'genarrative-pingora-gateway.service', reason: 'Pingora 直连启用脚本必须默认重启 Pingora 网关服务。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'deploy/systemd/genarrative-pingora-gateway-direct-entry.conf', reason: 'Pingora 直连启用脚本默认必须读取 current release 随包 direct-entry 模板,不能依赖 /etc 参考模板。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'GENARRATIVE_PINGORA_DIRECT_CURRENT_RELEASE_AUDIT_SCRIPT', reason: 'Pingora 直连启用脚本必须支持固定 current release 自审脚本,避免切换窗口依赖源码工作区。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'run_current_release_audit', reason: 'Pingora 直连启用 apply 前必须先跑 current release 自包含自审,再修改 systemd。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--require-pingora-gateway', reason: 'Pingora 直连启用 apply 前 current release 自审必须要求 Pingora 网关产物存在。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--systemd-show', reason: 'Pingora 直连启用 apply 前 current release 自审必须核验 systemd ExecStart。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--service-unit-path', reason: 'Pingora 直连启用脚本必须能固定随包主 service 模板作为 ExecStart 真相源。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'systemctl show ${SERVICE_NAME} --property=ExecStart --value --no-pager', reason: 'Pingora 直连启用脚本 apply 后必须核验 systemd ExecStart 指向 current release 网关二进制。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'assertApplyFailsWhenCurrentReleaseAuditFailsBeforeInstall', reason: 'Pingora 直连启用脚本自测必须覆盖 current release 自审失败时不安装 drop-in。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'assertApplyFailsWhenSystemdExecStartDiffers', reason: 'Pingora 直连启用脚本自测必须覆盖 systemd ExecStart 指向旧 release 的负例。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '该脚本不写入 TLS env', reason: 'Pingora 直连启用脚本不能隐式修改 TLS/env/证书边界。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --preflight-env-file', reason: 'Pingora 直连启用 apply 前必须强制通过 env 预检。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --preflight-check-cert-readable', reason: 'Pingora 直连启用 apply 前必须强制通过证书可读预检。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --preflight-check-service-env-file', reason: 'Pingora 直连启用 apply 前必须强制通过 service EnvironmentFile 一致性预检。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'systemd_env_file_matches', reason: 'Pingora 直连启用 apply 后必须精确核验 systemctl cat 中的 EnvironmentFile。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --preflight-check-service-user-cert-readable', reason: 'Pingora 直连启用 apply 前必须强制通过服务用户证书可读预检。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --preflight-check-service-binary-executable', reason: 'Pingora 直连启用 apply 前必须强制通过 service 二进制可执行预检。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --preflight-check-ports-free', reason: 'Pingora 直连启用 apply 前必须强制通过端口释放预检。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --direct-https-base-url', reason: 'Pingora 直连启用 apply 后必须强制验证 HTTPS 直连入口。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --direct-http-base-url', reason: 'Pingora 直连启用 apply 后必须强制验证 HTTP redirect / ACME 入口。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --direct-host', reason: 'Pingora 直连启用 apply 后必须用正式域名 Host/SNI 验证。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --direct-redirect-host', reason: 'Pingora 直连启用 apply 后必须验证 redirect Location host。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--direct-redirect-base-url', reason: 'Pingora 直连启用脚本必须支持把高端口 rehearsal 的 redirect base URL 透传给 direct live smoke。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --direct-spacetime-database', reason: 'Pingora 直连启用 apply 后必须验证目标库 WSS subscribe。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'systemctl cat ${SERVICE_NAME}', reason: 'Pingora 直连启用 apply 后必须核验 systemd drop-in 最终生效。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'systemctl is-active ${SERVICE_NAME}', reason: 'Pingora 直连启用 apply 后必须核验服务已 active。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'AmbientCapabilities=CAP_NET_BIND_SERVICE', reason: 'Pingora 直连启用 apply 后必须核验 AmbientCapabilities。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'CapabilityBoundingSet=CAP_NET_BIND_SERVICE', reason: 'Pingora 直连启用 apply 后必须核验 CapabilityBoundingSet。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--require-wss-upgrade', reason: 'Pingora 直连启用 apply 后 direct live smoke 必须强制 WSS 101。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'print_redacted_command node "${direct_live_args[@]}"', reason: 'Pingora 直连启用脚本展示 direct live 命令时必须隐藏 probe token。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'dry-run 不应安装临时 drop-in 文件', reason: 'Pingora 直连启用检查必须证明默认 dry-run 不修改 drop-in。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--probe-token ', reason: 'Pingora 直连启用检查必须覆盖 direct live 命令 token 脱敏。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'dry-run 必须展示并执行 direct preflight', reason: 'Pingora 直连启用检查必须证明可在启用前执行 direct preflight。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'release current 目录中的 enable dry-run 必须默认读取随包携带的 direct-entry 模板', reason: 'Pingora 直连启用检查必须证明从 /opt/genarrative/current 执行时默认使用发布包内 systemd 模板。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--apply 缺少 --preflight-env-file 必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖 apply 跳过 preflight 的负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--apply 缺少 --preflight-check-cert-readable 必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖 apply 跳过证书可读 preflight 的负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--apply 缺少 --preflight-check-service-user-cert-readable 必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖 apply 跳过服务用户证书可读 preflight 的负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--apply 缺少 --preflight-check-service-binary-executable 必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖 apply 跳过 service 二进制可执行 preflight 的负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--apply 缺少 --preflight-check-ports-free 必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖 apply 跳过端口释放 preflight 的负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'dry-run 必须展示启用后 systemd drop-in 生效核验', reason: 'Pingora 直连启用检查必须覆盖启用后的 systemd 生效核验步骤。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'dry-run 必须展示启用后 service active 核验', reason: 'Pingora 直连启用检查必须覆盖启用后的 service active 核验。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--apply 缺少 --direct-https-base-url 必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖缺少 direct HTTPS 参数的负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--apply 缺少 --direct-http-base-url 必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖缺少 direct HTTP 参数的负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--apply 缺少 --direct-host 必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖缺少 direct Host/SNI 的负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--apply 缺少 --direct-redirect-host 必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖缺少 redirect host 的负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--apply 缺少 --direct-spacetime-database 必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖缺少 WSS 数据库名的负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'direct live smoke 失败时 enable apply 必须失败', reason: 'Pingora 直连启用检查必须覆盖 direct live smoke 失败负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'direct preflight 脚本缺失时 enable apply 必须失败', reason: 'Pingora 直连启用检查必须覆盖 direct preflight 脚本缺失负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'direct live smoke 脚本缺失时 enable apply 必须失败', reason: 'Pingora 直连启用检查必须覆盖 direct live smoke 脚本缺失负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--template-path 必须是绝对路径', reason: 'Pingora 直连启用检查必须覆盖模板相对路径负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--dropin-path 必须是绝对路径', reason: 'Pingora 直连启用检查必须覆盖 drop-in 相对路径负例。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'drop-in 目录不能是符号链接', reason: 'Pingora 直连启用脚本 apply 前必须拒绝符号链接 drop-in 目录,避免写到非预期 systemd 位置。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'drop-in 目标不能是符号链接', reason: 'Pingora 直连启用脚本 apply 前必须拒绝符号链接 drop-in 目标,避免覆盖非预期文件。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'reject_control_characters', reason: 'Pingora 直连启用脚本必须在修改 systemd 前拒绝带换行或 NUL 的切换参数。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'reject_filesystem_root_path', reason: 'Pingora 直连启用脚本必须在修改 systemd 前拒绝文件系统根目录路径参数。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '不能包含换行或 NUL 字符', reason: 'Pingora 直连启用脚本拒绝控制字符参数时必须给出明确错误。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '不能是文件系统根目录', reason: 'Pingora 直连启用脚本拒绝文件系统根目录路径时必须给出明确错误。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'assertApplyRejectsSymlinkDropinDirectoryBeforeInstall', reason: 'Pingora 直连启用检查必须覆盖符号链接 drop-in 目录负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'assertApplyRejectsSymlinkDropinFileBeforeInstall', reason: 'Pingora 直连启用检查必须覆盖符号链接 drop-in 目标负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'assertRejectsControlCharacterInputsBeforeApply', reason: 'Pingora 直连启用检查必须覆盖控制字符参数会在 apply 写 systemd 前失败。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'assertFilesystemRootPathsRejected', reason: 'Pingora 直连启用检查必须覆盖文件系统根目录路径会在 apply 写 systemd 前失败。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--preflight-script 必须是绝对路径', reason: 'Pingora 直连启用脚本的 preflight 脚本路径必须固定为绝对路径,避免切换窗口受 cwd 影响。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--direct-live-script 必须是绝对路径', reason: 'Pingora 直连启用脚本的 direct live smoke 脚本路径必须固定为绝对路径,避免切换窗口受 cwd 影响。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '相对路径 direct preflight 脚本必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖 direct preflight 脚本相对路径负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '相对路径 direct live smoke 脚本必须被拒绝', reason: 'Pingora 直连启用检查必须覆盖 direct live smoke 脚本相对路径负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'dry-run 不应删除临时 drop-in 文件', reason: 'Pingora 直连回退检查必须证明默认 dry-run 不修改 drop-in。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'dry-run 必须展示回退后 systemd drop-in 移除核验', reason: 'Pingora 直连回退检查必须覆盖回退后的 systemd 移除核验步骤。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'dry-run 必须展示回退后 ExecStart 指向核验', reason: 'Pingora 直连回退检查必须覆盖回退后的 current release ExecStart 核验。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: '回退脚本 ExecStart 核验必须以随包主 service 模板为真相源', reason: 'Pingora 直连回退脚本必须以随包主 service 模板为 ExecStart 真相源。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'dry-run 必须展示 reload Nginx 后 active 核验', reason: 'Pingora 直连回退检查必须覆盖 Nginx reload 后状态核验步骤。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'dry-run 必须展示 Nginx 入口 smoke', reason: 'Pingora 直连回退检查必须覆盖 Nginx smoke dry-run 命令。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: '--apply 缺少 --reload-nginx 必须被拒绝', reason: 'Pingora 直连回退检查必须覆盖 apply 跳过 Nginx reload 的负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'nginx -t 失败时 rollback apply 必须失败', reason: 'Pingora 直连回退检查必须覆盖 Nginx 配置语法错误负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: '--apply 缺少 --nginx-smoke-url 必须被拒绝', reason: 'Pingora 直连回退检查必须覆盖缺少 Nginx smoke URL 的负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: '缺少 --nginx-smoke-host 必须被拒绝', reason: 'Pingora 直连回退检查必须覆盖 loopback smoke 缺少 Host 的负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: '非法 --nginx-smoke-host 必须被拒绝', reason: 'Pingora 直连回退检查必须覆盖非法 smoke Host 的负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'Nginx smoke 失败时 rollback apply 必须失败', reason: 'Pingora 直连回退检查必须覆盖 Nginx smoke 失败负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'Nginx smoke 响应体不匹配时 rollback apply 必须失败', reason: 'Pingora 直连回退检查必须覆盖 Nginx smoke 响应体漂移负例。', }, { file: 'scripts/check-pingora-release-readiness-plan.mjs', includes: 'dry-run cutover rollback apply 必须使用显式传入的 Nginx smoke body 片段', reason: 'Pingora cutover runbook 自检必须覆盖 rollback Nginx smoke body 显式配置门禁。', }, { file: 'scripts/check-pingora-release-readiness.mjs', includes: 'rollbackNginxSmokeExpectBody', reason: 'Pingora cutover runbook 必须把 rollback Nginx smoke body 片段作为显式配置。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'dry-run 必须展示 health patrol env 回退后复核命令', reason: 'Pingora 直连回退检查必须覆盖 health patrol env 复核 dry-run 命令。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: '相对路径 --health-patrol-env-file 必须被拒绝', reason: 'Pingora 直连回退检查必须覆盖 health patrol env 相对路径负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'health patrol env 仍停留在 pingora-direct 时 rollback apply 必须失败', reason: 'Pingora 直连回退检查必须覆盖巡检 env 未切回 nginx 的负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'dry-run 必须展示 Pingora shadow probe 命令且隐藏 token', reason: 'Pingora 直连回退检查必须覆盖 shadow probe dry-run 命令并避免泄露 token。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'shadow probe URL 缺少 token 必须被拒绝', reason: 'Pingora 直连回退检查必须覆盖 shadow probe 参数成对出现。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'Pingora shadow probe body 错误时 rollback apply 必须失败', reason: 'Pingora 直连回退检查必须覆盖 shadow probe 响应身份错误负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'systemctl show ExecStart 指向旧 release 时 rollback apply 必须失败', reason: 'Pingora 直连回退检查必须覆盖 systemd ExecStart 漂到旧 release 的负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: '--service-unit-path 必须是绝对路径', reason: 'Pingora 直连回退检查必须覆盖主 service 模板相对路径负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: '--dropin-path 必须是绝对路径', reason: 'Pingora 直连回退检查必须覆盖相对路径负例。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'require_absolute_path_if_path_like "--nginx-binary"', reason: 'Pingora 直连回退脚本覆盖 Nginx 二进制时,路径形式必须固定为绝对路径。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'require_absolute_path_if_path_like "--curl-binary"', reason: 'Pingora 直连回退脚本覆盖 curl 二进制时,路径形式必须固定为绝对路径。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: '相对路径 --nginx-binary 必须被拒绝', reason: 'Pingora 直连回退检查必须覆盖 Nginx 二进制相对路径负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: '相对路径 --curl-binary 必须被拒绝', reason: 'Pingora 直连回退检查必须覆盖 curl 二进制相对路径负例。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'validate_http_url "--nginx-smoke-url"', reason: 'Pingora 直连回退脚本必须在改 systemd 前拒绝非法 Nginx smoke URL。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'reject_control_characters', reason: 'Pingora 直连回退脚本必须在 nginx -t、删除 drop-in 或 reload 前拒绝带换行或 NUL 的回退参数。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: 'reject_filesystem_root_path', reason: 'Pingora 直连回退脚本必须在 nginx -t、删除 drop-in 或 reload 前拒绝文件系统根目录路径参数。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '不能包含换行或 NUL 字符', reason: 'Pingora 直连回退脚本拒绝控制字符参数时必须给出明确错误。', }, { file: 'scripts/deploy/pingora-direct-rollback.sh', includes: '不能是文件系统根目录', reason: 'Pingora 直连回退脚本拒绝文件系统根目录路径时必须给出明确错误。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: '非法 --nginx-smoke-url 必须被拒绝', reason: 'Pingora 直连回退检查必须覆盖非法 Nginx smoke URL 负例。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'assertRejectsControlCharacterInputsBeforeApply', reason: 'Pingora 直连回退检查必须覆盖控制字符参数会在 nginx -t 和删除 drop-in 前失败。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'assertRejectsFilesystemRootPathsBeforeApply', reason: 'Pingora 直连回退检查必须覆盖文件系统根目录路径会在 nginx -t 和删除 drop-in 前失败。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'assertApplyRejectsSymlinkDropinDirectoryBeforeNginxTest', reason: 'Pingora 直连回退检查必须覆盖符号链接 drop-in 目录会在 nginx -t 前失败。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'assertApplyRejectsSymlinkDropinFileBeforeRemoval', reason: 'Pingora 直连回退检查必须覆盖符号链接 drop-in 目标不会删除真实目标文件。', }, { file: 'scripts/check-pingora-direct-rollback.mjs', includes: 'assertApplyRejectsDirectoryDropinTargetBeforeNginxTest', reason: 'Pingora 直连回退检查必须覆盖目录型 drop-in 目标会在 nginx -t 前失败。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'scripts/deploy/pingora-direct-rollback.sh', reason: 'API deploy 必须把 Pingora 直连回退脚本复制到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'scripts/deploy/pingora-direct-enable.sh', reason: 'API deploy 必须把 Pingora 直连启用脚本复制到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'scripts/check-pingora-direct-preflight.mjs', reason: 'API deploy 必须把 Pingora 直连预检脚本复制到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'scripts/check-pingora-canary-live.mjs', reason: 'API deploy 必须把 Pingora canary live smoke 脚本复制到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'scripts/check-pingora-direct-live.mjs', reason: 'API deploy 必须把 Pingora 直连 live smoke 脚本复制到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'scripts/check-pingora-release-readiness.mjs', reason: 'API deploy 必须把 Pingora release readiness 聚合门禁脚本复制到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'deploy/pingora', reason: 'API deploy 必须把 Pingora 配置目录复制到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'deploy/systemd', reason: 'API deploy 必须把 systemd 配置目录复制到 current release,供直连预检读取主 service 和 drop-in 模板。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'ENV_DEPLOY_DIR_SOURCE', reason: 'API deploy 必须从发布包内复制 deploy/env 示例目录。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/deploy/production-api-deploy.sh', reason: 'API release build 动态烟测必须覆盖随产物执行的 deploy 脚本。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'API release README 必须说明随包携带 API Deploy 执行入口', reason: 'API release build 动态烟测必须覆盖发布包 README 中的 deploy 执行入口说明。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/deploy/maintenance-on.sh', reason: 'API release build 动态烟测必须覆盖 deploy 同目录维护开启脚本。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/deploy/maintenance-off.sh', reason: 'API release build 动态烟测必须覆盖 deploy 同目录维护关闭脚本。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/deploy/pingora-direct-enable.sh', reason: 'API release build 动态烟测必须覆盖直连启用脚本进入发布包。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/deploy/pingora-direct-rollback.sh', reason: 'API release build 动态烟测必须覆盖直连回退脚本进入发布包。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', reason: 'API release build 动态烟测必须覆盖 health patrol env 切换脚本进入发布包。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/deploy/pingora-gateway-env-shadow-switch.mjs', reason: 'API release build 动态烟测必须覆盖 gateway env shadow 切换脚本进入发布包。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/check-pingora-direct-preflight.mjs', reason: 'API release build 动态烟测必须覆盖直连预检脚本进入发布包。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/check-production-health-patrol-env.mjs', reason: 'API release build 动态烟测必须覆盖健康巡检 env 复核脚本进入发布包。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/check-pingora-release-readiness.mjs', reason: 'API release build 动态烟测必须覆盖 Pingora release readiness 聚合门禁脚本进入发布包。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/check-pingora-canary-live.mjs', reason: 'API release build 动态烟测必须覆盖 canary live smoke 脚本进入发布包。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'scripts/check-pingora-direct-live.mjs', reason: 'API release build 动态烟测必须覆盖直连 live smoke 脚本进入发布包。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'deploy/systemd/genarrative-pingora-gateway.service', reason: 'API release build 动态烟测必须覆盖 systemd 模板进入发布包。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'deploy/pingora/pingora-gateway.env.example', reason: 'API release build 动态烟测必须覆盖 Pingora 配置进入发布包。', }, { file: 'scripts/check-production-api-release.mjs', includes: '--skip-api-build', reason: 'API release build 动态烟测必须避免真实构建 Rust。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/deploy/production-api-deploy.sh', reason: 'API deploy 动态烟测必须从发布产物内执行 deploy 脚本。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/deploy/maintenance-on.sh', reason: 'API deploy 动态烟测必须覆盖 deploy 同目录维护开启脚本。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/deploy/maintenance-off.sh', reason: 'API deploy 动态烟测必须覆盖 deploy 同目录维护关闭脚本。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/check-pingora-canary-live.mjs', reason: 'API deploy 动态烟测必须覆盖 Pingora canary live smoke 脚本进入 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/check-pingora-release-readiness.mjs', reason: 'API deploy 动态烟测必须覆盖 Pingora release readiness 聚合门禁脚本进入 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'release-manifest.json 缺少 pingora-gateway artifact', reason: 'API deploy 必须阻断带 Pingora 二进制但 manifest 未登记 Pingora artifact 的发布包。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '发布产物缺少 release-manifest.json', reason: 'API deploy 必须强制要求 release manifest,避免 current release 缺少产物证据根。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'require_absolute_path "${RELEASE_ROOT}" "--release-root"', reason: 'API deploy 发布根目录必须是绝对路径,避免 Jenkins 工作目录影响 release 位置。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'require_absolute_path "${CURRENT_LINK}" "--current-link"', reason: 'API deploy current 链接必须是绝对路径,避免相对路径切错入口。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'require_absolute_path "${API_ENV_FILE}" "--api-env-file"', reason: 'API deploy 环境文件必须是绝对路径,避免相对路径写入工作区文件。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '^[0-9A-Za-z][0-9A-Za-z._-]*$', reason: 'API deploy release version 必须以数字或字母开头,避免点目录或隐藏 staging 名称污染 release 根目录。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '--version 不能是点目录', reason: 'API deploy 必须显式拒绝 . / .. 这类点目录版本名。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '.staging.$$', reason: 'API deploy 必须先写 staging release,避免失败时污染正式 release 目录。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '目标 release 已存在,拒绝覆盖或合并旧文件', reason: 'API deploy 必须拒绝同版本 release 目录复用,避免旧文件混入 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '目标 release 在发布过程中出现,拒绝合并 staging', reason: 'API deploy 在最终提升前必须再次拒绝同版本 release 竞态出现,避免把 staging 合并进旧目录。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'current 链接路径已存在但不是符号链接,拒绝覆盖', reason: 'API deploy 必须拒绝目录型 current 路径,避免 ln 把新链接写进旧目录。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'ln -sfnT "${RELEASE_DIR}" "${CURRENT_LINK}"', reason: 'API deploy 切换 current 必须用 -T 固定符号链接替换语义。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'mv -T "${STAGING_RELEASE_DIR}" "${RELEASE_DIR}"', reason: 'API deploy 必须用非合并语义把 staging release 提升为正式 release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsPingoraArtifactMissingManifestEntry', reason: 'API deploy 动态烟测必须覆盖 Pingora 二进制与 release manifest 漂移负例。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRequiresPingoraWhenRequested', reason: 'API deploy 动态烟测必须覆盖 --require-pingora-gateway 缺失产物负例。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertReadinessFailureKeepsMaintenanceAfterCurrentSwitch', reason: 'API deploy 动态烟测必须覆盖 current 切换后的 readiness 失败仍保留维护模式。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '--require-pingora-gateway', reason: 'API deploy 必须支持 Jenkins release 对 Pingora 产物做硬要求。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertMissingReleaseManifestFails', reason: 'API deploy 动态烟测必须覆盖缺少 release manifest 的失败维护回滚。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertReleaseManifestMissingApiArtifactFails', reason: 'API deploy 动态烟测必须覆盖 release manifest 缺少 api-server artifact 的负例。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsDotVersion', reason: 'API deploy 动态烟测必须覆盖 . 版本名负例。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsDotDotVersion', reason: 'API deploy 动态烟测必须覆盖 .. 版本名负例。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsVersionStartingWithDot', reason: 'API deploy 动态烟测必须覆盖以点开头版本名负例。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsExistingReleaseDirectory', reason: 'API deploy 动态烟测必须覆盖同版本 release 目录已存在时拒绝覆盖。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsDirectoryCurrentLink', reason: 'API deploy 动态烟测必须覆盖 current 路径不是符号链接时拒绝覆盖。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsRelativeReleaseRoot', reason: 'API deploy 动态烟测必须覆盖 release root 相对路径负例。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsRelativeCurrentLink', reason: 'API deploy 动态烟测必须覆盖 current link 相对路径负例。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsRelativeApiEnvFile', reason: 'API deploy 动态烟测必须覆盖 api env 文件相对路径负例。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployCleansStagingReleaseOnFailure', reason: 'API deploy 动态烟测必须覆盖失败时清理 staging release 且不留下正式 release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsFinalReleaseRaceAndCleansStaging', reason: 'API deploy 动态烟测必须覆盖最终提升前 release 目录竞态出现时拒绝合并并清理 staging。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertMissingBackupScriptFails', reason: 'API deploy 动态烟测必须覆盖缺少数据库备份脚本的失败维护回滚。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertMissingHealthPatrolScriptFails', reason: 'API deploy 动态烟测必须覆盖缺少健康巡检脚本的失败维护回滚。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertMissingHealthPatrolEnvCheckFails', reason: 'API deploy 动态烟测必须覆盖缺少健康巡检 env 复核脚本的失败维护回滚。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/check-pingora-direct-preflight.mjs', reason: 'API deploy 动态烟测必须覆盖直连预检脚本进入 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/check-production-health-patrol-env.mjs', reason: 'API deploy 动态烟测必须覆盖健康巡检 env 复核脚本进入 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/deploy/pingora-health-patrol-env-switch.mjs', reason: 'API deploy 动态烟测必须覆盖 health patrol env 切换脚本进入 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/deploy/pingora-gateway-env-shadow-switch.mjs', reason: 'API deploy 动态烟测必须覆盖 gateway env shadow 切换脚本进入 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'scripts/check-pingora-direct-live.mjs', reason: 'API deploy 动态烟测必须覆盖直连 live smoke 脚本进入 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'deploy/systemd/genarrative-pingora-gateway.service', reason: 'API deploy 动态烟测必须覆盖 systemd 模板进入 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'deploy/pingora/pingora-gateway.env.example', reason: 'API deploy 动态烟测必须覆盖 Pingora 配置进入 current release。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'fakeBin', reason: 'API deploy 动态烟测必须使用 fake systemctl/curl,禁止触碰真实服务。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'scripts/deploy/pingora-direct-rollback.sh', reason: 'API Build 归档必须包含 Pingora 直连回退脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'scripts/deploy/pingora-direct-enable.sh', reason: 'API Build 归档必须包含 Pingora 直连启用脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'scripts/check-pingora-direct-preflight.mjs', reason: 'API Build 归档必须包含 Pingora 直连预检脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'scripts/check-pingora-direct-live.mjs', reason: 'API Build 归档必须包含 Pingora 直连 live smoke 脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'deploy/pingora/**', reason: 'API Build 归档必须包含 Pingora 配置目录。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'deploy/systemd/**', reason: 'API Build 归档必须包含 systemd 配置目录。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'scripts/deploy/pingora-direct-rollback.sh', reason: 'API Deploy 复制上游产物时必须包含 Pingora 直连回退脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'scripts/deploy/pingora-direct-enable.sh', reason: 'API Deploy 复制上游产物时必须包含 Pingora 直连启用脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'scripts/check-pingora-direct-preflight.mjs', reason: 'API Deploy 复制上游产物时必须包含 Pingora 直连预检脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'scripts/check-pingora-direct-live.mjs', reason: 'API Deploy 复制上游产物时必须包含 Pingora 直连 live smoke 脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'deploy/pingora/**', reason: 'API Deploy 复制上游产物时必须包含 Pingora 配置目录。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'deploy/systemd/**', reason: 'API Deploy 复制上游产物时必须包含 systemd 配置目录。', }, { file: 'deploy/pingora/nginx-route-parity.matrix.json', includes: 'spacetime_subscribe', reason: 'Pingora 路由矩阵必须覆盖 SpacetimeDB WebSocket subscribe。', }, { file: 'scripts/check-pingora-route-parity.mjs', includes: 'deploy/nginx/genarrative.conf', reason: 'Pingora 路由矩阵检查必须覆盖生产 Nginx 模板。', }, { file: 'scripts/check-pingora-route-parity.mjs', includes: 'deploy/nginx/genarrative-dev-http.conf', reason: 'Pingora 路由矩阵检查必须覆盖开发服 Nginx 模板。', }, { file: 'server-rs/crates/pingora-gateway/src/main.rs', includes: 'ROUTE_PARITY_MATRIX_JSON', reason: 'Pingora Rust 路由单测必须读取共享路由矩阵。', }, { file: 'scripts/check-nginx-pingora-canary.mjs', includes: '--require-nginx', reason: 'Pingora canary 校验脚本必须支持在有 Nginx 的环境强制执行 nginx -t。', }, { file: 'scripts/check-nginx-pingora-canary.mjs', includes: 'proxy_set_header Upgrade $http_upgrade;', reason: 'Pingora canary 校验脚本必须覆盖 SpacetimeDB WebSocket Upgrade 设置。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'SpacetimeDB WebSocket Upgrade', reason: 'Pingora 网关 smoke 必须覆盖 SpacetimeDB WebSocket 代理。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'v2.bsatn.spacetimedb', reason: 'Pingora 网关 smoke 必须覆盖 SpacetimeDB WSS 子协议透传。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'gzip 压缩响应', reason: 'Pingora 网关 smoke 必须覆盖 gzip 响应压缩。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'gzip-only 压缩算法白名单', reason: 'Pingora 网关 smoke 必须覆盖压缩算法白名单。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'gzip 最小长度不压缩小响应', reason: 'Pingora 网关 smoke 必须覆盖 Nginx gzip_min_length parity。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'gzip types 不压缩图片资源', reason: 'Pingora 网关 smoke 必须覆盖 Nginx gzip_types parity。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: '主站指纹静态资源长缓存', reason: 'Pingora 网关 smoke 必须覆盖 Vite 指纹资源 immutable 缓存头。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: "response.headers['cache-control'] === 'no-cache'", reason: 'Pingora 网关 smoke 必须覆盖 HTML 和普通静态资源 no-cache 口径。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: '静态资源 If-None-Match 返回 304', reason: 'Pingora 网关 smoke 必须覆盖静态资源 ETag 协商缓存。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: '静态资源 If-Modified-Since 返回 304', reason: 'Pingora 网关 smoke 必须覆盖静态资源 Last-Modified 协商缓存。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: '静态资源非读取方法返回 405', reason: 'Pingora 网关 smoke 必须覆盖静态资源只允许 GET / HEAD。', }, { file: 'server-rs/crates/pingora-gateway/src/main.rs', includes: 'GET, HEAD', reason: 'Pingora 静态响应必须对非读取方法返回 Allow: GET, HEAD。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: '静态资源 Range 返回 206', reason: 'Pingora 网关 smoke 必须覆盖静态资源单 Range 局部读取。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: '静态资源 If-Range 日期匹配返回 206', reason: 'Pingora 网关 smoke 必须覆盖静态资源 If-Range 匹配时继续返回局部内容。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: '静态资源 If-Range 旧日期回完整文件', reason: 'Pingora 网关 smoke 必须覆盖静态资源 If-Range 不匹配时回完整内容。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: '静态资源越界 Range 返回 416', reason: 'Pingora 网关 smoke 必须覆盖静态资源越界 Range 响应。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'access log 静态边界状态对账', reason: 'Pingora 网关 smoke 必须按 request_id 对账静态 304 / 405 / 206 / 416 access log,避免直连证据链漏掉本地响应状态。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'entry.method === expected.method', reason: 'Pingora 网关 smoke 必须按 request_id 对账静态 access log 的 method,避免 HEAD / POST 边界被状态码巧合掩盖。', }, { file: 'server-rs/crates/pingora-gateway/src/main.rs', includes: 'Accept-Ranges', reason: 'Pingora 静态响应必须声明 bytes Range 能力。', }, { file: 'server-rs/crates/pingora-gateway/src/main.rs', includes: 'Content-Range', reason: 'Pingora 静态 Range 响应必须写入 Content-Range。', }, { file: 'server-rs/crates/pingora-gateway/src/main.rs', includes: 'Last-Modified', reason: 'Pingora 静态响应必须写入 Last-Modified,避免直连后协商缓存能力退化。', }, { file: 'server-rs/crates/pingora-gateway/src/main.rs', includes: 'if-none-match', reason: 'Pingora 静态响应必须支持 ETag 条件请求返回 304。', }, { file: 'server-rs/crates/pingora-gateway/src/main.rs', includes: 'GENARRATIVE_PINGORA_GATEWAY_ASSET_CACHE_CONTROL', reason: 'Pingora 网关必须暴露指纹静态资源 Cache-Control 配置。', }, { file: 'server-rs/crates/pingora-gateway/src/main.rs', includes: 'has_fingerprinted_file_name', reason: 'Pingora 网关必须按 Vite 指纹文件名区分长期缓存静态资源。', }, { file: 'server-rs/crates/pingora-gateway/src/main.rs', includes: '不能包含换行或 NUL 字符', reason: 'Pingora 静态缓存头配置必须拒绝响应头注入字符。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'GENARRATIVE_PINGORA_GATEWAY_GZIP_LEVEL', reason: 'Pingora 网关 smoke 必须覆盖 gzip 配置校验。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'GENARRATIVE_PINGORA_GATEWAY_COMPRESSION_ALGORITHMS', reason: 'Pingora 网关 smoke 必须覆盖压缩算法配置校验。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'GATEWAY_CONCURRENCY_LIMITED', reason: 'Pingora 网关 smoke 必须覆盖接流并发保护。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'PAYLOAD_TOO_LARGE', reason: 'Pingora 网关 smoke 必须覆盖请求体大小限制。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'access log 落盘', reason: 'Pingora 网关 smoke 必须覆盖 access log 文件写入。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: '配置错误启动失败', reason: 'Pingora 网关 smoke 必须覆盖不安全配置 fail-fast。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'SECRET_VALUE_FLAGS', reason: 'Pingora 网关 smoke 必须集中维护敏感参数脱敏列表。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'redactSecretArgs(args).join', reason: 'Pingora 网关 smoke 打印 direct live 命令时必须隐藏 probe token。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'GATEWAY_UPSTREAM_ERROR', reason: 'Pingora 网关 smoke 必须覆盖上游断连时的稳定 JSON 错误。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'GATEWAY_UPSTREAM_TIMEOUT', reason: 'Pingora 网关 smoke 必须覆盖上游超时时的稳定 JSON 错误。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'TLS 直连接口返回 index.html', reason: 'Pingora 网关 smoke 必须覆盖可选 TLS 直连接口。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'HTTP 入口 301 到 HTTPS', reason: 'Pingora 网关 smoke 必须覆盖可选 HTTP 到 HTTPS 重定向入口。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'direct-access-log', reason: 'Pingora direct live smoke 必须覆盖 Pingora access log 落盘校验。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'https-static-asset', reason: 'Pingora direct live smoke 必须自动发现并探测首页引用的静态资源,避免直连只验证 API / WSS 路径。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'https-static-asset-range', reason: 'Pingora direct live smoke 必须验证首页静态资产 Range: bytes=0-0,避免直连后媒体/浏览器探测能力退化。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'https-static-asset-head', reason: 'Pingora direct live smoke 必须验证首页静态资产 HEAD 行为,覆盖 curl -I、监控探针和 CDN 预检。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'https-static-fingerprinted-asset', reason: 'Pingora direct live smoke 必须额外探测首页引用的 Vite 指纹静态资源。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'public, max-age=31536000, immutable', reason: 'Pingora direct live smoke 必须验证指纹静态资源长期缓存头,避免直连后旧 tab chunk 缓存口径退化。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'pickEvidenceHeaders', reason: 'Pingora direct live smoke 必须把静态响应头白名单写入 JSON 证据,便于切换证据包复盘。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: "'content-range'", reason: 'Pingora direct live smoke 的静态响应头 JSON 证据必须包含 Content-Range。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'https-static-fingerprinted-asset-head', reason: 'Pingora direct live smoke 必须验证指纹静态资源 HEAD 行为。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'https-static-fingerprinted-asset-range', reason: 'Pingora direct live smoke 必须验证指纹静态资源 Range 行为。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'https-static-asset-etag-304', reason: 'Pingora direct live smoke 必须验证首页静态资源 ETag 条件请求返回 304。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'https-static-fingerprinted-asset-etag-304', reason: 'Pingora direct live smoke 必须验证指纹静态资源 ETag 条件请求返回 304。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: '', reason: 'Pingora 本地 smoke fixture 必须让 direct live 自动发现指纹静态资源。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'direct live 必须验证首页引用的指纹静态资源 GET 200。', reason: 'Pingora 本地 smoke 必须从 direct live JSON 结构化确认指纹资源 GET 证据。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'direct live JSON 必须保留指纹静态资源 immutable Cache-Control 证据。', reason: 'Pingora 本地 smoke 必须确认 direct live JSON 可复盘指纹资源长期缓存头。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'direct live JSON 必须保留指纹静态资源 Content-Range 证据。', reason: 'Pingora 本地 smoke 必须确认 direct live JSON 可复盘指纹资源 Range 响应头。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'direct live access log 必须保留指纹静态 Range 的 method/path/status 明细。', reason: 'Pingora 本地 smoke 必须确认指纹资源 Range 进入 access log method/path/status 证据。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'direct live 必须验证首页引用的指纹静态资源 ETag 304。', reason: 'Pingora 本地 smoke 必须从 direct live JSON 结构化确认指纹资源 304 证据。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'direct live access log 必须保留指纹静态 ETag 304 的 method/path/status 明细。', reason: 'Pingora 本地 smoke 必须确认指纹资源 304 进入 access log method/path/status 证据。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'Content-Range 不符合 bytes 0-0/', reason: 'Pingora direct live smoke 必须校验静态资产 Range 响应的 Content-Range。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'request_id', reason: 'Pingora direct live smoke 必须按 request_id 反查 access log。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'matchedCount', reason: 'Pingora direct live smoke 的 access log 证据必须记录匹配数量,便于证据包复盘。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'mismatches', reason: 'Pingora direct live smoke 的 access log 证据必须保留 method/path/status 漂移明细。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'expectedMethod', reason: 'Pingora direct live smoke 的 access log 反查必须记录每个 request_id 的预期 HTTP 方法。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'actualMethod', reason: 'Pingora direct live smoke 的 access log 反查必须记录每个 request_id 的实际 HTTP 方法。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'expectedStatusCode', reason: 'Pingora direct live smoke 的 access log 反查必须记录每个 request_id 的预期状态码。', }, { file: 'scripts/check-pingora-direct-live.mjs', includes: 'actualStatusCode', reason: 'Pingora direct live smoke 的 access log 反查必须记录每个 request_id 的实际状态码。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'direct-access-log 检查必须保留 mismatches 明细数组。', reason: 'Pingora 切流证据包自测必须防止 direct live access log JSON 明细退化。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'direct-access-log 检查必须保留已匹配 request_id 的预期方法。', reason: 'Pingora 切流证据包自测必须防止 direct live access log method 明细退化。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'direct-live.json 必须保留指纹静态资源 Cache-Control 证据。', reason: 'Pingora 切流证据包自测必须防止 direct live 静态响应头证据退化。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'direct-live.json 必须保留指纹静态资源 Content-Range 证据。', reason: 'Pingora 切流证据包自测必须防止 direct live Range 响应头证据退化。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'directLiveStaticHeaders', reason: 'Pingora 切流证据包 manifest 必须提升 direct live 静态响应头摘要,便于快速复盘。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'directLiveStaticHeaders?.ok', reason: 'Pingora 切流证据包必须把静态响应头摘要完整性纳入 direct live 成功判定。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'ETag 304 statusCode 应为 304', reason: 'Pingora 切流证据包必须诊断静态 ETag 304 证据缺失。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'Range statusCode 应为 206', reason: 'Pingora 切流证据包必须诊断静态 Range 证据缺失。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'manifest 必须提升指纹静态资源 Content-Range 证据。', reason: 'Pingora 切流证据包自测必须防止 manifest 静态响应头摘要退化。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertDirectLiveMissingStaticHeadersSummaryFails', reason: 'Pingora 切流证据包自测必须覆盖 direct live JSON 缺少静态响应头证据的负例。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertDirectLiveStaticHeaderDiagnosticsFails', reason: 'Pingora 切流证据包自测必须覆盖静态 Range / 304 摘要不完整时失败。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'manifest 必须提升普通静态资源 ETag 304 证据。', reason: 'Pingora 切流证据包自测必须防止 manifest 普通静态 304 摘要退化。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'summaryDirectLiveStaticHeaders', reason: 'Pingora 证据根目录审计必须读取阶段 manifest 的 direct live 静态响应头摘要。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: '--require-phase-pingora-env-shadow', reason: 'Pingora 证据根目录审计必须支持强制校验 post-rollback Pingora env shadow 摘要。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'summaryPingoraEnvShadow', reason: 'Pingora 证据根目录审计必须读取阶段 manifest 的 Pingora env shadow 摘要。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'tlsCertFile 必须为空', reason: 'Pingora 证据根目录审计必须拒绝 post-rollback TLS 证书路径残留。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'shadowReady 必须为 true', reason: 'Pingora 证据根目录审计必须拒绝 post-rollback 快照姿态不是 shadow 的证据。', }, { file: 'scripts/ops/pingora-cutover-evidence-audit.mjs', includes: 'directLiveStaticHeaders: latest.summaryDirectLiveStaticHeaders', reason: 'Pingora 证据根目录审计输出必须提升阶段 direct live 静态响应头摘要。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: 'assertRequirePhasePingoraEnvShadowFailsWhenDirectLowPortsRemain', reason: 'Pingora 证据根目录审计自测必须覆盖 post-rollback 低端口 env 残留失败路径。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: '证据根审计输出必须提升 post-enable direct live 指纹静态 Cache-Control 摘要。', reason: 'Pingora 证据根目录审计自测必须覆盖 direct live 静态响应头摘要输出。', }, { file: 'scripts/check-pingora-cutover-evidence-audit.mjs', includes: '证据根审计输出必须提升 post-enable direct live access log 摘要。', reason: 'Pingora 证据根目录审计自测必须覆盖 direct live access log 摘要输出。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: '静态 GET / HEAD / 304 / Range 结果还必须在 `direct-live.json` 中保留白名单响应头', reason: 'Pingora 试点文档必须说明 direct live JSON 会归档静态响应头白名单证据。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: '`cache-control`、`etag`、`last-modified`、`accept-ranges`、`content-range`、`content-length` 和 `content-encoding`', reason: 'Pingora 试点文档必须固定 direct live 静态响应头证据白名单。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: '静态摘要缺少缓存头、校验头、Range `206 + Content-Range`、ETag 304 / Last-Modified 304 证据时,证据包都会直接记为 `CRITICAL`', reason: 'Pingora 试点文档必须说明静态响应头证据不完整会让证据包失败。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: '总审计输出会把阶段 manifest 中的 `directLiveAccessLog` 与 `directLiveStaticHeaders` 一并带到对应 `phases[]` 项', reason: 'Pingora 试点文档必须说明最终证据根审计会输出 direct live 摘要。', }, { file: 'deploy/nginx/README.md', includes: 'direct live JSON 只给静态 GET / HEAD / 304 / Range 写入白名单 `headers`', reason: 'Nginx README 必须说明 Pingora direct live 静态头部证据归档口径。', }, { file: 'deploy/nginx/README.md', includes: 'manifest.summary.directLiveStaticHeaders', reason: 'Nginx README 必须说明切流 manifest 会提升 direct live 静态响应头摘要。', }, { file: 'deploy/nginx/README.md', includes: '证据包会记为 `CRITICAL`', reason: 'Nginx README 必须说明 direct live 静态响应头摘要缺关键证据时会阻断证据包。', }, { file: 'docs/project-memory/shared-memory/decision-log.md', includes: 'API / WSS 检查不落原始响应头', reason: '团队共享决策必须记录 direct live 只归档静态白名单响应头。', }, { file: 'docs/project-memory/shared-memory/decision-log.md', includes: 'directLiveStaticHeaders', reason: '团队共享决策必须记录切流 manifest 提升 direct live 静态响应头摘要。', }, { file: 'docs/project-memory/shared-memory/decision-log.md', includes: '静态头摘要缺少缓存头、校验头、Range `206 + Content-Range`、ETag 304 / Last-Modified 304 证据时整包记为 `CRITICAL`', reason: '团队共享决策必须记录静态响应头摘要不完整会阻断证据包。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: '不要把 `direct-live.json` 当成只有状态码的摘要', reason: '团队共享踩坑必须提醒 direct live JSON 需要可复盘静态响应头证据。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: 'manifest.summary.directLiveStaticHeaders', reason: '团队共享踩坑必须提醒切流 manifest 需要可快速复盘静态响应头摘要。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: '摘要缺少缓存头、校验头、Range `206 + Content-Range`、ETag 304 或 Last-Modified 304 证据,证据包会直接记为 `CRITICAL`', reason: '团队共享踩坑必须提醒静态响应头摘要不完整会阻断证据包。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'directLiveAccessLog', reason: 'Pingora 切流证据包 manifest 必须提升 direct live access log 摘要,便于快速复盘。', }, { file: 'scripts/ops/pingora-cutover-evidence-bundle.mjs', includes: 'direct live JSON missing direct-access-log result', reason: 'Pingora 切流证据包必须在 direct live JSON 缺少 access log 结果时标记 CRITICAL。', }, { file: 'scripts/check-pingora-cutover-evidence-bundle.mjs', includes: 'assertDirectLiveMissingAccessLogSummaryFails', reason: 'Pingora 切流证据包自测必须覆盖 direct live JSON 缺少 access log 结果的负例。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: '--apply 必须同时提供 --direct-pingora-access-log', reason: 'Pingora 直连启用 apply 必须强制 access log 落盘校验参数。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'direct_live_args+=(--json)', reason: 'Pingora 直连启用 apply 后必须用 JSON 模式运行 direct live,才能校验结构化接流证据。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'direct live JSON 缺少 direct-access-log 结构化结果', reason: 'Pingora 直连启用 apply 必须拒绝缺少 direct-access-log 结构化结果的 direct live 输出。', }, { file: 'scripts/deploy/pingora-direct-enable.sh', includes: 'direct-access-log evidence checked=', reason: 'Pingora 直连启用 apply 必须在 direct access log 结构化证据通过后输出摘要。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: '--apply 缺少 --direct-pingora-access-log 必须被拒绝', reason: 'Pingora 直连启用自测必须覆盖缺少 access log 参数的负例。', }, { file: 'scripts/check-pingora-direct-enable.mjs', includes: 'assertApplyFailsWhenDirectLiveAccessLogJsonMissing', reason: 'Pingora 直连启用自测必须覆盖 direct live 退出 0 但缺少 access log JSON 证据的负例。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: '--pingora-access-log', reason: 'Pingora 本地网关 smoke 必须把临时 access log 传给 direct live smoke。', }, { file: 'server-rs/crates/pingora-gateway/src/main.rs', includes: 'GENARRATIVE_PINGORA_GATEWAY_UPSTREAM_API_READ_TIMEOUT_SECONDS', reason: 'Pingora 网关必须暴露上游读取超时配置,避免正式切换时和 Nginx 超时口径漂移。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'production-health-patrol.mjs', reason: 'API deploy 必须把健康巡检脚本复制到 current release。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '发布产物缺少数据库备份脚本', reason: 'API deploy 缺少数据库备份脚本时必须 fail-fast。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: '发布产物缺少生产健康巡检脚本', reason: 'API deploy 缺少健康巡检脚本时必须 fail-fast。', }, { file: 'scripts/deploy/production-api-deploy.sh', excludes: 'WORKSPACE_BACKUP_SCRIPT_SOURCE', reason: 'API deploy 不应再从部署工作区兜底复制数据库备份脚本。', }, { file: 'scripts/deploy/production-api-deploy.sh', excludes: 'WORKSPACE_HEALTH_PATROL_SCRIPT_SOURCE', reason: 'API deploy 不应再从部署工作区兜底复制健康巡检脚本。', }, { file: 'scripts/deploy/production-api-deploy.sh', excludes: '回退使用部署工作区脚本', reason: 'API deploy 不应再用部署工作区脚本掩盖发布产物缺失。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'pingora-gateway.sha256', reason: 'API deploy 看到 Pingora 影子网关产物时必须校验 checksum 后复制。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'ensure_pingora_shadow_service', reason: 'API deploy 看到 Pingora 影子网关产物时必须先进入受控 shadow service 启动流程。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'systemctl cat "${service_name}"', reason: 'API deploy 自动启动或重启 Pingora 前必须读取 systemd 最终配置。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'CAP_NET_BIND_SERVICE', reason: 'API deploy 自动启动或重启 Pingora 前必须拒绝疑似 direct-entry 低端口 capability。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'Pingora 自动启动只允许 shadow 监听 127.0.0.1:18081', reason: 'API deploy 自动启动 Pingora 时必须限制为本机 shadow 高端口,避免误拉起公网直连入口。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'systemctl restart "${service_name}"', reason: 'API deploy 看到 Pingora 影子网关产物且 shadow 配置安全时必须随 current release 启动或重启。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRestartsActivePingoraWhenArtifactIncluded', reason: 'API deploy 动态烟测必须覆盖 Pingora 产物发布后 active shadow service 自动重启。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployStartsInactivePingoraWhenArtifactIncluded', reason: 'API deploy 动态烟测必须覆盖 Pingora shadow service inactive 但配置安全时会被主动拉起。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsPingoraDirectEntryWhenArtifactIncluded', reason: 'API deploy 动态烟测必须覆盖 direct-entry capability 下不会自动拉起 Pingora。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertDeployRejectsPingoraPublicListenWhenArtifactIncluded', reason: 'API deploy 动态烟测必须覆盖公网监听 env 下不会自动拉起 Pingora。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'assertApiReleaseCanIncludePingoraGatewayArtifact', reason: 'API release 动态烟测必须覆盖显式 include Pingora 影子网关产物。', }, { file: 'scripts/check-production-api-release.mjs', includes: '--skip-pingora-gateway-build', reason: 'API release 动态烟测应能用假二进制快速覆盖 Pingora 产物布局。', }, { file: 'scripts/check-production-api-release.mjs', includes: 'assertPingoraEnvProductionDefaults', reason: 'API release 动态烟测必须校验 Pingora env 的生产安全默认值。', }, { file: 'scripts/check-production-api-deploy.mjs', includes: 'assertPingoraEnvProductionDefaults', reason: 'API deploy 动态烟测必须校验 current release 内 Pingora env 的生产安全默认值。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_PROTECTION_ENABLED', reason: 'Pingora 网关配置示例必须保留接流保护总开关。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_INSTANCE_COUNT=1', reason: 'Pingora 网关配置示例必须显式保留默认单实例接流保护口径。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_SHARED_PROTECTION_CONFIRMED=false', reason: 'Pingora 网关配置示例必须默认不确认共享保护层。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_GZIP_ENABLED', reason: 'Pingora 网关配置示例必须暴露 gzip 总开关。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_TLS_LISTEN', reason: 'Pingora 网关配置示例必须暴露可选 TLS 直连入口。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_HTTP_REDIRECT_LISTEN', reason: 'Pingora 网关配置示例必须暴露可选 HTTP 到 HTTPS 重定向入口。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_COMPRESSION_ALGORITHMS=gzip', reason: 'Pingora 网关配置示例必须暴露压缩算法白名单。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'Pingora 正式化口径固定为 gzip-only', reason: 'Pingora 网关配置示例必须明确当前正式化压缩口径。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'Brotli', reason: 'Pingora 试点文档必须说明 Brotli 尚未进入 Pingora 的边界。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'Pingora 正式化口径固定为 gzip-only', reason: 'Pingora 试点文档必须把 Brotli 取舍落成明确结论。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', excludes: '补齐 Brotli 取舍', reason: 'Pingora 试点文档不能继续把 Brotli 取舍留成待办。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: 'Pingora Brotli 不能只看 Content-Encoding', reason: '团队共享踩坑必须记录 Pingora Brotli 端到端解压风险。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_GZIP_LEVEL=5', reason: 'Pingora 网关配置示例必须对齐 Nginx gzip 压缩等级。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_GZIP_MIN_LENGTH_BYTES=1024', reason: 'Pingora 网关配置示例必须对齐 Nginx gzip_min_length。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_HTML_CACHE_CONTROL=no-cache', reason: 'Pingora 网关配置示例必须暴露 HTML / SPA fallback 缓存头。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_ASSET_CACHE_CONTROL=public, max-age=31536000, immutable', reason: 'Pingora 网关配置示例必须暴露指纹静态资源长期缓存头。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'Vite 指纹静态资源', reason: 'Pingora 试点文档必须说明直连静态缓存头口径。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_UPSTREAM_API_READ_TIMEOUT_SECONDS=3600', reason: 'Pingora 网关配置示例必须保留上游 API 读取超时口径。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_UPSTREAM_LONG_READ_TIMEOUT_SECONDS=3600', reason: 'Pingora 网关配置示例必须保留长连接读取超时口径。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_API_MAX_CONCURRENT', reason: 'Pingora 网关配置示例必须保留通用 API 并发保护参数。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_ACCESS_LOG_FILE', reason: 'Pingora 网关配置示例必须暴露 access log 文件路径。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'API 上游未收到 X-Forwarded-Host', reason: 'Pingora gateway smoke 必须断言 API 上游收到 Nginx parity 的 X-Forwarded-Host。', }, { file: 'scripts/check-pingora-gateway-smoke.mjs', includes: 'API 上游 X-Forwarded-For 未追加 TCP 对端 IP', reason: 'Pingora gateway smoke 必须断言 X-Forwarded-For 追加真实 TCP 对端 IP。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'API 代理头', reason: 'Pingora 试点文档必须说明 API 代理头 parity 门禁。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'X-Real-IP', reason: 'Pingora 试点文档必须说明 X-Real-IP 的 TCP 对端 IP 口径。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: 'GENARRATIVE_PINGORA_DIRECT_PINGORA_ACCESS_LOG', reason: 'Pingora direct live env 示例必须暴露 direct access log 复核路径。', }, { file: 'deploy/env/pingora-direct-live.env.example', includes: 'GENARRATIVE_PINGORA_DIRECT_ACCESS_LOG_SINCE_LINES=2000', reason: 'Pingora direct live env 示例必须暴露 direct access log tail 行数。', }, { file: 'deploy/nginx/README.md', includes: '--direct-pingora-access-log /var/log/genarrative/pingora-gateway.access.log', reason: 'Nginx README 的 Pingora 直连 runbook 必须包含 access log 落盘校验参数。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: '--direct-pingora-access-log /var/log/genarrative/pingora-gateway.access.log', reason: 'Pingora 试点文档必须展示 direct access log 落盘校验参数。', }, { file: 'docs/【开发运维】本地开发验证与生产运维-2026-05-15.md', includes: '--direct-pingora-access-log /var/log/genarrative/pingora-gateway.access.log', reason: '生产运维文档必须展示 Pingora 直连 access log 落盘校验参数。', }, { file: 'docs/project-memory/shared-memory/decision-log.md', includes: '直连日志证据补充', reason: '团队共享决策必须记录 Pingora 直连 access log 证据门禁。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: '--direct-pingora-access-log /var/log/genarrative/pingora-gateway.access.log', reason: '团队共享踩坑必须记录 Pingora 直连 access log 参数。', }, { file: 'docs/【开发运维】本地开发验证与生产运维-2026-05-15.md', includes: '启用后 `--require-direct --release-runtime-only` 复核不再要求端口空闲', reason: '生产运维文档必须明确 Pingora 启用后直连复核不再要求 80/443 空闲。', }, { file: 'docs/【开发运维】本地开发验证与生产运维-2026-05-15.md', includes: '不要继续用固定 `http://127.0.0.1/healthz` 与 `"ok":true`', reason: '生产运维文档必须阻止回退 smoke 继续沿用旧的固定 healthz 响应片段。', }, { file: 'docs/【开发运维】本地开发验证与生产运维-2026-05-15.md', includes: "--rollback-nginx-smoke-expect-body ''", reason: '生产运维文档必须展示来自真实 Nginx 首页的回退响应体片段示例。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: '`--require-direct` 用于 Pingora 已接管后的直连复核,不再要求 `--direct-preflight-check-ports-free`', reason: 'Pingora 试点文档必须明确端口释放检查只属于切流前和启用 apply 阶段。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: "--rollback-nginx-smoke-expect-body ''", reason: 'Pingora 试点文档必须展示真实 Nginx 回退 smoke 响应体片段。', }, { file: 'deploy/nginx/README.md', includes: '启用后 `--require-direct` 复核不再要求端口空闲', reason: 'Nginx README 必须记录 Pingora 启用后 direct 复核的端口语义。', }, { file: 'deploy/nginx/README.md', includes: "--nginx-smoke-expect-body ''", reason: 'Nginx README 必须展示真实 Nginx 回退 smoke 响应体片段。', }, { file: 'deploy/nginx/README.md', includes: '不要继续用固定 `http://127.0.0.1/healthz` 与 `"ok":true`', reason: 'Nginx README 必须防止回退 smoke 示例回到旧 healthz 口径。', }, { file: 'docs/project-memory/shared-memory/decision-log.md', includes: '不再默认假定 `/healthz` 会返回 `"ok":true`', reason: '团队共享决策必须记录回退 smoke 的真实 Nginx 入口要求。', }, { file: 'docs/project-memory/shared-memory/decision-log.md', includes: '启用后复核应看到端口由 Pingora 占用而不是空闲', reason: '团队共享决策必须记录启用后 --require-direct 不再检查端口空闲。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: '不要继续用固定 `/healthz` 与 `"ok":true`', reason: '团队共享踩坑必须提醒回退 smoke 不能沿用旧 healthz 片段。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: '启用后 `--require-direct` 复核不再要求端口空闲', reason: '团队共享踩坑必须提醒端口空闲只属于切流前门禁。', }, { file: 'deploy/nginx/README.md', excludes: '--nginx-smoke-url http://127.0.0.1/healthz --nginx-smoke-host <域名> --nginx-smoke-expect-body \'"ok":true\'', reason: 'Nginx README 不应再给出固定 healthz + ok:true 的回退命令。', }, { file: 'docs/【开发运维】本地开发验证与生产运维-2026-05-15.md', excludes: '--nginx-smoke-url http://127.0.0.1/healthz --nginx-smoke-host <域名> --nginx-smoke-expect-body \'"ok":true\'', reason: '生产运维文档不应再给出固定 healthz + ok:true 的回退命令。', }, { file: 'docs/【开发运维】本地开发验证与生产运维-2026-05-15.md', excludes: 'rollback-nginx-smoke-expect-body="ok":true', reason: '生产运维 runbook 不应再默认展示 ok:true 作为回退响应体片段。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', excludes: 'rollback-nginx-smoke-expect-body="ok":true', reason: 'Pingora 试点 runbook 不应再默认展示 ok:true 作为回退响应体片段。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', excludes: '--nginx-smoke-url http://127.0.0.1/healthz --nginx-smoke-host <域名>', reason: '团队共享踩坑不应再把固定本机 healthz 当成可执行回退示例。', }, { file: 'deploy/pingora/pingora-gateway.env.example', includes: 'GENARRATIVE_PINGORA_GATEWAY_TRUSTED_FRONT_PROXY_CONFIRMED', reason: 'Pingora 网关配置示例必须暴露 X-Forwarded-For 信任确认开关。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'Brotli', reason: 'Pingora 试点文档必须明确 gzip 以外的压缩边界。', }, { file: 'deploy/nginx/README.md', includes: '直连 Pingora 时,不把 Brotli parity 作为切换门禁', reason: 'Nginx 压缩文档必须明确 Pingora Brotli 不作为直连切换门禁。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'Genarrative-Api-Deploy` 只能从上游构建归档复制并执行 `build//scripts/deploy/production-api-deploy.sh`', reason: 'Pingora 试点文档必须明确 API Deploy 执行入口来自 build 产物。', }, { file: 'docs/technical/【开发运维】Pingora独立网关试点-2026-06-11.md', includes: 'GENARRATIVE_PINGORA_GATEWAY_INSTANCE_COUNT>1', reason: 'Pingora 试点文档必须明确多实例接流保护确认边界。', }, { file: 'docs/【开发运维】本地开发验证与生产运维-2026-05-15.md', includes: 'GENARRATIVE_PINGORA_GATEWAY_INSTANCE_COUNT>1', reason: '生产运维文档必须明确多实例 Pingora 与进程内保护的启动 / preflight 边界。', }, { file: 'docs/project-memory/shared-memory/decision-log.md', includes: 'GENARRATIVE_PINGORA_GATEWAY_INSTANCE_COUNT>1', reason: '团队共享决策必须记录 Pingora 多实例接流保护边界。', }, { file: 'docs/project-memory/shared-memory/decision-log.md', includes: '禁止继续执行部署工作区根部脚本', reason: '团队共享决策必须记录 API Deploy 不再执行 workspace 根部脚本。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: 'API deploy 脚本本身也不能继续用部署工作区根部', reason: '团队共享踩坑必须记录 workspace 根部 deploy 脚本会掩盖发布包布局问题。', }, { file: 'docs/project-memory/shared-memory/pitfalls.md', includes: '备份脚本、健康巡检脚本和 env 示例目录同样不能从部署工作区兜底', reason: '团队共享踩坑必须记录备份/巡检脚本也不能使用 workspace fallback。', }, { file: 'deploy/nginx/README.md', includes: 'Pingora 影子网关已通过', reason: 'Nginx 压缩文档必须说明 Pingora gzip parity 口径。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'scripts/ops/production-health-patrol.mjs', reason: 'API Build 归档必须包含健康巡检脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/ops/pingora-current-release-audit.mjs', reason: 'API Build 归档必须包含 Pingora current release 自审脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/ops/pingora-cutover-status-snapshot.mjs', reason: 'API Build 归档必须包含 Pingora 切换状态快照脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/ops/pingora-cutover-evidence-bundle.mjs', reason: 'API Build 归档必须包含 Pingora 切换证据包脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/ops/pingora-cutover-command-evidence.mjs', reason: 'API Build 归档必须包含 Pingora 切换命令证据脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/ops/pingora-cutover-evidence-verify.mjs', reason: 'API Build 归档必须包含 Pingora 切换证据验真脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/ops/pingora-cutover-evidence-audit.mjs', reason: 'API Build 归档必须包含 Pingora 切换证据根目录审计脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/check-production-health-patrol-env.mjs', reason: 'API Build 归档必须包含健康巡检 env 复核脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/check-pingora-release-readiness.mjs', reason: 'API Build 归档必须包含 Pingora release readiness 聚合门禁脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/check-pingora-canary-live.mjs', reason: 'API Build 归档必须包含 Pingora canary live smoke 脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/check-pingora-canary-access-log-parity.mjs', reason: 'API Build 归档必须包含 Pingora canary access log 对账脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/deploy/production-api-deploy.sh', reason: 'API Build 归档必须包含 build 产物内的 deploy 脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/deploy/maintenance-on.sh', reason: 'API Build 归档必须包含 build 产物内的维护开启脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/deploy/maintenance-off.sh', reason: 'API Build 归档必须包含 build 产物内的维护关闭脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/deploy/pingora-health-patrol-env-switch.mjs', reason: 'API Build 归档必须包含 Pingora health patrol env 切换脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/deploy/pingora-gateway-env-shadow-switch.mjs', reason: 'API Build 归档必须包含 Pingora gateway env shadow 切换脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/deploy/pingora-tls-cert-sync.mjs', reason: 'API Build 归档必须包含 Pingora TLS 证书同步脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/deploy/pingora-realpath-canary-enable.sh', reason: 'API Build 归档必须包含 Pingora realpath canary 启用脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/scripts/deploy/pingora-realpath-canary-disable.sh', reason: 'API Build 归档必须包含 Pingora realpath canary 关闭脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/deploy/env/**', reason: 'API Build 归档必须包含 env 示例目录。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'build/${env.EFFECTIVE_BUILD_VERSION}/deploy/nginx/**', reason: 'API Build 归档必须包含 Nginx/Pingora canary snippet。', }, { file: 'jenkins/Jenkinsfile.production-api-build', excludes: ',scripts/deploy/production-api-deploy.sh', reason: 'API Build 不应再归档工作区根部 deploy 脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'INCLUDE_PINGORA_GATEWAY', reason: 'API Build 必须保留 Pingora 影子网关可选构建参数。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: 'command -v cmake', reason: 'API Build 勾选 Pingora 时必须前置检查 cmake。', }, { file: 'jenkins/Jenkinsfile.production-api-build', includes: '构建 Pingora 影子网关缺少 C++ 编译器', reason: 'API Build 勾选 Pingora 时必须前置检查 C++ 编译器。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'scripts/ops/production-health-patrol.mjs', reason: 'API Deploy 复制上游产物时必须包含健康巡检脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/ops/pingora-current-release-audit.mjs', reason: 'API Deploy 复制上游产物时必须包含 Pingora current release 自审脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/ops/pingora-cutover-status-snapshot.mjs', reason: 'API Deploy 复制上游产物时必须包含 Pingora 切换状态快照脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/ops/pingora-cutover-evidence-bundle.mjs', reason: 'API Deploy 复制上游产物时必须包含 Pingora 切换证据包脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/ops/pingora-cutover-command-evidence.mjs', reason: 'API Deploy 复制上游产物时必须包含 Pingora 切换命令证据脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/ops/pingora-cutover-evidence-verify.mjs', reason: 'API Deploy 复制上游产物时必须包含 Pingora 切换证据验真脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/ops/pingora-cutover-evidence-audit.mjs', reason: 'API Deploy 复制上游产物时必须包含 Pingora 切换证据根目录审计脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/check-production-health-patrol-env.mjs', reason: 'API Deploy 复制上游产物时必须包含健康巡检 env 复核脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/check-pingora-release-readiness.mjs', reason: 'API Deploy 复制上游产物时必须包含 Pingora release readiness 聚合门禁脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/check-pingora-canary-live.mjs', reason: 'API Deploy 复制上游产物时必须包含 Pingora canary live smoke 脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/check-pingora-canary-access-log-parity.mjs', reason: 'API Deploy 复制上游产物时必须包含 Pingora canary access log 对账脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/deploy/pingora-realpath-canary-enable.sh', reason: 'API Deploy 复制上游产物时必须包含 Pingora realpath canary 启用脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/deploy/pingora-realpath-canary-disable.sh', reason: 'API Deploy 复制上游产物时必须包含 Pingora realpath canary 关闭脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/deploy/production-api-deploy.sh', reason: 'API Deploy 必须复制并执行 build 产物内的 deploy 脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: '"build/${BUILD_VERSION}/scripts/deploy/production-api-deploy.sh"', reason: 'API Deploy 执行入口必须是 build 产物内的 deploy 脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/deploy/maintenance-on.sh', reason: 'API Deploy 必须复制 build 产物内的维护开启脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/deploy/pingora-health-patrol-env-switch.mjs', reason: 'API Deploy 必须复制 build 产物内的 Pingora health patrol env 切换脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/deploy/pingora-gateway-env-shadow-switch.mjs', reason: 'API Deploy 必须复制 build 产物内的 Pingora gateway env shadow 切换脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/deploy/pingora-tls-cert-sync.mjs', reason: 'API Deploy 必须复制 build 产物内的 Pingora TLS 证书同步脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/scripts/deploy/maintenance-off.sh', reason: 'API Deploy 必须复制 build 产物内的维护关闭脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/deploy/env/**', reason: 'API Deploy 必须从上游 build 产物复制 env 示例目录。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'build/${params.BUILD_VERSION}/deploy/nginx/**', reason: 'API Deploy 必须从上游 build 产物复制 Nginx/Pingora canary snippet。', }, { file: 'scripts/deploy/production-api-deploy.sh', includes: 'NGINX_DEPLOY_DIR_SOURCE', reason: 'API Deploy 必须把发布产物内 deploy/nginx 复制到 current release。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', excludes: ',scripts/deploy/production-api-deploy.sh', reason: 'API Deploy 不应再复制工作区根部 deploy 脚本。', }, { file: 'jenkins/Jenkinsfile.production-api-deploy', includes: 'pingora-gateway.sha256', reason: 'API Deploy 复制上游产物时必须保留 Pingora 影子网关可选 checksum 产物。', }, ]; const nodeEnvFileCommandFiles = [ 'package.json', 'deploy/systemd/genarrative-database-backup.service', 'deploy/systemd/genarrative-database-backup-files-history.conf', 'scripts/deploy/production-stdb-publish.sh', 'scripts/deploy/pingora-direct-enable.sh', 'scripts/deploy/pingora-direct-rollback.sh', ]; const jenkinsSourceCheckoutFiles = [ 'jenkins/Jenkinsfile.production-api-build', 'jenkins/Jenkinsfile.production-web-build', 'jenkins/Jenkinsfile.production-stdb-module-build', 'jenkins/Jenkinsfile.production-full-build-and-deploy', 'jenkins/Jenkinsfile.production-database-export', 'jenkins/Jenkinsfile.production-database-import', 'jenkins/Jenkinsfile.production-server-provision', ]; const jenkinsLoopbackGitRemote = "GIT_REMOTE_URL = 'ssh://git@127.0.0.1:2222/GenarrativeAI/Genarrative.git'"; const databaseTargetSourceStashes = [ { file: 'jenkins/Jenkinsfile.production-database-export', targetStage: "stage('Export Database')", stashName: 'database-export-source', }, { file: 'jenkins/Jenkinsfile.production-database-import', targetStage: "stage('Import Database')", stashName: 'database-import-source', }, ]; let failed = false; for (const check of checks) { const content = readFileSync(check.file, 'utf8'); if (check.includes && !content.includes(check.includes)) { failed = true; console.error( `[check:production-ops] ${check.file} 缺少 ${check.includes}。${check.reason}`, ); } if (check.excludes && content.includes(check.excludes)) { failed = true; console.error( `[check:production-ops] ${check.file} 不应包含 ${check.excludes}。${check.reason}`, ); } } for (const file of jenkinsSourceCheckoutFiles) { const content = readFileSync(file, 'utf8'); if (!content.includes(jenkinsLoopbackGitRemote)) { failed = true; console.error( `[check:production-ops] ${file} 的 Git checkout 必须固定使用本机 127.0.0.1:2222。`, ); } if ( !content.includes( "GIT_REMOTE_CREDENTIAL_ID = 'genarrative-local-gitea-ssh'", ) ) { failed = true; console.error( `[check:production-ops] ${file} 必须继续显式使用 Jenkins Gitea SSH 凭据。`, ); } if ( content.includes('192.168.35.82') || content.includes('git.genarrative.world') || content.includes('genarrative-station/git') ) { failed = true; console.error( `[check:production-ops] ${file} 不得保留局域网 IP、HTTP 内网别名或公网 Git 地址。`, ); } } for (const { file, targetStage, stashName } of databaseTargetSourceStashes) { const content = readFileSync(file, 'utf8'); const targetStageOffset = content.indexOf(targetStage); const prepareStageContent = targetStageOffset >= 0 ? content.slice(0, targetStageOffset) : ''; const targetStageContent = targetStageOffset >= 0 ? content.slice(targetStageOffset) : ''; if ( !prepareStageContent.includes("label 'linux && genarrative-build'") || !prepareStageContent.includes("$class: 'GitSCM'") ) { failed = true; console.error( `[check:production-ops] ${file} 必须只在 Jenkins Built-In Node 的 Prepare 阶段 checkout Git。`, ); } if ( !content.includes(`stash name: '${stashName}'`) || !targetStageContent.includes(`unstash '${stashName}'`) ) { failed = true; console.error( `[check:production-ops] ${file} 必须由本机 build 节点 stash 源码脚本,再交给数据库目标阶段。`, ); } if ( targetStageContent.includes("$class: 'GitSCM'") || targetStageContent.includes('sshUserPrivateKey(') ) { failed = true; console.error( `[check:production-ops] ${file} 的数据库目标阶段不得再次 checkout Git 或挂载 Git SSH 凭据。`, ); } } const fullPipelineContent = readFileSync( 'jenkins/Jenkinsfile.production-full-build-and-deploy', 'utf8', ); const forcedBuildOnlyCalls = fullPipelineContent.match( /booleanParam\(name: 'PUBLISH_AFTER_BUILD', value: false\)/gu, ); if ((forcedBuildOnlyCalls?.length ?? 0) !== 3) { failed = true; console.error( '[check:production-ops] Full Build 必须向 Web、API、Stdb 三个 Build Job 显式传 PUBLISH_AFTER_BUILD=false。', ); } const fullPipelineMaintenanceHoldCalls = fullPipelineContent.match( /booleanParam\(name: 'KEEP_MAINTENANCE_MODE', value: true\)/gu, ); if ((fullPipelineMaintenanceHoldCalls?.length ?? 0) !== 2) { failed = true; console.error( '[check:production-ops] Full Build 必须让 Stdb Publish 与 API Deploy 两个下游阶段都保持维护模式。', ); } const exitMaintenanceStageOffset = fullPipelineContent.indexOf( "stage('Exit Maintenance')", ); const fullPipelinePostOffset = fullPipelineContent.indexOf( '\n post {', exitMaintenanceStageOffset, ); const exitMaintenanceStageContent = exitMaintenanceStageOffset >= 0 && fullPipelinePostOffset > exitMaintenanceStageOffset ? fullPipelineContent.slice(exitMaintenanceStageOffset, fullPipelinePostOffset) : ''; if ( !exitMaintenanceStageContent.includes('agent none') || !exitMaintenanceStageContent.includes('node(deployLabel)') || exitMaintenanceStageContent.includes("$class: 'GitSCM'") || exitMaintenanceStageContent.includes('checkout scm') || exitMaintenanceStageContent.includes('sshUserPrivateKey(') ) { failed = true; console.error( '[check:production-ops] Full Build 的 Exit Maintenance 必须使用 agent none + 显式 node 执行 current release 脚本,不得在目标机 checkout Git 或挂载 Git SSH 凭据。', ); } for (const file of nodeEnvFileCommandFiles) { const content = readFileSync(file, 'utf8'); const commandText = content.replace(/\\\r?\n\s*/g, ' '); const unsafeCommands = commandText.match( /\bnode\b(?!\s+--)(?=[^;&|\n]*\.mjs)(?=[^;&|\n]*--env-file)[^;&|\n]*/g, ); if (!unsafeCommands) { continue; } failed = true; for (const command of unsafeCommands) { console.error( `[check:production-ops] ${file} 中的 Node 命令必须用 node -- 分隔业务 --env-file 参数: ${command.trim()}`, ); } } if (failed) { process.exit(1); } console.log('[check:production-ops] OK');