-
Notifications
You must be signed in to change notification settings - Fork 265
166 lines (148 loc) · 6.28 KB
/
Copy pathpublish.yml
File metadata and controls
166 lines (148 loc) · 6.28 KB
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
154
155
156
157
158
159
160
161
162
163
164
165
166
# Build and publish containers merged to master, on GitHub-hosted runners.
# A merge normally touches one container (enforced at PR time), but a direct push
# may touch several, so `detect` produces a matrix and `publish` fans out over it.
name: publish
on:
push:
branches: [master]
workflow_dispatch:
inputs:
container:
description: "Container name (top-level directory, e.g. aragorn)"
required: true
version:
description: "Version directory (e.g. 1.2.41)"
required: true
permissions:
contents: read
concurrency:
group: publish-${{ github.sha }}-${{ github.event.inputs.container }}
jobs:
detect:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.list.outputs.matrix }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine containers to publish
id: list
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
C='${{ github.event.inputs.container }}'
V='${{ github.event.inputs.version }}'
if [ ! -f "$C/$V/Dockerfile" ]; then
echo "No Dockerfile at $C/$V/Dockerfile"; exit 1
fi
echo "matrix=[{\"path\":\"$C/$V\",\"container\":\"$C\",\"version\":\"$V\"}]" >> "$GITHUB_OUTPUT"
echo "Manual publish: $C/$V"
else
git diff-tree --no-commit-id --name-only -r ${{ github.sha }} > changed_files.txt
echo "Changed files:"; cat changed_files.txt
python3 .github/scripts/validate.py list \
--changed-files changed_files.txt --out matrix.json
fi
publish:
needs: detect
if: ${{ needs.detect.outputs.matrix != '' && needs.detect.outputs.matrix != '[]' }}
runs-on: ubuntu-latest
permissions:
contents: write # create the Singularity release
security-events: write # upload the Trivy SARIF
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.detect.outputs.matrix) }}
env:
C: ${{ matrix.container }}
V: ${{ matrix.version }}
steps:
- uses: actions/checkout@v4
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- name: Build image (amd64) for validation
run: docker buildx build --load --platform linux/amd64 -t bcimg:local "$C/$V"
- name: Extract labels
run: docker inspect --format '{{json .Config.Labels}}' bcimg:local > labels.json
- name: Check labels and compute tag
id: check
run: |
python3 .github/scripts/validate.py check \
--container "$C" --version "$V" \
--labels labels.json --dockerfile "$C/$V/Dockerfile" --out report.json
- name: Run tests (test-cmds.txt)
run: |
TESTS="$C/$V/test-cmds.txt"
if [ ! -f "$TESTS" ]; then echo "No test-cmds.txt, skipping."; exit 0; fi
status=0
while IFS= read -r cmd || [ -n "$cmd" ]; do
[ -z "$cmd" ] && continue
echo "::group::TEST $cmd"
if docker run --rm bcimg:local $cmd; then echo "ok"; else echo "FAILED"; status=1; fi
echo "::endgroup::"
done < "$TESTS"
exit $status
# --- Security gate: scan the locally-built image BEFORE pushing. ---
# A fixable HIGH/CRITICAL CVE fails the job, so nothing is pushed. Unfixable
# OS-level CVEs are ignored. Maintainers can accept specific CVEs by adding a
# `.trivyignore` (CVE IDs, one per line) in the container's version directory.
- name: Prepare Trivy ignore file
run: |
if [ -f "$C/$V/.trivyignore" ]; then
cp "$C/$V/.trivyignore" .trivyignore
echo "Using per-container .trivyignore:"; cat .trivyignore
fi
- name: Trivy security scan (gate on fixable HIGH/CRITICAL)
uses: aquasecurity/trivy-action@0.35.0
with:
image-ref: bcimg:local
format: sarif
output: trivy.sarif
severity: HIGH,CRITICAL
ignore-unfixed: true
exit-code: '1'
- name: Upload Trivy results to Security tab
if: always()
continue-on-error: true
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy.sarif
category: trivy-${{ env.C }}
- name: Log in to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push (multi-arch, amd64 fallback)
run: |
TAG="${{ steps.check.outputs.tag }}"
IMG="biocontainers/${C}:${TAG}"
# Many legacy BioContainers base images are amd64-only, so the arm64 leg
# fails fast at the FROM pull. Try multi-arch, fall back to amd64-only so
# amd64 always publishes and arm64 is added only when the base supports it.
if docker buildx build --platform linux/amd64,linux/arm64 --pull --push -t "$IMG" "$C/$V"; then
echo "Published multi-arch (amd64+arm64): $IMG"
echo "- \`$IMG\` — **multi-arch** (amd64 + arm64)" >> "$GITHUB_STEP_SUMMARY"
else
echo "arm64 build failed (base likely amd64-only); publishing amd64-only."
docker buildx build --platform linux/amd64 --pull --push -t "$IMG" "$C/$V"
echo "Published amd64-only: $IMG"
echo "- \`$IMG\` — **amd64-only** (base has no arm64)" >> "$GITHUB_STEP_SUMMARY"
fi
- name: Set up Apptainer (Singularity)
uses: eWaterCycle/setup-apptainer@v2
- name: Convert to Singularity .sif
run: |
TAG="${{ steps.check.outputs.tag }}"
apptainer build "${C}_${TAG}.sif" "docker://biocontainers/${C}:${TAG}"
- name: Attach .sif to a GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ env.C }}-${{ steps.check.outputs.tag }}
name: ${{ env.C }} ${{ steps.check.outputs.tag }}
files: ${{ env.C }}_${{ steps.check.outputs.tag }}.sif
body: |
Singularity image for `biocontainers/${{ env.C }}:${{ steps.check.outputs.tag }}`.
Pull the container directly with:
`singularity pull docker://biocontainers/${{ env.C }}:${{ steps.check.outputs.tag }}`