Entry/Exit
- Entry: A new project needs CI, existing CI needs modification, deployment automation configuration
- Exit: Working pipeline definition + all quality gates pass
- Points to: After CI/CD configuration is complete, continue
/shipprocess - Preload: CANON.md
- Output path: Working pipeline definition + all quality gates pass →
ship-workflow-ship(continue release process)
When not to use
- Just running existing CI or viewing a single build result
- The project has no newly added/modified automated pipeline, quality gate, or deployment process
- Release decisions or go-live verification are the main issue (use
ship-workflow-ship/ship-infrastructure-deploy)
Iron Law
Core Principles
Shift Left
The earlier a problem is found, the lower the cost. Catching it in a PR is 10x cheaper than in staging, and 100x cheaper than in production.
Faster is Safer
Smaller batches + more frequent releases = lower risk. Big bang release = big bang rollback.
Quality Gate Pipeline
Lint ──→ Type Check ──→ Unit Tests ──→ Build ──→ Integration Tests ──→ E2E Tests ──→ Security Audit ──→ Bundle Size
│ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
代码风格 类型安全 单元行为 可构建 跨组件交互 关键用户流程 OWASP/CVE 不超过预算
任何门失败 → 管道停止 → 反馈给开发者
Do not create skippable gates. Every gate must pass to reach the next one.
GitHub Actions Configuration
name: CI
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'npm' }
- run: npm ci
- run: npm run lint
- run: npm run type-check
- run: npm test -- --coverage
- run: npm run build
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm audit --audit-level=high # 有 high/critical → 失败
Good/Bad CI Configuration Comparison
Bad CI configuration — never write it like this:
# Bad: 无缓存、允许失败、密钥硬编码、无超时
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout
- run: npm install
- run: npm test
continue-on-error: true # 测试失败也继续!
- run: npm run deploy
env:
AWS_SECRET_KEY: abc123hardcoded # 密钥硬编码!
Good CI configuration — use this as the standard:
# Good: 缓存、严格失败、密钥安全、超时、分离关注点
jobs:
lint-and-typecheck:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npm run lint
- run: npx tsc --noEmit
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npm test -- --coverage
- uses: codecov/codecov-action@v4
deploy:
needs: [lint-and-typecheck, test]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- run: npm run deploy
env:
AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }}
Anti-pattern Fix Table
| Problem | Fix |
|---|---|
In CI continue-on-error: true |
Remove. The point of CI is gating. Allowing failure = no gate. |
| Full install every time with no cache | Use actions/cache or the cache parameter of setup-node |
| Manual SSH deployment to the server | Use GitHub Actions / GitLab CI for automated deployment, auditable and rollback-capable |
| Skipping security audit in CI | Add npm audit / Snyk / Trivy steps; critical must block |
| Not pinning Action versions (using @main) | Pin to @v4 or @sha256. @main may be subject to supply chain attacks. |
| All steps crammed into one job | Separate by concern: lint, test, build, deploy as independent jobs |
| No timeout setting | Set timeout-minutes for each job. Prevent hangs from consuming resources |
CI Failure Feedback Loop
When CI fails → the output must tell the developer:
- What failed(Lint?Type?Test?)
- Which line/which file
- How to fix it(command hint)
# CI 配置加:失败时跑特定诊断
- name: Debug test failures
if: failure()
run: cat test-results.xml | grep -A 5 "failure"
Deployment Strategies
| Strategy | Risk | Applicable |
|---|---|---|
| Preview Deploy (per PR) | Very low | Independent environment per PR, reviewers can experience it directly |
| Blue/Green | Low | Two complete environments, instant switch, instant rollback |
| Staged Rollout (10% → 50% → 100%) | Low-Medium | High-traffic services, gradually reduce risk |
| Rolling Update | Medium | Update instance by instance, standard K8s/ECS |
Minimum requirements:
- Every deployment must have a corresponding rollback plan (command or one-click button)
- Staging deployment must precede production deployment
- Feature Flags are used to decouple deployment (shipping code) from release (enabling functionality)
CI optimization
CI 慢 (>10 min)?
├── 缓存 node_modules (.npm / actions/cache)
├── 测试并行 (按模块分 job)
├── 使用本地 CI runner (而非 GitHub hosted)
├── 仅跑受影响的测试 (test impact analysis)
└── 拆分 heavy job (lint + type 并行)
Common sayings
| Saying | Reality | Consequence |
|---|---|---|
| "Skip CI and deploy directly, it's too slow" | Skipping CI = moving quality checks to production. You will discover in production the problems CI could find in 5 minutes. | Skipping CI to deploy to production → introducing known lint/type/test issues → the cost of a production incident rollback is 100x the CI runtime. |
| "It's okay if this check fails" | Every "it's okay" becomes the next "it's okay." Eventually CI is completely ignored. | 3 months later CI is red and nobody looks → all quality gates become meaningless → the team loses trust in CI and reverts to manual processes. |
| "Manual deployment is faster" | Manual deployment = steps may be missed, the environment may be wrong, rollback steps are uncertain. One manual mistake > all automation costs. | Manual deployment misses one environment variable → production 500 errors persist for 45 minutes until someone notices → not rollback-able, not auditable. |
| "Ignore CI red for now, fix it later" | CI red is the project's only current truth. Continuing to commit on red CI = continuing to build on an uncertain foundation. | Continuing to commit on red CI → new code mixes with existing problems → root cause diagnosis takes 5-10x longer → "fix it later" becomes "never fix it." |
| "CI is green, so it's safe" | Green CI ≠ good tests. Tests may have insufficient coverage or allow_failure. | Green CI + low coverage = false sense of security. When coverage < 50%, major bugs still ship under green CI because critical paths are not tested. After release, 30% of bugs come from uncovered paths. |
| "E2E is too slow and unnecessary" | Critical user flows must have E2E. Only run critical paths, not full coverage. | Critical flows without E2E (payment/registration/login) → the user's first action in a real browser fails. After release, 40% of production failures come from browser compatibility issues in critical flows. |
| "Flaky tests are someone else's problem" | Flaky tests erode team trust. Whoever finds it fixes it, or marks it and creates an issue. | Flaky tests not fixed → the team gets used to ignoring CI failures → real failures are ignored as flaky → production bugs. When flaky rate > 5%, team trust in CI drops to < 30%. |
| "Add caching later" | Add caching on day one. Adding it after CI gets slow = waiting two months for nothing. | CI without caching takes 5-10 minutes to install dependencies each time → the whole team wastes hours cumulatively every day → developers avoid running CI. |
| "Manual QA is more reliable than CI" | Manual QA is not durable, not repeatable, and cannot bisect. Automation is the baseline. | Manual QA cannot regress → retesting all flows before every release → 20-30% miss rate and worsening as the project grows. |
| "Adding security audit steps to CI is too slow" | Security audits run in parallel in CI and do not increase critical path time. | Not running security audits in CI → known CVEs quietly enter production → supply chain attack risk keeps accumulating. On average, each project introduces 2-3 known CVEs per month, with detection lagging 30+ days. |
Violating the letter of the rule is violating the spirit. There is no gray area.
Red flag — STOP
- A CI gate is skipped/commented out/set to allow_failure
- Secrets written directly in CI yaml (use GitHub Secrets / Vault)
- In CI,
npm audithas high/critical but is unhandled - Manual deployment without an automatic rollback mechanism
- E2E tests are disabled in CI (too slow → parallelize or give more CI resources, do not disable)
- No caching in the CI configuration causes reinstallation every time (wasting CI minutes)
Pay attention to signals from human partners:
- "Did CI pass?" — You may not have waited for the CI result
- "How long does the build take?" — CI is too slow and needs optimization
- "Can we skip the security check just this once?" — Absolutely not. This is a red flag.
- "Why did CI fail?" — You need to read the error logs instead of guessing
Handling verification failures
| Failure scenario | Handling method |
|---|---|
| CI flaky (sometimes passes, sometimes fails) | Mark the flaky test. Run it in isolation to confirm. Fix nondeterminism (timing, order dependence, external services). |
| Passes locally but fails in CI | Check environment differences (Node version, OS, environment variables). Test locally using the same Docker image as CI. |
| CI build time > 30 minutes | Priority: add caching > split jobs for parallelism > reduce dependencies > incremental builds. |
| Security audit finds a Critical CVE | Block the merge. Assess actual exploitability. If a patch exists, update immediately; if not, evaluate alternatives. |
| E2E test timeout | Check the test waiting strategy (use wait-for instead of sleep). Check whether CI resources are sufficient. |
Output template
# CI/CD Pipeline Report — 持续集成与持续部署管道报告
## 元信息
- **配置者**: [姓名/角色]
- **项目**: [项目名]
- **配置日期**: YYYY-MM-DD
- **平台**: [GitHub Actions / GitLab CI / 其他]
## Quality Gate 状态
| Gate | 状态 | 阈值 | 实际值 | 备注 |
|------|------|------|--------|------|
| Lint | ✅ / ❌ | 零 error | [实际 error 数] | — |
| Type Check | ✅ / ❌ | 零 error | [实际 error 数] | — |
| Unit Tests | ✅ / ❌ | 覆盖率 ≥ 80% | [实际覆盖率] | — |
| Build | ✅ / ❌ | 成功构建 | [构建时间] | — |
| Integration Tests | ✅ / ❌ | 全部通过 | [通过/总数] | — |
| E2E Tests | ✅ / ❌ | 关键路径通过 | [通过/总数] | — |
| Security Audit | ✅ / ❌ | zero high/critical CVE | [high/critical 数] | — |
| Bundle Size | ✅ / ❌ | ≤ [预算]KB | [实际大小]KB | — |
## CI 配置清单
- [ ] 缓存配置(node_modules/.cache)
- [ ] 所有 job 有 timeout-minutes
- [ ] 密钥使用 Secrets(无硬编码)
- [ ] Action 版本固定(@v4 或 @sha256,非 @main)
- [ ] 失败时输出诊断信息
## 部署策略
- **策略类型**: [Preview / Blue-Green / Staged Rollout / Rolling Update]
- **Staging 先于生产**: ✅ / ❌
- **回滚方案**: [描述或命令]
- **Feature Flag**: ✅ 已配置 / ❌ 未配置
## 性能指标
- **总 CI 运行时间**: [分钟]
- **关键路径时间**: [分钟]
- **优化建议**: [如有 > 10min,列出优化方向]
## 审查结论
- **通过**: 所有质量门 ✅ + 部署策略明确 + 回滚方案就绪
- **阻止**: 任何质量门 ❌ 或回滚方案缺失
## 验证清单
- [ ] 所有质量门在 CI 中启用且必须通过
- [ ] CI 配置文件已提交(无密钥硬编码)
- [ ] 依赖缓存配置(node_modules/.cache)
- [ ] 部署策略明确(Preview / Blue-Green / Staged)
- [ ] 每个部署有回滚方案
- [ ] CI 失败输出包含具体诊断信息
- [ ] Staging 先于生产部署