feat(auth): M19 harness auth tooling — auth.sh checkpoint + per-launch account injection (#47)

Investigation (pi 0.84.4 docs + host auth.json metadata, values never
read): provider stacking is native (one auth.json keyed by provider;
resolution --api-key > auth.json > env > models.json; OAuth auto-refresh).
Multi-account per provider is NOT native -> named-file design:
auth.<account>.json + per-launch injection.

- scripts/auth.sh: status (provider names, credential types, perms,
  env-side names informational — never credential material) and accounts
  (named files, active marker). Exit codes per convention: 3 missing for
  a read, 2 unparseable, 4 file/environment (symlinks refuse).
- scripts/agent.sh --auth <account>: resolves auth.<account>.json and
  exports PI_AUTH_FILE (the existing compose read-only mount source — no
  new plumbing); missing/invalid account refuses pre-container.
- scripts/test-auth.sh: 13 no-Docker cases; core assertion is the safety
  property itself — fixture key/token/env VALUES never reach output.
- Docs: TOOLS.md Auth section, AGENTS.md command surface + suites.

Headless task runs keep the default credential (worker auth selection is
a separate policy decision). Real-host smoke: anthropic/openai-codex
oauth + zai api_key reported, perms 600, no named accounts yet.

Suites 24/90/14/17/13 + verify green. Agreed sequence M16-M19 complete;
M20 owner-gated.
This commit is contained in:
2026-09-03 19:58:50 -05:00
parent d1d7b5598d
commit 073bbfdb6a
8 changed files with 259 additions and 6 deletions
+20 -1
View File
@@ -54,7 +54,25 @@ contract's tools are a ceiling the seat definition or `--tools` may narrow,
never escalate past. Missing/invalid contract refuses the launch; empty
intersection = loud tool-free seat. An explicit `MOSAIC_AGENTS_DIR` override
that cannot resolve the named seat also refuses (#46) — unset the override
for the M13 plain governed TUI.
for the M13 plain governed TUI. `--auth <account>` injects
`auth.<account>.json` (beside the active credential file) as the launch's
`PI_AUTH_FILE`; a missing/invalid account refuses (M19).
## Auth (credentials)
Credential checkpoint over pi's auth model (one `auth.json` keyed by
provider; resolution order `--api-key``auth.json` → env → models.json).
No credential material is ever printed — provider names, credential types,
and env var NAMES only.
| Command | Purpose | Notes |
|---|---|---|
| `scripts/auth.sh status` | Per-provider credential report | Types (`oauth`/`api_key`), perms, env-side names (informational); exit 3 when the file is missing |
| `scripts/auth.sh accounts` | List named account files | `auth.<account>.json` beside the credential file; marks the active one |
The file is the compose read-only mount source (`PI_AUTH_FILE`, default
`~/.pi/agent/auth.json`); named accounts ride the same mount per launch via
`agent.sh --auth`. Headless task runs keep the default credential.
## Release
@@ -86,6 +104,7 @@ Push is never automatic.
| `scripts/test-task.sh` | Task selftests + live cases | 90 cases |
| `scripts/test-release.sh` | Release selftests | 14 cases |
| `scripts/test-conductor.sh` | Auto-apply selftests (sandboxed) | 17 cases |
| `scripts/test-auth.sh` | Auth checkpoint selftests (no Docker) | 13 cases |
| `scripts/gitea-api.sh <METHOD> <path> [body]` | Gitea API helper | Token never on argv/stdout |
## Tools (host-side)