Skip to main content

antithesis-moog

MOOG CLI for Antithesis test management on Cardano. Setup using the release binary (never moog-head — they encode types differently), identity switching (requester/agent/oracle wallets via being_*), token state inspection, retracting stuck requests during an oracle crash-loop, cleaning stale "running" tests, how the agent reconciles on-chain test-runs against the Antithesis REST API (email is gone — incomplete maps to failure), and the multi-tenant Antithesis configuration introduced by https://github.com/cardano-foundation/moog/pull/93. Triggers — "moog", "moog-head", "MOOG CLI", "being_requester", "being_agent", "being_oracle", "moog token", "moog facts test-runs", "moog retract", "moog agent report-test", "moog wallet info", "UnknownUpdateValidationFailure", "oracle crash-loop", "stale running test", "Antithesis report URL", "incomplete maps to failure", "Antithesis API reconciliation", "amaru-cardano", "pragma tenant", "MOOG_ANTITHESIS_LAUNCH_URL", "MOOG_REGISTRY".

Ir para a instalação

Informações da origem

Repositório
cardano-foundation/moog
Última atividade na origem
12 de junho de 2026 às 07:53
Idioma detectado do SKILL.md
inglês
Estrelas
13
Forks
3

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
antithesis-moog
description
MOOG CLI for Antithesis test management on Cardano. Setup using the release binary (never moog-head — they encode types differently), identity switching (requester/agent/oracle wallets via being_*), token state inspection, retracting stuck requests during an oracle crash-loop, cleaning stale "running" tests, how the agent reconciles on-chain test-runs against the Antithesis REST API (email is gone — incomplete maps to failure), and the multi-tenant Antithesis configuration introduced by https://github.com/cardano-foundation/moog/pull/93. Triggers — "moog", "moog-head", "MOOG CLI", "being_requester", "being_agent", "being_oracle", "moog token", "moog facts test-runs", "moog retract", "moog agent report-test", "moog wallet info", "UnknownUpdateValidationFailure", "oracle crash-loop", "stale running test", "Antithesis report URL", "incomplete maps to failure", "Antithesis API reconciliation", "amaru-cardano", "pragma tenant", "MOOG_ANTITHESIS_LAUNCH_URL", "MOOG_REGISTRY".
# MOOG Operations ## Setup — CRITICAL **Always use the release binary, never `moog-head`.** ```bash cd /code/moog # Download the release binary (same as the GitHub Actions workflow uses). # Latest release is v0.5.1.5; asset naming changed at v0.5.x — the portable, # statically-linked CLI is now `moog-<ver>-x86_64-linux-musl.tar.gz` (it # extracts a single `moog` binary; moog-agent / moog-oracle are separate assets). curl -sL "https://github.com/cardano-foundation/moog/releases/download/v0.5.1.5/moog-0.5.1.5-x86_64-linux-musl.tar.gz" | tar xz -C ./tmp/ export PATH=/code/moog/tmp:$PATH source tmp/prod-setup.sh ``` > **Asset naming history:** ≤ v0.4.1.2 used `moog-vX.Y.Z.W-linux64.tar.gz`; > v0.5.x switched to per-arch names — `moog-X.Y.Z.W-x86_64-linux-musl.tar.gz` > (musl = static/portable), plus `.AppImage`, `.deb`, `.rpm`, and aarch64 > variants. Always match what `.github/workflows/cardano-node.yaml` downloads. **WARNING**: `moog-head` in `/code/moog/tmp/` is a dev build. It reports the same `--version` as the release but encodes Duration differently (`{"minutes":0}` instead of `0`), producing requests the oracle can't parse (`UnknownUpdateValidationFailure`). Never symlink `moog-head` as `moog`. Always download the release binary. The workflow at `.github/workflows/cardano-node.yaml` downloads from `cardano-foundation/moog` releases — match that exactly. ## Active Antithesis tenant: `amaru-cardano` (2026-05-26 →) Antithesis migrated Cardano testing from the `cardano` tenant (`cardano.antithesis.com` / user `cardano`) to `amaru-cardano` (`amaru-cardano.antithesis.com` / user `pragma`). The moog-agent binary at `851aac3-dirty` (= `v0.4.1.2`) **hardcodes** the old URL at `src/User/Agent/PushTest.hs:246`. The multi-tenant fix lives in https://github.com/cardano-foundation/moog/pull/93 (branch `feat/multi-tenant-antithesis`, head `e6157f6`); it reads `MOOG_ANTITHESIS_LAUNCH_URL` and `MOOG_REGISTRY` from env. Anything older than that PR cannot reach the new tenant; treat the deployed `image:` tag as part of the diagnosis. **Working credentials matrix (verify with curl before rotating anything — see `feedback_split_config_test_outside.md`):** | Field | Value | Source | |---|---|---| | Antithesis URL | `https://amaru-cardano.antithesis.com/api/v1/launch/amaru-cardano` | env `MOOG_ANTITHESIS_LAUNCH_URL` | | Antithesis user | `pragma` | env `MOOG_ANTITHESIS_USER` | | Antithesis password | per `secrets.yaml.antithesisPassword` | secret file | | GAR registry | `us-central1-docker.pkg.dev/molten-verve-216720/cardano-repository` (unchanged at the migration) | env `MOOG_REGISTRY` | **Direct API check (outside moog) — succeeds with the right user/pw, 403 otherwise:** ```bash ssh agent 'PW=$(sudo awk "/^antithesisPassword:/{sub(/^antithesisPassword:[[:space:]]*\"?/,\"\");sub(/\"?[[:space:]]*$/,\"\");print}" /secrets/moog-agent/new/secrets.yaml) && \ curl -sS -o /dev/null -w "%{http_code}\n" -u "pragma:$PW" \ -X POST https://amaru-cardano.antithesis.com/api/v1/launch/amaru-cardano \ -H "Content-Type: application/json" -d "{}"' # 200 → creds OK; 403 → creds rejected (and same 403 with no -u, so 403 alone doesn't distinguish) ``` ## Identities | Role | Wallet | Set with | |------|--------|----------| | Requester | `tmp/requester.json` | `being_requester` | | Agent | `tmp/agent.json` | `being_agent` | | Oracle | `tmp/oracle.json` | `being_oracle` | Check current identity: `being` ## Key commands | Command | Purpose | |---------|---------| | `moog token --no-pretty` | Full token state with pending requests | | `moog facts test-runs --whose cfhal` | List test runs (run as `being_requester` to auto-decrypt the Antithesis report URL in the `url` field) | | `moog retract -w <wallet> -o <outref>` | Retract a request you own | | `moog agent report-test -i <id> -w <wallet> --outcome unknown --duration 0 --url "reason"` | Force-finish a stale test (manual override) | | `moog antithesis runs --no-pretty` | List the Antithesis runs the agent reconciles against (see "How the agent reconciles results") | | `moog wallet info` | Show wallet owner hash | ## Reading Antithesis runs directly (`moog antithesis`, v0.5.1.0+) `moog antithesis` (added in v0.5.1.0) reaches the Antithesis report data through the Moog proxy — no browser, SSO cookie, or Playwright. All subcommands emit newline-delimited JSON; pair with `--no-pretty | jq`. Exit codes on `runs`: `0` success, `2` auth/SSO failure, `3` proxy/network failure, `4` invalid JSON from proxy. | Command | Purpose | |---------|---------| | `moog antithesis runs [--limit N] [--cursor C]` | List runs (paginated; `--limit` max 100). Each entry carries `run_id` (e.g. `46d4…-54-7`), `status` (`in_progress` / `completed` / `incomplete`), and a JSON `description` with the testRun `directory` (e.g. `testnets/cardano_node_governance`). | | `moog antithesis run --run-id ID` | Full details of one run. For `incomplete` runs it includes `failure_moment {input_hash, vtime}`; for `completed` runs it carries `links.triage_report` (the report URL). | | `moog antithesis properties --run-id ID` | Property pass/fail for a **completed** run (404 while still in progress). | | `moog antithesis events --run-id ID [--q TEXT]` | Stream matching events as NDJSON; free-text substring via `--q`; upstream caps at 50 results. | | `moog antithesis logs --run-id ID --input-hash H --vtime V` | Logs at a specific moment. Needs a real moment — `in_progress` runs 400 (`Invalid query parameters`); a degenerate `0/0` failure moment returns empty. | | `moog antithesis build-logs --run-id ID` | Stream the config-image **build** logs as NDJSON (`{timestamp, text, stream}`). Works regardless of run status — the fallback when there's no usable failure moment. | **Find a run, then read it** — e.g. the latest governance run's build logs: ```bash # Locate the run id by directory (the banner from prod-setup.sh precedes the JSON, # so select the JSON line explicitly): moog antithesis runs --limit 100 --no-pretty | grep '^{"data"' \ | jq -r '.data[] | select(.description|contains("governance")) | [.created_at, .status, .run_id] | @tsv' | head # Moment logs need input_hash + vtime from `run`; build-logs need only the id: moog antithesis build-logs --run-id 46d4033b0cbaec3715d6a7a77b4411cb-54-7 --no-pretty ``` ## Retract stuck requests (oracle crash-loop fix) ```bash # 1. List pending requests on token moog token --no-pretty | jq -c '.requests[] | {outref: .request.outputRefId, owner: .request.owner}' # 2. Match owner to wallet (check with: moog wallet info) # 3. Retract each owned request being_requester # or being_agent moog retract -w $MOOG_WALLET_FILE -o "<outref>" # 4. Oracle picks up changes automatically (no restart needed in theory, # but restart if it's stuck in a crash-loop reading stale state) ``` ## How the agent reconciles results (Antithesis API, v0.5.1.2+) **The agent derives outcomes from the Antithesis REST API, not email.** The service loop (commit `ca82717e`, shipped in v0.5.1.2+) lists Antithesis runs and matches each to an on-chain test-run by its rendered `description`, then advances the on-chain phase. Reconciliation rules live in `src/User/Agent/Antithesis/State.hs`: - **`pending` on-chain** → no matching Antithesis run yet ⇒ launch it; exactly one match ⇒ accept; many ⇒ flagged duplicate. - **`accepted` (running) on-chain** → when the matched run reaches a *terminal* API status, write a `finished` fact with this mapping (`terminalOutcome`): | Antithesis status | on-chain outcome | |---|---| | `completed` | `success` — **only if** the run has a `triage_report` link; without it the agent keeps waiting (success is never attested without the report) | | `incomplete` | **`failure`** | | `cancelled` | `failure` | | `starting` / `in_progress` / `unknown` | keep waiting | - **Terminal but no triage-report link** (`incomplete` / `cancelled`): finished as `failure` anyway, with a deterministic synthetic URL `antithesis://runs/<run_id>/no-triage-report` (`terminalNoReportOutcome`, fix `04a74a40` / issue #138) so these no longer stay `accepted` forever. So **`incomplete` has no on-chain representation of its own — it is recorded as `outcome: failure`** (the report URL if one exists, else the `no-triage-report` synthetic URL). The on-chain `duration` field is the *requested* hours, not actual runtime, so a truncated run is invisible once finished. ## Clean up stale "running" tests With the v0.5.1.2+ loop, terminal Antithesis runs auto-finish, so a genuinely stuck `accepted` fact now means either a **correlation miss** (the agent's `description` match failed — e.g. the run was launched by a different binary) or an agent running a **pre-v0.5.1.2** binary. The manual escape hatch is unchanged: ```bash # 1. Find accepted (running) tests on-chain moog facts test-runs --whose cfhal --no-pretty | jq -c '.[] | select(.value.phase == "accepted") | {id: .id[:16], commit: .key.commitId[:8], try: .key.try}' # 2. Confirm against the Antithesis API what status the run actually reached moog antithesis runs --limit 100 --no-pretty | grep '^{"data"' | jq -r '.data[] | [.status, .run_id] | @tsv' # 3. Report as unknown to finish them (manual override) being_agent moog agent report-test -i <full-test-run-id> -w $MOOG_WALLET_FILE --outcome unknown --duration 0 --url "stale-uncorrelated-run" ``` ## Infrastructure SSH | Host | Service | Container | |------|---------|-----------| | `oracle` | moog-oracle v0.4.1.2 | `oracle-moog-oracle-1` | | `agent` | moog-agent (release binary; the v0.5.1.2+ loop reconciles via the Antithesis API) | `agent-moog-agent-1` | Compose lives at `/opt/hal/infrastructure/moog/agent/docker-compose.yaml` on the `agent` host. Edits go in there, not in `/home/paolino/hal/...` (which is a checkout, not the deployed copy). ## Secrets layout ### Agent host (`agent`) ``` /secrets/moog-agent/ ├── old/ # previous rotation generation (kept for rollback) │ ├── secrets.yaml │ └── docker/config.json └── new/ # currently mounted by compose ├── secrets.yaml # githubPAT, antithesisPassword, trustedRequesters, │ # mnemonics or encryptedMnemonics, walletPassphrase, slackWebhook, │ # tokenId, mpfsHost, registry, antithesisUser, antithesisLaunchUrl, │ # pollIntervalSeconds, minutes, wait └── docker/ ├── config.json # docker auth (auths block with base64 _json_key:<sa>) └── sa-key.json # raw GCP service-account JSON (kept for regenerating config.json) agent-wallet (a separate compose secret) └── /secrets/moog-agent/new/agent.json (or wherever the agent-wallet.file points) ``` Compose: `/opt/hal/infrastructure/moog/agent/docker-compose.yaml`. ### Oracle host (`oracle`) ``` /home/paolino/secrets/moog/oracle/ ├── oracle.json # oracle wallet (mnemonics OR encryptedMnemonics) └── secrets.yaml # githubPAT (cfhal-owned, distinct from agent's PAT), # walletPassphrase (if oracle.json is encrypted) ``` Compose: `/opt/hal/infrastructure/moog/oracle/docker-compose.yaml`. Container env points `MOOG_WALLET_FILE=/run/secrets/oracle-wallet` and `MOOG_SECRETS_FILE=/run/secrets/secrets` at the in-container tmpfs paths the compose materialises from the two host files. **The oracle wallet CANNOT be rotated on a live token.** The on-chain token's `state.owner` is permanently bound to the wallet's pubkey-hash at mint time (`moog token state --no-pretty | jq .state.owner`). Rotating the oracle wallet means burning the token and reminting — which loses the entire test-run history. If the oracle mnemonics leak (as happened 2026-05-28 — see lessons), the only mitigations are (a) `moog wallet encrypt` so on-disk material isn't immediately usable without the passphrase, and (b) accepting that the preprod blast radius is limited to fraudulent inclusions on this token's history and drainable preprod ADA — no mainnet impact. Treat the oracle wallet file as if it were a mainnet hot key: never `cat`, never `head`, never `scp` it off the host. `old/` and `new/` may have *different* `githubPAT` / `antithesisPassword` / docker `config.json` values. When something fails on auth, diff the two — a half-applied rotation is a real failure mode. **`docker/config.json` is NOT the raw SA key.** It must be a real docker config: ```json { "auths": { "us-central1-docker.pkg.dev": {
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub