Commit Graph
10 Commits
Author SHA1 Message Date
dguiducci 17f5769e0d mcp: per-user connector access control with deny-by-default grants
Nightly Build / build (push) Successful in 6m33s
2026-07-21 20:48:56 +01:00
dguiducci 79a62c0b93 Add update.sh, release-channel tagging, mobile settings page
Nightly Build / build (push) Successful in 6m28s
install.sh / install-nightly.sh:
  - Write .release-channel file ('release' or 'nightly') for future updates
  - install.sh also writes .release-version (for update --check)

update.sh (new):
  - Reads .release-channel to determine which channel to pull from
  - Release: checks releases/LATEST vs .release-version, skips if current
  - Nightly: always downloads latest
  - Stops service before extraction, restarts after
  - Rebuilds Python venv on update

ci/package.sh:
  - Include update.sh in distribution tarball

Web / mobile:
  - Add settings-page component for mobile
  - Wire settings page into mobile-app navigation
  - Chat page: load current user (/api/auth/me) for sender identity
  - Full mobile.css redesign
  - i18n: add mobile settings strings (en/fr/it)
2026-07-20 22:31:41 +01:00
dguiducci 6b25e7a2bf Sidebar: group nav into priority-ordered functional sections
Nightly Build / build (push) Successful in 6m27s
Turn the flat sidebar into a data-driven nav: each entry declares a
group (workspace/extensions/config/dev) and a numeric priority, and each
section renders by sorting on that key. Split axis is function, not
permission — adminOnly/debugOnly gate individual entries and an empty
section is hidden, so Configuration vanishes for non-admins without a
section-level role check.

- Shared folders moves into 'Your space' (still admin-gated per-entry).
- Plugin pages merge into the workspace group on the same priority line
  (>=100 by default); rebase the two in-repo plugins accordingly.
- Configuration and Development are collapsible, closed by default,
  state persisted in localStorage. Simple mode unchanged.
- Rename nav.catalog to 'Connectors Catalog' to disambiguate from the
  Plugin Catalog; add nav.section.* header keys (en/it/fr).
- Replace dead .sidebar-section-toggle CSS with real section classes.
2026-07-20 16:31:17 +01:00
dguiducci fb3eeeeec6 Refactor: remove desktop/Tauri bundle, add i18n, CI/CD pipeline
Nightly Build / build (push) Failing after 6s
- Remove desktop (Tauri) bundle: docs/desktop.md, icons/, tauri.conf.json,
  src/desktop/mod.rs, gen/schemas/
- Remove build.rs (no longer needed)
- Add i18n system (crates/core-api, plugin-mobile-connector, web)
- Refactor config system (src/config.rs, boot_format.rs)
- Add mobile connector features (app, router, device pairing)
- Plugin system improvements (skald-core)
- Update dependencies (Cargo.lock, Cargo.toml)
- CI/CD: Gitea Actions workflows (nightly + release), package.sh,
  verify-version.sh, builds.skaldagent.net config
2026-07-19 22:35:06 +01:00
dguiducci ba911ae8cb feat(plugins): plugin pages, per-user config, capabilities gate, mobile/telegram refactors
- Plugin HTTP routes + web pages (plugin-page-host, plugin-catalog, plugin-detail)
- Plugin access grants + per-user config (DB tables + API + frontend forms)
- Capabilities-based guard (caps.rs) replacing role-id checks
- Mobile connector: message routing, payload types, router refactor
- Telegram bot: auth flow, event handling improvements
- Honcho plugin: substantial rework
- Sidebar: plugin pages integration, role-driven visibility
- i18n: new strings for plugins, connectors, capabilities
- Remove unused mascot asset
2026-07-19 20:47:09 +01:00
dguiducci 126886e309 Major rebranding, i18n, dashboard, shared folders, role capabilities
- Rebrand: new app/agent icons, SKALD.md, warm "paper" CSS palette
  (terracotta accent, --radius tokens, WCAG contrast, reduced-motion),
  updated favicon, tray icon, skaldkonur asset
- i18n: backend crate (i18n.rs, locale column, ui_locale config),
  frontend library (web/lib/i18n.js, I18nMixin, t(key)),
  translation files (web/i18n/), every component wired
- Dashboard: <dashboard-page> replaces old home-page content;
  <app-copilot> becomes the landing page (full/dock layout modes)
- Shared folders: API endpoints (shared_folders.rs), frontend page,
  can_write membership, container mount topology, user_fs routing
- Role capabilities: new db table & authorization seam (data not enums),
  roles.attrs JSON for ui_mode / interface select
- Setup: skald-setup prompts for language + password, sets ui_locale
- General: components migrated to CSS variables, Lit conventions cleanup,
  connectors/catalog/marketplace/approval refactoring
2026-07-18 21:38:42 +01:00
dguiducci e6c4e202a4 feat(mcp): OAuth per-user connectors (§15) — providers, PKCE copy-paste flow, env credential delivery
- oauth_providers registry table (per-provider client creds) + db/oauth_providers.rs
- mcp/oauth.rs: authorization-code + PKCE S256, RAM-only TTL'd flow store, copy-paste consent
- mcp/install.rs + verify.rs: connector file install + manifest verification
- activate persists a pending row (needs_oauth); /mcp/oauth/start + /complete exchange code for refresh token
- credential delivery via env var on docker exec (google_authorized_user JSON), never on disk
- mcp_catalog/mcp_user_servers: additive OAuth columns (ensure_column), catalog_name/oauth_provider/deliver_json bare TEXT snapshots
- frontend: connector-detail.js (OAuth login panel), shared/connector-common.js, connectors.js admin Sign-in providers modal
- API: /mcp/providers (admin OAuth creds), /mcp/oauth/start|complete
- .gitignore: add /homes/ (instance data), /connectors/, /reset.sh; drop stale /secrets/
2026-07-17 21:47:51 +01:00
dguiducci bcd8f7b5c0 feat(mcp): connector marketplace + split the Connectors surface (§7/§14/§15)
Fills a gap the blueprint names: the admin had to hand-author every
`mcp_catalog` entry. A remote feed of vetted connectors now proposes them
and the admin installs — the feed is *consultative*, so §14's risk axis is
untouched and the trust anchor stays on the box.

Marketplace client (`src/frontend/api/marketplace.rs`):
- Fetches the feed server-side (it sends no CORS headers) and caches it;
  icons are proxied for the same reason.
- Verifies every declared SHA-256 before writing, fail-closed and
  all-or-nothing. Feed-supplied paths are refused if they escape
  `./scripts/<id>/`. Importing an `mcp_local` entry still demands the
  admin-only `mcp.register_local_script`.
- Translates the feed's vocabulary into Skald's: `user`→`per_user`,
  `mcp_local`→`local_script`. Scope is read, never inferred from transport
  (a remote connector can be per-user — that is what `mcp.register_remote`
  is for), and an unreadable `type` fails closed to the answer needing more
  authority. The feed's `llm_short_description` maps to `description`, the
  column `render_mcp_list` puts in front of the LLM for `activate_tools()`.
- Feed URL is config (`marketplace.url`), not a constant: an on-premise
  product must not hard-require reaching one vendor's host.

Two silent failures found while wiring it:
- `transport_of` maps anything unknown to Stdio, so the feed's
  `streamable-http` would have tried to spawn a command. Normalised on import.
- Some servers want their key as a query param, not a bearer header, and say
  so with a `{key}` placeholder. Substituted at connect time in
  `global_row_spec`/`user_row_spec` — never at rest, so the key stays in its
  own column and the stored URL stays a template.

Pages, split by the question each answers:
- Connectors — what runs (`UserMcpView` = global ∪ per-user) and what I can
  add. Same page for everyone; the admin just has more verbs. One Available
  list with the verb per row: `per_user`→Activate, `global`→Enable globally.
  Enabling a global is the admin's counterpart to activating a per-user one,
  so the catalog picker dropdown is gone — the entry comes from the row.
- Connector Catalog (admin) — what this box offers. One `Add connector`
  with two sources: marketplace first (vetted, hashed), manual second
  (unvetted by nature) — the order mirrors the trust model.
- Marketplace (admin) — reached from the catalog, not the sidebar: it is a
  destination of an action, not a place.

`available()` no longer returns `McpGlobalServerRow`: that row carries
`api_key` and this view now reaches every logged-in user. A slim `GlobalView`
crosses instead, and an admin sees every global (with `can_use` marking their
own) so one enabled for someone else stays manageable.

Also fixes `connectors-page` having no CSS rule at all — every sibling page
has one, so it never got `flex: 1` and left an empty column beside it.
2026-07-16 18:52:59 +01:00
dguiducci 7dd77d4ef4 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
2026-07-10 19:19:25 +01:00
dguiducci 38494a85a9 First Version 2026-07-10 15:02:09 +01:00