Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/scheduled_tasks.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sessionId":"15ed6d5b-da97-4056-bd7c-9cd50b309a62","pid":38820,"acquiredAt":1775846795737}
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
with:
go-version-file: go.mod
cache: true
- run: go build ./cmd/broker ./cmd/aactl
- run: go build ./cmd/broker ./cmd/awrit

vet:
name: vet
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

# Go build artifacts
*.test
/awrit
/aactl
/broker
/agentauth-broker
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Renamed CLI binary `aactl` → `awrit` (TD-CLI-001)

- **`cmd/aactl/` → `cmd/awrit/`** — directory renamed. Cobra command name changed (`Use: "aactl"` → `Use: "awrit"`). All internal CLI output, help text, and error messages updated.
- **`docs/aactl-reference.md` → `docs/awrit-reference.md`** — reference doc renamed. All example commands in the doc rewritten to use `awrit`.
- **Docs, scripts, tests, README, CONTRIBUTING, docker-compose.yml, .github/workflows/ci.yml, .gitignore** — every `aactl` reference in ship-to-main files rewritten to `awrit`. Evidence files under `tests/*/evidence/*.md` intentionally preserved as-is because they are historical records of past test runs (rewriting history would misrepresent what happened at the time).
- **`cmd/broker/main.go`** — error message `"Run 'aactl init'..."` → `"Run 'awrit init'..."`.
- **`.gitignore`** — both `/awrit` and `/aactl` listed so accidentally-built binaries under either name stay untracked during the transition.
- **`internal/cfg/configfile.go`** — user-visible references in the env var comment block updated to `awrit`.

Scope: ~36 files touched plus directory + file renames. No production logic changes — pure mechanical rename. The `github.com/devonartis/agentauth` Go module path is NOT changed (that's gated on the GitHub repo rename, separate work).

### Promoted `adminTTL` const to configurable `cfg.AdminTokenTTL` (TD-010)

- **`internal/admin/admin_svc.go`** — deleted the magic-number const `adminTTL = 300`. Admin JWT TTL is now driven by `cfg.AdminTokenTTL` (seconds), wired through a new `tokenTTL` parameter on `NewAdminSvc`. Operators tune via `AA_ADMIN_TOKEN_TTL` (default 300 / 5 min).
Expand Down
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Substantial contributions (anything beyond typo fixes or minor doc corrections)
agentauth/
├── cmd/
│ ├── broker/ # Credential broker HTTP server (main binary)
│ └── aactl/ # Operator CLI — admin auth, app management, audit
│ └── awrit/ # Operator CLI — admin auth, app management, audit
├── internal/
│ ├── admin/ # Admin authentication (bcrypt, shared secret)
│ ├── app/ # App registration, credential lifecycle, launch tokens
Expand Down Expand Up @@ -88,7 +88,7 @@ Before you start, ensure you have:

```bash
go build -o bin/broker ./cmd/broker/
go build -o bin/aactl ./cmd/aactl/
go build -o bin/awrit ./cmd/awrit/
```

5. **Run unit tests:**
Expand Down Expand Up @@ -155,7 +155,7 @@ Examples: `feature/key-rotation`, `fix/renew-ttl-preservation`, `security/rate-l
go vet ./... # Static analysis
go test ./... # Unit tests
go build -o bin/broker ./cmd/broker/ # Broker builds
go build -o bin/aactl ./cmd/aactl/ # CLI builds
go build -o bin/awrit ./cmd/awrit/ # CLI builds
```

### Commit Messages
Expand Down Expand Up @@ -382,7 +382,7 @@ log.Printf("Token %s validated for scope %s", tokenID, scope)
go vet ./... # No warnings
go test ./... # All pass
go build -o bin/broker ./cmd/broker/ # Broker builds
go build -o bin/aactl ./cmd/aactl/ # CLI builds
go build -o bin/awrit ./cmd/awrit/ # CLI builds
```

3. **Submit your PR** against **`develop`** (not `main`) with:
Expand Down
52 changes: 26 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ curl -s -X POST http://localhost:8080/v1/admin/auth \
```bash
# 1. Build the broker and operator CLI
go build -o bin/broker ./cmd/broker/
go build -o bin/aactl ./cmd/aactl/
go build -o bin/awrit ./cmd/awrit/

# 2. Generate a config file with a secure admin secret
./bin/aactl init --config-path /tmp/agentauth/config
./bin/awrit init --config-path /tmp/agentauth/config

# 3. Start the broker
AA_CONFIG_PATH=/tmp/agentauth/config \
Expand Down Expand Up @@ -158,7 +158,7 @@ A FastAPI web app where you enter a patient ID and a plain-language request. A l

## Architecture

AgentAuth is a single broker binary. Operators manage it with the `aactl` CLI. Developers and agents interact with it over HTTP.
AgentAuth is a single broker binary. Operators manage it with the `awrit` CLI. Developers and agents interact with it over HTTP.

```mermaid
flowchart TB
Expand All @@ -181,7 +181,7 @@ flowchart TB
STORE["Store\nSQLite persistence"]
end

AACTL["aactl\nOperator CLI"]
AACTL["awrit\nOperator CLI"]

AGENT -- "POST /v1/register\n(launch token + signed nonce)" --> IDENTITY
AGENT -- "Bearer token" --> RS
Expand Down Expand Up @@ -261,13 +261,13 @@ All error responses use [RFC 7807](https://tools.ietf.org/html/rfc7807) `applica

## Configuration

All broker environment variables use the `AA_` prefix. The broker also reads config files generated by `aactl init` (see [Getting Started: Operator](docs/getting-started-operator.md)).
All broker environment variables use the `AA_` prefix. The broker also reads config files generated by `awrit init` (see [Getting Started: Operator](docs/getting-started-operator.md)).

### Required

| Variable | Description |
|----------|-------------|
| `AA_ADMIN_SECRET` | Shared secret for admin authentication. Broker exits if unset. Use `aactl init` to generate one securely. |
| `AA_ADMIN_SECRET` | Shared secret for admin authentication. Broker exits if unset. Use `awrit init` to generate one securely. |

### Broker settings

Expand Down Expand Up @@ -296,7 +296,7 @@ If `AA_DEFAULT_TTL` exceeds `AA_MAX_TTL`, the broker logs a warning at startup a
|----------|---------|-------------|
| `AA_DB_PATH` | `./agentauth.db` | SQLite database path (audit events, revocations, agents, apps) |
| `AA_SIGNING_KEY_PATH` | `./signing.key` | Ed25519 signing key path. Auto-generated on first startup. |
| `AA_CONFIG_PATH` | *(none)* | Path to config file from `aactl init`. Optional — env vars override config file values. |
| `AA_CONFIG_PATH` | *(none)* | Path to config file from `awrit init`. Optional — env vars override config file values. |

### TLS / mTLS

Expand All @@ -312,7 +312,7 @@ If `AA_DEFAULT_TTL` exceeds `AA_MAX_TTL`, the broker logs a warning at startup a
| Variable | Description |
|----------|-------------|
| `AACTL_BROKER_URL` | Broker base URL (e.g., `http://localhost:8080`) |
| `AACTL_ADMIN_SECRET` | Admin secret for aactl authentication |
| `AACTL_ADMIN_SECRET` | Admin secret for awrit authentication |

---

Expand Down Expand Up @@ -355,13 +355,13 @@ The Docker Compose stack runs the broker on port 8080 (override with `AA_HOST_PO

---

## Operator CLI (aactl)
## Operator CLI (awrit)

`aactl` is the operator's command-line tool for managing the AgentAuth broker. It auto-authenticates with the broker using `AACTL_BROKER_URL` and `AACTL_ADMIN_SECRET`.
`awrit` is the operator's command-line tool for managing the AgentAuth broker. It auto-authenticates with the broker using `AACTL_BROKER_URL` and `AACTL_ADMIN_SECRET`.

```bash
# Build
go build -o bin/aactl ./cmd/aactl/
go build -o bin/awrit ./cmd/awrit/

# Configure
export AACTL_BROKER_URL=http://localhost:8080
Expand All @@ -371,37 +371,37 @@ export AACTL_ADMIN_SECRET="your-admin-secret-here"
### Config generation

```bash
aactl init # Dev mode (plaintext secret in config)
aactl init --mode=prod # Prod mode (bcrypt hash in config, plaintext shown once)
aactl init --force --config-path /etc/aa/cfg # Force overwrite at custom path
awrit init # Dev mode (plaintext secret in config)
awrit init --mode=prod # Prod mode (bcrypt hash in config, plaintext shown once)
awrit init --force --config-path /etc/aa/cfg # Force overwrite at custom path
```

### App management

```bash
aactl app register --name my-pipeline --scopes "read:data:*,write:logs:*"
aactl app list
aactl app get <app-id>
aactl app update --id <app-id> --scopes "read:data:*"
aactl app remove --id <app-id>
awrit app register --name my-pipeline --scopes "read:data:*,write:logs:*"
awrit app list
awrit app get <app-id>
awrit app update --id <app-id> --scopes "read:data:*"
awrit app remove --id <app-id>
```

### Revocation and audit

```bash
aactl revoke --level token --target <jti> # Revoke a single token
aactl revoke --level agent --target <agent-id> # Revoke all tokens for an agent
aactl audit events # Full audit trail
aactl audit events --outcome denied --limit 20 # Filter for denied events
awrit revoke --level token --target <jti> # Revoke a single token
awrit revoke --level agent --target <agent-id> # Revoke all tokens for an agent
awrit audit events # Full audit trail
awrit audit events --outcome denied --limit 20 # Filter for denied events
```

### Token operations

```bash
aactl token release --token <jwt> # Self-revoke a token
awrit token release --token <jwt> # Self-revoke a token
```

All commands support `--json` for machine-readable output. See [aactl CLI Reference](docs/aactl-reference.md) for the complete command reference.
All commands support `--json` for machine-readable output. See [awrit CLI Reference](docs/awrit-reference.md) for the complete command reference.

---

Expand Down Expand Up @@ -477,7 +477,7 @@ server {
| Document | Description |
|----------|-------------|
| [Integration Patterns](docs/integration-patterns.md) | Real-world patterns with Python examples: multi-agent pipelines, delegation chains, token release, emergency revocation |
| [aactl CLI Reference](docs/aactl-reference.md) | Complete operator CLI reference: all commands, flags, examples |
| [awrit CLI Reference](docs/awrit-reference.md) | Complete operator CLI reference: all commands, flags, examples |

### Project

Expand Down
2 changes: 1 addition & 1 deletion TECH-DEBT.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ Audit triggered by discovery of hardcoded `iss: "agentauth"` in `internal/token/
| TD-CFG-002 | ~~**Hardcoded FHS search path `/etc/agentauth/config`**~~ | ~~CRITICAL~~ | **RESOLVED 2026-04-10** — config search paths updated: `/etc/agentauth/config` → `/etc/broker/config` and `~/.agentauth/config` → `~/.broker/config`. Generated config file header `# AgentAuth Configuration` → `# Broker Configuration`. Same branch as TD-TOKEN-001. | `internal/cfg/configfile.go` |
| TD-TOKEN-003 | ~~**Tests lock the issuer hardcode in place** — 6 assertions across `tkn_svc_test.go` and `val_mw_test.go`~~ | ~~HIGH~~ | **RESOLVED 2026-04-10** — all 6 assertions and 3 `cfg.Cfg{}` literal constructions updated to drive from fixture `Issuer: "test-issuer"`. Same branch as TD-TOKEN-001. | `internal/token/tkn_svc_test.go`, `internal/authz/val_mw_test.go`, `internal/deleg/deleg_svc_test.go`, `internal/admin/admin_svc_test.go` |
| TD-TEST-001 | ~~**Test SPIFFE fixtures leak `agentauth.local`**~~ | ~~MEDIUM~~ | **RESOLVED 2026-04-10** — all `agentauth.local` references in test files swept to `test.local` (mechanical sed across `admin_hdl_test.go`, `identity/id_svc_test.go`, `mutauth/{heartbeat,discovery,mut_auth_hdl}_test.go`, `token/tkn_svc_test.go`). Same branch as TD-TOKEN-001. | `internal/admin/admin_hdl_test.go`, `internal/identity/id_svc_test.go`, `internal/mutauth/heartbeat_test.go`, `internal/mutauth/discovery_test.go`, `internal/mutauth/mut_auth_hdl_test.go`, `internal/token/tkn_svc_test.go` |
| TD-CLI-001 | **Binary name `aactl` → `awrit` rename** — 227 occurrences across `cmd/aactl/`, scripts, docs, tests, CHANGELOG. Mechanical. No logic change. | **MEDIUM** | PR 2 (can parallel PR 1) | `cmd/aactl/` (→ `cmd/awrit/`), `docs/aactl-reference.md`, scripts, tests |
| TD-CLI-001 | ~~**Binary name `aactl` → `awrit` rename**~~ | ~~MEDIUM~~ | **RESOLVED 2026-04-10** — `cmd/aactl/` → `cmd/awrit/`, `docs/aactl-reference.md` → `docs/awrit-reference.md`, Cobra command `Use` field, all ship-to-main doc/script/test/config references rewritten. Evidence files under `tests/*/evidence/*.md` preserved as-is (historical records). Branch `fix/td-cli-001-aactl-to-awrit-rename`. | `cmd/awrit/`, `docs/awrit-reference.md`, scripts, docs, tests |

**Not creating a TD for env var prefix** — decided 2026-04-10 to keep `AA_*` indefinitely. Neutral enough (two letters), operator-facing, highest-friction change in the whole rebrand. Re-evaluate at 1.0 if ever.

Expand Down
7 changes: 0 additions & 7 deletions cmd/aactl/main.go

This file was deleted.

30 changes: 15 additions & 15 deletions cmd/aactl/apps.go → cmd/awrit/apps.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Package main — aactl app subcommands for managing registered apps.
// Package main — awrit app subcommands for managing registered apps.
//
// Commands:
//
// aactl app register --name NAME --scopes SCOPE_CSV [--token-ttl N]
// aactl app list [--json]
// aactl app get APP_ID
// aactl app update --id APP_ID [--scopes SCOPE_CSV] [--token-ttl N]
// aactl app remove --id APP_ID
// awrit app register --name NAME --scopes SCOPE_CSV [--token-ttl N]
// awrit app list [--json]
// awrit app get APP_ID
// awrit app update --id APP_ID [--scopes SCOPE_CSV] [--token-ttl N]
// awrit app remove --id APP_ID
package main

import (
Expand All @@ -19,21 +19,21 @@ import (
)

// appCmd is the parent command grouping all app-related subcommands
// under "aactl app".
// under "awrit app".
var appCmd = &cobra.Command{
Use: "app",
Short: "Manage registered apps",
}

// appRegisterName, appRegisterScopes, and appRegisterTokenTTL hold flag values
// for "aactl app register".
// for "awrit app register".
var (
appRegisterName string
appRegisterScopes string
appRegisterTokenTTL int
)

// appRegisterCmd implements "aactl app register", creating a new app registration
// appRegisterCmd implements "awrit app register", creating a new app registration
// and printing the generated client_id and client_secret.
var appRegisterCmd = &cobra.Command{
Use: "register",
Expand Down Expand Up @@ -92,7 +92,7 @@ var appRegisterCmd = &cobra.Command{
},
}

// appListCmd implements "aactl app list", printing all registered apps.
// appListCmd implements "awrit app list", printing all registered apps.
var appListCmd = &cobra.Command{
Use: "list",
Short: "List all registered apps",
Expand Down Expand Up @@ -144,7 +144,7 @@ var appListCmd = &cobra.Command{
},
}

// appGetCmd implements "aactl app get APP_ID", printing full details for one app.
// appGetCmd implements "awrit app get APP_ID", printing full details for one app.
var appGetCmd = &cobra.Command{
Use: "get APP_ID",
Short: "Get details of a specific app",
Expand Down Expand Up @@ -195,14 +195,14 @@ var appGetCmd = &cobra.Command{
}

// appUpdateID, appUpdateScopes, and appUpdateTokenTTL hold flag values
// for "aactl app update".
// for "awrit app update".
var (
appUpdateID string
appUpdateScopes string
appUpdateTokenTTL int
)

// appUpdateCmd implements "aactl app update --id APP_ID [--scopes SCOPE_CSV] [--token-ttl N]",
// appUpdateCmd implements "awrit app update --id APP_ID [--scopes SCOPE_CSV] [--token-ttl N]",
// updating scope ceiling and/or token TTL for an existing app.
var appUpdateCmd = &cobra.Command{
Use: "update",
Expand Down Expand Up @@ -252,10 +252,10 @@ var appUpdateCmd = &cobra.Command{
},
}

// appRemoveID holds the --id flag value for "aactl app remove".
// appRemoveID holds the --id flag value for "awrit app remove".
var appRemoveID string

// appRemoveCmd implements "aactl app remove --id APP_ID", deregistering an app
// appRemoveCmd implements "awrit app remove --id APP_ID", deregistering an app
// (soft delete — credentials stop working but record is retained).
var appRemoveCmd = &cobra.Command{
Use: "remove",
Expand Down
2 changes: 1 addition & 1 deletion cmd/aactl/audit.go → cmd/awrit/audit.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// audit.go implements the aactl audit command group.
// audit.go implements the awrit audit command group.
package main

import (
Expand Down
2 changes: 1 addition & 1 deletion cmd/aactl/client.go → cmd/awrit/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"os"
)

// defaultHTTPClient returns the shared HTTP client for all aactl requests.
// defaultHTTPClient returns the shared HTTP client for all awrit requests.
func defaultHTTPClient() *http.Client {
return &http.Client{}
}
Expand Down
File renamed without changes.
File renamed without changes.
7 changes: 7 additions & 0 deletions cmd/awrit/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Command awrit is the operator CLI for the AgentAuth broker.
package main

// main is the entry point for the awrit binary.
func main() {
Execute()
}
File renamed without changes.
2 changes: 1 addition & 1 deletion cmd/aactl/revoke.go → cmd/awrit/revoke.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Command aactl revoke subcommand — revokes tokens at various granularity levels.
// Command awrit revoke subcommand — revokes tokens at various granularity levels.
package main

import (
Expand Down
4 changes: 2 additions & 2 deletions cmd/aactl/root.go → cmd/awrit/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ var jsonOutput bool

// rootCmd is the top-level cobra command that all subcommands are attached to.
var rootCmd = &cobra.Command{
Use: "aactl",
Use: "awrit",
Short: "AgentAuth operator CLI",
Long: "aactl is the operator CLI for managing the AgentAuth broker.",
Long: "awrit is the operator CLI for managing the AgentAuth broker.",
}

func init() {
Expand Down
2 changes: 1 addition & 1 deletion cmd/aactl/token.go → cmd/awrit/token.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Command aactl token subcommand — token operations including release.
// Command awrit token subcommand — token operations including release.
package main

import (
Expand Down
2 changes: 1 addition & 1 deletion cmd/broker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func main() {

// P1: Fail fast if admin secret is not configured.
if c.AdminSecretHash == "" {
fmt.Fprintln(os.Stderr, "FATAL: No admin secret configured. Run 'aactl init' or set the AA_ADMIN_SECRET environment variable.")
fmt.Fprintln(os.Stderr, "FATAL: No admin secret configured. Run 'awrit init' or set the AA_ADMIN_SECRET environment variable.")
os.Exit(1)
}

Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ services:
# The secure default (127.0.0.1) is for VPS mode only — Docker's
# network isolation handles security instead.
- AA_BIND_ADDRESS=${AA_BIND_ADDRESS:-0.0.0.0}
# Admin secret: use aactl init + config file mount, or set AA_ADMIN_SECRET in .env
# Admin secret: use awrit init + config file mount, or set AA_ADMIN_SECRET in .env
- AA_ADMIN_SECRET=${AA_ADMIN_SECRET:-}
- AA_SEED_TOKENS=${AA_SEED_TOKENS:-false}
- AA_LOG_LEVEL=${AA_LOG_LEVEL:-standard}
Expand Down
Loading