Skip to content

fix: guard RC docker job against empty vtag and add early validation in docker.yml#983

Merged
magyargergo merged 3 commits into
mainfrom
copilot/guard-docker-job-with-tag-check
Apr 19, 2026
Merged

fix: guard RC docker job against empty vtag and add early validation in docker.yml#983
magyargergo merged 3 commits into
mainfrom
copilot/guard-docker-job-with-tag-check

Conversation

Copilot AI commented Apr 19, 2026

Copy link
Copy Markdown
Contributor

When the publish job in the RC workflow fails before the Create and push rc tags step, needs.publish.outputs.vtag is empty. The docker job still ran, calling docker.yml with no tag, which caused buildx to error with the opaque tag is needed when pushing to registry.

Changes

  • release-candidate.yml — tighten the docker job's if: to skip entirely when vtag is empty:

    if: needs.guard.outputs.should_run == 'true' && needs.publish.outputs.vtag != ''
  • docker.yml — add a fail-fast validation step as the first step in the build job, before any docker setup runs:

    - name: Validate tag input
      shell: bash
      env:
        TAG_INPUT: ${{ inputs.tag }}
      run: |
        if [ -z "${TAG_INPUT}" ]; then
          echo "::error::No tag provided to docker.yml — refusing to build/push."
          exit 1
        fi

    This acts as a second line of defence for any direct workflow_call invocation that bypasses the RC guard.

Original prompt

Background

The Build & Push RC Docker images job in the Release Candidate workflow failed with:

ERROR: failed to build: tag is needed when pushing to registry

Failing run: https://github.com/abhigyanpatwari/GitNexus/actions/runs/24623117763/job/71998787708
Workflow: .github/workflows/release-candidate.yml
Reusable workflow being called: .github/workflows/docker.yml

Root cause

The docker job in .github/workflows/release-candidate.yml calls the reusable docker.yml workflow and passes tag: ${{ needs.publish.outputs.vtag }}. vtag is only set by the Create and push rc tags step inside the publish job. If the publish job fails before that step runs (or the output is otherwise empty), docker.yml is invoked with an empty tag input. docker/build-push-action then runs with push: true but no tags, and buildx errors with "tag is needed when pushing to registry".

Required changes

Please make the following changes:

1. Guard the docker job in .github/workflows/release-candidate.yml

Update the docker job's if: condition to also require that publish.outputs.vtag is non-empty, so the job is skipped (rather than producing a confusing buildx error) when no rc tag was produced:

docker:
  name: Build & Push RC Docker images
  needs: [guard, publish]
  if: needs.guard.outputs.should_run == 'true' && needs.publish.outputs.vtag != ''
  uses: ./.github/workflows/docker.yml
  ...
  with:
    tag: ${{ needs.publish.outputs.vtag }}

2. Validate the tag input inside .github/workflows/docker.yml

Add an early validation step (before any docker build/push step) in .github/workflows/docker.yml that fails fast with a clear error message when the tag input is empty. Something like:

- name: Validate tag input
  shell: bash
  env:
    TAG_INPUT: ${{ inputs.tag }}
  run: |
    if [ -z "${TAG_INPUT}" ]; then
      echo "::error::No tag provided to docker.yml — refusing to build/push."
      exit 1
    fi

Place it as the first step in any job that performs a docker/build-push-action with push: true, before the buildx/build step runs. This ensures the failure is loud and obvious instead of an opaque buildx error.

Acceptance criteria

  • .github/workflows/release-candidate.yml's docker job has an if: that includes needs.publish.outputs.vtag != ''.
  • .github/workflows/docker.yml fails fast with a clear ::error:: message when invoked with an empty tag input.
  • No other behavior changes; existing successful RC flows still build and push images normally.
  • YAML is valid and workflow syntax is correct.

Out of scope

  • Investigating why the publish job itself failed in run 24623117763 (tag/package.json version mismatch and cosign issues). That can be handled in a follow-up.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: How can I fix this build?

Assistant: ## Why the build failed

The failing job is Build & Push RC Docker images (reusable workflow docker.yml, called from release-candidate.yml). Buildx errored with:

ERROR: failed to build: tag is needed when pushing to registry

This means the docker build step ran with push: true but no tags: were resolved. Looking at the caller in .github/workflows/release-candidate.yml (lines 377–388):

docker:
  name: Build & Push RC Docker images
  needs: [guard, publish]
  ...
  uses: ./.github/workflows/docker.yml
  with:
    tag: ${{ needs.publish.outputs.vtag }}

The docker job only needs: [guard, publish], but not ci. Because ci was still running/queued (or finished after publish started), and more importantly because publish.outputs.vtag is only set by the Create and push rc tags step inside publish, the value passed to docker.yml came through empty for this run — so docker/metadata-action (or the tags: input in docker.yml) produced no tag, and buildx refused to push.

In the logs you can confirm publish did not actually emit a vtag for this run before docker consumed it (the publish job's tag-creation step never ran successfully — note there's no rc tag commit in the output, only the buildx push failure).

How to fix

Two things to do — pick one minimally, but I'd recommend both:

1. Guard the docker job against an empty tag

In .github/workflows/release-candidate.yml, tighten the if: so docker only runs when publish actually produced a vtag:

docker:
  name: Build & Push RC Docker images
  needs: [guard, publish]
  if: needs.guard.outputs.should_run == 'true' && needs.publish.outputs.vtag != ''
  uses: ./.github/workflows/docker.yml
  ...
  with:
    tag: ${{ needs.publish.outputs.vtag }}

This makes the failure mode loud and prevents calling docker.yml with an empty tag.

#...

This pull request was created from Copilot chat.

@vercel

vercel Bot commented Apr 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gitnexus Ready Ready Preview, Comment Apr 19, 2026 8:27am

Request Review

- Add `&& needs.publish.outputs.vtag != ''` to the `docker` job's
  `if:` in release-candidate.yml so it is skipped when publish
  produces no vtag, preventing an opaque buildx "tag is needed" error.
- Add an early "Validate tag input" step in docker.yml that fails fast
  with a clear ::error:: message when inputs.tag is empty, covering
  direct workflow_call invocations that bypass the release-candidate
  guard.

Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/b9afe2df-85ea-4a87-bf30-77f0e945a64d

Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix docker job to ensure tag is set before pushing fix: guard RC docker job against empty vtag and add early validation in docker.yml Apr 19, 2026
Copilot AI requested a review from magyargergo April 19, 2026 08:21
@magyargergo

Copy link
Copy Markdown
Collaborator

@claude review this

@github-actions

github-actions Bot commented Apr 19, 2026

Copy link
Copy Markdown
Contributor

Claude finished @magyargergo's task in 1m 13s —— View job


Code Review

  • Gather context
  • Read changed files
  • Analyze changes
  • Post review feedback

Summary

The fix correctly addresses the root cause: docker.yml was being called with an empty tag when publish failed before emitting vtag. Both changes are clean and well-motivated. However, there is one functional bug in docker.yml that would break legitimate direct tag-push invocations.


.github/workflows/release-candidate.yml — ✅ Looks good

- if: needs.guard.outputs.should_run == 'true'
+ if: needs.guard.outputs.should_run == 'true' && needs.publish.outputs.vtag != ''

This is exactly right. Skipping the job at the caller level when no vtag was produced is the primary fix — it prevents a wasted workflow_call invocation entirely and gives a much clearer signal ("job skipped") vs. an opaque buildx error.


.github/workflows/docker.yml⚠️ Bug: breaks direct tag-push triggers

The problem: docker.yml has two triggers:

on:
  push:
    tags:
      - 'v*'
  workflow_call:
    inputs:
      tag:
        required: true
        type: string

When triggered by a direct tag push (on: push), inputs.tag is empty — there is no workflow_call input populated. The new validation step checks TAG_INPUT=${{ inputs.tag }} and exits 1 when it is empty, which means every direct tag-push trigger will now fail before reaching any useful work.

The existing "Verify tag matches gitnexus/package.json version" step already handles this correctly by falling back to GITHUB_REF when INPUT_TAG is empty:

if [ -n "$INPUT_TAG" ]; then
  TAG_VERSION="${INPUT_TAG#v}"
else
  TAG_VERSION="${GITHUB_REF#refs/tags/v}"  # ← handles push events
fi

The new step has no such fallback and will block the push path.

Fix: Scope the validation to workflow_call events only, since that's the only path where an empty tag is a problem:

- name: Validate tag input
  if: github.event_name == 'workflow_call'
  shell: bash
  env:
    TAG_INPUT: ${{ inputs.tag }}
  run: |
    if [ -z "${TAG_INPUT}" ]; then
      echo "::error::No tag provided to docker.yml — refusing to build/push."
      exit 1
    fi

Fix this →


Minor observations

  • Matrix duplication: The validation step runs once per matrix entry (gitnexus-web and gitnexus). With the if: github.event_name == 'workflow_call' guard this remains low-noise, but it's worth knowing both matrix legs will fail independently if somehow called with no tag. Not a bug — just expected matrix behaviour.
  • Injection safety: Using env: TAG_INPUT: ${{ inputs.tag }} and referencing ${TAG_INPUT} in the shell script (rather than inlining ${{ inputs.tag }} directly in the run: block) is the correct, injection-safe pattern. Good.
  • Second line of defence intent: The design rationale (RC guard in release-candidate.yml + early exit in docker.yml for any direct workflow_call invocation) is sound. Once the if: condition is added to the step, both layers work correctly together.

Verdict

One blocking issue: the missing if: github.event_name == 'workflow_call' on the new validation step. Everything else is correct. The fix to release-candidate.yml can merge as-is.

@magyargergo

Copy link
Copy Markdown
Collaborator

Claude finished @magyargergo's task in 1m 13s —— View job

Code Review

  • Gather context
  • Read changed files
  • Analyze changes
  • Post review feedback

Summary

The fix correctly addresses the root cause: docker.yml was being called with an empty tag when publish failed before emitting vtag. Both changes are clean and well-motivated. However, there is one functional bug in docker.yml that would break legitimate direct tag-push invocations.

.github/workflows/release-candidate.yml — ✅ Looks good

- if: needs.guard.outputs.should_run == 'true'
+ if: needs.guard.outputs.should_run == 'true' && needs.publish.outputs.vtag != ''

This is exactly right. Skipping the job at the caller level when no vtag was produced is the primary fix — it prevents a wasted workflow_call invocation entirely and gives a much clearer signal ("job skipped") vs. an opaque buildx error.

.github/workflows/docker.yml⚠️ Bug: breaks direct tag-push triggers

The problem: docker.yml has two triggers:

on:
  push:
    tags:
      - 'v*'
  workflow_call:
    inputs:
      tag:
        required: true
        type: string

When triggered by a direct tag push (on: push), inputs.tag is empty — there is no workflow_call input populated. The new validation step checks TAG_INPUT=${{ inputs.tag }} and exits 1 when it is empty, which means every direct tag-push trigger will now fail before reaching any useful work.

The existing "Verify tag matches gitnexus/package.json version" step already handles this correctly by falling back to GITHUB_REF when INPUT_TAG is empty:

if [ -n "$INPUT_TAG" ]; then
  TAG_VERSION="${INPUT_TAG#v}"
else
  TAG_VERSION="${GITHUB_REF#refs/tags/v}"  # ← handles push events
fi

The new step has no such fallback and will block the push path.

Fix: Scope the validation to workflow_call events only, since that's the only path where an empty tag is a problem:

- name: Validate tag input
  if: github.event_name == 'workflow_call'
  shell: bash
  env:
    TAG_INPUT: ${{ inputs.tag }}
  run: |
    if [ -z "${TAG_INPUT}" ]; then
      echo "::error::No tag provided to docker.yml — refusing to build/push."
      exit 1
    fi

Fix this →

Minor observations

  • Matrix duplication: The validation step runs once per matrix entry (gitnexus-web and gitnexus). With the if: github.event_name == 'workflow_call' guard this remains low-noise, but it's worth knowing both matrix legs will fail independently if somehow called with no tag. Not a bug — just expected matrix behaviour.
  • Injection safety: Using env: TAG_INPUT: ${{ inputs.tag }} and referencing ${TAG_INPUT} in the shell script (rather than inlining ${{ inputs.tag }} directly in the run: block) is the correct, injection-safe pattern. Good.
  • Second line of defence intent: The design rationale (RC guard in release-candidate.yml + early exit in docker.yml for any direct workflow_call invocation) is sound. Once the if: condition is added to the step, both layers work correctly together.

Verdict

One blocking issue: the missing if: github.event_name == 'workflow_call' on the new validation step. Everything else is correct. The fix to release-candidate.yml can merge as-is.

@copilot look into this

Direct tag-push triggers (on: push, tags: v*) populate the tag from
GITHUB_REF and have inputs.tag empty, so the unconditional validation
step would fail every direct tag-push run. Restrict the new step to
workflow_call invocations, which is the only path where an empty tag
is actually a problem.

Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/4b7e3bfa-15c0-4186-affa-95cd71e50153

Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>

Copilot AI commented Apr 19, 2026

Copy link
Copy Markdown
Contributor Author

Claude finished @magyargergo's task in 1m 13s —— View job

Code Review

...

Good catch — added if: github.event_name == 'workflow_call' to the validation step so direct tag-push triggers (where inputs.tag is always empty by design) aren't blocked. The existing "Verify tag matches gitnexus/package.json version" step already handles the GITHUB_REF fallback for that path. Fixed in c61fb6f.

@magyargergo magyargergo marked this pull request as ready for review April 19, 2026 08:33
@magyargergo magyargergo merged commit d976038 into main Apr 19, 2026
14 checks passed
@magyargergo magyargergo deleted the copilot/guard-docker-job-with-tag-check branch April 19, 2026 08:41
github714801013 pushed a commit to github714801013/GitNexus that referenced this pull request Apr 28, 2026
…in docker.yml (abhigyanpatwari#983)

* Initial plan

* fix: guard docker job and add tag validation in docker.yml

- Add `&& needs.publish.outputs.vtag != ''` to the `docker` job's
  `if:` in release-candidate.yml so it is skipped when publish
  produces no vtag, preventing an opaque buildx "tag is needed" error.
- Add an early "Validate tag input" step in docker.yml that fails fast
  with a clear ::error:: message when inputs.tag is empty, covering
  direct workflow_call invocations that bypass the release-candidate
  guard.

Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/b9afe2df-85ea-4a87-bf30-77f0e945a64d

Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>

* fix: scope docker.yml tag validation to workflow_call only

Direct tag-push triggers (on: push, tags: v*) populate the tag from
GITHUB_REF and have inputs.tag empty, so the unconditional validation
step would fail every direct tag-push run. Restrict the new step to
workflow_call invocations, which is the only path where an empty tag
is actually a problem.

Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/4b7e3bfa-15c0-4186-affa-95cd71e50153

Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com>
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