diff --git a/.github/workflows/measure-classic-check.yml b/.github/workflows/measure-classic-check.yml index 66a1b6e..97894e9 100644 --- a/.github/workflows/measure-classic-check.yml +++ b/.github/workflows/measure-classic-check.yml @@ -15,6 +15,7 @@ on: - tools/build-sdl3-mixer.sh - tools/measure-classic-check-images.sh - tools/smoke-classic-check.sh + - tools/smoke-git-lfs.sh - tools/tests/** - tools/validate-toolchains.sh - tools/verify-classic-check-package.py diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 1afe64a..cde6812 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -45,6 +45,7 @@ jobs: tools/build-sdl3-mixer.sh | \ tools/install_classic_vulkan_toolchain.py | \ tools/require-image-checks.sh | \ + tools/smoke-git-lfs.sh | \ tools/test-require-image-checks.sh | \ tools/validate-toolchains.sh | \ tools/validate-vulkan-toolchain.sh) @@ -63,6 +64,7 @@ jobs: classic-vulkan-packages.lock | \ tools/audio/* | tools/build-sdl3-mixer.sh | \ tools/require-image-checks.sh | \ + tools/smoke-git-lfs.sh | \ tools/test-require-image-checks.sh | \ tools/validate-classic-check.sh | \ tools/validate-classic-image.sh | \ diff --git a/AGENTS.md b/AGENTS.md index 9381c8a..86cffec 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,6 +20,10 @@ revision, shader-toolchain inventory, GPU runtime, smoke/SBOM checks, and published tags synchronized. Do not make it inherit the broad replacement/development toolchain. +- The broad Linux and `classic-final` images include the snapshot-pinned Git LFS + client. Keep the Linux tool manifests, Classic package lock, non-root version + checks, and isolated worktree/payload smoke synchronized when changing this + prerequisite. - The public Classic image's shader contract is defined by `classic-shader-toolchain.json`: retain the exact DXC/SPIRV-Cross archive and source checksums, upstream licenses, and `/usr/local/bin` tool paths. Its diff --git a/README.md b/README.md index 94c24b9..55cebaa 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,10 @@ docker build --file windows/Dockerfile \ --tag atrinik-windows-check . docker run --rm atrinik-linux-build clang --version +docker run --rm --user ubuntu --env HOME=/home/ubuntu \ + atrinik-linux-build git lfs version +docker run --rm --user ubuntu --env HOME=/home/ubuntu \ + atrinik-linux-build atrinik-git-lfs-smoke docker run --rm --user ubuntu --env HOME=/home/ubuntu \ atrinik-linux-build gh version docker run --rm --user ubuntu --env HOME=/home/ubuntu \ @@ -107,6 +111,10 @@ docker run --rm atrinik-linux-build node --version docker run --rm atrinik-linux-build pnpm --version docker run --rm atrinik-classic-build gcc --version docker run --rm atrinik-classic-build cmake --version +docker run --rm --user ubuntu --env HOME=/home/ubuntu \ + atrinik-classic-build git lfs version +docker run --rm --user ubuntu --env HOME=/home/ubuntu \ + atrinik-classic-build atrinik-git-lfs-smoke docker run --rm atrinik-classic-build ccache --version docker run --rm atrinik-classic-build dxc --version docker run --rm atrinik-classic-build spirv-cross --help diff --git a/classic-packages.lock b/classic-packages.lock index 0fc08a5..90e1d80 100644 --- a/classic-packages.lock +++ b/classic-packages.lock @@ -9,6 +9,7 @@ g++=4:15.2.0-5ubuntu1 gcc=4:15.2.0-5ubuntu1 gcovr=7.2+really-2 git=1:2.53.0-1ubuntu1 +git-lfs=3.7.1-1 jq=1.8.1-4ubuntu2 libcurl4-openssl-dev=8.18.0-1ubuntu2.3 libdrm2=2.4.131-1 diff --git a/classic-toolchain.json b/classic-toolchain.json index f12c229..c665fa5 100644 --- a/classic-toolchain.json +++ b/classic-toolchain.json @@ -14,6 +14,7 @@ "cmake": "4.2.3", "gcc": "15.2.0", "gcovr": "7.2", + "git-lfs": "3.7.1", "ninja": "1.13.2", "python": "3.14.4" }, diff --git a/linux/Dockerfile b/linux/Dockerfile index 9a38be8..666a848 100644 --- a/linux/Dockerfile +++ b/linux/Dockerfile @@ -140,6 +140,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ fzf \ gdb \ git \ + git-lfs \ iproute2 \ jq \ libasound2-plugins \ @@ -210,6 +211,7 @@ ARG GH_STACK_SHA256_AMD64=358552dd7dce0a46ce153fe196270cec482b84f080947890aad406 ARG GH_STACK_SOURCE_COMMIT=a1b4a3d4d0bcde9ec3a78ab99b2d63af121857a9 ARG GH_STACK_LICENSE_SHA256=2510b446bc1f0cf9702453075d20cd88631e20e5642658edb7325d9c1eb534f7 ARG GIT_VERSION=2.53.0 +ARG GIT_LFS_VERSION=3.7.1 ARG GO_VERSION=1.26.5 ARG GO_SHA256=5c2c3b16caefa1d968a94c1daca04a7ca301a496d9b086e17ad77bb81393f053 ARG NODE_VERSION=24.18.1 @@ -386,7 +388,9 @@ RUN HOME="/home/${USERNAME}" runuser -u "${USERNAME}" -- \ && rm -rf "/home/${USERNAME}/.cache/gh" \ "/home/${USERNAME}/.local/state/gh" -RUN clang --version \ +COPY tools/smoke-git-lfs.sh /usr/local/bin/atrinik-git-lfs-smoke +RUN chmod 0755 /usr/local/bin/atrinik-git-lfs-smoke \ + && clang --version \ && test "$(go env GOVERSION)" = "go${GO_VERSION}" \ && test "$(rustc --version | cut -d' ' -f2)" = "${RUST_VERSION}" \ && test "$(node --version)" = "v${NODE_VERSION}" \ @@ -401,6 +405,9 @@ RUN clang --version \ = "${GH_VERSION}" \ && test "$(runuser -u "${USERNAME}" -- env HOME="/home/${USERNAME}" \ git version)" = "git version ${GIT_VERSION}" \ + && test "$(runuser -u "${USERNAME}" -- env HOME="/home/${USERNAME}" \ + git lfs version | sed -n '1s|^git-lfs/\([^ ]*\).*$|\1|p')" \ + = "${GIT_LFS_VERSION}" \ && test "$(runuser -u "${USERNAME}" -- env HOME="/home/${USERNAME}" \ gh stack --version)" = "gh stack version ${GH_STACK_VERSION}" \ && runuser -u "${USERNAME}" -- env HOME="/home/${USERNAME}" \ @@ -417,7 +424,9 @@ RUN clang --version \ && command -v xvfb-run \ && ssh -V \ && zip -v >/dev/null \ - && unzip -v >/dev/null + && unzip -v >/dev/null \ + && runuser -u "${USERNAME}" -- env HOME="/home/${USERNAME}" \ + bash /usr/local/bin/atrinik-git-lfs-smoke COPY toolchains.json /usr/local/share/atrinik/toolchains.json COPY audio-toolchain.json /usr/local/share/atrinik/audio-toolchain.json @@ -439,6 +448,7 @@ COPY audio-toolchain.spdx.json /workspace/audio-toolchain.spdx.json COPY classic-vulkan-toolchain.json /workspace/classic-vulkan-toolchain.json COPY classic-vulkan-toolchain.spdx.json /workspace/classic-vulkan-toolchain.spdx.json COPY tools/validate-toolchains.sh /workspace/tools/validate-toolchains.sh +COPY tools/smoke-git-lfs.sh /workspace/tools/smoke-git-lfs.sh COPY tools/validate-vulkan-toolchain.sh \ /workspace/tools/validate-vulkan-toolchain.sh @@ -552,6 +562,11 @@ RUN test "${TARGETARCH}" = amd64 \ && rm -f /etc/apt/apt.conf.d/80-snapshot-retries \ && rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*.deb +COPY tools/smoke-git-lfs.sh /usr/local/bin/atrinik-git-lfs-smoke +RUN chmod 0755 /usr/local/bin/atrinik-git-lfs-smoke \ + && runuser -u ubuntu -- env HOME=/home/ubuntu \ + bash /usr/local/bin/atrinik-git-lfs-smoke + COPY --from=mesa-dozen \ /usr/lib/x86_64-linux-gnu/libvulkan_dzn.so \ /usr/lib/x86_64-linux-gnu/libvulkan_dzn.so @@ -648,6 +663,7 @@ COPY classic-vulkan-toolchain.spdx.json /workspace/classic-vulkan-toolchain.spdx COPY audio-toolchain.json /workspace/audio-toolchain.json COPY linux/Dockerfile /workspace/linux/Dockerfile COPY tools/validate-classic-image.sh /workspace/tools/validate-classic-image.sh +COPY tools/smoke-git-lfs.sh /workspace/tools/smoke-git-lfs.sh COPY tools/validate-vulkan-toolchain.sh \ /workspace/tools/validate-vulkan-toolchain.sh diff --git a/toolchains.json b/toolchains.json index 6459d8f..d254098 100644 --- a/toolchains.json +++ b/toolchains.json @@ -4,6 +4,7 @@ "platform": "linux/amd64", "tools": { "buf": "1.72.0", + "git-lfs": "3.7.1", "go": "1.26.5", "node": "24.18.1", "pnpm": "11.20.0", diff --git a/tools/smoke-git-lfs.sh b/tools/smoke-git-lfs.sh new file mode 100755 index 0000000..8b28f31 --- /dev/null +++ b/tools/smoke-git-lfs.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -ne 0 ]]; then + echo "usage: $0" >&2 + exit 2 +fi + +work=$(mktemp -d) +trap 'rm -rf -- "${work}"' EXIT +repo="${work}/repo" +checkout="${work}/worktree" +payload='Atrinik Git LFS smoke payload' + +git init --quiet "${repo}" +git -C "${repo}" config user.email 'image-smoke@example.invalid' +git -C "${repo}" config user.name 'Atrinik image smoke' +git -C "${repo}" lfs install --local >/dev/null +git -C "${repo}" lfs track '*.payload' >/dev/null +printf '%s\n' "${payload}" > "${repo}/sample.payload" +git -C "${repo}" add .gitattributes sample.payload +git -C "${repo}" commit --quiet -m 'smoke Git LFS payload' +git -C "${repo}" worktree add --quiet "${checkout}" HEAD + +test "$(git -C "${checkout}" lfs ls-files --name-only)" = 'sample.payload' +test "$(cat "${checkout}/sample.payload")" = "${payload}" +test "$(git -C "${checkout}" check-attr filter -- sample.payload)" = \ + 'sample.payload: filter: lfs' +test "$(git -C "${repo}" show HEAD:sample.payload | sed -n '1p')" = \ + 'version https://git-lfs.github.com/spec/v1' + +echo 'git-lfs smoke: passed' diff --git a/tools/validate-classic-image.sh b/tools/validate-classic-image.sh index 55782c6..cfad644 100755 --- a/tools/validate-classic-image.sh +++ b/tools/validate-classic-image.sh @@ -180,6 +180,10 @@ while IFS='=' read -r package version; do test "$(dpkg-query --show --showformat='${Version}' "${package}")" = "${version}" done < "${package_lock}" +test "$(git lfs version | sed -n '1s|^git-lfs/\([^ ]*\).*$|\1|p')" = \ + "$(jq -r '.tools["git-lfs"]' "${expected}")" +bash "$(dirname -- "${BASH_SOURCE[0]}")/smoke-git-lfs.sh" + test "$(ccache --version | sed -n '1s/^ccache version //p')" = \ "$(jq -r '.tools.ccache' "${expected}")" test "$(cmake --version | sed -n '1s/^cmake version //p')" = \ diff --git a/tools/validate-toolchains.sh b/tools/validate-toolchains.sh index 62c1049..14d7284 100755 --- a/tools/validate-toolchains.sh +++ b/tools/validate-toolchains.sh @@ -14,7 +14,7 @@ jq -e ' .schema_version == 1 and .platform == "linux/amd64" and (.tools | keys == [ - "buf", "go", "node", "pnpm", "protoc", "protoc-gen-go", + "buf", "git-lfs", "go", "node", "pnpm", "protoc", "protoc-gen-go", "protoc-gen-prost", "rust", "rustup", "syft", "trivy" ]) and (.consumers | length == 7) @@ -41,8 +41,11 @@ if [[ -n ${installed} ]]; then "$(jq -r '.tools.syft' "${expected}")" test "$(trivy --version | sed -n '1s/^Version: //p')" = \ "$(jq -r '.tools.trivy' "${expected}")" + test "$(git lfs version | sed -n '1s|^git-lfs/\([^ ]*\).*$|\1|p')" = \ + "$(jq -r '.tools["git-lfs"]' "${expected}")" command -v Xvfb >/dev/null command -v xvfb-run >/dev/null + bash "$(dirname -- "${BASH_SOURCE[0]}")/smoke-git-lfs.sh" fi jq -e '