ci: push nightly .devX Docker images to langflowai/langflow and fix db-migration-validation image references (#13836)

* ci: push nightly .devX docker images to langflowai/langflow in addition to langflowai/langflow-nightly

Mirrors PyPI behaviour where .devX releases are published under the
'langflow' package name (not 'langflow-nightly'). The Docker nightly
workflow now tags and pushes every nightly image to both repos:

- langflowai/langflow-nightly:{ver}  (existing)
- langflowai/langflow:{ver}          (new — matches PyPI)
- langflowai/langflow-nightly:latest (existing)
- langflowai/langflow:latest         (new)

Same mirroring applied to the base and main-all variants, and to GHCR.

The arch-specific intermediate tags (used to assemble multi-arch
manifests) remain under the '-nightly' repos; only the final merged
manifests are additionally published to the canonical 'langflow' repos.

Fixes: LE-1667

* ci: update db-migration-validation to use canonical langflowai/langflow image

The db-migration-validation workflow was still referencing the old
langflowai/langflow-nightly image for its nightly upgrade step.
Now that .devX images are also pushed to langflowai/langflow (canonical
repo, matching PyPI), update all consumer-side references:

- nightly_build.yml: nightly_tag now passes langflowai/langflow:<tag>
- db-migration-validation.yml: default and shell fallbacks updated to
  langflowai/langflow:latest; inline comments updated to match

The langflowai/langflow-nightly images remain in use as intermediate
arch-specific staging tags inside docker-nightly-build.yml only.

Relates to: LE-1667

* ci: fix stale langflow-nightly package name reference in comment

The nightly is published as canonical .devN pre-releases of langflow /
langflow-base (not as separate langflow-nightly / langflow-base-nightly
packages). Update the generate-shared-tag step comment to accurately
reflect this since the rename that happened in the 1.10 release cycle.

Relates to: LE-1353, LE-1667

* fix(ci): do not set :latest on canonical langflow repo for nightly .devX images

Nightly .devX images should not overwrite the stable :latest tag on
langflowai/langflow. The :latest (and :base-latest) floating tags are
only set on the -nightly repos (langflowai/langflow-nightly), which
are explicitly nightly-only. The canonical langflowai/langflow repo
only receives the versioned tag (e.g. :1.11.0.dev20250522), matching
PyPI behaviour where langflow==1.11.0.dev20250522 is published but
never becomes the 'latest' release index entry.

Addresses PR review comment from @jordanrfrazier.

Relates to: LE-1667

* fix(ci): prevent shell injection from inputs.nightly_tag in db-migration-validation

Pass inputs.nightly_tag through an env: block and reference it as
$INPUT_NIGHTLY_TAG in the shell script rather than expanding the
GitHub Actions expression directly inside run:. Direct expansion of
${{ inputs.* }} in shell scripts allows an attacker-controlled input
to inject arbitrary shell commands (CWE-78).

Flagged by CodeRabbit security review.

Relates to: LE-1667
This commit is contained in:
vjgit96
2026-06-25 16:39:39 -04:00
committed by Eric Hare
parent 4da60c4b12
commit a277209fe4
3 changed files with 34 additions and 20 deletions

View File

@ -10,10 +10,10 @@ on:
workflow_dispatch:
inputs:
nightly_tag:
description: "Nightly tag to test migration to (e.g., langflowai/langflow-nightly:latest)"
description: "Nightly tag to test migration to (e.g., langflowai/langflow:latest)"
required: false
type: string
default: "langflowai/langflow-nightly:latest"
default: "langflowai/langflow:latest"
# Note: This workflow is called by nightly_build.yml after Docker images are built
env:
@ -155,10 +155,12 @@ jobs:
- name: Upgrade to nightly version
working-directory: migration-test
env:
INPUT_NIGHTLY_TAG: ${{ inputs.nightly_tag }}
run: |
source .venv/bin/activate
NIGHTLY_TAG="${{ inputs.nightly_tag || 'langflowai/langflow-nightly:latest' }}"
NIGHTLY_TAG="${INPUT_NIGHTLY_TAG:-langflowai/langflow:latest}"
echo "Upgrading to nightly version: $NIGHTLY_TAG"
# Remove the stable install first. The nightly now publishes as a `.devN` pre-release of
@ -169,7 +171,7 @@ jobs:
echo "Removing stable langflow to force a clean install of the nightly dev version..."
uv pip uninstall -y langflow langflow-base || true
# Extract version from Docker tag (format: langflowai/langflow-nightly:v1.10.0.dev20260522)
# Extract version from Docker tag (format: langflowai/langflow:v1.10.0.dev20260522)
if [[ "$NIGHTLY_TAG" == *":"* ]]; then
VERSION="${NIGHTLY_TAG##*:}"
echo "Extracted version from tag: $VERSION"
@ -412,10 +414,12 @@ jobs:
- name: Update to nightly image
working-directory: docker-migration-test
env:
INPUT_NIGHTLY_TAG: ${{ inputs.nightly_tag }}
run: |
NIGHTLY_TAG="${{ inputs.nightly_tag || 'langflowai/langflow-nightly:latest' }}"
NIGHTLY_TAG="${INPUT_NIGHTLY_TAG:-langflowai/langflow:latest}"
# Strip 'v' prefix from version part — Docker images are published without it
# e.g. langflowai/langflow-nightly:v1.10.0.dev20260522 → langflowai/langflow-nightly:1.10.0.dev20260522
# e.g. langflowai/langflow:v1.10.0.dev20260522 → langflowai/langflow:1.10.0.dev20260522
VERSION_PART="${NIGHTLY_TAG##*:}"
IMAGE_NAME="${NIGHTLY_TAG%%:*}"
DOCKER_TAG="${IMAGE_NAME}:${VERSION_PART#v}"

View File

@ -92,8 +92,8 @@ jobs:
id: tags
run: |
version="${{ steps.version.outputs.version }}"
echo "docker_tags=langflowai/langflow-nightly:base-${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
echo "ghcr_tags=ghcr.io/langflow-ai/langflow-nightly:base-${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
echo "docker_tags=langflowai/langflow-nightly:base-${version}-${{ matrix.arch }},langflowai/langflow:base-${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
echo "ghcr_tags=ghcr.io/langflow-ai/langflow-nightly:base-${version}-${{ matrix.arch }},ghcr.io/langflow-ai/langflow:base-${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
- name: Docker cleanup
run: |
@ -187,8 +187,8 @@ jobs:
id: tags
run: |
version="${{ steps.version.outputs.version }}"
echo "docker_tags=langflowai/langflow-nightly:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
echo "ghcr_tags=ghcr.io/langflow-ai/langflow-nightly:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
echo "docker_tags=langflowai/langflow-nightly:${version}-${{ matrix.arch }},langflowai/langflow:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
echo "ghcr_tags=ghcr.io/langflow-ai/langflow-nightly:${version}-${{ matrix.arch }},ghcr.io/langflow-ai/langflow:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
- name: Docker cleanup
run: |
@ -282,8 +282,8 @@ jobs:
id: tags
run: |
version="${{ steps.version.outputs.version }}"
echo "docker_tags=langflowai/langflow-nightly-all:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
echo "ghcr_tags=ghcr.io/langflow-ai/langflow-nightly-all:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
echo "docker_tags=langflowai/langflow-nightly-all:${version}-${{ matrix.arch }},langflowai/langflow-all:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
echo "ghcr_tags=ghcr.io/langflow-ai/langflow-nightly-all:${version}-${{ matrix.arch }},ghcr.io/langflow-ai/langflow-all:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT
- name: Docker cleanup
run: |
@ -368,17 +368,26 @@ jobs:
version="${{ steps.version.outputs.version }}"
case "${{ inputs.release_type }}" in
"nightly-base")
echo "final_tags=langflowai/langflow-nightly:base-${version},langflowai/langflow-nightly:base-latest,ghcr.io/langflow-ai/langflow-nightly:base-${version},ghcr.io/langflow-ai/langflow-nightly:base-latest" >> $GITHUB_OUTPUT
# Push versioned tag to canonical langflow repo (matches PyPI langflow-base .devN publish).
# :base-latest is only set on the -nightly repo to avoid overwriting the stable :base-latest
# on langflowai/langflow with a pre-release image.
echo "final_tags=langflowai/langflow-nightly:base-${version},langflowai/langflow-nightly:base-latest,langflowai/langflow:base-${version},ghcr.io/langflow-ai/langflow-nightly:base-${version},ghcr.io/langflow-ai/langflow-nightly:base-latest,ghcr.io/langflow-ai/langflow:base-${version}" >> $GITHUB_OUTPUT
echo "arch_base=langflowai/langflow-nightly:base-${version}" >> $GITHUB_OUTPUT
echo "ghcr_arch_base=ghcr.io/langflow-ai/langflow-nightly:base-${version}" >> $GITHUB_OUTPUT
;;
"nightly-main")
echo "final_tags=langflowai/langflow-nightly:${version},langflowai/langflow-nightly:latest,ghcr.io/langflow-ai/langflow-nightly:${version},ghcr.io/langflow-ai/langflow-nightly:latest" >> $GITHUB_OUTPUT
# Push versioned tag to canonical langflow repo (matches PyPI langflow .devN publish).
# :latest is only set on the -nightly repo to avoid overwriting the stable :latest
# on langflowai/langflow with a pre-release image.
echo "final_tags=langflowai/langflow-nightly:${version},langflowai/langflow-nightly:latest,langflowai/langflow:${version},ghcr.io/langflow-ai/langflow-nightly:${version},ghcr.io/langflow-ai/langflow-nightly:latest,ghcr.io/langflow-ai/langflow:${version}" >> $GITHUB_OUTPUT
echo "arch_base=langflowai/langflow-nightly:${version}" >> $GITHUB_OUTPUT
echo "ghcr_arch_base=ghcr.io/langflow-ai/langflow-nightly:${version}" >> $GITHUB_OUTPUT
;;
"nightly-main-all")
echo "final_tags=langflowai/langflow-nightly-all:${version},langflowai/langflow-nightly-all:latest,ghcr.io/langflow-ai/langflow-nightly-all:${version},ghcr.io/langflow-ai/langflow-nightly-all:latest" >> $GITHUB_OUTPUT
# Push versioned tag to canonical langflow-all repo (matches PyPI publish).
# :latest is only set on the -nightly-all repo to avoid overwriting the stable :latest
# on langflowai/langflow-all with a pre-release image.
echo "final_tags=langflowai/langflow-nightly-all:${version},langflowai/langflow-nightly-all:latest,langflowai/langflow-all:${version},ghcr.io/langflow-ai/langflow-nightly-all:${version},ghcr.io/langflow-ai/langflow-nightly-all:latest,ghcr.io/langflow-ai/langflow-all:${version}" >> $GITHUB_OUTPUT
echo "arch_base=langflowai/langflow-nightly-all:${version}" >> $GITHUB_OUTPUT
echo "ghcr_arch_base=ghcr.io/langflow-ai/langflow-nightly-all:${version}" >> $GITHUB_OUTPUT
;;

View File

@ -110,9 +110,9 @@ jobs:
- name: Generate shared nightly tag (main == base, lockstep)
id: generate_shared_tag
run: |
# langflow-nightly pins langflow-base-nightly[complete]==<exact dev>, so both tags
# MUST be identical. Compute them in ONE invocation (single PyPI snapshot) so they
# cannot drift across separate calls.
# langflow (nightly .devN pre-release) pins langflow-base[complete]==<exact dev>, so
# both tags MUST be identical. Compute them in ONE invocation (single PyPI snapshot)
# so they cannot drift across separate calls.
# NOTE: This outputs the tag with the `v` prefix.
TAGS_OUTPUT="$(uv run ./scripts/ci/pypi_nightly_tag.py both)"
RELEASE_TAG="$(printf '%s\n' "$TAGS_OUTPUT" | sed -n '1p')"
@ -314,8 +314,9 @@ jobs:
with:
# Pass Docker image reference for docker-compose and version without 'v' prefix for pip
# release_tag format: v1.10.0.dev20260522
# We need: langflowai/langflow-nightly:1.10.0.dev20260522 for Docker
nightly_tag: langflowai/langflow-nightly:${{ needs.create-nightly-tag.outputs.release_tag }}
# We need: langflowai/langflow:1.10.0.dev20260522 for Docker (nightly .devX images are
# pushed to the canonical langflowai/langflow repo to match PyPI langflow package naming)
nightly_tag: langflowai/langflow:${{ needs.create-nightly-tag.outputs.release_tag }}
secrets: inherit
slack-notification: