create-dwy 0.5.0 → 0.6.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.
Files changed (156) hide show
  1. package/bin/index.js +1 -1
  2. package/package.json +2 -2
  3. package/src/create.js +61 -37
  4. package/src/sync.js +213 -53
  5. package/templates/claude-global/CLAUDE.md +92 -0
  6. package/templates/claude-global/rules/dwy-android-core.md +610 -0
  7. package/templates/claude-global/rules/dwy-api-design.md +110 -0
  8. package/templates/claude-global/rules/dwy-db-migration.md +46 -0
  9. package/templates/claude-global/rules/dwy-flutter-core.md +564 -0
  10. package/templates/claude-global/rules/dwy-flutter-network.md +222 -0
  11. package/templates/claude-global/rules/dwy-flutter-router.md +97 -0
  12. package/templates/claude-global/rules/dwy-flutter-testing.md +94 -0
  13. package/templates/claude-global/rules/dwy-git-commit-convention.md +82 -0
  14. package/templates/claude-global/rules/dwy-git-security.md +53 -0
  15. package/templates/claude-global/rules/dwy-payload-limits.md +178 -0
  16. package/templates/claude-global/rules/{prefer-open-source.md → dwy-prefer-open-source.md} +4 -0
  17. package/templates/claude-global/rules/dwy-project-structure.md +181 -0
  18. package/templates/claude-global/rules/{python-code-style.md → dwy-python-core.md} +314 -357
  19. package/templates/claude-global/rules/dwy-python-fastapi.md +272 -0
  20. package/templates/claude-global/rules/dwy-python-orm.md +61 -0
  21. package/templates/claude-global/rules/{backend-security.md → dwy-python-security.md} +116 -79
  22. package/templates/claude-global/rules/dwy-python-testing.md +53 -0
  23. package/templates/claude-global/rules/{server-security.md → dwy-server-security.md} +1 -2
  24. package/templates/claude-global/rules/dwy-tdd-development.md +70 -0
  25. package/templates/claude-global/rules/dwy-tech-stack.md +60 -0
  26. package/templates/claude-global/rules/dwy-vue-api.md +146 -0
  27. package/templates/claude-global/rules/{vue-code-style.md → dwy-vue-core.md} +361 -152
  28. package/templates/claude-global/rules/dwy-vue-pinia.md +75 -0
  29. package/templates/claude-global/rules/dwy-vue-testing.md +102 -0
  30. package/templates/claude-global/settings.json +20 -0
  31. package/templates/claude-global/skills/dwy-deploy-audit/SKILL.md +481 -0
  32. package/templates/claude-global/skills/dwy-deploy-audit/references/checks-data.md +117 -0
  33. package/templates/claude-global/skills/dwy-deploy-audit/references/checks-network.md +74 -0
  34. package/templates/claude-global/skills/dwy-deploy-audit/references/checks-runtime.md +184 -0
  35. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_base.sh +39 -0
  36. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_capacity.sh +278 -0
  37. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_db.sh +122 -0
  38. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_docker.sh +249 -0
  39. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_env.sh +64 -0
  40. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_https.sh +60 -0
  41. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_logs.sh +209 -0
  42. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_nginx.sh +92 -0
  43. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_resilience.sh +157 -0
  44. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_secrets.sh +327 -0
  45. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_services.sh +77 -0
  46. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_ssh.sh +56 -0
  47. package/templates/claude-global/skills/dwy-deploy-audit/scripts/run_all.sh +105 -0
  48. package/templates/claude-global/skills/dwy-docker/SKILL.md +187 -0
  49. package/templates/claude-global/skills/dwy-docker/references/ask-templates.md +142 -0
  50. package/templates/claude-global/skills/dwy-docker/references/templates.md +479 -0
  51. package/templates/claude-global/skills/dwy-docker/references/version-rules.md +76 -0
  52. package/templates/claude-global/skills/dwy-docker/scripts/query_dockerhub.py +204 -0
  53. package/templates/claude-global/skills/dwy-docker/scripts/scan_images.sh +185 -0
  54. package/templates/claude-global/skills/dwy-eapi/SKILL.md +433 -0
  55. package/templates/claude-global/skills/dwy-eapi/references/tasks-integration-guide.md +387 -0
  56. package/templates/claude-global/skills/dwy-ekit/SKILL.md +85 -0
  57. package/templates/claude-global/skills/dwy-ekit/references/data.md +135 -0
  58. package/templates/claude-global/skills/dwy-ekit/references/form.md +68 -0
  59. package/templates/claude-global/skills/dwy-ekit/references/request.md +183 -0
  60. package/templates/claude-global/skills/dwy-ekit/references/ui.md +109 -0
  61. package/templates/claude-global/skills/{dwy-frontend-eui → dwy-eui}/SKILL.md +129 -15
  62. package/templates/claude-global/skills/dwy-eui/references/eui-design-guide.md +257 -0
  63. package/templates/claude-global/skills/dwy-eui/references/eui-integration-guide.md +302 -0
  64. package/templates/claude-global/skills/dwy-eui/references/eui-landing-design-guide.md +437 -0
  65. package/templates/claude-global/skills/dwy-fullstack-scaffold/SKILL.md +214 -0
  66. package/templates/claude-global/skills/dwy-mirror-source/SKILL.md +275 -0
  67. package/templates/claude-global/skills/dwy-mirror-source/references/dockerfile-snippets.md +228 -0
  68. package/templates/claude-global/skills/dwy-mirror-source/references/mirror-providers.md +150 -0
  69. package/templates/claude-global/skills/dwy-mirror-source/scripts/__pycache__/check_mirrors.cpython-313.pyc +0 -0
  70. package/templates/claude-global/skills/dwy-mirror-source/scripts/apply_mirrors.py +666 -0
  71. package/templates/claude-global/skills/dwy-mirror-source/scripts/check_mirrors.py +868 -0
  72. package/templates/claude-global/skills/dwy-pentest/SKILL.md +344 -0
  73. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__init__.py +1 -0
  74. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__pycache__/__init__.cpython-311.pyc +0 -0
  75. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__pycache__/config.cpython-311.pyc +0 -0
  76. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__pycache__/executor.cpython-311.pyc +0 -0
  77. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__pycache__/severity.cpython-311.pyc +0 -0
  78. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__pycache__/validator.cpython-311.pyc +0 -0
  79. package/templates/claude-global/skills/dwy-pentest/scripts/lib/config.py +109 -0
  80. package/templates/claude-global/skills/dwy-pentest/scripts/lib/executor.py +157 -0
  81. package/templates/claude-global/skills/dwy-pentest/scripts/lib/severity.py +96 -0
  82. package/templates/claude-global/skills/dwy-pentest/scripts/lib/validator.py +113 -0
  83. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_auth.py +289 -0
  84. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_recon.py +217 -0
  85. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_report.py +343 -0
  86. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_scan.py +205 -0
  87. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_ssl.py +208 -0
  88. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_vuln.py +205 -0
  89. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_web.py +330 -0
  90. package/templates/claude-global/skills/dwy-pentest/scripts/pyproject.toml +14 -0
  91. package/templates/claude-global/skills/dwy-pentest/scripts/setup_tools.sh +97 -0
  92. package/templates/claude-global/skills/dwy-pentest/scripts/uv.lock +415 -0
  93. package/templates/claude-global/skills/dwy-publish/SKILL.md +135 -0
  94. package/templates/claude-global/skills/dwy-vue-core/SKILL.md +890 -0
  95. package/templates/project/backend/.dwy.hbs +5 -0
  96. package/templates/project/backend/.python-version +1 -0
  97. package/templates/project/backend/CLAUDE.md.hbs +40 -0
  98. package/templates/project/{web/backend → backend}/alembic/script.py.mako +2 -0
  99. package/templates/project/{web/backend → backend}/alembic.ini.hbs +0 -1
  100. package/templates/project/backend/deploy.sh.hbs +18 -0
  101. package/templates/project/{web → backend}/docker-compose.prod.yml.hbs +1 -1
  102. package/templates/project/{web/backend → backend}/pyproject.toml.hbs +4 -5
  103. package/templates/project/{web/backend → backend}/src/app/config.py.hbs +1 -1
  104. package/templates/project/backend/src/app/database.py +10 -0
  105. package/templates/project/backend/src/app/dependencies.py +5 -0
  106. package/templates/project/{web/backend → backend}/src/app/main.py.hbs +3 -3
  107. package/templates/project/backend/src/app/models/base.py +5 -0
  108. package/templates/project/web/CLAUDE.md.hbs +29 -36
  109. package/templates/project/web/{frontend → apps/web}/index.html.hbs +1 -0
  110. package/templates/project/web/{frontend → apps/web}/package.json.hbs +4 -3
  111. package/templates/project/web/apps/web/src/App.vue +9 -0
  112. package/templates/project/web/apps/web/src/api/client.ts +5 -0
  113. package/templates/project/web/apps/web/src/composables/.gitkeep +0 -0
  114. package/templates/project/web/apps/web/src/layouts/DefaultLayout.vue +8 -0
  115. package/templates/project/web/{frontend → apps/web}/src/router/index.ts +1 -1
  116. package/templates/project/web/{frontend → apps/web}/src/stores/auth.ts +4 -2
  117. package/templates/project/web/apps/web/src/style.css +2 -0
  118. package/templates/project/web/apps/web/src/types/router.d.ts +8 -0
  119. package/templates/project/web/apps/web/src/views/HomeView.vue +8 -0
  120. package/templates/project/web/apps/web/tsconfig.app.json +18 -0
  121. package/templates/project/web/apps/web/tsconfig.json +6 -0
  122. package/templates/project/web/{frontend → apps/web}/vite.config.ts.hbs +7 -1
  123. package/templates/project/web/package.json.hbs +16 -0
  124. package/templates/project/web/packages/.gitkeep +0 -0
  125. package/templates/project/web/pnpm-workspace.yaml +3 -0
  126. package/templates/claude-global/rules/agent-team-execution.md +0 -138
  127. package/templates/claude-global/rules/agent-team-patterns.md +0 -157
  128. package/templates/claude-global/rules/git-security.md +0 -144
  129. package/templates/claude-global/skills/dwy-auto-sync/SKILL.md +0 -52
  130. package/templates/claude-global/skills/dwy-backend-base/SKILL.md +0 -279
  131. package/templates/claude-global/skills/dwy-frontend-core/SKILL.md +0 -181
  132. package/templates/project/web/.claude/commands/deploy.md +0 -4
  133. package/templates/project/web/backend/src/app/models/base.py +0 -5
  134. package/templates/project/web/deploy.sh.hbs +0 -113
  135. package/templates/project/web/frontend/src/App.vue +0 -3
  136. package/templates/project/web/frontend/src/api/client.ts +0 -13
  137. package/templates/project/web/frontend/src/style.css +0 -1
  138. package/templates/project/web/frontend/src/views/HomeView.vue +0 -5
  139. package/templates/project/web/frontend/tsconfig.app.json +0 -14
  140. package/templates/project/web/frontend/tsconfig.json +0 -4
  141. /package/templates/{project/web/backend → claude-global/skills/dwy-pentest/scripts}/.python-version +0 -0
  142. /package/templates/project/{web/backend → backend}/Dockerfile +0 -0
  143. /package/templates/project/{web/backend → backend}/alembic/env.py.hbs +0 -0
  144. /package/templates/{claude-global/skills → project/backend/alembic/versions}/.gitkeep +0 -0
  145. /package/templates/project/{web → backend}/docker-compose.dev.yml.hbs +0 -0
  146. /package/templates/project/{web/backend → backend}/src/app/__init__.py +0 -0
  147. /package/templates/project/{web/backend → backend}/src/app/models/__init__.py +0 -0
  148. /package/templates/project/{web/backend → backend}/src/app/routers/__init__.py +0 -0
  149. /package/templates/project/{web/backend → backend}/src/app/routers/health.py +0 -0
  150. /package/templates/project/{web/backend → backend}/src/app/schemas/__init__.py +0 -0
  151. /package/templates/project/{web/backend → backend}/src/app/services/__init__.py +0 -0
  152. /package/templates/project/{web/backend → backend}/tests/__init__.py +0 -0
  153. /package/templates/project/{web/backend → backend}/tests/conftest.py.hbs +0 -0
  154. /package/templates/project/{web/backend/alembic/versions → mobile}/.gitkeep +0 -0
  155. /package/templates/project/web/{frontend → apps/web}/src/components/.gitkeep +0 -0
  156. /package/templates/project/web/{frontend → apps/web}/src/main.ts +0 -0
@@ -0,0 +1,187 @@
1
+ ---
2
+ name: dwy-docker
3
+ description: "Docker 工程规范检查与镜像版本管理。触发场景:用户编辑/新建/粘贴 Dockerfile / docker-compose / k8s manifest / .github workflow / .gitlab-ci / .dockerignore / dev.sh 时;用户口头提到 docker / 容器 / compose / 镜像版本 / k8s 镜像时;用户说'扫描 latest' / '检查 docker' / '固定镜像版本' / 'docker 规范'。运作方式:问题驱动 — AI 检查合规性,合规则静默放行,违规才用 AskUserQuestion 让用户决策修复,禁止 AI 自行拍板修改。覆盖镜像版本(禁 latest / 浮动 tag、N-1 minor)、Dockerfile 工程(多阶段、non-root、.dockerignore)、compose 工程(dev/prod 分离、healthcheck、restart 策略)、一键启动 dev.sh。"
4
+ ---
5
+
6
+ # Docker 工程规范
7
+
8
+ 涵盖镜像版本选择 + Dockerfile / docker-compose / k8s manifest 工程结构。
9
+
10
+ **脚本目录:** `~/.claude/skills/dwy-docker/scripts/`(以下简称 `{scripts}`)
11
+
12
+ **参考文件:** `~/.claude/skills/dwy-docker/references/`
13
+ - `templates.md` — compose / Dockerfile / dev.sh 模板(用户问"怎么写"时读)
14
+ - `version-rules.md` — N-1 minor 选法 + 各类镜像表(选具体版本号时读)
15
+ - `ask-templates.md` — AskUserQuestion 模板(违规需要询问用户时读)
16
+
17
+ ---
18
+
19
+ ## 运作原则(最重要)
20
+
21
+ **问题驱动 + 不打扰用户**。
22
+
23
+ | 用户当前文件状态 | AI 行为 |
24
+ |---|---|
25
+ | 已合规(tag 固定 / Dockerfile 多阶段 / compose 分离) | **静默放行**,不打扰 |
26
+ | 违规(latest / 浮动 tag / 单一 compose / 缺 healthcheck 等) | 自动 `AskUserQuestion`,让用户决策 |
27
+ | AI 即将新写入(用户让我加 redis 服务) | 先 query_dockerhub.py + AskUserQuestion 选 tag,再写入 |
28
+
29
+ **为什么这样设计**:用户写 docker 一半被中断 N 次问"要选哪个版本"会很烦;已经写了 `nginx:1.26.2` 这种合规字段也不该 AI 啰嗦"建议你改成…"。只在违规时才介入。
30
+
31
+ **禁止**:
32
+ - AI 自行决定违规项的修复方案后直接 Edit
33
+ - 对已合规的字段啰嗦"建议你改成…"
34
+ - 对每个 `image:` 字段都强制询问,即使它已经是合规的具体版本号
35
+
36
+ ---
37
+
38
+ ## 触发场景
39
+
40
+ AI 看到下列情况之一,立即进入「检查清单」:
41
+
42
+ 1. 用户编辑 / 新建 / 修改:`Dockerfile`、`Dockerfile.*`、`*.Dockerfile`、`docker-compose*.yml`、`compose.yml`、`*.dockerignore`、`dev.sh`
43
+ 2. 用户在 K8s manifest(`.yaml` 含 `image:`)中改镜像
44
+ 3. 用户在 `.github/workflows/*.yml` 的 `container:` / `services:` 段或 `.gitlab-ci.yml` 的 `image:` 段改镜像
45
+ 4. 用户口头说"加 postgres" / "用 redis 当缓存" / "写个 Dockerfile" / "compose 怎么写"
46
+ 5. 用户说"扫描 latest" / "检查 docker" / "docker 规范"
47
+
48
+ ---
49
+
50
+ ## 检查清单
51
+
52
+ ### A. 镜像 tag(针对每个 `FROM` / `image:` 字段)
53
+
54
+ | 检测 | 严重度 | 触发 AskUserQuestion |
55
+ |---|---|---|
56
+ | `xxx:latest` 或 `xxx`(无 tag) | critical | ✓ 必须 |
57
+ | 浮动 tag:`stable` / `mainline` / `current` / `release` / `lts` / `rolling` / `main` / `master` / `head` / `edge` / `nightly` / `alpine` / `slim` / `bookworm` / `bullseye` / `buster` / `jammy` / `focal` / `noble` / `trixie` 单独使用 | high | ✓ 必须 |
58
+ | 单段版本号(如 `redis:7`,不到 minor) | high | ✓ 必须 |
59
+ | codename 不带版本号(如 `:bookworm`) | high | ✓ 必须 |
60
+ | 已固定到 `MAJOR.MINOR.PATCH` / `MAJOR.MINOR` 具体版本号 | — | ✗ 静默放行 |
61
+ | 生产关键服务(数据库、消息队列、网关)只有 tag 无 digest | low | ⚠ 仅在用户明确说"生产环境"时提示 |
62
+
63
+ → 修复时读 `references/ask-templates.md` 模板 1(tag 违规);选具体版本号读 `references/version-rules.md`。
64
+
65
+ ### B. Dockerfile 工程结构(针对生产 Dockerfile)
66
+
67
+ 文件名形如 `Dockerfile.prod` / `Dockerfile`(无 dev 后缀)时检查:
68
+
69
+ | 检测 | 严重度 | 触发 AskUserQuestion |
70
+ |---|---|---|
71
+ | 单阶段构建(无 `FROM ... AS builder` 多阶段) | high | ✓ 必须 |
72
+ | 没有 `USER` 指令,或 `USER root` | high | ✓ 必须 |
73
+ | 同目录无 `.dockerignore` | medium | ✓ 必须 |
74
+ | 镜像里包含 dev 依赖(`pip install -e ".[dev]"` / `pnpm install` 不带 `--prod`) | high | ✓ 必须 |
75
+ | 已合规 | — | ✗ 静默放行 |
76
+
77
+ → 修复时读 `references/ask-templates.md` 模板 2(Dockerfile 结构);模板示例读 `references/templates.md`。
78
+
79
+ ### C. docker-compose 工程结构
80
+
81
+ | 检测 | 严重度 | 触发 AskUserQuestion |
82
+ |---|---|---|
83
+ | 项目只有一份 `docker-compose.yml`(没有 dev/prod 分离) | high | ✓ 必须 |
84
+ | `docker-compose.prod.yml` 中 postgres/redis/minio 等基础设施暴露端口(`ports:` 段) | critical | ✓ 必须 |
85
+ | `docker-compose.prod.yml` 中服务无 `restart:` 策略 | medium | ✓ 必须 |
86
+ | `docker-compose.prod.yml` 中数据库/缓存无 `healthcheck:` | medium | ✓ 必须 |
87
+ | compose 文件中硬编码密码(`POSTGRES_PASSWORD: postgres123` 而非 `${DB_PASSWORD}`) | critical | ✓ 必须 |
88
+ | 已合规 | — | ✗ 静默放行 |
89
+
90
+ → 修复时读 `references/ask-templates.md` 模板 3(compose 结构);模板示例读 `references/templates.md`。
91
+
92
+ ### D. 一键启动脚本
93
+
94
+ 每个全栈项目根**必须**有两个脚本,都采用**子命令模式 + 显式传参**设计:
95
+
96
+ - `dev.sh` — 开发环境管理:`start` / `stop` / `restart` / `infra` / `status` / `logs`
97
+ - `prod.sh` — 生产环境管理:`start` / `stop` / `restart` / `status` / `logs` / `update`
98
+
99
+ **两个脚本必须满足**:不传子命令或传错时**只打印 help 不执行任何动作**(生产最忌默认行为,运维手抖少敲一个词不能误启动服务)。
100
+
101
+ | 检测 | 严重度 | 触发 AskUserQuestion |
102
+ |---|---|---|
103
+ | 项目根无 `dev.sh`(且确认是 dwy 风格 monorepo / 全栈项目) | low | ⚠ 仅在用户问"怎么启动"时提示创建 |
104
+ | 项目根无 `prod.sh`(且已有 `docker-compose.prod.yml`) | medium | ⚠ 仅在用户问"怎么部署 / 怎么重启" 时提示创建 |
105
+ | `dev.sh` 或 `prod.sh` 不支持 `start` / `stop` / `restart` 三个核心子命令 | medium | ✓ 必须 |
106
+ | `dev.sh` 或 `prod.sh` 不传参数时直接执行启动逻辑(而非打印 help) | high | ✓ 必须 |
107
+ | `prod.sh` 中 docker compose 命令未带 `--env-file` 加载 `.env.prod` | high | ✓ 必须 |
108
+ | `dev.sh` 的 `start` 子命令缺少 `trap cleanup INT TERM EXIT`(Ctrl+C 后留下孤儿进程) | medium | ✓ 必须 |
109
+
110
+ → 模板见 `references/templates.md` 末尾「一键启动脚本」段,含 `dev.sh` 和 `prod.sh` 完整模板及设计理由。
111
+
112
+ ---
113
+
114
+ ## 交互流程(三种场景)
115
+
116
+ ### 1. 写入前(AI 即将新增 image / Dockerfile / compose)
117
+
118
+ 例:用户说"帮我加个 redis"。
119
+
120
+ 1. `python3 {scripts}/query_dockerhub.py redis` 查推荐版本
121
+ 2. AskUserQuestion 让用户选 tag(模板见 `references/ask-templates.md` 模板 1)
122
+ 3. 用户选完后用 Edit / Write 写入,按 `references/templates.md` 填补 healthcheck / restart 等字段
123
+ 4. 写入完成后**不再二次询问已写入的合规字段**
124
+
125
+ ### 2. 检查现有文件(用户编辑或粘贴文件后)
126
+
127
+ 1. 扫描该文件,按「检查清单 A/B/C」逐项核对
128
+ 2. 收集所有违规项
129
+ 3. 一次性 AskUserQuestion(最多 4 个并列询问,超过分批;批量 tag 用 `references/ask-templates.md` 模板 4)
130
+ 4. 用户选完后 Edit 修改
131
+
132
+ ### 3. 全项目扫描(用户主动要求)
133
+
134
+ 例:用户说"扫描 latest" / "检查 docker 配置"。
135
+
136
+ 1. `bash {scripts}/scan_images.sh <project-path>`
137
+ 2. 收集违规清单
138
+ 3. 对每个 `critical` / `high` 违规:query_dockerhub.py 拿推荐 + AskUserQuestion
139
+ 4. 用户选完批量 Edit
140
+ 5. `low` / `medium` 在最后汇总告诉用户但不强制改
141
+
142
+ ---
143
+
144
+ ## 镜像版本核心规则(速查)
145
+
146
+ 1. **禁止 `latest`** — 任何位置不允许,省略 tag 等同于 `latest`。**为什么**:镜像漂移会让"昨天能跑今天炸",CI 和 prod 跑不一样的内容
147
+ 2. **必须固定 tag** — 必须是具体版本号,禁止浮动 tag(`stable` / `alpine` / `bookworm` 等)
148
+ 3. **优先选 N-1 minor** — 当前最新稳定 minor 的前一个 minor 系列最新 patch。**为什么**:避开新版刚发布时未暴露的回归 bug,行业惯例
149
+ 4. **生产关键服务用 digest** — 数据库、消息队列、网关钉 `@sha256:...`,让 image 100% 不可篡改
150
+
151
+ **完整选法(含 4 类镜像表 + LTS 例外 + 具体例子)**:见 `references/version-rules.md`。
152
+
153
+ ---
154
+
155
+ ## 工具脚本
156
+
157
+ ### `query_dockerhub.py`
158
+
159
+ ```bash
160
+ python3 {scripts}/query_dockerhub.py <image> [--namespace library] [--top 20]
161
+ ```
162
+
163
+ 输出最近的稳定 tag 列表 + 推荐 N-1 minor。私有命名空间用 `org/image`。
164
+
165
+ ### `scan_images.sh`
166
+
167
+ ```bash
168
+ bash {scripts}/scan_images.sh [project-path]
169
+ ```
170
+
171
+ 扫描项目所有 Dockerfile / docker-compose / k8s yaml / CI 配置中的镜像引用,输出违规清单。**只读,不改文件**。
172
+
173
+ ### 降级流程(脚本不可用时)
174
+
175
+ `query_dockerhub.py` 失败(私有仓库 / 网络不通):
176
+
177
+ 1. 用 WebFetch 查 DockerHub `https://hub.docker.com/_/<image>/tags` 或官方 release page
178
+ 2. 如果仍无法拿到版本列表,**仍然走 AskUserQuestion**,措辞改为"无法自动查询版本,请手动确认",options 提供常见稳定版本号 + "Other (我手动输入)"
179
+
180
+ ---
181
+
182
+ ## 与 dwy-deploy-audit 的关系
183
+
184
+ - **本 skill (`dwy-docker`)**:源代码层面,编写阶段强制规范
185
+ - **`dwy-deploy-audit`**:生产环境层面,巡检线上服务器实际跑的镜像
186
+
187
+ 两者互补:先在源码层面固定 + 工程合规,再在部署后验证实际跑的是预期版本。
@@ -0,0 +1,142 @@
1
+ # AskUserQuestion 模板(按违规类型)
2
+
3
+ 发现违规需要让用户决策时读这份。模板都用 `preview` 字段(用户能直接看到将要写入的那一行)。
4
+
5
+ ## 通用措辞要点
6
+
7
+ - `question` 必须**指出当前问题**("latest 不符合规范" / "redis:7 只有 major"),而不是泛泛"选个版本"
8
+ - `header` ≤12 字符,用 `<image> tag` / `多阶段` / `compose 分离` 这类
9
+ - 第一个 option 永远是推荐项,标 `(推荐)` / `(N-1 推荐)`
10
+ - `description` 必须含**理由**(为什么这个选项),含日期更好
11
+ - `preview` 用实际写入文件的那一行(`FROM xxx:tag` / `image: xxx:tag`)
12
+ - 选项 2-4 个;非生产关键服务不给 digest 选项
13
+
14
+ ---
15
+
16
+ ## 模板 1:tag 违规(最常用)
17
+
18
+ 适用:`latest` / 浮动 tag(`stable` / `mainline` / `alpine` / `bookworm` 等单独使用)/ 单段版本号(`redis:7`)/ codename 不带版本号。
19
+
20
+ ```jsonc
21
+ AskUserQuestion({
22
+ questions: [{
23
+ question: "nginx:latest 不符合规范(禁用 latest)。请选择固定版本:",
24
+ header: "nginx tag",
25
+ multiSelect: false,
26
+ options: [
27
+ {
28
+ label: "1.26.2 (N-1 推荐)",
29
+ description: "N-1 minor 系列最新 patch,发布 2024-08-28,已过早期回归窗口",
30
+ preview: "image: nginx:1.26.2"
31
+ },
32
+ {
33
+ label: "1.27.3 (最新稳定)",
34
+ description: "最新稳定版,2024-11-26 发布,新功能尝鲜场景再选",
35
+ preview: "image: nginx:1.27.3"
36
+ },
37
+ {
38
+ label: "1.26.2 + digest (生产关键)",
39
+ description: "钉到 digest,image 100% 不可篡改,生产网关推荐",
40
+ preview: "image: nginx:1.26.2@sha256:..."
41
+ }
42
+ ]
43
+ }]
44
+ })
45
+ ```
46
+
47
+ ---
48
+
49
+ ## 模板 2:Dockerfile 结构违规
50
+
51
+ 适用:单阶段构建 / 缺 USER / 缺 .dockerignore / 包含 dev 依赖。
52
+
53
+ ```jsonc
54
+ AskUserQuestion({
55
+ questions: [{
56
+ question: "Dockerfile.prod 是单阶段构建,镜像会包含 dev 依赖(违反多阶段约束)。如何处理?",
57
+ header: "多阶段",
58
+ multiSelect: false,
59
+ options: [
60
+ {
61
+ label: "改为 builder + runtime 多阶段",
62
+ description: "我把当前 Dockerfile 重写成 builder + 精简 runtime,仅复制必要文件",
63
+ preview: "FROM python:3.11-slim AS builder\n...\nFROM python:3.11-slim\nCOPY --from=builder ..."
64
+ },
65
+ {
66
+ label: "保留单阶段(说明原因)",
67
+ description: "比如你正在写 Dockerfile.dev,或镜像本身就是 dev/调试用",
68
+ preview: "(保留现状)"
69
+ }
70
+ ]
71
+ }]
72
+ })
73
+ ```
74
+
75
+ ---
76
+
77
+ ## 模板 3:compose 结构违规
78
+
79
+ 适用:未分离 dev/prod / prod 暴露内部端口 / 缺 healthcheck / 硬编码密码。
80
+
81
+ ```jsonc
82
+ AskUserQuestion({
83
+ questions: [{
84
+ question: "项目只有一份 docker-compose.yml,dev 和 prod 配置混合(违反 dev/prod 分离)。如何处理?",
85
+ header: "compose 分离",
86
+ multiSelect: false,
87
+ options: [
88
+ {
89
+ label: "拆分为 dev.yml + prod.yml",
90
+ description: "我把当前 compose 拆成两份:dev 暴露端口 + 应用宿主机跑,prod 不暴露端口 + 全容器化 + healthcheck",
91
+ preview: "docker-compose.dev.yml\ndocker-compose.prod.yml"
92
+ },
93
+ {
94
+ label: "暂不拆分(仅本地原型)",
95
+ description: "如果只是临时原型不上线,可以先不拆,但记得上线前必须分离",
96
+ preview: "(保留现状)"
97
+ }
98
+ ]
99
+ }]
100
+ })
101
+ ```
102
+
103
+ ---
104
+
105
+ ## 模板 4:批量 tag 违规(一次询问多镜像)
106
+
107
+ 一份 compose 文件含 postgres + redis + nginx 都用了 latest 时,并列询问。
108
+
109
+ ```jsonc
110
+ AskUserQuestion({
111
+ questions: [
112
+ {
113
+ question: "postgres:latest → 选固定版本:",
114
+ header: "postgres tag",
115
+ multiSelect: false,
116
+ options: [/* 同模板 1 结构 */]
117
+ },
118
+ {
119
+ question: "redis:latest → 选固定版本:",
120
+ header: "redis tag",
121
+ multiSelect: false,
122
+ options: [/* 同模板 1 结构 */]
123
+ },
124
+ {
125
+ question: "nginx:latest → 选固定版本:",
126
+ header: "nginx tag",
127
+ multiSelect: false,
128
+ options: [/* 同模板 1 结构 */]
129
+ }
130
+ ]
131
+ })
132
+ ```
133
+
134
+ **约束**:一次最多 4 个并列 question;超过分批询问。
135
+
136
+ ---
137
+
138
+ ## 用户选了 "Other" 自定义版本时
139
+
140
+ 按用户输入的值写入,但口头提醒一句:"你选的 `xxx:Y.Y.Y` 不在 N-1 推荐范围内(当前推荐 N-1 是 `xxx:Z.Z.Z`),确认是出于具体原因吗?"
141
+
142
+ 不要拒绝写入,但要让用户知道这是非常规选择。