Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -740,10 +740,27 @@ jobs:
sudo chmod +x /usr/local/bin/yq
yq --version
- name: Audit
id: audit
env:
GH_TOKEN: ${{ steps.setup.outputs.token }}
run: bash scripts/audit_branch_protection.sh

# The job-level `continue-on-error: true` above silences the audit
# step's failure entirely during the #1555 stabilization window,
# which means real drift could ship invisibly. Surface a warning
# annotation when the audit detected drift; the warning shows up
# in the run summary and check-run UI even though the job stays
# green per #1555. Promote the job to blocking once #1555 closes
# the 30-day zero-drift window.
- name: Report drift outcome
if: always()
env:
AUDIT_OUTCOME: ${{ steps.audit.outcome }}
run: |
if [ "$AUDIT_OUTCOME" = "failure" ]; then
echo "::warning::Branch-protection drift detected -- see Audit step log. Job stays green via job-level continue-on-error during the #1555 stabilization window; promote to blocking once the spec has survived 30 days of zero-drift runs."
fi

# ── Gate: all required checks passed ──
ci-pass:
name: CI Pass
Expand Down
60 changes: 41 additions & 19 deletions .github/workflows/cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -261,34 +261,56 @@ jobs:
go-version-file: cli/go.mod
cache: false

- name: Run fuzz tests (30s per target)
id: fuzz_run
continue-on-error: true
# Two steps: discovery and execution are split so compile errors
# in fuzz targets fail the matrix cell loudly. The prior single
# step had a job-level `continue-on-error: true` that silenced
# both fuzzer-found crashes (intentional, advisory only) AND
# `go test -list` compile failures (unintentional, real bugs).
# Discovery runs without continue-on-error; execution keeps it.
- name: List fuzz targets
id: fuzz_list
working-directory: cli
env:
PKG: ${{ matrix.package }}
run: |
set -euo pipefail
# Run each Fuzz* function in the package for 30s.
# go test -fuzz only supports one fuzz target at a time,
# so we discover and iterate.
#
# Discover fuzz targets. go test -list exits non-zero on compile
# errors; let that propagate so broken packages aren't silently
# skipped.
LIST_OUTPUT=$(go test -list 'Fuzz.*' ${{ matrix.package }} 2>&1) || {
echo "::error::go test -list failed for ${{ matrix.package }}"
# go test -list exits non-zero on compile errors; let that
# propagate so broken packages aren't silently skipped.
LIST_OUTPUT=$(go test -list 'Fuzz.*' "$PKG" 2>&1) || {
echo "::error::go test -list failed for $PKG (compile error?)"
echo "$LIST_OUTPUT"
exit 1
}
FUZZ_TARGETS=$(echo "$LIST_OUTPUT" | grep '^Fuzz' || true)
if [ -z "$FUZZ_TARGETS" ]; then
echo "No fuzz targets found in ${{ matrix.package }}"
exit 0
fi
for target in $FUZZ_TARGETS; do
# Multi-line GITHUB_OUTPUT requires a heredoc-style delimiter;
# see https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings
{
echo "targets<<TARGETS_EOF"
echo "$FUZZ_TARGETS"
echo "TARGETS_EOF"
} >> "$GITHUB_OUTPUT"

- name: Run fuzz tests (30s per target)
id: fuzz_run
if: steps.fuzz_list.outputs.targets != ''
continue-on-error: true
working-directory: cli
env:
# Pass via env (not direct ${{ }} interpolation) so multi-line
# values survive without GitHub Actions expression-syntax
# escaping pitfalls.
FUZZ_TARGETS: ${{ steps.fuzz_list.outputs.targets }}
PKG: ${{ matrix.package }}
run: |
set -euo pipefail
# Run each Fuzz* function in the package for 30s. go test
# -fuzz only supports one fuzz target at a time, so iterate.
while IFS= read -r target; do
[ -z "$target" ] && continue
echo "::group::Fuzzing $target"
go test -fuzz="^${target}$" -fuzztime=30s ${{ matrix.package }}
go test -fuzz="^${target}$" -fuzztime=30s "$PKG"
echo "::endgroup::"
done
done <<< "$FUZZ_TARGETS"

- name: Report fuzz outcome
if: always()
Expand Down
58 changes: 53 additions & 5 deletions .github/workflows/dev-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,25 @@ jobs:
# 2. Create a draft pre-release pointing at the tag. The draft
# follows the same lifecycle as stable releases: Docker + CLI
# workflows attach assets, then finalize-release publishes
# once both succeed. Clean up the tag on failure.
# once both succeed.
#
# On failure we deliberately do NOT delete the tag. Step 1
# already pushed the ref, which fired downstream `tags: v*`
# workflows (cli.yml, docker.yml). Deleting the ref now
# would race their actions/checkout step and 404 on
# `refs/tags/$DEV_TAG`, surfacing a false-positive red on
# main even when the squash content is clean (#1818). The
# orphan tag is harmless: the "Clean up old dev pre-
# releases" step below + finalize-release.yml's stable-
# release sweep garbage-collect it later, and finalize-
# release.yml correctly skip-publishes a tag with no draft.
if ! gh release create "$DEV_TAG" \
--draft \
--prerelease \
--title "$DEV_TAG" \
--notes-file "$NOTES_FILE"; then
echo "::warning::Release creation failed, cleaning up tag"
gh api -X DELETE "repos/$GITHUB_REPOSITORY/git/refs/tags/$DEV_TAG" || true
echo "::error::Release creation failed for $DEV_TAG"
echo "::warning::Tag preserved to avoid racing downstream workflows (#1818)"
exit 1
fi

Expand All @@ -208,14 +219,51 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
# Keep the 5 most recent dev pre-releases, delete the rest
# Keep the 5 most recent dev pre-releases, delete the rest.
# The "keep 5 newest" filter guarantees the JUST-MINTED tag is
# never selected for deletion -- the deleted tags are 5+
# revisions old, and their downstream Docker / CLI workflows
# have long since completed. The race documented in #1818
# requires deleting a tag whose downstream workflows are
# still in flight, which this bulk-prune doesn't do.
gh release list --limit 50 --json tagName,isPrerelease,createdAt \
--jq '[.[] | select(.isPrerelease and (.tagName | contains("-dev.")))] | sort_by(.createdAt) | reverse | .[5:] | .[].tagName' \
| while read -r tag; do
echo "Deleting old dev release: $tag"
gh release delete "$tag" --yes --cleanup-tag 2>/dev/null || true
gh release delete "$tag" --yes --cleanup-tag 2>/dev/null || true # lint-allow: workflow-tag-lifecycle -- bulk-deletes 5+-revision-old dev tags whose downstream workflows have completed; not the just-minted tag (#1818)
done

# Regression guard for #1818. The dev tag was created near the
# top of this job; if anything in the run between then and now
# deleted it, downstream Docker / CLI workflows triggered by the
# initial tag push are about to 404 on actions/checkout. Surface
# the deletion as a hard job failure so the existing report-
# failure job opens the dev-release-regression tracking issue
# with the run URL, instead of debugging from downstream symptoms.
- name: Verify minted tag survived the run
# always() ensures this regression guard runs on the failure
# paths -- which is precisely when tag loss is most likely
# (release-create or cleanup step erroring out partway). Without
# always(), the implicit success() condition would skip the
# guard the moment any earlier step failed, defeating the
# canary's purpose.
if: >-
always()
&& steps.check-tag.outputs.skip != 'true'
&& steps.version.outputs.skip != 'true'
&& steps.tag-exists.outputs.skip != 'true'
env:
GH_TOKEN: ${{ github.token }}
DEV_TAG: ${{ steps.version.outputs.dev_tag }}
run: |
set -euo pipefail
if ! gh api "repos/$GITHUB_REPOSITORY/git/refs/tags/$DEV_TAG" \
>/dev/null 2>&1; then
echo "::error::Tag $DEV_TAG was deleted during this run -- downstream Docker/CLI workflows are about to 404 on actions/checkout. Investigate dev-release.yml."
exit 1
fi
echo "Tag $DEV_TAG present at end-of-run."
Comment thread
coderabbitai[bot] marked this conversation as resolved.

report-failure:
name: Open / update tracking issue on dev-release failure
needs: dev-release
Expand Down
Loading
Loading