Skip to content

fix(version)!: resolve CLI version from reusable workflow ref - #5357

Merged
rh-hemartin merged 1 commit into
mainfrom
hemartin/resolve-sha-to-release
Jul 31, 2026
Merged

fix(version)!: resolve CLI version from reusable workflow ref#5357
rh-hemartin merged 1 commit into
mainfrom
hemartin/resolve-sha-to-release

Conversation

@rh-hemartin

@rh-hemartin rh-hemartin commented Jul 20, 2026

Copy link
Copy Markdown
Member

Summary

  • Default fullsend_version to "" across reusable workflows so callers that omit it fall through to job.workflow_sha instead of latest, preventing version skew between the workflow ref and the CLI binary (fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369)
  • Add SHA-to-tag resolution in both the install action (.github/actions/install-fullsend-cli/action.yml) and the root action.yml, so a 40-char commit SHA is mapped to its release tag before download, avoiding unnecessary source builds
  • Paginate tag lookups, use safe jq parameterization (--arg), derive OS/arch from runner context instead of hardcoding linux, and add a source-build fallback when the release download fails
  • When no tag matches, the existing source-build fallback is preserved

Breaking change

fullsend_version in reusable workflows now defaults to the workflow SHA instead of "latest". Callers that omit fullsend_version and want the previous behavior should pass fullsend_version: "latest" explicitly.

Closes #3369

Test plan

  • Tested on rh-hemartin-fullsendai/standalone-fullsend run 29739450357 — confirmed the source-build fallback triggers when SHA resolution is missing
  • Re-run the same caller with this branch to verify the SHA resolves to v0.31.0 and downloads the pre-built binary
  • Verify a non-tagged SHA still falls back to source build
  • Verify version: latest and version: v0.31.0 paths are unaffected

🤖 Generated with Claude Code

@rh-hemartin
rh-hemartin requested a review from a team as a code owner July 20, 2026 13:49
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

CI: resolve workflow SHA to release tag for Fullsend CLI installs

🐞 Bug fix ✨ Enhancement ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Default reusable workflow fullsend_version to empty to avoid latest skew.
• Resolve 40-char SHAs to release tags to download GoReleaser binaries.
• Preserve source-build fallback when no matching tag exists.
Diagram

graph TD
  A["Caller workflow"] --> B["Reusable workflows"] --> C["Fullsend action (action.yml)"] --> D["Install decision"]
  D --> E["Resolve SHA->tag"] --> F["GitHub API (tags/releases)"] --> G["Release artifact"]
  D --> H["Source build"]
  subgraph Legend
    direction LR
    _wf["Workflow"] ~~~ _act["Composite action"] ~~~ _ext["GitHub API"]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Resolve SHA via git tags after shallow fetch
  • ➕ No dependence on GitHub tags API page size (100) or pagination logic
  • ➕ Can precisely detect tags pointing at the fetched commit
  • ➖ Requires cloning/fetching tags even when a release artifact exists
  • ➖ More network and time cost; defeats some of the optimization goal
2. Paginate tag resolution (API loop) until match or exhaustion
  • ➕ Keeps the fast-path download approach while avoiding 100-tag blind spots
  • ➕ More robust as tag history grows
  • ➖ More scripting complexity and API calls (rate limits)
  • ➖ Needs careful handling of retries/fail-open behavior

Recommendation: The PR’s approach (best-effort SHA→tag resolution with a preserved source-build fallback) is the right default for CI: it improves performance without breaking untagged SHAs. Consider a follow-up enhancement to paginate tag lookup (or switch to a git-based tag check) if the repository’s tag count makes the current per_page=100 approach unreliable over time.

Files changed (9) +82 / -24

Enhancement (2) +62 / -4
action.ymlPrefer release artifact when workflow SHA matches a tag +48/-4

Prefer release artifact when workflow SHA matches a tag

• Adds a SHA-to-tag resolution step for upstream installs and downloads the corresponding GoReleaser release asset when found. Gates Go setup and source build steps behind the 'no tag found' condition while preserving the original build-from-source fallback.

.github/actions/install-fullsend-cli/action.yml

action.ymlResolve SHA version inputs to release tags before install +14/-0

Resolve SHA version inputs to release tags before install

• Enhances the top-level composite action’s install detection to map 40-character SHAs to matching 'v*' tags via the GitHub API. This allows the action to take the existing release-download path instead of falling back to source builds when a release exists.

action.yml

Other (7) +20 / -20
reusable-code.ymlDefault CLI version to workflow SHA when input omitted +2/-2

Default CLI version to workflow SHA when input omitted

• Changes 'fullsend_version' default from 'latest' to empty and updates the Fullsend action invocation to use 'inputs.fullsend_version || job.workflow_sha'. This prevents callers that omit the version from unintentionally pinning the CLI to 'latest'.

.github/workflows/reusable-code.yml

reusable-dispatch.ymlUse workflow SHA as implicit CLI version across dispatch stages +8/-8

Use workflow SHA as implicit CLI version across dispatch stages

• Sets 'fullsend_version' input default to empty and updates all stage invocations to fall back to 'job.workflow_sha' when the input is unset. Aligns the CLI binary version with the workflow ref to avoid version skew.

.github/workflows/reusable-dispatch.yml

reusable-fix.ymlAlign fix workflow CLI version with workflow SHA by default +2/-2

Align fix workflow CLI version with workflow SHA by default

• Defaults 'fullsend_version' to empty and passes 'inputs.fullsend_version || job.workflow_sha' into the Fullsend action. Ensures fix runs use the CLI corresponding to the workflow ref unless explicitly overridden.

.github/workflows/reusable-fix.yml

reusable-prioritize.ymlAlign prioritize workflow CLI version with workflow SHA by default +2/-2

Align prioritize workflow CLI version with workflow SHA by default

• Defaults 'fullsend_version' to empty and updates the action call to fall back to 'job.workflow_sha'. Reduces unexpected upgrades caused by implicit 'latest' installs.

.github/workflows/reusable-prioritize.yml

reusable-retro.ymlAlign retro workflow CLI version with workflow SHA by default +2/-2

Align retro workflow CLI version with workflow SHA by default

• Defaults 'fullsend_version' to empty and ensures the invoked action uses 'job.workflow_sha' when the input is not set. Keeps workflow ref and CLI binary consistent.

.github/workflows/reusable-retro.yml

reusable-review.ymlAlign review workflow CLI version with workflow SHA by default +2/-2

Align review workflow CLI version with workflow SHA by default

• Defaults 'fullsend_version' to empty and updates the Fullsend action invocation to use 'inputs.fullsend_version || job.workflow_sha'. Avoids accidental 'latest' installs when callers omit the input.

.github/workflows/reusable-review.yml

reusable-triage.ymlAlign triage workflow CLI version with workflow SHA by default +2/-2

Align triage workflow CLI version with workflow SHA by default

• Defaults 'fullsend_version' to empty and passes 'inputs.fullsend_version || job.workflow_sha' to the Fullsend action. Ensures triage uses the CLI corresponding to the workflow revision.

.github/workflows/reusable-triage.yml

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 20, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 1:51 PM UTC · Ended 1:53 PM UTC
Commit: 586fd4f · View workflow run →

@rh-hemartin
rh-hemartin force-pushed the hemartin/resolve-sha-to-release branch from 586fd4f to a738f3a Compare July 20, 2026 13:53
@rh-hemartin rh-hemartin changed the title feat(ci): resolve SHA to release tag for CLI install fix(version): resolve CLI version from reusable workflow ref Jul 20, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 20, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 1:55 PM UTC · Ended 2:03 PM UTC
Commit: a738f3a · View workflow run →

@qodo-code-review

qodo-code-review Bot commented Jul 20, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 54 rules

Grey Divider


Remediation recommended

1. Unpaged tags lookup ✓ Resolved 🐞 Bug ➹ Performance
Description
Both the composite installer and the root action’s SHA→tag resolution fetch only the first 100 tags
(per_page=100) without pagination, so repositories with more than 100 tags can fail to find an
existing matching release tag. When that happens, the action incorrectly falls back to the
source-build path instead of using the pre-built release artifact.
Code

.github/actions/install-fullsend-cli/action.yml[R59-62]

+        TAG=$(gh api "repos/${WORKFLOW_REPOSITORY}/tags?per_page=100" \
+          --jq ".[] | select(.commit.sha == \"${WORKFLOW_SHA}\") | .name" \
+          | grep '^v[0-9]' | head -1) || true
+        echo "tag=${TAG}" >> "${GITHUB_OUTPUT}"
Relevance

●●● Strong

Team has accepted pagination fixes for per_page=100 truncation (added --paginate) in PR #225 and
#2398.

PR-#225
PR-#2398

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The cited implementations perform a single tags API request capped at 100 items and then search only
within that truncated response, which cannot reliably resolve a SHA to a tag once the repository has
more than 100 tags. The repo already demonstrates an established approach for complete API
enumeration by using gh api --paginate in other workflows, indicating pagination is the expected
pattern when correctness depends on scanning all results.

.github/actions/install-fullsend-cli/action.yml[49-67]
.github/workflows/e2e.yml[115-130]
action.yml[118-130]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
SHA→tag resolution is implemented with a single `.../tags?per_page=100` request and no pagination, so if the matching tag is beyond the first page the lookup fails and the action unnecessarily takes the source-build path (skipping the pre-built release artifact even though it exists).

## Issue Context
- The composite installer currently uses `gh api` for the tags request, but it limits results to 100 and does not paginate.
- The repo already uses `gh api --paginate` elsewhere when complete results are required, showing pagination is an established pattern.
- The root action’s SHA→tag resolution currently uses `curl` (not `gh`) for API calls, so pagination either needs to be implemented in bash (e.g., looping over `page=`) or the action needs to intentionally add/standardize on a `gh` dependency.
- Optional hardening noted in the findings: normalize/validate `WORKFLOW_SHA` (e.g., lowercase + 40-hex check) to reduce surprising lookup failures.

## Fix Focus Areas
- .github/actions/install-fullsend-cli/action.yml[49-67]
- .github/workflows/e2e.yml[115-130]
- action.yml[118-130]

## Suggested fix
1. **Add pagination to tag fetching so the lookup is complete**
  - For the composite action (using `gh`): switch to `gh api "repos/${WORKFLOW_REPOSITORY}/tags?per_page=100" --paginate`.
  - Because `--paginate` returns multiple JSON arrays, combine pages before filtering (e.g., `jq -s 'add | ...'`), or use `jq -rs` to read/merge all pages.
  - For the root action (using `curl`): implement a bounded `page=1..N` loop fetching `tags?per_page=100&page=$page`, stopping when a match is found or when the returned array is empty.
2. **Make the SHA matching/filtering more robust**
  - Avoid string interpolation inside a jq program; pass the SHA as an argument (e.g., `jq ... --arg sha "$WORKFLOW_SHA" '... select(.commit.sha == $sha) ...'`).
3. **(Optional hardening + debuggability)**
  - Normalize/validate the SHA prior to lookup (accept `[0-9a-fA-F]{40}` then lowercase).
  - Preserve non-fatal behavior when no match is found (keep existing `|| true` behavior where applicable), and add a short log line when pagination exhausts without a match to aid debugging.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Linux-only release download ✓ Resolved 🐞 Bug ≡ Correctness
Description
The new install-release step in the composite installer hard-codes a Linux asset name
(..._linux_${ARCH}.tar.gz), so running the reusable workflow on a non-Linux runner_image will
download the wrong artifact and fail the job (no source-build fallback runs once a tag is resolved).
Code

.github/actions/install-fullsend-cli/action.yml[R79-88]

+        VERSION="${TAG#v}"
+        ARCH="$(uname -m)"
+        [[ "${ARCH}" == "x86_64" ]] && ARCH="amd64"
+        [[ "${ARCH}" == "aarch64" ]] && ARCH="arm64"
+        ASSET="fullsend_${VERSION}_linux_${ARCH}.tar.gz"
+        mkdir -p "${RUNNER_TEMP}/fullsend"
+        echo "Downloading ${ASSET} from release ${TAG}"
+        gh release download "${TAG}" -R "${WORKFLOW_REPOSITORY}" -p "${ASSET}" -D "${RUNNER_TEMP}/fullsend"
+        tar -xzf "${RUNNER_TEMP}/fullsend/${ASSET}" -C "${RUNNER_TEMP}/fullsend"
+        rm -f "${RUNNER_TEMP}/fullsend/${ASSET}"
Relevance

●● Moderate

No clear historical evidence on enforcing cross-runner OS asset naming in composite installers.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The composite action constructs a Linux-only asset name, while the reusable workflow explicitly
allows choosing the runner image. The repo’s root action already demonstrates the intended
cross-platform OS/arch mapping logic, highlighting the inconsistency.

.github/actions/install-fullsend-cli/action.yml[69-91]
.github/workflows/reusable-dispatch.yml[57-62]
action.yml[171-217]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The composite action `.github/actions/install-fullsend-cli` downloads `fullsend_${VERSION}_linux_${ARCH}.tar.gz` when a release tag is resolved. This is Linux-specific and can break installs on non-Linux runners (or custom runner images), and because the source-build steps are gated on `steps.resolve-tag.outputs.tag == ''`, there is no fallback if the download step fails.

## Issue Context
- Reusable workflows allow selecting `runner_image` (default `ubuntu-24.04`), so non-Linux runners are possible.
- The root `action.yml` already implements correct OS/arch mapping for release assets.

## Fix Focus Areas
- .github/actions/install-fullsend-cli/action.yml[69-91]
- .github/workflows/reusable-dispatch.yml[57-62]
- action.yml[171-223]

## Suggested fix
1. In `install-release`, derive `os` and `arch` similarly to the root action (use `${{ runner.os }}` / `${{ runner.arch }}` passed via `env`, or `uname -s` + `uname -m`) and construct `ASSET_NAME="fullsend_${VERSION}_${os}_${arch}.tar.gz"`.
2. Alternatively, explicitly gate the release-download step to Linux only (and keep source build for other OSes).
3. Consider adding a guarded fallback: if download/extract fails, run the source-build path (e.g., via `continue-on-error: true` on download and a subsequent conditional build step) if that behavior is desired.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Direct api.github.com call 📘 Rule violation ⌂ Architecture
Description
The root action.yml adds a direct GitHub REST API call (including GitHub-specific headers) outside
internal/forge/github/, which violates the repository policy to centralize GitHub API interactions
in the forge GitHub layer.
Code

action.yml[R120-125]

+          TAG=$(retry_curl -fsSL \
+            -H "Accept: application/vnd.github+json" \
+            -H "Authorization: Bearer ${GH_TOKEN}" \
+            "https://api.github.com/repos/fullsend-ai/fullsend/tags?per_page=100" \
+            | jq -r --arg sha "${VERSION}" '.[] | select(.commit.sha == $sha) | .name' \
+            | grep '^v[0-9]' | head -1) || true
Relevance

● Weak

Similar “avoid direct api.github.com / centralize in forge” suggestions were rejected previously (PR
#4901, #1333).

PR-#4901
PR-#1333

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 1062054 restricts direct GitHub API calls (including hardcoded api.github.com
URLs and GitHub-specific headers) to internal/forge/github/. The change in action.yml adds a
retry_curl call to https://api.github.com/repos/fullsend-ai/fullsend/tags... with `Accept:
application/vnd.github+json and Authorization: Bearer ...`, which is outside the allowed
directory.

Rule 1062054: Restrict direct GitHub API calls to internal/forge/github
action.yml[118-130]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`action.yml` makes a direct request to `https://api.github.com/...` and sets GitHub-specific headers outside `internal/forge/github/`, which violates the rule restricting direct GitHub API calls.

## Issue Context
The new logic resolves a 40-char SHA to a release tag using the GitHub tags API. The compliance requirement is that GitHub API specifics (URLs/headers) should live in `internal/forge/github/` and be consumed via an abstraction.

## Fix Focus Areas
- action.yml[118-130]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread .github/actions/install-fullsend-cli/action.yml
Comment thread .github/actions/install-fullsend-cli/action.yml Outdated
@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@rh-hemartin
rh-hemartin force-pushed the hemartin/resolve-sha-to-release branch from a738f3a to eedfa3e Compare July 20, 2026 14:02
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 20, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 2:04 PM UTC · Completed 2:19 PM UTC
Commit: eedfa3e · View workflow run →

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown

Site preview

Preview: https://ca78803d-site.fullsend-ai.workers.dev

Commit: 0e86cb3a076b5f7b85023883c6f2d7cea1acf66b

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Multi-agent review (3 agents: Claude ×2, Grok). 2 unique findings posted inline; 2 additional MEDIUM findings (Linux-only asset name, tags pagination) already covered by existing qodo comments — not re-posted.

Comment thread .github/actions/install-fullsend-cli/action.yml
Comment thread .github/actions/install-fullsend-cli/action.yml
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review

Findings

Medium

  • [error-handling-gap] .github/actions/install-fullsend-cli/action.yml:174 — When workflow_sha is empty (GHES scenario) and the release download fails, the source-build fallback step uses WORKFLOW_SHA: ${{ inputs.workflow_sha }} (empty string) instead of the resolved tag from steps.resolve-tag.outputs.tag. The git fetch and git checkout commands will fail with an empty ref, breaking the source-build fallback in this edge case. In contrast, action.yml correctly provides a fallback chain via steps.detect.outputs.source-ref || steps.detect.outputs.version-url.
    Remediation: Change the WORKFLOW_SHA env var in the clone step to: WORKFLOW_SHA: ${{ inputs.workflow_sha || steps.resolve-tag.outputs.tag }}.

  • [protected-path] .github/ — This PR modifies 8 files under .github/ (a protected path): .github/actions/install-fullsend-cli/action.yml, .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-prioritize.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml. The PR links to issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 and explains the rationale for the changes. Human approval is required for protected-path changes regardless of context.

Low

  • [error-handling-gap] action.yml:215 — The download-release step has continue-on-error: true, so OS/arch validation errors (exit 1 for unsupported OS or architecture) are swallowed and the workflow falls through to source build. The job will still fail at later Linux-specific steps (Podman, systemd), so the impact is limited to delayed/confusing error messages.

  • [annotation-stderr-divergence] action.yml — The PR adds >&2 to GitHub Actions workflow annotations (::error::, ::warning::) in the retry_curl function. The established codebase convention is to write workflow annotations to stdout without >&2. GitHub Actions processes annotations identically from both streams, so this is a consistency concern rather than a functional issue.

  • [function-duplication] .github/actions/install-fullsend-cli/action.ymlretry() is defined in two steps within the same composite action ("Resolve SHA to release tag" and "Download pre-built binary from release"). Each composite action step has its own shell scope so duplication is structurally required. Note: the two implementations differ (the resolve-tag version captures output to a tmpfile); cross-reference comments would aid maintenance.

  • [function-duplication] action.ymlretry_curl() is defined in two steps within the same composite action ("Detect install method" and "Download release binary"). Same structural constraint; the two copies use different error messages. Cross-reference comments would aid maintenance.

  • [stale-doc] docs/guides/dev/testing-workflows.md:14 — The testing-workflows guide's description of the version resolution flow is now incomplete. The guide omits the new intermediate steps added in this PR: SHA-to-release-tag resolution and pre-built binary download, with source build as final fallback only when both earlier steps fail. The guide's core testing advice remains valid.

Previous run

Review

Findings

Medium

  • [error-handling-gap] .github/actions/install-fullsend-cli/action.yml:174 — When workflow_sha is empty (GHES scenario) and the release download fails, the source-build fallback step uses WORKFLOW_SHA: ${{ inputs.workflow_sha }} (empty string) instead of the resolved tag from steps.resolve-tag.outputs.tag. The git fetch and git checkout commands will fail with an empty ref, breaking the source-build fallback in this edge case. In contrast, action.yml correctly provides a fallback chain via steps.detect.outputs.source-ref || steps.detect.outputs.version-url.
    Remediation: Change the WORKFLOW_SHA env var in the clone step to: WORKFLOW_SHA: ${{ inputs.workflow_sha || steps.resolve-tag.outputs.tag }}.

  • [protected-path] .github/ — This PR modifies 8 files under .github/ (a protected path): .github/actions/install-fullsend-cli/action.yml, .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-prioritize.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml. The PR links to issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 and explains the rationale for the changes. Human approval is required for protected-path changes regardless of context.

Low

  • [error-handling-gap] action.yml:200 — The download-release step has continue-on-error: true, so OS/arch validation errors (exit 1 for unsupported OS or architecture) are swallowed and the workflow falls through to source build. The job will still fail at later Linux-specific steps (Podman, systemd), so the impact is limited to delayed/confusing error messages.

  • [annotation-stderr-divergence] action.yml — The PR adds >&2 to GitHub Actions workflow annotations (::error::, ::warning::) in the retry_curl function. The established codebase convention is to write workflow annotations to stdout without >&2. GitHub Actions processes annotations identically from both streams, so this is a consistency concern rather than a functional issue.

  • [function-duplication] .github/actions/install-fullsend-cli/action.ymlretry() is defined in two steps within the same composite action ("Resolve SHA to release tag" and "Download pre-built binary from release"). Each composite action step has its own shell scope so duplication is structurally required. Note: the two implementations differ (the resolve-tag version captures output to a tmpfile); cross-reference comments would aid maintenance.

  • [function-duplication] action.ymlretry_curl() is defined in two steps within the same composite action ("Detect install method" and "Download release binary"). Same structural constraint; the two copies use different error messages. Cross-reference comments would aid maintenance.

  • [stale-doc] docs/guides/dev/testing-workflows.md:14 — The testing-workflows guide's description of the version resolution flow is now incomplete. The guide omits the new intermediate steps added in this PR: SHA-to-release-tag resolution and pre-built binary download, with source build as final fallback only when both earlier steps fail. The guide's core testing advice remains valid.

Previous run (2)

Review

Findings

Medium

  • [error-handling-gap] .github/actions/install-fullsend-cli/action.yml:132 — When workflow_sha is empty (GHES scenario) and the release download fails, the source-build fallback step uses WORKFLOW_SHA: ${{ inputs.workflow_sha }} (empty string) instead of the resolved tag from steps.resolve-tag.outputs.tag. The git fetch and git checkout commands will fail with an empty ref, breaking the source-build fallback in this edge case. In contrast, action.yml correctly provides a fallback chain via steps.detect.outputs.source-ref || steps.detect.outputs.version-url.
    Remediation: Change the WORKFLOW_SHA env var in the clone step to: WORKFLOW_SHA: ${{ inputs.workflow_sha || steps.resolve-tag.outputs.tag }}.

  • [breaking-change] action.yml:17 — The root action.yml (GitHub Marketplace action) changes the version input from default: latest to required: true with no default. External callers that relied on the implicit default will fail immediately with an empty-version guard. The PR title correctly marks this as a breaking change (fix(version)!:) and the PR body includes migration guidance. Ensure the breaking change is communicated in release notes.

  • [behavioral-change] .github/workflows/reusable-code.yml:29 (and 6 other reusable workflows) — The fullsend_version input default changes from "latest" to "" with a || job.workflow_sha fallback expression. External repositories calling these reusable workflows and omitting fullsend_version will now get the CLI version matching the workflow's commit SHA instead of the latest release. This is the intended fix for fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369. See also: [input-default-change] finding below.

  • [protected-path] .github/ — This PR modifies 8 files under .github/ (a protected path): .github/actions/install-fullsend-cli/action.yml, .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-prioritize.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml. The PR links to issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 and explains the rationale for the changes. Human approval is required for protected-path changes regardless of context.

Low

  • [annotation-stderr-divergence] action.yml:74 — The PR adds >&2 to GitHub Actions workflow annotations (::error::, ::warning::) in the retry_curl function. The established codebase convention is to write workflow annotations to stdout without >&2. GitHub Actions processes annotations from both stdout and stderr, but mixing conventions creates inconsistency within the same file.

  • [scope-creep] action.yml:228 — The root action.yml now enforces Linux-only via a hard error, replacing the previous dynamic OS/arch mapping. While technically outside the scope of fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369, the action already implicitly required Linux: subsequent steps install podman, check cgroups v2, and start systemd user services. The previous macOS/darwin mapping was effectively dead code. The Linux-only enforcement is a fail-fast improvement, not a functional restriction. Consider documenting in the BREAKING CHANGE trailer.

  • [error-handling-gap] action.yml:199 — The download-release step has continue-on-error: true, so OS/arch validation errors (exit 1 for unsupported OS or architecture) are swallowed and the workflow falls through to source build. The job will still fail at later Linux-specific steps (Podman, systemd), so the impact is limited to delayed/confusing error messages.

  • [error-message-format] action.yml:104 — The validation error for empty version uses a bare echo ('Empty version, version is a required field.') without the ::error:: annotation prefix. Every other fatal validation failure in the repo's actions uses the ::error:: prefix for consistency and visibility in the GitHub Actions UI.

  • [function-duplication] .github/actions/install-fullsend-cli/action.yml:59retry() is defined identically in two steps within the same composite action ("Resolve SHA to release tag" and "Download pre-built binary from release"). Each composite action step has its own shell scope so duplication is structurally required, but cross-reference comments would aid maintenance.

  • [function-duplication] action.yml:66retry_curl() is defined identically in two steps within the same composite action ("Detect install method" and "Download release binary"). Same structural constraint; cross-reference comments would aid maintenance.

  • [scope-consistency] .github/actions/install-fullsend-cli/action.yml — SHA-to-tag resolution uses gh api --paginate + jq in this file vs manual pagination with retry_curl and a 50-page cap in action.yml. The divergence is justified by different execution contexts: the composite action has gh CLI available while the standalone marketplace action uses curl for broader compatibility.

  • [stale-doc] docs/plans/automatic-updates.md:16 — The plan document's "Current state" section says the CLI defaults to "latest". This is now outdated: action.yml requires an explicit version with no default, and the reusable workflows default to empty string with job.workflow_sha fallback.

  • [stale-doc] docs/guides/dev/testing-workflows.md:14 — The testing-workflows guide's description of the version resolution flow is now incomplete. The guide omits the new intermediate steps added in this PR: SHA-to-release-tag resolution and pre-built binary download, with source build as final fallback only when both earlier steps fail. The guide's core testing advice remains valid.

Previous run (3)

Review

Findings

Medium

  • [breaking-change] action.yml:17 — The root action.yml (GitHub Marketplace action) changes the version input from default: latest to required: true with no default. External callers that relied on the implicit default will need to add version: latest (or another explicit version) to avoid workflow failures. The PR title correctly marks this as a breaking change (fix(version)!:) and the PR body includes migration guidance. Ensure the breaking change is communicated in release notes.

  • [behavioral-change] .github/workflows/reusable-code.yml:29 (and 6 other reusable workflows) — The fullsend_version input default changes from "latest" to "" with a || job.workflow_sha fallback expression. External repositories calling these reusable workflows and omitting fullsend_version will now get the CLI version matching the workflow's commit SHA instead of the latest release. This is the intended fix for fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369. See also: [input-default-change] finding below.

  • [protected-path] .github/ — This PR modifies 8 files under .github/ (a protected path): .github/actions/install-fullsend-cli/action.yml, .github/workflows/reusable-code.yml, .github/workflows/reusable-dispatch.yml, .github/workflows/reusable-fix.yml, .github/workflows/reusable-prioritize.yml, .github/workflows/reusable-retro.yml, .github/workflows/reusable-review.yml, .github/workflows/reusable-triage.yml. The PR links to issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 and explains the rationale for the changes. Human approval is required for protected-path changes regardless of context.

Low

  • [input-default-change] .github/workflows/reusable-code.yml:29 — The fullsend_version input default changed from "latest" to "" across all 7 reusable workflows. Combined with the expression change to ${{ inputs.fullsend_version || job.workflow_sha }}, callers that omit fullsend_version will receive the CLI version matching job.workflow_sha instead of the latest release. This is a properly documented breaking change: the PR title uses the ! suffix and the PR body includes migration guidance. See also: [behavioral-change] finding above.

  • [error-handling-gap] action.yml:199 — The download-release step has continue-on-error: true, so OS/arch validation errors (exit 1 for unsupported OS or architecture) are swallowed and the workflow falls through to source build. The job will still fail at later Linux-specific steps (Podman, systemd), so the impact is limited to delayed/confusing error messages.

  • [function-duplication] .github/actions/install-fullsend-cli/action.yml:59retry() is defined identically in two steps within the same composite action ("Resolve SHA to release tag" and "Download pre-built binary from release"). Each composite action step has its own shell scope so duplication is structurally required, but cross-reference comments would aid maintenance.

  • [function-duplication] action.yml:66retry_curl() is defined identically in two steps within the same composite action ("Detect install method" and "Download release binary"). Same structural constraint; cross-reference comments would aid maintenance.

  • [scope-consistency] .github/actions/install-fullsend-cli/action.yml — SHA-to-tag resolution uses gh api --paginate + jq in this file vs manual pagination with retry_curl and a 50-page cap in action.yml. The divergence is justified by different execution contexts: the composite action has gh CLI available while the standalone marketplace action uses curl for broader compatibility.

  • [os-arch-normalization-divergence] .github/actions/install-fullsend-cli/action.yml — OS/arch normalization uses case-insensitive matching with broader platform support (macos→darwin, x86→386, aarch64→arm64) while action.yml uses strict Linux-only enforcement with case-sensitive X64/ARM64 matching. Divergence justified by action.yml's explicit Linux-only requirement (Podman, systemd, cgroups v2).

  • [stale-doc] docs/guides/dev/testing-workflows.md:14 — The testing-workflows guide's description of the version resolution flow could be more complete now that SHA-to-tag resolution and release download retry/fallback have been added. The guide's core advice remains valid but omits the new intermediate steps.

  • [stale-doc] docs/plans/automatic-updates.md:16 — The plan document's "Current state" section says the CLI defaults to "latest". This is now outdated: action.yml requires an explicit version with no default, and the reusable workflows default to empty string with job.workflow_sha fallback.

Previous run (4)

Review

Findings

Medium

  • [stale-doc] docs/guides/dev/testing-workflows.md:14 — The testing-workflows guide's description of the version resolution flow is now incomplete. The version resolution chain is now: caller-supplied version → job.workflow_sha fallback → SHA-to-tag resolution → release download (with retry and continue-on-error) → source build fallback. The guide omits the SHA-to-tag resolution step and the changed default from "latest" to "".

  • [edge-case] action.yml:102 — When action.yml receives an empty-string version input, lines 102–103 silently default it to "latest" via ${VERSION:-latest}. While the reusable workflows always provide || job.workflow_sha, any future direct caller that passes an empty version will silently get "latest" — the same failure mode this PR intends to eliminate. Consider emitting a warning when the version falls through to "latest".

  • [stale-doc] action.yml:17 — The version input description says "Release tag or version: use latest, v0.0.1, or 0.0.1" but this PR adds SHA-to-tag resolution that accepts a full 40-character commit SHA. The description does not mention SHA acceptance.

  • [expression-interpolation-inconsistency] .github/actions/install-fullsend-cli/action.yml:148${{ steps.install-release.outcome }} is interpolated directly into the run: script body. The equivalent code in action.yml uses env var indirection (DOWNLOAD_OUTCOME: ${{ steps.download-release.outcome }}). Exploitation is infeasible (GHA-controlled enum: success/failure/cancelled/skipped), but the inconsistency deviates from the repo's own hardening convention.

  • [function-duplication] .github/actions/install-fullsend-cli/action.yml:59retry() is defined identically in two steps within the same composite action ("Resolve SHA to release tag" and "Download pre-built binary from release"). Each composite action step has its own shell scope so duplication is structurally required, but cross-reference comments should be added to keep the two copies in sync.

  • [protected-path] .github/ — This PR modifies 8 files under .github/ (a protected path). The PR links to issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 and explains the rationale for the changes. Human approval is required for protected-path changes regardless of context.

Low

  • [input-default-change] .github/workflows/reusable-code.yml:29 — The fullsend_version input default changed from "latest" to "" across all 7 reusable workflows. Combined with the expression change to ${{ inputs.fullsend_version || job.workflow_sha }}, callers that omit fullsend_version will receive the CLI version matching job.workflow_sha instead of the latest release. This is a properly documented breaking change: the PR title uses the ! suffix (fix(version)!:) and the PR body includes migration guidance.

  • [error-handling-gap] action.yml:158 — Adding continue-on-error: true to the download-release step means OS/arch validation errors (exit 1 for unsupported OS or architecture) are swallowed, and the workflow falls through to source build. The job will still fail at later Linux-specific steps (Install Podman), so the impact is limited to delayed/confusing error messages. Consider moving OS/arch validation into the detect step.

  • [scope-consistency] .github/actions/install-fullsend-cli/action.yml — SHA-to-tag resolution uses gh api --paginate + jq in this file vs manual pagination with retry_curl and a 50-page cap in action.yml. The divergence is justified by different execution contexts: the composite action has gh CLI available while the standalone marketplace action uses curl for broader compatibility. Cross-reference comments would aid future maintenance.

  • [os-arch-normalization-divergence] .github/actions/install-fullsend-cli/action.yml — OS/arch normalization uses case-insensitive matching with broader platform support (macos→darwin, x86→386, aarch64→arm64) while action.yml uses strict case-sensitive matching (X64, ARM64 only) with hard errors. The divergence is intentional (action.yml requires Linux for Podman) but should be documented with inline comments.

  • [stale-doc] docs/plans/automatic-updates.md:16 — The plan document's "Current state" section says the CLI defaults to "latest". This remains literally true for the root action.yml (default: latest), but the reusable workflow inputs now default to empty string with job.workflow_sha fallback.

Previous run (5)

Review

Findings

Medium

  • [input-default-change] .github/workflows/reusable-code.yml (and 7 other reusable workflows) — The fullsend_version input default changed from "latest" to "" across all reusable workflows. Callers that omit this input will now receive the CLI version matching job.workflow_sha instead of the latest release. This is a properly documented breaking change: the PR title uses the ! suffix (fix(version)!:) and the PR body includes migration guidance ("pass fullsend_version: 'latest' explicitly").

  • [protected-path] .github/ — This PR modifies 8 files under .github/ (a protected path). The PR links to issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 and explains the rationale for the changes. Human approval is required for protected-path changes regardless of context.

Low

  • [error-handling-gap] action.yml — Adding continue-on-error: true to the download-release step means OS/arch validation errors (exit 1 for unsupported OS or architecture) are swallowed, and the workflow falls through to source build. The job will still fail at later Linux-specific steps (Install Podman), so the impact is limited to delayed/confusing error messages rather than incorrect artifacts. Consider moving OS/arch validation into the detect step.

  • [injection-pattern] .github/actions/install-fullsend-cli/action.yml${{ steps.install-release.outcome }} is interpolated directly into the run: script body rather than via an env: variable. The equivalent code in action.yml correctly uses DOWNLOAD_OUTCOME env var indirection. Exploitation is infeasible (GHA-controlled values), but the inconsistency should be aligned.

  • [code-duplication-divergence] .github/actions/install-fullsend-cli/action.yml — SHA-to-tag resolution logic uses gh api --paginate + jq in this file vs manual pagination with retry_curl in action.yml. The different HTTP clients and pagination strategies serve different execution contexts but create maintenance burden. Add cross-reference comments to aid future sync.

  • [os-arch-normalization-divergence] .github/actions/install-fullsend-cli/action.yml — OS/arch normalization uses case-insensitive matching with broader platform support (macos→darwin, x86→386) while action.yml uses strict case-sensitive matching (X64, ARM64 only) with hard errors. The divergence is intentional (action.yml requires Linux for Podman) but should be documented.

  • [stale-doc] docs/plans/automatic-updates.md — While action.yml's inputs.version default remains "latest", the new SHA-to-tag resolution behavior and the reusable workflow fullsend_version default change are not reflected in this plan document. Consider adding an amendment section about the new version resolution flow.

Previous run

Review

Findings

Medium

  • [breaking-change-input-default] .github/workflows/reusable-code.yml (and 6 other reusable workflows) — Changing the fullsend_version input default from "latest" to "" alters the version resolution path for callers that omit the input: they shift from receiving the latest GitHub Release to receiving the CLI version at job.workflow_sha. Issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 documents the old "latest" behavior as a bug causing version skew — the new behavior is the intended contract (callers referencing @v0 get the CLI matching that ref). The behavioral change is from broken to correct, but callers who relied on the "latest" default will observe different behavior. Consider whether fix(version)!: with a BREAKING CHANGE: trailer is warranted per COMMITS.md, or document in the PR description why the ! suffix is not needed.

  • [protected-path] .github/ — This PR modifies 8 files under .github/ (a protected path). The PR links to issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 and explains the rationale for the changes. Human approval is required for protected-path changes regardless of context.

Low

  • [code-duplication-divergence] .github/actions/install-fullsend-cli/action.yml — The SHA-to-tag resolution logic is duplicated between this file (gh api --paginate + jq) and action.yml (manual pagination with retry_curl). The two implementations use different HTTP clients and pagination strategies. Both serve different execution contexts, but the divergence creates maintenance burden. Add cross-reference comments to aid future sync.

  • [os-arch-normalization-duplication] .github/actions/install-fullsend-cli/action.yml — OS/arch normalization logic (macos→darwin, x64→amd64, etc.) is duplicated between this file and action.yml. Add cross-reference comments to keep implementations in sync.

Previous run (6)

Review

Findings

Medium

  • [breaking-change-input-default] .github/workflows/reusable-code.yml (and 6 other reusable workflows) — Changing the fullsend_version input default from "latest" to "" alters the version resolution path for callers that omit the input: they shift from receiving the latest GitHub Release to receiving the CLI version at job.workflow_sha. Issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 documents the old "latest" behavior as a bug causing version skew — the new behavior is the intended contract (callers referencing @v0 get the CLI matching that ref). The behavioral change is from broken to correct, but callers who relied on the "latest" default will observe different behavior. Consider whether fix(version)!: with a BREAKING CHANGE: trailer is warranted per COMMITS.md, or document in the PR description why the ! suffix is not needed.

  • [protected-path] .github/ — This PR modifies 8 files under .github/ (a protected path). The PR links to issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 and explains the rationale for the changes. Human approval is required for protected-path changes regardless of context.

Low

  • [code-duplication-divergence] .github/actions/install-fullsend-cli/action.yml — The SHA-to-tag resolution logic is duplicated between this file (gh api --paginate + jq) and action.yml (manual pagination with retry_curl). The two implementations use different HTTP clients and pagination strategies. Both serve different execution contexts, but the divergence creates maintenance burden. Add cross-reference comments to aid future sync.

  • [os-arch-normalization-duplication] .github/actions/install-fullsend-cli/action.yml — OS/arch normalization logic (macos→darwin, x64→amd64, etc.) is duplicated between this file and action.yml. Add cross-reference comments to keep implementations in sync.

Previous run (7)

Review

Findings

Medium

  • [error-handling-gap] .github/actions/install-fullsend-cli/action.yml — The "Download pre-built binary from release" step runs whenever a tag matching the SHA is found (steps.resolve-tag.outputs.tag != ''), but does not verify that a GitHub release with assets exists for that tag. If a version tag (e.g., v0.5.2) exists as a lightweight tag without a corresponding GitHub release, gh release download will fail with a non-zero exit and set -euo pipefail will hard-fail the job. The source-build fallback steps are skipped because their condition requires tag == ''. By contrast, the parallel change in action.yml correctly checks the release API status (HTTP 200 vs 404) before attempting download, and falls through to source build on 404.
    Remediation: Add a release existence check before downloading (similar to the HTTP status check in action.yml), or catch the gh release download failure and fall through to the source build steps.

  • [breaking-change-default-input] .github/workflows/reusable-code.yml (and 6 other reusable workflows) — The fullsend_version input default changes from "latest" to "" across all 7 reusable workflows. Downstream callers that omit fullsend_version shift from resolving the latest GitHub Release to resolving job.workflow_sha. Per COMMITS.md, "Default values change in ways that alter existing behavior" is a breaking change indicator, and "a missing ! is an important-severity review finding." The PR title fix(version): lacks the ! suffix. Issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 documents that the old "latest" behavior was a bug causing version skew — the change is an intentional fix. Consider whether fix(version)!: is warranted per COMMITS.md, or document why the ! suffix is not needed.

  • [protected-path] .github/ — This PR modifies 8 files under .github/ (a protected path). The PR links to issue fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags #3369 and explains the rationale for the changes. Human approval is required for protected-path changes regardless of context.

Low

  • [injection] .github/actions/install-fullsend-cli/action.ymlWORKFLOW_SHA is interpolated directly into a jq expression via shell string interpolation in the --jq flag, unlike the equivalent code in action.yml which uses jq --arg sha for safe parameterization. The default input (github.sha) and typical callers (job.workflow_sha) are constrained 40-char hex strings, making exploitation impractical, but the pattern should be aligned with the safer approach already used in action.yml.
    Remediation: Use jq -r --arg sha "${WORKFLOW_SHA}" '.[] | select(.commit.sha == $sha) | .name' instead of inlining into the --jq expression.

Labels: PR modifies CI workflows, dispatch version resolution, and CLI install logic to fix a version skew bug.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment component/ci CI pipelines and checks component/dispatch Workflow dispatch and triggers component/install CLI install and app setup type/bug Confirmed defect in existing behavior labels Jul 20, 2026
@rh-hemartin
rh-hemartin force-pushed the hemartin/resolve-sha-to-release branch from eedfa3e to a8886ed Compare July 21, 2026 11:58
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 21, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 11:59 AM UTC · Completed 12:16 PM UTC
Commit: a8886ed · View workflow run →

@rh-hemartin rh-hemartin changed the title fix(version): resolve CLI version from reusable workflow ref fix(version)!: resolve CLI version from reusable workflow ref Jul 21, 2026

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Multi-agent review (3 agents: Claude ×2, Grok). The 5 previously-flagged issues from the earlier review round are confirmed fixed in this diff and not re-flagged. 3 unique findings posted inline; the following medium+ findings don't anchor to a diff hunk in this repo, so noted here:

[HIGH] — Root action.yml's "Download release binary" step (~line 187-239) has no fallback if the resolved release lacks the runner's OS/arch asset. install-fullsend-cli/action.yml's equivalent step got continue-on-error: true + a source-build fallback in the prior review round; this step wasn't touched by this PR but is now reached far more often since the default version resolves to an arbitrary historical job.workflow_sha instead of always-well-covered "latest". Suggest mirroring the same continue-on-error + outcome-gated fallback here.

[MEDIUM] — The primary production caller, fullsend-ai/.fullsend, hardcodes fullsend_version: main in all 6 stage workflows (code/triage/review/fix/retro/prioritize), so inputs.fullsend_version || job.workflow_sha always evaluates to "main" there — this PR's stated fix for #3369 has no effect on the org's actual production install path unless .fullsend is separately updated to drop that override. Worth a follow-up PR/issue against fullsend-ai/.fullsend.

[MEDIUM] (premature-decision) — SHA→tag resolution and OS/arch mapping logic are duplicated verbatim across action.yml and install-fullsend-cli/action.yml with no shared source. This is the second time in this PR's own review history the same bug had to be patched in both places (the jq-injection fix was one bug fixed twice in the prior round). Suggest extracting a shared script both action files can source.

[MEDIUM] (premature-decision) — Only 1 of 4 items in the PR's own test plan is checked off. The core new behavior (a real SHA resolving to its tag and downloading the prebuilt binary) hasn't been demonstrated end-to-end — only the "no match, fall back to source" path has been exercised. Suggest completing the checklist before merge.

Comment thread action.yml
Comment thread .github/actions/install-fullsend-cli/action.yml
Comment thread .github/actions/install-fullsend-cli/action.yml
@rh-hemartin

Copy link
Copy Markdown
Member Author

Opened #5511 to address the duplication and the creation of a shared lib.

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 27, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 7:24 AM UTC · Completed 7:42 AM UTC
Commit: 521e190 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@rh-hemartin
rh-hemartin force-pushed the hemartin/resolve-sha-to-release branch from 521e190 to e15045d Compare July 27, 2026 08:32
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 27, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:34 AM UTC · Completed 8:53 AM UTC
Commit: e15045d · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Review squad round 4 (Claude x2 + Grok, 3 agents) — fix verification of the 2026-07-27 commit plus first design review of the breaking change itself.

Fix verification of the four "Fixed." replies:

Prior finding Verdict
[high] Unguarded stdout capture in SHA-to-tag pagination Partially fixed — reported site guarded; two residual captures in the same step (details in the existing thread)
[medium] "linux only" claim / dropped darwin mapping Confirmed fixed — new comment is verifiably correct; release assets checked (darwin_{amd64,arm64} exist); install action retains darwin mapping
[medium] gh release download retry without clobber Confirmed fixed--clobber present
[high, earlier round] TAG capture swallowing API failures Still intact, no regression — and tag selection now consistent (sort -V | tail -1) across both files

The seven reusable workflows are consistent: identical default: "" and identical ${{ inputs.fullsend_version || job.workflow_sha }} at all 13 use-sites; no workflow left behind.

Two findings that don't anchor to changed lines:

  • [medium] The #3369 skew is moved, not eliminated: workflow + CLI + .defaults scaffold content now align at job.workflow_sha, but the agents-repo fallback (ADR 0058) resolves fullsend-ai/agents@v0 at run time regardless of the pinned CLI/workflow SHA. An org pinned at a v0.30-era workflow runs the v0.30 CLI against today's agents-repo harness content — the same mismatch class this PR fixes, one layer down. release.yml already pushes vX.Y.Z tags to the agents repo; the runtime never consumes them. Suggested follow-up: when the CLI resolves to a release tag, fetch agents content at that same tag, falling back to v0 only for untagged dev builds — and note in #3369 that it's partially closed.
  • [medium] The two resolution implementations have opposite behavior during a GitHub API outage: install-fullsend-cli warns and silently source-builds; this file's release-existence check (no -f, so retries never engage on 5xx) hard-fails the run. Neither policy is chosen — both are accidents of implementation. And nothing after the run distinguishes "downloaded v0.32.0" from "source-built at SHA": no install-method/resolved-version step output or job summary, so the degraded mode (which the blast-radius comment shows is easy to enter permanently) is only detectable by grepping logs. Suggested: pick one outage policy (source-build fallback is the safer), apply it in both files, and emit install-method/resolved-version outputs plus a step-summary line.

Not re-raised (settled): 50-page cap, hot-path caching, OS/arch normalization divergence, continue-on-error swallowing, outcome interpolation (follow-up issues), Linux-only scope (intentional). Lower-severity notes (OS/arch guard inside the continue-on-error step defeating fail-fast, gh api --paginate retry accumulation forcing silent source builds, redundant empty-check + unannotated error message, input-description/docs not updated for the new default semantics) available on request.

Comment thread .github/workflows/reusable-code.yml
Comment thread action.yml Outdated
Comment thread action.yml
Comment thread action.yml Outdated
@rh-hemartin
rh-hemartin force-pushed the hemartin/resolve-sha-to-release branch from e15045d to bd6e99f Compare July 29, 2026 15:15
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 29, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:17 PM UTC · Completed 3:55 PM UTC
Commit: bd6e99f · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Review pass: 3 findings posted inline below. One additional finding has no line in this PR's diff to anchor to (the affected file isn't touched by this PR), noted here instead:

[HIGH] Root action's now-required version input already breaks this project's own documented example — docs/guides/user/building-custom-agents.md (not modified by this PR), around line 469

That guide's "Install fullsend CLI" step is a real, currently-live workflow snippet:

- name: Install fullsend CLI
  uses: fullsend-ai/fullsend@v0
  with:
    agent: __install_only__

— a direct invocation of the root action with no version key at all. This PR removes default: latest from the root action's version input and makes it required: true, adding a runtime exit 1 on empty. Any user following this project's own guide verbatim will hit that failure the next time the v0 floating tag moves past this PR.

This directly contradicts the reply on the existing breaking-change thread on action.yml's version input ("There are no direct callers, if someone is calling this directly is up to them") — there is a direct caller, and it's the project's own documented onboarding path, not a hypothetical external integrator.

Suggestion: Either restore default: latest on the root action's version input (the maintained reusable workflows already pass an explicit value either way, so they're unaffected), or, if required: true is intentional, update this doc's example to add version: ${{ job.workflow_sha }} (or version: latest) so it stays correct, and audit docs/ for other undocumented direct uses: fullsend-ai/fullsend@ callers before merging.

Comment thread action.yml Outdated
Comment thread .github/actions/install-fullsend-cli/action.yml
Comment thread .github/actions/install-fullsend-cli/action.yml
@rh-hemartin
rh-hemartin force-pushed the hemartin/resolve-sha-to-release branch from bd6e99f to d502be4 Compare July 30, 2026 06:47
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 30, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:49 AM UTC · Completed 7:05 AM UTC
Commit: d502be4 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approving — no new findings from this round's review squad pass.

On the behaviour check (currently red): traced this down before approving. The failure is harness run for "pr-ping" concluded with "failure", which matches the exact signature of open issue #5707 ("fork-related harness agent timeouts across all branches," High priority) — known, tracked, cross-branch flakiness that's also been hitting the merge queue on main, unrelated to this PR's diff (version resolution / install action only, no dispatch or harness code touched).

Separately confirmed this branch's merge-base with main predates e534f24a (today's podman 5.8.4 pin + rootless AppArmor fix, #5742/#5743), which resolves most instances of this class of failure. A rebase onto current main would likely pick that up and could clear the check — though #5707 itself is still open, so treat that as likely-but-not-guaranteed.

We're aware of the BT case; not treating it as a blocker on this PR specifically.

Default fullsend_version to "" across all reusable workflows so callers
that omit it resolve to job.workflow_sha instead of "latest". In the
install action, resolve the SHA to a release tag via the GitHub API and
download the GoReleaser artifact, falling back to source build for
untagged commits or download failures.

Harden the install action: paginate tag lookups, use safe jq
parameterization, derive OS/arch from runner context instead of
hardcoding linux, and add a source-build fallback when the release
download fails.

Closes #3369

BREAKING CHANGE: fullsend_version in reusable workflows now defaults to
the workflow SHA instead of "latest". Callers that omit fullsend_version
and want the previous behavior should pass fullsend_version: "latest"
explicitly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
@rh-hemartin
rh-hemartin force-pushed the hemartin/resolve-sha-to-release branch from d502be4 to 7967290 Compare July 30, 2026 14:38
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 30, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 2:39 PM UTC · Completed 2:58 PM UTC
Commit: 7967290 · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

Comment thread .github/actions/install-fullsend-cli/action.yml
Comment thread action.yml
@rh-hemartin
rh-hemartin enabled auto-merge July 31, 2026 06:28
@rh-hemartin
rh-hemartin added this pull request to the merge queue Jul 31, 2026
Merged via the queue into main with commit 3f36f02 Jul 31, 2026
19 checks passed
@rh-hemartin
rh-hemartin deleted the hemartin/resolve-sha-to-release branch July 31, 2026 06:38
@fullsend-ai-retro

fullsend-ai-retro Bot commented Jul 31, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 6:41 AM UTC · Completed 6:58 AM UTC
Commit: 7967290 · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #5357fix(version)!: resolve CLI version from reusable workflow ref

Timeline: Opened 2026-07-20 by rh-hemartin, merged 2026-07-31 (11 days). 9 files changed (+220/−43). Closed #3369 (CLI version skew from fullsend_version defaulting to latest).

Review cycle: 11 review agent runs (3 cancelled, 8 completed), 6 distinct review rounds. Human reviewer waynesun09 ran a multi-agent review squad alongside the fullsend-ai-review bot. Final approval on 2026-07-30 after a clean pass.

Review quality assessment

The human reviewer (waynesun09) found all 8 high/critical-severity findings across 6 rounds, including:

  • Missing source-build fallback when release download fails (HIGH, round 1)
  • set -euo pipefail interaction with pagination loop causing hard failures (HIGH, round 2)
  • retry_curl() stdout contamination polluting command substitution captures (HIGH, round 3) — then re-verified the fix was only partial in round 4
  • GHES empty-workflow_sha fallback applied to install-fullsend-cli/action.yml but missing from root action.yml used by all 13 real call sites (CRITICAL, round 5)

The review agent (fullsend-ai-review[bot]) contributed 5 unique findings, all low-severity (consistency nits, informational notes). It produced 6 duplicate comments — the same GHES fallback and continue-on-error findings repeated across 3+ rounds. No high or critical findings from the agent in any round.

Rework analysis

The 6-round, 11-day cycle was driven by the human reviewer's depth — each round surfaced issues that the review agent's correctness sub-agent could theoretically have caught earlier. Two patterns stood out:

  1. Partial-fix blindness: The agent verified that a specific reported site was fixed but did not check adjacent code sites with the same vulnerability (stdout contamination at lines 150, 158 after line 142 was fixed; GHES fallback in one file but not the other).
  2. Shell-specific reasoning gaps: The agent did not reason about stdout vs stderr in command substitution, set -euo pipefail interactions with loop control flow, or retry wrapper side effects — all of which were central to the HIGH findings.

Evidence supporting existing open issues

  • agents#106, fullsend#2959, fullsend#5265: The agent re-raised the GHES error-handling-gap finding 3 times and the continue-on-error finding 3 times across rounds, even after the author responded to each. This PR provides additional evidence for the dedup/prior-response-awareness gap.
  • fullsend#1525: The CRITICAL finding (GHES fallback missing from root action.yml while present in the sibling file) is a direct instance of the cross-file impact analysis gap described in Review agent misses cross-file impact analysis that Review Squad catches #1525.
  • agents#131, fullsend#1375: The agent missed stdout contamination in command substitution, set -euo pipefail interactions, and retry-wrapper side effects — all common shell pitfalls that these issues propose adding to the correctness sub-agent.

Proposals filed

2 proposals below — both verified as not covered by existing open issues.

Proposals filed

maruiz93 pushed a commit to maruiz93/fullsend that referenced this pull request Jul 31, 2026
…ipting guide

Add a fourth shell correctness pattern documenting how functions
that write diagnostic output to stdout pollute variables when
called inside $(...) command substitution. This pattern caused
a HIGH-severity bug on PR fullsend-ai#5357 where retry_curl() wrote
::warning:: and ::error:: annotations to stdout, contaminating
the resp variable and breaking downstream jq parsing.

The new section follows the existing format: problem description,
anti-pattern and correct code examples, and a review guidance
paragraph with severity levels. Also updates the AGENTS.md table
entry to reference the new pattern.

Note: pre-commit could not run (network access blocked in
sandbox). The post-script runs an authoritative pre-commit
check on the runner before pushing.

Closes fullsend-ai#5789
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/ci CI pipelines and checks component/dispatch Workflow dispatch and triggers component/install CLI install and app setup requires-manual-review Review requires human judgment type/bug Confirmed defect in existing behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fullsend_version defaulting to 'latest' in reusable workflows creates version skew with action tags

2 participants