7.1 KiB
Utilisation de ksp-config-lib
1. Bootstrap et moteur documentaire
Config doit interpréter ses propres arguments de bootstrap avant toute lecture de document :
let args: std::vec::Vec<std::ffi::OsString> = std::env::args_os().collect();
let bootstrap = match ksp_config_lib::ConfigBootstrapOptions::from_args(args.as_slice()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let registry = match ksp_config_lib::ConfigFileRegistry::from_args(args.as_slice()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let engine = ksp_config_lib::ConfigDocumentEngine::new(bootstrap, registry);
Les arguments compris par Config sont :
--cfgpath=/path/to/config
--schemapath=/path/to/schemas
--filemap=cfg.std.logging=my-logging.json
cfgpath et schemapath ne sont jamais lus depuis JSON, .env ou une variable KSP : cette règle évite un bootstrap récursif.
2. Charger et valider un document connu
Les consumers utilisent un file_id logique :
let file_id = match ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_STD_LOGGING) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let document = engine.load_validated_document(&file_id);
Le moteur résout le path physique via le registre, charge le schema associé, valide le schema lui-même, valide l'instance puis applique les invariants sémantiques KSP.
3. Environnement effectif
ConfigEnvironment::load() capture les variables process KSP/KSPB et lit ./.env :
let environment = match ksp_config_lib::ConfigEnvironment::load() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
La priorité est :
process environment > .env > fallback > missing
Une chaîne vide explicitement présente est une valeur définie ; elle ne provoque pas l'utilisation du fallback.
Exemples de placeholders :
${KSP_LOGS_DIRECTORY}
${KSP_LOGS_DIRECTORY:-logs}
Pour conserver la sensibilité et la provenance, préférer les variantes détaillées :
let resolved = environment.resolve_text_detailed("${KSP_SECRET_EXAMPLE}");
ResolvedConfigText / ResolvedConfigJson séparent valeur réelle et valeur sûre. Une représentation Debug ne doit pas révéler le réel d'un secret.
4. Construire Logging depuis Config
Le chemin normal consiste à charger le profil Logging, résoudre l'environnement puis construire directement le contrat Logging public :
let resolved = match engine.load_resolved_logging_config(std::option::Option::None, &environment) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let settings = resolved.into_settings();
let initialized = ksp_logging_lib::initialize(&settings);
let mut logging_guard = match initialized {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
L'application/service possède logging_guard. Config ne conserve pas de singleton Logging.
Un logs_directory relatif est ancré sur le current working directory du processus. Un path absolu est conservé. Une valeur explicite invalide produit une erreur effective : elle ne retombe pas silencieusement sur le fallback du placeholder.
Les files[].path restent relatifs sous le root Logging, y compris après interpolation.
5. Profils et composites
Pour un document standard profilé :
let profile = engine.load_resolved_profile(&file_id, std::option::Option::None);
None utilise le default_profile; Some("profile_id") impose un profil explicite.
Un composite référence les documents par file_id, jamais par filename. load_resolved_composite(...) conserve chaque ResolvedConfigProfile composant et sa provenance plutôt que d'aplatir plusieurs domaines dans une map ambiguë.
6. Management de std.logging.json
Une application de management construit la façade à partir d'un moteur :
let management = ksp_config_lib::ConfigManagement::new(engine);
let document = match management.load_logging_document() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
Le type LoggingConfigDocument et ses sous-structures exposent des setters/mutators typés. Après modification, la sauvegarde :
let saved = management.save_logging_document(&document);
valide le candidat complet avant toute substitution du fichier. Un candidat invalide ne remplace pas la source existante.
read_source(file_id) reste disponible pour une UI de réparation : il peut lire le texte brut d'un document enregistré même lorsque son JSON ou son schema est invalide. Il n'ouvre pas un path arbitraire.
7. Management de .env
Les rapports ordinaires sont sûrs :
let report = management.environment_report();
Ils distinguent notamment valeur souhaitée .env, valeur effective, source et shadowing process sans exposer un secret réel.
L'accès au réel est volontairement explicite :
let effective = management.reveal_effective_environment_value("KSP_SECRET_EXAMPLE");
let persisted = management.reveal_dotenv_value("KSP_SECRET_EXAMPLE");
Une application doit contrôler l'autorisation de l'utilisateur avant ces appels et ne jamais journaliser les valeurs retournées.
Les mutations persistantes utilisent :
let changed = management.set_dotenv_value("KSP_LOGS_DIRECTORY", "logs");
let removed = management.remove_dotenv_value("KSP_LOGS_DIRECTORY");
Elles n'altèrent jamais l'environnement hérité du processus. Une valeur process peut donc masquer une modification .env; ConfigEnvironmentChangeReport distingue source_changed, effective_changed, shadowed_by_process_environment et reload_required.
Sur Unix, un nouveau .env est créé avec des permissions privées 0600; les permissions existantes sont préservées lors des remplacements atomiques.
8. .env.example
/.env.example est l'inventaire versionné. /.env reste local et ignoré.
Toute nouvelle variable runtime concrète KSP_* / KSPB_* introduite dans le code ou les documents Config doit être ajoutée à .env.example avec un commentaire expliquant son usage. Les audits ksp-config-lib/tests/ownership.rs font échouer cargo test lorsqu'une clé concrète est oubliée.
9. Frontière Tauri
Une application Tauri doit appeler les APIs ci-dessus via ses commandes/DTO applicatifs. Elle ne lit ni JSON ni .env directement et ne résout jamais elle-même les placeholders.
Les valeurs Secret ne doivent pas être incluses par défaut dans les DTO publics. Une action UI explicitement autorisée peut appeler une méthode reveal_* et transporter le résultat par un DTO spécifique, sans log ni diagnostic contenant la valeur réelle.