Files
harmony/ROADMAP/02-refactor-harmony-config.md

5.0 KiB

Phase 2: Migrate Workspace to harmony_config

Goal

Replace every direct harmony_secret::SecretManager call with harmony_config equivalents. After this phase, modules and examples depend only on harmony_config. harmony_secret becomes an internal implementation detail behind StoreSource.

Current State

19 call sites use SecretManager::get_or_prompt::<T>() across:

Location Secret Types Call Sites
harmony/src/modules/brocade/brocade_snmp.rs BrocadeSnmpAuth, BrocadeSwitchAuth 2
harmony/src/modules/nats/score_nats_k8s.rs NatsAdmin 1
harmony/src/modules/okd/bootstrap_02_bootstrap.rs RedhatSecret, SshKeyPair 2
harmony/src/modules/application/features/monitoring.rs NtfyAuth 1
brocade/examples/main.rs BrocadeSwitchAuth 1
examples/okd_installation/src/main.rs + topology.rs SshKeyPair, BrocadeSwitchAuth, OPNSenseFirewallConfig 3
examples/okd_pxe/src/main.rs + topology.rs SshKeyPair, BrocadeSwitchAuth, OPNSenseFirewallCredentials 3
examples/opnsense/src/main.rs OPNSenseFirewallCredentials 1
examples/sttest/src/main.rs + topology.rs SshKeyPair, OPNSenseFirewallConfig 2
examples/opnsense_node_exporter/ (has dep but unclear usage) ~1
examples/okd_cluster_alerts/ (has dep but unclear usage) ~1
examples/brocade_snmp_server/ (has dep but unclear usage) ~1

Tasks

2.1 Bootstrap harmony_config in CLI and TUI entry points

Add harmony_config::init() as the first thing that happens in harmony_cli::run() and harmony_tui::run().

// harmony_cli/src/lib.rs — inside run()
pub async fn run<T: Topology + Send + Sync + 'static>(
    inventory: Inventory,
    topology: T,
    scores: Vec<Box<dyn Score<T>>>,
    args_struct: Option<Args>,
) -> Result<(), Box<dyn std::error::Error>> {
    // Initialize config system with default source chain
    let sqlite = Arc::new(SqliteSource::default().await?);
    let env = Arc::new(EnvSource);
    harmony_config::init(vec![env, sqlite]).await;

    // ... rest of run()
}

This replaces the implicit SecretManager lazy initialization that currently happens on first get_or_prompt call.

2.2 Migrate each secret type from Secret to Config

For each secret struct, change:

// Before
use harmony_secret::Secret;
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, InteractiveParse, Secret)]
struct BrocadeSwitchAuth { ... }

// After
use harmony_config::Config;
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, InteractiveParse, Config)]
struct BrocadeSwitchAuth { ... }

At each call site, change:

// Before
let config = SecretManager::get_or_prompt::<BrocadeSwitchAuth>().await.unwrap();

// After
let config = harmony_config::get_or_prompt::<BrocadeSwitchAuth>().await.unwrap();

2.3 Migration order (low risk to high risk)

  1. brocade/examples/main.rs — 1 call site, isolated example, easy to test manually
  2. examples/opnsense/src/main.rs — 1 call site, isolated
  3. harmony/src/modules/brocade/brocade_snmp.rs — 2 call sites, core module but straightforward
  4. harmony/src/modules/nats/score_nats_k8s.rs — 1 call site
  5. harmony/src/modules/application/features/monitoring.rs — 1 call site
  6. examples/sttest/ — 2 call sites, has both main.rs and topology.rs patterns
  7. examples/okd_installation/ — 3 call sites, complex topology setup
  8. examples/okd_pxe/ — 3 call sites, similar to okd_installation
  9. harmony/src/modules/okd/bootstrap_02_bootstrap.rs — 2 call sites, critical OKD bootstrap path

2.4 Remove harmony_secret from direct dependencies

After all call sites are migrated:

  1. Remove harmony_secret from Cargo.toml of: harmony, brocade, and all examples that had it
  2. harmony_config keeps harmony_secret as a dependency (for StoreSource)
  3. The Secret trait and SecretManager remain in harmony_secret but are not used directly anymore

2.5 Backward compatibility for existing local secrets

Users who already have secrets stored via LocalFileSecretStore (JSON files in ~/.local/share/harmony/secrets/) need a migration path:

  • On first run after upgrade, if SQLite has no entry for a key but the old JSON file exists, read from JSON and write to SQLite
  • Or: add LocalFileSource as a fallback source at the end of the chain (read-only) for one release cycle
  • Log a deprecation warning when reading from old JSON files

Deliverables

  • harmony_config::init() called in harmony_cli::run() and harmony_tui::run()
  • All 19 call sites migrated from SecretManager to harmony_config
  • harmony_secret removed from direct dependencies of harmony, brocade, and all examples
  • Backward compatibility for existing local JSON secrets
  • All existing unit tests still pass
  • Manual verification: one migrated example works end-to-end (prompt → persist → read)