Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
36b92ff
✨ feat: add auth DB schema tables and migration
vaayne Mar 20, 2026
453cc20
✨ feat: add sqlc queries for auth tables and regenerate
vaayne Mar 20, 2026
b715295
✨ feat: add auth package with types, password hashing, store interfac…
vaayne Mar 20, 2026
6769e5b
✅ test: add tests for auth password hashing and authdb store
vaayne Mar 20, 2026
3293372
📝 docs: update Phase 1 task checklist and handoff log
vaayne Mar 20, 2026
1434614
🐛 fix: improve auth store error wrapping and type safety
vaayne Mar 20, 2026
c988b23
✨ feat: add policy engine with deny-overrides and condition evaluator
vaayne Mar 20, 2026
7fbd984
✨ feat: add auth seed for built-in roles and policies
vaayne Mar 20, 2026
1ac9ee1
✨ feat: integrate auth seed into bootstrap
vaayne Mar 20, 2026
615f4fa
✅ test: add comprehensive tests for policy engine, conditions, and seed
vaayne Mar 20, 2026
ca28026
♻️ refactor: use strings.Contains in auth seed instead of custom impl
vaayne Mar 20, 2026
abea062
✨ feat: add session management and rate limiting for auth
vaayne Mar 20, 2026
610ec3c
✨ feat: add login/register page with standalone layout
vaayne Mar 20, 2026
da1b084
✨ feat: add admin UI authentication with session middleware
vaayne Mar 20, 2026
677142d
✅ test: add auth handler and middleware tests
vaayne Mar 20, 2026
09d6c78
📝 docs: update tasks and handoff for Phase 3 completion
vaayne Mar 20, 2026
34bb0e1
🐛 fix: address Phase 3 review issues
vaayne Mar 20, 2026
5fab37d
✨ feat: add profile page with password change, identity linking, and …
vaayne Mar 20, 2026
41f3c4a
✨ feat: intercept link codes in channel handlers for account linking
vaayne Mar 20, 2026
229aa69
✨ feat: auth-aware identity resolution with auto-migration fallback
vaayne Mar 20, 2026
c81caa8
✅ test: add tests for link codes, profile handlers, and auth-aware id…
vaayne Mar 20, 2026
5e93af4
📝 docs: update tasks and handoff for Phase 4 completion
vaayne Mar 20, 2026
f25f52d
🐛 fix: log role assignment error during auto-migration
vaayne Mar 20, 2026
79de064
✨ feat: add Scope field to Agent struct and wire in DB queries
vaayne Mar 20, 2026
2d416ef
✨ feat: agent user assignment API, admin UI, and policy engine filtering
vaayne Mar 20, 2026
3888f20
✨ feat: enforce agent access in channel identity resolution
vaayne Mar 20, 2026
b7824b3
♻️ refactor: wire auth store and policy engine to channel bots in gat…
vaayne Mar 20, 2026
bd0fbe7
📝 docs: update handoff and tasks for Phase 5 completion
vaayne Mar 20, 2026
061fa8e
✨ feat: add per-user workspace directories and skill isolation
vaayne Mar 20, 2026
c18f11f
✨ feat: add sandbox enforcement and per-session user tools
vaayne Mar 20, 2026
03b0d4a
📝 docs: update tasks and handoff for Phase 6 completion
vaayne Mar 20, 2026
b95fd8e
🐛 fix: mark user-installed skills as removable in list output
vaayne Mar 20, 2026
ec3be45
✨ feat: add admin user management page with auth users, roles, and ag…
vaayne Mar 20, 2026
5f4fbdf
📝 docs: update RBAC session docs for Phase 7 completion
vaayne Mar 20, 2026
74a3a06
♻️ refactor: merge onboard into default action, move authdb to db pac…
vaayne Mar 20, 2026
307b086
🔥 chore: remove hardcoded db path from admin footer
vaayne Mar 20, 2026
8efa5fc
✨ feat: add RBAC to scheduler and sessions, per-user notifications
vaayne Mar 20, 2026
ec70c46
✨ feat: add admin identity unlink for auth users
vaayne Mar 20, 2026
5f9322b
🐛 fix: share LinkCodeStore between admin panel and channel bots
vaayne Mar 20, 2026
130faa3
♻️ refactor: remove auto-migration, use /link command for identity li…
vaayne Mar 20, 2026
2ce6005
🐛 fix: use auth user ID for session ownership and memory lookup
vaayne Mar 20, 2026
b78f861
🐛 fix: drop settings_users FK from ctx_agent_memory
vaayne Mar 20, 2026
3bb8e33
🐛 fix: resolve session user name from auth_users, not settings_users
vaayne Mar 20, 2026
68e47ec
♻️ refactor: consolidate settings_users into auth_users
vaayne Mar 20, 2026
41c5059
🐛 fix: address codex review feedback
vaayne Mar 21, 2026
2a7e38d
♻️ refactor: simplify roles to single role column on auth_users
vaayne Mar 21, 2026
e6f3df5
✨ feat: share sessions across channels for linked users
vaayne Mar 21, 2026
f527d34
🐛 fix: merge identity sections, hide linked platforms, fix link code …
vaayne Mar 21, 2026
e211c1d
🐛 fix: display QQ as uppercase in link button
vaayne Mar 21, 2026
3236e09
🎨 fix: remove "admin" from footer, pin footer to bottom
vaayne Mar 21, 2026
276c10f
✨ feat: add user memory management to profile page
vaayne Mar 21, 2026
cb02ba9
♻️ refactor: move user memory from profile to agent page
vaayne Mar 21, 2026
87a5380
✨ feat: add creator_id to agents, auto-generate ID, simplify agent cr…
vaayne Mar 21, 2026
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
433 changes: 433 additions & 0 deletions .agents/sessions/2026-03-20-rbac/handoff.md

Large diffs are not rendered by default.

453 changes: 453 additions & 0 deletions .agents/sessions/2026-03-20-rbac/plan.md

Large diffs are not rendered by default.

80 changes: 80 additions & 0 deletions .agents/sessions/2026-03-20-rbac/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Tasks: RBAC + ABAC Permission System

## Phase 1: Auth Foundation — DB Schema + Auth Package

- [x] 1.1 — Create auth DB schema files (`internal/db/schemas/tables/auth_users.sql`, `auth_roles.sql`, `auth_user_roles.sql`, `auth_identities.sql`, `auth_policies.sql`, `auth_user_agents.sql`, `auth_sessions.sql`)
- [x] 1.2 — Add `scope` column to `settings_agents` table (`internal/db/schemas/tables/settings_agents.sql`)
- [x] 1.3 — Generate Atlas migration (`mise run atlas:diff -- add-auth-tables`)
- [x] 1.4 — Create sqlc queries for all auth tables (`internal/db/queries/auth_*.sql`)
- [x] 1.5 — Run `mise run generate` to regenerate sqlc
- [x] 1.6 — Create `internal/auth/types.go`
- [x] 1.7 — Create `internal/auth/password.go`
- [x] 1.8 — Create `internal/auth/store.go` (AuthStore interface)
- [x] 1.9 — Create `internal/auth/authdb/store.go` (SQLite implementation)
- [x] 1.10 — Write tests for password and authdb store

## Phase 2: Policy Engine

- [x] 2.1 — Create `internal/auth/engine.go` (PolicyEngine, Can, Must)
- [x] 2.2 — Implement condition evaluator (JSON conditions, operators: eq, neq, in, not_in, contains)
- [x] 2.3 — Implement deny-overrides algorithm
- [x] 2.4 — Create `internal/auth/seed.go` (8 built-in policies + 2 roles)
- [x] 2.5 — Integrate seed into bootstrap
- [x] 2.6 — Write tests (policy matching, conditions, deny-overrides, edge cases)

## Phase 3: Admin UI Authentication

- [x] 3.1 — Create `internal/auth/session.go` (crypto/rand IDs, cookies, lazy cleanup)
- [x] 3.2 — Create `internal/auth/ratelimit.go` (per-IP + per-username throttling)
- [x] 3.3 — Create login/register templ page (`internal/admin/ui/pages/login.templ`)
- [x] 3.4 — Create login page JS (`internal/admin/ui/static/js/pages/login.js`)
- [x] 3.5 — Add auth API handlers (`internal/admin/auth.go`)
- [x] 3.6 — Add auth middleware (`internal/admin/middleware.go`)
- [x] 3.7 — Harden CORS in `server.go`
- [x] 3.8 — Apply auth middleware to routes, exempt login/static/auth
- [x] 3.9 — Add admin-only route guard middleware
- [x] 3.10 — Modify navbar for role-based visibility
- [x] 3.11 — Modify root redirect (unauthenticated → login)
- [x] 3.12 — Write tests

## Phase 4: User Profile + Channel Linking

- [x] 4.1 — Create `internal/auth/linkcode.go` (in-memory sync.Map, 5-min TTL)
- [x] 4.2 — Create profile templ page (`internal/admin/ui/pages/profile.templ`)
- [x] 4.3 — Create profile page JS (`internal/admin/ui/static/js/pages/profile.js`)
- [x] 4.4 — Add profile API handlers (get profile, update password, link code, identities)
- [x] 4.5 — Add route + nav link for `/profile`
- [x] 4.6 — Modify channel handlers to intercept link-code messages
- [x] 4.7 — Modify `identity.go`: resolve via auth_identities with auto-migration fallback
- [x] 4.8 — Write tests

## Phase 5: Agent Scoping + Access Enforcement

- [x] 5.1 — Add `scope` field to `config.Agent` struct and agent form in admin UI
- [x] 5.2 — Create user-agent assignment API (`POST/DELETE /api/agents/{id}/users/{userId}`)
- [x] 5.3 — Create admin UI for agent user management
- [x] 5.4 — Integrate policy engine into admin API middleware
- [x] 5.5 — Integrate policy engine into channel identity resolution
- [x] 5.6 — Return permission denied / link prompt on channel access failures
- [x] 5.7 — Modify `ResolveAgent()` to filter by accessible agents
- [x] 5.8 — Write tests

## Phase 6: Per-User Data + Skills Isolation

- [x] 6.1 — Modify `SetupWorkspace()` for per-user directories
- [x] 6.2 — Modify `SkillsTool` to accept `userID`, per-user skill path
- [x] 6.3 — Modify skill load/list/install/remove for per-user paths
- [x] 6.4 — Modify `LoadSkills()` in `runner/skill.go`: add user dir in priority chain
- [x] 6.5 — Modify runner creation to pass user ID
- [x] 6.6 — Add sandbox enforcement (`internal/auth/sandbox.go`, file tool integration)
- [x] 6.7 — Migrate existing agent-level skills as shared
- [x] 6.8 — Write tests

## Phase 7: Admin User Management

- [x] 7.1 — Enhance `/users` page to show auth_users, roles, linked identities
- [x] 7.2 — Add role management (admin promote/demote)
- [x] 7.3 — Add agent assignment management
- [x] 7.4 — Add user detail view (sessions, skills, identities)
- [x] 7.5 — Cleanup old settings_users page functionality
- [x] 7.6 — Write tests
12 changes: 6 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Overview

anna is a self-hosted AI assistant with lossless context management (LCM). Native Go runner calling LLM providers. Two interfaces: CLI chat (Bubble Tea TUI) and gateway daemon (Telegram, QQ, Feishu bots). Built-in scheduler, heartbeat monitoring, and multi-channel notifications.
anna is a self-hosted AI assistant with lossless context management (LCM). Native Go runner calling LLM providers. Two interfaces: CLI chat (Bubble Tea TUI) and server daemon (admin panel + Telegram, QQ, Feishu bots). Built-in scheduler, heartbeat monitoring, and multi-channel notifications.

## Packages

Expand All @@ -12,7 +12,7 @@ Side packages: `internal/channel/` (cli, telegram, qq, feishu, notifier) → `in

Admin UI: `internal/admin/` — templ + Alpine.js + daisyUI. See `internal/admin/CLAUDE.md` for details.

Config: `~/.anna/config.yaml` | Data: `~/.anna/workspace/` (memory.db, skills, identity files)
Config + Data: `~/.anna/` (anna.db, workspace/, cache/)

## Tasks

Expand All @@ -23,9 +23,9 @@ mise run lint # golangci-lint
mise run format # gofmt + go mod tidy
mise run generate # templ generate + sqlc codegen
mise run templ:watch # watch templ files + live reload proxy
mise run atlas:diff -- NAME # generate migration from schema changes
mise run atlas:hash # recalculate migration checksum
mise run atlas:validate # validate migration integrity
mise run db:diff -- NAME # generate migration from schema changes
mise run db:hash # recalculate migration checksum
mise run db:validate # validate migration integrity
```

## Database Migrations
Expand All @@ -35,7 +35,7 @@ Schema source of truth: `internal/db/schemas/tables/*.sql`. Migrations are gener
**Workflow for schema changes:**

1. Edit the schema files in `internal/db/schemas/tables/`
2. Run `mise run atlas:diff -- <name>` to generate a new migration in `internal/db/migrations/`
2. Run `mise run db:diff -- <name>` to generate a new migration in `internal/db/migrations/`
3. Run `mise run generate` to regenerate sqlc
4. The migration is auto-applied on `db.OpenDB()` at startup

Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ Or grab a binary from [Releases](https://github.com/vaayne/anna/releases), or se
### Set up

```bash
anna onboard
anna --open
```

This opens a web admin panel in your browser where you can configure everything: providers, API keys, agents, channels (Telegram, QQ, Feishu), users, scheduled jobs, and settings. All configuration is stored in `~/.anna/anna.db`. There are no YAML config files.
Expand All @@ -161,21 +161,21 @@ This opens a web admin panel in your browser where you can configure everything:
```bash
anna chat # Terminal chat (default agent)
anna chat --agent helper # Terminal chat with a specific agent
anna gateway # Start daemon (bots + scheduler)
anna gateway --admin-port 8080 # Start daemon with admin panel
anna # Start daemon (bots + scheduler)
anna --admin-port 8080 # Start daemon with admin panel
```

`anna chat` gives you a terminal conversation. `anna gateway` starts all your configured channels and the scheduler. Add `--admin-port` to expose the admin panel alongside the gateway for runtime configuration.
`anna chat` gives you a terminal conversation. `anna` (bare command) starts all your configured channels and the scheduler. Add `--admin-port` to expose the admin panel alongside the daemon for runtime configuration.

## CLI reference

```bash
anna onboard # Open web admin panel to configure anna
anna --open # Open web admin panel to configure anna
anna chat # Interactive terminal chat
anna chat --agent <name> # Chat with a specific agent
anna chat --stream # Pipe stdin, stream to stdout
anna gateway # Start daemon (bots + scheduler)
anna gateway --admin-port <port> # Start daemon with admin panel
anna # Start daemon (bots + scheduler)
anna --admin-port <port> # Start daemon with admin panel
anna models list # List available models
anna models set <p/m> # Switch model (e.g. openai/gpt-4o)
anna models search <q> # Search models
Expand Down
16 changes: 10 additions & 6 deletions cmd/anna/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/vaayne/anna/internal/agent"
"github.com/vaayne/anna/internal/agent/runner"
agenttool "github.com/vaayne/anna/internal/agent/tool"
"github.com/vaayne/anna/internal/auth"
"github.com/vaayne/anna/internal/channel"
"github.com/vaayne/anna/internal/config"
appdb "github.com/vaayne/anna/internal/db"
Expand All @@ -27,13 +28,13 @@ func newApp() *ucli.App {
Name: "anna",
Usage: "A local AI assistant",
Version: displayVersion(),
Flags: serverFlags(),
Action: serverAction,
Commands: []*ucli.Command{
chatCommand(),
gatewayCommand(),
modelsCommand(),
skillsCommand(),
pluginCommand(),
onboardCommand(),
versionCommand(),
upgradeCommand(),
},
Expand Down Expand Up @@ -70,6 +71,12 @@ func setup(parent context.Context, gateway bool) (*setupResult, error) {
return nil, fmt.Errorf("seed defaults: %w", err)
}

// Seed auth policies.
authStore := appdb.NewAuthStore(db)
if err := auth.SeedPolicies(parent, authStore); err != nil {
return nil, fmt.Errorf("seed auth: %w", err)
}

// Get snapshot for the default agent (used for global settings).
agents, err := store.ListEnabledAgents(parent)
if err != nil || len(agents) == 0 {
Expand Down Expand Up @@ -191,11 +198,8 @@ func setup(parent context.Context, gateway bool) (*setupResult, error) {
})
}

// Resolve a CLI user for local chat sessions.
// CLI sessions don't use auth — userID stays 0.
var cliUserID int64
if cliUser, err := channel.ResolveUser(ctx, store, "cli", "cli", "CLI User"); err == nil {
cliUserID = cliUser.ID
}

return &setupResult{
ctx: ctx,
Expand Down
Loading
Loading