From 3077dd4f275742c787f8adb58d20e9ee9cfa33c7 Mon Sep 17 00:00:00 2001 From: Malte Poll Date: Mon, 2 Jan 2023 12:25:17 +0100 Subject: [PATCH] ci: implement first half of release checklist --- .github/actions/setup_crane/action.yaml | 17 ++ .../workflows/build-micro-service-manual.yml | 39 +++- .github/workflows/build-operator-manual.yml | 31 +++- .github/workflows/build-os-image.yml | 33 +++- .github/workflows/generate-measurements.yml | 34 +++- .github/workflows/release.yml | 174 ++++++++++++++++++ 6 files changed, 309 insertions(+), 19 deletions(-) create mode 100644 .github/actions/setup_crane/action.yaml create mode 100644 .github/workflows/release.yml diff --git a/.github/actions/setup_crane/action.yaml b/.github/actions/setup_crane/action.yaml new file mode 100644 index 000000000..ff512ecd0 --- /dev/null +++ b/.github/actions/setup_crane/action.yaml @@ -0,0 +1,17 @@ +name: Setup crane +description: "Install crane (go-containerregistry)." +runs: + using: composite + steps: + - name: Install + shell: bash + env: + VERSION: "0.12.1" + OS: ${{ runner.os == 'Linux' && 'Linux' || 'Darwin' }} + ARCH: ${{ runner.arch == 'X64' && 'x86_64' || runner.arch == 'ARM64' && 'arm64' }} + run: | + echo "::group::Install crane" + curl -fsSL "https://github.com/google/go-containerregistry/releases/download/v${VERSION}/go-containerregistry_${OS}_${ARCH}.tar.gz" > go-containerregistry.tar.gz + tar -xzf go-containerregistry.tar.gz + sudo mv krane gcrane crane /usr/local/bin/ + echo "::endgroup::" diff --git a/.github/workflows/build-micro-service-manual.yml b/.github/workflows/build-micro-service-manual.yml index 90e2a5b55..dab5e130c 100644 --- a/.github/workflows/build-micro-service-manual.yml +++ b/.github/workflows/build-micro-service-manual.yml @@ -23,6 +23,37 @@ on: description: "Version of the image to build" required: true default: "0.0.0" + ref: + type: string + description: "Git ref to checkout" + required: false + release: + type: boolean + description: "Is this a release build?" + required: false + default: false + workflow_call: + inputs: + microService: + description: "Name of the micro-service image to build" + type: string + required: true + imageTag: + type: string + description: "Container image tag" + required: true + version: + type: string + description: "Version of the image to build" + required: true + ref: + type: string + description: "Git ref to checkout" + required: false + release: + type: boolean + description: "Is this a release build?" + required: true jobs: build-micro-service: @@ -35,7 +66,7 @@ jobs: id: checkout uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 with: - ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || '' }} + ref: ${{ inputs.ref || github.head_ref }} - name: Setup Go environment uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 @@ -70,6 +101,6 @@ jobs: dockerfile: ${{ env.microServiceDockerfile }} pushTag: ${{ inputs.imageTag }} githubToken: ${{ secrets.GITHUB_TOKEN }} - cosignPublicKey: ${{ startsWith(github.ref, 'refs/heads/release/v') && secrets.COSIGN_PUBLIC_KEY || secrets.COSIGN_DEV_PUBLIC_KEY }} - cosignPrivateKey: ${{ startsWith(github.ref, 'refs/heads/release/v') && secrets.COSIGN_PRIVATE_KEY || secrets.COSIGN_DEV_PRIVATE_KEY }} - cosignPassword: ${{ startsWith(github.ref, 'refs/heads/release/v') && secrets.COSIGN_PASSWORD || secrets.COSIGN_DEV_PASSWORD }} + cosignPublicKey: ${{ inputs.release && secrets.COSIGN_PUBLIC_KEY || secrets.COSIGN_DEV_PUBLIC_KEY }} + cosignPrivateKey: ${{ inputs.release && secrets.COSIGN_PRIVATE_KEY || secrets.COSIGN_DEV_PRIVATE_KEY }} + cosignPassword: ${{ inputs.release && secrets.COSIGN_PASSWORD || secrets.COSIGN_DEV_PASSWORD }} diff --git a/.github/workflows/build-operator-manual.yml b/.github/workflows/build-operator-manual.yml index a7bd00c58..2b63c5b94 100644 --- a/.github/workflows/build-operator-manual.yml +++ b/.github/workflows/build-operator-manual.yml @@ -6,6 +6,29 @@ on: imageTag: description: "Container image tag." required: false + ref: + type: string + description: "Git ref to checkout" + required: false + release: + type: boolean + description: "Is this a release build?" + required: false + default: false + workflow_call: + inputs: + imageTag: + type: string + description: "Container image tag" + required: true + ref: + type: string + description: "Git ref to checkout" + required: false + release: + type: boolean + description: "Is this a release build?" + required: true jobs: build-operator-manual: @@ -18,7 +41,7 @@ jobs: id: checkout uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 with: - ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || '' }} + ref: ${{ inputs.ref || github.head_ref }} - name: Setup Go environment uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 @@ -32,6 +55,6 @@ jobs: sourceDir: operators/constellation-node-operator githubToken: ${{ secrets.GITHUB_TOKEN }} pushTag: ${{ inputs.imageTag }} - cosignPublicKey: ${{ startsWith(github.ref, 'refs/heads/release/v') && secrets.COSIGN_PUBLIC_KEY || secrets.COSIGN_DEV_PUBLIC_KEY }} - cosignPrivateKey: ${{ startsWith(github.ref, 'refs/heads/release/v') && secrets.COSIGN_PRIVATE_KEY || secrets.COSIGN_DEV_PRIVATE_KEY }} - cosignPassword: ${{ startsWith(github.ref, 'refs/heads/release/v') && secrets.COSIGN_PASSWORD || secrets.COSIGN_DEV_PASSWORD }} + cosignPublicKey: ${{ inputs.release && secrets.COSIGN_PUBLIC_KEY || secrets.COSIGN_DEV_PUBLIC_KEY }} + cosignPrivateKey: ${{ inputs.release && secrets.COSIGN_PRIVATE_KEY || secrets.COSIGN_DEV_PRIVATE_KEY }} + cosignPassword: ${{ inputs.release && secrets.COSIGN_PASSWORD || secrets.COSIGN_DEV_PASSWORD }} diff --git a/.github/workflows/build-os-image.yml b/.github/workflows/build-os-image.yml index 4314bdd33..2d8b1d834 100644 --- a/.github/workflows/build-os-image.yml +++ b/.github/workflows/build-os-image.yml @@ -20,6 +20,29 @@ on: - "debug" # TODO: implement console access enabled image # - "console" + ref: + type: string + description: "Git ref to checkout" + required: false + workflow_call: + inputs: + imageVersion: + description: "Semantic version including patch e.g. v.. (only used for releases)" + required: false + type: string + isRelease: + description: 'Is this a release? (sets "ref" to special value "-")' + type: boolean + required: false + default: false + stream: + description: "Image stream / type. (Use 'stable' for releases, 'nightly' for regular non-release images and 'debug' for debug builds)" + type: string + required: true + ref: + type: string + description: "Git ref to checkout" + required: false jobs: build-dependencies: @@ -36,7 +59,7 @@ jobs: - name: Checkout uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 with: - ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || '' }} + ref: ${{ inputs.ref || github.head_ref }} - name: Build bootstrapper if: inputs.stream != 'debug' @@ -95,7 +118,7 @@ jobs: - name: Checkout uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 with: - ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || '' }} + ref: ${{ inputs.ref || github.head_ref }} - name: Determine version id: version @@ -209,7 +232,7 @@ jobs: - name: Checkout uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 with: - ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || '' }} + ref: ${{ inputs.ref || github.head_ref }} - name: Download build dependencies uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 @@ -321,7 +344,7 @@ jobs: - name: Checkout uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 with: - ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || '' }} + ref: ${{ inputs.ref || github.head_ref }} - name: Download OS image artifact uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 @@ -508,7 +531,7 @@ jobs: - name: Checkout repository uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 with: - ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || '' }} + ref: ${{ inputs.ref || github.head_ref }} - name: Login to AWS uses: aws-actions/configure-aws-credentials@67fbcbb121271f7775d2e7715933280b06314838 # tag=v1.7.0 diff --git a/.github/workflows/generate-measurements.yml b/.github/workflows/generate-measurements.yml index fa0db97ce..7aab09bfe 100644 --- a/.github/workflows/generate-measurements.yml +++ b/.github/workflows/generate-measurements.yml @@ -15,6 +15,28 @@ on: description: "Sign and upload the measurements?" type: boolean required: true + ref: + type: string + description: "Git ref to checkout" + required: false + workflow_call: + inputs: + osImage: + description: "Full name of OS image (CSP independent image version UID)." + type: string + required: true + isDebugImage: + description: "Is OS image a debug image?" + type: boolean + required: true + signMeasurements: + description: "Sign and upload the measurements?" + type: boolean + required: true + ref: + type: string + description: "Git ref to checkout" + required: false jobs: calculate-measurements-on-csp: @@ -40,13 +62,13 @@ jobs: - name: Check out repository uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 with: - ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || '' }} + ref: ${{ inputs.ref || github.head_ref }} - name: Extract ref, stream and version id: extract uses: ./.github/actions/shortname with: - shortname: ${{ github.event.inputs.osImage }} + shortname: ${{ inputs.osImage }} - name: Check if image definition from build pipeline exists run: | @@ -97,8 +119,8 @@ jobs: azureClientSecret: ${{ secrets.AZURE_E2E_CLIENT_SECRET }} azureUserAssignedIdentity: ${{ secrets.AZURE_E2E_USER_ASSIGNED_IDENTITY }} azureResourceGroup: ${{ steps.az_resource_group_gen.outputs.res_group_name }} - osImage: ${{ github.event.inputs.osImage }} - isDebugImage: ${{ github.event.inputs.isDebugImage }} + osImage: ${{ inputs.osImage }} + isDebugImage: ${{ inputs.isDebugImage }} test: "nop" - name: Fetch PCRs from running cluster @@ -106,7 +128,7 @@ jobs: KUBECONFIG="${PWD}/constellation-admin.conf" kubectl rollout status ds/verification-service -n kube-system --timeout=3m CONSTELL_IP=$(jq -r ".ip" constellation-id.json) mkdir -p "${{ github.workspace }}/generated-measurements" - pcr-reader -constell-ip "${CONSTELL_IP}" -format json -metadata -csp "${{ matrix.provider }}" -image "${{ github.event.inputs.osImage }}" > "${{ github.workspace }}/generated-measurements/measurements.json" + pcr-reader -constell-ip "${CONSTELL_IP}" -format json -metadata -csp "${{ matrix.provider }}" -image "${{ inputs.osImage }}" > "${{ github.workspace }}/generated-measurements/measurements.json" echo "All PCRs of current boot:" cat "${{ github.workspace }}/generated-measurements/measurements.json" case ${CSP} in @@ -195,7 +217,7 @@ jobs: - name: Check out repository uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 with: - ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || '' }} + ref: ${{ inputs.ref || github.head_ref }} - name: Setup Go environment uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..d2e1be502 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,174 @@ +name: Release + +on: + workflow_dispatch: + inputs: + version: + description: "Version to release (e.g. v1.2.3)" + required: true + kind: + description: "Release kind" + type: choice + options: [minor, patch] + required: true + default: "minor" + +jobs: + verify-inputs: + name: Verify inputs + runs-on: ubuntu-22.04 + env: + FULL_VERSION: ${{ inputs.version }} + outputs: + WITHOUT_V: ${{ steps.version-info.outputs.WITHOUT_V }} + PART_MAJOR: ${{ steps.version-info.outputs.PART_MAJOR }} + PART_MINOR: ${{ steps.version-info.outputs.PART_MINOR }} + PART_PATCH: ${{ steps.version-info.outputs.PART_PATCH }} + MAJOR: ${{ steps.version-info.outputs.MAJOR }} + MAJOR_MINOR: ${{ steps.version-info.outputs.MAJOR_MINOR }} + MAJOR_MINOR_PATCH: ${{ steps.version-info.outputs.MAJOR_MINOR_PATCH }} + RELEASE_BRANCH: ${{ steps.version-info.outputs.RELEASE_BRANCH }} + steps: + - name: Verify version + run: | + if [[ ! "${FULL_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Version must be in the form of vX.Y.Z" + exit 1 + fi + - name: Extract version info + id: version-info + run: | + WITHOUT_V=${FULL_VERSION#v} + PART_MAJOR=${WITHOUT_V%%.*} + PART_MINOR=${WITHOUT_V#*.} + PART_MINOR=${PART_MINOR%%.*} + PART_PATCH=${WITHOUT_V##*.} + { + echo "WITHOUT_V=${WITHOUT_V}" + echo "PART_MAJOR=${PART_MAJOR}" + echo "PART_MINOR=${PART_MINOR}" + echo "PART_PATCH=${PART_PATCH}" + echo "MAJOR=${PART_MAJOR}" + echo "MAJOR_MINOR=${PART_MAJOR}.${PART_MINOR}" + echo "MAJOR_MINOR_PATCH=${PART_MAJOR}.${PART_MINOR}.${PART_PATCH}" + echo "RELEASE_BRANCH=release/v${PART_MAJOR}.${PART_MINOR}" + } | tee "$GITHUB_OUTPUT" + + prepare-release-branch: + name: Prepare release branch + runs-on: ubuntu-22.04 + needs: verify-inputs + env: + BRANCH: ${{ needs.verify-inputs.outputs.RELEASE_BRANCH }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + with: + ref: ${{ github.head_ref }} + - name: Create release branch + if: inputs.kind == 'minor' + run: | + git fetch + git pull + git checkout "${BRANCH}" || git checkout -B "${BRANCH}" + git push origin "${BRANCH}" + + micro-services: + needs: [verify-inputs, prepare-release-branch] + uses: ./.github/workflows/build-micro-service-manual.yml + secrets: inherit + strategy: + matrix: + service: + [join-service, kmsserver, verification-service, qemu-metadata-api] + with: + microService: ${{ matrix.service }} + imageTag: ${{ inputs.version }} + version: ${{ needs.verify-inputs.outputs.WITHOUT_V }} + ref: ${{ needs.verify-inputs.outputs.RELEASE_BRANCH }} + release: true + + constellation-node-operator: + needs: [verify-inputs, prepare-release-branch] + secrets: inherit + uses: ./.github/workflows/build-operator-manual.yml + with: + imageTag: ${{ inputs.version }} + ref: ${{ needs.verify-inputs.outputs.RELEASE_BRANCH }} + release: true + + update-versions: + needs: [verify-inputs, micro-services, constellation-node-operator] + runs-on: ubuntu-22.04 + env: + VERSION: ${{ inputs.version }} + WITHOUT_V: ${{ needs.verify-inputs.outputs.WITHOUT_V }} + steps: + - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + with: + ref: ${{ needs.verify-inputs.outputs.RELEASE_BRANCH }} + + - name: Install crane + uses: ./.github/actions/setup_crane + + - name: Update enterprise image version + run: | + sed -i "s/defaultImage = \"v[0-9]\+\.[0-9]\+\.[0-9]\+\"/defaultImage = \"${VERSION}\"/" internal/config/images_enterprise.go + git add internal/config/images_enterprise.go + + - name: Update CMakeLists.txt + run: | + sed -i "s/project(constellation LANGUAGES C VERSION [0-9]\+\.[0-9]\+\.[0-9]\+)/project(constellation LANGUAGES C VERSION ${WITHOUT_V})/" CMakeLists.txt + git add CMakeLists.txt + + - name: Update Helm Charts + run: | + yq eval -i ".version = \"${WITHOUT_V}\"" cli/internal/helm/charts/edgeless/constellation-services/Chart.yaml + for service in kms join-service ccm cnm autoscaler verification-service konnectivity gcp-guest-agent; do + yq eval -i "(.dependencies[] | select(.name == \"${service}\")).version = \"${WITHOUT_V}\"" cli/internal/helm/charts/edgeless/constellation-services/Chart.yaml + yq eval -i ".version = \"${WITHOUT_V}\"" "cli/internal/helm/charts/edgeless/constellation-services/charts/${service}/Chart.yaml" + git add "cli/internal/helm/charts/edgeless/constellation-services/charts/${service}/Chart.yaml" + done + git add cli/internal/helm/charts/edgeless/constellation-services/Chart.yaml + yq eval -i ".version = \"${WITHOUT_V}\"" cli/internal/helm/charts/edgeless/operators/Chart.yaml + for service in node-maintenance-operator constellation-operator; do + yq eval -i "(.dependencies[] | select(.name == \"${service}\")).version = \"${WITHOUT_V}\"" cli/internal/helm/charts/edgeless/operators/Chart.yaml + yq eval -i ".version = \"${WITHOUT_V}\"" "cli/internal/helm/charts/edgeless/operators/charts/${service}/Chart.yaml" + git add "cli/internal/helm/charts/edgeless/operators/charts/${service}/Chart.yaml" + done + git add cli/internal/helm/charts/edgeless/operators/Chart.yaml + + - name: Update micro service versions + run: | + for service in node-operator join-service kmsserver verification-service qemu-metadata-api; do + name=ghcr.io/edgelesssys/constellation/${service} + digest=$(crane digest "${name}:${VERSION}") + sed -i "s#\"${name}:v[0-9]\+\.[0-9]\+\.[0-9]\+[^@]*@sha256:[0-9a-f]\+\"#\"${name}:${VERSION}@${digest}\"#" internal/versions/versions.go + done + git add internal/versions/versions.go + + - name: Commit + run: | + git config --global user.name "release[bot]" + git config --global user.email "release[bot]@users.noreply.github.com" + git commit -m "deps: update version to ${VERSION}" + git push + + os-image: + needs: [verify-inputs, update-versions] + uses: ./.github/workflows/build-os-image.yml + secrets: inherit + with: + imageVersion: ${{ inputs.version }} + isRelease: true + stream: "stable" + ref: ${{ needs.verify-inputs.outputs.RELEASE_BRANCH }} + + generate-measurements: + needs: [verify-inputs, os-image] + uses: ./.github/workflows/generate-measurements.yml + secrets: inherit + with: + osImage: ${{ inputs.version }} + isDebugImage: false + signMeasurements: true + ref: ${{ needs.verify-inputs.outputs.RELEASE_BRANCH }}