|
4 | 4 | schedule: |
5 | 5 | - cron: '31 16 * * 1' |
6 | 6 | workflow_dispatch: |
| 7 | + push: |
| 8 | + branches: [main] |
| 9 | + paths: |
| 10 | + - 'Dockerfile' |
| 11 | + - '.github/workflows/docker-publish.yml' |
| 12 | + pull_request: |
| 13 | + branches: [main] |
| 14 | + paths: |
| 15 | + - 'Dockerfile' |
| 16 | + - '.github/workflows/docker-publish.yml' |
7 | 17 |
|
8 | | -jobs: |
9 | | - Alpine: |
| 18 | +concurrency: |
| 19 | + group: ${{ github.workflow }}-${{ github.ref }} |
| 20 | + cancel-in-progress: true |
10 | 21 |
|
| 22 | +jobs: |
| 23 | + build: |
11 | 24 | runs-on: ubuntu-latest |
| 25 | + strategy: |
| 26 | + matrix: |
| 27 | + distro: [alpine, debian] |
| 28 | + include: |
| 29 | + - distro: alpine |
| 30 | + is_latest: true |
| 31 | + distro_version: 'latest' |
| 32 | + - distro: debian |
| 33 | + is_latest: false |
| 34 | + debian_version: 'stable-slim' |
12 | 35 | permissions: |
13 | | - contents: write |
| 36 | + contents: read |
14 | 37 | packages: write |
15 | 38 | security-events: write |
16 | | - |
| 39 | + id-token: write # For OIDC auth |
| 40 | + |
17 | 41 | steps: |
18 | | - - |
19 | | - name: Docker Setup QEMU |
20 | | - uses: docker/setup-qemu-action@v4 |
21 | | - id: qemu |
22 | | - with: |
23 | | - platforms: amd64,arm64,arm |
24 | | - - |
25 | | - name: Docker Setup Buildx |
26 | | - id: buildx |
27 | | - uses: docker/setup-buildx-action@v4 |
28 | | - - |
29 | | - name: Login to DockerHub |
30 | | - uses: docker/login-action@v4 |
31 | | - with: |
32 | | - username: ${{ secrets.DOCKERHUB_USERNAME }} |
33 | | - password: ${{ secrets.DOCKERHUB_TOKEN }} |
34 | | - - |
35 | | - name: Log into ghcr.io registry |
36 | | - uses: docker/login-action@v4 |
37 | | - with: |
38 | | - registry: ghcr.io |
39 | | - username: ${{ github.repository_owner }} |
40 | | - password: ${{ secrets.GITHUB_TOKEN }} |
41 | | - - |
42 | | - name: Login to Quay.io |
43 | | - uses: docker/login-action@v4 |
44 | | - with: |
45 | | - registry: quay.io |
46 | | - username: ${{ secrets.QUAY_USERNAME }} |
47 | | - password: ${{ secrets.QUAY_ROBOT_TOKEN }} |
48 | | - - |
49 | | - name: Build and test docker image |
50 | | - uses: docker/build-push-action@v7 |
51 | | - with: |
52 | | - # context: . |
53 | | - file: ./Dockerfile.alpine |
54 | | - load: true |
55 | | - tags: docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:alpine-test |
56 | | - cache-from: type=gha |
57 | | - cache-to: type=gha,mode=max |
58 | | - - |
59 | | - name: Test |
60 | | - run: | |
61 | | - docker run --rm docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:alpine-test doxygen --help |
62 | | - - |
63 | | - name: Retrieve doxygen version |
64 | | - run: | |
65 | | - echo "doxygen_version=$(docker run --rm docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:alpine-test doxygen -v)" >> $GITHUB_OUTPUT |
66 | | - id: version |
67 | | - # ${{ steps.version.outputs.doxygen_version }} |
68 | | - - |
69 | | - name: Run Trivy vulnerability scanner |
70 | | - uses: aquasecurity/trivy-action@master |
71 | | - with: |
72 | | - scan-type: image |
73 | | - image-ref: docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:alpine-test |
74 | | - format: 'sarif' |
75 | | - output: 'trivy-results-alpine.sarif' |
76 | | - severity: 'MEDIUM,CRITICAL,HIGH' |
77 | | - hide-progress: false |
78 | | - - |
79 | | - name: Upload Trivy scan results to GitHub Security tab |
80 | | - uses: github/codeql-action/upload-sarif@v4 |
81 | | - with: |
82 | | - sarif_file: 'trivy-results-alpine.sarif' |
83 | | - - |
84 | | - name: Build and push Docker image |
85 | | - uses: docker/build-push-action@v7 |
86 | | - with: |
87 | | - # context: . |
88 | | - file: ./Dockerfile.alpine |
89 | | - platforms: linux/amd64,linux/arm64,linux/arm/v7 |
90 | | - push: true |
91 | | - cache-from: type=gha |
92 | | - cache-to: type=gha,mode=max |
93 | | - tags: | |
94 | | - ghcr.io/kingpin/${{ github.event.repository.name }}:latest |
95 | | - ghcr.io/kingpin/${{ github.event.repository.name }}:alpine |
96 | | - ghcr.io/kingpin/${{ github.event.repository.name }}:alpine-${{ steps.version.outputs.doxygen_version }} |
97 | | - docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:latest |
98 | | - docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:alpine |
99 | | - docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:alpine-${{ steps.version.outputs.doxygen_version }} |
100 | | - quay.io/kingpinx1/${{ github.event.repository.name }}:latest |
101 | | - quay.io/kingpinx1/${{ github.event.repository.name }}:alpine |
102 | | - quay.io/kingpinx1/${{ github.event.repository.name }}:alpine-${{ steps.version.outputs.doxygen_version }} |
103 | | - Debian: |
| 42 | + - name: Checkout code |
| 43 | + uses: actions/checkout@v4 |
104 | 44 |
|
105 | | - runs-on: ubuntu-latest |
106 | | - permissions: |
107 | | - contents: write |
108 | | - packages: write |
109 | | - security-events: write |
| 45 | + - name: Validate entrypoint syntax |
| 46 | + run: sh -n entrypoint.sh |
110 | 47 |
|
111 | | - steps: |
112 | | - - |
113 | | - name: Docker Setup QEMU |
| 48 | + - name: Set up Docker Buildx |
| 49 | + uses: docker/setup-buildx-action@v4 |
| 50 | + |
| 51 | + - name: Set up QEMU |
114 | 52 | uses: docker/setup-qemu-action@v4 |
115 | | - id: qemu |
116 | 53 | with: |
117 | | - platforms: amd64,arm64,arm |
118 | | - - |
119 | | - name: Docker Setup Buildx |
120 | | - id: buildx |
121 | | - uses: docker/setup-buildx-action@v4 |
122 | | - - |
123 | | - name: Login to DockerHub |
124 | | - uses: docker/login-action@v4 |
| 54 | + platforms: linux/amd64,linux/arm64,linux/arm/v7 |
| 55 | + |
| 56 | + # Login to Docker Hub |
| 57 | + - name: Login to Docker Hub |
| 58 | + if: github.event_name != 'pull_request' |
| 59 | + uses: docker/login-action@v4 |
125 | 60 | with: |
126 | 61 | username: ${{ secrets.DOCKERHUB_USERNAME }} |
127 | 62 | password: ${{ secrets.DOCKERHUB_TOKEN }} |
128 | | - - |
129 | | - name: Log into ghcr.io registry |
| 63 | + |
| 64 | + # Login to GitHub Container Registry |
| 65 | + - name: Login to GitHub Container Registry |
130 | 66 | uses: docker/login-action@v4 |
131 | 67 | with: |
132 | 68 | registry: ghcr.io |
133 | 69 | username: ${{ github.repository_owner }} |
134 | 70 | password: ${{ secrets.GITHUB_TOKEN }} |
135 | | - - |
136 | | - name: Login to Quay.io |
| 71 | + |
| 72 | + # Login to Quay.io |
| 73 | + - name: Login to Quay.io |
| 74 | + if: github.event_name != 'pull_request' |
137 | 75 | uses: docker/login-action@v4 |
138 | 76 | with: |
139 | 77 | registry: quay.io |
140 | 78 | username: ${{ secrets.QUAY_USERNAME }} |
141 | 79 | password: ${{ secrets.QUAY_ROBOT_TOKEN }} |
142 | | - - |
143 | | - name: Build and test docker image |
| 80 | + |
| 81 | + # Generate Dockerfile hash |
| 82 | + - name: Generate Dockerfile hash |
| 83 | + id: hash |
| 84 | + run: | |
| 85 | + echo "hash=$(sha256sum Dockerfile | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT |
| 86 | + |
| 87 | + # Build test image |
| 88 | + - name: Build test image |
144 | 89 | uses: docker/build-push-action@v7 |
145 | 90 | with: |
146 | | - # context: . |
147 | | - file: ./Dockerfile.debian |
| 91 | + context: . |
| 92 | + file: ./Dockerfile |
| 93 | + build-args: | |
| 94 | + DISTRO=${{ matrix.distro }} |
| 95 | + ${{ matrix.distro == 'alpine' && format('DISTRO_VERSION={0}', matrix.distro_version) || format('DEBIAN_VERSION={0}', matrix.debian_version) }} |
148 | 96 | load: true |
149 | | - tags: docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:debian-test |
150 | | - cache-from: type=gha |
151 | | - cache-to: type=gha,mode=max |
152 | | - - |
153 | | - name: Test |
154 | | - run: | |
155 | | - docker run --rm docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:debian-test doxygen --help |
156 | | - - |
157 | | - name: Retrieve doxygen version |
| 97 | + tags: doxygen-test:${{ matrix.distro }} |
| 98 | + cache-from: | |
| 99 | + type=gha,scope=${{ matrix.distro }}-${{ steps.hash.outputs.hash }} |
| 100 | + type=registry,ref=ghcr.io/kingpin/${{ github.event.repository.name }}:${{ matrix.distro }}-cache |
| 101 | + cache-to: | |
| 102 | + type=gha,scope=${{ matrix.distro }}-${{ steps.hash.outputs.hash }},mode=max |
| 103 | + ${{ github.ref == 'refs/heads/main' && format('type=registry,ref=ghcr.io/kingpin/{0}:{1}-cache,mode=max', github.event.repository.name, matrix.distro) || '' }} |
| 104 | +
|
| 105 | + # Test image |
| 106 | + - name: Test image |
158 | 107 | run: | |
159 | | - echo "doxygen_version=$(docker run --rm docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:debian-test doxygen -v)" >> $GITHUB_OUTPUT |
| 108 | + docker run --rm doxygen-test:${{ matrix.distro }} doxygen --help |
| 109 | + |
| 110 | + # Get Doxygen version |
| 111 | + - name: Extract Doxygen version |
160 | 112 | id: version |
161 | | - # ${{ steps.version.outputs.doxygen_version }} |
162 | | - - |
163 | | - name: Run Trivy vulnerability scanner |
164 | | - uses: aquasecurity/trivy-action@master |
| 113 | + run: | |
| 114 | + # Run with environment variable to silence entrypoint output |
| 115 | + echo "doxygen_version=$(docker run --rm doxygen-test:${{ matrix.distro }} doxygen -v | tail -n1 | tr -d '\n')" >> $GITHUB_OUTPUT |
| 116 | + |
| 117 | + # Verify that we got a clean version |
| 118 | + if ! [[ $(cat $GITHUB_OUTPUT | grep doxygen_version | cut -d= -f2) =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then |
| 119 | + echo "Error: Invalid Doxygen version extracted. Check entrypoint script output." |
| 120 | + cat $GITHUB_OUTPUT |
| 121 | + exit 1 |
| 122 | + fi |
| 123 | + |
| 124 | + # Vulnerability scan |
| 125 | + - name: Run Trivy vulnerability scanner |
| 126 | + uses: aquasecurity/trivy-action@0.30.0 |
165 | 127 | with: |
166 | 128 | scan-type: image |
167 | | - image-ref: docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:debian-test |
| 129 | + image-ref: doxygen-test:${{ matrix.distro }} |
168 | 130 | format: 'sarif' |
169 | | - output: 'trivy-results-debian.sarif' |
| 131 | + output: 'trivy-results-${{ matrix.distro }}.sarif' |
170 | 132 | severity: 'MEDIUM,CRITICAL,HIGH' |
171 | 133 | hide-progress: false |
172 | | - - |
173 | | - name: Upload Trivy scan results to GitHub Security tab |
174 | | - uses: github/codeql-action/upload-sarif@v4 |
175 | | - with: |
176 | | - sarif_file: 'trivy-results-debian.sarif' |
177 | | - - |
178 | | - name: Build and push Docker image |
| 134 | + |
| 135 | + # Upload scan results |
| 136 | + - name: Upload Trivy scan results |
| 137 | + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository |
| 138 | + uses: github/codeql-action/upload-sarif@v3 |
| 139 | + with: |
| 140 | + sarif_file: 'trivy-results-${{ matrix.distro }}.sarif' |
| 141 | + |
| 142 | + # Generate tag lists based on context |
| 143 | + - name: Prepare tags |
| 144 | + id: prep |
| 145 | + run: | |
| 146 | + # Generate current timestamp in ISO 8601 format |
| 147 | + echo "timestamp=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT |
| 148 | + |
| 149 | + # For PR builds, only create GHCR tags with PR number |
| 150 | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then |
| 151 | + PR_NUMBER=$(echo "$GITHUB_REF" | awk -F / '{print $3}') |
| 152 | + if [ -z "$PR_NUMBER" ]; then |
| 153 | + echo "Error: could not extract PR number from GITHUB_REF='$GITHUB_REF'" >&2 |
| 154 | + exit 1 |
| 155 | + fi |
| 156 | + TAGS="ghcr.io/kingpin/${{ github.event.repository.name }}:${{ matrix.distro }}-pr-${PR_NUMBER} |
| 157 | + ghcr.io/kingpin/${{ github.event.repository.name }}:${{ matrix.distro }}-${{ steps.version.outputs.doxygen_version }}-pr-${PR_NUMBER}" |
| 158 | + |
| 159 | + if [ "${{ matrix.is_latest }}" = "true" ]; then |
| 160 | + TAGS="$TAGS |
| 161 | + ghcr.io/kingpin/${{ github.event.repository.name }}:pr-${PR_NUMBER}" |
| 162 | + fi |
| 163 | + else |
| 164 | + # For main branch, create all registry tags |
| 165 | + TAGS="ghcr.io/kingpin/${{ github.event.repository.name }}:${{ matrix.distro }} |
| 166 | + docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:${{ matrix.distro }} |
| 167 | + quay.io/kingpinx1/${{ github.event.repository.name }}:${{ matrix.distro }} |
| 168 | + ghcr.io/kingpin/${{ github.event.repository.name }}:${{ matrix.distro }}-${{ steps.version.outputs.doxygen_version }} |
| 169 | + docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:${{ matrix.distro }}-${{ steps.version.outputs.doxygen_version }} |
| 170 | + quay.io/kingpinx1/${{ github.event.repository.name }}:${{ matrix.distro }}-${{ steps.version.outputs.doxygen_version }}" |
| 171 | + |
| 172 | + # Add latest tags if this is the latest version |
| 173 | + if [ "${{ matrix.is_latest }}" = "true" ]; then |
| 174 | + TAGS="$TAGS |
| 175 | + ghcr.io/kingpin/${{ github.event.repository.name }}:latest |
| 176 | + docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:latest |
| 177 | + quay.io/kingpinx1/${{ github.event.repository.name }}:latest" |
| 178 | + fi |
| 179 | + fi |
| 180 | + |
| 181 | + echo "tags<<EOF" >> $GITHUB_OUTPUT |
| 182 | + echo "$TAGS" >> $GITHUB_OUTPUT |
| 183 | + echo "EOF" >> $GITHUB_OUTPUT |
| 184 | + |
| 185 | + # Build and push the images |
| 186 | + - name: Build and push |
179 | 187 | uses: docker/build-push-action@v7 |
180 | 188 | with: |
181 | | - # context: . |
182 | | - file: ./Dockerfile.debian |
| 189 | + context: . |
| 190 | + file: ./Dockerfile |
| 191 | + build-args: | |
| 192 | + DISTRO=${{ matrix.distro }} |
| 193 | + ${{ matrix.distro == 'alpine' && format('DISTRO_VERSION={0}', matrix.distro_version) || format('DEBIAN_VERSION={0}', matrix.debian_version) }} |
183 | 194 | platforms: linux/amd64,linux/arm64,linux/arm/v7 |
184 | | - push: true |
185 | | - cache-from: type=gha |
186 | | - cache-to: type=gha,mode=max |
187 | | - tags: | |
188 | | - ghcr.io/kingpin/${{ github.event.repository.name }}:debian |
189 | | - docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:debian |
190 | | - quay.io/kingpinx1/${{ github.event.repository.name }}:debian |
191 | | - ghcr.io/kingpin/${{ github.event.repository.name }}:debian-${{ steps.version.outputs.doxygen_version }} |
192 | | - docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:debian-${{ steps.version.outputs.doxygen_version }} |
193 | | - quay.io/kingpinx1/${{ github.event.repository.name }}:debian-${{ steps.version.outputs.doxygen_version }} |
| 195 | + push: ${{ github.ref == 'refs/heads/main' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) }} |
| 196 | + tags: ${{ steps.prep.outputs.tags }} |
| 197 | + cache-from: | |
| 198 | + type=gha,scope=${{ matrix.distro }} |
| 199 | + type=registry,ref=ghcr.io/kingpin/${{ github.event.repository.name }}:${{ matrix.distro }}-cache |
| 200 | + cache-to: | |
| 201 | + type=gha,scope=${{ matrix.distro }},mode=max |
| 202 | + ${{ github.ref == 'refs/heads/main' && format('type=registry,ref=ghcr.io/kingpin/{0}:{1}-cache,mode=max', github.event.repository.name, matrix.distro) || '' }} |
| 203 | + labels: | |
| 204 | + org.opencontainers.image.title=${{ github.event.repository.name }} |
| 205 | + org.opencontainers.image.description=Doxygen container based on ${{ matrix.distro }} |
| 206 | + org.opencontainers.image.version=${{ steps.version.outputs.doxygen_version }} |
| 207 | + org.opencontainers.image.created=${{ steps.prep.outputs.timestamp }} |
| 208 | + org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} |
0 commit comments