保姆级|腾讯云助手配合 GitHub Actions,自动优化适配腾讯云 SCF / 静态托管的 CI/CD 流水线 YAML
适用人群:已经在用 GitHub 管理代码、想一键把 Node/Python/Java 函数或前端静态站部署到腾讯云,但被 AI 生成的 YAML 坑过的人。
本文不科普GitHub Actions 基础(on/jobs/steps 是什么你自己查)。只做三件事:
- 教你把项目结构"喂"给腾讯云助手,让它读懂你的工程再写流水线;
- 给出 SCF 云函数、静态托管两套可直接抄的完整流水线;
- 逐条拆解 AI 生成 YAML 的三大高频事故:密钥泄露、权限不足、缓存异常(AI 原始输出 VS 修正后版本)。
一、为什么 AI 写的腾讯云流水线总是"看着对、跑不通"
AI 生成 GitHub Actions YAML 的失败率极高,根因不是 AI 不懂 YAML,而是:
- 它没看到你的项目结构:入口文件在哪、构建产物在哪、有没有
serverless.yml、锁文件package-lock.json是否提交——全靠猜; - 它把"通用套路"硬套到腾讯云链路上:GitHub 生态默认是 AWS/Netlify/Vercel 那套,腾讯云需要
SERVERLESS_PLATFORM_VENDOR: tencent、需要TENCENT_SECRET_ID/KEY、需要serverless.yml里做exclude防密钥入库,这些"腾讯云特有姿势"AI 默认不会写; - 它会在安全细节上翻车:明文密钥、固定缓存 key、漏掉
permissions,三个雷一个不落。
解决办法就一句话:先喂上下文,再让它写;写完让它自审,你只做终审。
二、第一步:让助手"读懂"你的项目(可复制的提示词模板)
把下面这段提示词连同你的项目信息一起发给腾讯云助手,它才能生成"适配你的项目"而不是"适配所有项目"的流水线。
你是我的 CI/CD 流水线顾问,请基于以下项目信息生成/审查 GitHub Actions 流水线。 【项目结构】 <直接把目录树贴进来,例如:> . ├── serverless.yml # SCF 部署配置(Web 函数) ├── package.json ├── package-lock.json ├── scf_bootstrap # Web 函数启动文件 ├── src/ │ └── index.js # 函数入口 └── .env # 含敏感配置,绝不能打进部署包 【构建与部署目标】 - 构建命令:npm run build,产物目录 dist/ - 部署目标:腾讯云 SCF(Web 函数,区域 ap-guangzhou) - 期望的触发方式:push 到 main 时自动部署;支持手动触发 【硬性约束(违反任一条都算错误)】 1. 密钥一律用 ${{ secrets.XXX }} 引用,禁止出现任何明文 AK/SK,禁止把 .env 写入部署产物; 2. 显式声明 job 级 permissions,遵循最小权限; 3. 任何缓存 key 必须包含 hashFiles('**/package-lock.json'),禁止用固定字符串当 key; 4. action 一律用当前稳定版本(checkout@v4、setup-node@v4、cache@v4); 5. 输出格式:先给修正后的完整 YAML,再逐条列出"改了什么、为什么改"。提示词里最容易漏、也最关键的是第 3、5 条。前者直接杜绝"缓存永不失效",后者让 AI 把决策过程暴露出来,方便你抓它的错误逻辑。
如果助手第一次给的不是你想要的,追加一句话即可修正,不用重新发一遍:
上面的 YAML 里 serverless.yml 没有 exclude .env,请补上;缓存 key 是固定字符串,请改成 hashFiles 形式。三、腾讯云侧前置准备(30 秒,别跳过)
部署用的密钥不要用主账号的。正确姿势:
- 到 访问管理 CAM 创建子账号;
- 给子账号绑定最小权限策略:
- 只部署 SCF:
QcloudSCFFullAccess(或更细的QcloudSCFReadOnlyAccess+ 资源级授权) - 只部署静态托管(COS):
QcloudCOSFullAccess - 两者都要:两个都绑,不要绑
AdministratorAccess;
- 只部署 SCF:
- 拿到该子账号的 SecretId / SecretKey;
- 到 GitHub 仓库Settings → Secrets and variables → Actions新增:
TENCENT_SECRET_ID/TENCENT_SECRET_KEY(SCF、COS 通用)ENV_ID(走云开发静态托管才需要)COS_BUCKET(走 COS 静态托管才需要,格式为桶名-APPID,如my-site-1250000000)
权限不足类报错的 90% 都发生在这一环节:用了根账号密钥(风险大)或子账号没绑策略(报
AuthFailure/UnauthorizedOperation)。
四、场景 A:SCF 云函数(Web 函数)完整流水线
4.1 完整流水线片段(修正版,可直接抄)
name:deploy-scf-webon:push:branches:[main]paths:# 只动到相关文件才触发,省 Actions 分钟数-'src/**'-'serverless.yml'-'package.json'-'package-lock.json'workflow_dispatch:{}# 支持手动触发,方便回滚验证concurrency:# 防止连续 push 的并发部署互相覆盖group:deploy-scf-${{github.ref}}cancel-in-progress:truejobs:build-and-deploy:runs-on:ubuntu-latesttimeout-minutes:15permissions:# 显式声明,最小权限contents:read# checkout 需要actions:write# actions/cache 保存缓存需要,缺了会报权限错误steps:-name:Checkoutuses:actions/checkout@v4-name:Setup Nodeuses:actions/setup-node@v4with:node-version:20cache:npm# setup-node 自带缓存,key 自动包含 lockfile 哈希-name:Install & Buildrun:|npm ci # 必须用 ci,要求 lockfile 存在且一致 npm run build-name:Deploy to SCFuses:woodyyan/tencent-serverless-action@main# 腾讯云官方 Serverless Actionenv:STAGE:dev# 部署环境,对应 serverless.yml 的 stageSERVERLESS_PLATFORM_VENDOR:tencent# 关键:不设默认走 AWS,部署到境外TENCENT_SECRET_ID:${{secrets.TENCENT_SECRET_ID}}TENCENT_SECRET_KEY:${{secrets.TENCENT_SECRET_KEY}}# 该 action 会自动执行 serverless deploy,读取项目根目录的 serverless.yml4.2 配套serverless.yml(适配点全注释)
component:scfname:my-web-apiapp:my-appstage:devinputs:name:my-web-apisrc:src:./exclude:# ❗ 打包时排除敏感与无关文件,防密钥入库/入包-.env# 最高优先级:本地密钥文件绝不进函数包-.git/**-node_modules/**# 由平台安装依赖,不用本地 node_modules-dist/static# 如果静态资源单独托管,别打进函数type:web# Web 函数(HTTP 触发);不填默认为事件函数runtime:Nodejs16.13region:ap-guangzhoutimeout:10memorySize:256environment:variables:NODE_ENV:productionevents:-apigw:# 自动绑定 API 网关name:serverlessparameters:protocols:[https]注意:Web 函数无需指定入口文件,但要保证项目根目录有可执行的
scf_bootstrap启动文件(构建产物若改变启动方式,记得一起提交)。
4.3 错误对比 ① 密钥泄露(AI 原始输出 VS 修正版)
AI 原始输出(踩雷版):
-name:deploy serverlessuses:woodyyan/tencent-serverless-action@mainenv:STAGE:devSERVERLESS_PLATFORM_VENDOR:tencentTENCENT_SECRET_ID:AKIDabc123def456xyz789# ❌ 明文写死TENCENT_SECRET_KEY:0p1q2r3s4t5u6v7w8x9y0z# ❌ 明文写死为什么是雷:YAML 进了 Git 仓库 = 密钥进了 git 历史。哪怕你后来删掉,历史里永远有,等于把云账号密码公布在互联网上。GitHub 的 secret scanning 扫描到后还会给腾讯云发告警、可能直接吊销密钥。
修正后版本:
-name:deploy serverlessuses:woodyyan/tencent-serverless-action@mainenv:STAGE:devSERVERLESS_PLATFORM_VENDOR:tencentTENCENT_SECRET_ID:${{secrets.TENCENT_SECRET_ID}}# ✅ 只引用,不落地TENCENT_SECRET_KEY:${{secrets.TENCENT_SECRET_KEY}}# ✅ 只引用,不落地补救动作(如果已经推过明文,必须做,别只改文件):
- 立即在 CAM 里禁用/轮换泄露的密钥对,重新生成;
- 用
git filter-repo清掉历史里的明文(普通git rm没用); - 检查 GitHub 仓库 Settings → Security 里的 secret scanning 告警,确认已处理。
同类雷区:AI 有时会把serverless.yml的exclude漏掉,导致.env随代码打进函数包——这不是 YAML 层的明文,但泄露后果一样,所以exclude: .env必须存在。
五、场景 B:静态托管完整流水线(COS 与云开发两版)
5.1 版本一:部署到 COS 静态网站托管
name:deploy-static-to-coson:push:branches:[main]paths:['src/**','package.json','package-lock.json']workflow_dispatch:{}jobs:deploy:runs-on:ubuntu-latestpermissions:contents:readsteps:-name:Checkoutuses:actions/checkout@v4-name:Setup Node & Builduses:actions/setup-node@v4with:node-version:20cache:npm-run:|npm ci npm run build-name:Upload to COSuses:tencentyun/cos-action@master# 腾讯云官方 COS Actionwith:secret_id:${{secrets.TENCENT_SECRET_ID}}secret_key:${{secrets.TENCENT_SECRET_KEY}}cos_bucket:${{secrets.COS_BUCKET}}# 格式:桶名-APPIDcos_region:ap-guangzhoulocal_path:dist# 构建产物目录remote_path:/# 上传到桶根目录clean:true# 同步模式:先清远端多余文件,防止旧文件残留COS 静态网站托管需要先在控制台给桶开启"静态网站"功能并设置索引文档(如
index.html)。上传后直接用 COS 静态网站域名或绑定的自定义域名访问。
5.2 版本二:部署到云开发(CloudBase)静态托管
-name:Deploy static to CloudBaseuses:TencentCloudBase/cloudbase-action@v2# 注意:用前到仓库确认最新版本号with:secretId:${{secrets.TENCENT_SECRET_ID}}secretKey:${{secrets.TENCENT_SECRET_KEY}}envId:${{secrets.ENV_ID}}# 云开发环境 ID,不是桶名staticSrcPath:dist# 静态文件路径# staticDestPath: / # 需要传到子目录时再开两个版本共用同一套 Secrets(
TENCENT_SECRET_ID/KEY),只是部署目标不同。选哪个取决于你后端是否要用云开发的云函数/数据库——要用就选 CloudBase,纯静态站选 COS 更简单直接。
5.3 错误对比 ② 权限不足(AI 原始输出 VS 修正版)
AI 原始输出(踩雷版):
jobs:deploy:runs-on:ubuntu-lateststeps:-uses:actions/checkout@v4-uses:actions/cache@v4with:path:~/.npmkey:${{runner.os}}-npm-${{hashFiles('**/package-lock.json')}}-run:npm ci# ... deploy ...为什么是雷(这一版其实是两级权限问题):
- GitHub 侧:job 没有
permissions。在新仓库默认GITHUB_TOKEN收紧的情况下,actions/cache保存缓存会失败,报错类似:Failed to save: ... GITHUB_TOKEN is not authorized; - 腾讯云侧:AI 只给了 YAML,没管 CAM。如果你按它的方案把主账号密钥填进 Secrets,能跑通但风险爆炸;如果用了没绑策略的子账号,直接报
AuthFailure/UnauthorizedOperation。
修正后版本:
jobs:deploy:runs-on:ubuntu-latestpermissions:# ✅ GitHub 侧:显式最小权限contents:readactions:write# ✅ cache 保存需要,缺了就报权限错误steps:-uses:actions/checkout@v4-uses:actions/cache@v4...腾讯云侧修正(YAML 之外同样关键):子账号绑定QcloudCOSFullAccess(或QcloudSCFFullAccess)策略,别用主账号密钥,别绑AdministratorAccess。
经验法则:GitHub 侧的权限错误看 Actions 日志的 token 报错;腾讯云侧的权限错误看
AuthFailure/UnauthorizedOperation字样。两者不是一个东西,别拿 CAM 策略去修 GitHub 的 token 报错。
5.4 错误对比 ③ 缓存异常(AI 原始输出 VS 修正版)
AI 原始输出(踩雷版):
-name:Cache node_modulesuses:actions/cache@v2# ❌ 旧版,且缓存的是 node_moduleswith:path:node_modules# ❌ 直接缓存安装目录key:deps-cache# ❌ 固定 key,永不失效为什么是雷:
| 问题 | 后果 |
|---|---|
key: deps-cache固定字符串 | 缓存永远命中旧依赖,package.json升级后 CI 还是装老版本 → “本地能跑、CI 出幽灵 bug” |
缓存node_modules | 跨 Node 版本、跨 runner 平台(ubuntu/windows)的产物互相污染,还常因actions/cache@v2与 Node20 runner 不兼容直接报错 |
配套用npm install | 无 lockfile 校验,依赖漂移,和缓存叠加后问题更难排查 |
修正后版本:
-name:Cache npm cacheuses:actions/cache@v4# ✅ 新版with:path:~/.npm# ✅ 缓存 npm 全局缓存而非 node_moduleskey:${{runner.os}}-node-${{hashFiles('**/package-lock.json')}}# ✅ key 随依赖变化restore-keys:|${{ runner.os }}-node- # ✅ 未精确命中时退回旧缓存,仍能加速更省心的做法:直接用actions/setup-node的cache: npm(本文章节四/五的写法),key 自动带 lockfile 哈希,不用手写 cache 步骤,也少一个出错点。
同类雷区:
- AI 生成
npm install而仓库里没有package-lock.json→npm ci直接报错;修复:本地npm install生成后把 lockfile 提交进仓库; - AI 把
local_path/staticSrcPath指向仓库根目录 → 把源码甚至.env一起传上静态托管,等于公开源码。
六、AI 生成 YAML 十大典型错误对照表(可直接做成给助手的检查单)
| # | 类型 | AI 常见输出 | 真实危害 | 修正 |
|---|---|---|---|---|
| 1 | 密钥 | TENCENT_SECRET_ID: AKIDxxxx明文 | 密钥进 git 历史,全网可见 | ${{ secrets.XXX }}+ 轮换密钥 |
| 2 | 密钥 | 用主账号密钥 | 泄露即账号失控 | 子账号 + 最小策略 |
| 3 | 密钥 | serverless.yml未exclude: .env | 密钥随函数包上传 | 补 exclude |
| 4 | 权限 | 漏permissions | cache 保存失败、token 报错 | actions: write+contents: read |
| 5 | 权限 | 子账号无 SCF/COS 策略 | AuthFailure/UnauthorizedOperation | 绑定QcloudSCFFullAccess等 |
| 6 | 缓存 | key: deps-cache固定 | 依赖永不更新,幽灵 bug | hashFiles('**/package-lock.json') |
| 7 | 缓存 | 缓存node_modules | 跨平台/版本污染 | 缓存~/.npm |
| 8 | 构建 | npm install无 lockfile | 依赖漂移 | npm ci+ 提交 lockfile |
| 9 | 触发 | on: [push]全量触发 | 空跑浪费 Actions 分钟 | branches+paths过滤 |
| 10 | 并发 | 无concurrency | 连推代码部署互相覆盖 | concurrency.group+cancel-in-progress |
把这张表原样发给腾讯云助手,让它逐项自审,可以一次过滤掉 80% 的低级错误:
请以安全审计视角检查以下流水线 YAML,逐项回答: 1. 是否存在明文密钥、或会被打包进部署产物的敏感文件? 2. permissions 是否最小化且能支撑 cache/checkout? 3. 缓存 key 是否随依赖变化自动失效?是否缓存了 node_modules? 4. serverless.yml 的 exclude 是否覆盖 .env、.git、node_modules? 5. 触发器是否按分支/路径过滤?是否有并发控制? 只输出:结论 + 需要修改的片段(不改的给出理由)。七、调试速查:常见报错 → 原因 → 修复
| Actions 里的报错 | 原因 | 修复 |
|---|---|---|
TENCENT_SECRET_ID is not defined/Secret not found | Secrets 没配或名字不一致 | Settings → Secrets 新增TENCENT_SECRET_ID/KEY,名字和 YAML 完全一致 |
AuthFailure.SignatureFailure | 密钥错误、已轮换、或用了失效密钥 | 更新 Secrets;确认是子账号密钥 |
UnauthorizedOperation/You are not authorized to perform this operation | 子账号缺 CAM 策略 | 绑定QcloudSCFFullAccess/QcloudCOSFullAccess |
Failed to save: ... not authorized | GitHub token 权限不足 | job 加permissions.actions: write |
Cannot read properties of undefined(cloudbase-action) | action 版本过旧,与新 runner 不兼容 | 升级到仓库最新 release 版本 |
Bucket not found: xxx | COS_BUCKET不是桶名-APPID格式 | 改为my-site-1250000000这种格式 |
npm ci报package-lock.json缺失 / ERESOLVE | lockfile 未提交或与 package.json 不一致 | 本地npm install后提交 lockfile |
| 部署成功但网站 404 | 构建产物路径不对,或 COS 未开启静态网站 | 核对local_path/staticSrcPath;控制台开启静态网站并设索引文档 |
八、最后:一套可沉淀的 SOP
- 喂上下文:贴目录树 + 关键文件内容 + 部署目标,附上第二节的提示词模板;
- 要它自审:把第六节的检查单丢给它,让它逐项过;
- 你只终审三处:① 全文搜一遍
AKID、sk等字样,确认无明文;② 看permissions和exclude在不在;③ 看缓存 key 有没有hashFiles; - 灰度验证:先
workflow_dispatch手动触发一次,确认构建和部署都绿了,再推到 main 自动跑; - 密钥轮换演练:把"轮换 Secrets 后重新部署"跑通一次,保证真出事时你有恢复路径。
记住:AI 写流水线不是一次成型,而是"上下文 + 约束 + 自审 + 人审"的循环。上下文给得越准、约束列得越狠,AI 犯的错就越少;而密钥、权限、缓存这三关,永远值得你亲自把最后一道。
参考:腾讯云官方文档《SCF 自动化部署》《Serverless 快速部署 Web 函数》《静态网站托管自动化部署》