Skip to content

Commit e94c67d

Browse files
committed
feat: adding back publish-image-and-sign support
Signed-off-by: NucleoFusion <[email protected]> fix: adding back publish-release dependency on test-code Signed-off-by: NucleoFusion <[email protected]> test Signed-off-by: NucleoFusion <[email protected]> test Signed-off-by: NucleoFusion <[email protected]> test Signed-off-by: NucleoFusion <[email protected]> test Signed-off-by: NucleoFusion <[email protected]> test Signed-off-by: NucleoFusion <[email protected]>
1 parent 256b67a commit e94c67d

File tree

4 files changed

+261
-62
lines changed

4 files changed

+261
-62
lines changed

.dagger/pipeline/apt-repo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ EOF`,
6060
cd /repo
6161
6262
git init
63-
git remote add origin https://x-access-token:[email protected]/goharbor/harbor-cli.git
63+
git remote add origin https://x-access-token:[email protected]/nucleofusion/harbor-cli.git
6464
git checkout -B gh-pages || git checkout --orphan gh-pages
6565
6666
git config user.name "github-actions[bot]"

.dagger/publishimage.go

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
"time"
8+
9+
"dagger/harbor-cli/internal/dagger"
10+
)
11+
12+
func (m *HarborCli) PublishImageAndSign(
13+
ctx context.Context,
14+
source *dagger.Directory,
15+
registry string,
16+
registryUsername string,
17+
registryPassword *dagger.Secret,
18+
imageTags []string,
19+
// +optional
20+
githubToken *dagger.Secret,
21+
// +optional
22+
actionsIdTokenRequestToken *dagger.Secret,
23+
// +optional
24+
actionsIdTokenRequestUrl string,
25+
) (string, error) {
26+
m.init(ctx, source)
27+
28+
imageAddrs := m.PublishImage(ctx, registry, registryUsername, imageTags, registryPassword)
29+
30+
_, err := m.Sign(
31+
ctx,
32+
githubToken,
33+
actionsIdTokenRequestUrl,
34+
actionsIdTokenRequestToken,
35+
registryUsername,
36+
registryPassword,
37+
imageAddrs[0],
38+
)
39+
if err != nil {
40+
return "", fmt.Errorf("failed to sign image: %w", err)
41+
}
42+
43+
fmt.Printf("Signed image: %s\n", imageAddrs)
44+
return imageAddrs[0], nil
45+
}
46+
47+
func (m *HarborCli) PublishImage(
48+
ctx context.Context,
49+
registry, registryUsername string,
50+
// +optional
51+
// +default=["latest"]
52+
imageTags []string,
53+
registryPassword *dagger.Secret,
54+
) []string {
55+
version := getVersion(imageTags)
56+
builders := m.build(ctx, version)
57+
releaseImages := []*dagger.Container{}
58+
59+
for i, tag := range imageTags {
60+
imageTags[i] = strings.TrimSpace(tag)
61+
if strings.HasPrefix(imageTags[i], "v") {
62+
imageTags[i] = strings.TrimPrefix(imageTags[i], "v")
63+
}
64+
}
65+
fmt.Printf("provided tags: %s\n", imageTags)
66+
67+
// Get current time for image creation timestamp
68+
creationTime := time.Now().UTC().Format(time.RFC3339)
69+
70+
for _, builder := range builders {
71+
os, _ := builder.EnvVariable(ctx, "GOOS")
72+
arch, _ := builder.EnvVariable(ctx, "GOARCH")
73+
74+
if os != "linux" {
75+
continue
76+
}
77+
78+
ctr := dag.Container(dagger.ContainerOpts{Platform: dagger.Platform(os + "/" + arch)}).
79+
From("alpine:latest").
80+
WithWorkdir("/").
81+
WithFile("/harbor", builder.File("./harbor")).
82+
WithExec([]string{"ls", "-al"}).
83+
WithExec([]string{"./harbor", "version"}).
84+
// Add required metadata labels for ArtifactHub
85+
WithLabel("org.opencontainers.image.created", creationTime).
86+
WithLabel("org.opencontainers.image.description", "Harbor CLI - A command-line interface for CNCF Harbor, the cloud native registry!").
87+
WithLabel("io.artifacthub.package.readme-url", "https://raw.githubusercontent.com/goharbor/harbor-cli/main/README.md").
88+
WithLabel("org.opencontainers.image.source", "https://github.com/goharbor/harbor-cli").
89+
WithLabel("org.opencontainers.image.version", version).
90+
WithLabel("io.artifacthub.package.license", "Apache-2.0").
91+
WithEntrypoint([]string{"/harbor"})
92+
releaseImages = append(releaseImages, ctr)
93+
}
94+
95+
imageAddrs := []string{}
96+
for _, imageTag := range imageTags {
97+
addr, err := dag.Container().WithRegistryAuth(registry, registryUsername, registryPassword).
98+
Publish(ctx,
99+
fmt.Sprintf("%s/%s/harbor-cli:%s", registry, registryUsername, imageTag),
100+
dagger.ContainerPublishOpts{PlatformVariants: releaseImages},
101+
)
102+
if err != nil {
103+
panic(err)
104+
}
105+
fmt.Printf("Published image address: %s\n", addr)
106+
imageAddrs = append(imageAddrs, addr)
107+
}
108+
return imageAddrs
109+
}
110+
111+
func (m *HarborCli) build(
112+
ctx context.Context,
113+
version string,
114+
) []*dagger.Container {
115+
var builds []*dagger.Container
116+
117+
fmt.Println("🛠️ Building with Dagger...")
118+
oses := []string{"linux", "darwin", "windows"}
119+
arches := []string{"amd64", "arm64"}
120+
121+
// temp container with git installed
122+
temp := dag.Container().
123+
From("alpine:latest").
124+
WithMountedDirectory("/src", m.Source).
125+
// --no-cache option is to avoid caching the apk package index
126+
WithExec([]string{"apk", "add", "--no-cache", "git"}).
127+
WithWorkdir("/src")
128+
129+
gitCommit, _ := temp.WithExec([]string{"git", "rev-parse", "--short", "HEAD", "--always"}).Stdout(ctx)
130+
buildTime := time.Now().UTC().Format(time.RFC3339)
131+
ldflagsArgs := fmt.Sprintf(`-X github.com/goharbor/harbor-cli/cmd/harbor/internal/version.Version=%s
132+
-X github.com/goharbor/harbor-cli/cmd/harbor/internal/version.GoVersion=%s
133+
-X github.com/goharbor/harbor-cli/cmd/harbor/internal/version.BuildTime=%s
134+
-X github.com/goharbor/harbor-cli/cmd/harbor/internal/version.GitCommit=%s
135+
`, version, m.GoVersion, buildTime, gitCommit)
136+
137+
for _, goos := range oses {
138+
for _, goarch := range arches {
139+
bin_path := fmt.Sprintf("build/%s/%s/", goos, goarch)
140+
builder := dag.Container().
141+
From("golang:"+m.GoVersion+"-alpine").
142+
WithMountedCache("/go/pkg/mod", dag.CacheVolume("go-mod-"+m.GoVersion)).
143+
WithEnvVariable("GOMODCACHE", "/go/pkg/mod").
144+
WithMountedCache("/go/build-cache", dag.CacheVolume("go-build-"+m.GoVersion)).
145+
WithEnvVariable("GOCACHE", "/go/build-cache").
146+
WithMountedDirectory("/src", m.Source).
147+
WithWorkdir("/src").
148+
WithEnvVariable("GOOS", goos).
149+
WithEnvVariable("GOARCH", goarch).
150+
WithExec([]string{"go", "build", "-ldflags", ldflagsArgs, "-o", bin_path + "harbor", "/src/cmd/harbor/main.go"}).
151+
WithWorkdir(bin_path).
152+
WithExec([]string{"ls"}).
153+
WithEntrypoint([]string{"./harbor"})
154+
155+
builds = append(builds, builder)
156+
}
157+
}
158+
return builds
159+
}
160+
161+
// Sign signs a container image using Cosign, works also with GitHub Actions
162+
func (m *HarborCli) Sign(ctx context.Context,
163+
// +optional
164+
githubToken *dagger.Secret,
165+
// +optional
166+
actionsIdTokenRequestUrl string,
167+
// +optional
168+
actionsIdTokenRequestToken *dagger.Secret,
169+
registryUsername string,
170+
registryPassword *dagger.Secret,
171+
imageAddr string,
172+
) (string, error) {
173+
registryPasswordPlain, _ := registryPassword.Plaintext(ctx)
174+
175+
cosing_ctr := dag.Container().From("cgr.dev/chainguard/cosign")
176+
177+
// If githubToken is provided, use it to sign the image
178+
if githubToken != nil {
179+
if actionsIdTokenRequestUrl == "" || actionsIdTokenRequestToken == nil {
180+
return "", fmt.Errorf("actionsIdTokenRequestUrl (exist=%s) and actionsIdTokenRequestToken (exist=%t) must be provided when githubToken is provided", actionsIdTokenRequestUrl, actionsIdTokenRequestToken != nil)
181+
}
182+
fmt.Printf("Setting the ENV Vars GITHUB_TOKEN, ACTIONS_ID_TOKEN_REQUEST_URL, ACTIONS_ID_TOKEN_REQUEST_TOKEN to sign with GitHub Token")
183+
cosing_ctr = cosing_ctr.WithSecretVariable("GITHUB_TOKEN", githubToken).
184+
WithEnvVariable("ACTIONS_ID_TOKEN_REQUEST_URL", actionsIdTokenRequestUrl).
185+
WithSecretVariable("ACTIONS_ID_TOKEN_REQUEST_TOKEN", actionsIdTokenRequestToken)
186+
}
187+
188+
return cosing_ctr.WithSecretVariable("REGISTRY_PASSWORD", registryPassword).
189+
WithExec([]string{"cosign", "env"}).
190+
WithExec([]string{
191+
"cosign", "sign", "--yes", "--recursive",
192+
"--registry-username", registryUsername,
193+
"--registry-password", registryPasswordPlain,
194+
imageAddr,
195+
"--timeout", "1m",
196+
}).Stdout(ctx)
197+
}
198+
199+
func getVersion(tags []string) string {
200+
for _, tag := range tags {
201+
if strings.HasPrefix(tag, "v") {
202+
return tag
203+
}
204+
}
205+
return "latest"
206+
}

.github/actions/publish-and-sign/action.yaml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ runs:
3131
shell: bash
3232
env:
3333
GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }}
34-
run: cosign env
34+
run: |
35+
echo $REGISTRY_PASSWORD
36+
cosign env
3537
3638
- name: Publish and Sign Snapshot Image
3739
uses: dagger/dagger-for-github@v7
@@ -45,10 +47,11 @@ runs:
4547
version: ${{ steps.dagger_version.outputs.version }}
4648
verb: call
4749
args: "publish-image-and-sign \
48-
--registry='${{ env.REGISTRY_ADDRESS }}' \
49-
--registry-username='${{ env.REGISTRY_USERNAME }}' \
50-
--registry-password=env:REGISTRY_PASSWORD \
50+
--source=.
51+
--registry=${{ env.REGISTRY_ADDRESS }} \
52+
--registry-username=${{ env.REGISTRY_USERNAME }} \
53+
--registry-password=env://REGISTRY_PASSWORD \
5154
--image-tags='${{ env.IMAGE_TAGS}}' \
52-
--github-token=env:GITHUB_TOKEN \
55+
--github-token=env://GITHUB_TOKEN \
5356
--actions-id-token-request-url=$ACTIONS_ID_TOKEN_REQUEST_URL \
54-
--actions-id-token-request-token=env:ACTIONS_ID_TOKEN_REQUEST_TOKEN"
57+
--actions-id-token-request-token=env://ACTIONS_ID_TOKEN_REQUEST_TOKEN"

.github/workflows/default.yaml

Lines changed: 45 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -168,47 +168,47 @@ jobs:
168168
env:
169169
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
170170

171-
# - name: Build Binary
172-
# uses: dagger/dagger-for-github@v7
173-
# with:
174-
# version: ${{ steps.dagger_version.outputs.version }}
175-
# verb: call
176-
# args: build-dev --platform linux/amd64 export --path=./harbor-dev
171+
- name: Build Binary
172+
uses: dagger/dagger-for-github@v7
173+
with:
174+
version: ${{ steps.dagger_version.outputs.version }}
175+
verb: call
176+
args: build-dev --source=. --platform linux/amd64 export --path=./harbor-dev
177177

178-
# push-latest-images:
179-
# needs:
180-
# - lint
181-
# - test-code
182-
# permissions:
183-
# contents: read
184-
# id-token: write
185-
# runs-on: ubuntu-latest
186-
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
187-
# steps:
188-
# - name: Print GitHub ref for debugging
189-
# run: |
190-
# echo "GitHub ref: $GITHUB_REF"
191-
#
192-
# - name: Checkout repo
193-
# if: github.event_name == 'push' && (github.ref == 'refs/heads/main')
194-
# uses: actions/checkout@v4
195-
# with:
196-
# fetch-depth: 0
197-
#
198-
# - name: Publish and Sign Snapshot Image
199-
# if: github.event_name == 'push' && (github.ref == 'refs/heads/main')
200-
# uses: ./.github/actions/publish-and-sign
201-
# with:
202-
# IMAGE_TAGS: latest
203-
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
204-
# REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
205-
# REGISTRY_ADDRESS: ${{ vars.REGISTRY_ADDRESS }}
206-
# REGISTRY_USERNAME: ${{ vars.REGISTRY_USERNAME }}
178+
push-latest-images:
179+
needs:
180+
- lint
181+
- test-code
182+
permissions:
183+
contents: read
184+
id-token: write
185+
runs-on: ubuntu-latest
186+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
187+
steps:
188+
- name: Print GitHub ref for debugging
189+
run: |
190+
echo "GitHub ref: $GITHUB_REF"
191+
192+
- name: Checkout repo
193+
if: github.event_name == 'push' && (github.ref == 'refs/heads/main')
194+
uses: actions/checkout@v4
195+
with:
196+
fetch-depth: 0
197+
198+
- name: Publish and Sign Snapshot Image
199+
if: github.event_name == 'push' && (github.ref == 'refs/heads/main')
200+
uses: ./.github/actions/publish-and-sign
201+
with:
202+
IMAGE_TAGS: latest
203+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
204+
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
205+
REGISTRY_ADDRESS: ${{ vars.REGISTRY_ADDRESS }}
206+
REGISTRY_USERNAME: ${{ vars.REGISTRY_USERNAME }}
207207

208208
publish-release:
209209
needs:
210210
- lint
211-
# - test-code
211+
- test-code
212212
permissions:
213213
contents: write
214214
packages: write
@@ -228,16 +228,6 @@ jobs:
228228
with:
229229
fetch-depth: 0
230230

231-
# - name: Push images
232-
# if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/'))
233-
# uses: ./.github/actions/publish-and-sign
234-
# with:
235-
# IMAGE_TAGS: latest, ${{ github.ref_name }}
236-
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
237-
# REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
238-
# REGISTRY_ADDRESS: ${{ vars.REGISTRY_ADDRESS }}
239-
# REGISTRY_USERNAME: ${{ vars.REGISTRY_USERNAME }}
240-
241231
- name: Create Release
242232
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/'))
243233
uses: dagger/dagger-for-github@v7
@@ -248,12 +238,12 @@ jobs:
248238
verb: call
249239
args: "pipeline --source=. --github-token=env://GITHUB_TOKEN"
250240

251-
# - name: Publish and Sign Tagged Image
252-
# if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/'))
253-
# uses: ./.github/actions/publish-and-sign
254-
# with:
255-
# IMAGE_TAGS: "latest, ${{ github.ref_name }}"
256-
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
257-
# REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
258-
# REGISTRY_ADDRESS: ${{ vars.REGISTRY_ADDRESS }}
259-
# REGISTRY_USERNAME: ${{ vars.REGISTRY_USERNAME }}
241+
- name: Publish and Sign Tagged Image
242+
if: github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/'))
243+
uses: ./.github/actions/publish-and-sign
244+
with:
245+
IMAGE_TAGS: "latest, ${{ github.ref_name }}"
246+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
247+
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
248+
REGISTRY_ADDRESS: ${{ vars.REGISTRY_ADDRESS }}
249+
REGISTRY_USERNAME: ${{ vars.REGISTRY_USERNAME }}

0 commit comments

Comments
 (0)