- Login.vue: no prefilled default creds; no anonymous entity enumeration on mount - deploy.sh: readiness polling (0.5s/30s cap) replaces fixed sleep 3; login smoke reads same-source 600 secret file, missing file = explicit abort - 19 verify/check/gen_report scripts: shared _admin_creds() loader (CMA_ADMIN_ENV -> ops .secrets -> profile copy); no hardcoded creds - tests: single TEST_USER_PASSWORD fixture constant; docs: pointer to 600 secret file; removed 4 legacy .bak + pycache residue
78 lines
3.6 KiB
Python
78 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
||
"""查询管理会计OS各模块数据量"""
|
||
import subprocess, json, sys
|
||
|
||
# 登录获取token
|
||
import os # noqa: E402 (凭据加载器需要)
|
||
# ---- 管理员凭据同源加载(2026-09-14 cma-defaultcred-code-fix)----
|
||
# 生产凭据只存 600 密钥文件;禁止在脚本/文档/日志里硬编码口令。
|
||
# 顺序:$CMA_ADMIN_ENV → wecom-ops 主副本(ops 轮换落点,权威) → 本 profile 副本。
|
||
def _admin_creds():
|
||
"""返回 (user, password, 来源文件);未找到 → 显式报错退出(不静默退回默认口令)"""
|
||
for p in (os.environ.get("CMA_ADMIN_ENV"),
|
||
"/root/.hermes/profiles/wecom-ops/.secrets/cma-admin.env",
|
||
"/root/.hermes/profiles/wecom-fullstack/.secrets/cma-admin.env"):
|
||
if p and os.path.isfile(p):
|
||
kv = {}
|
||
for line in open(p, encoding="utf-8"):
|
||
line = line.strip()
|
||
if "=" in line and not line.startswith("#"):
|
||
k, v = line.split("=", 1)
|
||
kv[k.strip()] = v.strip().strip('"').strip("'")
|
||
if kv.get("CMA_ADMIN_USER") and kv.get("CMA_ADMIN_PASS"):
|
||
return kv["CMA_ADMIN_USER"], kv["CMA_ADMIN_PASS"], p
|
||
raise SystemExit("[错误] 未找到 CMA 管理员凭据:请设 $CMA_ADMIN_ENV,或准备 600 权限密钥文件 "
|
||
".secrets/cma-admin.env(键名 CMA_ADMIN_USER / CMA_ADMIN_PASS)")
|
||
|
||
|
||
ADMIN_USER, ADMIN_PASS, CRED_SRC = _admin_creds()
|
||
print(f"[creds] 来源={CRED_SRC} 账号={ADMIN_USER}(口令不回显)")
|
||
|
||
r = subprocess.run(
|
||
f"curl -s -X POST http://127.0.0.1:8010/api/cma/auth/login -H 'Content-Type: application/json' -d '{{\"username\":\"{ADMIN_USER}\",\"password\":\"{ADMIN_PASS}\"}}'",
|
||
shell=True, capture_output=True, text=True, timeout=10
|
||
)
|
||
login = json.loads(r.stdout)
|
||
token = login['token']
|
||
|
||
endpoints = [
|
||
("KPI定义", "/api/cma/kpis"),
|
||
("战略地图", "/api/cma/maps"),
|
||
("预警记录", "/api/cma/alerts"),
|
||
("用户列表", "/api/cma/users"),
|
||
("数据源配置", "/api/cma/data/sources"),
|
||
("通知渠道", "/api/cma/notifications/channels"),
|
||
("预警规则", "/api/cma/alert-rules"),
|
||
("行动计划", "/api/cma/action-plans"),
|
||
("dashboard/KPI", "/api/cma/dashboard/kpis"),
|
||
("dashboard/财务分析", "/api/cma/dashboard/finance-analysis"),
|
||
("dashboard/总览", "/api/cma/dashboard/summary"),
|
||
("dashboard/预测", "/api/cma/dashboard/predict"),
|
||
("权限配置", "/api/cma/permissions/config"),
|
||
("权限模块", "/api/cma/permissions/modules"),
|
||
]
|
||
|
||
for name, path in endpoints:
|
||
cmd = f"curl -s '{path}' -H 'Authorization: Bearer {token}'"
|
||
r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=15)
|
||
try:
|
||
data = json.loads(r.stdout)
|
||
if isinstance(data, list):
|
||
print(f" {name:25s} → {len(data)} 条记录")
|
||
elif isinstance(data, dict):
|
||
if 'detail' in data:
|
||
print(f" {name:25s} → ❌ {str(data['detail'])[:50]}")
|
||
else:
|
||
# 尝试找列表字段
|
||
found = False
|
||
for k in ['data', 'items', 'records', 'modules', 'actions', 'roles', 'channels']:
|
||
if k in data and isinstance(data[k], list):
|
||
print(f" {name:25s} → {len(data[k])} 条 ({k})")
|
||
found = True
|
||
break
|
||
if not found:
|
||
preview = {k: str(v)[:60] for k, v in list(data.items())[:4]}
|
||
print(f" {name:25s} → dict: {preview}")
|
||
except:
|
||
print(f" {name:25s} → ⚠️ 解析失败: {r.stdout[:100]}")
|