v0.1.3-pre.015
This commit is contained in:
82
crates/ksp-config-lib/README.md
Normal file
82
crates/ksp-config-lib/README.md
Normal file
@@ -0,0 +1,82 @@
|
||||
<!-- file: crates/ksp-config-lib/README.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# ksp-config-lib
|
||||
|
||||
`ksp-config-lib` est le propriétaire unique de la configuration applicative KSP.
|
||||
|
||||
La crate centralise les documents JSON, leurs schemas, les profils et compositions, les variables d'environnement `KSP_*` / `KSPB_*`, le fichier `.env`, la résolution effective et les mutations persistantes explicitement autorisées.
|
||||
|
||||
## Responsabilités
|
||||
|
||||
`ksp-config-lib` possède :
|
||||
|
||||
- le bootstrap non récursif `config/` / `config/schemas/` et les overrides `--cfgpath` / `--schemapath` ;
|
||||
- le registre logique `file_id -> filename` et les overrides `--filemap=<file_id>=<filename>` ;
|
||||
- la lecture JSON et la validation JSON Schema Draft 2020-12 ;
|
||||
- les invariants sémantiques KSP des documents connus ;
|
||||
- les globals, `default_profile`, profils nommés et leur provenance ;
|
||||
- les compositions génériques par `file_id`, sans dépendance à un filename physique ;
|
||||
- le snapshot des variables process KSP/KSPB et la lecture de `./.env` ;
|
||||
- la priorité `process > .env > fallback > missing` ;
|
||||
- les placeholders `${NAME}` et `${NAME:-fallback}` ;
|
||||
- la classification `Public`, `Internal`, `Secret` ;
|
||||
- les représentations réelle et sûre/redacted ainsi que la provenance des valeurs résolues ;
|
||||
- l'adapter du document Logging effectif vers `ksp_logging_lib::LoggingSettings` ;
|
||||
- la surface de management pour inspecter les sources, modifier `std.logging.json`, consulter les rapports d'environnement, révéler explicitement une valeur réelle et modifier `.env` ;
|
||||
- les écritures atomiques JSON/`.env` et la protection des permissions `.env` ;
|
||||
- les audits workspace empêchant les bypass d'ownership Config et les oublis dans `.env.example`.
|
||||
|
||||
## Ressources gérées dans `0.1.3`
|
||||
|
||||
Le registre par défaut connaît :
|
||||
|
||||
```text
|
||||
cfg.std.logging -> config/std.logging.json
|
||||
schema.std.logging -> config/schemas/std.logging.schema.json
|
||||
schema.composite -> config/schemas/composite.schema.json
|
||||
```
|
||||
|
||||
`config/examples/composite.example.json` démontre le format composite sans créer de composite runtime fictif.
|
||||
|
||||
Le fichier local d'environnement est :
|
||||
|
||||
```text
|
||||
./.env
|
||||
```
|
||||
|
||||
Il n'est ni versionné ni livré. Le dépôt maintient `/.env.example` comme inventaire versionné des variables runtime utilisées. Toute nouvelle variable KSP/KSPB concrète doit y être ajoutée avec un commentaire d'usage dans le même delta que sa première utilisation.
|
||||
|
||||
## Frontières
|
||||
|
||||
Les autres crates et applications KSP ne doivent pas :
|
||||
|
||||
- lire directement les variables applicatives `KSP_*` / `KSPB_*` ;
|
||||
- parser ou écrire directement `.env` ;
|
||||
- ouvrir directement les documents Config connus par leur filename physique ;
|
||||
- réimplémenter la sélection de profils, les compositions ou les placeholders ;
|
||||
- reconstruire elles-mêmes la configuration Logging depuis le JSON.
|
||||
|
||||
`ksp-config-lib` dépend de `ksp-core-lib` pour `Error`/`Result` et de `ksp-logging-lib` pour les événements Config utiles et le contrat `LoggingSettings`.
|
||||
|
||||
La dépendance inverse est interdite : `ksp-core-lib` et `ksp-logging-lib` ne dépendent pas de Config.
|
||||
|
||||
Config ne possède pas le `LoggingGuard`. L'application ou le service qui orchestre le runtime construit la configuration effective puis possède le lifecycle `ksp_logging_lib::initialize/reinitialize`.
|
||||
|
||||
Tauri et les DTO TS-RS restent hors de cette crate. La future `ksp-app-config-desk` doit rester une frontière applicative mince au-dessus des APIs Config.
|
||||
|
||||
## Secrets
|
||||
|
||||
Un secret reste accessible au runtime ou au management lorsqu'un consumer autorisé en a réellement besoin, mais les vues ordinaires utilisent la représentation sûre.
|
||||
|
||||
Les méthodes `reveal_*` constituent un opt-in explicite au réel. L'authentification/autorisation de l'utilisateur humain appartient à l'application appelante et les valeurs retournées par ces méthodes ne doivent jamais être journalisées.
|
||||
|
||||
Le document Logging refuse les valeurs de sensibilité `Secret` dans sa configuration effective.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [`USAGE.md`](USAGE.md) — construction du moteur, résolution runtime et management ;
|
||||
- [`TODO.md`](TODO.md) — points explicitement différés après `0.1.3` ;
|
||||
- [`../../docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md`](../../docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md) — plan historique détaillé de la fondation Config ;
|
||||
- [`../../config/std.logging.json`](../../config/std.logging.json) — premier document standard concret ;
|
||||
- [`../../.env.example`](../../.env.example) — inventaire versionné des variables d'environnement runtime.
|
||||
38
crates/ksp-config-lib/TODO.md
Normal file
38
crates/ksp-config-lib/TODO.md
Normal file
@@ -0,0 +1,38 @@
|
||||
<!-- file: crates/ksp-config-lib/TODO.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# TODO ksp-config-lib
|
||||
|
||||
## État de clôture `0.1.3`
|
||||
|
||||
Aucun TODO fonctionnel bloquant n'est ouvert pour la fondation Config `0.1.3`.
|
||||
|
||||
Les responsabilités prévues pour cette release sont implémentées et couvertes par les tests : bootstrap, registre `file_id`, JSON/JSON Schema, profils, composites, environnement process/`.env`, placeholders, sensibilité/provenance, adapter Logging, management/persistence et audits d'ownership.
|
||||
|
||||
## Reporté explicitement à `0.1.4`
|
||||
|
||||
La validation applicative desktop appartient à `ksp-app-config-desk` :
|
||||
|
||||
- frontière Tauri et DTO TS-RS applicatifs ;
|
||||
- affichage des sources et diagnostics Config ;
|
||||
- sélection/inspection des profils ;
|
||||
- affichage desired/effective/shadow des variables ;
|
||||
- actions explicites de reveal de secrets avec contrôle d'autorisation côté application ;
|
||||
- édition/sauvegarde de `std.logging.json` via `ConfigManagement` ;
|
||||
- édition de `.env` via `ConfigManagement` ;
|
||||
- orchestration réelle `Config -> LoggingSettings -> initialize/reinitialize` avec `LoggingGuard` possédé par l'application ;
|
||||
- validation UX des erreurs de source invalide, des modifications non effectives car masquées par le process et des besoins de reload.
|
||||
|
||||
Ces points ne nécessitent pas de duplication de logique dans `ksp-config-lib`; toute lacune réelle révélée par l'application ouvrira un delta Config explicite.
|
||||
|
||||
## Futur, uniquement au besoin
|
||||
|
||||
Les capacités suivantes sont différées jusqu'à l'apparition de composants réels :
|
||||
|
||||
- nouveaux documents `std.<domain>.json` et schemas associés ;
|
||||
- descriptors `cfg.composite.<consumer>` pour de vrais consumers ;
|
||||
- contrats typés de management supplémentaires pour les nouveaux documents ;
|
||||
- watcher filesystem/reload automatique si une application ou un service démontre le besoin ;
|
||||
- intégration éventuelle d'un secrets manager externe.
|
||||
|
||||
Ne pas introduire par anticipation un JSON patch arbitraire, un watcher générique, un service distribué de configuration ou un chiffrement maison de `.env`.
|
||||
184
crates/ksp-config-lib/USAGE.md
Normal file
184
crates/ksp-config-lib/USAGE.md
Normal file
@@ -0,0 +1,184 @@
|
||||
<!-- file: crates/ksp-config-lib/USAGE.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Utilisation de ksp-config-lib
|
||||
|
||||
## 1. Bootstrap et moteur documentaire
|
||||
|
||||
Config doit interpréter ses propres arguments de bootstrap avant toute lecture de document :
|
||||
|
||||
```rust
|
||||
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 :
|
||||
|
||||
```text
|
||||
--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 :
|
||||
|
||||
```rust
|
||||
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` :
|
||||
|
||||
```rust
|
||||
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 :
|
||||
|
||||
```text
|
||||
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 :
|
||||
|
||||
```text
|
||||
${KSP_LOGS_DIRECTORY}
|
||||
${KSP_LOGS_DIRECTORY:-logs}
|
||||
```
|
||||
|
||||
Pour conserver la sensibilité et la provenance, préférer les variantes détaillées :
|
||||
|
||||
```rust
|
||||
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 :
|
||||
|
||||
```rust
|
||||
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é :
|
||||
|
||||
```rust
|
||||
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 :
|
||||
|
||||
```rust
|
||||
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 :
|
||||
|
||||
```rust
|
||||
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 :
|
||||
|
||||
```rust
|
||||
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 :
|
||||
|
||||
```rust
|
||||
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 :
|
||||
|
||||
```rust
|
||||
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.
|
||||
@@ -1,15 +1,15 @@
|
||||
// file: crates/ksp-config-lib/src/lib.rs
|
||||
// version: 9
|
||||
// version: 10
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
//! KSP-owned application configuration facade.
|
||||
//!
|
||||
//! `0.1.3-pre.013` owns bootstrap roots, the logical file registry, generic JSON/JSON Schema loading, standard-document profile resolution, generic composite
|
||||
//! resolution and KSP/KSPB environment resolution through process + `.env` + fallback precedence. The standard Logging document remains the first registered
|
||||
//! runtime document. Environment-derived values preserve real/safe representations, sensitivity and provenance; the standard Logging profile can now be
|
||||
//! mapped explicitly to `ksp_logging_lib::LoggingSettings`. Explicit management now owns typed Logging mutation, safe environment reports, privileged reveal calls and atomic JSON/`.env` persistence.
|
||||
//! The `0.1.3` surface owns bootstrap roots, the logical file registry, JSON/JSON Schema validation, standard-document profiles, generic composites and
|
||||
//! KSP/KSPB environment resolution through process + `.env` + fallback precedence. Resolved values preserve real/safe representations, sensitivity and
|
||||
//! provenance. The standard Logging document maps explicitly to `ksp_logging_lib::LoggingSettings`, while the management surface provides typed Logging
|
||||
//! mutation, safe environment reports, explicit privileged reveal calls and atomic JSON/`.env` persistence.
|
||||
|
||||
mod bootstrap;
|
||||
mod composite;
|
||||
|
||||
Reference in New Issue
Block a user