summaryrefslogtreecommitdiff
path: root/.github/workflows/promote-acr.yml
blob: 6b00e3bc615a80022fccb32ce71d3dac75b20a70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
---
name: Promote image to ACR

on:
  workflow_dispatch:
    inputs:
      source_tag:
        description: "Existing GHCR tag to promote"
        required: true
        type: string
      target_tags:
        description: "Space-separated ACR tags to publish; defaults to source_tag"
        required: false
        type: string
      image_name:
        description: "Image name override; defaults to IMAGE_NAME var, then image-template.env"
        required: false
        type: string

env:
  IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}"

concurrency:
  group: ${{ github.workflow }}-${{ inputs.image_name || 'default' }}-${{ inputs.source_tag }}
  cancel-in-progress: false

jobs:
  promote_acr:
    name: Promote GHCR image to ACR
    runs-on: ubuntu-24.04

    permissions:
      contents: read
      packages: read

    steps:
      - name: Checkout
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7

      - name: Install just
        uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 #v4.0.0

      - name: Install skopeo
        run: |
          sudo apt-get update
          sudo apt-get install -y skopeo

      - name: Prepare image variables
        env:
          IMAGE_NAME_INPUT: ${{ inputs.image_name }}
          IMAGE_NAME_VAR: ${{ vars.IMAGE_NAME }}
          SOURCE_TAG: ${{ inputs.source_tag }}
          TARGET_TAGS_INPUT: ${{ inputs.target_tags }}
        run: |
          set -euo pipefail

          image_name="${IMAGE_NAME_INPUT:-${IMAGE_NAME_VAR:-$(just image_name)}}"
          target_tags="${TARGET_TAGS_INPUT:-$SOURCE_TAG}"

          {
            echo "IMAGE_REGISTRY=${IMAGE_REGISTRY,,}"
            echo "IMAGE_NAME=${image_name,,}"
            echo "SOURCE_TAG=${SOURCE_TAG}"
            echo "TARGET_TAGS=${target_tags}"
          } >> "$GITHUB_ENV"

      - name: Validate ACR configuration
        env:
          ACR_REGISTRY: ${{ vars.ACR_REGISTRY }}
          ACR_NAMESPACE: ${{ vars.ACR_NAMESPACE }}
          ACR_USERNAME: ${{ secrets.ACR_USERNAME }}
          ACR_PASSWORD: ${{ secrets.ACR_PASSWORD }}
          COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
          COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
        run: |
          set -euo pipefail

          : "${ACR_REGISTRY:?Repository variable ACR_REGISTRY is required.}"
          : "${ACR_NAMESPACE:?Repository variable ACR_NAMESPACE is required.}"
          : "${ACR_USERNAME:?Repository secret ACR_USERNAME is required.}"
          : "${ACR_PASSWORD:?Repository secret ACR_PASSWORD is required.}"
          : "${COSIGN_PRIVATE_KEY:?Repository secret SIGNING_SECRET is required.}"
          : "${COSIGN_PASSWORD:?Repository secret COSIGN_PASSWORD is required.}"

      - name: Login to GitHub Container Registry
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          set -euo pipefail
          echo "$GITHUB_TOKEN" | sudo -E podman login ghcr.io -u "${{ github.actor }}" --password-stdin

      - name: Login to ACR
        env:
          ACR_REGISTRY: ${{ vars.ACR_REGISTRY }}
          ACR_USERNAME: ${{ secrets.ACR_USERNAME }}
          ACR_PASSWORD: ${{ secrets.ACR_PASSWORD }}
        run: |
          set -euo pipefail
          echo "$ACR_PASSWORD" | sudo -E podman login "$ACR_REGISTRY" -u "$ACR_USERNAME" --password-stdin
          echo "$ACR_PASSWORD" | docker login "$ACR_REGISTRY" -u "$ACR_USERNAME" --password-stdin

      - name: Promote image
        id: promote
        env:
          ACR_REGISTRY: ${{ vars.ACR_REGISTRY }}
          ACR_NAMESPACE: ${{ vars.ACR_NAMESPACE }}
        run: |
          set -euo pipefail

          source_image="docker://${IMAGE_REGISTRY}/${IMAGE_NAME}:${SOURCE_TAG}"
          first_target=""

          {
            echo "# Promote to ACR result"
            echo '```'
          } >> "$GITHUB_STEP_SUMMARY"

          for tag in ${TARGET_TAGS}; do
            dest_image="${ACR_REGISTRY}/${ACR_NAMESPACE}/${IMAGE_NAME}:${tag}"
            sudo -E skopeo copy "$source_image" "docker://$dest_image"
            echo "$dest_image" >> "$GITHUB_STEP_SUMMARY"
            if [ -z "$first_target" ]; then
              first_target="$dest_image"
            fi
          done

          echo '```' >> "$GITHUB_STEP_SUMMARY"

          digest=$(sudo -E skopeo inspect --format '{{.Digest}}' "docker://$first_target")
          if [ -z "$digest" ]; then
            echo "Failed to resolve digest for $first_target" >&2
            exit 1
          fi

          echo "digest=${digest}" >> "$GITHUB_OUTPUT"

      - name: Install Cosign
        uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
        with:
          cosign-release: 'v2.6.3'

      - name: Sign ACR image
        env:
          ACR_REGISTRY: ${{ vars.ACR_REGISTRY }}
          ACR_NAMESPACE: ${{ vars.ACR_NAMESPACE }}
          COSIGN_EXPERIMENTAL: false
          COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
          COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
          DIGEST: ${{ steps.promote.outputs.digest }}
        run: |
          set -euo pipefail

          cosign sign -y --key env://COSIGN_PRIVATE_KEY "${ACR_REGISTRY}/${ACR_NAMESPACE}/${IMAGE_NAME}@${DIGEST}"