@optima-chat/dev-skills 0.3.0 → 0.4.0
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.
- package/.claude/commands/query-db.md +160 -21
- package/.claude/settings.local.json +6 -1
- package/package.json +1 -1
|
@@ -114,47 +114,186 @@ sshpass -p "$CI_PASSWORD" ssh -o StrictHostKeyChecking=no ${CI_USER}@${CI_HOST}
|
|
|
114
114
|
|
|
115
115
|
### 1. Stage 环境(environment = "stage")
|
|
116
116
|
|
|
117
|
-
**访问方式**:
|
|
117
|
+
**访问方式**: 通过 EC2 SSH 隧道访问 RDS(通过 Infisical 获取密钥)
|
|
118
|
+
|
|
119
|
+
**前置条件**:
|
|
120
|
+
1. 获取 `optima-ec2-key` SSH 密钥文件(联系 xbfool)
|
|
121
|
+
2. 保存到 `~/.ssh/optima-ec2-key` 并设置权限: `chmod 600 ~/.ssh/optima-ec2-key`
|
|
118
122
|
|
|
119
123
|
**步骤**:
|
|
120
124
|
```bash
|
|
121
125
|
# IMPORTANT: 使用单行命令
|
|
122
126
|
|
|
123
|
-
#
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
# 1. 获取 Infisical 配置
|
|
128
|
+
INFISICAL_URL=$(gh variable get INFISICAL_URL -R Optima-Chat/optima-dev-skills)
|
|
129
|
+
INFISICAL_CLIENT_ID=$(gh variable get INFISICAL_CLIENT_ID -R Optima-Chat/optima-dev-skills)
|
|
130
|
+
INFISICAL_CLIENT_SECRET=$(gh variable get INFISICAL_CLIENT_SECRET -R Optima-Chat/optima-dev-skills)
|
|
131
|
+
INFISICAL_PROJECT_ID=$(gh variable get INFISICAL_PROJECT_ID -R Optima-Chat/optima-dev-skills)
|
|
132
|
+
|
|
133
|
+
# 2. 获取 Infisical Access Token
|
|
134
|
+
INFISICAL_TOKEN=$(curl -s -X POST "${INFISICAL_URL}/api/v1/auth/universal-auth/login" \
|
|
135
|
+
-H "Content-Type: application/json" \
|
|
136
|
+
-d "{\"clientId\": \"${INFISICAL_CLIENT_ID}\", \"clientSecret\": \"${INFISICAL_CLIENT_SECRET}\"}" \
|
|
137
|
+
| python3 -c "import sys, json; print(json.load(sys.stdin)['accessToken'])")
|
|
138
|
+
|
|
139
|
+
# 3. 从 Infisical 获取数据库配置(以 commerce-backend 为例)
|
|
140
|
+
curl -s "${INFISICAL_URL}/api/v3/secrets/raw?workspaceId=${INFISICAL_PROJECT_ID}&environment=staging&secretPath=/infrastructure" \
|
|
141
|
+
-H "Authorization: Bearer ${INFISICAL_TOKEN}" | python3 -c "
|
|
142
|
+
import sys, json
|
|
143
|
+
secrets = {s['secretKey']: s['secretValue'] for s in json.load(sys.stdin)['secrets']}
|
|
144
|
+
print(f\"DATABASE_HOST={secrets['DATABASE_HOST']}\")
|
|
145
|
+
print(f\"COMMERCE_DB_USER={secrets['COMMERCE_DB_USER']}\")
|
|
146
|
+
print(f\"COMMERCE_DB_PASSWORD={secrets['COMMERCE_DB_PASSWORD']}\")
|
|
147
|
+
" > /tmp/stage_db_config.sh && source /tmp/stage_db_config.sh
|
|
148
|
+
|
|
149
|
+
# 4. 建立 SSH 隧道到 Stage EC2,通过隧道访问 RDS
|
|
150
|
+
ssh -i ~/.ssh/optima-ec2-key -f -N -L 15432:${DATABASE_HOST}:5432 ec2-user@54.179.132.102
|
|
151
|
+
|
|
152
|
+
# 5. 通过本地端口 15432 连接到 RDS
|
|
153
|
+
PGPASSWORD="${COMMERCE_DB_PASSWORD}" psql -h localhost -p 15432 -U "${COMMERCE_DB_USER}" -d optima_stage_commerce -c "SELECT COUNT(*) FROM products"
|
|
154
|
+
|
|
155
|
+
# 6. 关闭 SSH 隧道(可选)
|
|
156
|
+
pkill -f "ssh.*15432:${DATABASE_HOST}:5432"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**完整示例(四个服务)**:
|
|
160
|
+
```bash
|
|
161
|
+
# commerce-backend
|
|
162
|
+
# 使用 COMMERCE_DB_USER, COMMERCE_DB_PASSWORD, 数据库: optima_stage_commerce
|
|
163
|
+
|
|
164
|
+
# user-auth
|
|
165
|
+
# 使用 AUTH_DB_USER, AUTH_DB_PASSWORD, 数据库: optima_stage_auth
|
|
126
166
|
|
|
127
|
-
#
|
|
128
|
-
|
|
167
|
+
# mcp-host
|
|
168
|
+
# 使用 MCP_DB_USER, MCP_DB_PASSWORD, 数据库: optima_stage_mcp
|
|
169
|
+
|
|
170
|
+
# agentic-chat
|
|
171
|
+
# 使用 CHAT_DB_USER, CHAT_DB_PASSWORD, 数据库: optima_stage_chat
|
|
129
172
|
```
|
|
130
173
|
|
|
131
|
-
|
|
132
|
-
- `
|
|
133
|
-
- `
|
|
134
|
-
-
|
|
174
|
+
**数据库配置映射**:
|
|
175
|
+
- `commerce-backend`:
|
|
176
|
+
- 数据库: `optima_stage_commerce`
|
|
177
|
+
- 用户: Infisical `COMMERCE_DB_USER`
|
|
178
|
+
- 密码: Infisical `COMMERCE_DB_PASSWORD`
|
|
179
|
+
|
|
180
|
+
- `user-auth`:
|
|
181
|
+
- 数据库: `optima_stage_auth`
|
|
182
|
+
- 用户: Infisical `AUTH_DB_USER`
|
|
183
|
+
- 密码: Infisical `AUTH_DB_PASSWORD`
|
|
184
|
+
|
|
185
|
+
- `mcp-host`:
|
|
186
|
+
- 数据库: `optima_stage_mcp`
|
|
187
|
+
- 用户: Infisical `MCP_DB_USER`
|
|
188
|
+
- 密码: Infisical `MCP_DB_PASSWORD`
|
|
189
|
+
|
|
190
|
+
- `agentic-chat`:
|
|
191
|
+
- 数据库: `optima_stage_chat`
|
|
192
|
+
- 用户: Infisical `CHAT_DB_USER`
|
|
193
|
+
- 密码: Infisical `CHAT_DB_PASSWORD`
|
|
194
|
+
|
|
195
|
+
**说明**:
|
|
196
|
+
- Infisical 配置从 GitHub Variables 获取
|
|
197
|
+
- 数据库密钥从 Infisical 动态获取(项目: optima-secrets, 环境: staging, 路径: /infrastructure)
|
|
198
|
+
- DATABASE_HOST: `optima-prod-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com`
|
|
199
|
+
- Stage EC2 IP: `54.179.132.102`
|
|
200
|
+
- SSH 隧道: 本地端口 `15432` → EC2 → RDS `5432`
|
|
201
|
+
- Stage 和 Prod 共享同一个 RDS 实例,通过不同的数据库名隔离
|
|
135
202
|
|
|
136
203
|
### 2. Prod 环境(environment = "prod")
|
|
137
204
|
|
|
138
|
-
**访问方式**:
|
|
205
|
+
**访问方式**: 通过 EC2 SSH 隧道访问 RDS(通过 Infisical 获取密钥)
|
|
206
|
+
|
|
207
|
+
**前置条件**:
|
|
208
|
+
1. 获取 `optima-ec2-key` SSH 密钥文件(联系 xbfool)
|
|
209
|
+
2. 保存到 `~/.ssh/optima-ec2-key` 并设置权限: `chmod 600 ~/.ssh/optima-ec2-key`
|
|
139
210
|
|
|
140
211
|
**步骤**:
|
|
141
212
|
```bash
|
|
142
213
|
# IMPORTANT: 使用单行命令
|
|
143
|
-
# ⚠️
|
|
214
|
+
# ⚠️ 生产环境谨慎操作
|
|
215
|
+
|
|
216
|
+
# 1. 获取 Infisical 配置
|
|
217
|
+
INFISICAL_URL=$(gh variable get INFISICAL_URL -R Optima-Chat/optima-dev-skills)
|
|
218
|
+
INFISICAL_CLIENT_ID=$(gh variable get INFISICAL_CLIENT_ID -R Optima-Chat/optima-dev-skills)
|
|
219
|
+
INFISICAL_CLIENT_SECRET=$(gh variable get INFISICAL_CLIENT_SECRET -R Optima-Chat/optima-dev-skills)
|
|
220
|
+
INFISICAL_PROJECT_ID=$(gh variable get INFISICAL_PROJECT_ID -R Optima-Chat/optima-dev-skills)
|
|
221
|
+
|
|
222
|
+
# 2. 获取 Infisical Access Token
|
|
223
|
+
INFISICAL_TOKEN=$(curl -s -X POST "${INFISICAL_URL}/api/v1/auth/universal-auth/login" \
|
|
224
|
+
-H "Content-Type: application/json" \
|
|
225
|
+
-d "{\"clientId\": \"${INFISICAL_CLIENT_ID}\", \"clientSecret\": \"${INFISICAL_CLIENT_SECRET}\"}" \
|
|
226
|
+
| python3 -c "import sys, json; print(json.load(sys.stdin)['accessToken'])")
|
|
227
|
+
|
|
228
|
+
# 3. 从 Infisical 获取数据库配置(以 commerce-backend 为例)
|
|
229
|
+
curl -s "${INFISICAL_URL}/api/v3/secrets/raw?workspaceId=${INFISICAL_PROJECT_ID}&environment=prod&secretPath=/infrastructure" \
|
|
230
|
+
-H "Authorization: Bearer ${INFISICAL_TOKEN}" | python3 -c "
|
|
231
|
+
import sys, json
|
|
232
|
+
secrets = {s['secretKey']: s['secretValue'] for s in json.load(sys.stdin)['secrets']}
|
|
233
|
+
print(f\"DATABASE_HOST={secrets['DATABASE_HOST']}\")
|
|
234
|
+
print(f\"COMMERCE_DB_USER={secrets['COMMERCE_DB_USER']}\")
|
|
235
|
+
print(f\"COMMERCE_DB_PASSWORD={secrets['COMMERCE_DB_PASSWORD']}\")
|
|
236
|
+
" > /tmp/prod_db_config.sh && source /tmp/prod_db_config.sh
|
|
237
|
+
|
|
238
|
+
# 4. 建立 SSH 隧道到 Prod EC2,通过隧道访问 RDS
|
|
239
|
+
ssh -i ~/.ssh/optima-ec2-key -f -N -L 15433:${DATABASE_HOST}:5432 ec2-user@18.136.25.239
|
|
240
|
+
|
|
241
|
+
# 5. 通过本地端口 15433 连接到 RDS
|
|
242
|
+
PGPASSWORD="${COMMERCE_DB_PASSWORD}" psql -h localhost -p 15433 -U "${COMMERCE_DB_USER}" -d optima_commerce -c "SELECT COUNT(*) FROM products"
|
|
243
|
+
|
|
244
|
+
# 6. 关闭 SSH 隧道(可选)
|
|
245
|
+
pkill -f "ssh.*15433:${DATABASE_HOST}:5432"
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**完整示例(四个服务)**:
|
|
249
|
+
```bash
|
|
250
|
+
# commerce-backend
|
|
251
|
+
# 使用 COMMERCE_DB_USER, COMMERCE_DB_PASSWORD, 数据库: optima_commerce
|
|
252
|
+
|
|
253
|
+
# user-auth
|
|
254
|
+
# 使用 AUTH_DB_USER, AUTH_DB_PASSWORD, 数据库: optima_auth
|
|
144
255
|
|
|
145
|
-
#
|
|
146
|
-
|
|
147
|
-
PROD_DB_PASSWORD=$(gh variable get PROD_DB_PASSWORD -R Optima-Chat/optima-dev-skills)
|
|
256
|
+
# mcp-host
|
|
257
|
+
# 使用 MCP_DB_USER, MCP_DB_PASSWORD, 数据库: optima_mcp
|
|
148
258
|
|
|
149
|
-
#
|
|
150
|
-
|
|
259
|
+
# agentic-chat
|
|
260
|
+
# 使用 CHAT_DB_USER, CHAT_DB_PASSWORD, 数据库: optima_chat
|
|
151
261
|
```
|
|
152
262
|
|
|
263
|
+
**数据库配置映射**:
|
|
264
|
+
- `commerce-backend`:
|
|
265
|
+
- 数据库: `optima_commerce`
|
|
266
|
+
- 用户: Infisical `COMMERCE_DB_USER`
|
|
267
|
+
- 密码: Infisical `COMMERCE_DB_PASSWORD`
|
|
268
|
+
|
|
269
|
+
- `user-auth`:
|
|
270
|
+
- 数据库: `optima_auth`
|
|
271
|
+
- 用户: Infisical `AUTH_DB_USER`
|
|
272
|
+
- 密码: Infisical `AUTH_DB_PASSWORD`
|
|
273
|
+
|
|
274
|
+
- `mcp-host`:
|
|
275
|
+
- 数据库: `optima_mcp`
|
|
276
|
+
- 用户: Infisical `MCP_DB_USER`
|
|
277
|
+
- 密码: Infisical `MCP_DB_PASSWORD`
|
|
278
|
+
|
|
279
|
+
- `agentic-chat`:
|
|
280
|
+
- 数据库: `optima_chat`
|
|
281
|
+
- 用户: Infisical `CHAT_DB_USER`
|
|
282
|
+
- 密码: Infisical `CHAT_DB_PASSWORD`
|
|
283
|
+
|
|
284
|
+
**说明**:
|
|
285
|
+
- Infisical 配置从 GitHub Variables 获取
|
|
286
|
+
- 数据库密钥从 Infisical 动态获取(项目: optima-secrets, 环境: prod, 路径: /infrastructure)
|
|
287
|
+
- DATABASE_HOST: `optima-prod-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com`
|
|
288
|
+
- Prod EC2 IP: `18.136.25.239`
|
|
289
|
+
- SSH 隧道: 本地端口 `15433` → EC2 → RDS `5432` (注意 Prod 用 15433,Stage 用 15432)
|
|
290
|
+
- Stage 和 Prod 共享同一个 RDS 实例,通过不同的数据库名隔离
|
|
291
|
+
|
|
153
292
|
**⚠️ 生产环境安全规则**:
|
|
154
|
-
1.
|
|
155
|
-
2.
|
|
156
|
-
3.
|
|
157
|
-
4.
|
|
293
|
+
1. **谨慎操作** - 生产数据库,避免误操作
|
|
294
|
+
2. **避免 DELETE/UPDATE** - 除非明确需要
|
|
295
|
+
3. **使用 LIMIT** - 防止查询过多数据
|
|
296
|
+
4. **不查敏感数据** - 避免查询密码、密钥等
|
|
158
297
|
|
|
159
298
|
## 安全注意事项
|
|
160
299
|
|
|
@@ -23,7 +23,12 @@
|
|
|
23
23
|
"Bash(npm install:*)",
|
|
24
24
|
"Bash(optima-dev-skills:*)",
|
|
25
25
|
"Bash(gh variable set:*)",
|
|
26
|
-
"Bash(npm publish:*)"
|
|
26
|
+
"Bash(npm publish:*)",
|
|
27
|
+
"Bash(curl -s \"https://secrets.optima.onl/api/v3/secrets/raw?workspaceId=f2415dc2-f79d-4e41-90bb-cd3d2631ec71&environment=staging&secretPath=/infrastructure\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eUlkIjoiMjZiNmYxMmItZjNjYy00OTE2LTliMTItNWFiYzZhMTlmNGI0IiwiY2xpZW50U2VjcmV0SWQiOiIxZjRhM2I0Ni03NTZmLTQwNmItOGQ1OS0yODI0YjUzOGFlMmMiLCJpZGVudGl0eUFjY2Vzc1Rva2VuSWQiOiJlMDQ1Y2MyOC02Nzk5LTRhODYtYWEwNy02YTQ4NmZkYzczODgiLCJhdXRoVG9rZW5UeXBlIjoiaWRlbnRpdHlBY2Nlc3NUb2tlbiIsImlhdCI6MTc2MzkxMzAxNywiZXhwIjoxNzY2NTA1MDE3fQ.xkPyv9MwXKLg3t-h1C_6mHSV5-cFuuvHnrkOoaGtuaQ\")",
|
|
28
|
+
"Bash(python3:*)",
|
|
29
|
+
"Bash(curl -s \"https://secrets.optima.onl/api/v1/folders?workspaceId=f2415dc2-f79d-4e41-90bb-cd3d2631ec71&environment=prod\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eUlkIjoiMjZiNmYxMmItZjNjYy00OTE2LTliMTItNWFiYzZhMTlmNGI0IiwiY2xpZW50U2VjcmV0SWQiOiIxZjRhM2I0Ni03NTZmLTQwNmItOGQ1OS0yODI0YjUzOGFlMmMiLCJpZGVudGl0eUFjY2Vzc1Rva2VuSWQiOiJlMDQ1Y2MyOC02Nzk5LTRhODYtYWEwNy02YTQ4NmZkYzczODgiLCJhdXRoVG9rZW5UeXBlIjoiaWRlbnRpdHlBY2Nlc3NUb2tlbiIsImlhdCI6MTc2MzkxMzAxNywiZXhwIjoxNzY2NTA1MDE3fQ.xkPyv9MwXKLg3t-h1C_6mHSV5-cFuuvHnrkOoaGtuaQ\")",
|
|
30
|
+
"Bash(curl -s \"https://secrets.optima.onl/api/v3/secrets/raw?workspaceId=f2415dc2-f79d-4e41-90bb-cd3d2631ec71&environment=prod&secretPath=/infrastructure\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eUlkIjoiMjZiNmYxMmItZjNjYy00OTE2LTliMTItNWFiYzZhMTlmNGI0IiwiY2xpZW50U2VjcmV0SWQiOiIxZjRhM2I0Ni03NTZmLTQwNmItOGQ1OS0yODI0YjUzOGFlMmMiLCJpZGVudGl0eUFjY2Vzc1Rva2VuSWQiOiJlMDQ1Y2MyOC02Nzk5LTRhODYtYWEwNy02YTQ4NmZkYzczODgiLCJhdXRoVG9rZW5UeXBlIjoiaWRlbnRpdHlBY2Nlc3NUb2tlbiIsImlhdCI6MTc2MzkxMzAxNywiZXhwIjoxNzY2NTA1MDE3fQ.xkPyv9MwXKLg3t-h1C_6mHSV5-cFuuvHnrkOoaGtuaQ\")",
|
|
31
|
+
"Bash(gh api:*)"
|
|
27
32
|
],
|
|
28
33
|
"deny": [],
|
|
29
34
|
"ask": []
|