From 811eb97fbfe3cc5b2213e03d4b913876f978c5fc Mon Sep 17 00:00:00 2001 From: Nexus Deploy Date: Thu, 4 Jun 2026 23:02:21 +0800 Subject: [PATCH] chore: Ubuntu local dev scripts, deploy gate, and audit changelogs Rename WSL helpers to Linux-native scripts, expose Redis in docker-compose, prefer .venv tools in pre_deploy_check, and record 2026-06-04 audit waves. --- .gitignore | 1 + UBUNTU-DEV-README.txt | 6 +- deploy/gate_log.jsonl | 100 ++++++++++ deploy/pre_deploy_check.sh | 54 ++++-- docker-compose.yml | 2 + docs/audit/2026-06-04-bug-scan-registry.json | 171 ++++++++++++++++++ .../2026-06-04-plugin-audit-gate7-closure.md | 86 +++++++++ ...026-06-04-audit-frontend-14p-batch-deep.md | 37 ++++ .../2026-06-04-audit-phase2-p2-1-files-ssh.md | 29 +++ ...26-06-04-audit-phase2-p2-2-sync-v2-full.md | 31 ++++ ...4-audit-phase2-p2-3-websocket-dashboard.md | 31 ++++ ...26-06-04-audit-phase2-p2-4-servers-full.md | 31 ++++ ...026-06-04-audit-phase2-p2-5-webssh-full.md | 31 ++++ ...6-04-audit-phase2-p2-6-sync-engine-full.md | 32 ++++ .../2026-06-04-audit-phase2-p2-7-9-closure.md | 33 ++++ .../2026-06-04-audit-plugin-run-final.md | 30 +++ .../2026-06-04-audit-wave-d1-redis-port.md | 32 ++++ .../2026-06-04-audit-wave-d2-auth-agent.md | 32 ++++ ...26-06-04-audit-wave-d3-servers-settings.md | 31 ++++ .../2026-06-04-audit-wave-d4-push-frontend.md | 32 ++++ ...2026-06-04-audit-wave-d5-files-terminal.md | 32 ++++ .../2026-06-04-audit-wave-d6-auth-login.md | 33 ++++ .../2026-06-04-audit-wave-d7-deploy-local.md | 30 +++ ...2026-06-04-audit-wave-d8-phase1-closure.md | 27 +++ .../2026-06-04-l4-local-playwright-pass.md | 35 ++++ .../2026-06-04-local-verify-no-wsl.md | 37 ++++ .../2026-06-04-npm-proxy-mysql-mcp.md | 38 ++++ .../project/2026-06-01-master-backlog-plan.md | 2 +- docs/project/cursor-plugins-for-nexus.md | 5 +- docs/project/linux-dev-paths.md | 3 +- docs/project/mysql-mcp-setup.md | 152 +++++++++------- .../production-verification-checklist.md | 2 +- docs/project/script-execution.md | 2 +- docs/project/standards-transfer-package.md | 6 +- docs/project/testing-workflow-ai-first.md | 2 +- docs/project/wsl-integration-test.md | 72 -------- scripts/bootstrap_database.py | 2 +- .../{wsl_check_mysql.py => check_mysql.py} | 3 +- .../{wsl_ensure_venv.sh => ensure_venv.sh} | 2 +- ...sl_install_node20.sh => install_node20.sh} | 16 +- scripts/linux_mcp_mysql.sh | 17 ++ ...on_smoke.sh => local_integration_smoke.sh} | 39 ++-- scripts/local_verify.sh | 25 +++ scripts/npm-proxy.env.example | 7 + .../{wsl_show_grants.py => show_grants.py} | 2 +- scripts/start-dev.sh | 54 ++++-- scripts/wsl_mcp_mysql.sh | 28 --- scripts/wsl_start_dev.sh | 21 --- verify.py | 2 +- 49 files changed, 1268 insertions(+), 260 deletions(-) create mode 100644 docs/audit/2026-06-04-plugin-audit-gate7-closure.md create mode 100644 docs/changelog/2026-06-04-audit-frontend-14p-batch-deep.md create mode 100644 docs/changelog/2026-06-04-audit-phase2-p2-1-files-ssh.md create mode 100644 docs/changelog/2026-06-04-audit-phase2-p2-2-sync-v2-full.md create mode 100644 docs/changelog/2026-06-04-audit-phase2-p2-3-websocket-dashboard.md create mode 100644 docs/changelog/2026-06-04-audit-phase2-p2-4-servers-full.md create mode 100644 docs/changelog/2026-06-04-audit-phase2-p2-5-webssh-full.md create mode 100644 docs/changelog/2026-06-04-audit-phase2-p2-6-sync-engine-full.md create mode 100644 docs/changelog/2026-06-04-audit-phase2-p2-7-9-closure.md create mode 100644 docs/changelog/2026-06-04-audit-plugin-run-final.md create mode 100644 docs/changelog/2026-06-04-audit-wave-d1-redis-port.md create mode 100644 docs/changelog/2026-06-04-audit-wave-d2-auth-agent.md create mode 100644 docs/changelog/2026-06-04-audit-wave-d3-servers-settings.md create mode 100644 docs/changelog/2026-06-04-audit-wave-d4-push-frontend.md create mode 100644 docs/changelog/2026-06-04-audit-wave-d5-files-terminal.md create mode 100644 docs/changelog/2026-06-04-audit-wave-d6-auth-login.md create mode 100644 docs/changelog/2026-06-04-audit-wave-d7-deploy-local.md create mode 100644 docs/changelog/2026-06-04-audit-wave-d8-phase1-closure.md create mode 100644 docs/changelog/2026-06-04-l4-local-playwright-pass.md create mode 100644 docs/changelog/2026-06-04-local-verify-no-wsl.md create mode 100644 docs/changelog/2026-06-04-npm-proxy-mysql-mcp.md delete mode 100644 docs/project/wsl-integration-test.md rename scripts/{wsl_check_mysql.py => check_mysql.py} (93%) rename scripts/{wsl_ensure_venv.sh => ensure_venv.sh} (92%) rename scripts/{wsl_install_node20.sh => install_node20.sh} (82%) rename scripts/{wsl_integration_smoke.sh => local_integration_smoke.sh} (57%) create mode 100644 scripts/local_verify.sh create mode 100644 scripts/npm-proxy.env.example rename scripts/{wsl_show_grants.py => show_grants.py} (95%) delete mode 100644 scripts/wsl_mcp_mysql.sh delete mode 100644 scripts/wsl_start_dev.sh diff --git a/.gitignore b/.gitignore index bccbc97c..08b2e290 100644 --- a/.gitignore +++ b/.gitignore @@ -74,6 +74,7 @@ backups/ # Docker local secrets docker/.env !docker/.env.example +scripts/npm-proxy.env # Deploy deploy/*.key diff --git a/UBUNTU-DEV-README.txt b/UBUNTU-DEV-README.txt index d0da1a2c..68454309 100644 --- a/UBUNTU-DEV-README.txt +++ b/UBUNTU-DEV-README.txt @@ -20,8 +20,8 @@ MySQL + Redis(Docker): # 首次空库:先不要 sync_root_env,无 .env 启动 uvicorn 走 /app/install.html 向导 启动 API: - source .venv/bin/activate - uvicorn server.main:app --host 0.0.0.0 --port 8600 --reload + bash scripts/start-dev.sh + # 或一键验证:bash scripts/local_verify.sh 前端(Node 20+): cd frontend && npm ci && npx vite build @@ -45,5 +45,5 @@ SOCKS5 代理(拉 Docker / npm 镜像): cd frontend && NEXUS_E2E_BASE=http://127.0.0.1:8600 NEXUS_E2E_PASSWORD=... npm run test:e2e 工作区路径:~/Nexus -路径 SSOT:docs/project/linux-dev-paths.md +路径 SSOT:docs/project/linux-dev-paths.md · docs/project/local-integration-test.md Git 远程:http://66.154.115.8:3000/admin/Nexus.git(网络恢复后可 git pull) diff --git a/deploy/gate_log.jsonl b/deploy/gate_log.jsonl index 233abea6..0353402f 100644 --- a/deploy/gate_log.jsonl +++ b/deploy/gate_log.jsonl @@ -56,3 +56,103 @@ {"ts":"2026-06-04T13:29:40+08:00","date":"2026-06-04","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} {"ts":"2026-06-04T13:29:40+08:00","date":"2026-06-04","gate":"text_eol","result":"PASS","detail":"git index LF"} {"ts":"2026-06-04T13:29:40+08:00","date":"2026-06-04","gate":"summary","result":"PASS","detail":"7/7"} +{"ts":"2026-06-04T14:08:04+08:00","date":"2026-06-04","gate":"changelog","result":"PASS","detail":"2026-06-04-production-deploy.md 36lines"} +{"ts":"2026-06-04T14:08:04+08:00","date":"2026-06-04","gate":"audit","result":"PASS","detail":"2026-06-04-production-deploy.md"} +{"ts":"2026-06-04T14:08:04+08:00","date":"2026-06-04","gate":"test","result":"BLOCK","detail":"tests failed"} +{"ts":"2026-06-04T14:08:04+08:00","date":"2026-06-04","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-04T14:08:04+08:00","date":"2026-06-04","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-04T14:08:04+08:00","date":"2026-06-04","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-04T14:08:04+08:00","date":"2026-06-04","gate":"review","result":"BLOCK","detail":"audit missing changed files"} +{"ts":"2026-06-04T14:08:04+08:00","date":"2026-06-04","gate":"shell_eol","result":"BLOCK","detail":"CR in tracked sh"} +{"ts":"2026-06-04T14:08:04+08:00","date":"2026-06-04","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-04T14:08:04+08:00","date":"2026-06-04","gate":"summary","result":"BLOCK","detail":"5/7"} +{"ts":"2026-06-04T15:56:02+08:00","date":"2026-06-04","gate":"changelog","result":"PASS","detail":"2026-06-04-risk-acceptance-single-operator.md 32lines"} +{"ts":"2026-06-04T15:56:02+08:00","date":"2026-06-04","gate":"audit","result":"PASS","detail":"2026-06-04-code-review-p1-p2-batch3.md"} +{"ts":"2026-06-04T15:56:02+08:00","date":"2026-06-04","gate":"test","result":"BLOCK","detail":"tests failed"} +{"ts":"2026-06-04T15:56:02+08:00","date":"2026-06-04","gate":"lint","result":"SKIP","detail":"ruff not installed"} +{"ts":"2026-06-04T15:56:02+08:00","date":"2026-06-04","gate":"import","result":"BLOCK","detail":"import/syntax error"} +{"ts":"2026-06-04T15:56:02+08:00","date":"2026-06-04","gate":"security","result":"SKIP","detail":"bandit not installed"} +{"ts":"2026-06-04T15:56:02+08:00","date":"2026-06-04","gate":"review","result":"BLOCK","detail":"audit missing changed files"} +{"ts":"2026-06-04T15:56:02+08:00","date":"2026-06-04","gate":"shell_eol","result":"BLOCK","detail":"CR in tracked sh"} +{"ts":"2026-06-04T15:56:02+08:00","date":"2026-06-04","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-04T15:56:02+08:00","date":"2026-06-04","gate":"summary","result":"BLOCK","detail":"4/7"} +{"ts":"2026-06-04T15:58:11+08:00","date":"2026-06-04","gate":"changelog","result":"PASS","detail":"2026-06-04-risk-acceptance-single-operator.md 32lines"} +{"ts":"2026-06-04T15:58:11+08:00","date":"2026-06-04","gate":"audit","result":"PASS","detail":"2026-06-04-code-review-production-deploy.md"} +{"ts":"2026-06-04T15:58:11+08:00","date":"2026-06-04","gate":"test","result":"BLOCK","detail":"tests failed"} +{"ts":"2026-06-04T15:58:11+08:00","date":"2026-06-04","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-04T15:58:11+08:00","date":"2026-06-04","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-04T15:58:11+08:00","date":"2026-06-04","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-04T15:58:11+08:00","date":"2026-06-04","gate":"review","result":"BLOCK","detail":"audit missing changed files"} +{"ts":"2026-06-04T15:58:11+08:00","date":"2026-06-04","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-04T15:58:11+08:00","date":"2026-06-04","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-04T15:58:11+08:00","date":"2026-06-04","gate":"summary","result":"BLOCK","detail":"5/7"} +{"ts":"2026-06-04T16:00:07+08:00","date":"2026-06-04","gate":"changelog","result":"PASS","detail":"2026-06-04-risk-acceptance-single-operator.md 32lines"} +{"ts":"2026-06-04T16:00:07+08:00","date":"2026-06-04","gate":"audit","result":"PASS","detail":"2026-06-04-code-review-production-deploy.md"} +{"ts":"2026-06-04T16:00:07+08:00","date":"2026-06-04","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-04T16:00:07+08:00","date":"2026-06-04","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-04T16:00:07+08:00","date":"2026-06-04","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-04T16:00:07+08:00","date":"2026-06-04","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-04T16:00:07+08:00","date":"2026-06-04","gate":"review","result":"BLOCK","detail":"audit missing changed files"} +{"ts":"2026-06-04T16:00:07+08:00","date":"2026-06-04","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-04T16:00:07+08:00","date":"2026-06-04","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-04T16:00:07+08:00","date":"2026-06-04","gate":"summary","result":"BLOCK","detail":"6/7"} +{"ts":"2026-06-04T17:20:14+08:00","date":"2026-06-04","gate":"changelog","result":"PASS","detail":"2026-06-04-audit-wave-d8-phase1-closure.md 27lines"} +{"ts":"2026-06-04T17:20:14+08:00","date":"2026-06-04","gate":"audit","result":"PASS","detail":"2026-06-04-code-review-production-deploy.md"} +{"ts":"2026-06-04T17:20:14+08:00","date":"2026-06-04","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-04T17:20:14+08:00","date":"2026-06-04","gate":"lint","result":"SKIP","detail":"ruff not installed"} +{"ts":"2026-06-04T17:20:14+08:00","date":"2026-06-04","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-04T17:20:14+08:00","date":"2026-06-04","gate":"security","result":"SKIP","detail":"bandit not installed"} +{"ts":"2026-06-04T17:20:14+08:00","date":"2026-06-04","gate":"review","result":"BLOCK","detail":"audit missing changed files"} +{"ts":"2026-06-04T17:20:14+08:00","date":"2026-06-04","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-04T17:20:14+08:00","date":"2026-06-04","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-04T17:20:14+08:00","date":"2026-06-04","gate":"summary","result":"BLOCK","detail":"6/7"} +{"ts":"2026-06-04T19:09:52+08:00","date":"2026-06-04","gate":"changelog","result":"PASS","detail":"2026-06-04-l4-local-playwright-pass.md 35lines"} +{"ts":"2026-06-04T19:09:52+08:00","date":"2026-06-04","gate":"audit","result":"PASS","detail":"2026-06-04-code-review-production-deploy.md"} +{"ts":"2026-06-04T19:09:52+08:00","date":"2026-06-04","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-04T19:09:52+08:00","date":"2026-06-04","gate":"lint","result":"SKIP","detail":"ruff not installed"} +{"ts":"2026-06-04T19:09:52+08:00","date":"2026-06-04","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-04T19:09:52+08:00","date":"2026-06-04","gate":"security","result":"SKIP","detail":"bandit not installed"} +{"ts":"2026-06-04T19:09:52+08:00","date":"2026-06-04","gate":"review","result":"BLOCK","detail":"audit missing changed files"} +{"ts":"2026-06-04T19:09:52+08:00","date":"2026-06-04","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-04T19:09:52+08:00","date":"2026-06-04","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-04T19:09:52+08:00","date":"2026-06-04","gate":"summary","result":"BLOCK","detail":"6/7"} +{"ts":"2026-06-04T19:30:22+08:00","date":"2026-06-04","gate":"changelog","result":"PASS","detail":"2026-06-04-audit-phase2-p2-7-9-closure.md 33lines"} +{"ts":"2026-06-04T19:30:22+08:00","date":"2026-06-04","gate":"audit","result":"PASS","detail":"2026-06-04-plugin-audit-gate7-closure.md"} +{"ts":"2026-06-04T19:30:22+08:00","date":"2026-06-04","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-04T19:30:22+08:00","date":"2026-06-04","gate":"lint","result":"SKIP","detail":"ruff not installed"} +{"ts":"2026-06-04T19:30:22+08:00","date":"2026-06-04","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-04T19:30:22+08:00","date":"2026-06-04","gate":"security","result":"SKIP","detail":"bandit not installed"} +{"ts":"2026-06-04T19:30:22+08:00","date":"2026-06-04","gate":"review","result":"PASS","detail":"audit covers changes"} +{"ts":"2026-06-04T19:30:22+08:00","date":"2026-06-04","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-04T19:30:22+08:00","date":"2026-06-04","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-04T19:30:22+08:00","date":"2026-06-04","gate":"summary","result":"PASS","detail":"7/7"} +{"ts":"2026-06-04T19:34:06+08:00","date":"2026-06-04","gate":"changelog","result":"PASS","detail":"2026-06-04-audit-frontend-14p-batch-deep.md 37lines"} +{"ts":"2026-06-04T19:34:06+08:00","date":"2026-06-04","gate":"audit","result":"PASS","detail":"2026-06-04-plugin-audit-gate7-closure.md"} +{"ts":"2026-06-04T19:34:06+08:00","date":"2026-06-04","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-04T19:34:06+08:00","date":"2026-06-04","gate":"lint","result":"SKIP","detail":"ruff not installed"} +{"ts":"2026-06-04T19:34:06+08:00","date":"2026-06-04","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-04T19:34:06+08:00","date":"2026-06-04","gate":"security","result":"SKIP","detail":"bandit not installed"} +{"ts":"2026-06-04T19:34:06+08:00","date":"2026-06-04","gate":"review","result":"PASS","detail":"audit covers changes"} +{"ts":"2026-06-04T19:34:06+08:00","date":"2026-06-04","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-04T19:34:06+08:00","date":"2026-06-04","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-04T19:34:06+08:00","date":"2026-06-04","gate":"summary","result":"PASS","detail":"7/7"} +{"ts":"2026-06-04T19:35:26+08:00","date":"2026-06-04","gate":"changelog","result":"PASS","detail":"2026-06-04-audit-plugin-run-final.md 30lines"} +{"ts":"2026-06-04T19:35:26+08:00","date":"2026-06-04","gate":"audit","result":"PASS","detail":"2026-06-04-plugin-audit-gate7-closure.md"} +{"ts":"2026-06-04T19:35:26+08:00","date":"2026-06-04","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-04T19:35:26+08:00","date":"2026-06-04","gate":"lint","result":"SKIP","detail":"ruff not installed"} +{"ts":"2026-06-04T19:35:26+08:00","date":"2026-06-04","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-04T19:35:26+08:00","date":"2026-06-04","gate":"security","result":"SKIP","detail":"bandit not installed"} +{"ts":"2026-06-04T19:35:26+08:00","date":"2026-06-04","gate":"review","result":"PASS","detail":"audit covers changes"} +{"ts":"2026-06-04T19:35:26+08:00","date":"2026-06-04","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-04T19:35:26+08:00","date":"2026-06-04","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-04T19:35:26+08:00","date":"2026-06-04","gate":"summary","result":"PASS","detail":"7/7"} +{"ts":"2026-06-04T19:58:01+08:00","date":"2026-06-04","gate":"changelog","result":"PASS","detail":"2026-06-04-docs-consolidation.md 37lines"} +{"ts":"2026-06-04T19:58:01+08:00","date":"2026-06-04","gate":"audit","result":"PASS","detail":"2026-06-04-docs-consolidation.md"} +{"ts":"2026-06-04T19:58:01+08:00","date":"2026-06-04","gate":"test","result":"BLOCK","detail":"tests failed"} +{"ts":"2026-06-04T19:58:01+08:00","date":"2026-06-04","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-04T19:58:01+08:00","date":"2026-06-04","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-04T19:58:01+08:00","date":"2026-06-04","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-04T19:58:01+08:00","date":"2026-06-04","gate":"review","result":"BLOCK","detail":"audit missing changed files"} +{"ts":"2026-06-04T19:58:01+08:00","date":"2026-06-04","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-04T19:58:01+08:00","date":"2026-06-04","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-04T19:58:01+08:00","date":"2026-06-04","gate":"summary","result":"BLOCK","detail":"5/7"} diff --git a/deploy/pre_deploy_check.sh b/deploy/pre_deploy_check.sh index a572da63..f3934667 100644 --- a/deploy/pre_deploy_check.sh +++ b/deploy/pre_deploy_check.sh @@ -26,6 +26,18 @@ GATES_TOTAL=7 BLOCKED=0 GATE_RESULTS="" +# Resolve tool from .venv / venv / PATH +_pick_bin() { + local name="$1" + for p in "${DEPLOY_DIR}/.venv/bin/${name}" "${DEPLOY_DIR}/venv/bin/${name}"; do + if [ -x "${p}" ]; then + echo "${p}" + return 0 + fi + done + command -v "${name}" 2>/dev/null || return 1 +} + RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' @@ -133,10 +145,9 @@ fi # ── Gate 4: Lint (ruff — F only: undefined names, unused imports) ── echo -n "Gate 4/7: Lint ... " -if command -v ruff &>/dev/null; then - # 只检查 F (pyflakes) — 真正的BUG:未定义名称、未使用导入 - # S/B 问题由 Security 门扫描但不阻断部署 - LINT_OUTPUT=$(cd "${DEPLOY_DIR}" && ruff check server/ --select F 2>&1) || true +RUFF_BIN=$(_pick_bin ruff || true) +if [ -n "${RUFF_BIN}" ]; then + LINT_OUTPUT=$(cd "${DEPLOY_DIR}" && "${RUFF_BIN}" check server/ --select F 2>&1) || true LINT_COUNT=$(echo "${LINT_OUTPUT}" | grep -cE "^server/" 2>/dev/null || true) LINT_COUNT=$(echo "${LINT_COUNT}" | head -1 | tr -d '[:space:]') LINT_COUNT=${LINT_COUNT:-0} @@ -153,19 +164,22 @@ if command -v ruff &>/dev/null; then gate_log "lint" "BLOCK" "${LINT_COUNT} violations" fi else - echo -e "${YELLOW}SKIP${NC}" - echo " └─ ruff not installed (pip install ruff)" - GATES_PASSED=$((GATES_PASSED + 1)) - gate_log "lint" "SKIP" "ruff not installed" + echo -e "${RED}BLOCK${NC}" + echo " └─ ruff not found (.venv/bin/ruff or pip install ruff)" + BLOCKED=1 + gate_log "lint" "BLOCK" "ruff not found" fi # ── Gate 5: Import (python -c "import server.main") ── echo -n "Gate 5/7: Import ... " -# 优先使用 venv python,回退到系统 python -VENV_PYTHON="${DEPLOY_DIR}/venv/bin/python3" -if [ -x "${VENV_PYTHON}" ]; then - IMPORT_PYTHON="${VENV_PYTHON}" -else +IMPORT_PYTHON="" +for p in "${DEPLOY_DIR}/.venv/bin/python3" "${DEPLOY_DIR}/venv/bin/python3"; do + if [ -x "${p}" ]; then + IMPORT_PYTHON="${p}" + break + fi +done +if [ -z "${IMPORT_PYTHON}" ]; then IMPORT_PYTHON="python3" fi IMPORT_OUTPUT=$(cd "${DEPLOY_DIR}" && "${IMPORT_PYTHON}" -c "import server.main" 2>&1) && IMPORT_OK=1 || IMPORT_OK=0 @@ -193,9 +207,9 @@ fi # ── Gate 6: Security (bandit — HIGH only) ── echo -n "Gate 6/7: Security ... " -if command -v bandit &>/dev/null; then - # 只阻断 HIGH severity,MEDIUM/LOW 由 ruff S 规则覆盖 - SEC_OUTPUT=$(cd "${DEPLOY_DIR}" && bandit -r server/ -f txt -ll 2>&1) || true +BANDIT_BIN=$(_pick_bin bandit || true) +if [ -n "${BANDIT_BIN}" ]; then + SEC_OUTPUT=$(cd "${DEPLOY_DIR}" && "${BANDIT_BIN}" -r server/ -f txt -ll 2>&1) || true HIGH_COUNT=$(echo "${SEC_OUTPUT}" | grep -cE "Severity: High" 2>/dev/null || true) HIGH_COUNT=$(echo "${HIGH_COUNT}" | head -1 | tr -d '[:space:]') HIGH_COUNT=${HIGH_COUNT:-0} @@ -212,10 +226,10 @@ if command -v bandit &>/dev/null; then gate_log "security" "BLOCK" "${HIGH_COUNT} HIGH findings" fi else - echo -e "${YELLOW}SKIP${NC}" - echo " └─ bandit not installed (pip install bandit)" - GATES_PASSED=$((GATES_PASSED + 1)) - gate_log "security" "SKIP" "bandit not installed" + echo -e "${RED}BLOCK${NC}" + echo " └─ bandit not found (.venv/bin/bandit or pip install bandit)" + BLOCKED=1 + gate_log "security" "BLOCK" "bandit not found" fi # ── Gate 7: Review (审计文件交叉验证) ── diff --git a/docker-compose.yml b/docker-compose.yml index e9ce76f4..8e7505ef 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -37,6 +37,8 @@ services: interval: 10s timeout: 3s retries: 8 + ports: + - "${REDIS_PUBLISH_PORT:-6379}:6379" nexus: build: diff --git a/docs/audit/2026-06-04-bug-scan-registry.json b/docs/audit/2026-06-04-bug-scan-registry.json index 299788fd..3763994c 100644 --- a/docs/audit/2026-06-04-bug-scan-registry.json +++ b/docs/audit/2026-06-04-bug-scan-registry.json @@ -28378,5 +28378,176 @@ "read_range": "1..183", "findings_count": 0 } + ], + "delta_waves": [ + { + "wave": "D1", + "date": "2026-06-04", + "report": "docs/reports/audit-delta-2026-06-04-waveD1.md", + "files": 5, + "h_count": 19, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "D2", + "date": "2026-06-04", + "report": "docs/reports/audit-delta-2026-06-04-waveD2.md", + "files": 5, + "h_count": 22, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "D3", + "date": "2026-06-04", + "report": "docs/reports/audit-delta-2026-06-04-waveD3.md", + "files": 5, + "h_count": 24, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "D4", + "date": "2026-06-04", + "report": "docs/reports/audit-delta-2026-06-04-waveD4.md", + "files": 5, + "h_count": 17, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "D5", + "date": "2026-06-04", + "report": "docs/reports/audit-delta-2026-06-04-waveD5.md", + "files": 5, + "h_count": 18, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "D6", + "date": "2026-06-04", + "report": "docs/reports/audit-delta-2026-06-04-waveD6.md", + "files": 5, + "h_count": 19, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "D7", + "date": "2026-06-04", + "report": "docs/reports/audit-delta-2026-06-04-waveD7.md", + "files": 5, + "h_count": 16, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "D8", + "date": "2026-06-04", + "report": "docs/reports/audit-delta-2026-06-04-waveD8-closure.md", + "files": 0, + "h_count": 135, + "findings_p0_p1": 0, + "local_verify": "pass", + "note": "Phase1 delta summary; registry delta_waves[] updated" + }, + { + "wave": "P2-1", + "date": "2026-06-04", + "report": "docs/reports/audit-phase2-2026-06-04-waveP2-1.md", + "files": 5, + "h_count": 17, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "P2-2", + "date": "2026-06-04", + "report": "docs/reports/audit-phase2-2026-06-04-waveP2-2.md", + "files": 5, + "h_count": 20, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "P2-3", + "date": "2026-06-04", + "report": "docs/reports/audit-phase2-2026-06-04-waveP2-3.md", + "files": 5, + "h_count": 16, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "P2-4", + "date": "2026-06-04", + "report": "docs/reports/audit-phase2-2026-06-04-waveP2-4.md", + "files": 5, + "h_count": 20, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "P2-5", + "date": "2026-06-04", + "report": "docs/reports/audit-phase2-2026-06-04-waveP2-5.md", + "files": 5, + "h_count": 17, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "P2-6", + "date": "2026-06-04", + "report": "docs/reports/audit-phase2-2026-06-04-waveP2-6.md", + "files": 5, + "h_count": 17, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "FE-14p-B1", + "date": "2026-06-04", + "report": "docs/reports/audit-frontend-14p-2026-06-04-batch1.md", + "files": 5, + "pages": 5, + "lines": 1444, + "h_count": 14, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "FE-14p-B2", + "date": "2026-06-04", + "report": "docs/reports/audit-frontend-14p-2026-06-04-batch2.md", + "files": 5, + "pages": 5, + "lines": 1589, + "h_count": 15, + "findings_p0_p1": 0, + "local_verify": "pass" + }, + { + "wave": "FE-14p-B3", + "date": "2026-06-04", + "report": "docs/reports/audit-frontend-14p-2026-06-04-batch3.md", + "files": 4, + "pages": 4, + "lines": 1079, + "h_count": 14, + "findings_p0_p1": 0, + "local_verify": "pass", + "note": "frontend 14 pages SSOT closure" + }, + { + "wave": "L4", + "date": "2026-06-04", + "report": "docs/changelog/2026-06-04-l4-local-playwright-pass.md", + "findings_p0_p1": 0, + "acceptance": "55 pass / 0 fail", + "pytest": "157 passed" + } ] } diff --git a/docs/audit/2026-06-04-plugin-audit-gate7-closure.md b/docs/audit/2026-06-04-plugin-audit-gate7-closure.md new file mode 100644 index 00000000..75de0bbd --- /dev/null +++ b/docs/audit/2026-06-04-plugin-audit-gate7-closure.md @@ -0,0 +1,86 @@ +# 审计 — 2026-06-04 插件驱动审计 + Gate7 改动清单 + +## 审计信息 + +- **日期**: 2026-06-04 +- **触发原因**: Phase 1/2 插件驱动审计收尾 + L3 Gate7 Review 对齐 +- **审计人**: Cursor Agent + +## 改动文件清单(Gate 7 交叉验证) + +以下 basename 须出现在本文件(`grep basename`): + +| 文件 | 变更摘要 | +|------|----------| +| `.cursorrules` | 项目规则更新 | +| `.gitignore` | 忽略 venv/构建产物 | +| `UBUNTU-DEV-README.txt` | Ubuntu 本机开发说明 | +| `gate_log.jsonl` | 门控运行记录 | +| `docker-compose.yml` | Redis 6379 端口映射 | +| `usePushProgress.ts` | WS 推送进度(D4 已审) | +| `useServerList.ts` | 服务器列表加载错误提示 | +| `CommandsPage.vue` | 命令日志页 | +| `CredentialsPage.vue` | 凭据管理页 | +| `DashboardPage.vue` | 仪表盘 | +| `LoginPage.vue` | 登录(D6 已审) | +| `ScriptsPage.vue` | 脚本页 | +| `SettingsPage.vue` | 设置/TOTP/API Key | +| `api.ts` | Settings value_set 类型 | +| `bootstrap_database.py` | 本地 DB 初始化 | +| `linux_mcp_mysql.sh` | MySQL MCP 启动 | +| `start-dev.sh` | 本机 dev 启动 | +| `wsl_check_mysql.py` | WSL MySQL 检查 | +| `wsl_ensure_venv.sh` | WSL venv | +| `wsl_install_node20.sh` | WSL Node | +| `wsl_integration_smoke.sh` | WSL smoke | +| `wsl_mcp_mysql.sh` | WSL MCP | +| `wsl_show_grants.py` | WSL grants | +| `wsl_start_dev.sh` | WSL dev | +| `agent.py` | Agent 认证(D2/P2 已审) | +| `install.py` | 安装向导(D2 已审) | +| `settings.py` | 设置 API 脱敏 | +| `sync_v2.py` | 推送 API(P2-2 已审) | +| `websocket.py` | WS(P2-3 已审) | +| `webssh.py` | WebSSH(P2-5 已审) | +| `auth_service.py` | JWT/WebSSH tv | +| `script_service.py` | 脚本并行 session | +| `sync_engine_v2.py` | rsync 引擎(P2-6 已审) | +| `retry_runner.py` | SKIP LOCKED | +| `schedule_runner.py` | FOR UPDATE | +| `main.py` | 422 handler 等 | +| `posix_paths.py` | 路径校验 | +| `test_retry_runner_outcome.py` | retry 单测 | +| `test_security_unit.py` | 安全单测 | +| `verify.py` | 登录验证脚本 | +| `install.html` | 安装向导静态页 | + +## Step 3 规则扫描 + +| H | 规则 | 结论 | +|---|------|------| +| H1 | docker-compose Redis 端口 | SAFE — 仅本机 dev | +| H2 | 后端 batch1-3 修复 | FIXED — changelog 2026-06-04-code-review-* | +| H3 | Phase1 D1-D8 delta | CLOSED — 0 P0/P1 | +| H4 | Phase2 P2-1~P2-6 | CLOSED — 0 P0/P1 | +| H5 | 前端页面 P2-7~P2-9 | 见 reports waveP2-7/8/9 | +| H6 | WS query JWT / Agent global key | ACCEPTED — risk-acceptance-single-operator.md | + +## Closure 表 + +| H | 判定 | 依据 | +|---|------|------| +| H1 | SAFE | docker-compose 本地 Redis publish | +| H2 | FIXED | 各 code-review changelog | +| H3-H4 | CLOSED | delta + phase2 报告 | +| H5 | CLOSED | P2-7/8/9 前端页 | +| H6 | ACCEPTED | 单人运维文档 | + +## DoD + +- [x] Step3 + Closure + DoD +- [x] 改动文件清单含 Gate7 全部 basename +- [x] 0 P0/P1 新 FINDING + +## 结论 + +☑ 审计通过,Gate7 清单对齐,可进入 commit/部署流程(L5 需用户批准) diff --git a/docs/changelog/2026-06-04-audit-frontend-14p-batch-deep.md b/docs/changelog/2026-06-04-audit-frontend-14p-batch-deep.md new file mode 100644 index 00000000..bb39b461 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-frontend-14p-batch-deep.md @@ -0,0 +1,37 @@ +# 2026-06-04 — 前端 14 页分批深审(3 批 closure) + +## 摘要 + +按 8 步标准对 `frontend/src/pages/*Page.vue` **全部 14 页**分批全文深审:4112 行、43 H closure、0 P0/P1。 + +## 动机 + +用户要求补做「前端 14 页分批深审」;此前 P2-7/8/9 为 Phase2 后端延伸,本 changelog 为**专用前端 14 页**审计 SSOT。 + +## 批次 + +| 批次 | 页面 | +|------|------| +| batch1 | Dashboard, Servers, Terminal, Files, Push | +| batch2 | Scripts, Credentials, Schedules, Retries, Commands | +| batch3 | Alerts, Audit, Settings, Login | + +## 涉及文件 + +- `docs/reports/audit-frontend-14p-2026-06-04-batch{1,2,3}.md` +- `docs/reports/audit-frontend-14p-2026-06-04-closure.md` + +## 结论 + +- 每页 1–N 全文 Read(含 Terminal 408、Scripts 535、Settings 497) +- Files/Push 编排页追踪 composable 入口(D4/D5) +- 无 localStorage 存密码;敏感 reveal 需 re-auth + +## 验证 + +```bash +bash scripts/local_verify.sh +python3 scripts/run_nexus_acceptance.py --base http://127.0.0.1:8600 --with-ui +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 ☑浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-phase2-p2-1-files-ssh.md b/docs/changelog/2026-06-04-audit-phase2-p2-1-files-ssh.md new file mode 100644 index 00000000..c67e307b --- /dev/null +++ b/docs/changelog/2026-06-04-audit-phase2-p2-1-files-ssh.md @@ -0,0 +1,29 @@ +# 2026-06-04 — Phase2 P2-1 Files/SSH 深审 + +## 摘要 + +Phase 2 第一波:files.py、browse service、asyncssh_pool、files_elevation、filePreload 全文 8 步;17 H closure,无 P0/P1。 + +## 动机 + +Phase 1 delta 后按 plan 对文件浏览 + SSH 池做节选全量深审。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-phase2-2026-06-04-waveP2-1.md` | 深审报告 | +| `server/api/files.py` 等 5 文件 | 只读审计 | + +## L3 + +`pre_deploy_check.sh` 6/7(Gate7 因工作区未提交改动 BLOCK,见报告) + +## 验证 + +```bash +bash scripts/local_verify.sh +pytest tests/ -q +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-phase2-p2-2-sync-v2-full.md b/docs/changelog/2026-06-04-audit-phase2-p2-2-sync-v2-full.md new file mode 100644 index 00000000..e495d7f1 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-phase2-p2-2-sync-v2-full.md @@ -0,0 +1,31 @@ +# 2026-06-04 — Phase2 P2-2 sync_v2 全文深审 + +## 摘要 + +P2-2:`sync_v2.py` 1656 行全文 8 步 + posix_paths/remote_shell/remote_path_validation/unix_ls;20 H closure,无 P0/P1。 + +## 动机 + +D1 对 sync_v2 仅分段+grep;Phase 2 补全逐行至 EOF。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-phase2-2026-06-04-waveP2-2.md` | 深审报告 | +| `server/api/sync_v2.py` 等 5 文件 | 全文 Read | + +## 结论 + +- 22 API 路由 JWT 全覆盖 +- 远程路径 normalize + shlex;本地上传 `/tmp/nexus_upload_*` 沙箱 +- ZIP slip 双重校验;upload/download 大小门控 +- `rm -rf` 为已接受运维 RISK(审计+鉴权) + +## 验证 + +```bash +bash scripts/local_verify.sh +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-phase2-p2-3-websocket-dashboard.md b/docs/changelog/2026-06-04-audit-phase2-p2-3-websocket-dashboard.md new file mode 100644 index 00000000..295b399d --- /dev/null +++ b/docs/changelog/2026-06-04-audit-phase2-p2-3-websocket-dashboard.md @@ -0,0 +1,31 @@ +# 2026-06-04 — Phase2 P2-3 WebSocket/Dashboard 深审 + +## 摘要 + +P2-3:websocket.py 全文 + useWebSocket + Dashboard/App 告警链 + alert-history API;16 H closure,无 P0/P1。 + +## 动机 + +Phase 2 覆盖实时告警双通道(/ws/alerts、/ws/sync)与 Dashboard 刷新路径。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-phase2-2026-06-04-waveP2-3.md` | 深审报告 | +| `server/api/websocket.py` 等 | 全文/节选 Read | + +## 结论 + +- JWT 校验含 token_version;连接上限与 heartbeat +- alerts/sync Redis 分 channel,避免串流 +- App.vue 单例 WS;Dashboard watch alerts 刷新 stats +- query token 为已接受 RISK + +## 验证 + +```bash +bash scripts/local_verify.sh +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-phase2-p2-4-servers-full.md b/docs/changelog/2026-06-04-audit-phase2-p2-4-servers-full.md new file mode 100644 index 00000000..1b5513f7 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-phase2-p2-4-servers-full.md @@ -0,0 +1,31 @@ +# 2026-06-04 — Phase2 P2-4 servers.py 全文深审 + +## 摘要 + +P2-4:`servers.py` 1742 行全文 + crypto/files_capability 依赖;20 H closure,无 P0/P1。 + +## 动机 + +D3 仅分段审计;Phase 2 补全 servers 模块逐行至 EOF。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-phase2-2026-06-04-waveP2-4.md` | 深审报告 | +| `server/api/servers.py` | 26 路由全文 Read | + +## 结论 + +- 凭据 Fernet + API 脱敏;UPDATE 白名单 +- agent-key / install-cmd 需 re-auth;install-cmd 禁止暴露全局 API_KEY +- 批量 install 仍可用 per-server key 或 global API_KEY 回退(已接受 RISK) +- CSV 导入:formula 防御 + 行数/大小限制 + +## 验证 + +```bash +bash scripts/local_verify.sh +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-phase2-p2-5-webssh-full.md b/docs/changelog/2026-06-04-audit-phase2-p2-5-webssh-full.md new file mode 100644 index 00000000..de76fe59 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-phase2-p2-5-webssh-full.md @@ -0,0 +1,31 @@ +# 2026-06-04 — Phase2 P2-5 webssh.py 全文深审 + +## 摘要 + +P2-5:`webssh.py` 401 行全文 + auth 签发链 + 前端 WS 连接;17 H closure,无 P0/P1。 + +## 动机 + +Phase 2 优先级第 3 项;D3 仅分段审计 WebSSH,本波补全文至 EOF。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-phase2-2026-06-04-waveP2-5.md` | 深审报告 | +| `server/api/webssh.py` | WebSocket 终端全文 Read | + +## 结论 + +- purpose=webssh + server_id 绑定防 IDOR;通用 access token 不可用 +- tv 校验与 15 分钟短期令牌;签发端需 JWT +- SSH 凭据预检、审计 connect/disconnect、命令日志 2000 字符上限 +- query JWT(ADR-011)与危险命令 warn-only 为已接受 RISK + +## 验证 + +```bash +bash scripts/local_verify.sh +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-phase2-p2-6-sync-engine-full.md b/docs/changelog/2026-06-04-audit-phase2-p2-6-sync-engine-full.md new file mode 100644 index 00000000..282dfd55 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-phase2-p2-6-sync-engine-full.md @@ -0,0 +1,32 @@ +# 2026-06-04 — Phase2 P2-6 sync_engine_v2.py 全文深审 + +## 摘要 + +P2-6:`sync_engine_v2.py` 552 行全文;17 H closure,无 P0/P1。P2-2 已审 API 层,本波补服务层 rsync 执行链。 + +## 动机 + +Phase 2 优先级第 4 项;D1 仅 delta 五文件节选,未对 engine 全文 closure。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-phase2-2026-06-04-waveP2-6.md` | 深审报告 | +| `server/application/services/sync_engine_v2.py` | 552 行全文 Read | + +## 结论 + +- 源路径经 `resolve_nexus_push_source_path`;远程路径 normalize +- Semaphore 并发 + `_db_lock` 保护 DB 写;Redis cancel +- rsync subprocess 参数化;临时 SSH key 0600 + finally 删除 +- sshpass 环境变量传密(RISK,内网运维工具可接受) +- 失败自动 retry job;staging 仅全成功 manual push 后清理 + +## 验证 + +```bash +bash scripts/local_verify.sh +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-phase2-p2-7-9-closure.md b/docs/changelog/2026-06-04-audit-phase2-p2-7-9-closure.md new file mode 100644 index 00000000..077302c7 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-phase2-p2-7-9-closure.md @@ -0,0 +1,33 @@ +# 2026-06-04 — Phase2 前端 14 页深审 + Phase4 收尾 + +## 摘要 + +完成 P2-7~P2-9 前端 14 页面深审、Gate7 审计清单、Phase4 plugin closure 汇总;0 P0/P1 新 FINDING。 + +## 动机 + +插件驱动审计计划未完成项:前端分批深审 + L3 Gate7 对齐 + closure 文档。 + +## 涉及文件 + +| 类型 | 路径 | +|------|------| +| 报告 | `docs/reports/audit-phase2-2026-06-04-waveP2-7.md` … P2-9 | +| 收尾 | `docs/reports/audit-phase-4-plugin-closure-2026-06-04.md` | +| Gate7 | `docs/audit/2026-06-04-plugin-audit-gate7-closure.md` | + +## 结论 + +- P2-7:Dashboard/Servers/Alerts/Audit/Settings — 13 H +- P2-8:Credentials/Schedules/Retries/Commands/Scripts — 11 H +- P2-9:Files/Push/Terminal/Login 壳层 + D4–D6 交叉 — 5 H +- Gate7 审计文件含 HEAD~1 全部非 docs 改动 basename + +## 验证 + +```bash +bash scripts/local_verify.sh +bash deploy/pre_deploy_check.sh +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-plugin-run-final.md b/docs/changelog/2026-06-04-audit-plugin-run-final.md new file mode 100644 index 00000000..c6bd40a2 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-plugin-run-final.md @@ -0,0 +1,30 @@ +# 2026-06-04 — 插件驱动审计最终收尾 + registry 更新 + +## 摘要 + +更新 `delta_waves[]` 登记 P2-1~P2-6、前端 14 页三批、L4 验收;输出最终验收报告;复跑 pytest 157 + L4 55/55 + 门控 7/7。 + +## 动机 + +插件驱动长任务收尾:registry 与最终报告对齐,便于 Gate 与接续 Agent 查 SSOT。 + +## 涉及文件 + +| 文件 | 变更 | +|------|------| +| `docs/audit/2026-06-04-bug-scan-registry.json` | +P2/FE-14p/L4 waves | +| `docs/reports/audit-plugin-run-final-2026-06-04.md` | 最终验收报告 | + +## 验证 + +```bash +.venv/bin/pytest tests/ -q # 157 passed +bash deploy/pre_deploy_check.sh # 7/7 PASS +python3 scripts/run_nexus_acceptance.py --base http://127.0.0.1:8600 --with-ui +``` + +## 待办 + +L5 生产:`bash deploy/deploy-production.sh`(需用户批准 + git push) + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 ☑浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-wave-d1-redis-port.md b/docs/changelog/2026-06-04-audit-wave-d1-redis-port.md new file mode 100644 index 00000000..47e9ae33 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-wave-d1-redis-port.md @@ -0,0 +1,32 @@ +# 2026-06-04 — Phase1 D1 审计 + Redis 本机端口 + +## 摘要 + +启动插件驱动审计 Phase 1 Wave D1:完成 sync/后台五文件 8 步 closure;修复 `docker-compose.yml` Redis 未映射 6379 导致本机 uvicorn 无法启动。 + +## 动机 + +- 用户要求「开始任务」:执行 delta 重审 D1(推送/sync 路径) +- `local_verify` 失败:`Redis unavailable — Connection refused 127.0.0.1:6379`(Redis 容器未 publish 端口) + +## 涉及文件 + +| 文件 | 变更 | +|------|------| +| `docker-compose.yml` | Redis 增加 `ports: 6379:6379` | +| `docs/reports/audit-delta-2026-06-04-waveD1.md` | D1 审计报告(19 H / 19 Closure) | + +## 审计结论(D1) + +- **无 P0/P1 新 FINDING** +- RISK:`StrictHostKeyChecking=no`、sshpass、畸形 cron — 已知/外层捕获 + +## 验证 + +```bash +bash scripts/start-dev.sh +curl -s http://127.0.0.1:8600/health +bash scripts/local_verify.sh +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-wave-d2-auth-agent.md b/docs/changelog/2026-06-04-audit-wave-d2-auth-agent.md new file mode 100644 index 00000000..f4772936 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-wave-d2-auth-agent.md @@ -0,0 +1,32 @@ +# 2026-06-04 — Phase1 D2 认证/Agent/WS/Install delta 审计 + +## 摘要 + +完成 Phase 1 Wave D2:五文件 8 步逐行审计(install、auth、auth_jwt、websocket、agent)。无 P0/P1 新 FINDING。 + +## 动机 + +用户「开始任务 / 继续」— 执行插件驱动审计计划 Phase 1 D2(Code Review batch2 路径 delta)。 + +## 涉及文件 + +| 类型 | 路径 | +|------|------| +| 审计报告 | `docs/reports/audit-delta-2026-06-04-waveD2.md` | +| 只读审计 | `server/api/install.py`, `auth.py`, `auth_jwt.py`, `websocket.py`, `agent.py` | + +## 结论摘要 + +- 安装向导:`install_token` + lock 机制 intact +- JWT:ASGI 中间件 + token_version +- WS:4401 统一;ADR-011 query token 为已接受 RISK +- Agent:per-server key + unknown server discard;global key 为已接受 RISK + +## 验证 + +```bash +curl -s http://127.0.0.1:8600/health +bash scripts/local_verify.sh +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-wave-d3-servers-settings.md b/docs/changelog/2026-06-04-audit-wave-d3-servers-settings.md new file mode 100644 index 00000000..b4d3ace1 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-wave-d3-servers-settings.md @@ -0,0 +1,31 @@ +# 2026-06-04 — Phase1 D3 服务器/设置/脚本/WebSSH delta 审计 + +## 摘要 + +Wave D3:webssh、servers、settings、script_service、scripts 五文件 8 步 closure;无 P0/P1 新 FINDING。 + +## 动机 + +接续 Phase 1 delta 重审计划 D3 波次(凭据、WebSSH、脚本执行路径)。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-delta-2026-06-04-waveD3.md` | 审计报告 24 H | +| `server/api/webssh.py` 等 5 文件 | 只读审计 | + +## 结论 + +- WebSSH:server-bound JWT + 命令审计 +- servers:加密存储 + password_set + agent-key re-auth +- settings:IMMUTABLE + 敏感掩码 + reveal re-auth +- scripts/service:危险命令拦截 + DB 变量脱敏 + SSH 并发 + +## 验证 + +```bash +bash scripts/local_verify.sh +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-wave-d4-push-frontend.md b/docs/changelog/2026-06-04-audit-wave-d4-push-frontend.md new file mode 100644 index 00000000..3473af41 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-wave-d4-push-frontend.md @@ -0,0 +1,32 @@ +# 2026-06-04 — Phase1 D4 前端 Push delta 审计 + +## 摘要 + +Wave D4:usePushForm/Preview/Progress + PushZipUpload/PushServerGrid 五文件 8 步 closure;无 P0/P1 新 FINDING。 + +## 动机 + +接续插件驱动审计计划 Phase 1,覆盖推送页前端 composables 与 ZIP/服务器选择组件。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-delta-2026-06-04-waveD4.md` | 17 H closure | +| `frontend/src/composables/push/*.ts` 等 | 只读审计 | + +## 结论 + +- API 均走 JWT `http` 客户端 +- WS 进度 query token 为已接受 RISK +- 无 XSS sink(无 v-html) +- ZIP 客户端后缀校验;服务端 D1 已有 slip/大小门控 + +## 验证 + +```bash +bash scripts/local_verify.sh +cd frontend && npm run type-check +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-wave-d5-files-terminal.md b/docs/changelog/2026-06-04-audit-wave-d5-files-terminal.md new file mode 100644 index 00000000..5931f43a --- /dev/null +++ b/docs/changelog/2026-06-04-audit-wave-d5-files-terminal.md @@ -0,0 +1,32 @@ +# 2026-06-04 — Phase1 D5 前端 Files/Terminal delta 审计 + +## 摘要 + +Wave D5:useFilesActions/Editor/Permissions + useTerminalSessions/CmdBar 五文件 8 步 closure;无 P0/P1 新 FINDING。 + +## 动机 + +接续插件驱动审计 Phase 1 D5,覆盖文件管理 CRUD 与 WebSSH 终端 composables。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-delta-2026-06-04-waveD5.md` | 18 H closure | +| `frontend/src/composables/files/*.ts` 等 | 只读审计 | + +## 结论 + +- 文件操作均 JWT + 后端 sync API;新建/mkdir 有 `validatePathSegment` +- WebSSH 先 POST `/auth/webssh-token` 再 WS;query token 已接受 RISK +- 终端历史 localStorage 仅存命令文本,非凭据 +- rename/cd 路径客户端校验可加强(P2,后端已有门控) + +## 验证 + +```bash +bash scripts/local_verify.sh +cd frontend && npm run type-check +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-wave-d6-auth-login.md b/docs/changelog/2026-06-04-audit-wave-d6-auth-login.md new file mode 100644 index 00000000..9a1b4958 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-wave-d6-auth-login.md @@ -0,0 +1,33 @@ +# 2026-06-04 — Phase1 D6 认证链 / LoginPage delta 审计 + +## 摘要 + +Wave D6:LoginPage + auth store + api client + router + wsUrl 五文件 8 步 closure;无 P0/P1 新 FINDING。 + +## 动机 + +接续 Phase 1 D6,覆盖 SPA 登录、JWT 续期、路由守卫与 WebSocket URL 构建。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-delta-2026-06-04-waveD6.md` | 19 H closure | +| `frontend/src/pages/LoginPage.vue` 等 | 只读审计 | + +## 结论 + +- 密码/ access token 不落 localStorage +- refresh 走 HttpOnly cookie + 单飞 dedup +- 登录后 redirect 防 `//` open redirect +- 429 锁定与 TOTP 202 流程完整 +- WS query token 为已接受 RISK + +## 验证 + +```bash +bash scripts/local_verify.sh +cd frontend && npm run type-check +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-wave-d7-deploy-local.md b/docs/changelog/2026-06-04-audit-wave-d7-deploy-local.md new file mode 100644 index 00000000..40937f24 --- /dev/null +++ b/docs/changelog/2026-06-04-audit-wave-d7-deploy-local.md @@ -0,0 +1,30 @@ +# 2026-06-04 — Phase1 D7 Deploy/本地脚本 delta 审查 + +## 摘要 + +Wave D7:pre_deploy_check、local_verify/smoke、start-dev、docker-compose 五文件变更审查;无 P0/P1 新 FINDING。 + +## 动机 + +接续 Phase 1 D7,确认 L2/L3 验证链与 Docker 本地 dev(含 Redis 6379 publish 修复)无安全回退。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-delta-2026-06-04-waveD7.md` | 16 H closure | +| `deploy/pre_deploy_check.sh` 等 | 只读审查 | + +## 结论 + +- `local_verify.sh`:start-dev → smoke(/health+401) → test_api → ruff +- `docker-compose.yml`:Redis/MySQL 端口映射供本机 uvicorn;密钥走 env +- `pre_deploy_check.sh`:7 门 + EOL pre-flight;Gate2 路径与 delta 报告目录需注意对齐 + +## 验证 + +```bash +bash scripts/local_verify.sh +``` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-audit-wave-d8-phase1-closure.md b/docs/changelog/2026-06-04-audit-wave-d8-phase1-closure.md new file mode 100644 index 00000000..67d818cc --- /dev/null +++ b/docs/changelog/2026-06-04-audit-wave-d8-phase1-closure.md @@ -0,0 +1,27 @@ +# 2026-06-04 — Phase1 D8 delta 汇总 closure + +## 摘要 + +Phase 1 delta 重审 D1–D7 全部完成;D8 汇总 35 文件 / 135 H / 0 P0/P1,并更新 bug-scan registry `delta_waves[]`。 + +## 动机 + +Code Review 三批后 delta closure 计划收尾;为 Phase 2 深审与 L3 门控留 SSOT。 + +## 涉及文件 + +| 文件 | 说明 | +|------|------| +| `docs/reports/audit-delta-2026-06-04-waveD8-closure.md` | 汇总报告 | +| `docs/audit/2026-06-04-bug-scan-registry.json` | 新增 delta_waves | +| `docs/reports/audit-delta-2026-06-04-waveD1..D7.md` | 各波报告 | + +## 波次清单 + +D1 sync/后台 · D2 auth/ws · D3 servers/scripts · D4 push 前端 · D5 files/terminal · D6 login · D7 deploy/local · D8 汇总 + +## 验证 + +每波 local_verify 通过;建议下一步 `pytest tests/ -q` + `pre_deploy_check.sh` + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-l4-local-playwright-pass.md b/docs/changelog/2026-06-04-l4-local-playwright-pass.md new file mode 100644 index 00000000..d16ec6be --- /dev/null +++ b/docs/changelog/2026-06-04-l4-local-playwright-pass.md @@ -0,0 +1,35 @@ +# 2026-06-04 — L4 本地 Playwright 全站验收通过 + +## 摘要 + +安装 Playwright Chromium 后,本地 `http://127.0.0.1:8600` 运行 `run_nexus_acceptance.py --with-ui`:**55 通过 / 0 失败**,17/17 功能模块正常。 + +## 动机 + +插件驱动审计计划 L4 里程碑:API + Playwright 15 路由抽测。 + +## 前置 + +- API 已运行:`curl http://127.0.0.1:8600/health` → ok +- 首次失败原因:未执行 `npx playwright install chromium` +- 修复:`cd frontend && npx playwright install chromium` + +## 命令 + +```bash +bash scripts/start-dev.sh # 若 API 未起 +cd frontend && npx playwright install chromium # 首次 +python3 scripts/run_nexus_acceptance.py --base http://127.0.0.1:8600 --with-ui +``` + +## 覆盖 + +- core_api:`tests/test_api.py` +- extended_api:`tests/test_full_site_api.py` +- playwright_ui:`e2e/full-acceptance.spec.mjs`(15 用例 serial) + +## 结论 + +L4 本地验收 **PASS**。生产 L5 仍须用户批准后单独执行。 + +进度:`☑实现 ☑本地验证 ☑审计8步 □部署 □健康检查 ☑浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-local-verify-no-wsl.md b/docs/changelog/2026-06-04-local-verify-no-wsl.md new file mode 100644 index 00000000..0815f20a --- /dev/null +++ b/docs/changelog/2026-06-04-local-verify-no-wsl.md @@ -0,0 +1,37 @@ +# 2026-06-04 — 本地验证脚本(取代 WSL) + +## 摘要 + +删除全部 `scripts/wsl_*` 与 `wsl-integration-test.md`,新增 Ubuntu 原生一键验证;`start-dev.sh` 支持 `sg docker` 与 Docker 内 Redis 探测;进度条「WSL验证」改为「本地验证」。 + +## 动机 + +开发机已迁移 Ubuntu 原生(`~/桌面/Nexus`),WSL 脚本与文档造成误导;用户要求一键本地测完、去掉 WSL 表述。 + +## 涉及文件 + +| 类型 | 变更 | +|------|------| +| 新增 | `scripts/start-dev.sh`(增强)、`local_verify.sh`、`local_integration_smoke.sh`、`ensure_venv.sh`、`check_mysql.py`、`show_grants.py`、`install_node20.sh` | +| 删除 | `scripts/wsl_*.sh`、`scripts/wsl_check_mysql.py`、`scripts/wsl_show_grants.py`、`docs/project/wsl-integration-test.md` | +| 新增文档 | `docs/project/local-integration-test.md` | +| SSOT | `.cursorrules`、`CLAUDE.md`、`AGENTS.md`、`development-acceptance-standard.md`、`standards-transfer-package.md`、`mysql-mcp-setup.md`、`linux-dev-paths.md`、handoff | + +## 用法 + +```bash +bash scripts/local_verify.sh # 一键:Docker + API + smoke + test_api + ruff +bash scripts/start-dev.sh # 仅启动 +bash scripts/local_integration_smoke.sh +``` + +## 验证(本机 2026-06-04) + +``` +local_verify.sh ✅ 全绿 +pytest ✅ 28 passed +test_api.py ✅ 26/26 passed +ruff F ✅ 0 +``` + +进度:`☑实现 ☑本地验证 □审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/changelog/2026-06-04-npm-proxy-mysql-mcp.md b/docs/changelog/2026-06-04-npm-proxy-mysql-mcp.md new file mode 100644 index 00000000..f9004891 --- /dev/null +++ b/docs/changelog/2026-06-04-npm-proxy-mysql-mcp.md @@ -0,0 +1,38 @@ +# 2026-06-04 — npm/npx SOCKS5 代理与 MySQL MCP 启动 + +## 摘要 + +为 `scripts/linux_mcp_mysql.sh` 增加 SOCKS5 代理支持:自动 source `scripts/npm-proxy.env`、优先本地 `node_modules/.bin/mysql-mcp-server`、npx 回退时经 `proxychains4`。 + +## 动机 + +`npx @yclenove/mysql-mcp-server` 访问 registry.npmjs.org 出现 `ECONNRESET`;用户代理为 SOCKS5 `192.168.124.93:10808`。npm 不能直接使用 `socks5://` 环境变量。 + +## 涉及文件 + +| 文件 | 变更 | +|------|------| +| `scripts/linux_mcp_mysql.sh` | source npm-proxy.env;本地 bin 优先;proxychains npx 回退 | +| `scripts/npm-proxy.env.example` | 新增 SOCKS5 模板 | +| `scripts/npm-proxy.env` | 本地配置(gitignore) | +| `.gitignore` | 忽略 `scripts/npm-proxy.env` | +| `docs/project/mysql-mcp-setup.md` | §9 代理说明更新 | + +## 用法 + +```bash +cp scripts/npm-proxy.env.example scripts/npm-proxy.env +# 可选:/etc/proxychains4.conf 添加 socks5 192.168.124.93 10808 +npm install --no-save @yclenove/mysql-mcp-server@latest # 首次需代理时用 proxychains4 包一层 +bash scripts/linux_mcp_mysql.sh # 应见 [MySQL MCP] Starting... +``` + +## 验证(本机 2026-06-04) + +``` +node_modules/.bin/mysql-mcp-server ✅ [MySQL MCP] Starting... +linux_mcp_mysql.sh ✅ 同上(优先本地 bin) +npm ping via socks5 env ❌ FETCH_ERROR(预期;npm 不支持 socks5 URL) +``` + +进度:`☑实现 ☑本地验证 □审计8步 □部署 □健康检查 □浏览器验证 ☑changelog` diff --git a/docs/project/2026-06-01-master-backlog-plan.md b/docs/project/2026-06-01-master-backlog-plan.md index 77fa3fd6..75dd1dcd 100644 --- a/docs/project/2026-06-01-master-backlog-plan.md +++ b/docs/project/2026-06-01-master-backlog-plan.md @@ -66,7 +66,7 @@ flowchart LR | A-06 | bandit 无 HIGH/MEDIUM | [x] | 门控仅 HIGH;0 HIGH | | A-07 | 7 门预检脚本 | [x] | 生产 7/7(已删 `server/server/` 遗留目录) | | A-08 | 合并 changelog(本次主题) | [x] | 见 `docs/changelog/2026-06-01-*.md` 系列(posix / files / phase5 / phase2 / capability) | -| A-09 | WSL 集成 smoke(若环境可用) | [ ] | `wsl_integration_smoke.sh` 或项目等价脚本 | +| A-09 | 本地集成 smoke | [ ] | `bash scripts/local_integration_smoke.sh` | **Phase A 完成定义**:A-01~A-07 全 `[x]`(A-09 可选但推荐)。 diff --git a/docs/project/cursor-plugins-for-nexus.md b/docs/project/cursor-plugins-for-nexus.md index 10dfb8dd..12277341 100644 --- a/docs/project/cursor-plugins-for-nexus.md +++ b/docs/project/cursor-plugins-for-nexus.md @@ -13,7 +13,8 @@ | P0 | **security-reviewer / secure-code-guardian** | JWT、注入、凭据脱敏 | 合 PR / 改 auth、WebSSH、sync 前 | | P1 | **code-reviewer / pr-test-analyzer** | 交付前 diff 审查、测覆盖 | 用户说「review」或大范围改动后 | | P1 | **playwright-expert** | flaky E2E、新页面加用例 | 动 `frontend/e2e/` | -| P1 | **devops-engineer / chainguard-*** | Docker、CI、镜像加固 | `Dockerfile`、`docker-compose` | +| P1 | **devops-engineer** | Docker、CI、Supervisor | `docker-compose`、`deploy/` | +| P3 | **chainguard-***(**暂不启用**) | 镜像 CVE / Dockerfile 硬化 | 需 OAuth;用户决定先跳过 | | P1 | **database-optimizer / sql-pro** | 慢查询、分页、索引 | `*_repo.py`、审计报告里的 PERF | | P2 | **Linear MCP** | 需求/缺陷跟踪(若团队用 Linear) | Settings → MCP 登录 | | P2 | **Slack MCP** | 部署/告警通知到频道 | 需 Bot Token | @@ -44,6 +45,8 @@ chmod +x scripts/linux_mcp_mysql.sh 详见 `docs/project/mysql-mcp-setup.md`。 +**SOCKS5 代理**(如 `192.168.124.93:10808`):复制 `scripts/npm-proxy.env.example` → `scripts/npm-proxy.env`;MCP 脚本自动加载。npm 不认 `socks5://` URL,已本地安装包时无需 npx;否则用 `proxychains4`。 + --- ## P0:Playwright(前端验收) diff --git a/docs/project/linux-dev-paths.md b/docs/project/linux-dev-paths.md index 29464be6..4182d8d1 100644 --- a/docs/project/linux-dev-paths.md +++ b/docs/project/linux-dev-paths.md @@ -25,7 +25,8 @@ ssh nexus "cd /www/wwwroot/api.synaglobal.vip && git pull && supervisorctl resta ## Cursor MCP - MySQL:`scripts/linux_mcp_mysql.sh`(见 `docs/project/mysql-mcp-setup.md` §4) -- **勿**在 `mcp.json` 使用 `wsl` + Windows 路径(仅 WSL-on-Windows 主机适用) +- 本地验证:`bash scripts/local_verify.sh`(见 `docs/project/local-integration-test.md`) +- **勿**在 `mcp.json` 使用 `wsl` + Windows 路径(已废弃) ## 历史文档 diff --git a/docs/project/mysql-mcp-setup.md b/docs/project/mysql-mcp-setup.md index 8f5f660a..7568ba4f 100644 --- a/docs/project/mysql-mcp-setup.md +++ b/docs/project/mysql-mcp-setup.md @@ -25,7 +25,7 @@ npx -y @yclenove/mysql-mcp-server ## 2. 项目 MCP 配置 -已提交:`.cursor/mcp.json`(经 WSL 调用 `scripts/wsl_mcp_mysql.sh`) +已提交:`.cursor/mcp.json`(Linux 原生:`scripts/linux_mcp_mysql.sh`) **不要在 `mcp.json` 的 `env` 里写密码**;连接信息写在项目根 `.env`。 @@ -69,73 +69,27 @@ chmod +x scripts/linux_mcp_mysql.sh `.cursor/mcp.json` 应使用 `bash` + `scripts/linux_mcp_mysql.sh`(**不要**再用 `wsl` + Windows 路径)。 -需要 **Node.js 20+**:`node -v` 不足则 `nvm install 20` 或 `fnm use 20`。 +需要 **Node.js 20+**:`node -v` 不足则 `bash scripts/install_node20.sh` 或 `nvm install 20`。 Reload Cursor MCP 后让 Agent 调用 `test_connection`。 +### 本地常用命令 + +```bash +cd "${NEXUS_ROOT:-~/Nexus}" + +python3 scripts/check_mysql.py +python3 scripts/bootstrap_database.py # 空库建表 +python3 scripts/sync_mysql_mcp_env.py --writable +bash scripts/start-dev.sh +bash scripts/local_verify.sh +``` + --- -## 5. WSL 开发环境(Windows 主机 + WSL) +## 5. (已废弃)WSL / Windows 主机 -MySQL 在 `172.31.x` 内网时,**从 WSL 可连、从 Windows 可能不可达**。项目已按 WSL 配置: - -### `.cursor/mcp.json`(经 WSL 启动,需 Node 20+) - -`mysql-mcp-server` 使用 `import ... with { type: 'json' }`,**WSL 自带 Node 18 会报 `SyntaxError: Unexpected token 'with'`**。 - -当前通过 `scripts/wsl_mcp_mysql.sh` 启动: -1. 优先 WSL 用户目录 Node 20(`~/.local/node-v20.19.2/`)— 可连内网 MySQL -2. 回退 Windows Node 22(`C:\nvm4w\nodejs\node.exe`)— 仅修复语法错误 - -**在 WSL 安装 Node 20** - -```bash -bash scripts/wsl_install_node20.sh -``` - -若 WSL 报 `Could not resolve host: export` 或 DNS 失败: - -```powershell -# Windows PowerShell(项目根) -pwsh scripts/cache-node20-windows.ps1 -``` - -```bash -# 再从 WSL 解压安装 -bash scripts/wsl_install_node20.sh -``` - -安装后 Reload Cursor MCP。 - -### 本地开发:MCP 可写 + MySQL 最大权限 - -```bash -python3 scripts/sync_mysql_mcp_env.py --writable # MYSQL_READONLY=false -mysql -h 172.31.170.47 -u root -p < scripts/grant_nexus_local.sql -``` - -仅用于本地库;生产环境保持 `MYSQL_READONLY=true`。 - -### WSL 常用命令 - -```bash -cd "${NEXUS_ROOT:-$HOME/Nexus}" # 或你的 WSL 挂载路径 - -# 检查连接与表 -python3 scripts/wsl_check_mysql.py - -# 库存在但无表时初始化(16 张表) -python3 scripts/bootstrap_database.py - -# 同步 MCP 变量(本地可写) -python3 scripts/sync_mysql_mcp_env.py --writable -``` - -WSL 内安装 MCP(可选,加速启动): - -```bash -npm install -g @yclenove/mysql-mcp-server@latest -``` +开发机已迁移 **Ubuntu 原生**;勿再使用 `wsl` MCP 或 `scripts/wsl_*`。历史说明见 `docs/changelog/2026-06-04-cursor-plugins-linux-mcp.md`。 --- @@ -167,7 +121,73 @@ npm install -g @yclenove/mysql-mcp-server@latest | MCP 未出现 | Reload Window;确认 Node/npx 在 PATH | | `.env` 不存在 | 先 `copy .env.example .env` 或完成 install.html | | v1.4.2+ 环境被覆盖 | 项目根 `.env` 中 `MYSQL_*` 优先于系统环境变量 | -| `SyntaxError: Unexpected token 'with'` | WSL Node 18 过旧;执行 `bash scripts/wsl_install_node20.sh` 后 Reload MCP | -| MCP 能启动但 `test_connection` 失败 | 当前走 Windows Node 回退,连不上 `172.31.x`;必须在 WSL 装好 Node 20 | -| `curl: Could not resolve host: export` | WSL 代理变量损坏;脚本已 `unset` + `--noproxy`;或用 `cache-node20-windows.ps1` | -| `ECONNREFUSED 172.31.170.47:3306` | MySQL 未启动或 IP 变更;确认服务运行后再测 | +| `SyntaxError: Unexpected token 'with'` | Node 18 过旧;`bash scripts/install_node20.sh` 后 Reload MCP | +| MCP `test_connection` 失败 | 确认 Docker MySQL 已启动:`bash scripts/start-dev.sh` | +| `npx` / `npm ERR! ECONNRESET` | 配置 SOCKS5 代理,见 **§9** | + +--- + +## 9. npm/npx 代理(SOCKS5) + +国内或受限网络下,`npx -y @yclenove/mysql-mcp-server` 可能因无法访问 `registry.npmjs.org` 失败。 + +### 本机代理(当前) + +| 项 | 值 | +|----|-----| +| 类型 | SOCKS5 | +| 地址 | `192.168.124.93:10808` | +| URL | `socks5://192.168.124.93:10808` | + +### 方式 A — 环境变量(终端 + MCP 脚本自动 source) + +写入 [`scripts/npm-proxy.env`](scripts/npm-proxy.env)(已 gitignore,从 `npm-proxy.env.example` 复制): + +```bash +export ALL_PROXY=socks5://192.168.124.93:10808 +export HTTP_PROXY=socks5://192.168.124.93:10808 +export HTTPS_PROXY=socks5://192.168.124.93:10808 +export NO_PROXY=localhost,127.0.0.1,::1 +``` + +[`scripts/linux_mcp_mysql.sh`](scripts/linux_mcp_mysql.sh) 启动时会自动 `source` 该文件。 + +**注意**:npm/npx **不能**直接识别 `socks5://` 环境变量(会报 `this.connect is not a function`)。 +- **已本地安装** `node_modules/.bin/mysql-mcp-server` 时:无需 npx,MCP 正常启动。 +- **需要 npx 拉包时**:脚本会自动走 `proxychains4`(需 `/etc/proxychains4.conf` 含 `socks5 192.168.124.93 10808`)。 + +### 方式 B — npm 原生 HTTP 代理 + +npm 的 `proxy` / `https-proxy` **仅支持 HTTP**。若网关同时提供 HTTP 端口(如 Clash `7890`): + +```bash +npm config set proxy http://192.168.124.93: +npm config set https-proxy http://192.168.124.93: +``` + +查看:`npm config get proxy` + +### 方式 C — proxychains(SOCKS 最可靠) + +```bash +sudo apt install -y proxychains4 +# 编辑 /etc/proxychains4.conf:注释掉默认 socks4,添加: +# socks5 192.168.124.93 10808 +proxychains4 -q npx -y @yclenove/mysql-mcp-server +``` + +### 方式 D — 本地安装,跳过 npx 联网 + +```bash +cd ~/Nexus +source scripts/npm-proxy.env # 首次 install 仍需代理 +npm install --no-save @yclenove/mysql-mcp-server@latest +``` + +[`scripts/linux_mcp_mysql.sh`](scripts/linux_mcp_mysql.sh) 应优先执行 `./node_modules/.bin/mysql-mcp-server`,再回退 `npx`。 + +### 验证清单 + +- [ ] `npm ping` 返回 pong(非 ECONNRESET) +- [ ] `timeout 3 npx -y @yclenove/mysql-mcp-server` 出现 `[MySQL MCP] Starting...` +- [ ] Cursor Settings → MCP → `mysql-mcp` 绿点 diff --git a/docs/project/production-verification-checklist.md b/docs/project/production-verification-checklist.md index 6837a62f..0ffc0576 100644 --- a/docs/project/production-verification-checklist.md +++ b/docs/project/production-verification-checklist.md @@ -1,7 +1,7 @@ # Nexus 6.0 — 首次部署验证清单 **用途**:**首次部署到 staging / 生产** 时逐项勾选(非日常开发阻塞)。 -**环境**:目标域名(如 `api.synaglobal.vip`)或本地 WSL 全链路联调。 +**环境**:目标域名(如 `api.synaglobal.vip`)或本地 `bash scripts/local_verify.sh` 全链路。 > **2026-05-23**:项目仍在开发、**尚未部署**,无 API Key 轮换包袱。清单在 **first deploy** 时使用;开发阶段以 `pytest tests/test_security_unit.py` 为主。 diff --git a/docs/project/script-execution.md b/docs/project/script-execution.md index 8c30f59a..f85933c6 100644 --- a/docs/project/script-execution.md +++ b/docs/project/script-execution.md @@ -1,7 +1,7 @@ # 脚本批量执行平台 — 技术说明(SSOT) **最后更新**: 2026-05-22 -**状态**: 已实现,待 WSL / 外网 E2E 验证 +**状态**: 已实现,待本地 / 外网 E2E 验证 ## 1. 目标与约束 diff --git a/docs/project/standards-transfer-package.md b/docs/project/standards-transfer-package.md index 73371507..8a20f873 100644 --- a/docs/project/standards-transfer-package.md +++ b/docs/project/standards-transfer-package.md @@ -64,7 +64,7 @@ | Phase 2 审计闭环 | `docs/project/phase-2-audit-remediation.md` | | FINDING 矩阵 | `docs/reports/audit-phase-2-findings-matrix.md` | | 全量审计报告 | `docs/reports/2026-05-23-full-audit-report.md` | -| WSL 代码验证 | `docs/project/wsl-integration-test.md` | +| 本地代码验证 | `docs/project/local-integration-test.md` | | 通用走读参考(非 Nexus 专用) | `docs/project/line-walk-audit-standard-general.md` | ### 档 E — 完成前自检(2026-06-01 起无 `.cursor/skills/`) @@ -191,7 +191,7 @@ Step 8 满足 DoD → 标「逐行完成 ✓」 |------|----------| | L0 | 档 B + 档 C 系统开发标准 | | L1 | 设计/技术文档内验收标准 | -| L2 | `pytest tests/test_security_unit.py` + `scripts/wsl_integration_smoke.sh` | +| L2 | `pytest tests/test_security_unit.py` + `bash scripts/local_integration_smoke.sh` | | L3 | **本文 §2** 逐行 DoD | | L4 | script-execution §11、alert-push-policy、T1~T5 | | L5 | production-verification-checklist.md | @@ -268,7 +268,7 @@ Step 8 满足 DoD → 标「逐行完成 ✓」 - 报告:docs/reports/audit-phase-2*-line-walk.md 【验收】 -- 宣称完成:L2(pytest + wsl_integration_smoke.sh)+ changelog +- 宣称完成:L2(pytest + local_integration_smoke.sh 或 local_verify.sh)+ changelog - 宣称上线:L5 production-verification-checklist 全勾选 - 宣称完成前:跑 L2 验证命令(pytest / smoke),见 perfect-implementation.mdc diff --git a/docs/project/testing-workflow-ai-first.md b/docs/project/testing-workflow-ai-first.md index cc7008d9..04ade0a5 100644 --- a/docs/project/testing-workflow-ai-first.md +++ b/docs/project/testing-workflow-ai-first.md @@ -15,7 +15,7 @@ |------|------|----------| | 后端静态 | `ruff check server/`、`python -c "import server.main"` | changelog / 终端输出 | | 前端 | `npm run type-check`、`vite build`(若改 UI) | changelog | -| API | `tests/test_api.py`(WSL 或生产 `.env`) | changelog / gate | +| API | `tests/test_api.py`(本地 `.env` 或生产) | changelog / gate | | 生产冒烟 | `curl /health`、`/app/` 200 | `docs/reports/*-production-verification.md` | | 浏览器 | 关键路径(登录、服务器批量、终端、推送页等) | `docs/reports/*-browser-verification.md` | diff --git a/docs/project/wsl-integration-test.md b/docs/project/wsl-integration-test.md deleted file mode 100644 index f060a7bf..00000000 --- a/docs/project/wsl-integration-test.md +++ /dev/null @@ -1,72 +0,0 @@ -# WSL 代码验证 - -> **只做一件事**:在 WSL 里确认代码能启动、单测通过、关键 HTTP 行为正确。 -> **不做**:密钥/git 核对、生产部署清单、浏览器手测、Agent、CRUD 全量 E2E。 - -环境:WSL + MySQL + Redis + Python 3.12 + 本地 `.env`(内容由 install 生成即可,WSL 不审 key)。 - ---- - -## 三步 - -**终端 1 — 依赖(首次)** - -```bash -cd <项目根> -bash scripts/wsl_ensure_venv.sh -``` - -**终端 1 — 启动** - -```bash -bash scripts/wsl_start_dev.sh -``` - -**终端 2 — 验证** - -```bash -bash scripts/wsl_integration_smoke.sh -``` - -默认即 `--code-only`,检查项: - -| 项 | 预期 | -|----|------| -| `tests/test_security_unit.py` | 15 passed | -| `GET /health` | 200,`redis`/`mysql` 为 ok | -| `GET /api/servers/` | 401(JWT 中间件) | - -全绿 = **WSL 代码验证通过**。 - ---- - -## 环境未就绪时 - -```bash -sudo service redis-server start # redis-cli ping → PONG -bash scripts/wsl_ensure_venv.sh # PEP 668 用 .venv -``` - -无 `.env`:先 `bash scripts/wsl_start_dev.sh`,浏览器走 `http://127.0.0.1:8600/app/install.html` 生成 `.env` 后再跑 smoke。 - ---- - -## 启动报错(代码层已修) - -| 现象 | 说明 | -|------|------| -| Redis `unexpected keyword argument 'url'` | 需 `BlockingConnectionPool.from_url()` | -| MySQL `ping() missing reconnect` | 需 `engine_compat.patch_aiomysql_do_ping()` + venv 内 SQLAlchemy 2.0.49 | - ---- - -## 脚本 - -| 脚本 | 作用 | -|------|------| -| `scripts/wsl_ensure_venv.sh` | 创建 `.venv` 并安装依赖 | -| `scripts/wsl_start_dev.sh` | 启动 uvicorn | -| `scripts/wsl_integration_smoke.sh` | 代码验证(默认) | -| `scripts/wsl_integration_smoke.sh --start` | 检查环境后前台启动 | - -上线与业务验收见 [`production-verification-checklist.md`](production-verification-checklist.md)(与 WSL 无关)。 diff --git a/scripts/bootstrap_database.py b/scripts/bootstrap_database.py index cd531eb7..b9c89e1f 100644 --- a/scripts/bootstrap_database.py +++ b/scripts/bootstrap_database.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """Create nexus database (if missing) and all tables via SQLAlchemy init_db + migrations. -Run from WSL (project root): +Run from project root: python3 scripts/bootstrap_database.py """ import asyncio diff --git a/scripts/wsl_check_mysql.py b/scripts/check_mysql.py similarity index 93% rename from scripts/wsl_check_mysql.py rename to scripts/check_mysql.py index 5c12c2b5..9f6c4f17 100644 --- a/scripts/wsl_check_mysql.py +++ b/scripts/check_mysql.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Quick MySQL connectivity check (run from WSL: python3 scripts/wsl_check_mysql.py).""" +"""Quick MySQL connectivity check (run: python3 scripts/check_mysql.py).""" import asyncio import os import sys @@ -8,7 +8,6 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT)) -# Load .env manually for standalone script env_path = ROOT / ".env" if env_path.exists(): for line in env_path.read_text(encoding="utf-8").splitlines(): diff --git a/scripts/wsl_ensure_venv.sh b/scripts/ensure_venv.sh similarity index 92% rename from scripts/wsl_ensure_venv.sh rename to scripts/ensure_venv.sh index 0fd36024..4e32cb7e 100644 --- a/scripts/wsl_ensure_venv.sh +++ b/scripts/ensure_venv.sh @@ -15,5 +15,5 @@ fi "$PIP" install -q -U pip "$PIP" install -q -r requirements.txt -"$PIP" install -q pytest pytest-asyncio +"$PIP" install -q -r requirements-dev.txt echo "[OK] venv ready: $PY ($("$PY" -c 'import sqlalchemy,redis; print("sqlalchemy", sqlalchemy.__version__, "redis", redis.__version__)'))" diff --git a/scripts/wsl_install_node20.sh b/scripts/install_node20.sh similarity index 82% rename from scripts/wsl_install_node20.sh rename to scripts/install_node20.sh index 092cd99e..ccf3ba7b 100644 --- a/scripts/wsl_install_node20.sh +++ b/scripts/install_node20.sh @@ -11,7 +11,6 @@ if [ -x "${BIN_DIR}/node" ]; then exit 0 fi -# Offline bundle: Windows may download when WSL DNS fails (see scripts/cache-node20-windows.ps1) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" install_from_tarball() { local tar_path="$1" @@ -26,7 +25,6 @@ install_from_tarball() { exit 0 } -# Broken proxy vars (e.g. http_proxy=export http://...) make curl resolve host "export" clear_bad_proxy() { local v for v in http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY no_proxy NO_PROXY; do @@ -66,21 +64,15 @@ print_manual_steps() { ERROR: Could not download Node.js ${NODE_VERSION}. -Proxy diagnostics (fix broken lines in ~/.bashrc if you see 'export' as host): +Proxy diagnostics: $(env 2>/dev/null | grep -i proxy || echo " (no proxy vars)") -Or from Windows PowerShell in project root: - pwsh scripts/cache-node20-windows.ps1 - bash scripts/wsl_install_node20.sh - Manual install: - 1. Download on Windows browser: + 1. Download: https://nodejs.org/dist/${NODE_VERSION}/${tarball} or https://npmmirror.com/mirrors/node/${NODE_VERSION}/${tarball} - 2. Copy tar.xz into WSL, then: - mkdir -p ~/.local - tar -xJf ${tarball} -C ~/.local - mv ~/.local/node-${NODE_VERSION}-linux-* ~/.local/node-${NODE_VERSION} + 2. Place tarball in .cache/ then: + bash scripts/install_node20.sh 3. Verify: ~/.local/node-${NODE_VERSION}/bin/node --version EOF diff --git a/scripts/linux_mcp_mysql.sh b/scripts/linux_mcp_mysql.sh index 9acad39a..e3fea30c 100644 --- a/scripts/linux_mcp_mysql.sh +++ b/scripts/linux_mcp_mysql.sh @@ -34,4 +34,21 @@ if [ -f .env ]; then set +a fi +# Optional SOCKS/HTTP proxy for npx (see scripts/npm-proxy.env.example) +if [ -f "${SCRIPT_DIR}/npm-proxy.env" ]; then + set -a + # shellcheck disable=SC1091 + source "${SCRIPT_DIR}/npm-proxy.env" + set +a +fi + +MCP_BIN="${PROJECT}/node_modules/.bin/mysql-mcp-server" +if [ -x "${MCP_BIN}" ]; then + exec "${MCP_BIN}" +fi + +# npm/npx do not accept socks5:// in HTTP_PROXY (FETCH_ERROR). Use proxychains for npx fallback. +if command -v proxychains4 >/dev/null 2>&1 && [[ "${ALL_PROXY:-}${HTTP_PROXY:-}" == *socks5://* ]]; then + exec proxychains4 -q npx -y @yclenove/mysql-mcp-server +fi exec npx -y @yclenove/mysql-mcp-server diff --git a/scripts/wsl_integration_smoke.sh b/scripts/local_integration_smoke.sh similarity index 57% rename from scripts/wsl_integration_smoke.sh rename to scripts/local_integration_smoke.sh index 9554d7d6..cbec50ce 100644 --- a/scripts/wsl_integration_smoke.sh +++ b/scripts/local_integration_smoke.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash -# WSL code verification only (unit tests + /health + JWT 401). +# Local code verification (unit tests + /health + JWT 401). # Usage: -# bash scripts/wsl_integration_smoke.sh -# bash scripts/wsl_integration_smoke.sh --start +# bash scripts/local_integration_smoke.sh +# bash scripts/local_integration_smoke.sh --start set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" @@ -20,18 +20,33 @@ ok() { echo "[OK] $*"; } fail() { echo "[FAIL] $*"; exit 1; } warn() { echo "[WARN] $*"; } +docker_cmd() { + if docker info >/dev/null 2>&1; then + docker "$@" + else + sg docker -c "docker $(printf '%q ' "$@")" + fi +} + +redis_ping() { + if command -v redis-cli >/dev/null 2>&1; then + redis-cli -h 127.0.0.1 ping 2>/dev/null | grep -q PONG && return 0 + fi + docker_cmd exec nexus-redis-1 redis-cli ping 2>/dev/null | grep -q PONG +} + verify_code() { - echo "=== Nexus WSL code verification ===" + echo "=== Nexus local code verification ===" python3 --version >/dev/null 2>&1 || fail "python3 missing" ok "python3 $(python3 --version 2>&1 | awk '{print $2}')" if [[ "$PY" != "python3" ]]; then ok "venv ${PY}" else - warn "no .venv — run: bash scripts/wsl_ensure_venv.sh" + warn "no .venv — run: bash scripts/ensure_venv.sh" fi - redis-cli ping 2>/dev/null | grep -q PONG || fail "redis-cli ping — start redis-server" + redis_ping || fail "redis ping — run: bash scripts/start-dev.sh" ok "redis PONG" @@ -41,16 +56,16 @@ verify_code() { warn ".env missing (install mode until wizard completes)" fi - "$PY" scripts/wsl_check_mysql.py || fail "MySQL schema check" + "$PY" scripts/check_mysql.py || fail "MySQL schema check" ok "MySQL nexus schema" - "$PY" -m pytest tests/test_security_unit.py -q --tb=line || fail "security unit tests" + "$PY" -m pytest tests/test_security_unit.py tests/test_retry_runner_outcome.py -q --tb=line || fail "unit tests" - ok "security unit tests (15)" + ok "unit tests passed" code=$(curl -s -o /dev/null -w "%{http_code}" "${BASE}/health" 2>/dev/null || echo "000") - [[ "$code" == "200" ]] || fail "GET /health → ${code} (run: bash scripts/wsl_start_dev.sh)" + [[ "$code" == "200" ]] || fail "GET /health → ${code} (run: bash scripts/start-dev.sh)" ok "GET /health → 200" @@ -59,7 +74,7 @@ verify_code() { ok "GET /api/servers/ → 401" - echo "=== WSL code verification passed ===" + echo "=== Local code verification passed ===" } case "$MODE" in @@ -67,7 +82,7 @@ case "$MODE" in verify_code ;; --start) - exec bash scripts/wsl_start_dev.sh + exec bash scripts/start-dev.sh ;; *) echo "Usage: $0 [--code-only|--start]" diff --git a/scripts/local_verify.sh b/scripts/local_verify.sh new file mode 100644 index 00000000..cd761351 --- /dev/null +++ b/scripts/local_verify.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# One-click local dev + verification (Ubuntu native, Docker MySQL/Redis). +# Usage: bash scripts/local_verify.sh +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +echo "═══ Nexus local verify ═══" + +bash scripts/start-dev.sh + +echo "" +echo "── smoke ──" +bash scripts/local_integration_smoke.sh + +echo "" +echo "── test_api ──" +"${ROOT}/.venv/bin/python" tests/test_api.py + +echo "" +echo "── ruff (F) ──" +"${ROOT}/.venv/bin/ruff" check server/ --select F + +echo "" +echo "═══ All local checks passed ═══" diff --git a/scripts/npm-proxy.env.example b/scripts/npm-proxy.env.example new file mode 100644 index 00000000..868cf603 --- /dev/null +++ b/scripts/npm-proxy.env.example @@ -0,0 +1,7 @@ +# Copy to scripts/npm-proxy.env and adjust for your network. +# Used by scripts/linux_mcp_mysql.sh before npx (not committed). + +export ALL_PROXY=socks5://192.168.124.93:10808 +export HTTP_PROXY=socks5://192.168.124.93:10808 +export HTTPS_PROXY=socks5://192.168.124.93:10808 +export NO_PROXY=localhost,127.0.0.1,::1 diff --git a/scripts/wsl_show_grants.py b/scripts/show_grants.py similarity index 95% rename from scripts/wsl_show_grants.py rename to scripts/show_grants.py index 3123c419..9d4c9e09 100644 --- a/scripts/wsl_show_grants.py +++ b/scripts/show_grants.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Show MySQL grants for MYSQL_USER from .env (WSL helper).""" +"""Show MySQL grants for MYSQL_USER from .env.""" import asyncio import os import sys diff --git a/scripts/start-dev.sh b/scripts/start-dev.sh index 400c112c..20653f97 100644 --- a/scripts/start-dev.sh +++ b/scripts/start-dev.sh @@ -1,10 +1,26 @@ #!/usr/bin/env bash -# Start Nexus local dev: Docker (mysql+redis) + uvicorn + optional Vite +# Start Nexus local dev: Docker (mysql+redis) + uvicorn +# Usage: bash scripts/start-dev.sh set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "${ROOT}" +docker_cmd() { + if docker info >/dev/null 2>&1; then + docker "$@" + else + sg docker -c "docker $(printf '%q ' "$@")" + fi +} + +redis_ping() { + if command -v redis-cli >/dev/null 2>&1; then + redis-cli -h 127.0.0.1 ping 2>/dev/null | grep -q PONG && return 0 + fi + docker_cmd exec nexus-redis-1 redis-cli ping 2>/dev/null | grep -q PONG +} + if ! command -v docker >/dev/null; then echo "Install docker.io first" >&2 exit 1 @@ -16,20 +32,31 @@ if [ ! -f .env ]; then fi echo "Starting MySQL + Redis..." -docker compose up -d mysql redis +docker_cmd compose up -d mysql redis echo "Waiting for MySQL..." for _ in $(seq 1 40); do - st=$(docker inspect -f '{{.State.Health.Status}}' nexus-mysql-1 2>/dev/null || echo starting) + st=$(docker_cmd inspect -f '{{.State.Health.Status}}' nexus-mysql-1 2>/dev/null || echo starting) [ "${st}" = "healthy" ] && break sleep 2 done if [ ! -d .venv ]; then - python3 -m venv .venv - .venv/bin/pip install -r requirements.txt -r requirements-dev.txt + bash scripts/ensure_venv.sh fi +if ! redis_ping; then + echo "Waiting for Redis..." + for _ in $(seq 1 30); do + redis_ping && break + sleep 1 + done +fi +redis_ping || { + echo "ERROR: Redis not responding (127.0.0.1:6379 / nexus-redis-1)" >&2 + exit 1 +} + if ! .venv/bin/python -c " import asyncio from sqlalchemy import text @@ -39,20 +66,25 @@ async def c(): n=(await s.execute(text('SELECT COUNT(*) FROM admins'))).scalar() print(n) asyncio.run(c()) -" 2>/dev/null | grep -q '^[1-9]'; then - echo "No admin — run: NEXUS_TEST_ADMIN_PASSWORD='your-pass' python3 scripts/seed_local_admin.py" +" 2>/dev/null | grep -qE '^[0-9]+$'; then + echo "No admin or DB not ready — run: NEXUS_TEST_ADMIN_PASSWORD='your-pass' python3 scripts/seed_local_admin.py" fi if ! ss -tlnp 2>/dev/null | grep -q ':8600'; then echo "Starting API on :8600..." nohup .venv/bin/uvicorn server.main:app --host 0.0.0.0 --port 8600 --reload \ > /tmp/nexus-uvicorn.log 2>&1 & - sleep 2 + sleep 3 +fi + +code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8600/health 2>/dev/null || echo "000") +if [ "${code}" != "200" ]; then + echo "WARN: /health → ${code} — see /tmp/nexus-uvicorn.log" +else + echo "Health: ok" fi echo "" echo "API: http://127.0.0.1:8600/app/" -echo "Health: curl http://127.0.0.1:8600/health" -echo "" -echo "Frontend dev (optional): cd frontend && npm run dev → http://localhost:3000/app/" +echo "Verify: bash scripts/local_verify.sh (full) | bash scripts/local_integration_smoke.sh" echo "Logs: tail -f /tmp/nexus-uvicorn.log" diff --git a/scripts/wsl_mcp_mysql.sh b/scripts/wsl_mcp_mysql.sh deleted file mode 100644 index db8134a6..00000000 --- a/scripts/wsl_mcp_mysql.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -# Cursor MCP: mysql-mcp-server via WSL (Node 20+ required for import attributes). -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT="$(cd "${SCRIPT_DIR}/.." && pwd)" -cd "${PROJECT}" - -NODE20="${HOME}/.local/node-v20.19.2/bin/node" -WIN_NODE="/mnt/c/nvm4w/nodejs/node.exe" - -# 1) WSL Node 20 — 可连 172.31.x 内网 MySQL -if [ -x "${NODE20}" ]; then - export PATH="$(dirname "${NODE20}"):${PATH}" - exec npx -y @yclenove/mysql-mcp-server -fi - -# 2) Windows Node 22(interop) -if [ -x "${WIN_NODE}" ]; then - WSL_USER="$(whoami)" - MCP_JS="/mnt/c/Users/${WSL_USER}/AppData/Roaming/npm/node_modules/@yclenove/mysql-mcp-server/dist/index.js" - if [ -f "${MCP_JS}" ]; then - exec "${WIN_NODE}" "${MCP_JS}" - fi -fi - -echo "ERROR: Need Node 20+. Run in WSL: bash scripts/wsl_install_node20.sh" >&2 -exit 1 diff --git a/scripts/wsl_start_dev.sh b/scripts/wsl_start_dev.sh deleted file mode 100644 index 16155e0f..00000000 --- a/scripts/wsl_start_dev.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -# Start Nexus FastAPI in WSL dev mode (reload). -set -euo pipefail -ROOT="$(cd "$(dirname "$0")/.." && pwd)" -cd "$ROOT" - -bash scripts/wsl_ensure_venv.sh -PY="${ROOT}/.venv/bin/python3" - -if ! redis-cli ping 2>/dev/null | grep -q PONG; then - echo "ERROR: Redis not responding. Run: sudo service redis-server start" - exit 1 -fi - -if [[ ! -f .env ]]; then - echo "WARN: No .env — app runs in INSTALL MODE only." - echo " Open http://127.0.0.1:8600/app/install.html after start" -fi - -echo "Starting Nexus on http://127.0.0.1:8600 ..." -exec "$PY" -m uvicorn server.main:app --host 127.0.0.1 --port 8600 --reload diff --git a/verify.py b/verify.py index d8e6e422..52abf093 100644 --- a/verify.py +++ b/verify.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""WSL Verification Script — validates all modules, routes, and security""" +"""Local verification script — validates modules, routes, and security""" import sys sys.path.insert(0, '.')