feat(auth): login, roles, user mgmt, setup wizard, and session guard

- New skald-setup crate: interactive first-run wizard that creates the
  admin user, prompts for encryption choice and password
- Auth system: session-based login/logout with cookie, guard middleware
- Roles API: CRUD for data-driven roles, seeded on first boot
- Users management API: create, list, edit, delete users
- Setup state API: check if first admin has been created
- Frontend: login-page, setup-page, users-page, roles-page, profile-page
  components with corresponding CSS
- Topbar: avatar dropdown with profile link and logout
- Sidebar: nav entries for Users and Roles (admin only)
- Page shell CSS: layout support for the new pages
- build.sh: builds both skald and skald-setup binaries
- run.sh: runs skald-setup before the server loop
- CLAUDE.md: updated workspace layout and build/run docs
This commit is contained in:
2026-07-10 19:19:25 +01:00
parent 178a38357e
commit 7dd77d4ef4
36 changed files with 2660 additions and 27 deletions
+21
View File
@@ -1,10 +1,12 @@
pub mod agents;
pub mod auth;
pub mod commands;
pub mod config;
pub mod approval;
pub mod cron;
pub mod dev;
pub mod file_watch;
pub mod guard;
pub mod stats;
pub mod files;
pub mod image_generate_models;
@@ -15,12 +17,15 @@ pub mod mcp;
pub mod mcp_media;
pub mod plugins;
pub mod projects;
pub mod roles;
pub mod run_context;
pub mod sessions;
pub mod setup;
pub mod transcribe_audio;
pub mod transcribe_models;
pub mod tts_models;
pub mod uploads;
pub mod users_mgmt;
pub mod ws;
pub mod ws_session;
@@ -44,6 +49,15 @@ pub fn router() -> Router<Arc<Skald>> {
// Custom slash commands (file-based, read-only listing for autocomplete + /help)
.route("/commands", get(commands::list))
.route("/sessions", get(sessions::list_sessions).post(sessions::create))
// First-run setup
.route("/setup/status", get(setup::status))
.route("/setup/user", post(setup::create_user))
// Auth
.route("/auth/login", post(auth::login))
.route("/auth/me", get(auth::me))
.route("/auth/logout", post(auth::logout))
.route("/auth/profile", put(auth::update_profile))
.route("/auth/change-password", post(auth::change_password))
.route("/sessions/{id}", get(sessions::get_session_detail))
.route("/web/messages", get(sessions::web_messages))
.route("/{source}/messages", get(sessions::source_messages))
@@ -130,6 +144,13 @@ pub fn router() -> Router<Arc<Skald>> {
// Plugins
.route("/plugins", get(plugins::list))
.route("/plugins/{id}", put(plugins::update))
// Roles
.route("/roles", get(roles::list).post(roles::create))
.route("/roles/{id}", put(roles::update).delete(roles::delete))
// User management
.route("/users", get(users_mgmt::list).post(users_mgmt::create))
.route("/users/{id}", put(users_mgmt::update).delete(users_mgmt::delete))
.route("/users/{id}/password", post(users_mgmt::reset_password))
// Images (generated by image_generate tool)
.route("/images/{task_id}", get(images::get_image))
// MCP tool-result media (images/audio/files returned by MCP servers)