Skip to content

Add multi-arch (amd64/arm64) Docker builds with manifest stitching#72

Open
t0mdavid-m wants to merge 18 commits into
developfrom
claude/dazzling-mayer-fV7HC
Open

Add multi-arch (amd64/arm64) Docker builds with manifest stitching#72
t0mdavid-m wants to merge 18 commits into
developfrom
claude/dazzling-mayer-fV7HC

Conversation

@t0mdavid-m
Copy link
Copy Markdown
Member

@t0mdavid-m t0mdavid-m commented May 27, 2026

Summary

This PR adds native ARM64 (aarch64) Docker image builds alongside existing AMD64 builds, with automatic multi-arch manifest creation for transparent architecture selection on pull. The workflow now produces per-architecture tags (-amd64, -arm64) that are merged into unified manifest lists under the original tag scheme, allowing existing consumers (k8s overlays, docker-compose, direct pulls) to work unchanged while gaining ARM support.

Key Changes

  • Split build job into architecture-specific jobs:

    • build-amd64: Runs on ubuntu-latest, produces *-amd64 tags, uses standard Dockerfile
    • build-arm64: Runs on native ubuntu-24.04-arm runner, produces *-arm64 tags, uses Dockerfile.arm (with aarch64-specific miniforge installer and THIRDPARTY paths)
  • New create-manifest job: Stitches per-arch tags into multi-arch manifest lists under the original tag scheme (<ref>-<variant>, latest), enabling transparent architecture selection on docker pull

  • Updated test jobs for ARM support:

    • test-nginx and test-traefik: Now run on both ubuntu-latest (amd64) and ubuntu-24.04-arm (arm64) via matrix strategy
    • test-apptainer: Remains amd64-only (upstream apptainer does not publish arm64 .deb assets)
    • All test jobs now use kind load image-archive instead of docker load + kind load docker-image to save ~5-8 GB of disk space
  • Disk space optimizations:

    • Added "Free disk space" step to build-arm64, test-nginx, and test-traefik jobs (removes /usr/share/dotnet, /usr/local/lib/android, /opt/ghc)
    • Changed image loading strategy in test jobs to avoid storing full images in host docker
  • Improved image tagging and retagging:

    • Per-arch tags now include architecture suffix in all metadata (cache refs, artifact names)
    • Retagging step now uses the canonical image name (ghcr.io/openms/flashapp:latest) instead of a temporary local name, with clearer comments explaining the kustomize overlay contract
  • Enhanced test failure diagnostics:

    • Added "Dump cluster state on failure" steps to test-nginx and test-traefik jobs for better debugging (nodes, pods, logs, ingress/ingressroute, services, controller logs)
  • Minor sed regex fix: Updated imagePullPolicy sed patterns to handle both IfNotPresent and Always values

Implementation Details

  • ARM builds use Dockerfile.arm (separate from standard Dockerfile) to swap the miniforge installer to aarch64 and conditionally copy THIRDPARTY/Linux/aarch64
  • Per-arch cache layers are maintained separately (cache:*-amd64, cache:*-arm64) to avoid cross-architecture pollution
  • Multi-arch manifest creation uses docker manifest create --amend for idempotency across workflow_dispatch reruns
  • PRs do not push per-arch tags or create manifests (only non-PR events trigger the create-manifest job)
  • All per-arch image artifacts are retained for 1 day to support test job downloads

https://claude.ai/code/session_01XXcpjdQC93TA4xKHeZPPAp

Summary by CodeRabbit

  • Chores
    • CI restructured to produce and publish multi-architecture container images (amd64 and arm64) and combined multi-arch manifests.
    • Deployment templating adjusted to ensure images are used from local test artifacts.
  • Tests
    • Test matrix expanded to cover amd64 and arm64; tests now consume arch-specific artifacts.
    • Improved failure diagnostics to dump cluster state and logs; tests include disk-space safeguards.

Review Change Stack

claude and others added 16 commits May 25, 2026 15:26
Mirror FLASHApp's split-build / manifest-merge approach so both
linux/amd64 and linux/arm64 are published for the full and simple
variants. Existing `<ref>-full` / `<ref>-simple` / `latest` tags
become multi-arch manifests — k8s overlays, docker-compose users,
and direct `docker pull` callers transparently get the right arch.

Dockerfile.arm (delta from Dockerfile):
 - aarch64 miniforge installer
 - conditional THIRDPARTY/Linux/aarch64 copy (some OpenMS releases
   ship an empty/missing aarch64 dir)
 - pruned thirdparty PATH to tools that actually have ARM builds:
   LuciPHOr2, MSGFPlus, ThermoRawFileParser, Comet, Percolator, Sage

Dockerfile_simple.arm (delta from Dockerfile_simple):
 - aarch64 miniforge installer only — pyOpenMS ships aarch64 wheels
   on PyPI, so `pip install -r requirements.txt` works as-is

The shared docker/entrypoint.sh is reused as-is on ARM: its
apptainer/read-only-root handling is arch-neutral and worth keeping.
Base stays ubuntu:22.04 (Redis 6.0 predates the ARM64-COW-BUG
warning, so no `--ignore-warnings` flag needed).

Workflow changes (build-and-test.yml):
 - `build` renamed `build-amd64`; per-arch tags carry `-amd64`.
 - New `build-arm64` job runs on `ubuntu-24.04-arm`, builds the
   `.arm` Dockerfiles for both variants, ends with a pull-back +
   /_stcore/health probe on push events.
 - New `create-manifest` job stitches `<ref>-<variant>-amd64` +
   `<ref>-<variant>-arm64` into multi-arch `<ref>-<variant>` and
   `latest` manifests.
 - test-apptainer / test-nginx / test-traefik / publish-apptainer
   keep consuming the amd64 artifact only. SIF publishing stays
   amd64-only this iteration.
 - PRs build both arches (registry cache keeps warm runs cheap) but
   don't push; manifest creation also skipped on PRs.

Branch-protection note: the `build` required check is renamed to
`build-amd64`. Admins should update protected-branch rules and add
`build-arm64` / `create-manifest` if those should also be required.
Previously the apptainer/nginx/traefik integration tests only ran
against the amd64 artifact, so the arm64 image was validated solely
by its build succeeding plus a post-push /_stcore/health probe. Now
all three integration matrices fan out over arch=[amd64, arm64] with
a matrix-driven runs-on, exercising the read-only-root apptainer
contract and both kind-based ingress paths on a native ARM runner
too.

Changes:
 - `build-amd64` artifact renamed from
   `openms-streamlit-<variant>-image` to
   `openms-streamlit-<variant>-amd64-image` for symmetry.
 - `build-arm64` now also `load: true`'s the built image, retags to
   the kind-friendly `openms-streamlit:test`, saves it as a tar, and
   uploads it as `openms-streamlit-<variant>-arm64-image`. The
   post-push pull-back smoke test is removed — the new apptainer/
   nginx/traefik runs subsume it and avoid the slow GHCR pull.
 - `test-apptainer`, `test-nginx`, `test-traefik` matrices switched
   from `variant: [full, simple]` to an `include:` list with
   {variant, arch, runner} tuples; `runs-on: ${{ matrix.runner }}`
   selects `ubuntu-latest` for amd64 and `ubuntu-24.04-arm` for arm64.
   Artifact download names get `${{ matrix.arch }}` interpolated.
 - SIF upload at the tail of `test-apptainer` gated on
   `matrix.arch == 'amd64'`: arm64 still runs the full apptainer
   contract end-to-end, but only amd64 produces the SIF that
   `publish-apptainer` ships to GHCR (HPC SIF consumers are amd64).

Note on `publish-apptainer`: it stays on `needs: test-apptainer`,
which now waits for the arm64 matrix entries too — meaning an arm64
apptainer regression will block amd64 SIF publishing. Conservative
on purpose; happy to decouple via separate jobs if that turns out to
be too strict in practice.
The ARM build of `make -j4 TOPP` failed at the link step with

    /usr/bin/ld: /root/miniforge3/lib/libyaml-cpp.so.0.8: undefined
    reference to `std::ios_base_library_init()@GLIBCXX_3.4.32'

The conda-forge libyaml-cpp wheel for aarch64 is built against
GLIBCXX_3.4.32 (gcc 13+), but Ubuntu 22.04's system g++ ships with an
older libstdc++. Running cmake inside the mamba shell lets it discover
/root/miniforge3/lib first, so the conda-forge yaml-cpp gets linked
into every TOPP binary and breaks. amd64 happens to work because the
conda-forge amd64 yaml-cpp build is older.

Fix mirrors FLASHApp's Dockerfile.arm: configure OpenMS in two cmake
passes — pass 1 under plain `/bin/bash` with
`-DCMAKE_IGNORE_PREFIX_PATH=/root/miniforge3` so cmake resolves C++
deps from the system tree (libyaml-cpp from contrib, boost from apt,
etc.); pass 2 under `mamba run` with `-DPYOPENMS=ON` so the Python
bindings still find conda-forge Python / Cython / NumPy. The
IGNORE_PREFIX_PATH flag is repeated on pass 2 to keep the cached C++
link command unchanged.

Only Dockerfile.arm changes; Dockerfile (amd64) keeps its single-pass
cmake to avoid disturbing the working x86 path.
The two-pass cmake split from 1d73b67 runs pass 1 under
`SHELL ["/bin/bash", "-c"]`, but the only cmake on the image is the
one from `mamba install cmake` at /root/miniforge3/envs/streamlit-env/bin/cmake
— not on plain bash's PATH. Result: exit 127 (command not found) the
moment pass 1 invokes cmake.

FLASHApp.arm sidesteps this by installing cmake via apt; do the same
here (just append `cmake` to the existing apt-get install line). The
mamba cmake install stays, so pass 2 under the mamba shell continues
to use the conda-forge cmake exactly as it did before. Ubuntu 22.04
ships cmake 3.22, comfortably above OpenMS 3.5's 3.15 floor.
The previous fix (install cmake via apt) didn't actually help: OpenMS
3.5's CMakeLists.txt requires cmake >= 3.24, and Ubuntu 22.04's apt
cmake is 3.22.1, which fails configure with

    CMake Error at src/openms/extern/CMakeLists.txt:11 (cmake_minimum_required):
      CMake 3.24 or higher is required. You are running version 3.22.1

That's exactly why the existing x86 Dockerfile installs cmake via
mamba (the conda-forge build is 3.30+). FLASHApp.arm escapes this by
using ubuntu:24.04 (apt cmake 3.28); we stay on 22.04 to minimize
churn vs. the working x86 Dockerfile.

Fix: in pass 1, call the mamba-env cmake by its full path
`/root/miniforge3/envs/streamlit-env/bin/cmake`. The plain-bash SHELL
is still in effect, so cmake doesn't pick up any conda-forge
environment side effects, and CMAKE_IGNORE_PREFIX_PATH keeps it from
auto-discovering miniforge libraries during find_package. The cmake
binary itself runs against miniforge's libstdc++, but that's a
runtime detail of cmake — it doesn't leak into the configured
project's link command.

The apt cmake addition from f11bc99 is now redundant but harmless;
leaving it in place to keep this diff focused.
Two failures in the previous run (test-traefik full, test-nginx
simple) ended with the runner reporting "No space left on device"
while flushing its diagnostic log. ubuntu-latest starts with ~14 GB
free; downloading the full image artifact (5-8 GB), loading it into
docker (decompressed, larger), pulling kind's node image, then
loading the OCI tar into the kind cluster easily exceeds that budget.

Mirror the cleanup already used by `build-arm64`: drop the runner's
preinstalled dotnet / android SDK / ghc / hostedtoolcache to recover
~30 GB. Same step now runs at the top of test-apptainer, test-nginx,
and test-traefik on both amd64 (ubuntu-latest) and arm64
(ubuntu-24.04-arm) matrix entries — the arm runner is at least as
tight as amd64.
After the two-pass cmake configure landed in 5185c3e, the next
attempt got past `make -j4 TOPP` (the link error is fixed) but
failed fast in `make -j4 pyopenms` with:

    CMake Error: Not a file: /openms-build/CMakeFiles/VerifyGlobs.cmake
    CMake Error: Error processing file: /openms-build/CMakeFiles/VerifyGlobs.cmake
    make: *** [Makefile:11553: cmake_check_build_system] Error 1

`VerifyGlobs.cmake` is generated by cmake for `file(GLOB CONFIGURE_DEPENDS ...)`
targets and is consulted by `cmake_check_build_system` at the top of
every subsequent `make` invocation. The intermediate cleanup line

    RUN rm -rf src doc CMakeFiles

deleted it, which is fine on the x86 single-pass build (different
cmake codepath when PYOPENMS=ON is set in the initial configure, no
VerifyGlobs.cmake generated) but breaks the ARM two-pass build.

Stop deleting CMakeFiles/ between `make TOPP` and `make pyopenms`.
We still drop `src/` and `doc/` for disk savings; keeping CMakeFiles
costs only a few hundred MB on the intermediate layer.
eWaterCycle/setup-apptainer@v2 installs apptainer from the upstream
.deb asset on the GitHub release. Upstream apptainer only publishes
amd64 .debs (verified: every v1.3.x release lists only
`apptainer_<ver>_amd64.deb`, no _arm64 / _aarch64 variant). On the
ubuntu-24.04-arm runner the action's `apt-get install ./apptainer_*.deb`
fails with sudo exit code 100 because the package can't be resolved.

Building apptainer from source on the ARM runner would add ~15 minutes
and a maintenance surface (Go toolchain, suid configuration) for
limited value — HPC SIF consumers remain amd64. Revert test-apptainer
to amd64-only and document why. test-nginx and test-traefik still
exercise the ARM image via kind, which gives us functional ARM
coverage at the docker-runtime level even without apptainer.

Side cleanups now that arm64 is gone from this matrix:
- artifact name back to a literal `*-amd64-image` (no matrix.arch)
- SIF upload gate drops the `matrix.arch == 'amd64'` check
kind/kubectl/helm setup actions fail with "Cache directory
'/opt/hostedtoolcache' does not exist". Drop just dotnet/android/ghc
(~34 GB) and leave the tool cache in place.
curl exit-22 doesn't tell us whether the pod, service, or ingress is
the broken link. Dump pods/logs/ingress/controller logs on failure so
the next run surfaces the actual cause.
\`docker load\` + \`kind load docker-image\` keeps the image in both host
docker AND each kind node's containerd. With a 5-8 GB image and two
kind nodes that's ~25 GB of duplicated storage, which trips the
"no space left on device" error in kind's ctr import.

Switch to \`kind load image-archive\` so the tar streams directly into
each node, and rm the tar after to reclaim /tmp.
503s in test-nginx/test-traefik traced to two issues:

1. The prod overlay maps openms-streamlit ->
   ghcr.io/openms/streamlit-template:main-full, but the build job was
   re-tagging the local image as openms-streamlit:test. Rendered
   manifests pointed at the registry name; kind only had :test loaded;
   pods stayed ErrImagePull. Retag as :main-full so kind has exactly
   the ref the manifests use.

2. Three of the four pod specs declare imagePullPolicy: Always; the
   existing sed only rewrote IfNotPresent. With Always and no registry
   creds in kind, pods loop on ImagePullBackOff. Extend the sed to
   catch both.
Add ARM64 (aarch64) multi-architecture Docker build support
…er-fV7HC

Adopt the template's modernized build-and-test.yml: split into
build-amd64 + build-arm64 (ubuntu-24.04-arm) + create-manifest jobs,
per-arch GHCR cache, image-artifact deposit for downstream tests,
and the extended apptainer/nginx/traefik kind-cluster test suite
covering both architectures.

FLASHApp customizations applied on top of the template workflow:
- Trigger branches main -> develop
- Matrix reduced to variant=full only (FLASHApp dropped the simple
  variant in d1b3de0); test-nginx/test-traefik arch matrices keep
  amd64 + arm64
- Retag-for-kind targets ghcr.io/openms/flashapp:latest to match the
  prod overlay's newName/newTag
- Latest tag rule keyed to refs/heads/develop

Keep FLASHApp's OpenMS build setup: Dockerfile and Dockerfile.arm
unchanged (Vue JS stage, t0mdavid-m/OpenMS.git#FVdeploy fork,
FLASHApp ARGs, two-pass cmake). Drop template's Dockerfile_simple.arm.

publish-docker-images.yml (release-tag flow) left untouched.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7b747e35-d4dc-4da1-a1ee-ab8b26217b5c

📥 Commits

Reviewing files that changed from the base of the PR and between e1338f8 and 0c29d06.

📒 Files selected for processing (1)
  • .github/workflows/build-and-test.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/build-and-test.yml

📝 Walkthrough

Walkthrough

Splits image builds into explicit amd64 and arm64 jobs that upload per-arch tar artifacts, adds a non-PR manifest job to create multi-arch lists, and updates apptainer/nginx/traefik tests to consume arch-specific artifacts via kind image loading with enhanced failure diagnostics.

Changes

Multi-architecture build and test orchestration

Layer / File(s) Summary
amd64 and arm64 build jobs with per-arch artifacts
.github/workflows/build-and-test.yml
Adds build-amd64 and build-arm64 jobs producing -amd64/-arm64 tags and tar artifacts; introduces create-manifest to compose and push multi-arch manifest lists on non-PR events.
Apptainer test adapted to amd64 artifacts
.github/workflows/build-and-test.yml
test-apptainer now depends on build-amd64, adds a disk-freeing step, and downloads the amd64-specific tar for SIF creation and execution.
Nginx test: arch-matrix with kind image loading and diagnostics
.github/workflows/build-and-test.yml
test-nginx becomes an amd64+arm64 matrix, frees disk, downloads arch-specific artifact, uses kind load image-archive, updates manifest templating to force imagePullPolicy: Never, and adds comprehensive cluster-state dumps on failure.
Traefik test: arch-matrix with kind image loading and diagnostics
.github/workflows/build-and-test.yml
test-traefik mirrors nginx changes: arch matrix, disk free, arch-specific artifact download, kind load image-archive, enforces imagePullPolicy: Never, and adds Traefik/IngressRoute-specific diagnostics and controller logs.

Sequence Diagram

sequenceDiagram
  participant build_amd64 as build-amd64
  participant build_arm64 as build-arm64
  participant create_manifest as create-manifest
  participant GHCR as GHCR registry
  
  par amd64 path
    build_amd64->>build_amd64: Build linux/amd64, tag -amd64
    build_amd64->>build_amd64: Upload -amd64 artifact
  and arm64 path
    build_arm64->>build_arm64: Free disk space
    build_arm64->>build_arm64: Build linux/arm64, tag -arm64
    build_arm64->>build_arm64: Upload -arm64 artifact
  end
  
  build_amd64->>create_manifest: await both builds
  build_arm64->>create_manifest: await both builds
  create_manifest->>create_manifest: Iterate manifest tags
  create_manifest->>GHCR: Create and push multi-arch manifests
Loading

Possibly related PRs

  • OpenMS/FLASHApp#64: Introduced ARM64 Dockerfile and parallel per-architecture CI/publish jobs that align with this PR's multi-arch build and manifest logic.

Poem

🐰 A rabbit's note on multi-arch cheer

Two builds hop: amd64 and arm64 clear,
Tars tucked, manifests stitched with care,
Kind loads images into clusters fair,
Logs and dumps chase failures away,
Hooray—parallel builds brighten the day!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding multi-architecture (amd64/arm64) Docker builds with manifest stitching, which is the primary objective of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/dazzling-mayer-fV7HC

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-and-test.yml:
- Line 149: Update every GitHub Actions "uses:" line that uses a mutable tag
(e.g., actions/checkout@v4, docker/*`@v3/`@v5, actions/*`@v4`,
eWaterCycle/setup-apptainer@v2, helm/kind-action@v1, azure/setup-helm@v4) to the
corresponding full 40-character commit SHA; find each occurrence of those module
references in the workflow and replace the tag form with the specific commit SHA
for that release so the CI is pinned to immutable versions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3af9f83d-3238-4113-b78a-2217cf5abd22

📥 Commits

Reviewing files that changed from the base of the PR and between 3f031e7 and e1338f8.

📒 Files selected for processing (1)
  • .github/workflows/build-and-test.yml

sudo apt-get clean
df -h

- uses: actions/checkout@v4
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# List every action reference in this workflow that is not pinned to a full 40-char SHA.
rg -nP '^\s*uses:\s+\S+@(?![0-9a-fA-F]{40}\b)\S+' .github/workflows/build-and-test.yml

Repository: OpenMS/FLASHApp

Length of output: 1117


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE=".github/workflows/build-and-test.yml"

echo "== checkout uses lines =="
rg -n "uses:\s+actions/checkout@" "$FILE" || true

echo
echo "== line context around 140-170 =="
nl -ba "$FILE" | sed -n '140,175p'

echo
echo "== all sed -E occurrences (with a bit of surrounding context) =="
rg -n "sed -E" "$FILE" || true
rg -n -C 3 "sed -E" "$FILE" || true

echo
echo "== any imagePullPolicy rewrite lines =="
rg -n "imagePullPolicy" "$FILE" || true
rg -n -C 3 "imagePullPolicy" "$FILE" || true

echo
echo "== full list of all non-SHA-pinned uses lines (reuse same regex) =="
rg -nP '^\s*uses:\s+\S+@(?![0-9a-fA-F]{40}\b)\S+' "$FILE"

Repository: OpenMS/FLASHApp

Length of output: 408


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE=".github/workflows/build-and-test.yml"

echo "== line context around 140-180 =="
awk 'NR>=140 && NR<=180 {printf "%d:%s\n", NR, $0}' "$FILE"

echo
echo "== line context around 190-270 =="
awk 'NR>=190 && NR<=270 {printf "%d:%s\n", NR, $0}' "$FILE"

echo
echo "== all sed -E occurrences with nearby lines =="
# Print only the matching line plus next 6 lines for each occurrence
awk '
  /sed -E/ {print "---- match at line " NR " ----"; print NR ":" $0; for(i=1;i<=6;i++){getline; print (NR+i) ":" $0}}
' "$FILE"

echo
echo "== imagePullPolicy occurrences with nearby lines =="
awk '
  /imagePullPolicy/ {print "---- match at line " NR " ----"; print NR ":" $0; for(i=1;i<=6;i++){getline; print (NR+i) ":" $0}}
' "$FILE"

echo
echo "== non-SHA-pinned uses lines (regex from prior script) =="
rg -nP '^\s*uses:\s+\S+@(?![0-9a-fA-F]{40}\b)\S+' "$FILE"

Repository: OpenMS/FLASHApp

Length of output: 8882


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE=".github/workflows/build-and-test.yml"

echo "== line context around 140-180 =="
awk 'NR>=140 && NR<=180 {printf "%d:%s\n", NR, $0}' "$FILE"

echo
echo "== line context around 190-270 =="
awk 'NR>=190 && NR<=270 {printf "%d:%s\n", NR, $0}' "$FILE"

echo
echo "== all sed -E occurrences with nearby lines =="
# Print only the matching line plus next 6 lines for each occurrence
awk '
  /sed -E/ {print "---- match at line " NR " ----"; print NR ":" $0; for(i=1;i<=6;i++){getline; print (NR+i) ":" $0}}
' "$FILE"

echo
echo "== imagePullPolicy occurrences with nearby lines =="
awk '
  /imagePullPolicy/ {print "---- match at line " NR " ----"; print NR ":" $0; for(i=1;i<=6;i++){getline; print (NR+i) ":" $0}}
' "$FILE"

echo
echo "== non-SHA-pinned uses lines (regex from prior script) =="
rg -nP '^\s*uses:\s+\S+@(?![0-9a-fA-F]{40}\b)\S+' "$FILE"

Repository: OpenMS/FLASHApp

Length of output: 8882


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE=".github/workflows/build-and-test.yml"

# Extract the exact sed -E replacement expression(s) from the workflow and test them on sample inputs.
expr=$(rg -o "sed -E 's\|imagePullPolicy: \\(IfNotPresent\\\\\|Always\\)\\|imagePullPolicy: Never\\|g'" "$FILE" | head -n 1 || true)
if [[ -z "${expr}" ]]; then
  # Fallback: use the literal expression observed in the file
  expr="sed -E 's|imagePullPolicy: (IfNotPresent\\|Always)|imagePullPolicy: Never|g'"
fi

echo "Using expression: $expr"
echo

printf '%s\n' \
  "imagePullPolicy: IfNotPresent" \
  "imagePullPolicy: Always" \
  "imagePullPolicy: IfNotPresent|Always" | while read -r line; do
    printf 'IN : %s\n' "$line"
    out=$(printf '%s\n' "$line" | bash -lc "$expr")
    printf 'OUT: %s\n\n' "$out"
done

Repository: OpenMS/FLASHApp

Length of output: 669


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE=".github/workflows/build-and-test.yml"

# Match both `uses:` and `- uses:` lines; flag anything not pinned to a full 40-char SHA.
rg -nP '^\s*(?:-\s*)?uses:\s+\S+@(?![0-9a-fA-F]{40}\b)\S+' "$FILE"

Repository: OpenMS/FLASHApp

Length of output: 1343


Pin CI uses: references in .github/workflows/build-and-test.yml to full commit SHAs

The workflow has many uses: entries using mutable version tags (e.g., actions/checkout@v4, docker/*@v3/@v5, actions/*@v4``, eWaterCycle/setup-apptainer@v2, `helm/kind-action@v1`, `azure/setup-helm@v4`); pin each to its 40-char commit SHA.

The sed -E pattern used to rewrite imagePullPolicy correctly matches both IfNotPresent and Always and replaces them with Never, so that concern doesn’t apply here.

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 149-149: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 149-149: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-and-test.yml at line 149, Update every GitHub
Actions "uses:" line that uses a mutable tag (e.g., actions/checkout@v4,
docker/*`@v3/`@v5, actions/*`@v4`, eWaterCycle/setup-apptainer@v2,
helm/kind-action@v1, azure/setup-helm@v4) to the corresponding full 40-character
commit SHA; find each occurrence of those module references in the workflow and
replace the tag form with the specific commit SHA for that release so the CI is
pinned to immutable versions.

claude added 2 commits May 27, 2026 16:25
…fest

create-manifest fails with "ghcr.io/openms/streamlit-template:main-full-amd64
is a manifest list" because docker/build-push-action v5 adds a provenance
attestation by default, which buildx packs as a manifest list (image +
attestation entries). docker manifest create rejects manifest lists as
components.

build-arm64 already sets provenance: false for the same reason; mirror
that on the amd64 path so both per-arch tags are flat image manifests
that can be merged into the multi-arch manifest.
test-traefik failed unpacking the OpenMS image into containerd
overlayfs on the kind node:

  no space left on device while extracting layer
  /usr/include/boost/json/object.hpp

The image is loaded into BOTH kind nodes (control-plane + worker)
so the OpenMS source / boost headers / pyopenms layers consume
~2x their unpacked size. The previous cleanup only removed dotnet,
android and ghc, leaving the runner well short of what kind's
double-extraction needs.

Drop the next biggest unused chunks (~16 GB more):
- /usr/local/.ghcup (~2.7 GB)
- /usr/share/swift (~2 GB)
- /usr/local/share/boost (~1.5 GB)
- /opt/hostedtoolcache/CodeQL (~5 GB; keep the rest of hostedtoolcache
  since helm/kind-action and setup-kubectl cache binaries there)
- docker image prune (~5-7 GB of pre-installed runner images)

Applied uniformly to build-arm64 / test-apptainer / test-nginx /
test-traefik since they all eat the same image.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants