From 3833929dcb301683049858ab1a299015b9510303 Mon Sep 17 00:00:00 2001 From: ruv Date: Sat, 23 May 2026 23:05:54 -0400 Subject: [PATCH] cog-ha-matter (ADR-116 P8): CI release workflow + fix inherited filename bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .github/workflows/cog-ha-matter-release.yml | 200 ++++++++++++++++++++ v2/crates/cog-ha-matter/cog/Makefile | 30 +-- v2/crates/cog-ha-matter/cog/README.md | 4 +- 3 files changed, 217 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/cog-ha-matter-release.yml diff --git a/.github/workflows/cog-ha-matter-release.yml b/.github/workflows/cog-ha-matter-release.yml new file mode 100644 index 00000000..05f12716 --- /dev/null +++ b/.github/workflows/cog-ha-matter-release.yml @@ -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 < 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)-* diff --git a/v2/crates/cog-ha-matter/cog/README.md b/v2/crates/cog-ha-matter/cog/README.md index cc353896..a1d5a42b 100644 --- a/v2/crates/cog-ha-matter/cog/README.md +++ b/v2/crates/cog-ha-matter/cog/README.md @@ -62,8 +62,8 @@ that appends: "id": "ha-matter", "version": "", "binary_url": "https://storage.googleapis.com/cognitum-apps/cogs/{arch}/cog-ha-matter-{arch}", - "binary_sha256": "", - "binary_signature": "", + "binary_sha256": "", + "binary_signature": "", "description": "Home Assistant + Matter Cognitum Seed cog (mDNS + witness chain)", "min_seed_version": "0.6.0", "installable_on": ["arm", "x86_64"]