Skip to content

Commit 4a18e52

Browse files
authored
fix(migrations): upgrade atlas base image to v1.1.3 (#2763)
Signed-off-by: Miguel Martinez <[email protected]>
1 parent 3d856a3 commit 4a18e52

File tree

2 files changed

+212
-4
lines changed

2 files changed

+212
-4
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
---
2+
name: vulnerability-remediation
3+
description: Reviews vulnerability policy violations for the chainloop project recorded in Chainloop and performs fixes in Dockerfiles or go.mod. Use when asked to fix vulnerabilities, review CVEs, or remediate security issues in chainloop.
4+
allowed-tools:
5+
- Bash
6+
- Read
7+
- Edit
8+
- Task
9+
- mcp__claude_ai_Chainloop__list_products_with_versions
10+
- mcp__claude_ai_Chainloop__get_frameworks_compliance
11+
- mcp__claude_ai_Chainloop__list_pieces_of_evidence
12+
- mcp__claude_ai_Chainloop__download_evidence_by_digest
13+
---
14+
15+
# Vulnerability Remediation for chainloop
16+
17+
This skill reviews open vulnerability policy violations recorded in Chainloop for the `chainloop` project and applies fixes to the affected source files.
18+
19+
## Step 1: Find the Latest Project Version
20+
21+
Use `list_products_with_versions` (no parameters needed — uses the current `chainloop` org) and locate the **Chainloop Community Edition** product. Find the `chainloop` project version entry and note its `projectVersionId` (UUID).
22+
23+
## Step 2: Gather Compliance Results and Evidence in Parallel
24+
25+
Once the `projectVersionId` is known, make both of these calls **at the same time**:
26+
27+
**Call A**`get_frameworks_compliance`:
28+
- `project_version_id`: the UUID from Step 1
29+
- `framework_ids`: `["0ceef195-6900-4166-8407-77eb84954ed3"]` (chainloop-best-practices)
30+
31+
**Call B**`list_pieces_of_evidence`:
32+
- `project_name`: `chainloop`
33+
- `project_version_name`: the version name from Step 1 (e.g. `v1.77.0`)
34+
- `latest`: `true`
35+
36+
### Parsing the compliance result (Call A)
37+
38+
The response will be large — parse it programmatically using a Bash subagent:
39+
40+
```python
41+
import json
42+
43+
with open('<tool-result-file>') as f:
44+
raw = json.load(f)
45+
data = json.loads(raw[0]['text'])
46+
47+
for req in data:
48+
if 'vulnerabilit' in req.get('name', '').lower():
49+
status = req.get('status', '')
50+
failed = [e for e in req.get('policyEvaluations', [])
51+
if e.get('status') not in ('PASSED', 'SKIPPED')]
52+
print(f"Requirement: {req['name']} — Status: {status}")
53+
for e in failed:
54+
print(f" FAILED: policy={e['name']} material={e.get('materialName','-')} status={e.get('status','-')}")
55+
```
56+
57+
This gives you the list of **failing material names** (e.g. `control-plane-migrations-report`).
58+
59+
## Step 3: Download the SARIF for Each Failing Material
60+
61+
From the `list_pieces_of_evidence` result (Call B above), find the item whose `name` matches the failing material name and whose `kind` is `SARIF`. Use its `digest` field directly — no need to decode attestations.
62+
63+
Call `download_evidence_by_digest` with:
64+
- `digest`: the digest of the matching SARIF item
65+
- `download_content`: `true`
66+
67+
The SARIF `logicalLocations[].fullyQualifiedName` field contains the full image reference, e.g.:
68+
```
69+
ghcr.io/chainloop-dev/chainloop/control-plane-migrations:v1.77.0@sha256:<digest>:/atlas
70+
```
71+
72+
The binary path (e.g. `/atlas`, `/app`) tells you which binary inside the image is vulnerable.
73+
74+
## Step 4: Identify the Fix
75+
76+
### 4a. Atlas / Migration Dockerfile vulnerabilities
77+
78+
**Symptom**: SARIF location is `/atlas`, image is `control-plane-migrations`
79+
80+
**Source file**: `app/controlplane/Dockerfile.migrations`
81+
82+
**Fix procedure**:
83+
1. Check the current atlas version in the comment at the top of the Dockerfile (e.g. `# atlas version v1.1.0`)
84+
2. Find the latest available version:
85+
```bash
86+
curl -s "https://registry.hub.docker.com/v2/repositories/arigaio/atlas/tags?page_size=20&ordering=last_updated" \
87+
| python3 -c "import json,sys; [print(t['name']) for t in json.load(sys.stdin)['results'] if t['name'][0].isdigit() and '-' not in t['name']]"
88+
```
89+
3. Run grype on the current and candidate versions to confirm the CVEs are present then gone:
90+
```bash
91+
grype arigaio/atlas:<current-version> --only-fixed 2>&1
92+
grype arigaio/atlas:<new-version> --only-fixed 2>&1
93+
```
94+
A clean run has only the header line and no CVE rows.
95+
4. Once a clean version is confirmed, pull it and get its digest:
96+
```bash
97+
docker pull arigaio/atlas:<new-version>
98+
docker inspect --format='{{index .RepoDigests 0}}' arigaio/atlas:<new-version>
99+
```
100+
5. Update `app/controlplane/Dockerfile.migrations`:
101+
```dockerfile
102+
# from: arigaio/atlas:<NEW_VERSION>
103+
# docker run arigaio/atlas@sha256:<NEW_DIGEST> version
104+
# atlas version v<NEW_VERSION>
105+
FROM arigaio/atlas@sha256:<NEW_DIGEST> as base
106+
```
107+
108+
### 4b. Go stdlib / Go module vulnerabilities (backend)
109+
110+
**Symptom**: SARIF location is a Go binary (e.g. `/app`, `/server`), package is `stdlib` or a Go module
111+
112+
**Fix options** (in order of preference):
113+
114+
**Option A — Upgrade Go version** (for stdlib CVEs):
115+
Use the `upgrading-golang` skill to bump the Go version in `go.mod` and all Dockerfiles.
116+
117+
**Option B — Upgrade a specific Go dependency** (for third-party modules):
118+
1. Identify the affected module from the SARIF `purls` field (e.g. `pkg:golang/github.com/foo/[email protected]`)
119+
2. Update `go.mod`:
120+
```bash
121+
go get github.com/foo/bar@<fixed-version>
122+
go mod tidy
123+
```
124+
3. Verify with grype:
125+
```bash
126+
grype dir:. --only-fixed 2>&1
127+
```
128+
129+
## Step 5: Verify the Fix with Grype
130+
131+
Always run grype before and after the change to confirm the CVEs are resolved:
132+
133+
```bash
134+
# Before — should show the CVE rows
135+
grype <image>:<current-version> --only-fixed 2>&1
136+
137+
# After — should show header only, no CVE rows
138+
grype <image>:<new-version> --only-fixed 2>&1
139+
```
140+
141+
A clean run has only the column header line and zero data rows.
142+
143+
## Step 6: Commit and Create a PR
144+
145+
1. Check which branch you are on — do **not** create a new branch if one already exists:
146+
```bash
147+
git branch --show-current
148+
```
149+
150+
2. Commit with signoff (no co-author):
151+
```bash
152+
git add <changed-files>
153+
git commit -s -m "fix(<scope>): <short description of the CVE fix>"
154+
git push -u origin <current-branch>
155+
```
156+
157+
3. Create the PR with `gh pr create`:
158+
```bash
159+
gh pr create --title "fix(<scope>): <short description>" --body "$(cat <<'EOF'
160+
## Summary
161+
162+
- <bullet: what was upgraded and why>
163+
- Fixes <CVE-ID> (<Severity>) and <CVE-ID> (<Severity>) in <package>
164+
- <brief note on how the fix works, e.g. new version built with Go X.Y.Z>
165+
EOF
166+
)"
167+
```
168+
169+
## Step 7: Report Results
170+
171+
Summarise the findings and changes in this format:
172+
173+
```
174+
## Vulnerability Remediation Summary
175+
176+
**Project**: chainloop v<version>
177+
**Requirement**: no-vulnerabilities-high — was: FAIL
178+
179+
### Fixed
180+
181+
| CVE | Severity | Package | Old Version | Fix Applied |
182+
|-----|----------|---------|-------------|-------------|
183+
| CVE-XXXX-XXXXX | Critical | <pkg> | <old> | Upgraded <file> to <new> |
184+
185+
### Files Changed
186+
- `app/controlplane/Dockerfile.migrations` — atlas vX.X.X → vX.X.X
187+
188+
### PR
189+
<GitHub PR URL>
190+
```
191+
192+
## Key Reference Data
193+
194+
| Item | Value |
195+
|------|-------|
196+
| Chainloop org | `chainloop` |
197+
| Project name | `chainloop` |
198+
| chainloop-best-practices framework ID | `0ceef195-6900-4166-8407-77eb84954ed3` |
199+
| Continuous-scanning workflow ID | `c506a425-d307-4a59-9132-659ffd417b57` |
200+
| Migrations Dockerfile | `app/controlplane/Dockerfile.migrations` |
201+
| Backend go.mod | `go.mod` (root) |
202+
203+
## Important Notes
204+
205+
- Always pin Docker images by SHA256 digest, not tag alone
206+
- For Go stdlib CVEs, upgrading the atlas or golang builder image is usually sufficient — check via grype before touching go.mod
207+
- Run `go mod tidy` after any go.mod change
208+
- The compliance-scanning runs daily, so the policy status will update automatically after the fix is merged and a new image is built

app/controlplane/Dockerfile.migrations

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Container image built by go-releaser that's used to run migrations against the database during deployment
22
# See https://atlasgo.io/guides/deploying/image
3-
# from: arigaio/atlas:latest
4-
# docker run arigaio/atlas@sha256:779e402cb5e93982271474834c4f0a89b5edf714b21dbc1770661e86e68db1ed version
5-
# atlas version v1.1.0
6-
FROM arigaio/atlas@sha256:779e402cb5e93982271474834c4f0a89b5edf714b21dbc1770661e86e68db1ed as base
3+
# from: arigaio/atlas:1.1.3
4+
# docker run arigaio/atlas@sha256:f0a0022a34e5ddffb634e75dfece214a86dfc1bb15151927c20cf3e6a84bac76 version
5+
# atlas version v1.1.3
6+
FROM arigaio/atlas@sha256:f0a0022a34e5ddffb634e75dfece214a86dfc1bb15151927c20cf3e6a84bac76 as base
77

88
FROM scratch
99
# Update permissions to make it readable by the user

0 commit comments

Comments
 (0)