@optima-chat/dev-skills 0.7.11 → 0.7.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
执行 SQL 查询,支持 CI/Stage/Prod 三个环境。
|
|
4
4
|
|
|
5
|
-
**版本**: v0.
|
|
5
|
+
**版本**: v0.7.0
|
|
6
6
|
|
|
7
7
|
## 使用场景
|
|
8
8
|
|
|
@@ -182,11 +182,11 @@ INFISICAL_TOKEN=$(curl -s -X POST "${INFISICAL_URL}/api/v1/auth/universal-auth/l
|
|
|
182
182
|
| python3 -c "import sys, json; print(json.load(sys.stdin)['accessToken'])")
|
|
183
183
|
|
|
184
184
|
# 3. 从 Infisical 获取数据库配置(以 commerce-backend 为例)
|
|
185
|
-
|
|
185
|
+
# 项目: optima-secrets-v2, 路径: /shared-secrets/database-users
|
|
186
|
+
curl -s "${INFISICAL_URL}/api/v3/secrets/raw?workspaceId=${INFISICAL_PROJECT_ID}&environment=staging&secretPath=/shared-secrets/database-users" \
|
|
186
187
|
-H "Authorization: Bearer ${INFISICAL_TOKEN}" | python3 -c "
|
|
187
188
|
import sys, json
|
|
188
189
|
secrets = {s['secretKey']: s['secretValue'] for s in json.load(sys.stdin)['secrets']}
|
|
189
|
-
print(f\"DATABASE_HOST={secrets['DATABASE_HOST']}\")
|
|
190
190
|
print(f\"COMMERCE_DB_USER={secrets['COMMERCE_DB_USER']}\")
|
|
191
191
|
print(f\"COMMERCE_DB_PASSWORD={secrets['COMMERCE_DB_PASSWORD']}\")
|
|
192
192
|
" > /tmp/stage_db_config.sh && source /tmp/stage_db_config.sh
|
|
@@ -216,7 +216,7 @@ pkill -f "ssh.*15432:${DATABASE_HOST}:5432"
|
|
|
216
216
|
# 使用 BI_DB_USER, BI_DB_PASSWORD, 数据库: optima_bi
|
|
217
217
|
|
|
218
218
|
# session-gateway (注意: Stage 数据库名是 optima_shell)
|
|
219
|
-
# 使用
|
|
219
|
+
# 使用 AI_SHELL_DB_USER, AI_SHELL_DB_PASSWORD, 数据库: optima_shell
|
|
220
220
|
```
|
|
221
221
|
|
|
222
222
|
**数据库配置映射**:
|
|
@@ -242,12 +242,12 @@ pkill -f "ssh.*15432:${DATABASE_HOST}:5432"
|
|
|
242
242
|
|
|
243
243
|
- `session-gateway`:
|
|
244
244
|
- 数据库: `optima_shell` ⚠️ (Stage 与 Prod 不同)
|
|
245
|
-
- 用户: Infisical `
|
|
246
|
-
- 密码: Infisical `
|
|
245
|
+
- 用户: Infisical `AI_SHELL_DB_USER`
|
|
246
|
+
- 密码: Infisical `AI_SHELL_DB_PASSWORD`
|
|
247
247
|
|
|
248
248
|
**说明**:
|
|
249
249
|
- Infisical 配置从 GitHub Variables 获取
|
|
250
|
-
- 数据库密钥从 Infisical 动态获取(项目: optima-secrets, 环境: staging, 路径: /
|
|
250
|
+
- 数据库密钥从 Infisical 动态获取(项目: optima-secrets-v2, 环境: staging, 路径: /shared-secrets/database-users)
|
|
251
251
|
- Stage RDS: `optima-stage-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com`
|
|
252
252
|
- Shared EC2 IP: `13.251.46.219`
|
|
253
253
|
- SSH 隧道: 本地端口 `15432` → Shared EC2 → Stage RDS `5432`
|
|
@@ -280,11 +280,11 @@ INFISICAL_TOKEN=$(curl -s -X POST "${INFISICAL_URL}/api/v1/auth/universal-auth/l
|
|
|
280
280
|
| python3 -c "import sys, json; print(json.load(sys.stdin)['accessToken'])")
|
|
281
281
|
|
|
282
282
|
# 3. 从 Infisical 获取数据库配置(以 commerce-backend 为例)
|
|
283
|
-
|
|
283
|
+
# 项目: optima-secrets-v2, 路径: /shared-secrets/database-users
|
|
284
|
+
curl -s "${INFISICAL_URL}/api/v3/secrets/raw?workspaceId=${INFISICAL_PROJECT_ID}&environment=prod&secretPath=/shared-secrets/database-users" \
|
|
284
285
|
-H "Authorization: Bearer ${INFISICAL_TOKEN}" | python3 -c "
|
|
285
286
|
import sys, json
|
|
286
287
|
secrets = {s['secretKey']: s['secretValue'] for s in json.load(sys.stdin)['secrets']}
|
|
287
|
-
print(f\"DATABASE_HOST={secrets['DATABASE_HOST']}\")
|
|
288
288
|
print(f\"COMMERCE_DB_USER={secrets['COMMERCE_DB_USER']}\")
|
|
289
289
|
print(f\"COMMERCE_DB_PASSWORD={secrets['COMMERCE_DB_PASSWORD']}\")
|
|
290
290
|
" > /tmp/prod_db_config.sh && source /tmp/prod_db_config.sh
|
|
@@ -345,7 +345,7 @@ pkill -f "ssh.*15433:${DATABASE_HOST}:5432"
|
|
|
345
345
|
|
|
346
346
|
**说明**:
|
|
347
347
|
- Infisical 配置从 GitHub Variables 获取
|
|
348
|
-
- 数据库密钥从 Infisical 动态获取(项目: optima-secrets, 环境: prod, 路径: /
|
|
348
|
+
- 数据库密钥从 Infisical 动态获取(项目: optima-secrets-v2, 环境: prod, 路径: /shared-secrets/database-users)
|
|
349
349
|
- Prod RDS: `optima-prod-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com`
|
|
350
350
|
- Shared EC2 IP: `13.251.46.219`
|
|
351
351
|
- SSH 隧道: 本地端口 `15433` → Shared EC2 → Prod RDS `5432`
|
|
@@ -178,6 +178,33 @@ optima-query-db commerce-backend "SELECT status, COUNT(*) FROM orders GROUP BY s
|
|
|
178
178
|
- 通过 SSH 隧道访问 RDS
|
|
179
179
|
- ⚠️ 谨慎使用
|
|
180
180
|
|
|
181
|
+
## 🔧 技术架构
|
|
182
|
+
|
|
183
|
+
### Infisical 配置(v0.7.0+)
|
|
184
|
+
|
|
185
|
+
数据库凭证从 Infisical 动态获取:
|
|
186
|
+
- **项目**: `optima-secrets-v2`
|
|
187
|
+
- **路径**: `/shared-secrets/database-users`
|
|
188
|
+
- **环境**: Stage 用 `staging`,Prod 用 `prod`
|
|
189
|
+
|
|
190
|
+
**凭证 Key 映射**:
|
|
191
|
+
| 服务 | 用户 Key | 密码 Key |
|
|
192
|
+
|------|----------|----------|
|
|
193
|
+
| commerce-backend | `COMMERCE_DB_USER` | `COMMERCE_DB_PASSWORD` |
|
|
194
|
+
| user-auth | `AUTH_DB_USER` | `AUTH_DB_PASSWORD` |
|
|
195
|
+
| agentic-chat | `CHAT_DB_USER` | `CHAT_DB_PASSWORD` |
|
|
196
|
+
| bi-backend | `BI_DB_USER` | `BI_DB_PASSWORD` |
|
|
197
|
+
| session-gateway | `AI_SHELL_DB_USER` | `AI_SHELL_DB_PASSWORD` |
|
|
198
|
+
|
|
199
|
+
### RDS 连接
|
|
200
|
+
|
|
201
|
+
| 环境 | RDS Host | 本地端口 |
|
|
202
|
+
|------|----------|----------|
|
|
203
|
+
| Stage | `optima-stage-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com` | 15432 |
|
|
204
|
+
| Prod | `optima-prod-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com` | 15433 |
|
|
205
|
+
|
|
206
|
+
**跳板机**: `13.251.46.219` (Shared EC2)
|
|
207
|
+
|
|
181
208
|
## 🔗 相关命令
|
|
182
209
|
|
|
183
210
|
- `optima-query-db` - CLI 查询工具(推荐)
|
package/bin/helpers/query-db.ts
CHANGED
|
@@ -40,7 +40,7 @@ const SERVICE_DB_MAP = {
|
|
|
40
40
|
},
|
|
41
41
|
'session-gateway': {
|
|
42
42
|
ci: null, // CI 环境暂无 session-gateway 数据库
|
|
43
|
-
stage: { userKey: '
|
|
43
|
+
stage: { userKey: 'AI_SHELL_DB_USER', passwordKey: 'AI_SHELL_DB_PASSWORD', database: 'optima_shell' },
|
|
44
44
|
prod: { userKey: 'AI_SHELL_DB_USER', passwordKey: 'AI_SHELL_DB_PASSWORD', database: 'optima_ai_shell' }
|
|
45
45
|
}
|
|
46
46
|
};
|
|
@@ -75,14 +75,14 @@ function getInfisicalToken(config: InfisicalConfig): string {
|
|
|
75
75
|
return JSON.parse(response).accessToken;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
function getInfisicalSecrets(config: InfisicalConfig, token: string, environment: string): Record<string, string> {
|
|
78
|
+
function getInfisicalSecrets(config: InfisicalConfig, token: string, environment: string, secretPath: string): Record<string, string> {
|
|
79
79
|
const response = execSync(
|
|
80
|
-
`curl -s "${config.url}/api/v3/secrets/raw?workspaceId=${config.projectId}&environment=${environment}&secretPath
|
|
80
|
+
`curl -s "${config.url}/api/v3/secrets/raw?workspaceId=${config.projectId}&environment=${environment}&secretPath=${secretPath}" -H "Authorization: Bearer ${token}"`,
|
|
81
81
|
{ encoding: 'utf-8' }
|
|
82
82
|
);
|
|
83
83
|
const data = JSON.parse(response);
|
|
84
84
|
const secrets: Record<string, string> = {};
|
|
85
|
-
for (const secret of data.secrets) {
|
|
85
|
+
for (const secret of data.secrets || []) {
|
|
86
86
|
secrets[secret.secretKey] = secret.secretValue;
|
|
87
87
|
}
|
|
88
88
|
return secrets;
|
|
@@ -223,8 +223,10 @@ async function main() {
|
|
|
223
223
|
const token = getInfisicalToken(infisicalConfig);
|
|
224
224
|
console.log('✓ Obtained Infisical access token');
|
|
225
225
|
|
|
226
|
-
//
|
|
227
|
-
|
|
226
|
+
// 数据库凭证存储在 Infisical 的 /shared-secrets/database-users 路径
|
|
227
|
+
// Stage 从 staging 环境读取,Prod 从 prod 环境读取
|
|
228
|
+
const infisicalEnv = environment === 'stage' ? 'staging' : 'prod';
|
|
229
|
+
const secrets = getInfisicalSecrets(infisicalConfig, token, infisicalEnv, '/shared-secrets/database-users');
|
|
228
230
|
console.log('✓ Retrieved database credentials from Infisical');
|
|
229
231
|
|
|
230
232
|
const { userKey, passwordKey, database } = serviceConfig as any;
|
|
@@ -59,7 +59,7 @@ const SERVICE_DB_MAP = {
|
|
|
59
59
|
},
|
|
60
60
|
'session-gateway': {
|
|
61
61
|
ci: null, // CI 环境暂无 session-gateway 数据库
|
|
62
|
-
stage: { userKey: '
|
|
62
|
+
stage: { userKey: 'AI_SHELL_DB_USER', passwordKey: 'AI_SHELL_DB_PASSWORD', database: 'optima_shell' },
|
|
63
63
|
prod: { userKey: 'AI_SHELL_DB_USER', passwordKey: 'AI_SHELL_DB_PASSWORD', database: 'optima_ai_shell' }
|
|
64
64
|
}
|
|
65
65
|
};
|
|
@@ -85,11 +85,11 @@ function getInfisicalToken(config) {
|
|
|
85
85
|
const response = (0, child_process_1.execSync)(`curl -s -X POST "${config.url}/api/v1/auth/universal-auth/login" -H "Content-Type: application/json" -d '{"clientId": "${config.clientId}", "clientSecret": "${config.clientSecret}"}'`, { encoding: 'utf-8' });
|
|
86
86
|
return JSON.parse(response).accessToken;
|
|
87
87
|
}
|
|
88
|
-
function getInfisicalSecrets(config, token, environment) {
|
|
89
|
-
const response = (0, child_process_1.execSync)(`curl -s "${config.url}/api/v3/secrets/raw?workspaceId=${config.projectId}&environment=${environment}&secretPath
|
|
88
|
+
function getInfisicalSecrets(config, token, environment, secretPath) {
|
|
89
|
+
const response = (0, child_process_1.execSync)(`curl -s "${config.url}/api/v3/secrets/raw?workspaceId=${config.projectId}&environment=${environment}&secretPath=${secretPath}" -H "Authorization: Bearer ${token}"`, { encoding: 'utf-8' });
|
|
90
90
|
const data = JSON.parse(response);
|
|
91
91
|
const secrets = {};
|
|
92
|
-
for (const secret of data.secrets) {
|
|
92
|
+
for (const secret of data.secrets || []) {
|
|
93
93
|
secrets[secret.secretKey] = secret.secretValue;
|
|
94
94
|
}
|
|
95
95
|
return secrets;
|
|
@@ -201,8 +201,10 @@ async function main() {
|
|
|
201
201
|
console.log('✓ Loaded Infisical config from GitHub Variables');
|
|
202
202
|
const token = getInfisicalToken(infisicalConfig);
|
|
203
203
|
console.log('✓ Obtained Infisical access token');
|
|
204
|
-
//
|
|
205
|
-
|
|
204
|
+
// 数据库凭证存储在 Infisical 的 /shared-secrets/database-users 路径
|
|
205
|
+
// Stage 从 staging 环境读取,Prod 从 prod 环境读取
|
|
206
|
+
const infisicalEnv = environment === 'stage' ? 'staging' : 'prod';
|
|
207
|
+
const secrets = getInfisicalSecrets(infisicalConfig, token, infisicalEnv, '/shared-secrets/database-users');
|
|
206
208
|
console.log('✓ Retrieved database credentials from Infisical');
|
|
207
209
|
const { userKey, passwordKey, database } = serviceConfig;
|
|
208
210
|
const dbHost = RDS_HOSTS[environment];
|