os_api: resolve pod name by label instead of hardcoded opensearch-0.
added find_pod_by_label helper to kube.rs.
secrets.py: sol-agent policy (read/write sol-tokens/*) and k8s auth
role bound to matrix namespace default SA.
SunbeamClient accessors are now async and resolve auth per-client:
- SSO bearer (get_token) for admin APIs, Matrix, La Suite, OpenSearch
- Gitea PAT (get_gitea_token) for VCS
- None for Prometheus, Loki, S3, LiveKit
Fixes client URLs to match deployed routes: hydra→hydra.{domain},
matrix→messages.{domain}, grafana→metrics.{domain},
prometheus→systemmetrics.{domain}, loki→systemlogs.{domain}.
Removes all ad-hoc token helpers from CLI modules (matrix_with_token,
os_client, people_client, etc). Every dispatch just calls
client.service().await?.
Patches gitea admin credentials into secret/sol for Sol's Gitea
integration. Adds sol-agent vault policy with read/write access
to sol-tokens/* for user impersonation PATs, plus k8s auth role
bound to the matrix namespace.
Adds Verb variants: auth, vcs, chat, search, storage, media, mon,
vault, people, docs, meet, drive, mail, cal, find. Each delegates
to the corresponding SDK cli.rs dispatch function.
Removes the legacy `user` command (replaced by `auth identity`).
Renames Get's -o to --kubectl-output to avoid conflict with the
new global -o/--output flag. Enables all SDK features in binary.
forge_url() now checks active context domain first before falling back
to production_host. Bare IP addresses are skipped in the host heuristic.
Adds .cargo/config.toml for the sunbeam Gitea Cargo registry.
Slim binary that depends on sunbeam-sdk for all logic. Replaces 62
crate:: refs with sunbeam_sdk::. Tracing filter updated to include
sunbeam_sdk=info.
Move kube (client, apply, exec, secrets, kustomize_build) into kube/
submodule with tools.rs as a child. Move openbao BaoClient into
openbao/ submodule.
Convert the single binary crate into a Cargo workspace with two members:
sunbeam-sdk (library) and sunbeam (thin binary). Moves build.rs to the
SDK with adjusted .git/HEAD path for the nested layout.
Python changes that were ported to Rust in preceding commits:
- User onboard/offboard with mailbox + Projects provisioning
- Welcome email with job title/department
- --no-cache build flag
- Date validation, apply confirmation, build targets
- Add --no-cache flag to sunbeam build (passes --no-cache to buildctl)
- Add Sol (virtual librarian) as a build target
- Wire no_cache through all build functions and dispatch
Onboarding now provisions app-level accounts:
- create_mailbox: Django ORM via kubectl exec into messages-backend
- setup_projects_user: knex.js via kubectl exec into projects pod
- Welcome email includes job title and department when provided
Offboarding cleans up:
- delete_mailbox: removes mailbox + Django user
- cleanup_projects_user: soft-deletes Planka user + memberships
All provisioning is best-effort (warns on failure, doesn't block).
Planka:
- Board discovery via GET /api/projects (no hardcoded IDs)
- String IDs (snowflake) throughout — TicketRef::Planka holds String
- Create auto-discovers first board/list, or matches --target by name
- Close finds "Done"/"Closed" list and moves card automatically
- Assign resolves users via search, supports "me" for self-assign
- Ticket IDs use p:/g: short prefixes
Gitea:
- Assign uses PATCH on issue (not POST /assignees which needs collaborator)
- Create requires --target org/repo
All pm subcommands tested against live Planka + Gitea instances.
Context resolution: --context flag > current-context from config > "local".
No more production/local distinction in the CLI flags — the context
determines everything (domain, kube-context, ssh-host, infra-dir).
Remove Env enum entirely. Production detection is now "context has ssh-host".
Config now supports named contexts (like kubectl), each bundling
domain, kube-context, ssh-host, infra-dir, and acme-email. Legacy
flat config auto-migrates to a "production" context on load.
- sunbeam config set --domain sunbeam.pt --host user@server
- sunbeam config use-context production
- sunbeam config get (shows all contexts)
Auth tokens stored per-domain (~/.local/share/sunbeam/auth/{domain}.json)
so local and production don't clobber each other. pm and auth commands
read domain from active context instead of K8s cluster discovery.
- 5-minute timeout on callback wait (Ctrl+C now works)
- Skip K8s client_id lookup when no cluster configured (removes noisy ERROR)
- Center the success page HTML to match Sunbeam Studios branding
New src/pm.rs module with sunbeam pm subcommand:
- Planka client: cards, boards, lists, comments, assignments
via OIDC token exchange for Planka JWT
- Gitea client: issues, comments, labels, milestones
via OAuth2 Bearer token
- Unified Ticket type with p:/g: ID prefixes
- pm list: parallel fetch from both sources, merged display
- pm show/create/comment/close/assign across both systems
- Auth via crate::auth::get_token() (Hydra OAuth2)
- set-password reads from stdin when password arg omitted
- Port-forward proxy retries on pod restart instead of failing
- cmd_seed acquires PID-based advisory lockfile to prevent concurrent runs