Files
orca/.coreci.yml
T
Jon Chery d7896e5287
Release / ci (push) Failing after 7m39s
Release / container-orca (push) Has been skipped
Release / container-traefik (push) Has been skipped
fix(P1): remove plugin: from .coreci.yml jobs — invoke-only (REQ-184)
CoreCI's validate() rejects jobs with both plugin and invoke set
(mutually exclusive — pipeline.go:119). The previous commit used both
plugin: docker://golang:1.25.12 and invoke: on each job, causing:
  Error: load config: validate: job "gosec": plugin and invoke are
  mutually exclusive

Fix: remove all plugin: fields. Jobs run via the shell-isolated executor
which runs sh -c <invoke> directly. Go 1.25 is installed on the Gitea
Actions runner via actions/setup-go, so all Go commands work. Tool
installation via go install (gosec, govulncheck) and curl (gitleaks,
tea) works in the shell-isolated executor.

---ci---
project: orca
phase: 1
milestone: v0.16
status: execute
---/ci---
2026-08-12 21:19:36 +00:00

194 lines
9.4 KiB
YAML

version: "1"
name: orca-ci
description: Orca — offline/CLI-first orchestration engine. Full release flow via CoreCI.
# CoreCI configuration for orca (v0.16 rewrite — native jobs: format).
#
# 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:`/`invoke:`/`vars:` format
# with a DAG via `needs:`.
#
# 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 uses `invoke:` only (no `plugin:`). CoreCI's validate()
# rejects jobs with both `plugin` and `invoke` set (mutually exclusive).
# Jobs run via the shell-isolated executor, which runs `sh -c <invoke>`
# directly. The Gitea Actions runner has Go 1.25 installed via
# actions/setup-go, so all Go commands work. Tool installation via
# `go install` (gosec, govulncheck) and `curl` (gitleaks, tea) works.
#
# 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).
jobs:
# ── validate ──────────────────────────────────────────────────────────
go-vet:
invoke: |
go version
gofmt -l .
go vet ./...
verify-reqs:
needs: [go-vet]
invoke: "make verify-reqs"
gosec:
needs: [go-vet]
invoke: |
go install github.com/securego/gosec/v2/cmd/gosec@v2.18.2
gosec -fmt text -quiet ./...
govulncheck:
needs: [go-vet]
vars:
GOFLAGS: "-mod=mod"
invoke: |
go install golang.org/x/vuln/cmd/govulncheck@v1.1.3
govulncheck -mode binary ./...
gitleaks:
needs: [go-vet]
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:
needs: [verify-reqs, gosec, govulncheck, gitleaks]
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:
needs: [build]
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:
needs: [test]
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"