fix(docker): pin the build workflow and keep the image on hash-locked dependencies
Four issues in the new workflow and Dockerfile: - Every action floated on a mutable major tag, and BuildKit was pinned to moby/buildkit:master. This was the only workflow in the repo doing so; the other four already pin full commit SHAs. All seven actions are now SHA-pinned with a version comment, and the custom driver-opts block is dropped, which also removes an unneeded network=host. - id-token: write was granted with no OIDC consumer anywhere in the workflow — no cosign, attestation, provenance, or OIDC login step. Dropped. - The Dockerfile installed channel extras with 'pip install -e ".[extras]"' after the --require-hashes lock install. lark-oapi, qrcode and python-telegram-bot are in neither requirements-lock.txt nor its source, so the build resolved them and their transitive deps unhashed from PyPI at build time — six lines below a comment stating deps come from the hash-pinned lock. They now come from requirements-channels-lock.txt (16 pins, all hashed, generated under the same constraint as the main lock: 12 packages are shared with it and none diverge in version). The project install is --no-deps, which is safe because all 44 pyproject base deps are already in the main lock. - The workflow_dispatch input was interpolated directly into the Summary step's run: body. It now passes through env, and the tag is validated against the Docker tag grammar before any registry work. CI verifies the new lock too. The existing 'Verify hash-locked dependencies' step only dry-ran requirements-lock.txt, so a second lock could have rotted undetected until a release build failed; both are now dry-run separately, since the Docker build installs them as two independent --require-hashes passes. The summary also states that a new GHCR package is private until its visibility is set once, so the pull command it prints is not read as working out of the box.
This commit is contained in:
1 parent
b23aabf0a0
commit
adaeeb5629
5 files changed
+417
-40
No files matched your search
@@ -1,5 +1,9 @@
|
||||
name: Build and Push Docker Image
|
||||
|
||||
# Actions are pinned to immutable commit SHAs, matching every other workflow in
|
||||
# this repository. Newer majors exist for the docker/* actions (v4/v6/v7); those
|
||||
# are a deliberate, separately testable bump, not a drive-by change here.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -20,31 +24,36 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Validate image tag
|
||||
env:
|
||||
IMAGE_TAG: ${{ inputs.image_tag }}
|
||||
run: |
|
||||
# Fail early with a readable message rather than at the registry push.
|
||||
if ! printf '%s' "$IMAGE_TAG" | grep -qE '^[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}$'; then
|
||||
echo "::error::'$IMAGE_TAG' is not a valid Docker tag." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
driver-opts: |
|
||||
image=moby/buildkit:master
|
||||
network=host
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
with:
|
||||
registry: ${{ env.GHCR_REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
with:
|
||||
registry: ${{ env.DOCKERHUB_REGISTRY }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
@@ -52,7 +61,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata for GHCR
|
||||
id: meta-ghcr
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
||||
with:
|
||||
images: ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}
|
||||
tags: |
|
||||
@@ -61,7 +70,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata for Docker Hub
|
||||
id: meta-dockerhub
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
||||
with:
|
||||
images: ${{ env.DOCKERHUB_REGISTRY }}/${{ env.DOCKERHUB_IMAGE_NAME }}
|
||||
tags: |
|
||||
@@ -69,7 +78,7 @@ jobs:
|
||||
type=raw,value=latest,enable=${{ inputs.image_tag != 'latest' }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5.4.0
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
@@ -83,7 +92,7 @@ jobs:
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Update Docker Hub description
|
||||
uses: peter-evans/dockerhub-description@v4
|
||||
uses: peter-evans/dockerhub-description@432a30c9e07499fd01da9f8a49f0faf9e0ca5b77 # v4.0.2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -92,15 +101,28 @@ jobs:
|
||||
short-description: "AI trading agent with backtesting. Includes Telegram & Feishu channels."
|
||||
|
||||
- name: Summary
|
||||
# Inputs go through env, never straight into the script body: a
|
||||
# workflow_dispatch input interpolated into `run:` is a shell-injection
|
||||
# vector even when only maintainers can dispatch it.
|
||||
env:
|
||||
IMAGE_TAG: ${{ inputs.image_tag }}
|
||||
GHCR_IMAGE: ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}
|
||||
DOCKERHUB_IMAGE: ${{ env.DOCKERHUB_REGISTRY }}/${{ env.DOCKERHUB_IMAGE_NAME }}
|
||||
run: |
|
||||
echo "### Docker Images Built and Pushed" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**GHCR:** \`${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${{ inputs.image_tag }}\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Docker Hub:** \`${{ env.DOCKERHUB_REGISTRY }}/${{ env.DOCKERHUB_IMAGE_NAME }}:${{ inputs.image_tag }}\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Platforms:** linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Channels:** feishu, telegram" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```bash' >> $GITHUB_STEP_SUMMARY
|
||||
echo "docker pull ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_IMAGE_NAME }}:${{ inputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
{
|
||||
echo "### Docker Images Built and Pushed"
|
||||
echo ""
|
||||
echo "**GHCR:** \`${GHCR_IMAGE}:${IMAGE_TAG}\`"
|
||||
echo "**Docker Hub:** \`${DOCKERHUB_IMAGE}:${IMAGE_TAG}\`"
|
||||
echo ""
|
||||
echo "**Platforms:** linux/amd64, linux/arm64"
|
||||
echo "**Channels:** feishu, telegram (from requirements-channels-lock.txt)"
|
||||
echo ""
|
||||
echo '```bash'
|
||||
echo "docker pull ${GHCR_IMAGE}:${IMAGE_TAG}"
|
||||
echo '```'
|
||||
echo ""
|
||||
echo "> A newly created GHCR package is **private by default**. Until its"
|
||||
echo "> visibility is set to public once in the org package settings, the"
|
||||
echo "> pull above works only for authenticated users with read access."
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
Reference in new issue
Block a user