diff --git a/backend/.env.example b/backend/.env.example index f3e266fc..af6b0032 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,6 +1,6 @@ # 管理会计OS — 数据库配置 CMA_DB_USER=cma_user -CMA_DB_PASS=cma_pass_2026 +CMA_DB_PASS=__CHANGE_ME__ CMA_DB_HOST=127.0.0.1 CMA_DB_PORT=3306 CMA_DB_NAME=cma diff --git a/backend/app/database.py b/backend/app/database.py index 9e474534..7004aa64 100644 --- a/backend/app/database.py +++ b/backend/app/database.py @@ -7,8 +7,16 @@ import logging logger = logging.getLogger("cma") -DB_USER = os.getenv("CMA_DB_USER", "cma_user") -DB_PASS = os.getenv("CMA_DB_PASS", "cma_pass_2026") +# 2026-09-12 库访问治理(wecom-ops):统一从 backend/.env 读取凭据, +# 定时任务/脚本与 8010 API 同源(此前脚本吃硬编码 fallback,与 .env 不一致)。 +try: + from dotenv import load_dotenv as _load_dotenv + _load_dotenv(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".env")) +except Exception: # dotenv 缺失/文件不可读时不影响启动,由下方环境变量兜底 + pass + +DB_USER = os.getenv("CMA_DB_USER", "cma_reader") # 兜底=只读账号(最小权限) +DB_PASS = os.getenv("CMA_DB_PASS", "") # 无明文兜底:缺失即连接失败并报错 DB_HOST = os.getenv("CMA_DB_HOST", "127.0.0.1") DB_PORT = os.getenv("CMA_DB_PORT", "3306") DB_NAME = os.getenv("CMA_DB_NAME", "cma") diff --git a/backend/app/security/__pycache__/__init__.cpython-311.pyc b/backend/app/security/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index cb36a646..00000000 Binary files a/backend/app/security/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/backend/app/security/__pycache__/__init__.cpython-312.pyc b/backend/app/security/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index afb5c39f..00000000 Binary files a/backend/app/security/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/backend/app/security/__pycache__/captcha.cpython-311.pyc b/backend/app/security/__pycache__/captcha.cpython-311.pyc deleted file mode 100644 index 6e0c4d1f..00000000 Binary files a/backend/app/security/__pycache__/captcha.cpython-311.pyc and /dev/null differ diff --git a/backend/app/security/__pycache__/captcha.cpython-312.pyc b/backend/app/security/__pycache__/captcha.cpython-312.pyc deleted file mode 100644 index 7a673f2e..00000000 Binary files a/backend/app/security/__pycache__/captcha.cpython-312.pyc and /dev/null differ diff --git a/backend/app/services/__pycache__/__init__.cpython-311.pyc b/backend/app/services/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index c144fddb..00000000 Binary files a/backend/app/services/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/backend/app/services/__pycache__/__init__.cpython-312.pyc b/backend/app/services/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 1bdd3af7..00000000 Binary files a/backend/app/services/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/backend/app/services/__pycache__/knowledge_service.cpython-311.pyc b/backend/app/services/__pycache__/knowledge_service.cpython-311.pyc deleted file mode 100644 index 02330614..00000000 Binary files a/backend/app/services/__pycache__/knowledge_service.cpython-311.pyc and /dev/null differ diff --git a/backend/app/services/__pycache__/knowledge_service.cpython-312.pyc b/backend/app/services/__pycache__/knowledge_service.cpython-312.pyc deleted file mode 100644 index 528fb4d7..00000000 Binary files a/backend/app/services/__pycache__/knowledge_service.cpython-312.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/__init__.cpython-311.pyc b/backend/app/utils/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index 21e7b583..00000000 Binary files a/backend/app/utils/__pycache__/__init__.cpython-311.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/__init__.cpython-312.pyc b/backend/app/utils/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 74699bb3..00000000 Binary files a/backend/app/utils/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/cache.cpython-311.pyc b/backend/app/utils/__pycache__/cache.cpython-311.pyc deleted file mode 100644 index 134d5746..00000000 Binary files a/backend/app/utils/__pycache__/cache.cpython-311.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/cache.cpython-312.pyc b/backend/app/utils/__pycache__/cache.cpython-312.pyc deleted file mode 100644 index 8daaf094..00000000 Binary files a/backend/app/utils/__pycache__/cache.cpython-312.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/calc_engine.cpython-311.pyc b/backend/app/utils/__pycache__/calc_engine.cpython-311.pyc deleted file mode 100644 index 1f8cff61..00000000 Binary files a/backend/app/utils/__pycache__/calc_engine.cpython-311.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/calc_engine.cpython-312.pyc b/backend/app/utils/__pycache__/calc_engine.cpython-312.pyc deleted file mode 100644 index 77e5a090..00000000 Binary files a/backend/app/utils/__pycache__/calc_engine.cpython-312.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/cost_engine.cpython-311.pyc b/backend/app/utils/__pycache__/cost_engine.cpython-311.pyc deleted file mode 100644 index 04035c3b..00000000 Binary files a/backend/app/utils/__pycache__/cost_engine.cpython-311.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/cost_engine.cpython-312.pyc b/backend/app/utils/__pycache__/cost_engine.cpython-312.pyc deleted file mode 100644 index d845a5aa..00000000 Binary files a/backend/app/utils/__pycache__/cost_engine.cpython-312.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/deviation_engine.cpython-311.pyc b/backend/app/utils/__pycache__/deviation_engine.cpython-311.pyc deleted file mode 100644 index 479f95c7..00000000 Binary files a/backend/app/utils/__pycache__/deviation_engine.cpython-311.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/deviation_engine.cpython-312.pyc b/backend/app/utils/__pycache__/deviation_engine.cpython-312.pyc deleted file mode 100644 index a95d5aeb..00000000 Binary files a/backend/app/utils/__pycache__/deviation_engine.cpython-312.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/notifier.cpython-311.pyc b/backend/app/utils/__pycache__/notifier.cpython-311.pyc deleted file mode 100644 index 368239fc..00000000 Binary files a/backend/app/utils/__pycache__/notifier.cpython-311.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/notifier.cpython-312.pyc b/backend/app/utils/__pycache__/notifier.cpython-312.pyc deleted file mode 100644 index 1237f410..00000000 Binary files a/backend/app/utils/__pycache__/notifier.cpython-312.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/predict_engine.cpython-311.pyc b/backend/app/utils/__pycache__/predict_engine.cpython-311.pyc deleted file mode 100644 index 468cf9aa..00000000 Binary files a/backend/app/utils/__pycache__/predict_engine.cpython-311.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/predict_engine.cpython-312.pyc b/backend/app/utils/__pycache__/predict_engine.cpython-312.pyc deleted file mode 100644 index de0015bb..00000000 Binary files a/backend/app/utils/__pycache__/predict_engine.cpython-312.pyc and /dev/null differ diff --git a/backend/app/utils/__pycache__/scenario_engine.cpython-312.pyc b/backend/app/utils/__pycache__/scenario_engine.cpython-312.pyc deleted file mode 100644 index 7d851042..00000000 Binary files a/backend/app/utils/__pycache__/scenario_engine.cpython-312.pyc and /dev/null differ diff --git a/backend/scripts/clean_kpi_data_governance.py b/backend/scripts/clean_kpi_data_governance.py index 5f5bb5e9..5f611b85 100644 --- a/backend/scripts/clean_kpi_data_governance.py +++ b/backend/scripts/clean_kpi_data_governance.py @@ -29,10 +29,21 @@ CMA 数据治理 P0-2 数据清洗脚本(2026-08-15) """ import pymysql +# 2026-09-12 库访问治理(ops):口令改从 .env 读取,清除硬编码 +import os as _os_gov +try: + from dotenv import load_dotenv as _ld_gov + _ld_gov('/root/cma-management/backend/.env', override=False) +except Exception: + pass +_CMA_DB_PASS = _os_gov.getenv('CMA_DB_PASS', '') +_CMA_DB_USER = _os_gov.getenv('CMA_DB_USER', '') +_CMA_DB_HOST = _os_gov.getenv('CMA_DB_HOST', '127.0.0.1') + def main(): - conn = pymysql.connect(host="127.0.0.1", port=3306, user="cma_user", - password="cma_pass_2026", database="cma", charset="utf8mb4") + conn = pymysql.connect(host="127.0.0.1", port=3306, user=_CMA_DB_USER, + password=_CMA_DB_PASS, database="cma", charset="utf8mb4") cur = conn.cursor(pymysql.cursors.DictCursor) def q(sql, args=None): diff --git a/backend/scripts/cleanup_kpi_encoding.py b/backend/scripts/cleanup_kpi_encoding.py index 80e9a404..cdd22d00 100644 --- a/backend/scripts/cleanup_kpi_encoding.py +++ b/backend/scripts/cleanup_kpi_encoding.py @@ -3,11 +3,21 @@ import pymysql import os import logging +# 2026-09-12 库访问治理(ops):凭据从 backend/.env 读取,无明文兜底 +import os +try: + from dotenv import load_dotenv as _ld_gov + _ld_gov('/root/cma-management/backend/.env') +except Exception: + pass +if not os.getenv('CMA_DB_PASS'): + raise SystemExit('ERROR: 缺少 CMA_DB_PASS(2026-09-12 凭据治理已移除明文兜底)') + logging.basicConfig(level=logging.INFO) logger = logging.getLogger("encoding-cleanup") DB_USER = os.getenv("CMA_DB_USER", "cma_user") -DB_PASS = os.getenv("CMA_DB_PASS", "cma_pass_2026") +DB_PASS = os.environ["CMA_DB_PASS"] DB_HOST = os.getenv("CMA_DB_HOST", "127.0.0.1") DB_PORT = int(os.getenv("CMA_DB_PORT", "3306")) DB_NAME = os.getenv("CMA_DB_NAME", "cma") diff --git a/backend/scripts/fix_kpi_governance.py b/backend/scripts/fix_kpi_governance.py index 1efc074b..f360ca68 100644 --- a/backend/scripts/fix_kpi_governance.py +++ b/backend/scripts/fix_kpi_governance.py @@ -8,6 +8,17 @@ import sys import pymysql +# 2026-09-12 库访问治理(ops):口令改从 .env 读取,清除硬编码 +import os as _os_gov +try: + from dotenv import load_dotenv as _ld_gov + _ld_gov('/root/cma-management/backend/.env', override=False) +except Exception: + pass +_CMA_DB_PASS = _os_gov.getenv('CMA_DB_PASS', '') +_CMA_DB_USER = _os_gov.getenv('CMA_DB_USER', '') +_CMA_DB_HOST = _os_gov.getenv('CMA_DB_HOST', '127.0.0.1') + PLACEHOLDERS = ("待补充", "待指定", "待完善", "待定", "暂无", "TBD", "tbd", "-", "--", "N/A", "n/a") DIM_PREFIX = {"finance": "F", "customer": "C", "process": "P", "learning": "L"} DIM_FORMULA = { @@ -82,8 +93,8 @@ def audit(kpis): def main(): apply = "--apply" in sys.argv - conn = pymysql.connect(host="127.0.0.1", port=3306, user="cma_user", - password="cma_pass_2026", database="cma", charset="utf8mb4") + conn = pymysql.connect(host="127.0.0.1", port=3306, user=_CMA_DB_USER, + password=_CMA_DB_PASS, database="cma", charset="utf8mb4") cur = conn.cursor(pymysql.cursors.DictCursor) cur.execute("SELECT * FROM kpi_definitions WHERE status='active'") kpis = cur.fetchall() diff --git a/backend/scripts/import_cma_knowledge.py b/backend/scripts/import_cma_knowledge.py index 6a50d940..b4039879 100644 --- a/backend/scripts/import_cma_knowledge.py +++ b/backend/scripts/import_cma_knowledge.py @@ -2,7 +2,18 @@ """将CMA战略地图完整文档导入知识库""" import pymysql, re -DB = dict(host='127.0.0.1', port=3306, user='cma_user', password='cma_pass_2026', database='cma', charset='utf8mb4') +# 2026-09-12 库访问治理(ops):口令改从 .env 读取,清除硬编码 +import os as _os_gov +try: + from dotenv import load_dotenv as _ld_gov + _ld_gov('/root/cma-management/backend/.env', override=False) +except Exception: + pass +_CMA_DB_PASS = _os_gov.getenv('CMA_DB_PASS', '') +_CMA_DB_USER = _os_gov.getenv('CMA_DB_USER', '') +_CMA_DB_HOST = _os_gov.getenv('CMA_DB_HOST', '127.0.0.1') + +DB = dict(host='127.0.0.1', port=3306, user=_CMA_DB_USER, password=_CMA_DB_PASS, database='cma', charset='utf8mb4') DOC = "/root/CMA_Strategy_Map_完整分析.md" diff --git a/backend/scripts/import_product_sales.py b/backend/scripts/import_product_sales.py index 83315f8d..4cab4993 100644 --- a/backend/scripts/import_product_sales.py +++ b/backend/scripts/import_product_sales.py @@ -6,11 +6,22 @@ import os import re import pymysql +# 2026-09-12 库访问治理(ops):口令改从 .env 读取,清除硬编码 +import os as _os_gov +try: + from dotenv import load_dotenv as _ld_gov + _ld_gov('/root/cma-management/backend/.env', override=False) +except Exception: + pass +_CMA_DB_PASS = _os_gov.getenv('CMA_DB_PASS', '') +_CMA_DB_USER = _os_gov.getenv('CMA_DB_USER', '') +_CMA_DB_HOST = _os_gov.getenv('CMA_DB_HOST', '127.0.0.1') + # DB连接 DB_CONFIG = { 'host': '127.0.0.1', - 'user': 'cma_user', - 'password': 'cma_pass_2026', + 'user': _CMA_DB_USER, + 'password': _CMA_DB_PASS, 'database': 'cma', 'charset': 'utf8mb4', } diff --git a/backend/scripts/migrate_data_governance.py b/backend/scripts/migrate_data_governance.py index 5c9f8cb2..79bd80b2 100644 --- a/backend/scripts/migrate_data_governance.py +++ b/backend/scripts/migrate_data_governance.py @@ -3,11 +3,21 @@ import pymysql import os import logging +# 2026-09-12 库访问治理(ops):凭据从 backend/.env 读取,无明文兜底 +import os +try: + from dotenv import load_dotenv as _ld_gov + _ld_gov('/root/cma-management/backend/.env') +except Exception: + pass +if not os.getenv('CMA_DB_PASS'): + raise SystemExit('ERROR: 缺少 CMA_DB_PASS(2026-09-12 凭据治理已移除明文兜底)') + logging.basicConfig(level=logging.INFO) logger = logging.getLogger("data-governance") DB_USER = os.getenv("CMA_DB_USER", "cma_user") -DB_PASS = os.getenv("CMA_DB_PASS", "cma_pass_2026") +DB_PASS = os.environ["CMA_DB_PASS"] DB_HOST = os.getenv("CMA_DB_HOST", "127.0.0.1") DB_PORT = int(os.getenv("CMA_DB_PORT", "3306")) DB_NAME = os.getenv("CMA_DB_NAME", "cma") diff --git a/backend/scripts/seed_finance_bot_kpis.py b/backend/scripts/seed_finance_bot_kpis.py index 37e0b56c..8908b45f 100644 --- a/backend/scripts/seed_finance_bot_kpis.py +++ b/backend/scripts/seed_finance_bot_kpis.py @@ -7,8 +7,18 @@ import os import sys from datetime import datetime +# 2026-09-12 库访问治理(ops):凭据从 backend/.env 读取,无明文兜底 +import os +try: + from dotenv import load_dotenv as _ld_gov + _ld_gov('/root/cma-management/backend/.env') +except Exception: + pass +if not os.getenv('CMA_DB_PASS'): + raise SystemExit('ERROR: 缺少 CMA_DB_PASS(2026-09-12 凭据治理已移除明文兜底)') + DB_USER = os.getenv("CMA_DB_USER", "cma_user") -DB_PASS = os.getenv("CMA_DB_PASS", "cma_pass_2026") +DB_PASS = os.environ["CMA_DB_PASS"] DB_HOST = os.getenv("CMA_DB_HOST", "127.0.0.1") DB_PORT = int(os.getenv("CMA_DB_PORT", "3306")) DB_NAME = os.getenv("CMA_DB_NAME", "cma") diff --git a/backend/scripts/verify_dashboard_isolation.py b/backend/scripts/verify_dashboard_isolation.py index 12adef57..a3d9be1b 100644 --- a/backend/scripts/verify_dashboard_isolation.py +++ b/backend/scripts/verify_dashboard_isolation.py @@ -5,6 +5,16 @@ import json import urllib.request import pymysql +# 2026-09-12 库访问治理(ops):凭据从 backend/.env 读取,无明文兜底 +import os +try: + from dotenv import load_dotenv as _ld_gov + _ld_gov('/root/cma-management/backend/.env') +except Exception: + pass +if not os.getenv('CMA_DB_PASS'): + raise SystemExit('ERROR: 缺少 CMA_DB_PASS(2026-09-12 凭据治理已移除明文兜底)') + BASE = "http://127.0.0.1:8010" @@ -39,7 +49,9 @@ def main(): reminders = d.get("reminders", []) print(f"2. my-dashboard OK: action_plans={len(plans)} 条, reminders={len(reminders)} 条") - conn = pymysql.connect(host="127.0.0.1", user="cma_user", password="cma_pass_2026", + # 账号与口令同源(backend/.env)——硬编码 cma_user + 应用口令会账号/口令错配 + conn = pymysql.connect(host="127.0.0.1", user=os.getenv("CMA_DB_USER", "cma_user"), + password=os.environ.get("CMA_DB_PASS", ""), database="cma", charset="utf8mb4") cur = conn.cursor() diff --git a/backend/scripts/verify_knowledge_partition_e2e.py b/backend/scripts/verify_knowledge_partition_e2e.py index 54a4e0bf..9eac0162 100644 --- a/backend/scripts/verify_knowledge_partition_e2e.py +++ b/backend/scripts/verify_knowledge_partition_e2e.py @@ -13,12 +13,15 @@ with open('/root/cma-management/backend/.env') as f: k, v = line.split('=', 1) env[k.strip()] = v.strip().strip('"').strip("'") +if not env.get('CMA_DB_PASS'): + raise SystemExit('ERROR: 缺少 CMA_DB_PASS(2026-09-12 凭据治理已移除明文兜底)') + import pymysql conn = pymysql.connect( host=env.get('CMA_DB_HOST', '127.0.0.1'), port=int(env.get('CMA_DB_PORT', '3306')), user=env.get('CMA_DB_USER', 'cma_user'), - password=env.get('CMA_DB_PASS', 'cma_pass_2026'), + password=env.get('CMA_DB_PASS'), database=env.get('CMA_DB_NAME', 'cma'), charset='utf8mb4', ) diff --git a/backend/tests/__pycache__/__init__.cpython-312.pyc b/backend/tests/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 3bcf3d6a..00000000 Binary files a/backend/tests/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/backend/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc b/backend/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc deleted file mode 100644 index 80e7ac14..00000000 Binary files a/backend/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc and /dev/null differ diff --git a/backend/tests/__pycache__/test_auth.cpython-312-pytest-9.0.3.pyc b/backend/tests/__pycache__/test_auth.cpython-312-pytest-9.0.3.pyc deleted file mode 100644 index f233ffad..00000000 Binary files a/backend/tests/__pycache__/test_auth.cpython-312-pytest-9.0.3.pyc and /dev/null differ diff --git a/check.sh b/check.sh index 4d7dbbc2..c48eae60 100755 --- a/check.sh +++ b/check.sh @@ -23,7 +23,12 @@ fi # 3. 数据库 echo "[3] 数据库" -if mysql -ucma_user -pcma_pass_2026 -h127.0.0.1 cma -e "SELECT 1;" &>/dev/null; then +# 2026-09-12 凭据治理:账号必须与口令同源(backend/.env 已切 cma_api),禁止硬编码账号名 +CMA_DB_USER="${CMA_DB_USER:-$(grep -m1 '^CMA_DB_USER=' /root/cma-management/backend/.env 2>/dev/null | cut -d= -f2- | tr -d '"')}" +CMA_DB_PASS="${CMA_DB_PASS:-$(grep -m1 '^CMA_DB_PASS=' /root/cma-management/backend/.env 2>/dev/null | cut -d= -f2- | tr -d '"')}" +if [ -z "$CMA_DB_USER" ] || [ -z "$CMA_DB_PASS" ]; then + echo " ! 未取到 CMA_DB_USER/PASS(2026-09-12 凭据治理:无明文兜底),跳过直连自检" +elif mysql -u"$CMA_DB_USER" -p"$CMA_DB_PASS" -h127.0.0.1 cma -e "SELECT 1;" &>/dev/null; then echo " ✓ MariaDB 连接正常" else echo " ✗ MariaDB 连接失败" diff --git a/scripts/sync_wecom_users.py b/scripts/sync_wecom_users.py index 22c0fc20..230f0574 100644 --- a/scripts/sync_wecom_users.py +++ b/scripts/sync_wecom_users.py @@ -12,12 +12,23 @@ import urllib.request import pymysql import hashlib +# 2026-09-12 库访问治理(ops):口令改从 .env 读取,清除硬编码 +import os as _os_gov +try: + from dotenv import load_dotenv as _ld_gov + _ld_gov('/root/cma-management/backend/.env', override=False) +except Exception: + pass +_CMA_DB_PASS = _os_gov.getenv('CMA_DB_PASS', '') +_CMA_DB_USER = _os_gov.getenv('CMA_DB_USER', '') +_CMA_DB_HOST = _os_gov.getenv('CMA_DB_HOST', '127.0.0.1') + # ==== 配置 ==== MCP_URL = "http://127.0.0.1:18900/call" DB_HOST = "127.0.0.1" DB_PORT = 3306 -DB_USER = "cma_user" -DB_PASS = "cma_pass_2026" +DB_USER = _CMA_DB_USER +DB_PASS = _CMA_DB_PASS DB_NAME = "cma" DEFAULT_PASSWORD = "admin123"