Commit Graph

67 Commits

Author SHA1 Message Date
890d7b80ac feat: GiteaClient — unified git forge API (50+ endpoints)
Typed Gitea REST API client with PAT auth covering repos, issues, PRs,
branches, orgs, users, file content, and notifications.

Bump: sunbeam-sdk v0.5.0
2026-03-21 20:24:48 +00:00
c597234cd9 feat: HydraClient — OAuth2/OIDC admin API (35 endpoints)
Typed Hydra admin API client covering OAuth2 clients, login/consent/logout
flows, JWK sets, trusted JWT issuers, sessions, and token introspection.

Bump: sunbeam-sdk v0.4.0
2026-03-21 20:22:39 +00:00
f0bc363755 feat: KratosClient — identity management (30 endpoints)
Typed Kratos admin API client covering identities, sessions,
recovery, schemas, courier messages, and health checks.

Bump: sunbeam-sdk v0.3.0
2026-03-21 20:20:08 +00:00
6823772055 feat: ServiceClient trait, HttpTransport, and SunbeamClient factory
Foundation layer for unified service client wrappers:
- AuthMethod enum (None, Bearer, Header, Token)
- ServiceClient trait with service_name(), base_url(), from_parts()
- HttpTransport with json(), json_opt(), send(), bytes() helpers
- SunbeamClient lazy factory with OnceLock-cached per-service clients
- Feature flags for all service modules (identity, gitea, matrix, etc.)

Bump: sunbeam-sdk v0.2.0
2026-03-21 20:15:11 +00:00
31fde1a8c6 fix: forge URL derivation for bare IP hosts, add Cargo registry config
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.
2026-03-21 15:17:47 +00:00
46d21330b1 docs: update README for Rust workspace layout 2026-03-21 14:51:45 +00:00
3ef3fc0255 feat: Python upstream — Sol bot registration TODO 2026-03-21 14:38:44 +00:00
e0961cce73 refactor: binary crate — thin main.rs + cli.rs dispatch
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.
2026-03-21 14:38:33 +00:00
8e5d295902 refactor: SDK small command modules — services, cluster, manifests, gitea, update, auth 2026-03-21 14:38:25 +00:00
6c7e1cd064 refactor: SDK users, pm, and checks modules with submodule splits
Split users.rs (1157L) into mod.rs + provisioning.rs (mailbox,
projects user, welcome email). Split pm.rs (1664L) into mod.rs +
planka.rs (PlankaClient) + gitea_issues.rs (GiteaClient). Split
checks.rs (1214L) into mod.rs + probes.rs (11 check functions + S3).
2026-03-21 14:38:18 +00:00
bc65b9157d refactor: SDK images and secrets modules with submodule splits
Split images.rs (1809L) into mod.rs + builders.rs (per-service build
functions). Split secrets.rs (1727L) into mod.rs + seeding.rs (KV
get_or_create, seed_openbao) + db_engine.rs (PostgreSQL static roles).
Moves BuildTarget enum from cli.rs into images/mod.rs with conditional
clap::ValueEnum derive behind the "cli" feature.
2026-03-21 14:37:47 +00:00
8e51e0b3ae refactor: SDK kube, openbao, and tools modules
Move kube (client, apply, exec, secrets, kustomize_build) into kube/
submodule with tools.rs as a child. Move openbao BaoClient into
openbao/ submodule.
2026-03-21 14:35:43 +00:00
b92700d363 refactor: SDK core modules — error, config, output, constants
Move foundational modules into sunbeam-sdk. All crate-internal references
remain unchanged since these are sibling modules within the SDK crate.
2026-03-21 14:34:23 +00:00
2ffedb95cb refactor: workspace scaffolding — sunbeam-sdk + sunbeam binary crate
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.
2026-03-21 14:34:15 +00:00
b6daf608af chore: suppress dead_code warning on exit code constants 2026-03-20 21:33:00 +00:00
b92c6ad18c feat: Python upstream — onboard/offboard, mailbox, Projects, --no-cache
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
2026-03-20 21:32:23 +00:00
8d6e815a91 feat: --no-cache build flag and Sol build target
- 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
2026-03-20 21:31:42 +00:00
f75f61f238 feat: user provisioning — mailbox, Projects, welcome email
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).
2026-03-20 21:30:27 +00:00
c6aa1bd8ce feat: complete pm subcommands with board discovery and user resolution
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.
2026-03-20 21:16:55 +00:00
ffc0fe917b feat: split auth into sso/git, Planka token exchange, board discovery
Auth:
- sunbeam auth login runs SSO (Hydra OIDC) then Git (Gitea PAT)
- SSO callback auto-redirects browser to Gitea token page
- sunbeam auth sso / sunbeam auth git for individual flows
- Gitea PAT verified against API before saving

Planka:
- Token exchange via /api/access-tokens/exchange-using-token endpoint
- Board discovery via GET /api/projects
- String IDs (snowflake) handled throughout

Config:
- kubectl-style contexts: --context flag > current-context > "local"
- Removed --env flag
- Per-domain auth token storage
2026-03-20 19:25:10 +00:00
ded0ab442e refactor: remove --env flag, use --context like kubectl
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".
2026-03-20 15:23:54 +00:00
88b02acdd1 feat: kubectl-style contexts with per-domain auth tokens
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.
2026-03-20 15:17:57 +00:00
3a5e1c62ba fix: use predictable client_id via pre-seeded K8s secret
Pre-create oidc-sunbeam-cli secret with CLIENT_ID=sunbeam-cli before
hydra-maester reconciles. No cluster access needed at login time.
2026-03-20 15:08:59 +00:00
1029ff0747 fix: auth login UX — timeout, Ctrl+C, suppress K8s error, center HTML
- 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
2026-03-20 14:31:59 +00:00
43b5a4eef9 fix: URL-encode scope parameter with %20 instead of + 2026-03-20 14:30:31 +00:00
7fab2a7f3c fix: auth login domain resolution with --domain flag
Domain resolves from: --domain flag > cached token > config
production_host > cluster discovery. Clear error when none available.
2026-03-20 14:29:08 +00:00
184ad85c60 fix: install rustls ring crypto provider at startup
Rustls 0.23 requires an explicit CryptoProvider. Enable the ring
feature and call install_default() before any TLS operations.
2026-03-20 14:15:16 +00:00
5bdb78933f feat: unified project management across Planka and Gitea
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)
2026-03-20 14:11:16 +00:00
d4421d3e29 feat: OAuth2 CLI authentication with PKCE and token caching
New src/auth.rs module:
- Authorization Code + PKCE flow via localhost redirect
- OIDC discovery from Hydra well-known endpoint
- Browser-based login (opens system browser automatically)
- Token caching at ~/.local/share/sunbeam/auth.json (0600 perms)
- Automatic refresh when access token expires (refresh valid 7 days)
- get_token() for use by other modules (pm, etc.)
- cmd_auth_login/logout/status subcommands
2026-03-20 14:10:37 +00:00
aad469e9c6 fix: stdin password, port-forward retry, seed advisory lock
- 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
2026-03-20 13:37:33 +00:00
dff4588e52 fix: employee ID pagination, add async tests
- next_employee_id now paginates through all identities (was limited to 200)
- Add #[tokio::test] tests: ensure_tunnel noop, BaoClient connection error,
  check_update_background returns quickly when forge URL empty
2026-03-20 13:37:25 +00:00
019c73e300 fix: S3 auth signature tested against AWS reference vector
Refactor s3_auth_headers into deterministic s3_auth_headers_at that
accepts a timestamp. Add test with AWS example credentials and fixed
date verifying canonical request, string-to-sign, and final signature.
2026-03-20 13:37:17 +00:00
e95ee4f377 fix: rewrite users.rs to fully async (was blocking tokio runtime)
Replace all blocking I/O with async equivalents:
- tokio::process::Command instead of std::process::Command
- tokio::time::sleep instead of std::thread::sleep
- reqwest::Client (async) instead of reqwest::blocking::Client
- All helper functions (api, find_identity, generate_recovery, etc.) now async
- PortForward::Drop uses start_kill() (sync SIGKILL) for cleanup
- send_welcome_email wrapped in spawn_blocking for lettre sync transport
2026-03-20 13:31:45 +00:00
24e98b4e7d fix: CNPG readiness, DKIM SPKI format, kv_patch, container name
- Check CNPG Cluster CRD status.phase instead of pod Running phase
- DKIM public key: use SPKI format (BEGIN PUBLIC KEY) matching Python
- Use kv_patch instead of kv_put for dirty paths (preserves external fields)
- Vault KV only written when password is newly generated
- Gitea exec passes container name Some("gitea")
- Fix openbao comment (400 not 409)
2026-03-20 13:29:59 +00:00
6ec0666aa1 fix: SSH tunnel leak, cmd_bao injection, discovery cache, DNS async
- Store SSH tunnel child in static Mutex (was dropped immediately)
- cmd_bao: use env(1) for VAULT_TOKEN instead of sh -c (no shell injection)
- Cache API discovery across kube_apply documents (was per-doc roundtrip)
- Replace blocking ToSocketAddrs with tokio::net::lookup_host
- Remove double YAML->JSON->string->JSON serialization in kube_apply
- ResultExt::ctx now preserves all SunbeamError variants
2026-03-20 13:29:51 +00:00
bcfb443757 refactor: deduplicate constants, fix secret key mismatch, add VSS pruning
- New src/constants.rs: single source for MANAGED_NS (includes monitoring)
  and GITEA_ADMIN_USER, imported by all modules that previously had copies
- Fix checks.rs reading wrong key names from gitea-admin-credentials secret
- Add VaultStaticSecret pruning in pre_apply_cleanup (H1)
- Fix cert_manager_present check (was always true after canonicalize)
- Add warnings for silent failures in pre_apply_cleanup
- Fix os_api dead variable assignment
- Set TLS private key permissions to 0600
- Redact Gitea admin password in print_urls
2026-03-20 13:29:35 +00:00
503e407243 feat: implement OpenSearch ML setup and model_id injection
ensure_opensearch_ml: cluster settings, model registration/deployment
(all-mpnet-base-v2), ingest + search pipelines for hybrid BM25+neural.

inject_opensearch_model_id: reads model_id from ingest pipeline,
writes to matrix/opensearch-ml-config ConfigMap.

os_api helper: kube exec curl inside opensearch pod.
2026-03-20 13:16:00 +00:00
bc5eeaae6e feat: implement secrets.rs with OpenBao HTTP API
Full cmd_seed implementation using openbao::BaoClient:
- OpenBao init/unseal via HTTP API (no kubectl exec)
- KV v2 seeding with get_or_create pattern and dirty-path tracking
- Kubernetes auth method + VSO policy configuration
- Database secrets engine with vault PG user and static roles
- DKIM key generation via rsa + pkcs8 crates
- Kratos admin identity seeding via port-forward + reqwest

cmd_verify: VSO E2E test with test sentinel, sync poll, cleanup.
2026-03-20 13:15:53 +00:00
7fd8874d99 refactor: migrate all modules from anyhow to SunbeamError
Replace anyhow::{bail, Context, Result} with crate::error::{Result,
SunbeamError, ResultExt} across all modules. Each module uses the
appropriate error variant (Kube, Secrets, Build, Identity, etc).
2026-03-20 13:15:45 +00:00
cc0b6a833e refactor: add thiserror error tree and tracing logging
SunbeamError enum with typed variants (Kube, Config, Network, Secrets,
Build, Identity, ExternalTool, Io, Json, Yaml, Other) each mapping to
a process exit code. ResultExt trait replaces anyhow's .context().

main.rs initializes tracing-subscriber with RUST_LOG env filter and
routes all errors to exit codes via SunbeamError::exit_code().

Removes anyhow dependency.
2026-03-20 13:15:26 +00:00
ec235685bf feat: Phase 2 feature modules + comprehensive test suite (142 tests)
services.rs:
- Pod status with unicode icons, grouped by namespace
- VSO sync status (VaultStaticSecret/VaultDynamicSecret via kube-rs DynamicObject)
- Log streaming via kube-rs log_stream + futures::AsyncBufReadExt
- Pod get in YAML/JSON format
- Rollout restart with namespace/service filtering

checks.rs:
- 11 health check functions (gitea, postgres, valkey, openbao, seaweedfs, kratos, hydra, people, livekit)
- AWS4-HMAC-SHA256 S3 auth header generation using sha2 + hmac
- Concurrent execution via tokio JoinSet
- mkcert root CA trust for local TLS

secrets.rs:
- Stub with cmd_seed/cmd_verify (requires live cluster for full impl)

users.rs:
- All 10 Kratos identity operations via reqwest + kubectl port-forward
- Welcome email via lettre SMTP through port-forwarded postfix
- Employee onboarding with auto-assigned ID, HR metadata
- Offboarding with Kratos + Hydra session revocation

gitea.rs:
- Bootstrap without Lima VM: admin password, org creation, OIDC auth source
- Gitea API via kubectl exec curl

images.rs:
- BuildEnv detection, buildctl build + push via port-forward
- Per-service builders for all 17 build targets
- Deploy rollout, node image pull, uv Dockerfile patching
- Mirror scaffolding (containerd operations marked TODO)

cluster.rs:
- Pure K8s cmd_up: cert-manager, linkerd, rcgen TLS certs, core service wait
- No Lima VM operations

manifests.rs:
- Full cmd_apply: kustomize build, two-pass convergence, ConfigMap restart detection
- Pre-apply cleanup, webhook wait, mkcert CA, tuwunel OAuth2 redirect patch

Test coverage: 142 tests across 14 modules (44 in checks, 27 in cli, 13 in images, 12 in tools, 12 in services, 11 in users, 10 in manifests, 9 in kube, 9 in cluster, 7 in update, 6 in gitea, 4 in openbao, 3 in output, 2 in config).
2026-03-20 12:45:07 +00:00
42c2a74928 feat: Phase 1 foundations — kube-rs client, OpenBao HTTP client, self-update
kube.rs:
- KubeClient with lazy init from kubeconfig + context selection
- SSH tunnel via subprocess (port 2222, forward 16443->6443)
- Server-side apply for multi-document YAML via kube-rs discovery
- Secret get/create, namespace ensure, exec in pod, rollout restart
- Domain discovery from gitea-inline-config secret
- kustomize_build with embedded binary, domain/email/registry substitution
- kubectl and bao CLI passthrough commands

openbao.rs:
- Lightweight Vault/OpenBao HTTP API client using reqwest
- System ops: seal-status, init, unseal
- KV v2: get, put, patch, delete with proper response parsing
- Auth: enable method, write policy, write roles
- Database secrets engine: config, static roles
- Replaces all kubectl exec bao shell commands from Python version

update.rs:
- Self-update from latest mainline commit via Gitea API
- CI artifact download with SHA256 checksum verification
- Atomic self-replace (temp file + rename)
- Background update check with hourly cache (~/.local/share/sunbeam/)
- Enhanced version command with target triple and build date

build.rs:
- Added SUNBEAM_TARGET and SUNBEAM_BUILD_DATE env vars

35 tests pass.
2026-03-20 12:37:02 +00:00
80c67d34cb feat: Rust rewrite scaffolding with embedded kustomize+helm
Phase 0 of Python-to-Rust CLI rewrite:

- Cargo.toml with all dependencies (kube-rs, reqwest, russh, rcgen, lettre, etc.)
- build.rs: downloads kustomize v5.8.1 + helm v4.1.0 at compile time, embeds as bytes, sets SUNBEAM_COMMIT from git
- src/main.rs: tokio main with anyhow error formatting
- src/cli.rs: full clap derive struct tree matching all Python argparse subcommands
- src/config.rs: SunbeamConfig serde struct, load/save ~/.sunbeam.json
- src/output.rs: step/ok/warn/table with exact Python format strings
- src/tools.rs: embedded kustomize+helm extraction to cache dir
- src/kube.rs: parse_target, domain_replace, context management
- src/manifests.rs: filter_by_namespace with full test coverage
- Stub modules for all remaining features (cluster, secrets, images, services, checks, gitea, users, update)

23 tests pass, cargo check clean.
2026-03-20 12:24:21 +00:00
d5b963253b refactor: cross-platform tool downloads, configurable infra dir and ACME email
- Make tool downloads platform-aware (darwin/linux, arm64/amd64)
- Add buildctl to bundled tools
- Add get_infra_dir() with config fallback for REPO_ROOT resolution
- Add ACME email to sunbeam config (set/get)
- Add REGISTRY_HOST_IP substitution in kustomize builds
- Update Kratos admin identity schema to employee
- Fix logs command to use production tunnel and context
2026-03-10 19:37:02 +00:00
c82f15b190 feat: add tuwunel/matrix support with OpenSearch ML post-apply hooks
- Add matrix to MANAGED_NS and tuwunel to restart/build targets
- Add post-apply hooks for matrix namespace:
  - _patch_tuwunel_oauth2_redirect: reads client_id from hydra-maester
    Secret and patches OAuth2Client redirectUris dynamically
  - _inject_opensearch_model_id: reads model_id from ingest pipeline
    and writes to ConfigMap for tuwunel deployment env var injection
- Add post-apply hook for data namespace:
  - _ensure_opensearch_ml: idempotently registers/deploys all-mpnet-base-v2
    (768-dim) model, creates ingest + hybrid search pipelines
- Add tuwunel secrets to OpenBao seed (OIDC, TURN, registration token)
- Refactor secret seeding to only write dirty paths (avoid VSO churn)
- Add ACME email fallback from config when not provided via CLI flag
2026-03-10 19:23:30 +00:00
928323e481 fix(cli): unify proxy build path, fix Gitea password sync
- Collapse proxy build to single path using real Dockerfile via remote buildkitd
- Remove cross-compile and Dockerfile.package codepath
- Fix missing --must-change-password=false in Gitea admin password sync
2026-03-08 20:37:53 +00:00
956a883985 chore: added AGENTS.md file for various models.
Signed-off-by: Sienna Meridian Satterwhite <sienna@r3t.io>
2026-03-07 17:24:09 +00:00
507b4d3fb7 feat(config): add production host and infrastructure directory configuration
- Add usage: sunbeam config [-h] action ...

positional arguments:
  action
    set       Set configuration values
    get       Get current configuration
    clear     Clear configuration

options:
  -h, --help  show this help message and exit subcommand with set/get/clear actions
- Store configuration in  with production_host and infra_directory
- Integrate with production environment detection, prioritizing config over SUNBEAM_SSH_HOST
- Add comprehensive test coverage with 11 new tests
- Update CLI help and error messages for better user experience
2026-03-07 16:08:38 +00:00
cbf5c12980 docs: update repository URLs to use HTTPS remotes for src.sunbeam.pt 2026-03-07 15:01:00 +00:00
133fc98440 docs: add comprehensive README with professional documentation 2026-03-07 14:54:29 +00:00