mirror of
https://github.com/hanzoai/cli.git
synced 2026-10-30 15:00:27 +00:00
hanzo-gen moves to 6741119: programs by full path only, a home read from the environment alone, run homes that survive no ending, the meter by brand. So the CLI: - link names the tmux server it works in (Tmux); a link uses the default socket, and its tests start one at a temp socket and kill it after, so the suite never reaches a person's tmux - holds the Store's one config behind a lock held for the whole ask, so an identity IAM moves during a heartbeat is never written back over; the profile and the meter are asked under it, the meter as the session's brand (Seam::open takes the brand) - finds npm and uv by full path, and hands the __mcp proxy its root - install.sh checks an attested tool's download (HANZO_INSTALL_SIGNER) against its workflow and tag with a signed-in gh, refuses a mismatch, and says so when it could not check - the console's screenshot test writes into a temp dir, not /tmp - hanzo.yml runs make test with HOME empty and read-only, then empty and writable and still empty after
93 lines
5.3 KiB
YAML
93 lines
5.3 KiB
YAML
# Canonical CI config for hanzoai/cli — read by the hanzoai/ci reusable
|
|
# (.github/workflows/cicd.yml) and by platform.hanzo.ai. This repo had neither
|
|
# this file nor a Makefile, which is why `genspec` — the one thing that keeps
|
|
# the CLI's command surface honest — was reachable only by a maintainer typing
|
|
# it. A capture nothing re-asks goes stale silently, and this one did: it was
|
|
# 7 operations short and 8 operations wrong against the document cloud had
|
|
# already committed.
|
|
#
|
|
# NO images: the CLI is a binary a person installs, not a container a cluster
|
|
# runs. NO binaries: this repo's binaries are the five-target cross-build in
|
|
# .hanzo/workflows/release-matrix.yml (cargo-zigbuild + a vendored macOS SDK) —
|
|
# that is genuinely per-repo build logic and it is already correct; the generic
|
|
# Go-shaped lane here cannot produce it. NO deploy: nothing here rolls out.
|
|
#
|
|
# That path is `.hanzo/`, not `.github/`: the runners belong to git.hanzo.ai and
|
|
# github.com has none, so a pipeline under `.github/` queues forever instead of
|
|
# building. Both CI files in this repo live under `.hanzo/workflows/` for that
|
|
# one reason.
|
|
#
|
|
# What CI owns for this repo is the two gates below and the client lane.
|
|
|
|
client:
|
|
# The document, by value at a pinned ref: the lane fetches openapi.yaml at the
|
|
# ref .spec-lock names and refuses on a digest mismatch. It does not choose the
|
|
# ref and does not write the lock — on a push it is check-only at the locked
|
|
# one. What MOVES the pin is the nightly re-pin in .hanzo/workflows/drift.yml,
|
|
# which reads hanzo-inc/cloud's main and commits the result once `make verify`
|
|
# rules on it. Reading api.hanzo.ai here would name whatever is serving now
|
|
# rather than a release.
|
|
spec: { repo: hanzo-inc/cloud, path: openapi.yaml }
|
|
generate: ./scripts/generate.sh
|
|
# PATCH only, derived. The command surface is the document's; this crate only
|
|
# restates it, so it never earns a minor or a major.
|
|
version: "Cargo.toml:grep -m1 '^version' Cargo.toml | sed -E 's/.*\"(.*)\".*/\\1/'"
|
|
|
|
# THE CAPTURE GATE is NOT here, and that is the point: hanzoai/ci's `client:` lane
|
|
# asks it for all eight client repos in one place, on every push — fetch the
|
|
# document .spec-lock names, refuse if the ref moved under it, re-run the
|
|
# derivation, refuse any delta, write nothing. `make spec-check` is the same
|
|
# question a human asks locally, through the same script.
|
|
#
|
|
# THE DRIFT GATE is a different question — a capture can equal its inputs exactly
|
|
# and still describe a surface production stopped serving, or miss a product
|
|
# production started — and it IS here, inside `cargo test`, because it stopped
|
|
# needing the network. It rules on `spec/live.json`: the raw answers the live
|
|
# server gave to every probe and to a nonsense-sibling CONTROL for each, captured
|
|
# by `make live` and committed. So the push gate asks both directions on every
|
|
# push, in the one lane, with nothing to fail for a reason that is not drift.
|
|
#
|
|
# It used to need the wire, and that is what made it fragile: a gate needing the
|
|
# network in CI gets switched off, and this one first sat in the list below where
|
|
# a failure in the client step or the KMS login meant it was never reached at all.
|
|
# It was never asked once that way.
|
|
#
|
|
# What still needs the wire is the OTHER half — has production moved under the
|
|
# committed evidence? — and that has its own job, its own triggers and nothing
|
|
# else in it: `.hanzo/workflows/drift.yml`, nightly and on a click, `make
|
|
# live-check`. One predicate per place, and neither shares its fate with anything.
|
|
#
|
|
# `make test`, never a bare `cargo test`: the gates below exec maintainer
|
|
# binaries that `cargo test` does not build, and a gate that dies on NotFound
|
|
# reads exactly like a gate that passed. One invocation, in the Makefile.
|
|
#
|
|
# THE LINT GATE HAS TO INSTALL WHAT IT LINTS WITH. `dtolnay/rust-toolchain@stable`
|
|
# provisions rustc and cargo and no components, so `cargo clippy` answered
|
|
# "'cargo-clippy' is not installed for the toolchain" and every main build went
|
|
# red on it — six in a row, while `make test` above passed every one of them. A
|
|
# gate that cannot run is worse than no gate whichever way it lands: red, it
|
|
# teaches people the build lies; green, it teaches them nothing at all. It asks
|
|
# for the component first now, which is idempotent and costs a cached download.
|
|
#
|
|
# THE SUITE NEVER TOUCHES A HOME, and the gate says so the way hanzoai/gen's
|
|
# does: it runs against an empty HOME it cannot write, then against an empty one
|
|
# it can, which must still be empty after. A runner can be a person's machine,
|
|
# and a test that wrote there once rewrote that person's agent configs. Cargo
|
|
# and rustup keep their own homes, named before HOME moves.
|
|
test:
|
|
- name: cargo-test
|
|
run: |
|
|
set -euo pipefail
|
|
export CARGO_HOME="${CARGO_HOME:-$HOME/.cargo}" RUSTUP_HOME="${RUSTUP_HOME:-$HOME/.rustup}" RUSTC_WRAPPER=
|
|
export PATH="$CARGO_HOME/bin:$PATH"
|
|
unset XDG_DATA_HOME XDG_CONFIG_HOME XDG_CACHE_HOME XDG_STATE_HOME
|
|
ro=$(mktemp -d); tmp=$(mktemp -d)
|
|
trap 'chmod u+w "$ro"; rm -rf "$ro" "$tmp"' EXIT
|
|
chmod 0555 "$ro"
|
|
HOME="$ro" make test
|
|
HOME="$tmp" make test
|
|
left=$(find "$tmp" -mindepth 1 | head -20)
|
|
[ -z "$left" ] || { echo "::error::the test suite wrote into HOME:"; echo "$left"; exit 1; }
|
|
- name: clippy
|
|
run: rustup component add clippy && cargo clippy --locked --all-targets -- -D warnings
|