Architecture of an AI-Assisted CI/CD Pipeline for Golang: A Complete Blueprint
An architecture blueprint for an AI-assisted pipeline for a Go service. Layer-by-layer design: syntactic, semantic, AI review, spec compliance — with a production-ready GitHub Actions workflow.
Before writing a single line of pipeline YAML, we need a clear blueprint for the AI golang CI/CD architecture we’re about to build. A pipeline built without a well-thought-out architecture ends up as a collection of steps that are hard to maintain, too slow, or full of false positives.
This article is an architecture session — we’ll design the pipeline top to bottom before implementation.
02.1 Our Pipeline Design Principles
Before getting to the diagram, there are three principles that will guide every architecture decision in Topic 4. These three principles — fail fast, parallel, and graduated enforcement — become the reference for every trade-off we make later.
1PRINCIPLE 1: FAIL FAST, FAIL CHEAP
2 The fastest and most frequently failing step should run first.
3
4 Order: build → test → lint → architecture → AI review → spec audit
5
6 Rationale:
7 - Build fail: most frequent, fastest (30 seconds)
8 - Test fail: frequent, 2-5 minutes
9 - AI review: rarely blocks, 2 minutes (but relatively expensive)
10 - Spec audit: rarely runs, 1 minute
11
12 Don't: run spec audit before tests — pointless if tests fail
13
14PRINCIPLE 2: PARALLEL WHERE POSSIBLE
15 Steps that aren't dependent on each other should run in parallel.
16
17 Parallel group A (blocking):
18 go build, go test, golangci-lint, architecture-check
19
20 Parallel group B (informational, non-blocking at first):
21 AI review, PR description generation
22
23 Total wall time: max(group A) + security-scan
24 Not: the sum of all steps
25
26PRINCIPLE 3: GRADUATED ENFORCEMENT
27 Not every failure should block merge from day one.
28
29 Level 1 (blocking from day one):
30 Build fail, test fail, critical security vulnerability
31
32 Level 2 (blocking after 2 sprints):
33 AI review CRITICAL issues, architecture violations
34
35 Level 3 (informational always):
36 AI review SUGGESTION, PR description qualityIf you had to pick the one principle people violate most, it’s principle 1: never burn AI tokens reviewing code whose tests haven’t even passed.
02.2 Layer Architecture: 4 Layers, 1 Pipeline
Our pipeline is built in layers, from the cheapest and most deterministic to the most expensive and semantic. The layer diagram below shows all four layers along with the time and blocking status of each.
1┌─────────────────────────────────────────────────────────────┐
2│ LAYER 1: SYNTACTIC (Deterministic, Zero AI Cost) │
3│ go build | go test -race | go vet | golangci-lint │
4│ Time: 2-5 minutes | Blocking: YES from day 1 │
5├─────────────────────────────────────────────────────────────┤
6│ LAYER 2: SEMANTIC-STATIC (Custom Script, Zero AI Cost) │
7│ Architecture boundary | Import graph | Naming convention │
8│ Time: 30 seconds | Blocking: YES (sprint 2+) │
9├─────────────────────────────────────────────────────────────┤
10│ LAYER 3: SEMANTIC-AI (LLM-Powered, Low Cost) │
11│ Copilot PR review | Claude error pattern check │
12│ Time: 2 minutes (parallel) | Blocking: CRITICAL only │
13├─────────────────────────────────────────────────────────────┤
14│ LAYER 4: SPEC COMPLIANCE (Spec Kit, Optional) │
15│ specify audit | AC coverage | Contract validation │
16│ Time: 1 minute | Blocking: if score < 80 │
17└─────────────────────────────────────────────────────────────┘Notice that only the top two layers are free of AI cost — this is why the majority of the validation load is deliberately placed in Layer 1 and 2, and AI only handles what static analysis can’t catch.
02.3 Full Pipeline Diagram
After understanding the layers conceptually, let’s see how everything connects in a single execution flow. The complete diagram below shows the trigger strategy, layer order, and the blocking points along with their parallel gate.
flowchart TD
Push[Git Push / PR Open] --> Trigger
subgraph Trigger["Trigger Strategy"]
direction LR
T1[push to main/develop] -->|full pipeline| Pipeline
T2[PR opened/updated] -->|full pipeline + AI review| Pipeline
T3[push to feature branch] -->|Layer 1 only| L1
end
subgraph L1["Layer 1: Syntactic"]
direction LR
Build[go build ./...] --> Test[go test -race -count=1 ./...]
Test --> Vet[go vet ./...]
Vet --> Lint[golangci-lint]
Lint --> SecScan[gosec + gitleaks]
end
subgraph L2["Layer 2: Semantic-Static"]
Arch[architecture-check.go]
DepCheck[dependency guard]
end
subgraph L3["Layer 3: Semantic-AI (parallel)"]
direction LR
CopilotReview[Copilot PR Review]
PRDesc[PR Description Generator]
FailureAnalysis[Test Failure Analysis]
end
subgraph L4["Layer 4: Spec Compliance"]
SpecAudit[specify audit]
end
Pipeline --> L1
L1 -->|PASS| L2
L1 -->|FAIL| BlockL1[❌ Block: Fix Build/Test/Lint]
L2 -->|PASS| ParallelGate
L2 -->|FAIL| BlockL2[⚠️ Block: Fix Architecture]
ParallelGate --> L3
ParallelGate --> L4
L3 -->|CRITICAL| BlockL3[⚠️ Block: Fix Critical AI Issues]
L3 -->|OK/SUGGESTION| PassL3[✅ AI Review Passed]
L4 -->|score < 80| BlockL4[⚠️ Block: Spec Non-Compliant]
L4 -->|score >= 80| PassL4[✅ Spec Compliant]
PassL3 --> Merge
PassL4 --> Merge
BlockL3 -.->|after fix| Merge
BlockL4 -.->|after fix| Merge
Merge[✅ Ready to Merge]
style L3 fill:#e8f4ff,stroke:#4a90d9
style L4 fill:#e8f4ff,stroke:#4a90d9
style CopilotReview fill:#dceeff,stroke:#4a90d9
style PRDesc fill:#dceeff,stroke:#4a90d9
style SpecAudit fill:#dceeff,stroke:#4a90d9
Diagram: Full AI-augmented pipeline — blue nodes are AI-powered steps
The most important point from this diagram: L3 and L4 branch from the same point (ParallelGate) after L1+L2 pass, so both run at the same time and save wall time.
02.4 GitHub Actions Job Structure
The diagram above needs to be translated into actual jobs in GitHub Actions. The workflow below is the full structure of all four layers, from the trigger to the spec-audit job — notice how needs orders the sequence and if limits when a job runs.
1# .github/workflows/ci.yml — Full Structure
2
3name: CI — AI-Assisted Quality Pipeline
4on:
5 push:
6 branches: [main, develop]
7 pull_request:
8 branches: [main, develop]
9 types: [opened, synchronize, ready_for_review]
10
11# One env block for all jobs
12env:
13 GO_VERSION: '1.22'
14
15jobs:
16 # ============================================================
17 # LAYER 1: SYNTACTIC — Always runs, blocks everything
18 # ============================================================
19
20 syntactic:
21 name: "L1: Build, Test & Lint"
22 runs-on: ubuntu-latest
23 outputs:
24 status: ${{ job.status }}
25 steps:
26 - uses: actions/checkout@v4
27 - uses: actions/setup-go@v5
28 with: { go-version: '${{ env.GO_VERSION }}', cache: true }
29 - name: Build
30 run: go build ./...
31 - name: Test
32 run: go test -race -count=1 -timeout=5m ./...
33 - name: Coverage gate
34 run: |
35 go test -coverprofile=cov.out ./...
36 COVERAGE=$(go tool cover -func=cov.out | grep total | awk '{print $3}' | tr -d '%')
37 echo "Coverage: ${COVERAGE}%"
38 awk "BEGIN {exit ($COVERAGE >= 70) ? 0 : 1}" || \
39 { echo "❌ Coverage below 70%"; exit 1; }
40 - name: Vet
41 run: go vet ./...
42 - name: Lint
43 uses: golangci/golangci-lint-action@v6
44 - name: Security scan
45 run: |
46 go install github.com/securego/gosec/v2/cmd/gosec@latest
47 gosec -severity medium -no-fail ./...
48
49 # ============================================================
50 # LAYER 2: SEMANTIC-STATIC — Runs after L1, blocks merge
51 # ============================================================
52
53 architecture:
54 name: "L2: Architecture Boundary Check"
55 runs-on: ubuntu-latest
56 needs: syntactic
57 steps:
58 - uses: actions/checkout@v4
59 - uses: actions/setup-go@v5
60 with: { go-version: '${{ env.GO_VERSION }}' }
61 - name: Check layer boundaries
62 run: go run ./scripts/check-architecture.go ./...
63 - name: Check dependency guard
64 run: |
65 # Ensure no cross-service internal imports
66 go run ./scripts/check-monorepo-boundaries.go ./...
67
68 # ============================================================
69 # LAYER 3: SEMANTIC-AI — Parallel with L4, PR only
70 # ============================================================
71
72 ai-review:
73 name: "L3: AI Semantic Review"
74 runs-on: ubuntu-latest
75 needs: syntactic # only runs after L1 passes
76 if: |
77 github.event_name == 'pull_request' &&
78 !github.event.pull_request.draft
79 permissions:
80 pull-requests: write
81 contents: read
82 steps:
83 - uses: actions/checkout@v4
84 with: { fetch-depth: 0 }
85 - name: Copilot PR Review
86 uses: github/copilot-for-pull-requests@v1
87 with:
88 github-token: ${{ secrets.GITHUB_TOKEN }}
89 review-instructions: |
90 Review Go code per CLAUDE.md rules.
91 CRITICAL (block): error not wrapped, float64 for money,
92 architecture violations, _ ignoring errors.
93 End with REVIEW_SCORE: X/100
94
95 pr-enrichment:
96 name: "L3: PR Description & Metadata"
97 runs-on: ubuntu-latest
98 needs: syntactic
99 if: |
100 github.event_name == 'pull_request' &&
101 github.event.action == 'opened'
102 permissions:
103 pull-requests: write
104 contents: read
105 env:
106 ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
107 steps:
108 - uses: actions/checkout@v4
109 with: { fetch-depth: 0 }
110 - name: Generate PR description
111 uses: actions/github-script@v7
112 with:
113 script: |
114 // Auto-generate PR description (details in Article 10)
115 console.log('PR description generation — see Article 10');
116
117 # ============================================================
118 # LAYER 4: SPEC COMPLIANCE — Parallel with L3, PR only
119 # ============================================================
120
121 spec-audit:
122 name: "L4: Spec Compliance Audit"
123 runs-on: ubuntu-latest
124 needs: syntactic
125 if: |
126 github.event_name == 'pull_request' &&
127 !github.event.pull_request.draft
128 steps:
129 - uses: actions/checkout@v4
130 - uses: actions/setup-node@v4
131 with: { node-version: '20' }
132 - name: Install specify CLI
133 run: npm install -g @santekno/spec-kit
134 - name: Run spec audit
135 run: specify audit --fail-on-score-below 80The key to reading this workflow: ai-review and spec-audit both needs: syntactic (not needs: architecture), so both run in parallel after Layer 1 passes — exactly like the parallel gate in the earlier diagram.
02.5 Trigger Strategy: When Each Thing Runs
Not every pipeline needs to run on every event; the wrong trigger produces a slow and expensive pipeline. The breakdown below maps each event to which layer runs and its estimated time.
1Not every pipeline needs to run on every event.
2The wrong trigger = a slow and expensive pipeline.
3
4EVENT: push to feature branch
5 Purpose: fast feedback for the developer currently coding
6 Run: Layer 1 only (build + test + lint)
7 Don't run: AI review (no PR), spec audit
8 Time: 3-5 minutes
9
10EVENT: PR opened or synchronize (new commit to PR)
11 Purpose: quality gate before code review
12 Run: Layer 1 + 2 + 3 + 4
13 Time: 7 minutes (L1+L2 sequential, L3+L4 parallel)
14
15EVENT: push to main or develop
16 Purpose: verify post-merge health
17 Run: Layer 1 + 2 (L3 and L4 not relevant — PR already reviewed)
18 Time: 5 minutes
19
20EVENT: PR marked ready_for_review (from draft)
21 Purpose: run the full pipeline for a PR that just became ready
22 Run: Layer 1 + 2 + 3 + 4 (full)
23 Time: 7 minutes
24
25EVENT: schedule (nightly)
26 Purpose: full health check + dependency update check
27 Run: Layer 1 + security deep scan
28 Time: 10 minutes (comprehensive scan)The principle to take away: a push event to a feature branch only needs Layer 1 for fast feedback, whereas the full pipeline with AI only needs to run when there’s a PR that’s actually going to be reviewed.
02.6 Cost Architecture: Estimated Cost per Event
Before enabling the pipeline, it helps to calculate its cost so there are no surprises in the monthly bill. The breakdown below sums the cost per layer up to a monthly estimate for an 8-developer team.
1Cost per pipeline run:
2
3Layer 1 (no AI cost):
4 GitHub Actions: ~$0.002 (ubuntu runner, 5 minutes)
5 Total L1: $0.002
6
7Layer 2 (no AI cost):
8 GitHub Actions: ~$0.001 (30 seconds)
9 Total L2: $0.001
10
11Layer 3 (AI cost):
12 Copilot PR review: already included in subscription
13 Claude PR description: ~500 tokens input, ~200 output
14 Cost: (500 × $0.80 + 200 × $4.00) / 1,000,000 = $0.0012
15 GitHub Actions: ~$0.001
16 Total L3: ~$0.002
17
18Layer 4 (no AI cost):
19 specify CLI: free
20 GitHub Actions: ~$0.001
21 Total L4: $0.001
22
23TOTAL per full pipeline run: ~$0.006
24
25Monthly estimate (24 PRs/week × 4 weeks = 96 PRs/month):
26 96 × $0.006 = $0.58/month
27 Plus GitHub Actions compute: ~$2/month
28
29 TOTAL: ~$2.60/month for an 8-developer team
30 (excluding the Copilot subscription you already have)That ~$2.60/month figure is practically negligible compared to the engineer time saved — cost is not the limiting factor in the decision to adopt this pipeline.
02.7 Repository Structure for the Pipeline
The pipeline needs the support of a tidy repository structure so every script and config is easy to find. The directory structure below shows where the workflows, scripts, and config files are placed.
1santekno-shop/
2├── .github/
3│ ├── workflows/
4│ │ ├── ci.yml ← main pipeline (this article)
5│ │ ├── release.yml ← release notes generator (article 11)
6│ │ └── nightly.yml ← scheduled security scan
7│ ├── copilot-instructions.md ← AI review context
8│ └── pull_request_template.md
9├── scripts/
10│ ├── check-architecture.go ← from Topic 3
11│ ├── check-monorepo-boundaries.go
12│ └── review-bot/
13│ └── main.go ← custom AI review (article 5)
14├── CLAUDE.md ← universal context
15├── .golangci.yml ← lint configuration
16├── .gitleaks.toml ← secret scan rules
17└── go.work ← workspace (if monorepo)Notice that all the supporting files — CLAUDE.md, lint config, architecture script — live inside the same repo, so the pipeline and its rules are versioned together with the code.
02.8 A Comprehensive .golangci.yml
Layer 1 is only as strong as its linter configuration. The .golangci.yml configuration below is the one we use in Santekno Shop — enabling linters for correctness, idiom, performance, security, and custom import rules.
1# .golangci.yml — configuration for Santekno Shop
2
3run:
4 timeout: 5m
5 go: '1.22'
6 tests: true
7
8linters:
9 enable:
10 # Core correctness
11 - errcheck # check unhandled errors
12 - govet # suspicious constructs
13 - staticcheck # comprehensive static analysis
14 - unused # unused code
15
16 # Go idioms
17 - gofmt # formatting
18 - goimports # import ordering
19 - misspell # typos
20
21 # Performance
22 - prealloc # slice preallocation
23 - bodyclose # HTTP response body close check
24
25 # Security
26 - gosec # security issues
27 - exhaustive # switch exhaustiveness
28
29 # Custom rules
30 - depguard # forbidden import paths
31 - gomodguard # module usage rules
32
33linters-settings:
34 depguard:
35 rules:
36 main:
37 deny:
38 # Ensure no cross-service internal imports
39 - pkg: "github.com/santekno/santekno-shop/services/*/internal"
40 desc: "Cross-service internal imports forbidden. Use Kafka events."
41 # Ensure no deprecated mock library
42 - pkg: "github.com/golang/mock"
43 desc: "Use go.uber.org/mock instead"
44
45 errcheck:
46 check-type-assertions: true
47 check-blank: true
48
49 govet:
50 enable-all: true
51
52issues:
53 exclude-rules:
54 # Test files may ignore errors
55 - path: _test\.go
56 linters: [errcheck]
57 # Generated files are excluded
58 - path: ".*\\.pb\\.go"
59 linters: [all]
60 - path: ".*mock.*\\.go"
61 linters: [all]
62
63 max-issues-per-linter: 50
64 max-same-issues: 3The depguard section is the most valuable part here: it enforces the architecture boundary (the ban on cross-service internal imports) deterministically without a single cent of AI cost.
02.9 Secrets Management in CI
A pipeline that calls external APIs needs secrets managed securely. The block below summarizes which secrets are needed, how to set them via the GitHub CLI, and the best practices for managing them.
1# GitHub Secrets that need to be set up:
2
3# Required for AI review via the Claude API:
4ANTHROPIC_API_KEY # from console.anthropic.com
5
6# Required for secret scanning:
7# (none — gitleaks and trufflehog don't need a secret)
8
9# Optional for extended features:
10SLACK_WEBHOOK # for deployment notifications
11SONAR_TOKEN # if using SonarQube
12
13# Setup via GitHub CLI:
14gh secret set ANTHROPIC_API_KEY --body "sk-ant-xxx"
15gh secret set SLACK_WEBHOOK --body "https://hooks.slack.com/xxx"
16
17# Verify:
18gh secret list
19
20# Security best practices for secrets in CI:
21# 1. Minimal permissions — API key only for what's needed
22# 2. Rotation schedule — rotate every 90 days
23# 3. Environment scoping — production secrets only in production env
24# 4. Audit logs — monitor usage in the Anthropic console
25
26# Environment protection (for production secrets):
27# GitHub → Settings → Environments → production → Protection rules
28# Required reviewers: [tech lead]
29# Restrict to protected branches: main onlyThe bottom line: only ANTHROPIC_API_KEY is truly required; secret scanning needs no credentials at all — and environment protection is an extra layer to separate production secrets from other branches.
02.10 Caching Strategy for Speed
Most of the pipeline time is spent downloading dependencies and rebuilding — caching cuts both. The configuration below shows four cache layers and the estimated time each one saves.
1# Caches that are significant for a Go pipeline:
2
3# 1. Go module cache (most impactful, 30-60 seconds saved)
4- uses: actions/setup-go@v5
5 with:
6 go-version: '1.22'
7 cache: true # this alone already caches go modules
8
9# 2. golangci-lint cache (10-20 seconds saved)
10- uses: golangci/golangci-lint-action@v6
11 with:
12 # Cache is already built into this action
13
14# 3. Build cache for custom scripts
15- uses: actions/cache@v4
16 with:
17 path: |
18 ~/.cache/go-build
19 ~/go/pkg/mod
20 key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
21 restore-keys: |
22 ${{ runner.os }}-go-
23
24# 4. Node modules for the specify CLI
25- uses: actions/cache@v4
26 with:
27 path: ~/.npm
28 key: ${{ runner.os }}-npm-specify-${{ hashFiles('package-lock.json') }}
29
30# Expected cache hit improvement:
31# Cold run (no cache): 8-12 minutes
32# Warm run (cache hit): 3-5 minutes
33# Savings: ~60% pipeline timeWith proper caching, a warm run drops from 8-12 minutes to 3-5 minutes — a ~60% savings that’s immediately felt by developers every time they push.
02.11 Notification and Feedback Loop
Excessive notifications actually make the team ignore alerts. The notification pattern below is deliberately sparing — only notifying when truly necessary, with an example Slack workflow for a failure on the main branch.
1# Useful notifications (not overwhelming):
2
3# Recommended pattern:
4# - SUCCESS: no notification needed (don't distract the developer)
5# - FAILURE on main: notify Slack channel #engineering-alerts
6# - FAILURE on PR: GitHub comment (auto from Actions)
7# - WEEKLY summary: digest in Slack #engineering
8
9# Workflow for Slack notification when main fails:
10- name: Notify on main branch failure
11 if: failure() && github.ref == 'refs/heads/main'
12 uses: 8398a7/action-slack@v3
13 with:
14 status: failure
15 fields: repo,message,commit,author,workflow
16 text: ':red_circle: Main branch CI failed! Check immediately.'
17 env:
18 SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
19
20# GitHub comment for PR failure (built-in from Actions):
21# When a job fails, GitHub automatically shows it in the PR checks tab
22# The developer sees what failed right away without needing SlackThe principle is simple: the fewer notifications, the higher the attention per notification — don’t train the team to ignore alerts by flooding them with success messages.
02.12 Measuring Pipeline Health
The pipeline needs to be monitored just like a production service. The set of gh and jq commands below computes three pipeline health metrics directly from the GitHub Actions API.
1# Dashboard metrics to track:
2
3# 1. Pipeline success rate (target: > 95%)
4# Via GitHub Actions API:
5gh run list --workflow=ci.yml --json conclusion \
6 | jq '[.[] | select(.conclusion != null)] | {
7 total: length,
8 success: [.[] | select(.conclusion == "success")] | length
9 } | .success / .total * 100 | floor'
10
11# 2. Average pipeline duration (target: < 10 minutes)
12gh run list --workflow=ci.yml --json createdAt,updatedAt \
13 | jq '[.[] | ((.updatedAt | fromdateiso8601) - (.createdAt | fromdateiso8601))] | add / length / 60'
14
15# 3. Most common failure reason
16gh run list --workflow=ci.yml --status failure --json jobs \
17 | jq '[.[].jobs[] | select(.conclusion == "failure") | .name] | group_by(.) | map({job: .[0], count: length}) | sort_by(-.count) | .[0:5]'
18
19# Store metrics weekly:
20# Spreadsheet or Grafana dashboard
21# Review in the sprint retrospectiveThe “most common failure reason” metric is the most actionable: if one job dominates the failures, that’s where your tuning effort should be focused.
02.13 Blue/Green Pipeline Rollout
Replacing an active pipeline risks disrupting development if done all at once. The three-phase rollout strategy below introduces the new pipeline gradually — from shadow mode to full enforcement.
1How to roll out a new pipeline without disrupting development:
2
3PHASE 1 (Week 1): Shadow mode
4 The new pipeline runs in parallel with the old pipeline
5 Its results are only logged, not blocking merge
6 Purpose: validate the false positive rate
7
8PHASE 2 (Week 2-3): Warning mode
9 The new pipeline replaces the old pipeline
10 Failures become GitHub comments (not blocking)
11 Developers can see them but aren't blocked
12 Purpose: developers get familiar with the output format
13
14PHASE 3 (Week 4+): Enforcement mode
15 CRITICAL issues block merge
16 SUGGESTION stays informational
17 Monitor: is anyone complaining about false positives?
18
19How to implement shadow mode:
20 continue-on-error: true # on all AI-related steps
21
22 # After the shadow period:
23 # Remove continue-on-error from CRITICAL checksThe technical key to this rollout is continue-on-error: true: it’s this flag that lets the new pipeline “peek” without blocking anyone during the shadow and warning phases.
02.14 Pipeline as Code: Versioning and Review
The pipeline YAML is code, and it must be treated like code. The five practices below enforce that discipline — from review via PR to a rollback plan with git tags.
1The pipeline YAML is code — it needs to be treated like code:
2
31. PR for pipeline changes
4 Changes to .github/workflows/*.yml must go via PR
5 Not directly pushed to main
6
72. Review by a senior developer
8 The pipeline affects all developers — it needs careful review
9
103. Testing in a branch before merge
11 Feature branch: make the pipeline change
12 Test: push a few commits, verify pipeline behavior
13 Merge: after confirmed working
14
154. CHANGELOG for the pipeline
16 Keep a changelog at .github/PIPELINE_CHANGELOG.md
17 Document every significant change
18
195. Rollback plan
20 Tag the pipeline state before a major change:
21 git tag pipeline-v1.0 (before AI review was added)
22 git tag pipeline-v2.0 (after AI review)
23
24 Rollback: git checkout pipeline-v1.0 -- .github/workflows/Because pipeline changes affect the whole team, points 2 and 3 aren’t formalities: one wrong YAML can block everyone, so review and testing in a branch first is a must.
02.15 Pipeline Security Architecture
A pipeline that has access to secrets and write permissions is a new attack surface. The guidance below enforces least-privilege for permissions, secrets, third-party actions, and the runner.
1Security considerations for a secure pipeline:
2
3PERMISSIONS (principle of least privilege):
4 Default for all jobs:
5 permissions:
6 contents: read # read-only by default
7
8 Override per-job only for those that need it:
9 ai-review job:
10 permissions:
11 pull-requests: write # to post comments
12 contents: read
13
14 pr-enrichment job:
15 permissions:
16 pull-requests: write
17 contents: read
18
19SECRETS:
20 - Don't expose secrets in logs
21 - Use ${{ secrets.XXX }}, not a hardcoded environment variable
22 - secrets.GITHUB_TOKEN: auto-generated, minimal scope
23
24THIRD-PARTY ACTIONS:
25 - Pin to a commit hash, not a floating tag
26 - Verified creator actions are safer
27
28 BAD: uses: some-action@main
29 OK: uses: some-action@v1
30 BEST: uses: some-action@abc123def456 # pinned commit
31
32RUNNER:
33 - ubuntu-latest for non-sensitive
34 - Self-hosted runner for sensitive secrets
35 - Isolated environment via container for high-securityOne practice that’s often overlooked but crucial: pin third-party actions to a commit hash, not a tag — because a tag can be changed by its owner and become a supply chain attack vector.
02.16 Implementation Skeleton: Start Here
All the theory above will be executed starting from one minimal starter file. The template below is the starting point for ci.yml — only Layer 1 is active, with Layers 2-4 prepared as comments to be filled in in the following articles.
1# STARTER TEMPLATE: .github/workflows/ci.yml
2# Copy this, customize, and extend it in the following articles
3
4name: CI — Santekno Shop
5on:
6 push:
7 branches: [main, develop]
8 pull_request:
9 branches: [main, develop]
10 types: [opened, synchronize, ready_for_review]
11
12env:
13 GO_VERSION: '1.22'
14
15jobs:
16 # Layer 1: Core Go checks
17 go-quality:
18 name: Go Quality Gates
19 runs-on: ubuntu-latest
20 steps:
21 - uses: actions/checkout@v4
22 - uses: actions/setup-go@v5
23 with: { go-version: '${{ env.GO_VERSION }}', cache: true }
24 - run: go build ./...
25 - run: go test -race -count=1 ./...
26 - run: go vet ./...
27 - uses: golangci/golangci-lint-action@v6
28
29 # Layer 2: Architecture (we add this in the next article)
30 # architecture-check: ...
31
32 # Layer 3: AI Review (article 03 onward)
33 # ai-review: ...
34
35 # Layer 4: Spec Audit (article 04)
36 # spec-audit: ...Start from this skeleton: commit a working Layer 1 first, then uncomment Layers 2, 3, and 4 one by one in the following articles — exactly in the spirit of the “start with a skeleton, iterate” principle.
02.17 Our Pipeline vs Other Popular Pipelines
To put this pipeline in context, it helps to compare it with the standard pipelines in the Go community. The comparison below shows where the Santekno pipeline stands relative to the standard and advanced pipelines.
1Comparison with standard pipelines in the Go community:
2
3STANDARD Go pipeline (most teams):
4 ✅ build, test, vet, lint
5 ❌ architecture enforcement
6 ❌ AI review
7 ❌ spec compliance
8 ❌ PR description generation
9
10ADVANCED Go pipeline (10% of teams):
11 ✅ everything above
12 ✅ security scanning (gosec, snyk)
13 ✅ coverage gate
14 ❌ AI review
15 ❌ spec compliance
16
17SANTEKNO AI-AUGMENTED (what we're building):
18 ✅ everything above
19 ✅ architecture enforcement (custom script)
20 ✅ AI semantic review (Copilot + Claude)
21 ✅ spec compliance (Spec Kit)
22 ✅ PR description generation
23 ✅ cost monitoring
24 ✅ graduated enforcement
25
26Competitive position:
27 Most Go teams in Indonesia: Standard pipeline
28 Our target: AI-Augmented, not yet widely adopted
29
30 Building this now = a 12-18 month head start
31 before this becomes the industry "standard"The conclusion is clear: by building an AI-augmented pipeline now, your team gains a 12-18 month head start before this approach becomes the industry standard.
02.18 Implementation Timeline for Parts 1-4
This blueprint will be executed gradually throughout Topic 4. The roadmap below maps out what’s done in each article, from today’s skeleton to LLMOps in Part 4.
1Implementation roadmap throughout Topic 4:
2
3NOW (Article 2):
4 ✅ Architecture blueprint (this article)
5 ✅ Skeleton workflow YAML
6 ✅ Directory structure
7
8ARTICLE 3 (next):
9 Claude Code setup in GitHub Actions
10 Environment, auth, CLAUDE.md access
11 Basic Claude API call from CI
12
13ARTICLE 4:
14 Spec validation integration
15 specify audit in the pipeline
16
17ARTICLES 5-9 (Part 2):
18 Quality gates: AI review, security, coverage, architecture
19
20ARTICLES 10-14 (Part 3):
21 Automation: PR description, changelog, migration check
22
23ARTICLES 15-20 (Part 4):
24 LLMOps: prompt versioning, cost monitoring, incident playbookThis roadmap also serves as an expectation contract: this article completes the architecture foundation, and the next article goes straight into setting up Claude in CI.
02.19 Architecture Tips & Gotchas
Before wrapping up, there are a few practical tips and traps worth noting when designing a pipeline architecture. The list below summarizes the three tips and three gotchas that most often determine whether an implementation succeeds.
💡 Tip 1: Start with a skeleton, iterate. Don’t build the full pipeline all at once. Start with a working Layer 1, commit to main, then add Layers 2, 3, 4 gradually.
💡 Tip 2: Test the pipeline in a feature branch. Before merging a pipeline change to main, test it in a feature branch with a few dummy commits to verify behavior.
💡 Tip 3: Comment your YAML. Pipeline YAML with no comments is hard to maintain 6 months later. Comment every job with its purpose and conditions.
⚠️ Gotcha 1: The wrong needs. If L3 doesn’t have needs: syntactic, it will run at the same time as L1 — and may fail because L1 isn’t done yet. Always define the dependency with needs.
⚠️ Gotcha 2: An if condition that’s too complex. If one job has 5+ conditions, split it into multiple jobs or use reusable workflows.
⚠️ Gotcha 3: No timeout. Jobs without a timeout can run forever if there’s an infinite loop or a stuck process. Always add timeout-minutes: 10.
If you can only remember one, remember Gotcha 1: the wrong needs is the most common cause of a pipeline that “sometimes passes, sometimes fails” for no clear reason.
02.20 Summary
The architecture blueprint we designed in this article is the foundation for all the implementation in Topic 4. Key decisions:
4 clear layers: Syntactic → Semantic-Static → Semantic-AI → Spec Compliance. Each layer has a different purpose and cost.
Parallel where possible: L3 and L4 run in parallel after L1+L2 finish. Total wall time ≤ 8 minutes.
Graduated enforcement: Warning first, block later. A pipeline that’s too strict from the start will be bypassed.
Predictable cost: ~$3/month for an 8-developer team with 24 PRs/week.
In the next article, we start implementation with the most critical step: setting up Claude Code in GitHub Actions.