From b8f4a3d5432566e69e26e96dc4bbf11906131d4d Mon Sep 17 00:00:00 2001 From: Hermes CI Fix Date: Sat, 12 Sep 2026 23:34:35 +0800 Subject: [PATCH] =?UTF-8?q?chore(security):=20=E5=87=AD=E6=8D=AE=E6=B2=BB?= =?UTF-8?q?=E7=90=86=E6=94=B6=E5=8F=A3=20=E2=80=94=20=E6=B8=85=E9=99=A4?= =?UTF-8?q?=E7=A1=AC=E7=BC=96=E7=A0=81DB=E8=B4=A6=E5=8F=B7/=E5=8F=A3?= =?UTF-8?q?=E4=BB=A4=EF=BC=8C=E8=84=9A=E6=9C=AC=E4=B8=8EAPI=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E4=BB=8E=20backend/.env=20=E8=AF=BB=E5=8F=96(?= =?UTF-8?q?=E6=97=A0=E6=98=8E=E6=96=87=E5=85=9C=E5=BA=95)=EF=BC=9B?= =?UTF-8?q?=E5=8F=96=E6=B6=88=E8=B7=9F=E8=B8=AA=20.pyc=20=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E4=BA=A7=E7=89=A9=20(credential-governance-20260912)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/.env.example | 2 +- backend/app/database.py | 12 ++++++++++-- .../__pycache__/__init__.cpython-311.pyc | Bin 162 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 150 -> 0 bytes .../__pycache__/captcha.cpython-311.pyc | Bin 11350 -> 0 bytes .../__pycache__/captcha.cpython-312.pyc | Bin 10557 -> 0 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 162 -> 0 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 150 -> 0 bytes .../knowledge_service.cpython-311.pyc | Bin 17159 -> 0 bytes .../knowledge_service.cpython-312.pyc | Bin 15900 -> 0 bytes .../utils/__pycache__/__init__.cpython-311.pyc | Bin 159 -> 0 bytes .../utils/__pycache__/__init__.cpython-312.pyc | Bin 147 -> 0 bytes .../app/utils/__pycache__/cache.cpython-311.pyc | Bin 4912 -> 0 bytes .../app/utils/__pycache__/cache.cpython-312.pyc | Bin 4289 -> 0 bytes .../__pycache__/calc_engine.cpython-311.pyc | Bin 6628 -> 0 bytes .../__pycache__/calc_engine.cpython-312.pyc | Bin 6014 -> 0 bytes .../__pycache__/cost_engine.cpython-311.pyc | Bin 15490 -> 0 bytes .../__pycache__/cost_engine.cpython-312.pyc | Bin 13731 -> 0 bytes .../deviation_engine.cpython-311.pyc | Bin 14182 -> 0 bytes .../deviation_engine.cpython-312.pyc | Bin 16098 -> 0 bytes .../utils/__pycache__/notifier.cpython-311.pyc | Bin 13775 -> 0 bytes .../utils/__pycache__/notifier.cpython-312.pyc | Bin 14930 -> 0 bytes .../__pycache__/predict_engine.cpython-311.pyc | Bin 9514 -> 0 bytes .../__pycache__/predict_engine.cpython-312.pyc | Bin 8363 -> 0 bytes .../__pycache__/scenario_engine.cpython-312.pyc | Bin 7615 -> 0 bytes backend/scripts/clean_kpi_data_governance.py | 15 +++++++++++++-- backend/scripts/cleanup_kpi_encoding.py | 12 +++++++++++- backend/scripts/fix_kpi_governance.py | 15 +++++++++++++-- backend/scripts/import_cma_knowledge.py | 13 ++++++++++++- backend/scripts/import_product_sales.py | 15 +++++++++++++-- backend/scripts/migrate_data_governance.py | 12 +++++++++++- backend/scripts/seed_finance_bot_kpis.py | 12 +++++++++++- backend/scripts/verify_dashboard_isolation.py | 14 +++++++++++++- .../scripts/verify_knowledge_partition_e2e.py | 5 ++++- .../tests/__pycache__/__init__.cpython-312.pyc | Bin 606 -> 0 bytes .../conftest.cpython-312-pytest-9.0.3.pyc | Bin 8553 -> 0 bytes .../test_auth.cpython-312-pytest-9.0.3.pyc | Bin 10631 -> 0 bytes check.sh | 7 ++++++- scripts/sync_wecom_users.py | 15 +++++++++++++-- 39 files changed, 131 insertions(+), 18 deletions(-) delete mode 100644 backend/app/security/__pycache__/__init__.cpython-311.pyc delete mode 100644 backend/app/security/__pycache__/__init__.cpython-312.pyc delete mode 100644 backend/app/security/__pycache__/captcha.cpython-311.pyc delete mode 100644 backend/app/security/__pycache__/captcha.cpython-312.pyc delete mode 100644 backend/app/services/__pycache__/__init__.cpython-311.pyc delete mode 100644 backend/app/services/__pycache__/__init__.cpython-312.pyc delete mode 100644 backend/app/services/__pycache__/knowledge_service.cpython-311.pyc delete mode 100644 backend/app/services/__pycache__/knowledge_service.cpython-312.pyc delete mode 100644 backend/app/utils/__pycache__/__init__.cpython-311.pyc delete mode 100644 backend/app/utils/__pycache__/__init__.cpython-312.pyc delete mode 100644 backend/app/utils/__pycache__/cache.cpython-311.pyc delete mode 100644 backend/app/utils/__pycache__/cache.cpython-312.pyc delete mode 100644 backend/app/utils/__pycache__/calc_engine.cpython-311.pyc delete mode 100644 backend/app/utils/__pycache__/calc_engine.cpython-312.pyc delete mode 100644 backend/app/utils/__pycache__/cost_engine.cpython-311.pyc delete mode 100644 backend/app/utils/__pycache__/cost_engine.cpython-312.pyc delete mode 100644 backend/app/utils/__pycache__/deviation_engine.cpython-311.pyc delete mode 100644 backend/app/utils/__pycache__/deviation_engine.cpython-312.pyc delete mode 100644 backend/app/utils/__pycache__/notifier.cpython-311.pyc delete mode 100644 backend/app/utils/__pycache__/notifier.cpython-312.pyc delete mode 100644 backend/app/utils/__pycache__/predict_engine.cpython-311.pyc delete mode 100644 backend/app/utils/__pycache__/predict_engine.cpython-312.pyc delete mode 100644 backend/app/utils/__pycache__/scenario_engine.cpython-312.pyc delete mode 100644 backend/tests/__pycache__/__init__.cpython-312.pyc delete mode 100644 backend/tests/__pycache__/conftest.cpython-312-pytest-9.0.3.pyc delete mode 100644 backend/tests/__pycache__/test_auth.cpython-312-pytest-9.0.3.pyc 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 cb36a64676b9e021ec4c55098c42e28dd316d086..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162 zcmZ3^%ge<81b*B~Ss?l`h=2h`DC095kTIPhg&~+hlhJP_LlF~@{~09t%T&K8Kfgpj zIX6)^H!&|UJvBEquS7p7F*!RmFGWAGpg_MkHMz7Xv!qf#K0Y%qvm`!Vub}c5hfQvN gN@-52T@fqL6p%f|{6OLZGb1D82L>2X#0(Sz0G|dW0RR91 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 afb5c39fe63e89aeee59e394e711dc1d95311fdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 150 zcmX@j%ge<81b*B~Ss?l`h(HIQS%4zb87dhx8U0o=6fpsLpFwJVnd%qi=a=Xw=O*gr zCgvrkr{<>SmFOoWCTFMSrRXOX6zCVHCYKgvmQ?D;$7kkcmc+;F6;%G>u*uC&Da}c> XD`Ewj!U)90AjU^#Mn=XWW*`dy9Z@3n 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 6e0c4d1f5bc8ac1a59a982faa079fe9fb113a459..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11350 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 QFV%FeV<_t{Q)QC=2j%;cqP$Dgn%5Y>$ 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 DzG%%| 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 c144fddb29ae18da736659332567f3e113233426..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162 zcmZ3^%ge<81g1XPSs?l`h=2h`DC095kTIPhg&~+hlhJP_LlF~@{~09t%T&K8Kfgpj zIX6)^H!&|UJvBEquS7p7F*!RmFGWAGpg_MkwWusJIki|nK0Y%qvm`!Vub}c5hfQvN gN@-52T@fqL6p%f|{6OLZGb1D82L>2X#0(Sz0JqX59smFU 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 1bdd3af7122deb84cd35ea504270b749274a841c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 150 zcmX@j%ge<81g1XPSs?l`h(HIQS%4zb87dhx8U0o=6fpsLpFwJVnd%qi=a=Xw=O*gr zCgvrkr{<>SmFOoWCTFMSrRXOX6zCVH7L{ctrxxqS$7kkcmc+;F6;%G>u*uC&Da}c> XD`Ewj!U)90AjU^#Mn=XWW*`dyG?^n3 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 0233061475ff5115124f3584d583a19ed4a67c6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17159 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 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 528fb4d7eba7d51bf6f17412f2c7cc4007df8531..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15900 zcmeHuX>e0ln&`cfu6B8mPszHTesZDLy zG-&K;4QV(nv!&ZJ8Zzve4ViXrgVwHV(Ao73dV5ww7Di@TE*nkY9?>Hl-3-e8VcwVI*n1$=?q0@FbamsgZfZj$P^)HyPVF1TGME) zkVESLhaP?ihn&tjAZeJ6F(leZ=xoR}C1AP2A)lBAg37rpV9y6aVfb`7RC{TGJq-Wu^pWQGUM!~mDJqk5bv|UXXLEn$W zFcblXX@Fr)QhGY1jY(+(q)S^x#+mN_35z^_`u&NEhax?F6Cdo2^uG~)ebDfG?=i#p zg~9ReLt|G?PFxtQtB)MrJNDVZi3>yFtA~`zv5~8Wx)!E+m4jvs^=`Y}%v#%+XIRH> zE6uQm@skIV>qq)8hdVy`{h?okdwdW^`a2MO(06yg4_c26zY*!XI5zB!oF9yM&!GInU3^33f(pa< z$Xk(j4}^~%4}aJf-Ukg%KHXZsX@enr@Z<51MrH!kxx1zdoL;% z0)oztNdNh}Z+$U#_0;&=CjbH8Rm)S^i^12o@LbDBESv}))Lc%EG zB-`E17EWSrrcFjEm$tsyvB$>HjZE!srrE`1#MAsDc*FSuZf+2&^2G#0zLVyA%CO^XO(?DGMBKf~Q`ta`dSncl*~c*d7bPh9%t*zo1# zqPlv1;>lEtrVrR)F~gs}KlXV)poQHFUl@!G36++%KelmrLtsT=L&o=A z2_L>(625xy?%+sbPoQ1+>i)5-gFqSxxpLx*x1b(6ARq1f2$yWr5BihQsya^yVV ziS(ZaI=y@BLb$6BNLa}a0O)J{O~7$-LHR;x5b=%xkt0&Lcq!8NCMrF4dhGI{u@Uds zXB~g=?w$DLNci=u;Sct~IFzsxJTkNt9lbDo9%er5<7M~;6M?(P8~ z{Mo_q3n1S^9%f{DwR+-a-b`Ymfsr~D4bNZw|FMxz;oP9pg7*XlF#gV^$eZu;`%=QMV5E28?%_93*LV?2VCOh#3+u4AxHuU) z1P-^0ld_D<%{E(r0OOwup#AWhoCdk;2@>R@D<*viqA9s%tO?@I=VJNoA_d{11YAv0 z0ZPOk^1N7(W{ZgZAUR(Z6U1?GulNu}5$$4+xJi+yEkHCyOFg1@h*Kh3M$7v}w1QT; zuv|wqXcgqBJveR@(Hc69PNy^asq>lV05|&f6S00Iv3?{TNt1>zOAgP)677_SY7(@A zqzbgwN;HzfY-t^mc`57Zt%Oi3WqB5zEtFeCv;_SV()%Huye1@3Pb?*lcERr@_$g)( z^9fu>0_%q7vy`9+C%H#N65C+ENTOBpig+8bhnzvUGK9g;B-oO6sY@%Qo3aEb5z{#y zDOzJ;e-J)e(k^{X+M3PBd&oTmkNZRM9@3cWo(8RXW*q0m)z7R=X2)DcO>ONn^|iI@ zO;BQ5U%RbMI zdw!*5huKvLaElGtxue##AL%)(dZByK0eu5LVe0)4-E!b-q`8!3*m zgP^x@aytkNb0gyf1TK~_+c_0r!BWr7GMv(Ge#PW+>|~mqfLXSKF@rMTXV*5=n(DXJZ?1jX^vtt$Pd~GnEk+%Qp*^RleZ|6H zDac7}j>blYEwB_cY;8*=tmiLRg@iu0cX`k9w;t`N3F&fr zm-Q^`Tk8`IxPrPe-==`Ba#Xi4pj$Y!c9;$7R*vdc2Xw2iwfdjk9MnDcr(!fbevsed zL4F?<0ow1QVpQ-wU&4p?aQUCVDkHJ7fBkWC zm0WuL2?@YA#3VGlAt4bgC85p@Ifj+eRfVz}8RROR`bMSj&fR?EeuDwn_X6$CB~a!xCDWCIZ96&Kzj5N9?>hL zQ&0Yc~dF}?>A*9@&zb$ zD_R6HTafT_j~t{Gl~1@3yTYF*ZlBWB&Kh7EB3jxE7IYhw!bqs5f>_0*h(;q!vEFQc z>injnq{cB&m_O`3ecJiN|NpMZz9|1X~ag+~F@?;wa5fs3>&+g0uAAE7&?NBJXkmoon+=}y_SAhFT{ z{AT$0zVVS0 zyvkwVZ3WzfMSHgzjAS)vGoaj<%ub8dy3tw&61hzbY8)puTaZ?EpPT^-lEejC7KC7A zu#ZAZPU~AP2^2fIg9V+-^l~dF zh5tc2X4X>Qp6HgnnfI* zO+)?4VUVU~Gx!%UWC7I>bUcR@aH0|`&57Wr!V@;}^V0AMLFs!6&=@r=+I)5?3YHcB;v5-ad$E7i^ zxLDXJ6OWO#KxQqj56s<5fXbuF_*yyh*s|UydY%aCW_njamO|Af@01@a49ch7R-|`k zA5)KJJQB!w#J4z*G4E2@=z_I@1#55C2NpaNRBXDf$n4BLRyL|N2DHXeZFxXj9@JI_ z74vQ@)SbE`Sy2T+DWYjaT84LZC|&n0p`lbA;!svjhccu}>#BOaYAi$FtL#zsEj(Ry zqH3u2Rz_7vbto^tZ&BZ>zMS**Lz(Bc3|W5l;$ZDC8^~MPvF;8iLz+%aNM9IQu=vx8 zUsrUm>fPA0aa3Ox(3joPS6q8Jl%3bx)YBBoD?B~@#B_hI(U<94cyYzq6~0P;c2y|b za8D)8QT`u7s!&DKVLZ_iVa~bzD@F_E2MXq2S~0qCZD8TrpnTnJg{D(~)ZYL6Y10YQ zCC%u(Cj;=m=*gg>nqMCIXvT~{#*6`XAfxR3j?s$hKt=Vn`as2+pkgh*Jab01vjW;# z{2~RlbAyU9VR=*p^q)b@F8h{{Q>uWxxP$6=r7t%mOtK)fX!+=(ny(ktbk~mRX9n~$ zNA(o}eZ?*PyqhJVto+fe*@3Ltq3mhh4SnpuoPm7be7~+dlv^~KJ2#L!_v_sGK6Yr) z&?oZ9^t9 zI+K$=UIAhR#ko>A?Si8WR6YwJaMNBh>t=y>J~YOM=mG3nqoZPjW}Df^R>#ru7oVN9s*;` zudaIpeQ?67lYZz7by) znuZU4GB$GjCBuDEX_TNUH6$!7nS=l$w!-r8?6^ZS+z z%nxSH`j(JVD>|tTvSUF=rRmt-S=E>OwW>Iz&g|OIxuLJRZ(-j~Ux{za*-~HO(54}F zc+N+jq2_BfH?=p{{HE|`nt#hSf5VIZmzY4qcK^0Uf8LJYs;wbSdbhN*p>OHenv&F* zo*fnqFa1n4)P8N{HTLGLFI%te^l#eie{QS)d2`^om;IY9ev94T+~VKW8fb3w+h6s+ z>hb5b|5p9logW+75be)<^tbBAq8gYH$OCmo*YeKg-OmM81%62ZOT+3}5ZwqLatZE- z-(&@xf8HqxDtU5^SWOp{^Pg~@Qt^dEtyC^bn#2lo40|etSui}>Nie*C(*bY#AHbK8 z8JcQLai#j9V~W>mLK@AK4>$rkUsJvZ#+kxEOt?r>8H1@@fWpk;Bh8u8B_xG9?chXp zl1E?jh?)>TnexGi!6=^kK`wG{P5HnXo62~Tq#89~FidF9 zb~l5RT3)rosvfl)UE_c|9ScS96T%ITF_T>j-C(VdU56mVfY^;FKvI%@9tGP_umJ@w z2*82HfMQB*x3ZwmVK#)+H>}8UYEabNW}6B3#kwKiNMS9JlYnOF8HhO)&!99Wq=X6;*>)&B0zcH?~|plXx1CX}A(T@%t|eoLfL=^f-9bz0Y&&NauL52~l# z*62F799z>{*HbsJ>x^sA70}NOYRYbFvO1qXwxie4;~32@4P=)Fv&({-^4l71=W|E4 zf-sAMo=^%=-t^JDvOr#0DBp0p`~+w*d8ef(q@b-8rGd7l zNsng2IHJ=CwccCzA6Vzzw~DICB5%m6H4t&?7M9s9FlP&5-ol5D3T7w%1Ur%ZMII+< z;+Dfhc*Gv5V8yq~TygR1k$FHFikHYe6gvaFCnQ*=a$zWm7%NRwD%+G6(~^9ozEG#A zHqh4UvJw{2ODdQX zSj)Wn1hE?Nlea`iH4-RoSAl;=3~Prh`fQ=!M2t$&olnxN;{K?lytrD2yiy+N`Sf$K zH3Uxqk&=NWsbo+ig%3+$ge3A0rSMOAk}$a946dm-F?Io>Gw}Xo;{DNj)T!nPs$P;W zz@x^uLf^rS&~Gf@M?mYehi7;?_uqmP;_qPK#ur``@FqRn)zV;ow^r_fdliW6aL=&= zVvF1E2L55)&7gZuCE_2|Y@@RZLnwvq)+z&TY^XHw%>jrZ04RYX-Y8))R2kq#7jE*= zE%3!d;BA1rQ$xvuc?*`5&s$PHe?bW#;FDVyEJ`HiEx~XCbx9mIb|b?(1N`kz}@k|@P*H+3>&TA!OpPAdE-WBaLOeu zpZC#W(4VUe{JRH(8*vH)LU8aSgS!GH;Fg)6IozqkYYKD$jW2t{@15Zr`*8q0tBoR1?VJkX=b;}VRBk_Fti&y3E+o7=3Y$qby;1IhmIm>%g6@-?hGfV zLLvn&&YIEHS31pDtmxTzMTr+9- zj?4tY%L;B6hFuR;+~_PNzi9}6`fHw?t9V*m(Iz+W^tA%)1}nV+q%SfW*)=Gzpa3c1 z>|PY03E*2KtoUOg$O6Lw<=zcm9~R4Ga1PPnO@aGGyA|%oS!O$2aP45rQ8kIRdAmdK z(8QM~;j3X^Lmj{+LCj#zK#f$;-feT4T;Ouy)X7qqBb}TqW-`Ljz52{@6|wlRVZ&-pRDiid~H74@SLv}UfX@+(QD=Yx^{o|YaJ?RnE%KC z8_X*m)s=cTKr(%LC`}jA6@@ahdkcCB-YV)&?`!qt`_%rl#i5LXkX9ek=Z10%|D|@* z(1w53SNnE#Z|dINvu%JJcw|r+$SMu$tNmMF_?Nj$`_!k?Po@uV4y6@^vSxjg14hzY zufA9BD+tb79LQN5(q(^Fkd`im+reoBB|E%&@9K`F2kJr+>EX3|*B)4pfOUJ>KGT(;@MX z(@7K-QxHDz?gFW9h=wPDnPXQk#mVBUZ~A6zC$CQu4pBxVA|dTT<*Wy+V-K83mR zU-jpMlS1T1r*GoTPr->jaq)d5#jtV?QY@yWcf14s3t-1cZ^sYz@O8RT!7Jiu%)BCw z&MYUlI>Bj*+@)Ck#)|lERAmnYMiK9SMKzsh(gp*sK*K?FnQUgKD}E5)hSJ}oYA-+l zK2vGTS$He6I4Cc{F2GwEhS7}KfsEO{S%HkoTl1?&=dTOQUw6|Sm|quEJcFHpx3ndK z7qB#-Ee&eRf{OCninPwGBRNq8MM-~X10%H(E3H}}ke~A~=NvRZUpom38X~VLU%XtD zq_UE!R8wdlw@wpCAUDO<$JJf2hfJtnGxBi}>X9p6S8N67RZi z)cWq{dK-Eg2C~i+3>Ns9i`KK&pn93N7N{^YyI(P|>sGEYkYV(${YF&)azGYT&GFWZ zWfq6z%8sYHq218t@5Cal^iPCHEserk0u-pF_nm0v_EkT=Qbt}U$d#1jI!OWifD0y0 ze(V0~u%}S)E(#LlElZF$Vx0~XYL-Oka;$=zXcs#G4U-=L@r+Z8=$s!`oY2og z%|D~sXwXv${Z6`mG~EzLHw4p5z{{X7?Az3{zI(-hXkeMIdhk)7(_gaCpSj4p4t$iy z)($K_vtn??FQ2%jUl>p?1RrU7P9KGQ2LrWd)(@^9%K9|#qr71Hquw=R_$0`KDx24aBGpv8eNm!Y`at3+5kX%_Txn4v8ocbgf{z@l-CeHyT^tJydSuwo8MEi*_ zz==uqvJt=Gi1m`hmPNo?W4S5VG8L!q2kD-Qv1Mrzean7?zU9emxxWKm)AID)M$Ot* zKFf}28J+-Q`oq*Li@6CAb@&e5X40 zb%=Un!-$jbMOa-Wtd;Zc0GLX?h)+-JnFcI3bIuPrwK=Gshq<&ir?;r5XkdPK5xDcu zD~5L6nzKBRxg1(xGF1dsrE!M6w!3X$@sR6bWJ;|}Bd^QIm1@a#If5<8QXW~JXqhJO zL-13Nc;mVNrGO^}skDV8HVluVFagA+vOq%ZQg~LALY;)%RQiK76 zc^7Rhw7}fXD2K<7=wYSR!KF1bd-$t!lg;61;V_TGjs{cgVJd@lgDEID%3^ak8F)~M zHHJ9qgawH%`W-E74|MuNPMS5<7Br#Zu%ANZX^0xpU5S_YE`w0(MpeZDRdG-?!&?&- zNvW)mHk-d>{zhHc_v}EHPdQXOyf~xuhl%2{q)ZceVc;LPhiO}QKWc3{4%Q@QWD)9q65fL6Hwr>IW*~CTyv87Z^lZj0r zE+K{s7g0(g6Qv|F(T@@t`EUZlMD`PP1R^^t+Q@zcGdIfFUqi%xjDkxj7(@ZKHWC~E z50D3xhRNX*RE~EZEg$%mc=@S|?|MvGM0-90HRho`-vWS__(r9DV8-ee-dN!ZU|ZGO1JNUce=!|Y`!a6YiB z`uMI2su9}OFQDG?pS!J(4L=(!eKM%6{)@Jiy#jsw_ksP%y+ktpXYOT!FUJ)Hw3*ic z!^)q#nJb204whC2wJZPf%`}pCr$JXna-&hSaieiACo`F7hs9*#Wau5gwYiaT4dus)}e`Ar!#VHe+EE4K0(kM73yp^lK ze*)oTkx<9JRQw1p@hlGCcybDGo@~H>Q-B?*Y$<9kMlaXI;48*1S&)2I_(KH=dX1Rm zw?!9~yeP#M$skJNV}|z!b66z*Fhj)02QT|s0y|AG1HCVQ48{mP?Z?^w4K-my2&Wu8 zJ5e!7lJ`UkQZkuMkmza!MQiHZPG@vlTdm?*hT6ps@-Mu{DF6!{%Fql)~1 zBERp6pkl698kH*xtfZgFxtE_qY6o;t0wSLiN5iWoQR?2Z`J}dcPn3XY;1wJV%dh1I zmaW6Ee@lb^1yf+l-%g?mQ5&ft3kPNnxCTq31b{>JIJ#!R(M=2d#Q|9uHRwov-&0Wn zBA>*!`K)phfzc&I@vKng!h4#>NL@&t9u-4;N0k<(AVw|$eN=`ZIoyy&6$nxS)V(I4 zDvGL5QcdUz`~`CZ+OjA@0e($s_GCJOR*Gb#v@a)0K;(m2LNt`?uL3vL`bm_C>eZxl zKo%t+@|Qg}iQ?!qlm~54Uipfoyhr%FipO!@WC<*MGy}$dPnAw);ekVp2M%#;;0WRe vj-aH0qokUUDkn7vnkgl-(8@sMlT4y0szq5_`7C`>RwJJ^^E*@vQ_BAbYZ5TZ 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 21e7b583f2859b07a63b386c08d3f16c5076f4c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 159 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� PoqBfF4iEc{hsgf}z0K0_ 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 8daaf094861d42be5e85f738c3f495335e7930eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4289 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 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 1f8cff6147044cb4aedd1f27e2d3f21d627a3dce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6628 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 Ga{mWPNSb&6 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 04035c3b275ec44558175446ca7ee4f53b0b438e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15490 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 C@r2y~ 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 d845a5aa55666a327ac3c73ca3f89345272fe40c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13731 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 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 a95d5aeb4ddc4b9dd41fcdd673e0f443f4706ec1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16098 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 G=>H!T9)SD+ 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 468cf9aa5ee488131c93717ccc26e5c69743db49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9514 zcma(%YjhjcnKOEh-nQh2{FWRWTY1=V0Ox@nFmW0}Ai;4G8i!QK8rhbSEqf%JU`9ni zLgdsCg(i)GK$UF^%0g3jSy~6e;{DUj*&lmma&%7T%sDyJz(Jps=jJ}n>K)j$w`M48-U$|mk=NP@UX&_o|Wle8j0 z_L2Cj=u^N~8BmU>`cxz8KJ|#EPcx$J(~^XO@F|9=93fiuAyD`jUg_!6=?EP`J888~ zPix@S!b`!cgIDh}3>ay{Np+u*HbUOyQ~C52xuyhd&f-wC<)o_5MAzRJ%jz@Jwk)Qe zE&*y5)F<@1jxL9CJG>R}R>E5auheTb;1$s|J_B6~Zymg-oT44jQ!%aRC0q>?46w5D zcPE!V`_WSJ^3sofn!bKv>Bnz5{t!LySiX9BIsV4&>+jyVdig-Fe%Fy_mM(p=a{6pK zb|oEqW9ftVAEU1>ow;!5vyIo?^21Xr~IL?sOt86!y(NfwJ_ArA!gdH64heeae8=mk4+>^n;#E4JS zFuw2vGwM~Zt^z@z#Z|(4w_brZ2TQQz3wVJU71|trvKN<4!S;%%!>dbA5UiRdrVIo@ zE2n@SYz=7tF}%_f(a3NWtQzAMVrgYqTA+A8S`^}nRmgDFg*~zwR?AYf`jR%HV^yyP zSrx0rTEPg4Cfv}?y+=Z?cffP!tMlpiKKT0jyUXvzZhw9@eeKgbmoG2Bb`1_j`s#H0 zRPxS0U0ZqQ6l9m*ySkJ(4JT^pHy zC(sddkHGoxkBU}VA>)BMQP=MqbEESW5)CNH_$Ga$6TbZnqAS`$o&jI@r7VFgUa7n= z+oBLxBA+{p($Qp)xE77s<0|!P&gQaYT%@RGf)k^(%Th2V+?av0M=-?*SP`%xPyzrQ z^Uy>f%#@;%as=!MAlb`Q0ti_Epw-HI{<^J|2?oQhAb2*7ct$;gz7gMOxV7KoeZeZJF!i>mFTL$Jgy%80RbYrYiPw zs)-5UPmgv5WhA4LmwVQ=9 z$6{Rr*SKxo$=7wH>N-$aX{}IRpRrJ8O@;sv{T|}1l+!wd+6_rRU%Qo~s)WP+oNwUf z;Q{XO!23R~Ve9-RzG2Ueb$r9qH^%weo>XlQ2fx4w;4a#0W~aD~JNdeu3!C`b1Kh#q z_}b^VAGmq@^C|oDG1Fr6Ca$Gxp^b0eooe14({Ppso@!iN-^y*?wJ^+Yeug{P%dbC_ zT7L-DJ-|~W3}w2PNSj zo%DsmXxT-**Ap6Y4+MfQhC~zX4|!o5hTX7_eO{z1at}IbSatEiU|9tt%=L|YRSn#YMmCF7$P?7FW*hNR0Evu2iuLA=hItt&WkgEdr&F^~ZZ=i_aaN9Y6OJZ+7yOGp2|s z7K=*b{an>1zHC!+oG)ri6}3h8!Z~T}A{W|jwsdnX-EWr07_Q_2-ts__8Eq!|7>+924DlrYvLR4Y7V1%SM&)g?8 zP=IWVyUzi*pg0WzKYu5~P6TiAB$Y2h3wL)n@gcPR7+&d-ulh7Ls6nJE_RBg(Q~n^l zcXt4|K<*<*?57+r#nVPc6s&?KrX}l_qzN>6xv4usTqH?iri=zJ#-(5yp=$pX0=zFp z%Vwqpa!e}%TLFa72?nVa#RBcGx{g8LsPDuWvvaD+&oC_=fuPqD2<>cfBU$JPuNAB! z4kIet0eo|ZxC8Q!v-ZO8*SqJs=9u`FS?4VMPIHn>c3n~P6)n82RjSX2SlWPiR)!`< zm<>S5rNq23STH*feWU=Nk4j96+AK3uCHG^|kMJJ`@Xa?-V$ovF@9E2<3sZdO!Bpo# zDCMoaDS(#Vl%aHtzoHVD63t_tmyi+Z9`iB&AT3tptO@W~^V{vTvEn^Yj znM-4XaeB7r+z@ZBOPT8uO^K#t!(8!|X1@NxRQ-dz`N4T|zU!KrH|+%F43wDZtutHW zM{gQxIYTX`Bv8gU8GrnoX4)K62?k5N@k~doL$KLn-MBuZCXDvKP{`D$XM4{LC!Bmy zL#n6&>vgLw`lL`=5#3*4E~wC00OZUCYrLPQ>@mGyDCH_P+%#<93>$=++SvZpE;eTL zM0I0g{N2vk&X_K~YuXaCB)wpaRM&8-3ZVjE*>`kOldwvMc+Pp5<(&`l)I%IqBN!Z9 zL;FobJ7;JYob{Yh8a5i%R_GHf#;yOKsey#u3ijfR{hp97=Y)cDigGyK zW5CI5ghv$$`^F@b1f^u59VEiBd2WY|2j;mV3LzUQgb`5;g1JpAPRe9Bt1>`v0}OX) z$SOaCwjZPR_$id#V+vX|NFr?v+VXc`bZcoGdH_QjOn;WbVi-mP!59Tok*^h4D8XSA z1=8uz3a|=IZETY3Sp|fBC~Px;MG-OFLkUX$CQ3$d3G#SiA=oUsifUU56DIcDW?2hFmU} z7F^*Wq=VdJ5Q#0#MrPc(GAYVx%N6G_gd$9#Z~DvBZ)*3abmm3__cqqIOrnx|9M$Hcne9l+`DW z@?|YC!!2`BbdP`+>V5U>iCKTrKG$`ndM?b{J5u%zST)|*nL_p53(f^wboVVwNros_ z8!(6|h2oNU=v+li1HPVfV{&}1{mK;Y*ny<9C%{#P-f!fb?ekTq>5)o8&ii@->|tRVlcKxvKH^ALi;GntPeAe|+Hu-r2() zdX{%S%N_0GtB$3rj&blC8|NrHG`BY-#*^)rr}*+Mb1yA)-O&8=ll;~LeAzQGgYbPX zS2g_p!-)-Z2EP80`ImX;lQ(*KCyohK9ZFRl;^5~W212(e%USaovrt*H*tnkC@YsTr zZ|qJrb_?saEY>%1%{%71`1+lx`kjJfGZZ8Zb3J_h)>Qpg$V0fxu7_}!UH>P7(i#4Y z0AzEZjHqY?U4$Y_$C6IId}FG7qfk^LlvE40%KJIOqCN;06(ev0{a(>9<_m>#85Pn= zve*!Eu+VA0`wg7m(u^$cGAFL`w5bzYM!72=^s6u+6 z!ql|xlKLJ2eS%fe`4?e^wM#KjmS{eDBYIZHJSyu;Pv_x*BYmF{uzD$W|6T2%HB!9y z8DDs(?Xu*w6-U{Xi4Th2Fg&)>X(6XTah>=xJn;P&rdJqT>^sZefwJc&PT7c-k$#@+!VGhz4i}~120_CwoAV{dwc%xr55R#Q|b7} zj;w}h1{Xek>K86Y`t2D9QYOuk26jo8FH#UPeo|_Bd;UjA72_Kgz)!z=HvQYH7;ysm z@)8SD60?Dm5-XxM+o5##p+a3@&kw6cms+GkUf(F(LI#-tkYYvvh?=ZPYLdR$n-WQ_ z1`&dd_CW*^U&9PA!4Wr-84zAxEd({Rf)+>S{iA{h;k}DIy*%&VimV2jSlc^N_<$yn z@1OPiZTPBJ$)Mgb`}-x^LWyk)=2<8fE#Tz)ykX>yVr`B+>|7Xt=>U|ehTLFRl~|sY zkqZ<2FJOk+0IYid`#9^q`L1|ZeCYhXL@Qs?Hs|4OTcNPvCwcv9QJ3o`#7rR0OrbFC zUY#9uJ%tPkG-vu3LE}qlmqt{=g|Fltd!U)*KdVMO;UQ5K8fU^TGc$zBQ8<7ZMqmc@j|#r!25?2?a4j-x(DaH{JQP)ZJ^*&pyO*gZ+J2WO(p0| z0DmGhNM{0oYz`C=w(8lg^BZSR04LFXf~gED)$1?-U)cazwQk*F)5c^^^28^{<{#lV zeeVXzH$9nZdNS6a z3-ZQVa3gOuH7D&qe>v9_e9N^uh#8bu3p#7OZKgUtl+x8DT*+AYrvMM4@fw5=_r{N-auxd5349re?Jb4$&5llsxkxu8iF)N4d_oG%u)O&5G~wy z{chx!uOWFCZk4$=>wiILFgGbU7q8s~vAvV_#k?#>YKNrvZkfATU;-gp>)xWh;Bw-B`KAYs7( zpqB8-wS?q?7ng9y`=#$FgTIB~2?bGED_CtpnH_Nm)Bp(9ax^FnveIEt$SQ{t7?cJE zWhg>}(!ijg7B|TaN@|QLNMMZI1jLF;GD`T~DlW~a;S0nJmW&pqC^Q>7lp?+bU_twT Dc{&l1 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 de0015bbe536053b272e1d27f5604fa5c2c628dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8363 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 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 3bcf3d6adc6d4b6f97bca6bc4842447fcd4241ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 606 zcmX@j%ge<81a{rMSs9EB439w^7+{7nJ}(0@rZc24L@}f=rZD9&Mlq%^r!r=-z!W0r z6c!sG2d6A6Se6ZkUUsl72M$?Iye4yjWGk68xl7Z446f(v7CxWQ_GHhj7wZ=K2P-_= z+Wlhv)R(Qj&-bq5;(D@o|MMv;6oLbNGD}hwp0>3F_X)l{sDEL+abv|xr;(7`4x8E(6lGNgoTinjRj`1!| z@u9)4L2yohV{q^-&Yb+@#GH(LBt;(n!6CO;jExP<5K8@nLf{-fM_*S>=3DIX@hSPq z@$t8q@{4b=r{$cQetv;YF>&y z$W6ui@$s2?nI-Y@dIgogIBatBQ%ZAE?TQ3}+JSM+P#g{TJ9yQ{7& 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 80e7ac14a120d26b018275a3883a54aa418745ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8553 zcmc&(Yg80hp1<|zcQ?&b-iRWGjtIVDd?$$SC>k*)_Uvw_>?)wKs~fATRUAy31Ovne zBr|FoafOVD>}ZVH&4W!enKLsVa?XBf2IkOHqi1tYY=lq2kU3^O^I`w@R(AtVPcoY? zTTu7;zyEvt-v9mmAN5~0n;F5g?!>9aGqVu-8du_vDOQ-=%^-9R@yLmIil@DllO{PM zvTm9}qRy$Ov>t=gAQ&1`;|!+q#*C?Qyu>p+dzIE|6#74m)BVJ8dfxDp<}>o9pES-q zeVt^-%uX}p7OzFLI;~{StX`X#;!GiBo7XO;I#WqG#hWIkJJZDsX9lU;y_sT`GmDf{ zy|ct@XAUW+d2_`)XC8%UB&71`d6SLM?d|=*cTVZ`c7&CzPWjFy!DId@l$s{zc}{M+34l7{p{1RzJ3@JYwtd-wT})Qhqd4V=JEDZWACM_*L%lq-2#^P`mW#o;^Mv2??>N$HQE&# zZ|{PETvO9%e_!@aD%XbfuIFku?p9emPoim8 zRc&pevSnxO9@XUayE$)ze>&05-FsAa>C#2Z6Qng&J2pBf)wEgg2@2d!FVL6$v!pU52$B-K!>)$q7lg;PB4U4Fk8YDS(@xc!_g zK$%?+`O$Rwpcl?)Rb^%6Dp3&qQu8V`&D|il54dDb6kJLJ%*1cPQ@H&;pWs$poK!EX zrY7L%_Hwf9U{o^~Q2cJcD0&ptgv)i_fZU+6`#nD19m7g;5sZ-H8$P)nTF;>t6r`Fl z1|u&zMk}$qkDy&)2|Xln43n1d^ak|L

>POsIu!j1x@D8x7Mcv7(}jx3!?e%|twt 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 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 f233ffadd32f5cf9b056cdf99f21953a077314eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10631 zcmeHNYitzP6`tLl-JP9%85@jw1k9TaU;_q|gh2CX5|yT?RiaciKSs;mvDwW&oIATQ zUS?HjP->bIh?)e_I*p^I)glN)s@fn`Rr0e^|JWF6chsnr8XNp?sVha|SI@b3W_D~A z){ZD?)sEKZKIY7wJLleW?sv}dAH!i;fNSq-CsRj*g79~2SeIy4rc+QkBM_lWATHug zySm)0^kl?@+a+YYT|O7TG?f~SJ!)Rb=U!B^N_UR(zF@qNKcpN| z<3yzi{$@_?Pd*IoGlD8~x!|+mbGtmmt%}5>db>p;9v8cOjJP?3hJ@euI83t82ot&fW_fbpV^bbX5{56qKHhMXg9(r0 z3;a;W_Vj))en8%3-P7IY&ALm_T`A`?CJU}9@eq-C2R#>j){2xox+i6c#TpFCl1Tg| zuP*A|7dJx7r~9-I^Z0glr6j9XEs3Q2x?LoI&vd)bn`06=5BrW^sgPBxmgmjt%YwGZ zF@B`VVbyex^@Y^Q*KGVzlT3G4o(i?yVD zlQjd!NVwByUAknAWR*W~k;q|JNrXQi$lQ}!JnIo?T5>7{NVFvDvL1L@Cpp{r73M0q!%E~OF*_{G13yKF6?tz_pu$1vQ0bWR7Y zi7A0FSxT1aVN(K;IZGg7jbxRU1Yo}f;fpOPEH|a_!2hBY`XjLw1+-7s-}&9d@86mn zI6d*B_ii<{$9t3QiA=m5Pn7m_t|yr_0(khuNd~GCE4FR#m_p-w&SOY;CS~Ip)sTAQ zn%0-2#0bDCmdy7nNpj9*h$$_Xo%#cEyKcGn>^bKucC6dj+rK@g$w$me>z-DuZH;Md z@S=P{QxZ9%%B9vl{Kn3hW{6bPdf|m0;6t(<$s>rjt*m6DFQZtA;0`=3*fVhZv06o73_}(DA8;{8(>4JL2QiSfC{0>9j)C zUYf{ddgD|zLU3C-SV*Sx$*gAh(mCMJj21;Zlq;kOV^w<6xr6bv!qy_7Xz^|pM=&Cf zGXVjbc#6^-HJT7LWa4>6J=~j)XXAOeLz`h*v8W+xYPy>ufTDPY(PcQ>AikSRd7HDb z!`bNI4L)?Iv+)pJJ8P7!&Ih+UdCejDC_9~Zc4<)BYzM|os{}x?z>d1*B!^^ggx2zd&Sv|gF=}o`*kUVf?S`Zt817am4G%Os8t{jQ39G2D( zbpRQTt{mzZiLM`$@ORDZ;4PbuNb3jkyfs>_US-U@`w9+c^V=2R9*;Ji>Oax{+K~Zq zJlZ@gtr+M#yLRCFW6}!vUE@vO7{vy!+7$TDuC;GlRr@wn;3;^;>8DTVXZMXnHw;Ui z<=sGrqZ`V*N1~l$68^549lSNlTD*P*`FYhzfyEm2>5=G~VQKSF0myK4%}`+^x_L~( z-!-#?w?fIl$JxZCSFaBpn|kw|8<#Fo)L)9w+6eT~ zT($>~D6rUQ&MBf-x(LYB8?Yy63pSS`L90iXBWXpl3dsI*L1wyXJN9fvvJJ_0Bppb0 zAlZqe6UipopO$3K2-7$UrE$Gy2#M3SNDQ{hsQCyQsCdrzK9?EIv03(@Jto$l0Y8Uh+Qcb zYp`0pwEPz4-&M!2;R#kfSnv?4oV7eb+t&pTAy9|cR`@!6wh9wVHGKqC(`Vvse|~}W zWsZ?hb!J_9Esq0L(*u9rlE_pOk8kewe}4Jo#D`}m2Fpx44PQ2QFh}|+GSF`zL7k-g zklbA-WAc|!N6Dd%OwsSCiRk}Wn#dJ#nL`n?xvY9PspSE1un@5x7YhGMobez;ktS@WkX>1I*XF@%qOTr`|R#+$Zl( z9=mj_VWuw)E^-(npgEc>GOw%Xe?kT4j<#aNm&a~3ijlB7c8|js+{F~_35_Aygk&?2 zSePRfJkSge#ERzySGXq_aTv)U4!j!4UCkx^8nQfwu0H>54hkY-e+ zF9~7mm*eRq;SufPs+m@_1`FaYO$0Dd#WR0tSUuD^+VJ3j7maH1L~(fO=JC+7vwcH_ zp`PIf+A1FRE_t9hEw~xJk?u3Tar$Rx9|1RTSlU_M1Y|h6zPxE9x^qmz-!-#?w?>rmPn2Ej5Y|2DMbbzqko zhQAs)uft~>bK)}%uaEdK18`5!QUDB#g_Z&_xv&N{`Q(`)ZdopVGIi$S)Zoz@zdFWK zCf9#@eDd{QPMrD$eGd4NKY^95V=@3Ly#TE9GX>v9O}iZhEpjSvu3+Y(iYsbru6-Xp z9PJe#9Qkl19gS|mfJM{&jF#Bmh7DU_QuvkFp8mOrK2Jylk5HHv{K9*6c<#C8a zx-A%BgQ8k+2XaZ6QIcl`1A_NVhiu=VuE$|>0(c3|RX6JJ*&v66>|j8cL>$3@xq2M6 zGD=aNMgrRSV~Mrj~uNVOAZ! zDzLNiKS7rN37YmLG-q!tWZ8DB1n`2gK^r5(7uWWrn^~@OF=>HZX?16Z^>9sJ`d;nq zCHHJ++mNm9&bB#WXD_LofRj7qa{#7>KLevc z7@h^<%o(!0QZ1m$gLCL&QB-?F=3#kE^TdMl_w4V0T;~m1X&feVN8}o2ho2?gV)M*H z&+116tes#O)pqkc##>g6x2zpsxN>~qikkuNZk93dGDI5rDiP_!Bhhuk(ysCfAj8ph zZxf#Fr1<`=UB$zJ*N0Z5QE2M6Q| z1Q?f&Mc1+SZZ0>mkpH@J)69@RbU35>P#=*t4-|PHqyeldg!^IEyc;qCw><@SfQ18P z=aFy6HpUrH{{KIgq-sSwoG{?O?jK7a#T_jm5SaSm$%zk6a!WaJ`XskZ^Z?vp$pIF7 zWH!sm81q!EAytqUhf1EVkGAPIk^5O7wZi#}XP6L$6nfLi1pJFvv9-1_sd6BM*WLqC zb$y-Yg=Hfbu7+$Rw=G{yHqye^`(t54Qdl}#Q4Cp8GC5L6t56Rq%1ecK8qXJK`4xra z5{g1mIVr$zfj))gTS&fx)6q-d7D4u4Fpns|9K#mK47MEAVh<8hQ zX+?nI^5SVMDy;$UhL7Zm0L7>NX)G$ue&~8|T7aU`D0@50#fkvM<-TbwDlH!GhVs5? z0g8&;=-o23uOdM4(KFLnR5r?RJB3edxZLwkEcnE5PO$~_5EOX6^29yM6d6ktp6YMo zIdw?Cw^6l^CiAKhu)7Su*~jushL1mDG3t?gBZ50kYfI#^-B_!}g(w<7F1IAsF#Ez}c}sefFVkL1p%1pYplt$D@wi;Bn{KyD m{K6-=T*rl1!k-DT&xF-~6`matp8dl2g3Gnx9|BS~*uMb#R5bel 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"