chore: Improve workflow generation for container image projects (#674)
Co-authored-by: okozachenko1203 <okozachenko1203@users.noreply.github.com>
diff --git a/internal/pkg/image_repositories/build_workflow.go b/internal/pkg/image_repositories/build_workflow.go
index 5b81286..e66347b 100644
--- a/internal/pkg/image_repositories/build_workflow.go
+++ b/internal/pkg/image_repositories/build_workflow.go
@@ -1,6 +1,7 @@
package image_repositories
import (
+ "context"
"fmt"
"strings"
)
@@ -101,8 +102,9 @@
return strings.Join(args.ToBuildArgs(), "\n")
}
-func NewBuildWorkflow(project string) *GithubWorkflow {
+func NewBuildWorkflow(ctx context.Context, ir *ImageRepository) *GithubWorkflow {
extras := ""
+ project := ir.Project
if val, ok := EXTRAS[project]; ok {
extras = fmt.Sprintf("[%s]", val)
}
@@ -132,9 +134,19 @@
gitRepo = fmt.Sprintf("https://github.com/vexxhost/%s", project)
}
+ builderImageTag, err := getImageTag(ctx, ir.githubClient, "docker-openstack-builder", "openstack-builder-focal")
+ if err != nil {
+ builderImageTag = "latest"
+ }
+
+ runtimeImageTag, err := getImageTag(ctx, ir.githubClient, "docker-openstack-runtime", "openstack-runtime-focal")
+ if err != nil {
+ runtimeImageTag = "latest"
+ }
+
imageBuildArgs := ImageBuildArgs{
- BuilderImage: "quay.io/vexxhost/openstack-builder-${{ matrix.from }}",
- RuntimeImage: "quay.io/vexxhost/openstack-runtime-${{ matrix.from }}",
+ BuilderImage: fmt.Sprintf("quay.io/vexxhost/openstack-builder-${{ matrix.from }}:%s", builderImageTag),
+ RuntimeImage: fmt.Sprintf("quay.io/vexxhost/openstack-runtime-${{ matrix.from }}:%s", runtimeImageTag),
Release: "${{ matrix.release }}",
Project: project,
ProjectRepo: gitRepo,
@@ -144,6 +156,10 @@
DistPackages: distPackages,
PipPackages: pipPackages,
}
+ imageVerifyCmds := []string{
+ fmt.Sprintf("cosign verify --certificate-oidc-issuer=https://token.actions.githubusercontent.com --certificate-identity=https://github.com/vexxhost/docker-openstack-builder/.github/workflows/build.yml@refs/heads/main quay.io/vexxhost/openstack-builder-${{ matrix.from }}:%s", builderImageTag),
+ fmt.Sprintf("cosign verify --certificate-oidc-issuer=https://token.actions.githubusercontent.com --certificate-identity=https://github.com/vexxhost/docker-openstack-runtime/.github/workflows/build.yml@refs/heads/main quay.io/vexxhost/openstack-runtime-${{ matrix.from }}:%s", runtimeImageTag),
+ }
releases := []string{"wallaby", "xena", "yoga", "zed", "2023.1"}
if project == "keystone" {
@@ -170,6 +186,12 @@
Jobs: map[string]GithubWorkflowJob{
"image": {
RunsOn: "ubuntu-latest",
+ Permissions: map[string]string{
+ "actions": "read",
+ "contents": "read",
+ "id-token": "write",
+ "security-events": "write",
+ },
Strategy: GithubWorkflowStrategy{
Matrix: map[string]interface{}{
"from": []string{"focal", "jammy"},
@@ -222,16 +244,62 @@
},
},
{
+ Name: "Install cosign",
+ Uses: "sigstore/cosign-installer@main",
+ },
+ {
+ Name: "Verify images",
+ Run: strings.Join(imageVerifyCmds, "\n"),
+ },
+ {
Name: "Build image",
Uses: "docker/build-push-action@v3",
+ Environment: map[string]string{
+ "DOCKER_CONTENT_TRUST": "1",
+ },
+ With: map[string]string{
+ "context": ".",
+ "cache-from": "type=gha,scope=${{ matrix.from }}-${{ matrix.release }}",
+ "cache-to": "type=gha,mode=max,scope=${{ matrix.from }}-${{ matrix.release }}",
+ "load": "true",
+ "build-args": imageBuildArgs.ToBuildArgsString(),
+ "tags": fmt.Sprintf("quay.io/vexxhost/%s:${{ env.PROJECT_REF }}-${{ matrix.from }}-${{ github.sha }}", project),
+ },
+ },
+ {
+ Name: "Scan image for vulnerabilities",
+ Uses: "aquasecurity/trivy-action@master",
+ With: map[string]string{
+ "image-ref": fmt.Sprintf("quay.io/vexxhost/%s:${{ env.PROJECT_REF }}-${{ matrix.from }}-${{ github.sha }}", project),
+ "format": "sarif",
+ "output": "trivy-results.sarif",
+ "ignore-unfixed": "true",
+ },
+ },
+ {
+ Name: "Upload scan result",
+ Uses: "github/codeql-action/upload-sarif@v2",
+ If: "always()",
+ With: map[string]string{
+ "category": "${{ env.PROJECT_REF }}-${{ matrix.from }}",
+ "sarif_file": "trivy-results.sarif",
+ },
+ },
+ {
+ Name: "Build image",
+ Uses: "docker/build-push-action@v3",
+ Environment: map[string]string{
+ "DOCKER_CONTENT_TRUST": "1",
+ },
With: map[string]string{
"context": ".",
"cache-from": "type=gha,scope=${{ matrix.from }}-${{ matrix.release }}",
"cache-to": "type=gha,mode=max,scope=${{ matrix.from }}-${{ matrix.release }}",
"platforms": platforms,
+ "sbom": "true",
"push": "${{ github.event_name == 'push' }}",
"build-args": imageBuildArgs.ToBuildArgsString(),
- "tags": fmt.Sprintf("quay.io/vexxhost/%s:${{ env.PROJECT_REF }}-${{ matrix.from }}", project),
+ "tags": fmt.Sprintf("quay.io/vexxhost/%s:${{ env.PROJECT_REF }}-${{ matrix.from }}-${{ github.sha }}", project),
},
},
{
@@ -239,10 +307,15 @@
Uses: "akhilerm/tag-push-action@v2.0.0",
If: `github.event_name == 'push' && ((matrix.from == 'focal') || (matrix.from == 'jammy' && matrix.release != 'yoga'))`,
With: map[string]string{
- "src": fmt.Sprintf("quay.io/vexxhost/%s:${{ env.PROJECT_REF }}-${{ matrix.from }}", project),
+ "src": fmt.Sprintf("quay.io/vexxhost/%s:${{ env.PROJECT_REF }}-${{ matrix.from }}-${{ github.sha }}", project),
"dst": fmt.Sprintf("quay.io/vexxhost/%s:${{ matrix.release }}", project),
},
},
+ {
+ Name: "Sign the container image",
+ If: "${{ github.event_name == 'push' }}",
+ Run: "cosign sign --yes quay.io/vexxhost/horizon@${{ steps.push-step.outputs.digest }}",
+ },
},
},
},
diff --git a/internal/pkg/image_repositories/dockerfile.go b/internal/pkg/image_repositories/dockerfile.go
index 4fed1af..f4c09cc 100644
--- a/internal/pkg/image_repositories/dockerfile.go
+++ b/internal/pkg/image_repositories/dockerfile.go
@@ -21,10 +21,6 @@
BindepImage string
BindepImageTag string
- BuilderImage string
- BuilderImageTag string
- RuntimeImage string
- RuntimeImageTag string
template *template.Template
}
@@ -35,25 +31,11 @@
return nil, err
}
- builderImageTag, err := getImageTag(ctx, ir.githubClient, "docker-openstack-builder", "openstack-builder-focal")
- if err != nil {
- return nil, err
- }
-
- runtimeImageTag, err := getImageTag(ctx, ir.githubClient, "docker-openstack-runtime", "openstack-runtime-focal")
- if err != nil {
- return nil, err
- }
-
return &Dockerfile{
Project: ir.Project,
BindepImage: "quay.io/vexxhost/bindep-loci",
BindepImageTag: "latest",
- BuilderImage: "quay.io/vexxhost/openstack-builder-focal",
- BuilderImageTag: builderImageTag,
- RuntimeImage: "quay.io/vexxhost/openstack-runtime-focal",
- RuntimeImageTag: runtimeImageTag,
template: tmpl,
}, nil
diff --git a/internal/pkg/image_repositories/github_workflow.go b/internal/pkg/image_repositories/github_workflow.go
index 2b1fefd..59aa047 100644
--- a/internal/pkg/image_repositories/github_workflow.go
+++ b/internal/pkg/image_repositories/github_workflow.go
@@ -50,9 +50,10 @@
}
type GithubWorkflowJob struct {
- RunsOn string `yaml:"runs-on"`
- Strategy GithubWorkflowStrategy `yaml:"strategy,omitempty"`
- Steps []GithubWorkflowStep `yaml:"steps"`
+ Permissions map[string]string `yaml:"permissions,omitempty"`
+ RunsOn string `yaml:"runs-on"`
+ Strategy GithubWorkflowStrategy `yaml:"strategy,omitempty"`
+ Steps []GithubWorkflowStep `yaml:"steps"`
}
func (j GithubWorkflowJob) DeepCopy() GithubWorkflowJob {
diff --git a/internal/pkg/image_repositories/image_repository.go b/internal/pkg/image_repositories/image_repository.go
index 0d2f369..d45a759 100644
--- a/internal/pkg/image_repositories/image_repository.go
+++ b/internal/pkg/image_repositories/image_repository.go
@@ -51,7 +51,7 @@
func (i *ImageRepository) WriteFiles(ctx context.Context, fs billy.Filesystem) error {
// .github/workflows/build.yml
- build := NewBuildWorkflow(i.Project)
+ build := NewBuildWorkflow(ctx, i)
err := build.WriteFile(fs)
if err != nil {
return err
diff --git a/internal/pkg/image_repositories/template/Dockerfile b/internal/pkg/image_repositories/template/Dockerfile
index 98edce3..830a633 100644
--- a/internal/pkg/image_repositories/template/Dockerfile
+++ b/internal/pkg/image_repositories/template/Dockerfile
@@ -1,14 +1,14 @@
# syntax=docker/dockerfile-upstream:master-labs
-ARG BUILDER_IMAGE={{ .BuilderImage }}
-ARG RUNTIME_IMAGE={{ .RuntimeImage }}
+ARG BUILDER_IMAGE
+ARG RUNTIME_IMAGE
FROM {{ .BindepImage }}:{{ .BindepImageTag }} AS bindep
-FROM ${BUILDER_IMAGE}:{{ .BuilderImageTag }} AS builder
+FROM ${BUILDER_IMAGE} AS builder
COPY --from=bindep --link /runtime-pip-packages /runtime-pip-packages
-FROM ${RUNTIME_IMAGE}:{{ .RuntimeImageTag }} AS runtime
+FROM ${RUNTIME_IMAGE} AS runtime
COPY --from=bindep --link /runtime-dist-packages /runtime-dist-packages
COPY --from=builder --link /var/lib/openstack /var/lib/openstack