Skip to content

Commit c98dfeb

Browse files
ericsmallingclaude
andcommitted
jenkins: route cosign/crane helper images via PULL_REGISTRY
In Harbor modes (HARBOR_ENABLED=true) the controller has no cgr.dev credentials, so pulling the cosign helper (cgSign/cgVerify) and the crane agent (refresh-cgimages-digests) directly from cgr.dev failed. Source them via $PULL_REGISTRY the same way cgImage() routes the application build/test agents — cgr.dev/<org> in Mode A, anonymous localhost/cgr-proxy/<org> in Modes B/C. Also align the surrounding docs (cgImages README, refresh-cgimages- digests README) with the real cgLogin/PULL_REGISTRY flow, and drop the obsolete .secrets/ entry from .gitignore (the OIDC flow writes to /tmp/cgjenkins-home/.docker, no in-repo secrets dir is created). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 04af03a commit c98dfeb

6 files changed

Lines changed: 29 additions & 13 deletions

File tree

jenkins/.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
# Local environment overrides (e.g. CHAINGUARD_ORG). Bootstrapped from .env.example.
22
.env
33

4-
# Pull-token-derived Docker config — generated by setup.sh, must not be committed.
5-
.secrets/
6-
74
# Identity UIDP file — generated by setup.sh, ephemeral, must not be committed.
85
shared-libraries/cg-images/IDENTITY
96

jenkins/ops/refresh-cgimages-digests/Jenkinsfile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ pipeline {
2727
stage('Refresh digests') {
2828
agent {
2929
docker {
30-
image "cgr.dev/${env.CHAINGUARD_ORG}/crane:latest-dev"
30+
// Pull crane via PULL_REGISTRY (cgr.dev/<org> in Mode A,
31+
// localhost/cgr-proxy/<org> in Modes B/C where the controller
32+
// has no cgr.dev creds — same routing as cgImage() applies to
33+
// the application build/test agents).
34+
image "${env.PULL_REGISTRY ?: "cgr.dev/${env.CHAINGUARD_ORG}"}/crane:latest-dev"
3135
// The agent inherits the controller's mounts via `--volumes-from`
3236
// (Jenkins docker-workflow plugin default), so the shared-libraries
3337
// tree (rw) and the pull-token docker config are already visible at

jenkins/ops/refresh-cgimages-digests/README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ Scheduled Jenkins job that re-resolves every digest in the [cgImages shared-libr
66

77
| Stage | Image | Purpose |
88
|-------|-------|---------|
9-
| Refresh digests | `cgr.dev/${CHAINGUARD_ORG}/crane:latest-dev` | Runs [refresh-digests.sh](../../shared-libraries/cg-images/refresh-digests.sh) which calls `crane digest` for each entry. |
9+
| Auth | (controller) | Runs `cgLogin()` — in Mode A this exchanges a Jenkins OIDC token for a chainctl session and writes a fresh docker config to `$DOCKER_CONFIG`; in Modes B/C (Harbor) it's a no-op because pulls go anonymously through the Harbor proxy. |
10+
| Refresh digests | `${PULL_REGISTRY}/crane:latest-dev` | Runs [refresh-digests.sh](../../shared-libraries/cg-images/refresh-digests.sh) which calls `crane digest` for each entry. |
1011

11-
The agent container gets:
12-
- `DOCKER_CONFIG=/dockerconfig` pointed at the bind-mounted pull-token config (so `crane` can authenticate to `cgr.dev`)
13-
- `/tmp/cgjenkins-home/shared-libraries` mounted **read-write** at `/sources` so the script can rewrite `vars/cgImage.groovy`
12+
The agent container inherits the controller's mounts (Jenkins docker-workflow `--volumes-from`), so:
13+
- `DOCKER_CONFIG=/tmp/cgjenkins-home/.docker` points at the controller's docker config — populated by `cgLogin()` in Mode A so `crane` can authenticate to `cgr.dev`; unused in Modes B/C where the Harbor proxy serves manifests anonymously.
14+
- `/tmp/cgjenkins-home/shared-libraries` is bind-mounted **read-write** so the script can rewrite `vars/cgImage.groovy` in place.
15+
16+
The crane image itself is pulled via `PULL_REGISTRY` (not `cgr.dev` directly), matching how `cgImage()` routes application build/test agents — so this job works in Harbor modes even though the controller has no cgr.dev creds.
1417

1518
When digests change, the next sample-app pipeline picks them up automatically — the cgImages library is live-loaded from the same bind-mounted dir on every build. No Jenkins restart needed.
1619

jenkins/shared-libraries/cg-images/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ To refresh the digests (e.g. to pick up a security patch in the underlying image
4848
./refresh-digests.sh
4949
```
5050

51-
The script reads the current `repo:tag` portion of each pinned reference, calls `crane digest cgr.dev/$CHAINGUARD_ORG/<repo>:<tag>` for each, and rewrites the digest in place. Requires `crane`. It picks up `CHAINGUARD_ORG` from `../../.env` so refreshing matches the org the demo is configured for.
51+
The script reads the current `repo:tag` portion of each pinned reference, calls `crane digest $PULL_REGISTRY/<repo>:<tag>` for each, and rewrites the digest in place. Requires `crane`. It picks up `CHAINGUARD_ORG` (and, optionally, `PULL_REGISTRY`) from `../../.env` so refreshing matches the org and pull routing the demo is configured for: `cgr.dev/<org>` directly in Mode A, or the anonymous `localhost/cgr-proxy/<org>` Harbor cache in Modes B/C.
5252

5353
## Adding a new token
5454

jenkins/shared-libraries/cg-images/vars/cgSign.groovy

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
// wrote earlier in the pipeline (Harbor admin creds in Mode C; nothing
2323
// needed in A/B since signatures push anonymously to ttl.sh).
2424
//
25+
// The cosign helper image itself is pulled from $PULL_REGISTRY (not
26+
// cgr.dev directly) — that's cgr.dev/<org> in Mode A but the anonymous
27+
// Harbor proxy at localhost/cgr-proxy/<org> in Modes B/C, where the
28+
// controller has no cgr.dev creds. Same routing as cgImage() uses for
29+
// the application build/test agents.
30+
//
2531
// Usage from a stage on `agent any`:
2632
//
2733
// stage('Sign') {
@@ -43,7 +49,8 @@ def call(String image) {
4349
// Pass `image` through the sh step's environment rather than interpolating
4450
// it into the script body — otherwise an image ref containing a single
4551
// quote (or other shell metacharacter) could break out of the surrounding
46-
// quoting. CHAINGUARD_ORG is already exposed to the shell by Jenkins.
52+
// quoting. CHAINGUARD_ORG and PULL_REGISTRY are already exposed to the
53+
// shell by Jenkins.
4754
withEnv(["IMAGE=${image}"]) {
4855
withCredentials([
4956
file(credentialsId: 'cosign-private-key', variable: 'COSIGN_KEY_FILE'),
@@ -71,13 +78,14 @@ def call(String image) {
7178
case "$DIGEST" in
7279
localhost/*) DIGEST="localhost:80/${DIGEST#localhost/}" ;;
7380
esac
81+
COSIGN_IMAGE="${PULL_REGISTRY:-cgr.dev/${CHAINGUARD_ORG}}/cosign:latest-dev"
7482
docker run --rm --network host \
7583
-v "$COSIGN_KEY_FILE:/cosign.key:ro" \
7684
-v "$DOCKER_CONFIG:/jenkins-docker:ro" \
7785
-e "COSIGN_PASSWORD=$COSIGN_PASSWORD" \
7886
-e DOCKER_CONFIG=/jenkins-docker \
7987
--entrypoint=/usr/bin/cosign \
80-
"cgr.dev/${CHAINGUARD_ORG}/cosign:latest-dev" \
88+
"$COSIGN_IMAGE" \
8189
sign --yes --allow-http-registry --key /cosign.key "$DIGEST"
8290
echo "cgSign: signed $DIGEST"
8391
'''

jenkins/shared-libraries/cg-images/vars/cgVerify.groovy

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
// the full sign-then-verify loop.
99
//
1010
// Cosign runs in a one-shot container with --network host for the same
11-
// reason cgSign does — see that file for the full rationale.
11+
// reason cgSign does — see that file for the full rationale. The cosign
12+
// helper image itself is pulled from $PULL_REGISTRY so it works whether
13+
// the controller has cgr.dev creds (Mode A) or only the anonymous Harbor
14+
// proxy (Modes B/C).
1215
//
1316
// Usage from a stage on `agent any`:
1417
//
@@ -47,12 +50,13 @@ def call(String image) {
4750
case "$DIGEST" in
4851
localhost/*) DIGEST="localhost:80/${DIGEST#localhost/}" ;;
4952
esac
53+
COSIGN_IMAGE="${PULL_REGISTRY:-cgr.dev/${CHAINGUARD_ORG}}/cosign:latest-dev"
5054
docker run --rm --network host \
5155
-v "$COSIGN_PUB_FILE:/cosign.pub:ro" \
5256
-v "$DOCKER_CONFIG:/jenkins-docker:ro" \
5357
-e DOCKER_CONFIG=/jenkins-docker \
5458
--entrypoint=/usr/bin/cosign \
55-
"cgr.dev/${CHAINGUARD_ORG}/cosign:latest-dev" \
59+
"$COSIGN_IMAGE" \
5660
verify --allow-http-registry --key /cosign.pub "$DIGEST" >/dev/null
5761
echo "cgVerify: signature OK for $DIGEST"
5862
'''

0 commit comments

Comments
 (0)