Skip to content

Commit 2f51bf9

Browse files
authored
[SVLS 8070] Switch dd-octo permissions to running a workflow for serverless-init ghcr (#997)
## Overview * While dd-oct-sts has package: write permissions, these only apply to github actions, not to gitlab pipelines. So we need to use a github action to push our ghcr package. * Pulls from the public registry to get around needing a gitlab token in github AND a github token in gitlab. Retry logic for public registry included. ## Testing * Via manual pipeline, from DataDog/serverless-init-ci#5
1 parent 334558a commit 2f51bf9

3 files changed

Lines changed: 140 additions & 8 deletions

File tree

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.github/chainguard/serverless-init-ci-publish.sts.yaml @DataDog/serverless
2+
.github/publish-serverless-init-to-ghcr.yaml @DataDog/serverless
Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
# DD Octo STS Trust Policy for serverless-init-ci GitLab pipeline
22
#
3-
# This policy allows the serverless-init-ci GitLab pipeline to publish
4-
# serverless-init images to GitHub Container Registry (GHCR).
3+
# This policy allows the serverless-init-ci GitLab pipeline to trigger
4+
# GitHub Actions workflows that publish serverless-init images to GHCR.
55
#
66
# Reference: https://datadoghq.atlassian.net/wiki/spaces/SECENG/pages/5138645099
77
# Pipeline: https://gitlab.ddbuild.io/DataDog/serverless-init-ci
88

99
issuer: https://gitlab.ddbuild.io
1010

11-
# Subject pattern matches the serverless-init-ci repo on any branch or tag
11+
# Subject pattern matches the serverless-init-ci repo on any protected branch or tag
1212
subject_pattern: "project_path:DataDog/serverless-init-ci:ref_type:(branch|tag):ref:.*"
1313

14-
# Allow all branches and tags for building RC and prod images
14+
# Only allow protected branches and tags (security control)
1515
claim_pattern:
1616
project_path: "DataDog/serverless-init-ci"
1717
ref_type: "^(branch|tag)$"
18-
pipeline_source: "^(web|pipeline|push)$"
18+
ref_protected: "true"
19+
pipeline_source: "^(web|pipeline)$"
1920
ci_config_ref_uri: "^gitlab\\.ddbuild\\.io/DataDog/serverless-init-ci//\\.gitlab-ci\\.yml@refs/(heads|tags)/.*$"
2021

21-
# Minimal permissions: only write packages to GHCR
22+
# Minimal permissions: only trigger GitHub Actions workflows
23+
# The workflow itself uses GITHUB_TOKEN for GHCR access
2224
permissions:
23-
packages: write
24-
metadata: read
25+
actions: write
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
name: Publish serverless-init to GHCR
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
source_image:
7+
description: 'Source image from registry.datadoghq.com (e.g., registry.datadoghq.com/serverless-init:1.7.8)'
8+
required: true
9+
type: string
10+
version:
11+
description: 'Version tag (e.g., 1.7.8 or 1.7.8-rc1)'
12+
required: true
13+
type: string
14+
image_suffix:
15+
description: 'Image suffix (empty for standard, -alpine for alpine)'
16+
required: false
17+
type: string
18+
default: ''
19+
pipeline_id:
20+
description: 'GitLab pipeline ID'
21+
required: true
22+
type: string
23+
is_latest:
24+
description: 'Tag as latest (true for prod releases, false for RCs)'
25+
required: true
26+
type: boolean
27+
default: false
28+
29+
permissions:
30+
packages: write
31+
contents: read
32+
33+
jobs:
34+
publish-to-ghcr:
35+
runs-on: ubuntu-latest
36+
steps:
37+
- name: Install crane
38+
run: |
39+
cd /tmp
40+
wget https://github.com/google/go-containerregistry/releases/download/v0.20.2/go-containerregistry_Linux_x86_64.tar.gz
41+
tar -xzf go-containerregistry_Linux_x86_64.tar.gz
42+
sudo mv crane /usr/local/bin/
43+
crane version
44+
45+
- name: Login to GHCR
46+
uses: docker/login-action@v3
47+
with:
48+
registry: ghcr.io
49+
username: ${{ github.actor }}
50+
password: ${{ secrets.GITHUB_TOKEN }}
51+
52+
- name: Wait for image availability
53+
run: |
54+
SOURCE_IMAGE="${{ inputs.source_image }}"
55+
MAX_ATTEMPTS=20
56+
RETRY_DELAY=30
57+
# Maximum wait time: 20 attempts × 30s = 600s (10 minutes)
58+
59+
echo "⏳ Waiting for image to be available: ${SOURCE_IMAGE}"
60+
echo "Will check every ${RETRY_DELAY}s for up to $((MAX_ATTEMPTS * RETRY_DELAY))s"
61+
62+
for i in $(seq 1 $MAX_ATTEMPTS); do
63+
echo "Attempt $i/$MAX_ATTEMPTS: Checking if image exists..."
64+
65+
if crane manifest ${SOURCE_IMAGE} >/dev/null 2>&1; then
66+
echo "✅ Image is available!"
67+
exit 0
68+
fi
69+
70+
if [ $i -lt $MAX_ATTEMPTS ]; then
71+
echo "⏳ Image not yet available, waiting ${RETRY_DELAY}s..."
72+
sleep $RETRY_DELAY
73+
fi
74+
done
75+
76+
echo "❌ Image did not become available after $((MAX_ATTEMPTS * RETRY_DELAY))s"
77+
exit 1
78+
79+
- name: Copy image to GHCR
80+
run: |
81+
SOURCE_IMAGE="${{ inputs.source_image }}"
82+
VERSION="${{ inputs.version }}"
83+
IMAGE_SUFFIX="${{ inputs.image_suffix }}"
84+
PIPELINE_ID="${{ inputs.pipeline_id }}"
85+
IS_LATEST="${{ inputs.is_latest }}"
86+
87+
DEST_BASE="ghcr.io/datadog/datadog-lambda-extension/serverless-init"
88+
89+
echo "📦 Publishing serverless-init image to GHCR"
90+
echo " Source: ${SOURCE_IMAGE}"
91+
echo " Destinations:"
92+
echo " - ${DEST_BASE}:${VERSION}${IMAGE_SUFFIX}"
93+
echo " - ${DEST_BASE}:v${PIPELINE_ID}${IMAGE_SUFFIX}"
94+
95+
# Copy with version tag (with retry logic)
96+
# Maximum retry duration: 3 attempts with 10s delays between retries
97+
# This workflow is triggered in parallel with the publish attempt to registry.datadoghq.com
98+
# Registry.datadoghq.com should normally need about ~30 seconds to recieve the new image
99+
MAX_COPY_ATTEMPTS=3
100+
COPY_RETRY_DELAY=10
101+
102+
for i in $(seq 1 $MAX_COPY_ATTEMPTS); do
103+
echo "Copying image (attempt $i/$MAX_COPY_ATTEMPTS)..."
104+
105+
if crane copy ${SOURCE_IMAGE} ${DEST_BASE}:${VERSION}${IMAGE_SUFFIX}; then
106+
echo "✅ Image copied successfully!"
107+
break
108+
fi
109+
110+
if [ $i -lt $MAX_COPY_ATTEMPTS ]; then
111+
echo "⚠️ Copy failed, retrying in ${COPY_RETRY_DELAY}s..."
112+
sleep $COPY_RETRY_DELAY
113+
else
114+
echo "❌ Failed to copy image after $MAX_COPY_ATTEMPTS attempts"
115+
exit 1
116+
fi
117+
done
118+
119+
# Tag for pipeline ID
120+
crane tag ${DEST_BASE}:${VERSION}${IMAGE_SUFFIX} v${PIPELINE_ID}${IMAGE_SUFFIX}
121+
122+
# Tag as latest if this is a production release
123+
if [ "$IS_LATEST" = "true" ]; then
124+
echo " - ${DEST_BASE}:latest${IMAGE_SUFFIX}"
125+
crane tag ${DEST_BASE}:${VERSION}${IMAGE_SUFFIX} latest${IMAGE_SUFFIX}
126+
fi
127+
128+
echo "✅ Successfully published image to GHCR!"
129+
echo "📍 View at: https://github.com/DataDog/datadog-lambda-extension/pkgs/container/datadog-lambda-extension%2Fserverless-init"

0 commit comments

Comments
 (0)