From 3be86e6daf76d629ebe16b8c4e5d9183e259813b Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Wed, 12 Aug 2026 21:05:21 +0000 Subject: [PATCH] fix(P1): Gitea Actions clone auth + .coreci.yml native format rewrite (REQ-183,184) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit REQ-183: Fix .gitea/workflows/release.yml — the git clone of the private coreci repo failed because the clone command had no credentials. The actions/checkout@v4 step only injects auth for the orca repo. Fix: pass GITEA_TOKEN env to the Install CoreCI step and embed it in the clone URL (https://cloudinit-bot:${GITEA_TOKEN}@git.cloudinit.dev/...). REQ-184: Rewrite .coreci.yml from the invalid pipelines:/steps:/image:/ commands: format to CoreCI's native jobs:/plugin:/invoke:/vars: format with a proper DAG (needs:). CoreCI's Pipeline struct only recognizes jobs:/services:/env: top-level keys — unknown fields are silently dropped by yaml.Unmarshal, producing an empty Jobs map → zero jobs execute. The rewrite: - 8 jobs: go-vet → fan-out (verify-reqs, gosec, govulncheck, gitleaks) → build → test → release - plugin: docker://golang:1.25.12 + invoke: on each job (container path with shell-isolated fallback — Go is installed on the runner) - GITEA_TOKEN via vars: with ${{ secrets.GITEA_TOKEN }} (resolved from env via CoreCI's secret resolver os.Getenv fallback) - CI_COMMIT_BRANCH (tag name on tag push) and CI_COMMIT_SHA for version injection — no ${VAR} interpolation in YAML fields (shell expansion only works inside invoke: via sh -c) - No apk add (runner is ubuntu, not alpine — uses curl for tool downloads) - Release job handles duplicate release (ship workflow creates release first with title+body; coreci run attaches binary assets later via API fallback if tea releases create fails) - Release job verifies asset count ≥ 2 (REQ-097 gate C-21) with retry Root cause: all 87 releases in repo history had zero binary assets because coreci run never executed any jobs (empty Jobs map from the invalid format) and the Gitea Actions workflow failed before reaching coreci run (private repo clone had no credentials). ---ci--- project: orca phase: 1 milestone: v0.16 status: execute requirements: covered: [183, 184] partial: [] ---/ci--- --- .ciagent/CHECKPOINT.json | 14 +- .ciagent/REQUIREMENTS.md | 4 +- .ciagent/ROADMAP.md | 2 +- .coreci.yml | 316 ++++++++++++++++++++--------------- .gitea/workflows/release.yml | 4 +- 5 files changed, 197 insertions(+), 143 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 22341ff..854be27 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,17 +1,17 @@ { - "phase": 0, - "stage": "plan", + "phase": 1, + "stage": "execute", "milestone": "v0.16", "milestone_slug": "release-binary-fix", - "phase_role": "pre_execution", + "phase_role": "execution", "attempts": 0, - "updated_at": "2026-08-12T21:15:00Z", + "updated_at": "2026-08-12T21:30:00Z", "milestone_complete": false, "previous_milestone": "v0.15", - "phases_shipped": [], - "tags_shipped": [], + "phases_shipped": ["P0"], + "tags_shipped": ["v0.15.0"], "requirements": { - "covered": [], + "covered": [183, 184], "partial": [] } } \ No newline at end of file diff --git a/.ciagent/REQUIREMENTS.md b/.ciagent/REQUIREMENTS.md index 7fb9913..1f79f83 100644 --- a/.ciagent/REQUIREMENTS.md +++ b/.ciagent/REQUIREMENTS.md @@ -469,8 +469,8 @@ release pipeline to actually build and upload binaries. | ID | Requirement | Priority | Phase | Status | |----|-------------|----------|-------|--------| -| REQ-183 | Fix `.gitea/workflows/release.yml` "Install CoreCI" step: the `git clone` of the private `coreci` repo fails because the clone command has no credentials. The `actions/checkout@v4` step only injects auth for the orca repo (via `http.https://git.cloudinit.dev/.extraheader`), not for the subsequent bare `git clone` of the coreci repo. Fix: embed the `PAT_TOKEN` in the clone URL (`https://cloudinit-bot:${GITEA_TOKEN}@git.cloudinit.dev/coreci/coreci.git`) and pass `GITEA_TOKEN: ${{ secrets.PAT_TOKEN }}` as env to the "Install CoreCI" step | Critical | **v0.16 P1** | pending | -| REQ-184 | Rewrite `.coreci.yml` from the invalid `pipelines:`/`steps:`/`image:`/`commands:` format to CoreCI's native `jobs:`/`plugin:`/`invoke:`/`vars:` format with a proper DAG (`needs:`). CoreCI's `Pipeline` struct only has `Jobs`/`Services`/`Env` fields — unknown top-level keys and unknown job fields are silently dropped by `yaml.Unmarshal`, producing an empty `Jobs` map. `coreci run` then executes zero jobs (validate does not reject empty jobs). The rewrite must: (a) convert each pipeline to a job with `plugin: docker://golang:1.25.12` and `invoke:` for the commands, (b) use `needs:` for DAG ordering (validate→build→test→release), (c) pass `GITEA_TOKEN` via `vars: { GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} }` (resolved from env via CoreCI's secret resolver `os.Getenv` fallback), (d) use `CI_COMMIT_BRANCH` (tag name on tag push, from CoreCI's github.go CI context) and `CI_COMMIT_SHA` for version injection, (e) handle the case where the release already exists (created by the CIAgent ship workflow with title+body but no binary) by falling back to Gitea API asset attachment, (f) verify assets are actually attached after release creation (REQ-097 gate C-21) | Critical | **v0.16 P1** | pending | +| REQ-183 | Fix `.gitea/workflows/release.yml` "Install CoreCI" step: the `git clone` of the private `coreci` repo fails because the clone command has no credentials. The `actions/checkout@v4` step only injects auth for the orca repo (via `http.https://git.cloudinit.dev/.extraheader`), not for the subsequent bare `git clone` of the coreci repo. Fix: embed the `PAT_TOKEN` in the clone URL (`https://cloudinit-bot:${GITEA_TOKEN}@git.cloudinit.dev/coreci/coreci.git`) and pass `GITEA_TOKEN: ${{ secrets.PAT_TOKEN }}` as env to the "Install CoreCI" step | Critical | **v0.16 P1** | complete | +| REQ-184 | Rewrite `.coreci.yml` from the invalid `pipelines:`/`steps:`/`image:`/`commands:` format to CoreCI's native `jobs:`/`plugin:`/`invoke:`/`vars:` format with a proper DAG (`needs:`). CoreCI's `Pipeline` struct only has `Jobs`/`Services`/`Env` fields — unknown top-level keys and unknown job fields are silently dropped by `yaml.Unmarshal`, producing an empty `Jobs` map. `coreci run` then executes zero jobs (validate does not reject empty jobs). The rewrite must: (a) convert each pipeline to a job with `plugin: docker://golang:1.25.12` and `invoke:` for the commands, (b) use `needs:` for DAG ordering (validate→build→test→release), (c) pass `GITEA_TOKEN` via `vars: { GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} }` (resolved from env via CoreCI's secret resolver `os.Getenv` fallback), (d) use `CI_COMMIT_BRANCH` (tag name on tag push, from CoreCI's github.go CI context) and `CI_COMMIT_SHA` for version injection, (e) handle the case where the release already exists (created by the CIAgent ship workflow with title+body but no binary) by falling back to Gitea API asset attachment, (f) verify assets are actually attached after release creation (REQ-097 gate C-21) | Critical | **v0.16 P1** | complete | ### Scope notes (v0.16) diff --git a/.ciagent/ROADMAP.md b/.ciagent/ROADMAP.md index bb3861a..2b3a14d 100644 --- a/.ciagent/ROADMAP.md +++ b/.ciagent/ROADMAP.md @@ -764,6 +764,6 @@ pipeline to actually build and upload binaries. **Milestone type**: fix (CI infrastructure). Tags on v0.15.x patch line: `v0.15.0` (P0) ... `v0.15.2` (P2 final = v0.16 milestone release). -- [ ] Phase 0: Pre-execution (SPECIFY→CLARIFY→RESEARCH→PLAN→GRILL) — tag `v0.15.0` +- [x] Phase 0: Pre-execution (SPECIFY→CLARIFY→RESEARCH→PLAN→GRILL) — tag `v0.15.0` - [ ] Phase 1: Fix Gitea Actions clone auth + rewrite .coreci.yml to CoreCI native format (REQ-183,184) — tag `v0.15.1` - [ ] Phase 2: Final review + ship + audit (milestone release) — tag `v0.15.2` = **v0.16 milestone release** diff --git a/.coreci.yml b/.coreci.yml index c7e7480..8b38f78 100644 --- a/.coreci.yml +++ b/.coreci.yml @@ -2,148 +2,200 @@ version: "1" name: orca-ci description: Orca — offline/CLI-first orchestration engine. Full release flow via CoreCI. -# CoreCI configuration for orca. +# CoreCI configuration for orca (v0.16 rewrite — native jobs: format). # -# Each pipeline runs in an isolated container with the golang:1.25 toolchain. -# All four pipelines (validate, build, test, release) must pass before a tag -# can be published. The release pipeline is gated on the existence of a -# semver tag (vX.Y.Z) and is the only pipeline that touches the Gitea API. +# CoreCI's Pipeline struct only recognizes `jobs:`, `services:`, and `env:` +# top-level keys. Unknown keys (like the old `pipelines:`) are silently +# dropped by yaml.Unmarshal, producing an empty Jobs map → zero jobs +# execute. This file uses the native `jobs:`/`plugin:`/`invoke:`/`vars:` +# format with a DAG via `needs:`. # -# P03 (v0.2) added three security-scanning stages to the `validate` pipeline: -# - gosec (REQ-014, REQ-040) Static analysis for Go security smells -# - govulncheck (REQ-014, REQ-027) Offline vuln scan of dependencies -# - gitleaks (REQ-039) Pre-commit-style secret scan -# v0.8 P03 added a requirements-hygiene stage: -# - verify-reqs (REQ-060) ROADMAP COMPLETE ↔ REQUIREMENTS Complete -# The `test` pipeline runs with -race (REQ-031). -# See docs/security-scanning.md for operator-facing details. +# DAG: go-vet → fan-out (verify-reqs, gosec, govulncheck, gitleaks) → build → test → release +# +# The Gitea Actions workflow (.gitea/workflows/release.yml) gates on +# `on: push: tags: ['v*']`, so every `coreci run` invocation is already +# a release run — no tag-conditional rules needed here. +# +# Each job declares `plugin: docker://golang:1.25.12` for the container +# path and `invoke:` for the shell command. If no container runtime is +# available (podman/docker), CoreCI's shell-isolated executor runs the +# `invoke:` command directly — the Gitea Actions runner has Go 1.25 +# installed via actions/setup-go, so Go commands work in both paths. +# +# Security scans (REQ-014, REQ-027, REQ-039): +# - gosec Static analysis for Go security smells +# - govulncheck Offline vuln scan of dependencies +# - gitleaks Pre-commit-style secret scan +# verify-reqs (REQ-060): ROADMAP COMPLETE ↔ REQUIREMENTS Complete +# test runs with -race (REQ-031). -pipelines: - validate: - description: Validate Go toolchain, formatting, and security scans - steps: - - name: go-version - image: golang:1.25.12 - commands: - - go version - - gofmt -l . - - go vet ./... +jobs: + # ── validate ────────────────────────────────────────────────────────── + go-vet: + plugin: docker://golang:1.25.12 + invoke: | + go version + gofmt -l . + go vet ./... - - name: verify-reqs - image: golang:1.25.12 - commands: - - make verify-reqs + verify-reqs: + needs: [go-vet] + plugin: docker://golang:1.25.12 + invoke: "make verify-reqs" - - name: gosec - image: golang:1.25.12 - commands: - - go install github.com/securego/gosec/v2/cmd/gosec@v2.18.2 - - gosec -fmt text -quiet ./... + gosec: + needs: [go-vet] + plugin: docker://golang:1.25.12 + invoke: | + go install github.com/securego/gosec/v2/cmd/gosec@v2.18.2 + gosec -fmt text -quiet ./... - - name: govulncheck - image: golang:1.25.12 - env: - # REQ-027: offline mode. GOFLAGS=-mod=mod ensures module mode; - # GOVULNCHECK_DB (when present) overrides the bundled DB. - GOFLAGS: -mod=mod - commands: - - go install golang.org/x/vuln/cmd/govulncheck@v1.1.3 - - govulncheck -mode binary ./... + govulncheck: + needs: [go-vet] + plugin: docker://golang:1.25.12 + vars: + GOFLAGS: "-mod=mod" + invoke: | + go install golang.org/x/vuln/cmd/govulncheck@v1.1.3 + govulncheck -mode binary ./... - - name: gitleaks - image: golang:1.25.12 - commands: - - apk add --no-cache curl - - sh -c "$(curl -fsSL https://github.com/gitleaks/gitleaks/releases/latest/download/install.sh)" - - gitleaks detect --source . --config .gitleaks.toml --baseline-path .gitleaks-baseline.json --no-banner + gitleaks: + needs: [go-vet] + plugin: docker://golang:1.25.12 + invoke: | + curl -fsSL https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks-linux-amd64.tar.gz -o /tmp/gitleaks.tar.gz + tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks + mv /tmp/gitleaks /usr/local/bin/gitleaks 2>/dev/null || sudo mv /tmp/gitleaks /usr/local/bin/gitleaks 2>/dev/null || cp /tmp/gitleaks ./gitleaks + chmod +x ./gitleaks 2>/dev/null || true + ./gitleaks detect --source . --config .gitleaks.toml --baseline-path .gitleaks-baseline.json --no-banner || gitleaks detect --source . --config .gitleaks.toml --baseline-path .gitleaks-baseline.json --no-banner + # ── build ──────────────────────────────────────────────────────────── + # CI_COMMIT_BRANCH contains the tag name on tag pushes (CoreCI's github.go + # maps GITHUB_REF_NAME → CI_COMMIT_BRANCH). CI_COMMIT_SHA is the commit. + # BUILD_TIME is computed inline via `date`. Shell expansion works inside + # invoke: via sh -c at runtime. build: - description: Build the orca binary with version injection - steps: - - name: build - image: golang:1.25.12 - env: - VERSION: ${CI_COMMIT_TAG:-dev} - GIT_COMMIT: ${CI_COMMIT_SHA} - BUILD_TIME: ${CI_BUILD_TIME} - commands: - - | - LDFLAGS="-s -w \ - -X git.cloudinit.dev/coreci/orca/internal/cli.version=${VERSION} \ - -X git.cloudinit.dev/coreci/orca/internal/cli.gitCommit=${GIT_COMMIT} \ - -X git.cloudinit.dev/coreci/orca/internal/cli.buildTime=${BUILD_TIME}" - go build -trimpath -ldflags="${LDFLAGS}" -o bin/orca ./cmd/orca - - file bin/orca - - ./bin/orca version + needs: [verify-reqs, gosec, govulncheck, gitleaks] + plugin: docker://golang:1.25.12 + invoke: | + VERSION="${CI_COMMIT_BRANCH:-dev}" + GIT_COMMIT="${CI_COMMIT_SHA:-unknown}" + BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" + LDFLAGS="-s -w \ + -X git.cloudinit.dev/coreci/orca/internal/cli.version=${VERSION} \ + -X git.cloudinit.dev/coreci/orca/internal/cli.gitCommit=${GIT_COMMIT} \ + -X git.cloudinit.dev/coreci/orca/internal/cli.buildTime=${BUILD_TIME}" + go build -trimpath -ldflags="${LDFLAGS}" -o bin/orca ./cmd/orca + file bin/orca + ./bin/orca version + # ── test (REQ-031: -race) ──────────────────────────────────────────── test: - description: Run all tests with race detection and coverage (REQ-031) - steps: - - name: test - image: golang:1.25.12 - commands: - - go test -race -coverprofile=coverage.out ./... - - go tool cover -func=coverage.out | tail -1 + needs: [build] + plugin: docker://golang:1.25.12 + invoke: | + go test -race -coverprofile=coverage.out ./... + go tool cover -func=coverage.out | tail -1 + # ── release ────────────────────────────────────────────────────────── + # Builds the release tarball, creates/updates the Gitea release with + # binary assets. Handles the case where the release already exists + # (created by the CIAgent ship workflow with title+body but no binary) + # by falling back to Gitea API asset attachment. + # GITEA_TOKEN is resolved from env via CoreCI's secret resolver + # (os.Getenv fallback in run.go:146-153) and forwarded by PassThroughEnv. release: - description: Full release flow — versioned build, tarball, changelog, Gitea release - when: - ref: "refs/tags/v*" - steps: - - name: build-artifact - image: golang:1.25.12 - env: - VERSION: ${CI_COMMIT_TAG} - GIT_COMMIT: ${CI_COMMIT_SHA} - BUILD_TIME: ${CI_BUILD_TIME} - commands: - - | - LDFLAGS="-s -w \ - -X git.cloudinit.dev/coreci/orca/internal/cli.version=${VERSION} \ - -X git.cloudinit.dev/coreci/orca/internal/cli.gitCommit=${GIT_COMMIT} \ - -X git.cloudinit.dev/coreci/orca/internal/cli.buildTime=${BUILD_TIME}" - go build -trimpath -ldflags="${LDFLAGS}" -o bin/orca ./cmd/orca - - make changelog - - tar -czf orca-${VERSION}-linux-amd64.tar.gz -C bin orca - - sha256sum orca-${VERSION}-linux-amd64.tar.gz > SHA256SUMS - - ls -lh orca-${VERSION}-linux-amd64.tar.gz SHA256SUMS - - cat SHA256SUMS - - name: gitea-release - image: golang:1.25.12 - env: - GITEA_TOKEN: ${GITEA_TOKEN} - VERSION: ${CI_COMMIT_TAG} - commands: - - apk add --no-cache curl tar python3 - - sh -c "$(curl -fsSL https://gitea.com/gitea/tea/releases/latest/download/install.sh)" - - tea releases create ${VERSION} - --repo coreci/orca - --title "Orca ${VERSION}" - --note-file CHANGELOG.md - --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 + needs: [test] + plugin: docker://golang:1.25.12 + vars: + GITEA_TOKEN: "${{ secrets.GITEA_TOKEN }}" + invoke: | + VERSION="${CI_COMMIT_BRANCH:-dev}" + GIT_COMMIT="${CI_COMMIT_SHA:-unknown}" + BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" + TARBALL="orca-${VERSION}-linux-amd64.tar.gz" + + # Build the release binary with version injection. + LDFLAGS="-s -w \ + -X git.cloudinit.dev/coreci/orca/internal/cli.version=${VERSION} \ + -X git.cloudinit.dev/coreci/orca/internal/cli.gitCommit=${GIT_COMMIT} \ + -X git.cloudinit.dev/coreci/orca/internal/cli.buildTime=${BUILD_TIME}" + go build -trimpath -ldflags="${LDFLAGS}" -o bin/orca ./cmd/orca + make changelog + tar -czf "${TARBALL}" -C bin orca + sha256sum "${TARBALL}" > SHA256SUMS + ls -lh "${TARBALL}" SHA256SUMS + cat SHA256SUMS + + # Install tea CLI for Gitea release creation. + sh -c "$(curl -fsSL https://gitea.com/gitea/tea/releases/latest/download/install.sh)" 2>/dev/null || true + + # Create release with assets. If the release already exists (created + # by the CIAgent ship workflow with title+body but no binary), fall + # back to attaching assets via the Gitea API. + tea releases create "${VERSION}" \ + --repo coreci/orca \ + --title "Orca ${VERSION}" \ + --note-file CHANGELOG.md \ + --asset "${TARBALL}" \ + --asset SHA256SUMS 2>/dev/null && echo "✓ release created via tea" || ATTACH_TO_EXISTING=1 + + if [ "${ATTACH_TO_EXISTING:-0}" = "1" ]; then + echo "Release ${VERSION} already exists — attaching assets via Gitea API..." + RELEASE_ID=$(curl -fsSL \ + "https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/tags/${VERSION}" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || echo "") + if [ -n "${RELEASE_ID}" ]; then + echo "Attaching assets to release ID ${RELEASE_ID}..." + curl -fsSL -X POST \ + "https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/${RELEASE_ID}/assets?name=${TARBALL}" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -F "attachment=@${TARBALL}" + curl -fsSL -X POST \ + "https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/${RELEASE_ID}/assets?name=SHA256SUMS" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -F "attachment=@SHA256SUMS" + echo "✓ assets attached via API" + else + echo "ERROR: Could not resolve release ID for ${VERSION}" + exit 1 + fi + fi + + # 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}" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + | python3 -c "import json,sys; print(len(json.load(sys.stdin).get('attachments',[])))" 2>/dev/null || echo "0") + 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 manual asset attachment..." + RELEASE_ID=$(curl -fsSL \ + "https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/tags/${VERSION}" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || echo "") + if [ -n "${RELEASE_ID}" ]; then + curl -fsSL -X POST \ + "https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/${RELEASE_ID}/assets?name=${TARBALL}" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -F "attachment=@${TARBALL}" + curl -fsSL -X POST \ + "https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/${RELEASE_ID}/assets?name=SHA256SUMS" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -F "attachment=@SHA256SUMS" + ASSET_COUNT=$(curl -fsSL \ + "https://git.cloudinit.dev/api/v1/repos/coreci/orca/releases/tags/${VERSION}" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + | python3 -c "import json,sys; print(len(json.load(sys.stdin).get('attachments',[])))" 2>/dev/null || echo "0") + echo "After retry: ${ASSET_COUNT} assets" + fi + if [ "${ASSET_COUNT}" -lt 2 ]; then + echo "FATAL: assets not attached after retry (REQ-097, C-21)" + exit 1 + fi + fi + echo "✓ release ${VERSION} published with ${ASSET_COUNT} binary assets" \ No newline at end of file diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index c76b2d5..be7ae09 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -18,8 +18,10 @@ jobs: go-version: '1.25' - name: Install CoreCI + env: + GITEA_TOKEN: ${{ secrets.PAT_TOKEN }} run: | - git clone --depth=1 https://git.cloudinit.dev/coreci/coreci.git /tmp/coreci + git clone --depth=1 https://cloudinit-bot:${GITEA_TOKEN}@git.cloudinit.dev/coreci/coreci.git /tmp/coreci cd /tmp/coreci CGO_ENABLED=0 go build -tags sqlite_go,embed -o /usr/local/bin/coreci ./cmd/coreci coreci version