Skip to content

feat(config): split API keys into a sidecar secrets.toml#6

Merged
ekrist1 merged 16 commits into
ekrist1:masterfrom
tharropoulos:feat/secrets-sidecar
Jun 3, 2026
Merged

feat(config): split API keys into a sidecar secrets.toml#6
ekrist1 merged 16 commits into
ekrist1:masterfrom
tharropoulos:feat/secrets-sidecar

Conversation

@tharropoulos

Copy link
Copy Markdown
Contributor
  • write API keys to a sidecar secrets.toml next to config.toml on every save, so the main config can be committed to dotfiles
  • merge secrets.toml API keys back into the loaded Config on load
  • migrate inline api_key values from an existing config.toml into a freshly written secrets.toml on first load
  • mark ClusterConfig.APIKey as omitempty so the rewritten config.toml does not leave behind empty api_key = "" lines
  • document the sidecar layout, the migration behavior, and the .gitignore recommendation in the README

depends on: #5

@tharropoulos tharropoulos force-pushed the feat/secrets-sidecar branch from 42cde4a to 3f854a4 Compare June 2, 2026 18:01
@ekrist1 ekrist1 marked this pull request as ready for review June 3, 2026 16:15
Copilot AI review requested due to automatic review settings June 3, 2026 16:15
@ekrist1 ekrist1 merged commit a027964 into ekrist1:master Jun 3, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates clisense’s configuration model so API keys are no longer stored in the main config.toml, but instead are split into a sidecar secrets.toml (with load-time merge + one-time migration of inline keys). It also updates the TUI to better support multi-cluster workflows (setup form cluster selection + global cluster picker overlay) and makes tab ordering configurable via tabs.order.

Changes:

  • Split API keys into secrets.toml on save; merge them back into Config on load; migrate inline api_key values into secrets.toml on first load.
  • Add a global cluster picker (c) rendered as an overlay, and update setup to allow choosing/creating a cluster.
  • Add configurable tab ordering via tabs.order, with validation and updated tab activation/routing.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
README.md Documents TOML config layout, cluster picker keys, and the new secrets.toml sidecar + migration behavior.
main.go Enters setup when the loaded config is present but incomplete (NeedsSetup).
internal/tui/screens/setup.go Extends setup flow to include cluster selection/creation and cycling through existing clusters.
internal/tui/overlay.go Introduces helpers to render a centered overlay on top of existing screen content.
internal/tui/app.go Adds cluster picker state/handlers, routes by tab IDs, supports configurable tab order, and overlays picker UI.
internal/tui/app_test.go Adds coverage for tab order, settings save, cluster switching, overlay behavior, and Ctrl+C quit in setup.
internal/config/config.go Switches config persistence to TOML, adds tabs validation, implements secrets sidecar split/merge + migration and legacy YAML fallback.
internal/config/config_test.go Updates/expands tests for TOML paths, legacy YAML fallback, tabs validation, secrets sidecar split/merge, and migration.
go.mod Adds TOML dependency requirement.
go.sum Adds TOML dependency checksums.
Comments suppressed due to low confidence (1)

internal/tui/app.go:253

  • Esc in Settings is documented to "return to Collections", but this handler always activates tab index 0. With a configurable tabs.order, index 0 may not be Collections (and if Settings is first, Esc becomes a no-op). Consider activating the "collections" tab by ID when present, and fall back to index 0 otherwise.
		// Settings is a form, so keep Tab/digits/q available for the inputs.
		// Esc returns to Collections.
		if a.activeTabID() == "settings" {
			switch m.String() {
			case "esc":
				return a, a.activateTab(0)
			}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/config/config.go
Comment on lines +155 to +160
public, secrets := splitSecrets(c)
if err := writeTOML(path, public); err != nil {
return err
}
return writeTOML(SecretsPath(path), secrets)
}
Comment thread internal/tui/app.go
Comment on lines +448 to +456
a.cfg.Global.DefaultCluster = names[a.pickIx]
if err := config.Save(a.cfgPath, a.cfg); err != nil {
a.pickErr = "save failed: " + err.Error()
return nil
}
a.picking = false
a.pickErr = ""
a.c = client.New(a.cfg.URL(), a.cfg.APIKey())
a.buildTabs()
Comment thread internal/tui/app.go
Comment on lines +209 to 211
if wasSettings {
return a, a.activateTab(0)
}
Comment thread README.md
Comment on lines +99 to +105
[clusters.local]
url = "http://localhost:8108"
api_key = "your-local-admin-api-key"

[clusters.production]
url = "https://typesense.example.com"
api_key = "your-production-admin-api-key"
Comment thread README.md

A legacy `config.yaml` at the same path is still loaded if no `config.toml` is present.

The file is written with `0600` permissions since it holds your API key.
Comment thread go.mod
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants