security: 移除程式碼中硬編碼的敏感資訊

- 移除 database.py、settings.py、auth_service.py 中的硬編碼預設值
- 移除 tools/*.py 中的硬編碼 IP 位址和服務名稱
- 更新 generate_documentation.py 移除硬編碼的帳號密碼
- 更新 MES_Database_Reference.md 和 Oracle_Authorized_Objects.md 移除敏感資訊
- 更新 .env.example 和 README.md 使用 placeholder 值
- 所有敏感設定現在必須透過 .env 檔案配置

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
beabigegg
2026-02-04 16:34:32 +08:00
parent ed60701465
commit 5299d187bc
11 changed files with 78 additions and 69 deletions

View File

@@ -10,9 +10,9 @@
# Database Configuration (REQUIRED) # Database Configuration (REQUIRED)
# ============================================================ # ============================================================
# Oracle Database connection settings # Oracle Database connection settings
DB_HOST=10.1.1.58 DB_HOST=your_database_host
DB_PORT=1521 DB_PORT=1521
DB_SERVICE=DWDB DB_SERVICE=your_service_name
DB_USER=your_username DB_USER=your_username
DB_PASSWORD=your_password DB_PASSWORD=your_password
@@ -41,10 +41,10 @@ SESSION_LIFETIME=28800
# Authentication Configuration # Authentication Configuration
# ============================================================ # ============================================================
# LDAP API endpoint for user authentication # LDAP API endpoint for user authentication
LDAP_API_URL=https://adapi.panjit.com.tw LDAP_API_URL=https://your-ldap-api-endpoint.example.com
# Admin email addresses (comma-separated for multiple) # Admin email addresses (comma-separated for multiple)
ADMIN_EMAILS=ymirliu@panjit.com.tw ADMIN_EMAILS=admin@example.com
# Local Authentication (for development/testing) # Local Authentication (for development/testing)
# When enabled, uses local credentials instead of LDAP # When enabled, uses local credentials instead of LDAP

View File

@@ -111,9 +111,9 @@ nano .env # 編輯資料庫連線等設定
```bash ```bash
# 資料庫設定(必填) # 資料庫設定(必填)
DB_HOST=10.1.1.58 DB_HOST=your_database_host
DB_PORT=1521 DB_PORT=1521
DB_SERVICE=DWDB DB_SERVICE=your_service_name
DB_USER=your_username DB_USER=your_username
DB_PASSWORD=your_password DB_PASSWORD=your_password
@@ -304,8 +304,8 @@ CIRCUIT_BREAKER_RECOVERY_TIMEOUT=30
### 資料庫 ### 資料庫
- Oracle Database 19c Enterprise Edition - Oracle Database 19c Enterprise Edition
- 主機: 10.1.1.58:1521 - 主機: 詳見 .env 檔案 (DB_HOST:DB_PORT)
- 服務名: DWDB - 服務名: 詳見 .env 檔案 (DB_SERVICE)
--- ---

View File

@@ -21,22 +21,27 @@
| 参数 | 值 | | 参数 | 值 |
|------|------| |------|------|
| 数据库类型 | Oracle Database 19c Enterprise Edition | | 数据库类型 | Oracle Database 19c Enterprise Edition |
| 主机地址 | 10.1.1.58 | | 主机地址 | 請參考 .env 檔案 (DB_HOST) |
| 端口 | 1521 | | 端口 | 請參考 .env 檔案 (DB_PORT) |
| 服务名 | DWDB | | 服务名 | 請參考 .env 檔案 (DB_SERVICE) |
| 用户名 | MBU1_R | | 用户名 | 請參考 .env 檔案 (DB_USER) |
| 密码 | Pj2481mbu1 | | 密码 | 請參考 .env 檔案 (DB_PASSWORD) |
### Python 连接示例 ### Python 连接示例
```python ```python
import os
import oracledb import oracledb
from dotenv import load_dotenv
# 连接配置 # 載入環境變數
load_dotenv()
# 连接配置 (從環境變數讀取)
DB_CONFIG = { DB_CONFIG = {
'user': 'MBU1_R', 'user': os.getenv('DB_USER'),
'password': 'Pj2481mbu1', 'password': os.getenv('DB_PASSWORD'),
'dsn': '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=10.1.1.58)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=DWDB)))' 'dsn': f"(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={os.getenv('DB_HOST')})(PORT={os.getenv('DB_PORT')})))(CONNECT_DATA=(SERVICE_NAME={os.getenv('DB_SERVICE')})))"
} }
# 建立连接 # 建立连接
@@ -55,7 +60,7 @@ connection.close()
### JDBC 连接字符串 ### JDBC 连接字符串
``` ```
jdbc:oracle:thin:@10.1.1.58:1521:DWDB jdbc:oracle:thin:@${DB_HOST}:${DB_PORT}:${DB_SERVICE}
``` ```
--- ---
@@ -1287,7 +1292,7 @@ jdbc:oracle:thin:@10.1.1.58:1521:DWDB
### 数据权限 ### 数据权限
- 当前账号 `MBU1_R` 为只读账号 - 當前帳號為唯讀帳號 (詳見 .env 中的 DB_USER)
- 仅可执行 SELECT 查询 - 仅可执行 SELECT 查询
- 无法进行 INSERT, UPDATE, DELETE 操作 - 无法进行 INSERT, UPDATE, DELETE 操作

View File

@@ -1,7 +1,7 @@
# Oracle 可使用 TABLE/VIEW 清單DWH # Oracle 可使用 TABLE/VIEW 清單DWH
**產生時間**: 2026-01-29 13:34:22 **產生時間**: 2026-01-29 13:34:22
**使用者**: MBU1_R **使用者**: (詳見 .env 中的 DB_USER)
**Schema**: DWH **Schema**: DWH
## 摘要 ## 摘要

View File

@@ -20,9 +20,10 @@ except ImportError:
pass # python-dotenv not installed, rely on system environment variables pass # python-dotenv not installed, rely on system environment variables
# Database connection settings from environment variables # Database connection settings from environment variables
DB_HOST = os.getenv('DB_HOST', '10.1.1.58') # All values MUST be set in .env file - no hardcoded defaults for security
DB_HOST = os.getenv('DB_HOST', '')
DB_PORT = os.getenv('DB_PORT', '1521') DB_PORT = os.getenv('DB_PORT', '1521')
DB_SERVICE = os.getenv('DB_SERVICE', 'DWDB') DB_SERVICE = os.getenv('DB_SERVICE', '')
DB_USER = os.getenv('DB_USER', '') DB_USER = os.getenv('DB_USER', '')
DB_PASSWORD = os.getenv('DB_PASSWORD', '') DB_PASSWORD = os.getenv('DB_PASSWORD', '')

View File

@@ -24,9 +24,9 @@ class Config:
DB_POOL_SIZE = _int_env("DB_POOL_SIZE", 5) DB_POOL_SIZE = _int_env("DB_POOL_SIZE", 5)
DB_MAX_OVERFLOW = _int_env("DB_MAX_OVERFLOW", 10) DB_MAX_OVERFLOW = _int_env("DB_MAX_OVERFLOW", 10)
# Auth configuration # Auth configuration - MUST be set in .env file
LDAP_API_URL = os.getenv("LDAP_API_URL", "https://adapi.panjit.com.tw") LDAP_API_URL = os.getenv("LDAP_API_URL", "")
ADMIN_EMAILS = os.getenv("ADMIN_EMAILS", "ymirliu@panjit.com.tw") ADMIN_EMAILS = os.getenv("ADMIN_EMAILS", "")
SECRET_KEY = os.getenv("SECRET_KEY", "dev-secret-key-change-in-prod") SECRET_KEY = os.getenv("SECRET_KEY", "dev-secret-key-change-in-prod")
# Session configuration # Session configuration

View File

@@ -10,11 +10,9 @@ import requests
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Configuration # Configuration - MUST be set in .env file
LDAP_API_BASE = os.environ.get("LDAP_API_URL", "https://adapi.panjit.com.tw") LDAP_API_BASE = os.environ.get("LDAP_API_URL", "")
ADMIN_EMAILS = os.environ.get( ADMIN_EMAILS = os.environ.get("ADMIN_EMAILS", "").lower().split(",")
"ADMIN_EMAILS", "ymirliu@panjit.com.tw"
).lower().split(",")
# Timeout for LDAP API requests # Timeout for LDAP API requests
LDAP_TIMEOUT = 10 LDAP_TIMEOUT = 10

View File

@@ -14,25 +14,25 @@ with open(DATA_FILE, 'r', encoding='utf-8') as f:
table_info = json.load(f) table_info = json.load(f)
# 表用途描述(根据表名推断) # 表用途描述(根据表名推断)
TABLE_DESCRIPTIONS = { TABLE_DESCRIPTIONS = {
'DW_MES_CONTAINER': '容器/批次主檔 - 目前在製容器狀態、數量與流程資訊', 'DW_MES_CONTAINER': '容器/批次主檔 - 目前在製容器狀態、數量與流程資訊',
'DW_MES_HOLDRELEASEHISTORY': 'Hold/Release 歷史表 - 批次停工與解除紀錄', 'DW_MES_HOLDRELEASEHISTORY': 'Hold/Release 歷史表 - 批次停工與解除紀錄',
'DW_MES_JOB': '設備維修工單表 - 維修工單的當前狀態與流程', 'DW_MES_JOB': '設備維修工單表 - 維修工單的當前狀態與流程',
'DW_MES_LOTREJECTHISTORY': '批次不良/報廢歷史表 - 不良原因與數量', 'DW_MES_LOTREJECTHISTORY': '批次不良/報廢歷史表 - 不良原因與數量',
'DW_MES_LOTWIPDATAHISTORY': '在製數據採集歷史表 - 製程量測/參數紀錄', 'DW_MES_LOTWIPDATAHISTORY': '在製數據採集歷史表 - 製程量測/參數紀錄',
'DW_MES_LOTWIPHISTORY': '在製流轉歷史表 - 批次進出站與流程軌跡', 'DW_MES_LOTWIPHISTORY': '在製流轉歷史表 - 批次進出站與流程軌跡',
'DW_MES_MAINTENANCE': '設備保養/維護紀錄表 - 保養計畫與點檢數據', 'DW_MES_MAINTENANCE': '設備保養/維護紀錄表 - 保養計畫與點檢數據',
'DW_MES_PARTREQUESTORDER': '維修用料請求表 - 維修/設備零件請領', 'DW_MES_PARTREQUESTORDER': '維修用料請求表 - 維修/設備零件請領',
'DW_MES_PJ_COMBINEDASSYLOTS': '併批紀錄表 - 合批/合併批次關聯與數量資訊', 'DW_MES_PJ_COMBINEDASSYLOTS': '併批紀錄表 - 合批/合併批次關聯與數量資訊',
'DW_MES_RESOURCESTATUS': '設備狀態變更歷史表 - 狀態切換與原因', 'DW_MES_RESOURCESTATUS': '設備狀態變更歷史表 - 狀態切換與原因',
'DW_MES_RESOURCESTATUS_SHIFT': '設備狀態班次彙總表 - 班次級狀態/工時', 'DW_MES_RESOURCESTATUS_SHIFT': '設備狀態班次彙總表 - 班次級狀態/工時',
'DW_MES_WIP': '在製品現況表(含歷史累積)- 當前 WIP 狀態/數量', 'DW_MES_WIP': '在製品現況表(含歷史累積)- 當前 WIP 狀態/數量',
'DW_MES_HM_LOTMOVEOUT': '批次出站事件歷史表 - 出站/移出交易', 'DW_MES_HM_LOTMOVEOUT': '批次出站事件歷史表 - 出站/移出交易',
'DW_MES_JOBTXNHISTORY': '維修工單交易歷史表 - 工單狀態變更紀錄', 'DW_MES_JOBTXNHISTORY': '維修工單交易歷史表 - 工單狀態變更紀錄',
'DW_MES_LOTMATERIALSHISTORY': '批次物料消耗歷史表 - 用料與批次關聯', 'DW_MES_LOTMATERIALSHISTORY': '批次物料消耗歷史表 - 用料與批次關聯',
'DW_MES_RESOURCE': '資源表 - 設備/載具等資源基本資料OBJECTCATEGORY=ASSEMBLY 時RESOURCENAME 為設備編號)' 'DW_MES_RESOURCE': '資源表 - 設備/載具等資源基本資料OBJECTCATEGORY=ASSEMBLY 時RESOURCENAME 為設備編號)'
} }
# 常见字段说明 # 常见字段说明
COMMON_FIELD_NOTES = { COMMON_FIELD_NOTES = {
'ID': '唯一标识符', 'ID': '唯一标识符',
@@ -79,21 +79,26 @@ def generate_markdown():
md.append("| 参数 | 值 |") md.append("| 参数 | 值 |")
md.append("|------|------|") md.append("|------|------|")
md.append("| 数据库类型 | Oracle Database 19c Enterprise Edition |") md.append("| 数据库类型 | Oracle Database 19c Enterprise Edition |")
md.append("| 主机地址 | 10.1.1.58 |") md.append("| 主机地址 | 請參考 .env 檔案 (DB_HOST) |")
md.append("| 端口 | 1521 |") md.append("| 端口 | 請參考 .env 檔案 (DB_PORT) |")
md.append("| 服务名 | DWDB |") md.append("| 服务名 | 請參考 .env 檔案 (DB_SERVICE) |")
md.append("| 用户名 | MBU1_R |") md.append("| 用户名 | 請參考 .env 檔案 (DB_USER) |")
md.append("| 密码 | Pj2481mbu1 |\n") md.append("| 密码 | 請參考 .env 檔案 (DB_PASSWORD) |\n")
md.append("### Python 连接示例\n") md.append("### Python 连接示例\n")
md.append("```python") md.append("```python")
md.append("import os")
md.append("import oracledb") md.append("import oracledb")
md.append("from dotenv import load_dotenv")
md.append("") md.append("")
md.append("# 连接配置") md.append("# 載入環境變數")
md.append("load_dotenv()")
md.append("")
md.append("# 连接配置 (從環境變數讀取)")
md.append("DB_CONFIG = {") md.append("DB_CONFIG = {")
md.append(" 'user': 'MBU1_R',") md.append(" 'user': os.getenv('DB_USER'),")
md.append(" 'password': 'Pj2481mbu1',") md.append(" 'password': os.getenv('DB_PASSWORD'),")
md.append(" 'dsn': '(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=10.1.1.58)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=DWDB)))'") md.append(" 'dsn': f\"(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST={os.getenv('DB_HOST')})(PORT={os.getenv('DB_PORT')})))(CONNECT_DATA=(SERVICE_NAME={os.getenv('DB_SERVICE')})))\"")
md.append("}") md.append("}")
md.append("") md.append("")
md.append("# 建立连接") md.append("# 建立连接")
@@ -111,7 +116,7 @@ def generate_markdown():
md.append("### JDBC 连接字符串\n") md.append("### JDBC 连接字符串\n")
md.append("```") md.append("```")
md.append("jdbc:oracle:thin:@10.1.1.58:1521:DWDB") md.append("jdbc:oracle:thin:@${DB_HOST}:${DB_PORT}:${DB_SERVICE}")
md.append("```\n") md.append("```\n")
# 2. 数据库概览 # 2. 数据库概览
@@ -231,7 +236,7 @@ def generate_markdown():
md.append("") md.append("")
md.append("### 数据时效性\n") md.append("### 数据时效性\n")
md.append("- **实时数据表**: `DW_MES_WIP`(含歷史累積), `DW_MES_RESOURCESTATUS`") md.append("- **实时数据表**: `DW_MES_WIP`(含歷史累積), `DW_MES_RESOURCESTATUS`")
md.append("- **历史数据表**: 带有 `HISTORY` 后缀的表") md.append("- **历史数据表**: 带有 `HISTORY` 后缀的表")
md.append("- **主数据表**: `DW_MES_RESOURCE`, `DW_MES_CONTAINER`") md.append("- **主数据表**: `DW_MES_RESOURCE`, `DW_MES_CONTAINER`")
md.append("") md.append("")
@@ -244,7 +249,7 @@ def generate_markdown():
md.append("") md.append("")
md.append("### 数据权限\n") md.append("### 数据权限\n")
md.append("- 当前账号 `MBU1_R` 为只读账号") md.append("- 當前帳號為唯讀帳號 (詳見 .env 中的 DB_USER)")
md.append("- 仅可执行 SELECT 查询") md.append("- 仅可执行 SELECT 查询")
md.append("- 无法进行 INSERT, UPDATE, DELETE 操作") md.append("- 无法进行 INSERT, UPDATE, DELETE 操作")
md.append("") md.append("")

View File

@@ -23,10 +23,10 @@ try:
except ImportError: except ImportError:
pass pass
# 数据库连接信息 (从环境变量读取) # 数据库连接信息 (从环境变量读取,必须在 .env 中设置)
DB_HOST = os.getenv('DB_HOST', '10.1.1.58') DB_HOST = os.getenv('DB_HOST', '')
DB_PORT = os.getenv('DB_PORT', '1521') DB_PORT = os.getenv('DB_PORT', '1521')
DB_SERVICE = os.getenv('DB_SERVICE', 'DWDB') DB_SERVICE = os.getenv('DB_SERVICE', '')
DB_USER = os.getenv('DB_USER', '') DB_USER = os.getenv('DB_USER', '')
DB_PASSWORD = os.getenv('DB_PASSWORD', '') DB_PASSWORD = os.getenv('DB_PASSWORD', '')

View File

@@ -21,10 +21,10 @@ try:
except ImportError: except ImportError:
pass pass
# 数据库连接信息 (从环境变量读取) # 数据库连接信息 (从环境变量读取,必须在 .env 中设置)
DB_HOST = os.getenv('DB_HOST', '10.1.1.58') DB_HOST = os.getenv('DB_HOST', '')
DB_PORT = os.getenv('DB_PORT', '1521') DB_PORT = os.getenv('DB_PORT', '1521')
DB_SERVICE = os.getenv('DB_SERVICE', 'DWDB') DB_SERVICE = os.getenv('DB_SERVICE', '')
DB_USER = os.getenv('DB_USER', '') DB_USER = os.getenv('DB_USER', '')
DB_PASSWORD = os.getenv('DB_PASSWORD', '') DB_PASSWORD = os.getenv('DB_PASSWORD', '')

View File

@@ -35,9 +35,9 @@ def load_env() -> None:
def get_connection(): def get_connection():
host = os.getenv("DB_HOST", "10.1.1.58") host = os.getenv("DB_HOST", "")
port = os.getenv("DB_PORT", "1521") port = os.getenv("DB_PORT", "1521")
service = os.getenv("DB_SERVICE", "DWDB") service = os.getenv("DB_SERVICE", "")
user = os.getenv("DB_USER", "") user = os.getenv("DB_USER", "")
password = os.getenv("DB_PASSWORD", "") password = os.getenv("DB_PASSWORD", "")
dsn = ( dsn = (