Skip to content

v0.0.1 candidate - #16

Merged
ndenny merged 93 commits into
mainfrom
develop
Sep 18, 2026
Merged

ndenny merged 93 commits into
mainfrom
develop

Conversation

@ndenny

@ndenny ndenny commented Jul 7, 2026

Copy link
Copy Markdown
Member

No description provided.

Gary-Darnell and others added 30 commits May 28, 2026 12:48
…claude trying basic cli commands instead of the skills
- Remove redundant tests
- Update commands test so we don't trigger ensureProject
…ting

Ds 5672 set up ci build and testing
…robust base64 decode, fail on tag publish without signing secret, safer goreleaser install\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…goreleaser

- upload darwin artifacts from Linux release job
- download/sign/rechecksum darwin archives on macOS
- replace mac assets on the GitHub release

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- remove broken mac_only path gating
- fail fast on all required signing secrets for tags
- validate related signing secrets before import
- use printf for base64 decoding inputs
- pass keychain explicitly to codesign

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- use boolean inputs context for snapshot conditions
- create tag releases as drafts before macOS signing
- finalize release after signed macOS assets are uploaded

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… prov profile

- Add xcrun notarytool step (sign + notarize per binary via zip submission)
- Add APPLE_ID/APPLE_ID_PASSWORD/APPLE_TEAM_ID to preflight secrets check
- Guard workflow_dispatch against non-tag + non-snapshot to prevent broken releases
- Replace secrets.X != '' step conditions with a secrets_check step output
- Remove checkout/setup-go/test from macOS job (pure signing job, no build needed)
- Remove APPLE_PROV_PROFILE handling (not needed for CLI tool signing)
- Simplify base64 decode to base64 -D (always macOS runner)
- Add security set-keychain-settings to prevent auto-lock during notarization
- Add timeout-minutes to both jobs
- Fix .gitignore missing trailing newline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Skip release-macos job entirely when snapshot=true to avoid
  spinning up a macOS runner unnecessarily
- Pass APPLE_CERT_P12 as an env var in secrets_check rather than
  interpolating the secret directly into shell
- Fix mktemp resource leak in notarization loop: use mktemp -d
  and rm -rf the directory instead of leaking the base tempfile

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use SNAPSHOT env var in Validate dispatch inputs step instead of
  interpolating ${{ inputs.snapshot }} directly into shell
- Remove inputs.snapshot != true from all step-level conditions in
  release-macos, since the job-level if already gates on this

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously goreleaser ran with --draft which created the GitHub release
as a draft but still triggered the blobs publisher, uploading unsigned
macOS artifacts and a mismatched checksums.txt to GCS immediately.

Fix: run goreleaser with --skip publish on tag pushes so it builds all
artifacts without touching GCS or GitHub. Create the GitHub draft release
manually with gh after the build. Expand the artifact store upload to
include all platforms. In the macOS job, after signing, upload all
artifacts (Linux + Windows + signed macOS + updated checksums) to GCS
before publishing the draft release. GCS is now never written until
signing is complete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without this, a missing or malformed GOOGLE_APPLICATION_CREDENTIALS
secret would only surface late in the macOS job — after the draft
release is created and artifacts are signed — leaving a partial release
state requiring manual cleanup.

The new step validates the secret is present and is valid JSON before
goreleaser runs, matching the existing pattern for Apple signing secrets.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Switch GCP auth to Workload Identity Federation (no long-lived key
  stored as a secret); mounts WIF credentials into the goreleaser-cross
  Docker container via ACTIONS_ID_TOKEN_REQUEST_URL/TOKEN env vars
- Remove duplicate go test step from workflow (goreleaser before.hooks
  already runs it)
- Drop --parallelism 4 to 2 to match ubuntu-latest's 2 vCPUs
- Add comment on v0.* tag pattern explaining it's intentional
- Add brews section to .goreleaser.yml for Homebrew tap publish

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two issues prevented the Homebrew tap from ever being updated:

1. GoReleaser ran with --skip publish on every tag push, so the brews
   publisher never executed. Fix: add a goreleaser publish step in the
   macOS job after the GitHub release is public, skipping only the
   publishers handled manually (blobs, release, announce).

2. GITHUB_TOKEN cannot push to APImetrics/homebrew-tap (different repo).
   Fix: use HOMEBREW_TAP_GITHUB_TOKEN (a PAT/App token with write access
   to the tap) via brews.repository.token in .goreleaser.yml.

Also: upload artifacts.json + metadata.json from the Linux build so the
macOS job has the goreleaser dist metadata needed to run goreleaser
publish. Update artifacts.json checksums in the signing loop so goreleaser
publish uses the signed (not original) macOS archive hashes. Add repo
checkout to release-macos so goreleaser-action can find .goreleaser.yml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Uses actions/create-github-app-token@v1 to generate a short-lived
installation token at release time instead of storing a long-lived PAT.
The App is installed only on APImetrics/homebrew-tap with Contents:write,
so the blast radius is minimal and no personal account is involved.

Required secrets: GH_APP_ID, GH_APP_PRIVATE_KEY (replace HOMEBREW_TAP_GITHUB_TOKEN).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents all required one-time configuration: GCP Workload Identity
Federation setup (with gcloud commands), GitHub App creation for
Homebrew tap access, Apple signing certificate setup, and a complete
secrets reference table. Also covers how to cut a release and run
snapshot builds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix invalid --skip values in Publish Homebrew formula step: remove
  'build' and 'checksum' (not valid in v2.12.7), replace with correct
  values. In v2, '--skip archive' encompasses the build step; '--skip
  publish' covers both the GitHub release and blob storage publishers.
  Final skip list: before,archive,sign,sbom,publish,announce,validate,notarize
- Add google-github-actions/setup-gcloud@v2 step after WIF auth in
  release-macos to explicitly install gsutil rather than relying on
  runner image pre-installation
- RELEASING.md: note that GH_APP_PRIVATE_KEY must include PEM header
  and footer lines

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
python3 -c "..." with a multi-line string placed Python code at zero
indentation inside the run: | literal block, which caused the YAML
parser to treat those lines as outside the block and fail on line 255.

Fix: switch to a heredoc (python3 << 'PYEOF') so Python content stays
at the run block's indentation level (10 spaces), which YAML strips
before passing to the shell, leaving Python with correct zero-indent
top-level code. Variables passed via env vars (PATCH_NAME/PATCH_SHA)
since heredocs don't support sys.argv.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ning

DS-5672: Harden release workflow and add Homebrew tap
… idempotent

- Remove the Authenticate to Google Cloud step from the Linux job —
  goreleaser always runs with --skip publish there so GCS uploads never
  happen from that job; the WIF credential was never used.
- Remove the CREDS_OPTS Docker mount logic that accompanied it.
- Make Create GitHub draft release idempotent: if the release already
  exists (workflow rerun after a partial failure), re-upload artifacts
  with --clobber instead of failing on a duplicate create.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ndenny

ndenny commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

Never mind - the mac signing failed because I had to accept some new t's & c's. All good to go now.

ndenny and others added 20 commits July 9, 2026 15:14
Added documentation link and APIContext Inc attribution.
Enhance README with documentation and attribution
… agents

Add eight current-format Claude Code Skills covering the operational
monitoring lifecycle, embedded in the CLI and installable to
.claude/skills/<name>/SKILL.md via a new, additive `skills install
--claude-skills` flag. Also add a repo-root AGENTS.md so non-Claude
agents (OpenAI Codex, Cursor, Gemini CLI, ...) get the same guidance.

Skills: project-bootstrap, weekly-health-review, failure-investigation,
incident-triage, monitoring-estate-audit, slo-review, config-as-code,
performance-analytics. Every command and JSON shape is grounded in the
built CLI's actual command surface (branch develop, commit 9697405).

The existing setup-* skills, `--claude-code`, `--codex`, `--dir`, and
`onboard` behavior are unchanged; this is purely additive.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`apimetrics --version` now prints the OpenAPI document version
(info.version) and the date/time the spec was last fetched from the
server, to aid customer support and debugging.

- Persist the spec version in the cached API struct (SpecVersion),
  captured from libopenapi's model.Info.Version (previously discarded).
- Record a `<name>.checked` timestamp in cacheAPI (24h refresh TTL
  unchanged).
- Add a custom cobra version template that appends the two lines.
- Make --version a pure reporting command: it reads the cached spec
  state from disk and skips the network load, so it works offline and
  never triggers an auth prompt.

Fixtures updated: testdata/*/output.yaml now include spec_version.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address PR review: versionExtraInfo now only trusts the on-disk cache
when its CLIVersion matches the running binary, mirroring Load's
validity check, so --version won't report a stale spec version/timestamp
after a binary upgrade (the CLI would refetch that cache anyway). Also
skip the cache lookup entirely when api-name is empty.

Add TestVersionExtraInfo covering the no-cache, valid-cache, and
stale-cache (mismatched CLIVersion) paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Loading the OpenAPI spec (the entrypoint and /openapi.json) is done
against public endpoints, but MakeRequest was still applying the
profile's auth, which triggered an interactive login on any invocation
that hit a cache miss -- including `apimetrics`, `apimetrics --help`,
completion, and config commands that never call an API operation.

Add an IgnoreAuth() request option and use it for the two spec-loading
requests in Load, so building the command tree never prompts for login.
Auth is still applied for real API operations (which don't pass the
option).

Add TestIgnoreAuth verifying the auth hook is skipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Address PR review: the offline/no-auth skip for --version matched only
the literal "--version" arg, so `--version=true` would still trigger the
network load. Register a version bool on GlobalFlags and read it via the
eager parse, which handles every bool form (--version, --version=true,
--version=false) consistently with Cobra.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update Homebrew installation command for APImetrics CLI
…-cmd

Report OpenAPI spec version and last-check date in --version
Each environment now bakes in its own command name, which also names the
config and cache directories, so the builds can be installed side by side
and stay logged in to different environments at the same time.

- Add qc-stable (build tag `qcstable`) and beta (build tag `beta`)
  configurations. Beta points at beta-client.apimetrics.io but authenticates
  against production Auth0. This also fixes the duplicate build tag that made
  config_qc_stable.go collide with config_qc.go.
- Derive the config and cache directories from the per-build app name, and
  map hyphens to underscores when building the <APPNAME>_CONFIG_DIR and
  <APPNAME>_CACHE_DIR overrides so hyphenated names remain usable.
- Report the environment, API host and config directory in --version.
- Add goreleaser configs for qc-stable and beta, and an environment selector
  to the develop workflow.
- Sign and notarize tagged environment builds: a semver prerelease suffix on
  a v0.* tag (-beta-N, -qc-N, -qc-stable-N) selects the environment and
  publishes a GitHub prerelease. Homebrew and WinGet stay production-only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nfiguration-for-cli

DS-5850 Add qc-stable and beta builds, installable in parallel
Authenticate with an APImetrics service account instead of the browser
login, which is what makes the CLI usable from CI and other headless
environments. Point `--service-account` (or the environment variable
`<APP_NAME>_SERVICE_ACCOUNT`) at the JSON file the web app issues and
every request uses the OAuth 2.0 client credentials grant.

The client credentials grant issues no refresh token (RFC 6749 4.4.3) and
Auth0 rejects `offline_access` for it, so the hour-long access token is
cached and simply re-requested on expiry. Tokens are cached under a key
derived from the credentials rather than the profile, so a service
account never picks up the interactive login's token or another
account's, and rotating a secret invalidates the cache instead of
silently serving the old token.

Also add `--project-id` / `<APP_NAME>_PROJECT_ID`. Service accounts are
granted access to specific projects and headless runs cannot answer the
interactive project picker, so without this the first call in CI hangs on
a prompt. The override applies to a single run and never overwrites the
project saved by `project select`; a non-TTY run with no project now
fails with an actionable message rather than a dead prompt.

Global flags are parsed exactly once, in Run. Parsing them a second time
would append to the repeatable flags, doubling every `-H` and `-q` value,
so the service account and project overrides are applied there rather
than in Init.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Include the audience in the service account's token cache key. The file
format lets a service account name its own audience, so two files sharing
a client id, secret and token URL but naming different audiences would
otherwise share a cache entry and be handed a token minted for the wrong
audience.

Clear the `.refresh` entry in `logout --service-account` alongside the
rest. The client credentials grant issues no refresh token, but
TokenHandler writes one whenever the endpoint returns it and reads it
back when rebuilding a cached token, so leaving it behind would let a
stale entry outlive a logout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 1, 2026 07:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 45 out of 46 changed files in this pull request and generated 4 comments.

Suppressed comments (1)

README.md:16

  • "MacOS" should be spelled "macOS" (Apple’s official capitalization).
## MacOS

Comment thread cli/request_test.go
Comment thread README.md
Comment thread skills/skills.go
Comment thread cli/cli_test.go
Add embedded Claude Code Skills + AGENTS.md for AI agents
@ndenny
ndenny disabled auto-merge September 18, 2026 21:03
@ndenny
ndenny merged commit 28246f6 into main Sep 18, 2026
3 checks passed
ndenny added a commit that referenced this pull request Sep 21, 2026
Docs:
- README/skills no longer claim create commands read JSON from stdin
  *only* — cli.GetBody also accepts CLI Shorthand args. Heredoc stdin is
  still the recommended form, and the "no --body/--data/-d" fact stands.
- README: demote Manual installation / MacOS / Windows / Linux to
  subheadings under Installation so the hierarchy reads correctly.
- setup-api-monitor.md: the scheduled target is the call ID, not the
  "monitor ID", matching the rest of that skill.

Code:
- skills: updateClaudeMD no longer swallows os.ReadFile errors. An
  unreadable-but-present CLAUDE.md was treated as empty and then
  overwritten, destroying its contents.

Tests:
- oauth: cover the reflected-XSS hardening in the auth callback handler.
  Both new escaping tests fail if html.EscapeString is removed.
- skills: table-driven tests for resolveTarget (no flag, each flag, and
  every mutually-exclusive combination).
- cli: TestAuthHookFailure was order-dependent — it needs a non-nil
  configs map and rsh-profile set, or it panics before reaching the auth
  hook. It now runs standalone.
- cli: typo in TestLoadCache comment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ndenny added a commit that referenced this pull request Sep 21, 2026
Address Copilot review feedback from PR #16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants