fix(release): install.sh asset matching + SHA256SUMS + Dockerfile 1.25.12
install.sh: - find_asset_url now matches by asset NAME (python3 JSON parse), not URL path — Gitea attachment URLs are opaque UUIDs that don't contain the tarball name. This was the root cause of the v0.12.18 install failure (asset existed but install.sh couldn't find it). - find_asset_in_releases walks recent releases by asset name and returns both URL + version for the fallback walk. - Handles 404 (tag without release) gracefully via fallback walk. Dockerfile: - golang:1.25 -> golang:1.25.12 (go.mod requires 1.25.12; the Docker image was using patch 0, causing `go mod download` to fail with "go.mod requires go >= 1.25.12 (running go 1.25.10)") coreci.yml: - All golang:1.25 images -> golang:1.25.12 - Release pipeline: add SHA256SUMS generation (sha256sum tarball) - Release pipeline: attach SHA256SUMS alongside tarball - Release pipeline: verify assets are actually attached after tea releases create (REQ-097 gate C-21); auto-attach via API if tea failed silently release.sh: - Add SHA256SUMS generation (sha256sum tarball > SHA256SUMS) ---ci--- project: orca milestone: v0.12.18 phase: release-fix status: complete ---/ci---
This commit is contained in:
+39
-11
@@ -23,25 +23,25 @@ pipelines:
|
|||||||
description: Validate Go toolchain, formatting, and security scans
|
description: Validate Go toolchain, formatting, and security scans
|
||||||
steps:
|
steps:
|
||||||
- name: go-version
|
- name: go-version
|
||||||
image: golang:1.25
|
image: golang:1.25.12
|
||||||
commands:
|
commands:
|
||||||
- go version
|
- go version
|
||||||
- gofmt -l .
|
- gofmt -l .
|
||||||
- go vet ./...
|
- go vet ./...
|
||||||
|
|
||||||
- name: verify-reqs
|
- name: verify-reqs
|
||||||
image: golang:1.25
|
image: golang:1.25.12
|
||||||
commands:
|
commands:
|
||||||
- make verify-reqs
|
- make verify-reqs
|
||||||
|
|
||||||
- name: gosec
|
- name: gosec
|
||||||
image: golang:1.25
|
image: golang:1.25.12
|
||||||
commands:
|
commands:
|
||||||
- go install github.com/securego/gosec/v2/cmd/gosec@v2.18.2
|
- go install github.com/securego/gosec/v2/cmd/gosec@v2.18.2
|
||||||
- gosec -fmt text -quiet ./...
|
- gosec -fmt text -quiet ./...
|
||||||
|
|
||||||
- name: govulncheck
|
- name: govulncheck
|
||||||
image: golang:1.25
|
image: golang:1.25.12
|
||||||
env:
|
env:
|
||||||
# REQ-027: offline mode. GOFLAGS=-mod=mod ensures module mode;
|
# REQ-027: offline mode. GOFLAGS=-mod=mod ensures module mode;
|
||||||
# GOVULNCHECK_DB (when present) overrides the bundled DB.
|
# GOVULNCHECK_DB (when present) overrides the bundled DB.
|
||||||
@@ -51,7 +51,7 @@ pipelines:
|
|||||||
- govulncheck -mode binary ./...
|
- govulncheck -mode binary ./...
|
||||||
|
|
||||||
- name: gitleaks
|
- name: gitleaks
|
||||||
image: golang:1.25
|
image: golang:1.25.12
|
||||||
commands:
|
commands:
|
||||||
- apk add --no-cache curl
|
- apk add --no-cache curl
|
||||||
- sh -c "$(curl -fsSL https://github.com/gitleaks/gitleaks/releases/latest/download/install.sh)"
|
- sh -c "$(curl -fsSL https://github.com/gitleaks/gitleaks/releases/latest/download/install.sh)"
|
||||||
@@ -61,7 +61,7 @@ pipelines:
|
|||||||
description: Build the orca binary with version injection
|
description: Build the orca binary with version injection
|
||||||
steps:
|
steps:
|
||||||
- name: build
|
- name: build
|
||||||
image: golang:1.25
|
image: golang:1.25.12
|
||||||
env:
|
env:
|
||||||
VERSION: ${CI_COMMIT_TAG:-dev}
|
VERSION: ${CI_COMMIT_TAG:-dev}
|
||||||
GIT_COMMIT: ${CI_COMMIT_SHA}
|
GIT_COMMIT: ${CI_COMMIT_SHA}
|
||||||
@@ -80,7 +80,7 @@ pipelines:
|
|||||||
description: Run all tests with race detection and coverage (REQ-031)
|
description: Run all tests with race detection and coverage (REQ-031)
|
||||||
steps:
|
steps:
|
||||||
- name: test
|
- name: test
|
||||||
image: golang:1.25
|
image: golang:1.25.12
|
||||||
commands:
|
commands:
|
||||||
- go test -race -coverprofile=coverage.out ./...
|
- go test -race -coverprofile=coverage.out ./...
|
||||||
- go tool cover -func=coverage.out | tail -1
|
- go tool cover -func=coverage.out | tail -1
|
||||||
@@ -91,7 +91,7 @@ pipelines:
|
|||||||
ref: "refs/tags/v*"
|
ref: "refs/tags/v*"
|
||||||
steps:
|
steps:
|
||||||
- name: build-artifact
|
- name: build-artifact
|
||||||
image: golang:1.25
|
image: golang:1.25.12
|
||||||
env:
|
env:
|
||||||
VERSION: ${CI_COMMIT_TAG}
|
VERSION: ${CI_COMMIT_TAG}
|
||||||
GIT_COMMIT: ${CI_COMMIT_SHA}
|
GIT_COMMIT: ${CI_COMMIT_SHA}
|
||||||
@@ -105,20 +105,48 @@ pipelines:
|
|||||||
go build -trimpath -ldflags="${LDFLAGS}" -o bin/orca ./cmd/orca
|
go build -trimpath -ldflags="${LDFLAGS}" -o bin/orca ./cmd/orca
|
||||||
- make changelog
|
- make changelog
|
||||||
- tar -czf orca-${VERSION}-linux-amd64.tar.gz -C bin orca
|
- tar -czf orca-${VERSION}-linux-amd64.tar.gz -C bin orca
|
||||||
- ls -lh orca-${VERSION}-linux-amd64.tar.gz
|
- sha256sum orca-${VERSION}-linux-amd64.tar.gz > SHA256SUMS
|
||||||
|
- ls -lh orca-${VERSION}-linux-amd64.tar.gz SHA256SUMS
|
||||||
|
- cat SHA256SUMS
|
||||||
- name: gitea-release
|
- name: gitea-release
|
||||||
image: golang:1.25
|
image: golang:1.25.12
|
||||||
env:
|
env:
|
||||||
GITEA_TOKEN: ${GITEA_TOKEN}
|
GITEA_TOKEN: ${GITEA_TOKEN}
|
||||||
VERSION: ${CI_COMMIT_TAG}
|
VERSION: ${CI_COMMIT_TAG}
|
||||||
commands:
|
commands:
|
||||||
- apk add --no-cache curl tar
|
- apk add --no-cache curl tar python3
|
||||||
- sh -c "$(curl -fsSL https://gitea.com/gitea/tea/releases/latest/download/install.sh)"
|
- sh -c "$(curl -fsSL https://gitea.com/gitea/tea/releases/latest/download/install.sh)"
|
||||||
- tea releases create ${VERSION}
|
- tea releases create ${VERSION}
|
||||||
--repo coreci/orca
|
--repo coreci/orca
|
||||||
--title "Orca ${VERSION}"
|
--title "Orca ${VERSION}"
|
||||||
--note-file CHANGELOG.md
|
--note-file CHANGELOG.md
|
||||||
--asset orca-${VERSION}-linux-amd64.tar.gz
|
--asset orca-${VERSION}-linux-amd64.tar.gz
|
||||||
|
--asset SHA256SUMS
|
||||||
|
- |
|
||||||
|
# Verify assets are actually attached (REQ-097, gate C-21).
|
||||||
|
# tea releases create has been observed to exit 0 without
|
||||||
|
# attaching the asset in some versions. Verify via the API.
|
||||||
|
ASSET_COUNT=$(curl -fsSL \
|
||||||
|
"https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/tags/${VERSION}" \
|
||||||
|
| python3 -c "import json,sys; r=json.load(sys.stdin); print(len(r.get('assets',[])))")
|
||||||
|
echo "Release ${VERSION} has ${ASSET_COUNT} assets"
|
||||||
|
if [ "${ASSET_COUNT}" -lt 2 ]; then
|
||||||
|
echo "ERROR: Expected at least 2 assets (tarball + SHA256SUMS), got ${ASSET_COUNT}"
|
||||||
|
echo "Attempting to attach assets manually..."
|
||||||
|
TARBALL_URL=$(curl -fsSL \
|
||||||
|
"https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/tags/${VERSION}" \
|
||||||
|
| python3 -c "import json,sys; r=json.load(sys.stdin); print(r.get('id',''))")
|
||||||
|
if [ -n "${TARBALL_URL}" ]; then
|
||||||
|
curl -fsSL -X "POST" \
|
||||||
|
"https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/${TARBALL_URL}/assets?name=orca-${VERSION}-linux-amd64.tar.gz" \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-F "attachment=@orca-${VERSION}-linux-amd64.tar.gz"
|
||||||
|
curl -fsSL -X "POST" \
|
||||||
|
"https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/${TARBALL_URL}/assets?name=SHA256SUMS" \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-F "attachment=@SHA256SUMS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
- name: container-publish
|
- name: container-publish
|
||||||
description: Build and publish OCI image to Gitea container registry (REQ-046)
|
description: Build and publish OCI image to Gitea container registry (REQ-046)
|
||||||
image: docker:24-cli
|
image: docker:24-cli
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ ARG BUILD_TIME=unknown
|
|||||||
|
|
||||||
# --- Stage 1: build -------------------------------------------------------
|
# --- Stage 1: build -------------------------------------------------------
|
||||||
|
|
||||||
FROM golang:1.25 AS builder
|
FROM golang:1.25.12 AS builder
|
||||||
|
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
ARG GIT_COMMIT
|
ARG GIT_COMMIT
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
9fa21a416801ef88e52d8f07b5406752f56a3f07ca8d758e445ba5f3a2fce055 orca-v0.12.18-linux-amd64.tar.gz
|
||||||
+43
-20
@@ -111,34 +111,57 @@ TARBALL="orca-${VERSION}-${OS}-${ARCH}.tar.gz"
|
|||||||
|
|
||||||
find_asset_url() {
|
find_asset_url() {
|
||||||
# $1 = tag. Prints the browser_download_url for the matching tarball, or empty.
|
# $1 = tag. Prints the browser_download_url for the matching tarball, or empty.
|
||||||
# The `|| true` prevents set -e + pipefail from exiting the script when
|
# Match by asset NAME (not URL path) — Gitea attachment URLs are opaque
|
||||||
# grep finds no match (exit 1) — an empty result is a valid outcome.
|
# UUIDs that don't contain the tarball name.
|
||||||
local tag="$1"
|
local tag="$1"
|
||||||
curl -fsSL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases/tags/${tag}" \
|
local json
|
||||||
| sed -n 's/.*"browser_download_url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
|
json="$(curl -fsSL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases/tags/${tag}" 2>/dev/null)" || return 1
|
||||||
| grep "/${TARBALL}\$" \
|
if command -v python3 >/dev/null 2>&1; then
|
||||||
| head -1 || true
|
echo "$json" | python3 -c "
|
||||||
|
import json,sys
|
||||||
|
r=json.load(sys.stdin)
|
||||||
|
for a in r.get('assets',[]):
|
||||||
|
if a.get('name')=='$TARBALL':
|
||||||
|
print(a.get('browser_download_url',''))
|
||||||
|
break
|
||||||
|
" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
echo "$json" | sed -n 's/.*"name"[[:space:]]*:[[:space:]]*"$TARBALL".*"browser_download_url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1 || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
find_asset_in_releases() {
|
||||||
|
# Walk recent releases, find the newest with a matching asset name.
|
||||||
|
# Outputs two lines: URL and VERSION (caller captures both).
|
||||||
|
local json
|
||||||
|
json="$(curl -fsSL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases?limit=50" 2>/dev/null)" || return 1
|
||||||
|
if command -v python3 >/dev/null 2>&1; then
|
||||||
|
echo "$json" | python3 -c "
|
||||||
|
import json,sys,re
|
||||||
|
rels=json.load(sys.stdin)
|
||||||
|
for r in rels:
|
||||||
|
tag=r.get('tag_name','')
|
||||||
|
for a in r.get('assets',[]):
|
||||||
|
name=a.get('name','')
|
||||||
|
m=re.match(r'orca-(v[0-9.]+)-' + '${OS}' + '-' + '${ARCH}' + r'\.tar\.gz$', name)
|
||||||
|
if m:
|
||||||
|
print(a.get('browser_download_url',''))
|
||||||
|
print(m.group(1))
|
||||||
|
sys.exit(0)
|
||||||
|
"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
info "locating asset ${TARBALL} in release ${VERSION}..."
|
info "locating asset ${TARBALL} in release ${VERSION}..."
|
||||||
ASSET_URL="$(find_asset_url "$VERSION")"
|
ASSET_URL="$(find_asset_url "$VERSION" 2>/dev/null)" || true
|
||||||
|
|
||||||
if [ -z "$ASSET_URL" ]; then
|
if [ -z "$ASSET_URL" ]; then
|
||||||
info "WARNING: release ${VERSION} has no ${TARBALL} asset. Walking back through recent releases..."
|
info "WARNING: release ${VERSION} has no ${TARBALL} asset. Walking back through recent releases..."
|
||||||
# The /releases list endpoint returns assets inline (browser_download_url
|
FALLBACK_OUT="$(find_asset_in_releases || true)"
|
||||||
# appears within each release's assets array). Extract all download URLs
|
ASSET_URL="$(echo "$FALLBACK_OUT" | head -1)"
|
||||||
# from the list response and find the first (newest) one matching our
|
|
||||||
# OS+arch tarball pattern (any version). This avoids per-release API calls.
|
|
||||||
ASSET_URL="$(curl -fsSL "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases?limit=50" \
|
|
||||||
| grep -oE '"browser_download_url"[[:space:]]*:[[:space:]]*"[^"]*"' \
|
|
||||||
| sed -n 's/.*"browser_download_url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
|
|
||||||
| grep -E "/orca-[^/]*-${OS}-${ARCH}\.tar\.gz$" \
|
|
||||||
| head -1 || true)"
|
|
||||||
if [ -n "$ASSET_URL" ]; then
|
if [ -n "$ASSET_URL" ]; then
|
||||||
# Extract the version from the URL (e.g. .../download/v0.4.5/orca-...)
|
VERSION="$(echo "$FALLBACK_OUT" | tail -1)"
|
||||||
FALLBACK_VERSION="$(echo "$ASSET_URL" | sed -n 's|.*/download/\([^/]*\)/.*|\1|p')"
|
info "WARNING: falling back to ${VERSION} which has orca-${VERSION}-${OS}-${ARCH}.tar.gz."
|
||||||
info "WARNING: latest release ${VERSION} has no binary asset; falling back to ${FALLBACK_VERSION} which has orca-${FALLBACK_VERSION}-${OS}-${ARCH}.tar.gz."
|
|
||||||
VERSION="$FALLBACK_VERSION"
|
|
||||||
else
|
else
|
||||||
err "could not find any release with a ${OS}-${ARCH} tarball in the last 50 releases. Check that a release exists with a linux-${ARCH} binary."
|
err "could not find any release with a ${OS}-${ARCH} tarball in the last 50 releases. Check that a release exists with a linux-${ARCH} binary."
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ info "built: bin/orca (linux-amd64)"
|
|||||||
|
|
||||||
TARBALL="orca-${VERSION}-linux-amd64.tar.gz"
|
TARBALL="orca-${VERSION}-linux-amd64.tar.gz"
|
||||||
tar -czf "$TARBALL" -C bin orca
|
tar -czf "$TARBALL" -C bin orca
|
||||||
|
sha256sum "$TARBALL" > SHA256SUMS
|
||||||
|
info "checksum: SHA256SUMS"
|
||||||
|
cat SHA256SUMS
|
||||||
info "packaged: $TARBALL ($(du -h "$TARBALL" | cut -f1))"
|
info "packaged: $TARBALL ($(du -h "$TARBALL" | cut -f1))"
|
||||||
|
|
||||||
# --- release notes from ---ci--- blocks ----------------------------------
|
# --- release notes from ---ci--- blocks ----------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user