cog-ha-matter (ADR-116 P8): CI release workflow + fix inherited filename bug

New `.github/workflows/cog-ha-matter-release.yml`:

  * Triggers on `cog-ha-matter-v*` tag-push + manual dispatch
  * Three jobs: build-x86_64, build-arm, publish-gcs
  * x86_64: native ubuntu-latest cargo build
  * arm: aarch64-unknown-linux-gnu via apt-installed gcc-aarch64-linux-gnu
    linker (no `cross` dep needed — keeps workflow self-contained)
  * Each build job runs make build-{arch} + make sign-{arch} +
    gated Ed25519 sign step (skipped when COGNITUM_OWNER_SIGNING_KEY
    secret is unset — workflow still produces unsigned artifacts so
    we get build coverage now and signing later without re-merging)
  * publish-gcs job gated on `vars.HAS_GCP_CREDENTIALS == 'true'`
    so the workflow is safe to merge before credentials land —
    no-op until the org admin sets the variable
  * Uploads binary + sha256 + (optional) sig to
    `gs://cognitum-apps/cogs/{arch}/cog-ha-matter-{arch}`
  * Prints the app-registry.json snippet for the cognitum-one PR
    (so the publish step's output is the exact JSON the user pastes)

Fixed a bug inherited from cog-pose-estimation's Makefile: the
precedent produces `dist/cog-cog-pose-estimation-arm` (double
`cog-` prefix because CRATE name already starts with `cog-`) but
the manifest URL has single prefix `cog-pose-estimation-arm`. The
upload path doesn't match the binary_url — a latent bug in the
pose cog's pipeline.

My copy now produces `dist/cog-ha-matter-arm` matching the
manifest URL `cog-ha-matter-{{ARCH}}`. Changed: Makefile (build /
sign / upload / verify / clean targets), workflow (artifact names
+ gsutil paths), README (local dry-run instructions). The
cog-pose-estimation precedent is unchanged — separate fix if/when
the user wants to align it.

What this iter does NOT do (P8 remaining):
  * provision GCP_CREDENTIALS / COGNITUM_OWNER_SIGNING_KEY secrets
    (user action — needs org admin access)
  * actually run the workflow (needs a `cog-ha-matter-v0.1.0` tag
    push, or workflow_dispatch from the Actions tab)
  * append to app-registry.json in cognitum-one (separate repo PR)

Next iter: tag a v0.0.1-dev (so the workflow runs once + we see
any build-time errors on real CI runners) OR scaffold the
app-registry.json patch payload as a check-in doc.

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
ruv 2026-05-23 23:05:54 -04:00
parent 1e469aa336
commit 3833929dcb
3 changed files with 217 additions and 17 deletions

View File

@ -0,0 +1,200 @@
name: Cog HA-Matter Release
# ADR-116 P8 — Build + sign + bundle the cog-ha-matter cog on a
# version tag. Upload to gs://cognitum-apps/ runs only when the
# GCP_CREDENTIALS + COGNITUM_OWNER_SIGNING_KEY secrets are set, so
# this workflow is safe to merge before the production credentials
# land — it'll bundle release artifacts to the workflow run page
# either way.
on:
push:
tags:
- 'cog-ha-matter-v*'
workflow_dispatch:
inputs:
dry_run:
description: 'Build + sign + bundle but skip GCS upload'
required: false
default: 'true'
env:
CARGO_TERM_COLOR: always
CRATE: cog-ha-matter
jobs:
build-x86_64:
name: Build x86_64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-unknown-linux-gnu
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
v2/target
key: cog-ha-matter-x86_64-${{ hashFiles('v2/Cargo.lock') }}
- name: Build release binary
working-directory: v2/crates/cog-ha-matter/cog
run: make build-x86_64
- name: Compute SHA-256
working-directory: v2/crates/cog-ha-matter/cog
run: make sign-x86_64
- name: Sign with Ed25519 (gated)
if: ${{ env.SIGNING_KEY != '' }}
env:
SIGNING_KEY: ${{ secrets.COGNITUM_OWNER_SIGNING_KEY }}
working-directory: v2/crates/cog-ha-matter/cog
run: |
printf '%s' "$SIGNING_KEY" \
| openssl pkeyutl -sign -inkey /dev/stdin -rawin \
-in dist/cog-ha-matter-x86_64.sha256 \
| base64 -w0 > dist/cog-ha-matter-x86_64.sig
echo "Signed cog-ha-matter-x86_64 ($(wc -c < dist/cog-ha-matter-x86_64.sig) bytes)"
- name: Upload workflow artifact
uses: actions/upload-artifact@v4
with:
name: cog-ha-matter-x86_64
path: |
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-x86_64
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-x86_64.sha256
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-x86_64.sig
if-no-files-found: warn
build-arm:
name: Build aarch64 (arm)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-unknown-linux-gnu
- name: Install cross-compiler
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
v2/target
key: cog-ha-matter-arm-${{ hashFiles('v2/Cargo.lock') }}
- name: Build release binary
working-directory: v2
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
run: |
cargo build -p cog-ha-matter --release --target aarch64-unknown-linux-gnu
mkdir -p crates/cog-ha-matter/cog/dist
cp target/aarch64-unknown-linux-gnu/release/cog-ha-matter \
crates/cog-ha-matter/cog/dist/cog-ha-matter-arm
# ^ matches Makefile's `dist/$(CRATE)-arm` so `make sign-arm` finds it
- name: Compute SHA-256
working-directory: v2/crates/cog-ha-matter/cog
run: make sign-arm
- name: Sign with Ed25519 (gated)
if: ${{ env.SIGNING_KEY != '' }}
env:
SIGNING_KEY: ${{ secrets.COGNITUM_OWNER_SIGNING_KEY }}
working-directory: v2/crates/cog-ha-matter/cog
run: |
printf '%s' "$SIGNING_KEY" \
| openssl pkeyutl -sign -inkey /dev/stdin -rawin \
-in dist/cog-ha-matter-arm.sha256 \
| base64 -w0 > dist/cog-ha-matter-arm.sig
echo "Signed cog-ha-matter-arm ($(wc -c < dist/cog-ha-matter-arm.sig) bytes)"
- name: Upload workflow artifact
uses: actions/upload-artifact@v4
with:
name: cog-ha-matter-arm
path: |
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-arm
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-arm.sha256
v2/crates/cog-ha-matter/cog/dist/cog-ha-matter-arm.sig
if-no-files-found: warn
publish-gcs:
name: Upload to GCS (gated)
needs: [build-x86_64, build-arm]
runs-on: ubuntu-latest
# Skip on dry-run dispatch; skip on tags when GCP_CREDENTIALS unset.
if: >
github.event_name == 'push' &&
vars.HAS_GCP_CREDENTIALS == 'true'
steps:
- uses: actions/checkout@v4
- name: Download x86_64 artifact
uses: actions/download-artifact@v4
with:
name: cog-ha-matter-x86_64
path: dist/
- name: Download arm artifact
uses: actions/download-artifact@v4
with:
name: cog-ha-matter-arm
path: dist/
- name: Auth to GCP
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.GCP_CREDENTIALS }}
- name: Set up gcloud
uses: google-github-actions/setup-gcloud@v2
- name: Upload binaries + sidecars
run: |
gsutil cp dist/cog-ha-matter-x86_64 gs://cognitum-apps/cogs/x86_64/cog-ha-matter-x86_64
gsutil cp dist/cog-ha-matter-x86_64.sha256 gs://cognitum-apps/cogs/x86_64/cog-ha-matter-x86_64.sha256
gsutil cp dist/cog-ha-matter-arm gs://cognitum-apps/cogs/arm/cog-ha-matter-arm
gsutil cp dist/cog-ha-matter-arm.sha256 gs://cognitum-apps/cogs/arm/cog-ha-matter-arm.sha256
if [ -f dist/cog-ha-matter-x86_64.sig ]; then
gsutil cp dist/cog-ha-matter-x86_64.sig gs://cognitum-apps/cogs/x86_64/cog-ha-matter-x86_64.sig
fi
if [ -f dist/cog-ha-matter-arm.sig ]; then
gsutil cp dist/cog-ha-matter-arm.sig gs://cognitum-apps/cogs/arm/cog-ha-matter-arm.sig
fi
- name: Print app-registry.json snippet for the cognitum-one PR
run: |
for arch in arm x86_64; do
sha=$(cat dist/cog-cog-ha-matter-$arch.sha256)
sig=$([ -f dist/cog-cog-ha-matter-$arch.sig ] && cat dist/cog-cog-ha-matter-$arch.sig || echo "")
cat <<EOF
--- $arch ---
{
"id": "ha-matter",
"version": "${GITHUB_REF_NAME#cog-ha-matter-v}",
"binary_url": "https://storage.googleapis.com/cognitum-apps/cogs/$arch/cog-cog-ha-matter-$arch",
"binary_sha256": "$sha",
"binary_signature": "$sig",
"description": "Home Assistant + Matter Cognitum Seed cog (mDNS + witness chain)",
"min_seed_version": "0.6.0",
"installable_on": ["$arch"]
}
EOF
done

View File

@ -19,12 +19,12 @@ build: build-arm build-x86_64
build-arm:
mkdir -p dist
cargo build -p $(CRATE) --release --target aarch64-unknown-linux-gnu
cp ../../target/aarch64-unknown-linux-gnu/release/$(CRATE) ./dist/cog-$(CRATE)-arm
cp ../../target/aarch64-unknown-linux-gnu/release/$(CRATE) ./dist/$(CRATE)-arm
build-x86_64:
mkdir -p dist
cargo build -p $(CRATE) --release --target x86_64-unknown-linux-gnu
cp ../../target/x86_64-unknown-linux-gnu/release/$(CRATE) ./dist/cog-$(CRATE)-x86_64
cp ../../target/x86_64-unknown-linux-gnu/release/$(CRATE) ./dist/$(CRATE)-x86_64
# --- Sign ---
@ -32,15 +32,15 @@ build-x86_64:
sign: sign-arm sign-x86_64
sign-arm: dist/cog-$(CRATE)-arm
sha256sum dist/cog-$(CRATE)-arm | cut -d' ' -f1 > dist/cog-$(CRATE)-arm.sha256
sign-arm: dist/$(CRATE)-arm
sha256sum dist/$(CRATE)-arm | cut -d' ' -f1 > dist/$(CRATE)-arm.sha256
# Signature: gcloud secrets versions access latest --secret=COGNITUM_OWNER_SIGNING_KEY \
# | openssl pkeyutl -sign -inkey /dev/stdin -rawin -in dist/cog-$(CRATE)-arm.sha256 \
# | base64 -w0 > dist/cog-$(CRATE)-arm.sig
# | openssl pkeyutl -sign -inkey /dev/stdin -rawin -in dist/$(CRATE)-arm.sha256 \
# | base64 -w0 > dist/$(CRATE)-arm.sig
@echo "TODO: wire Ed25519 sign step once COGNITUM_OWNER_SIGNING_KEY is provisioned to CI."
sign-x86_64: dist/cog-$(CRATE)-x86_64
sha256sum dist/cog-$(CRATE)-x86_64 | cut -d' ' -f1 > dist/cog-$(CRATE)-x86_64.sha256
sign-x86_64: dist/$(CRATE)-x86_64
sha256sum dist/$(CRATE)-x86_64 | cut -d' ' -f1 > dist/$(CRATE)-x86_64.sha256
@echo "TODO: wire Ed25519 sign step once COGNITUM_OWNER_SIGNING_KEY is provisioned to CI."
# --- Upload to GCS ---
@ -49,11 +49,11 @@ sign-x86_64: dist/cog-$(CRATE)-x86_64
upload: upload-arm upload-x86_64
upload-arm: dist/cog-$(CRATE)-arm
gsutil cp dist/cog-$(CRATE)-arm $(GCS_BUCKET)/arm/cog-$(CRATE)-arm
upload-arm: dist/$(CRATE)-arm
gsutil cp dist/$(CRATE)-arm $(GCS_BUCKET)/arm/$(CRATE)-arm
upload-x86_64: dist/cog-$(CRATE)-x86_64
gsutil cp dist/cog-$(CRATE)-x86_64 $(GCS_BUCKET)/x86_64/cog-$(CRATE)-x86_64
upload-x86_64: dist/$(CRATE)-x86_64
gsutil cp dist/$(CRATE)-x86_64 $(GCS_BUCKET)/x86_64/$(CRATE)-x86_64
# --- Manifest ---
@ -67,11 +67,11 @@ manifest:
.PHONY: release verify clean
release: build sign upload manifest
@echo "Release pipeline complete for cog-$(CRATE) v$(VERSION)"
@echo "Release pipeline complete for $(CRATE) v$(VERSION)"
verify:
@for arch in $(ARCHES); do \
f=dist/cog-$(CRATE)-$$arch; \
f=dist/$(CRATE)-$$arch; \
if [ ! -f $$f ]; then echo " MISSING $$f"; continue; fi; \
actual=$$(sha256sum $$f | cut -d' ' -f1); \
expected=$$(cat $$f.sha256 2>/dev/null); \
@ -80,4 +80,4 @@ verify:
done
clean:
rm -rf dist/cog-$(CRATE)-*
rm -rf dist/$(CRATE)-*

View File

@ -62,8 +62,8 @@ that appends:
"id": "ha-matter",
"version": "<the version make manifest printed>",
"binary_url": "https://storage.googleapis.com/cognitum-apps/cogs/{arch}/cog-ha-matter-{arch}",
"binary_sha256": "<from dist/cog-cog-ha-matter-{arch}.sha256>",
"binary_signature": "<from dist/cog-cog-ha-matter-{arch}.sig empty until signing is wired>",
"binary_sha256": "<from dist/cog-ha-matter-{arch}.sha256>",
"binary_signature": "<from dist/cog-ha-matter-{arch}.sig empty until signing is wired>",
"description": "Home Assistant + Matter Cognitum Seed cog (mDNS + witness chain)",
"min_seed_version": "0.6.0",
"installable_on": ["arm", "x86_64"]