fix(ci): 消除 workflow 所有 heredoc,改为外置脚本调用
- 删除 Configure remote backend 步骤的 shell heredoc(导致 YAML L191 语法错误) - 新增 scripts/render_backend_tf.py 外置脚本,接受 TF_STATE_ENDPOINT env 渲染 backend.tf - provision job 新增 Checkout xworkspace-console 步骤,确保 scripts/ 在 runner 可用 - 新增 CLAUDE.md,明确禁止 workflow 内嵌 heredoc(shell/python),要求外置脚本 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f636366699
commit
9b3687e189
23
.github/workflows/deploy-ai-workspace-iac.yaml
vendored
23
.github/workflows/deploy-ai-workspace-iac.yaml
vendored
@ -153,6 +153,11 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
[ "$missing" -eq 0 ] || { echo "::error::必需机密缺失,终止 provision"; exit 1; }
|
[ "$missing" -eq 0 ] || { echo "::error::必需机密缺失,终止 provision"; exit 1; }
|
||||||
|
|
||||||
|
- name: Checkout xworkspace-console (scripts)
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: xw-console
|
||||||
|
|
||||||
- name: Checkout iac_modules
|
- name: Checkout iac_modules
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@ -183,23 +188,7 @@ jobs:
|
|||||||
working-directory: ${{ env.ENV_DIR }}
|
working-directory: ${{ env.ENV_DIR }}
|
||||||
env:
|
env:
|
||||||
TF_STATE_ENDPOINT: ${{ steps.vault.outputs.TF_STATE_ENDPOINT }}
|
TF_STATE_ENDPOINT: ${{ steps.vault.outputs.TF_STATE_ENDPOINT }}
|
||||||
run: |
|
run: python3 $GITHUB_WORKSPACE/xw-console/scripts/render_backend_tf.py backend.tf
|
||||||
set -euo pipefail
|
|
||||||
# endpoints 块只能在 HCL 里配置,无法通过 -backend-config flag 传递。
|
|
||||||
# 用非引号 heredoc 将 endpoint URL 展开写入 backend.tf。
|
|
||||||
cat > backend.tf << TFEOF
|
|
||||||
terraform {
|
|
||||||
backend "s3" {
|
|
||||||
endpoints = { s3 = "${TF_STATE_ENDPOINT}" }
|
|
||||||
skip_credentials_validation = true
|
|
||||||
skip_region_validation = true
|
|
||||||
skip_requesting_account_id = true
|
|
||||||
skip_metadata_api_check = true
|
|
||||||
skip_s3_checksum = true
|
|
||||||
use_path_style = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TFEOF
|
|
||||||
|
|
||||||
- name: generate.py render (YAML -> 显式 HCL + tfvars)
|
- name: generate.py render (YAML -> 显式 HCL + tfvars)
|
||||||
working-directory: ${{ env.VPS_ROOT }}
|
working-directory: ${{ env.VPS_ROOT }}
|
||||||
|
|||||||
49
CLAUDE.md
Normal file
49
CLAUDE.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# xworkspace-console — Agent 规范
|
||||||
|
|
||||||
|
## GitHub Actions Workflow 编写规则
|
||||||
|
|
||||||
|
### 禁止内嵌脚本(shell heredoc / python heredoc)
|
||||||
|
|
||||||
|
**严禁**在 `.github/workflows/` 的 `run:` 块里使用任何内嵌 heredoc:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# ❌ 禁止 — shell heredoc
|
||||||
|
run: |
|
||||||
|
cat > file.tf << EOF
|
||||||
|
content
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# ❌ 禁止 — python 内联 heredoc
|
||||||
|
run: |
|
||||||
|
python3 - <<'PYEOF'
|
||||||
|
import os
|
||||||
|
...
|
||||||
|
PYEOF
|
||||||
|
```
|
||||||
|
|
||||||
|
**原因:**
|
||||||
|
- Shell heredoc 内容从列 1 开始,超出 YAML literal block 缩进范围,导致整个 workflow 文件 YAML 解析失败,GitHub 丢失 `on:` 触发器。
|
||||||
|
- Python 内联 heredoc 同理,且难以维护和测试。
|
||||||
|
|
||||||
|
**正确做法:外置脚本,workflow 只做调用。**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# ✅ 正确 — 外置 Python 脚本
|
||||||
|
- name: Checkout xworkspace-console (scripts)
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: xw-console
|
||||||
|
|
||||||
|
- name: Configure remote backend
|
||||||
|
env:
|
||||||
|
TF_STATE_ENDPOINT: ${{ steps.vault.outputs.TF_STATE_ENDPOINT }}
|
||||||
|
run: python3 $GITHUB_WORKSPACE/xw-console/scripts/render_backend_tf.py backend.tf
|
||||||
|
```
|
||||||
|
|
||||||
|
脚本存放在 `scripts/` 目录,命名规范 `动词_名词.py` 或 `动词-名词.sh`。
|
||||||
|
|
||||||
|
### 其他规范
|
||||||
|
|
||||||
|
- workflow 使用的外置脚本必须在 `scripts/` 目录下,不得内嵌在 `run:` 块里。
|
||||||
|
- workflow 文件修改后必须用 `python3 -c "import yaml; yaml.safe_load(open(...))"` 验证 YAML 语法再提交。
|
||||||
|
- 不使用 GitHub Actions Secrets,所有机密统一从 Vault (https://vault.svc.plus) OIDC 读取。
|
||||||
38
scripts/render_backend_tf.py
Normal file
38
scripts/render_backend_tf.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
渲染 Terraform S3 backend 配置文件(backend.tf)。
|
||||||
|
|
||||||
|
用法:
|
||||||
|
TF_STATE_ENDPOINT=https://... python3 render_backend_tf.py [output_path]
|
||||||
|
|
||||||
|
默认输出到当前目录的 backend.tf(terraform init 的 working-directory 里执行)。
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
endpoint = os.environ.get("TF_STATE_ENDPOINT", "")
|
||||||
|
if not endpoint:
|
||||||
|
print("ERROR: TF_STATE_ENDPOINT is not set", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
output = sys.argv[1] if len(sys.argv) > 1 else "backend.tf"
|
||||||
|
|
||||||
|
content = f"""\
|
||||||
|
terraform {{
|
||||||
|
backend "s3" {{
|
||||||
|
endpoints = {{ s3 = "{endpoint}" }}
|
||||||
|
skip_credentials_validation = true
|
||||||
|
skip_region_validation = true
|
||||||
|
skip_requesting_account_id = true
|
||||||
|
skip_metadata_api_check = true
|
||||||
|
skip_s3_checksum = true
|
||||||
|
use_path_style = true
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
with open(output, "w") as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
print(f"backend.tf written to {output}")
|
||||||
|
print(f" endpoint = {endpoint[:40]}...")
|
||||||
Loading…
Reference in New Issue
Block a user