0.5.1-pre.004

This commit is contained in:
2026-08-09 22:52:37 +02:00
parent 6151bb25e7
commit ec07ddbd80
53 changed files with 989 additions and 886 deletions

View File

@@ -3,36 +3,39 @@
# Never commit the real .env file. # Never commit the real .env file.
# Shared Helius credential used by the configured HTTP and WebSocket endpoints. # Shared Helius credential used by the configured HTTP and WebSocket endpoints.
HELIUS_API_KEY=replace-with-your-helius-api-key KS_SECRET_HELIUS_API_KEY=replace-with-your-helius-api-key
# PostgreSQL database used by the mainnet_research and mainnet profiles. # PostgreSQL database used by the mainnet_research and mainnet profiles.
KB_POSTGRES_MAINNET_URL=postgres://solana:solana@localhost:5432/khadhroony_mainnet KS_SECRET_POSTGRES_MAINNET_URL=postgres://solana:solana@localhost:5432/khadhroony_mainnet
# PostgreSQL database dedicated to the local_devnet profile and Devnet validation. # PostgreSQL database dedicated to the local_devnet profile and Devnet validation.
KB_POSTGRES_DEVNET_URL=postgres://solana:solana@localhost:5432/khadhroony_devnet KS_SECRET_POSTGRES_DEVNET_URL=postgres://solana:solana@localhost:5432/khadhroony_devnet
# PostgreSQL database reserved for automated integration tests. # PostgreSQL database reserved for automated integration tests.
KB_POSTGRES_TEST_URL=postgres://solana:solana@localhost:5432/khadhroony_test KS_SECRET_POSTGRES_TEST_URL=postgres://solana:solana@localhost:5432/khadhroony_test
# Optional configuration-file override. # Optional configuration-file override.
# KB_CONFIG_PATH=config/example.config.json # KS_CONFIG_PATH=config/example.config.json
# Optional Devnet profile selected by CLI and opt-in scenario tests. # Optional Devnet profile selected by CLI and opt-in scenario tests.
# When absent, the first compatible Devnet profile is selected. # When absent, the first compatible Devnet profile is selected.
# KB_DEVNET_PROFILE=local_devnet # KS_DEVNET_PROFILE=local_devnet
# Optional Token-2022 Devnet validation fixtures. # Optional Token-2022 Devnet validation fixtures.
TOKEN_2022_PROGRAM=TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID=TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
TOKEN_2022_MINT= KS_PUBLIC_DEVNET_TOKEN_2022_MINT=
TOKEN_2022_SOURCE= KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE=
TOKEN_2022_DESTINATION= KS_PUBLIC_DEVNET_TOKEN_2022_DESTINATION=
TOKEN_2022_CLOSE_ACCOUNT= KS_PUBLIC_DEVNET_TOKEN_2022_CLOSE_ACCOUNT=
TOKEN_2022_DELEGATE= KS_PUBLIC_DEVNET_TOKEN_2022_DELEGATE=
TOKEN_2022_AUTHORITY= KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY=
TOKEN_2022_FREEZE_AUTHORITY= KS_PUBLIC_DEVNET_TOKEN_2022_FREEZE_AUTHORITY=
TOKEN_2022_DECIMALS=9 KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS=9
TOKEN_2022_TRANSFER_AMOUNT_RAW=1 KS_PUBLIC_DEVNET_TOKEN_2022_MINT_AMOUNT_RAW=10000000000
KS_PUBLIC_DEVNET_TOKEN_2022_TRANSFER_AMOUNT_RAW=1000000000
KS_PUBLIC_DEVNET_TOKEN_2022_APPROVE_AMOUNT_RAW=2000000000
KS_PUBLIC_DEVNET_TOKEN_2022_BURN_AMOUNT_RAW=1000000000
# Optional explicit environment-file selection. Relative paths use the workspace root. # Optional explicit environment-file selection. Relative paths use the workspace root.
# Define this variable in the process environment when the selected file is not .env. # Define this variable in the process environment when the selected file is not .env.
# KB_ENV_FILE=.env.local # KS_ENV_FILE=.env.local

View File

@@ -1,5 +1,5 @@
# file: Cargo.toml # file: Cargo.toml
# version: 47 # version: 48
[workspace] [workspace]
resolver = "3" resolver = "3"
@@ -18,7 +18,7 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "0.5.1-pre.3" version = "0.5.1-pre.4"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-bot3" repository = "https://git.sasedev.com/Sasedev/khadhroony-bot3"

View File

@@ -1,5 +1,5 @@
<!-- file: README.md --> <!-- file: README.md -->
<!-- version: 21 --> <!-- version: 22 -->
# Khadhroony Bot3 # Khadhroony Bot3
@@ -21,7 +21,7 @@ Le workspace contient onze crates :
- `ks-wallet` : frontière de wallet et signataires ; - `ks-wallet` : frontière de wallet et signataires ;
- `kb-app-demo-desktop` : application Tauri de démonstration et validation opérateur. - `kb-app-demo-desktop` : application Tauri de démonstration et validation opérateur.
La série `0.5.x` prépare la séparation explicite entre le domaine applicatif `khadhroony-bot` et les bibliothèques généralistes `khadhroony-solana`. En `0.5.1`, les dix crates généralistes doivent migrer vers les noms `ks-*` / `ks_*`, tandis que `kb-app-demo-desktop` conserve son nom et reste une application du workspace Bot. Le workspace, le dépôt et le répertoire racine restent nommés `khadhroony-bot3` pendant cette migration et ne doivent pas être renommés avant `1.0` ou une version ultérieure explicitement dédiée. La politique de migration est définie dans [`docs/decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md`](docs/decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md). La série `0.5.x` prépare la séparation explicite entre le domaine applicatif `khadhroony-bot` et les bibliothèques généralistes `khadhroony-solana`. Depuis `0.5.1-pre.002`, les dix crates généralistes utilisent les noms `ks-*` / `ks_*`, tandis que `kb-app-demo-desktop` conserve son nom et reste une application du workspace Bot. Le workspace, le dépôt et le répertoire racine restent nommés `khadhroony-bot3` pendant cette migration et ne doivent pas être renommés avant `1.0` ou une version ultérieure explicitement dédiée. La politique de migration est définie dans [`docs/decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md`](docs/decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md).
Références : Références :

View File

@@ -1,5 +1,5 @@
<!-- file: ROADMAP.md --> <!-- file: ROADMAP.md -->
<!-- version: 35 --> <!-- version: 36 -->
# ROADMAP — khadhroony-bot3 # ROADMAP — khadhroony-bot3
@@ -71,7 +71,7 @@ Cadrage clôturé avant toute restructuration majeure :
- audit des responsabilités et couplages de `ks-config`, `ks-logging`, `ks-wallet`, `ks-store`, `ks-pipeline-demo-scenarios` et `kb-app-demo-desktop` ; - audit des responsabilités et couplages de `ks-config`, `ks-logging`, `ks-wallet`, `ks-store`, `ks-pipeline-demo-scenarios` et `kb-app-demo-desktop` ;
- inventaire des contrats publics, formats persistés, migrations, dépendances, scénarios et preuves de validation ; - inventaire des contrats publics, formats persistés, migrations, dépendances, scénarios et preuves de validation ;
- confirmation du split futur entre configuration généraliste et configuration logging ; - confirmation du split futur entre configuration généraliste et configuration logging ;
- définition de la politique de secrets et du namespace d'environnement `KS_*` ; - définition de la politique de secrets et des namespaces d'environnement `KS_*` pour Khadhroony Solana et `KB_*` pour les futurs contrats réellement spécifiques au Bot ;
- décision de migrer les dix bibliothèques Solana généralistes vers `ks-*` / `ks_*` ; - décision de migrer les dix bibliothèques Solana généralistes vers `ks-*` / `ks_*` ;
- décision de migrer les identités techniques généralistes `kb-lib.decoder.*`, `kb-lib.materializer.*` et `kb-lib.executor.*` vers `ks-lib-decoder.*`, `ks-lib-materializer.*` et `ks-lib-executor.*` ; - décision de migrer les identités techniques généralistes `kb-lib.decoder.*`, `kb-lib.materializer.*` et `kb-lib.executor.*` vers `ks-lib-decoder.*`, `ks-lib-materializer.*` et `ks-lib-executor.*` ;
- confirmation que `kb-app-demo-desktop` reste côté Bot et peut héberger à terme des démos Solana généralistes et des démos spécifiques au bot ; - confirmation que `kb-app-demo-desktop` reste côté Bot et peut héberger à terme des démos Solana généralistes et des démos spécifiques au bot ;
@@ -88,9 +88,9 @@ Cette version effectue la migration de namespace des bibliothèques Solana et re
- migrer les identifiants Rust correspondants vers `ks_*`, les manifests, chemins, imports, exports, tests externes, scripts et documentation ; - migrer les identifiants Rust correspondants vers `ks_*`, les manifests, chemins, imports, exports, tests externes, scripts et documentation ;
- conserver `kb-app-demo-desktop` comme application du domaine Bot, consommatrice des composants `ks-*` ; - conserver `kb-app-demo-desktop` comme application du domaine Bot, consommatrice des composants `ks-*` ;
- migrer les identités runtime/persistées généralistes vers la nomenclature `ks-*`, notamment `ks-lib-decoder.*`, `ks-lib-materializer.*` et `ks-lib-executor.*`, après inventaire exhaustif des chaînes concernées ; - migrer les identités runtime/persistées généralistes vers la nomenclature `ks-*`, notamment `ks-lib-decoder.*`, `ks-lib-materializer.*` et `ks-lib-executor.*`, après inventaire exhaustif des chaînes concernées ;
- imposer le namespace d'environnement `KS_*` pour les variables appartenant au workspace ; - imposer `KS_*` aux variables possédées par les composants Solana généralistes et réserver `KB_*` aux variables réellement possédées par `kb-app-demo-desktop` ou de futures crates spécifiques au Bot ;
- classifier `KS_SECRET_*` comme jamais exposable, `KS_PUBLIC_*` comme publiable uniquement via une surface explicitement autorisée et les autres `KS_*` comme internes/diagnostiques ; - appliquer symétriquement les classes `*_SECRET_*`, `*_PUBLIC_*` et internes aux namespaces `KS_*` et `KB_*`, avec exposition publique uniquement via une surface explicitement autorisée ;
- préserver la sensibilité après substitution : toute valeur composée contenant un `KS_SECRET_*` reste secrète ; - préserver la sensibilité après substitution : toute valeur composée contenant un `KS_SECRET_*` ou `KB_SECRET_*` reste secrète ;
- séparer la configuration généraliste et la configuration logging dans des documents et schémas indépendants ; - séparer la configuration généraliste et la configuration logging dans des documents et schémas indépendants ;
- permettre des profils logging indépendants des profils réseau/applicatifs ; - permettre des profils logging indépendants des profils réseau/applicatifs ;
- distinguer configuration source, configuration runtime résolue et DTO publics/diagnostiques ; - distinguer configuration source, configuration runtime résolue et DTO publics/diagnostiques ;

View File

@@ -1,5 +1,5 @@
<!-- file: config/README.md --> <!-- file: config/README.md -->
<!-- version: 18 --> <!-- version: 19 -->
# Configuration locale # Configuration locale
@@ -26,12 +26,12 @@ Ce dossier contient les exemples et le schéma de configuration JSON.
`example.config.json` conserve la topologie des profils et référence les valeurs locales avec des placeholders : `example.config.json` conserve la topologie des profils et référence les valeurs locales avec des placeholders :
```text ```text
HELIUS_API_KEY KS_SECRET_HELIUS_API_KEY
KB_POSTGRES_MAINNET_URL KS_SECRET_POSTGRES_MAINNET_URL
KB_POSTGRES_DEVNET_URL KS_SECRET_POSTGRES_DEVNET_URL
``` ```
`KB_POSTGRES_TEST_URL` nest pas utilisé par un profil runtime : il reste réservé aux tests dintégration PostgreSQL. Le profil `local_devnet` utilise `KB_POSTGRES_DEVNET_URL`; les profils `mainnet_research` et `mainnet` utilisent `KB_POSTGRES_MAINNET_URL`. Les trois bases doivent être distinctes. `KS_SECRET_POSTGRES_TEST_URL` nest pas utilisé par un profil runtime : il reste réservé aux tests dintégration PostgreSQL. Le profil `local_devnet` utilise `KS_SECRET_POSTGRES_DEVNET_URL`; les profils `mainnet_research` et `mainnet` utilisent `KS_SECRET_POSTGRES_MAINNET_URL`. Les trois bases doivent être distinctes.
Le fichier réel `.env` reste local et ignoré par Git. `.env.example` est le seul modèle dotenv versionné. Le fichier réel `.env` reste local et ignoré par Git. `.env.example` est le seul modèle dotenv versionné.
@@ -101,4 +101,3 @@ http_transactions:
Un fichier de configuration local déjà créé nest pas modifié automatiquement lorsque `example.config.json` évolue. Lopérateur doit reporter explicitement ces valeurs dans son profil `local_devnet`. Un fichier de configuration local déjà créé nest pas modifié automatiquement lorsque `example.config.json` évolue. Lopérateur doit reporter explicitement ces valeurs dans son profil `local_devnet`.
Un warning `retry_http_json_rpc_after_rate_limit` reste possible sur un service public partagé. Il indique que le cooldown et le retry borné ont été activés ; il ne constitue un échec que si les tentatives finissent par être épuisées. Un warning `retry_http_json_rpc_after_rate_limit` reste possible sur un service public partagé. Il indique que le cooldown et le retry borné ont été activés ; il ne constitue un échec que si les tentatives finissent par être épuisées.

View File

@@ -1195,7 +1195,7 @@
"enabled": true, "enabled": true,
"backend": "postgres", "backend": "postgres",
"postgres": { "postgres": {
"url": "${KB_POSTGRES_DEVNET_URL}", "url": "${KS_SECRET_POSTGRES_DEVNET_URL}",
"max_connections": 8, "max_connections": 8,
"connect_timeout_ms": 5000, "connect_timeout_ms": 5000,
"auto_initialize_schema": true "auto_initialize_schema": true
@@ -2613,7 +2613,7 @@
"enabled": true, "enabled": true,
"backend": "postgres", "backend": "postgres",
"postgres": { "postgres": {
"url": "${KB_POSTGRES_MAINNET_URL}", "url": "${KS_SECRET_POSTGRES_MAINNET_URL}",
"max_connections": 16, "max_connections": 16,
"connect_timeout_ms": 5000, "connect_timeout_ms": 5000,
"auto_initialize_schema": true "auto_initialize_schema": true
@@ -2764,7 +2764,7 @@
"enabled": true, "enabled": true,
"provider": "helius", "provider": "helius",
"cluster": "mainnet-beta", "cluster": "mainnet-beta",
"url": "https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}", "url": "https://mainnet.helius-rpc.com/?api-key=${KS_SECRET_HELIUS_API_KEY}",
"connect_timeout_ms": 4000, "connect_timeout_ms": 4000,
"request_timeout_ms": 10000, "request_timeout_ms": 10000,
"max_idle_connections_per_host": 8, "max_idle_connections_per_host": 8,
@@ -2924,7 +2924,7 @@
"enabled": true, "enabled": true,
"provider": "helius", "provider": "helius",
"cluster": "mainnet-beta", "cluster": "mainnet-beta",
"url": "wss://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}", "url": "wss://mainnet.helius-rpc.com/?api-key=${KS_SECRET_HELIUS_API_KEY}",
"connect_timeout_ms": 5000, "connect_timeout_ms": 5000,
"request_timeout_ms": 10000, "request_timeout_ms": 10000,
"unsubscribe_timeout_ms": 1500, "unsubscribe_timeout_ms": 1500,
@@ -4231,7 +4231,7 @@
"enabled": true, "enabled": true,
"backend": "postgres", "backend": "postgres",
"postgres": { "postgres": {
"url": "${KB_POSTGRES_MAINNET_URL}", "url": "${KS_SECRET_POSTGRES_MAINNET_URL}",
"max_connections": 16, "max_connections": 16,
"connect_timeout_ms": 5000, "connect_timeout_ms": 5000,
"auto_initialize_schema": true "auto_initialize_schema": true
@@ -4382,7 +4382,7 @@
"enabled": true, "enabled": true,
"provider": "helius", "provider": "helius",
"cluster": "mainnet-beta", "cluster": "mainnet-beta",
"url": "https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}", "url": "https://mainnet.helius-rpc.com/?api-key=${KS_SECRET_HELIUS_API_KEY}",
"connect_timeout_ms": 4000, "connect_timeout_ms": 4000,
"request_timeout_ms": 10000, "request_timeout_ms": 10000,
"max_idle_connections_per_host": 8, "max_idle_connections_per_host": 8,
@@ -4542,7 +4542,7 @@
"enabled": true, "enabled": true,
"provider": "helius", "provider": "helius",
"cluster": "mainnet-beta", "cluster": "mainnet-beta",
"url": "wss://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}", "url": "wss://mainnet.helius-rpc.com/?api-key=${KS_SECRET_HELIUS_API_KEY}",
"connect_timeout_ms": 5000, "connect_timeout_ms": 5000,
"request_timeout_ms": 10000, "request_timeout_ms": 10000,
"unsubscribe_timeout_ms": 1500, "unsubscribe_timeout_ms": 1500,

View File

@@ -1,5 +1,5 @@
<!-- file: docs/DEVNET_EXECUTION_GUIDE.md --> <!-- file: docs/DEVNET_EXECUTION_GUIDE.md -->
<!-- version: 25 --> <!-- version: 26 -->
# Guide dexécution Devnet # Guide dexécution Devnet
@@ -21,8 +21,8 @@ Les commandes réutilisables sont centralisées en section 4. Chaque scénario r
## 2. Préconditions ## 2. Préconditions
- `.env` contient `KB_POSTGRES_DEVNET_URL` et les secrets de transport requis ; - `.env` contient `KS_SECRET_POSTGRES_DEVNET_URL` et les secrets de transport requis ;
- `KB_POSTGRES_DEVNET_URL`, `KB_POSTGRES_MAINNET_URL` et `KB_POSTGRES_TEST_URL` désignent des bases distinctes ; - `KS_SECRET_POSTGRES_DEVNET_URL`, `KS_SECRET_POSTGRES_MAINNET_URL` et `KS_SECRET_POSTGRES_TEST_URL` désignent des bases distinctes ;
- le profil sélectionné est Devnet et autorise explicitement lenvoi Devnet ; - le profil sélectionné est Devnet et autorise explicitement lenvoi Devnet ;
- lenvoi Mainnet reste désactivé ; - lenvoi Mainnet reste désactivé ;
- les plafonds de frais, de dépense et de rent sont contrôlés ; - les plafonds de frais, de dépense et de rent sont contrôlés ;
@@ -44,7 +44,7 @@ Ce terminal reste occupé par `cargo tauri dev` pendant toute la campagne. Il af
Ce terminal reste disponible pour les commandes Solana, PostgreSQL, balances, confirmations et captures avec `tee`. Ce terminal reste disponible pour les commandes Solana, PostgreSQL, balances, confirmations et captures avec `tee`.
Les commandes `C01` à `C05` doivent être exécutées dans le terminal B. Le terminal A doit exécuter `T01`, puis rester ouvert. Avant chaque scénario, le terminal B doit définir `KB_DEVNET_SCENARIO` avant dappeler `C06`. Les commandes `C01` à `C05` doivent être exécutées dans le terminal B. Le terminal A doit exécuter `T01`, puis rester ouvert. Avant chaque scénario, le terminal B doit définir `KS_DEVNET_SCENARIO` avant dappeler `C06`.
## 4. Commandes communes ## 4. Commandes communes
@@ -100,13 +100,13 @@ Arrêter avec `Ctrl+C`, puis relancer `T01`.
### C01 — Initialiser lenvironnement de validation ### C01 — Initialiser lenvironnement de validation
```bash ```bash
cd ~/Projects/khadhroony-bot3 && set -o pipefail && export KB_DEVNET_PROFILE="local_devnet" && export KB_DEVNET_RPC_URL="https://api.devnet.solana.com" && export KB_DEVNET_VALIDATION_DIR="/tmp/devnet-validation/current" && export KB_DEVNET_WALLET="$PWD/wallets/temporary/local_devnet/local-devnet-operator.json" && mkdir -p "$KB_DEVNET_VALIDATION_DIR" && printf 'Profil : %s\n' "$KB_DEVNET_PROFILE" && printf 'RPC Devnet : %s\n' "$KB_DEVNET_RPC_URL" && printf 'Preuves : %s\n' "$KB_DEVNET_VALIDATION_DIR" && printf 'Wallet : %s\n' "$KB_DEVNET_WALLET"; cd ~/Projects/khadhroony-bot3 && set -o pipefail && export KS_DEVNET_PROFILE="local_devnet" && export KS_DEVNET_RPC_URL="https://api.devnet.solana.com" && export KS_DEVNET_VALIDATION_DIR="/tmp/devnet-validation/current" && export KS_DEVNET_WALLET="$PWD/wallets/temporary/local_devnet/local-devnet-operator.json" && mkdir -p "$KS_DEVNET_VALIDATION_DIR" && printf 'Profil : %s\n' "$KS_DEVNET_PROFILE" && printf 'RPC Devnet : %s\n' "$KS_DEVNET_RPC_URL" && printf 'Preuves : %s\n' "$KS_DEVNET_VALIDATION_DIR" && printf 'Wallet : %s\n' "$KS_DEVNET_WALLET";
``` ```
### C02 — Capturer les versions CLI ### C02 — Capturer les versions CLI
```bash ```bash
command -v solana && command -v solana-keygen && command -v spl-token && { date --iso-8601=seconds; solana --version; solana-keygen --version; spl-token --version; } | tee "$KB_DEVNET_VALIDATION_DIR/00-cli-versions.txt"; command -v solana && command -v solana-keygen && command -v spl-token && { date --iso-8601=seconds; solana --version; solana-keygen --version; spl-token --version; } | tee "$KS_DEVNET_VALIDATION_DIR/00-cli-versions.txt";
``` ```
Chaque campagne doit capturer les versions exactes des outils externes quelle utilise. Les fixtures Rust natives ne doivent pas dépendre implicitement de la configuration globale dune CLI. Chaque campagne doit capturer les versions exactes des outils externes quelle utilise. Les fixtures Rust natives ne doivent pas dépendre implicitement de la configuration globale dune CLI.
@@ -114,7 +114,7 @@ Chaque campagne doit capturer les versions exactes des outils externes quelle
### C03 — Vérifier lidentité du réseau ### C03 — Vérifier lidentité du réseau
```bash ```bash
solana config set --url "$KB_DEVNET_RPC_URL" && { date --iso-8601=seconds; solana config get; solana cluster-version --url "$KB_DEVNET_RPC_URL"; solana genesis-hash --url "$KB_DEVNET_RPC_URL"; solana epoch-info --url "$KB_DEVNET_RPC_URL"; } | tee "$KB_DEVNET_VALIDATION_DIR/01-devnet-network.txt"; solana config set --url "$KS_DEVNET_RPC_URL" && { date --iso-8601=seconds; solana config get; solana cluster-version --url "$KS_DEVNET_RPC_URL"; solana genesis-hash --url "$KS_DEVNET_RPC_URL"; solana epoch-info --url "$KS_DEVNET_RPC_URL"; } | tee "$KS_DEVNET_VALIDATION_DIR/01-devnet-network.txt";
``` ```
Le genesis hash Devnet attendu est : Le genesis hash Devnet attendu est :
@@ -126,37 +126,37 @@ EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG
### C04 — Vérifier le wallet opérateur ### C04 — Vérifier le wallet opérateur
```bash ```bash
test -f "$KB_DEVNET_WALLET" && chmod 600 "$KB_DEVNET_WALLET" && export KB_DEVNET_WALLET_PUBKEY="$(solana-keygen pubkey "$KB_DEVNET_WALLET")" && { date --iso-8601=seconds; printf 'wallet_path=%s\n' "$KB_DEVNET_WALLET"; printf 'wallet_pubkey=%s\n' "$KB_DEVNET_WALLET_PUBKEY"; solana balance "$KB_DEVNET_WALLET_PUBKEY" --url "$KB_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KB_DEVNET_VALIDATION_DIR/02-wallet.txt" test -f "$KS_DEVNET_WALLET" && chmod 600 "$KS_DEVNET_WALLET" && export KS_PUBLIC_DEVNET_WALLET_ADDRESS="$(solana-keygen pubkey "$KS_DEVNET_WALLET")" && { date --iso-8601=seconds; printf 'wallet_path=%s\n' "$KS_DEVNET_WALLET"; printf 'wallet_pubkey=%s\n' "$KS_PUBLIC_DEVNET_WALLET_ADDRESS"; solana balance "$KS_PUBLIC_DEVNET_WALLET_ADDRESS" --url "$KS_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KS_DEVNET_VALIDATION_DIR/02-wallet.txt"
``` ```
### C05 — Recréer la base Devnet ### C05 — Recréer la base Devnet
Cette commande est destructive. Elle ne doit viser que `KB_POSTGRES_DEVNET_URL`. Elle supprime toutes les données et tous les objets du schéma `public`, puis laisse lapplication recréer son schéma lors de louverture dune fenêtre Devnet. Cette commande est destructive. Elle ne doit viser que `KS_SECRET_POSTGRES_DEVNET_URL`. Elle supprime toutes les données et tous les objets du schéma `public`, puis laisse lapplication recréer son schéma lors de louverture dune fenêtre Devnet.
```bash ```bash
test -n "$KB_POSTGRES_DEVNET_URL" && printf '%s\n' "$KB_POSTGRES_DEVNET_URL" && export KB_CONFIRM_DEVNET_DATABASE_RESET="YES_RESET_SOLANA_DEVNET" && test "$KB_CONFIRM_DEVNET_DATABASE_RESET" = "YES_RESET_SOLANA_DEVNET" && psql "$KB_POSTGRES_DEVNET_URL" -v ON_ERROR_STOP=1 -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;' test -n "$KS_SECRET_POSTGRES_DEVNET_URL" && printf 'database_url=<configured>\n' && export KS_CONFIRM_DEVNET_DATABASE_RESET="YES_RESET_SOLANA_DEVNET" && test "$KS_CONFIRM_DEVNET_DATABASE_RESET" = "YES_RESET_SOLANA_DEVNET" && psql "$KS_SECRET_POSTGRES_DEVNET_URL" -v ON_ERROR_STOP=1 -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'
``` ```
Après ouverture dune fenêtre Devnet, contrôler les tables : Après ouverture dune fenêtre Devnet, contrôler les tables :
```bash ```bash
psql "$KB_POSTGRES_DEVNET_URL" -v ON_ERROR_STOP=1 -c "SELECT schemaname, tablename FROM pg_tables WHERE schemaname = 'public' ORDER BY tablename;" | tee "$KB_DEVNET_VALIDATION_DIR/03-devnet-schema.txt" psql "$KS_SECRET_POSTGRES_DEVNET_URL" -v ON_ERROR_STOP=1 -c "SELECT schemaname, tablename FROM pg_tables WHERE schemaname = 'public' ORDER BY tablename;" | tee "$KS_DEVNET_VALIDATION_DIR/03-devnet-schema.txt"
``` ```
### C06 — Capturer le solde avant scénario ### C06 — Capturer le solde avant scénario
Définir `KB_DEVNET_SCENARIO` avant lappel. Définir `KS_DEVNET_SCENARIO` avant lappel.
```bash ```bash
test -n "${KB_DEVNET_SCENARIO:-}" && test -n "${KB_DEVNET_WALLET_PUBKEY:-}" && test -n "${KB_DEVNET_RPC_URL:-}" && test -n "${KB_DEVNET_VALIDATION_DIR:-}" && { date --iso-8601=seconds; printf 'scenario=%s\nwallet=%s\n' "$KB_DEVNET_SCENARIO" "$KB_DEVNET_WALLET_PUBKEY"; solana balance "$KB_DEVNET_WALLET_PUBKEY" --url "$KB_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KB_DEVNET_VALIDATION_DIR/${KB_DEVNET_SCENARIO}-wallet-before.txt" test -n "${KS_DEVNET_SCENARIO:-}" && test -n "${KS_PUBLIC_DEVNET_WALLET_ADDRESS:-}" && test -n "${KS_DEVNET_RPC_URL:-}" && test -n "${KS_DEVNET_VALIDATION_DIR:-}" && { date --iso-8601=seconds; printf 'scenario=%s\nwallet=%s\n' "$KS_DEVNET_SCENARIO" "$KS_PUBLIC_DEVNET_WALLET_ADDRESS"; solana balance "$KS_PUBLIC_DEVNET_WALLET_ADDRESS" --url "$KS_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KS_DEVNET_VALIDATION_DIR/${KS_DEVNET_SCENARIO}-wallet-before.txt"
``` ```
### C07 — Confirmer une signature et capturer le solde après scénario ### C07 — Confirmer une signature et capturer le solde après scénario
Définir `KB_DEVNET_SCENARIO` et `KB_DEVNET_SIGNATURE` avant lappel. Définir `KS_DEVNET_SCENARIO` et `KS_DEVNET_SIGNATURE` avant lappel.
```bash ```bash
test -n "${KB_DEVNET_SCENARIO:-}" && test -n "${KB_DEVNET_SIGNATURE:-}" && test -n "${KB_DEVNET_WALLET_PUBKEY:-}" && test -n "${KB_DEVNET_RPC_URL:-}" && test -n "${KB_DEVNET_VALIDATION_DIR:-}" && { date --iso-8601=seconds; printf 'scenario=%s\nsignature=%s\n' "$KB_DEVNET_SCENARIO" "$KB_DEVNET_SIGNATURE"; solana confirm "$KB_DEVNET_SIGNATURE" --url "$KB_DEVNET_RPC_URL" --commitment finalized --verbose; solana balance "$KB_DEVNET_WALLET_PUBKEY" --url "$KB_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KB_DEVNET_VALIDATION_DIR/${KB_DEVNET_SCENARIO}-confirmation.txt" test -n "${KS_DEVNET_SCENARIO:-}" && test -n "${KS_DEVNET_SIGNATURE:-}" && test -n "${KS_PUBLIC_DEVNET_WALLET_ADDRESS:-}" && test -n "${KS_DEVNET_RPC_URL:-}" && test -n "${KS_DEVNET_VALIDATION_DIR:-}" && { date --iso-8601=seconds; printf 'scenario=%s\nsignature=%s\n' "$KS_DEVNET_SCENARIO" "$KS_DEVNET_SIGNATURE"; solana confirm "$KS_DEVNET_SIGNATURE" --url "$KS_DEVNET_RPC_URL" --commitment finalized --verbose; solana balance "$KS_PUBLIC_DEVNET_WALLET_ADDRESS" --url "$KS_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KS_DEVNET_VALIDATION_DIR/${KS_DEVNET_SCENARIO}-confirmation.txt"
``` ```
### C08 — Préparer un mint SPL Token classique pour ATA ### C08 — Préparer un mint SPL Token classique pour ATA
@@ -168,11 +168,11 @@ Loption `--silent` est obligatoire afin que la phrase de récupération ne so
La commande est idempotente au niveau du guide : si le compte du mint existe déjà sur Devnet, elle le réutilise. La commande est idempotente au niveau du guide : si le compte du mint existe déjà sur Devnet, elle le réutilise.
```bash ```bash
export KB_SPL_TOKEN_PROGRAM_ID="TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" && export KB_DEVNET_CLASSIC_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-classic-mint.json" && mkdir -p "$(dirname "$KB_DEVNET_CLASSIC_MINT_KEYPAIR")" && { test -f "$KB_DEVNET_CLASSIC_MINT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KB_DEVNET_CLASSIC_MINT_KEYPAIR"; } export KS_PUBLIC_SPL_TOKEN_PROGRAM_ID="TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" && export KS_DEVNET_CLASSIC_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-classic-mint.json" && mkdir -p "$(dirname "$KS_DEVNET_CLASSIC_MINT_KEYPAIR")" && { test -f "$KS_DEVNET_CLASSIC_MINT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KS_DEVNET_CLASSIC_MINT_KEYPAIR"; }
``` ```
```bash ```bash
export KB_DEVNET_CLASSIC_MINT="$(solana-keygen pubkey "$KB_DEVNET_CLASSIC_MINT_KEYPAIR")" && { solana account "$KB_DEVNET_CLASSIC_MINT" --url "$KB_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" create-token "$KB_DEVNET_CLASSIC_MINT_KEYPAIR" --decimals 9; } && printf 'classic_mint=%s\n' "$KB_DEVNET_CLASSIC_MINT" | tee "$KB_DEVNET_VALIDATION_DIR/30a-spl-ata-classic-mint.txt" export KS_DEVNET_CLASSIC_MINT="$(solana-keygen pubkey "$KS_DEVNET_CLASSIC_MINT_KEYPAIR")" && { solana account "$KS_DEVNET_CLASSIC_MINT" --url "$KS_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" create-token "$KS_DEVNET_CLASSIC_MINT_KEYPAIR" --decimals 9; } && printf 'classic_mint=%s\n' "$KS_DEVNET_CLASSIC_MINT" | tee "$KS_DEVNET_VALIDATION_DIR/30a-spl-ata-classic-mint.txt"
``` ```
### C09 — Préparer un mint Token-2022 pour ATA ### C09 — Préparer un mint Token-2022 pour ATA
@@ -180,11 +180,11 @@ export KB_DEVNET_CLASSIC_MINT="$(solana-keygen pubkey "$KB_DEVNET_CLASSIC_MINT_K
Cette commande crée uniquement un mint Token-2022 de test persistant, sans extension supplémentaire. Elle ne crée aucun ATA. Cette commande crée uniquement un mint Token-2022 de test persistant, sans extension supplémentaire. Elle ne crée aucun ATA.
```bash ```bash
export KB_SPL_TOKEN_2022_PROGRAM_ID="TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" && export KB_DEVNET_TOKEN_2022_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-token-2022-mint.json" && mkdir -p "$(dirname "$KB_DEVNET_TOKEN_2022_MINT_KEYPAIR")" && { test -f "$KB_DEVNET_TOKEN_2022_MINT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KB_DEVNET_TOKEN_2022_MINT_KEYPAIR"; } export KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID="TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" && export KS_DEVNET_TOKEN_2022_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-token-2022-mint.json" && mkdir -p "$(dirname "$KS_DEVNET_TOKEN_2022_MINT_KEYPAIR")" && { test -f "$KS_DEVNET_TOKEN_2022_MINT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KS_DEVNET_TOKEN_2022_MINT_KEYPAIR"; }
``` ```
```bash ```bash
export KB_DEVNET_TOKEN_2022_MINT="$(solana-keygen pubkey "$KB_DEVNET_TOKEN_2022_MINT_KEYPAIR")" && { solana account "$KB_DEVNET_TOKEN_2022_MINT" --url "$KB_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_2022_PROGRAM_ID" create-token "$KB_DEVNET_TOKEN_2022_MINT_KEYPAIR" --decimals 9; } && printf 'token_2022_mint=%s\n' "$KB_DEVNET_TOKEN_2022_MINT" | tee "$KB_DEVNET_VALIDATION_DIR/30b-spl-ata-token-2022-mint.txt" export KS_PUBLIC_DEVNET_TOKEN_2022_MINT="$(solana-keygen pubkey "$KS_DEVNET_TOKEN_2022_MINT_KEYPAIR")" && { solana account "$KS_PUBLIC_DEVNET_TOKEN_2022_MINT" --url "$KS_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID" create-token "$KS_DEVNET_TOKEN_2022_MINT_KEYPAIR" --decimals 9; } && printf 'token_2022_mint=%s\n' "$KS_PUBLIC_DEVNET_TOKEN_2022_MINT" | tee "$KS_DEVNET_VALIDATION_DIR/30b-spl-ata-token-2022-mint.txt"
``` ```
### C10 — Préparer les comptes du scénario SPL Token classique ### C10 — Préparer les comptes du scénario SPL Token classique
@@ -201,37 +201,37 @@ Cette préparation réutilise le mint créé par `C08` et lATA classique cré
1. Dériver lATA source avec la syntaxe exigée par `spl-token-cli 5.5.0` : 1. Dériver lATA source avec la syntaxe exigée par `spl-token-cli 5.5.0` :
```bash ```bash
export KB_DEVNET_CLASSIC_SOURCE_ATA="$(spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" address --verbose --token "$KB_DEVNET_CLASSIC_MINT" --owner "$KB_DEVNET_WALLET_PUBKEY" | awk -F': ' '/Associated token address/ {print $2}')" && test -n "$KB_DEVNET_CLASSIC_SOURCE_ATA" && printf 'source_ata=%s\n' "$KB_DEVNET_CLASSIC_SOURCE_ATA" export KS_DEVNET_CLASSIC_SOURCE_ATA="$(spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" address --verbose --token "$KS_DEVNET_CLASSIC_MINT" --owner "$KS_PUBLIC_DEVNET_WALLET_ADDRESS" | awk -F': ' '/Associated token address/ {print $2}')" && test -n "$KS_DEVNET_CLASSIC_SOURCE_ATA" && printf 'source_ata=%s\n' "$KS_DEVNET_CLASSIC_SOURCE_ATA"
``` ```
2. Préparer un owner destinataire persistant : 2. Préparer un owner destinataire persistant :
```bash ```bash
export KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR="$PWD/wallets/temporary/local_devnet/recipients/spl-token-transfer-recipient.json" && mkdir -p "$(dirname "$KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR")" && { test -f "$KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR"; } && export KB_DEVNET_CLASSIC_RECIPIENT="$(solana-keygen pubkey "$KB_DEVNET_CLASSIC_RECIPIENT_KEYPAIR")" export KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR="$PWD/wallets/temporary/local_devnet/recipients/spl-token-transfer-recipient.json" && mkdir -p "$(dirname "$KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR")" && { test -f "$KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR"; } && export KS_DEVNET_CLASSIC_RECIPIENT="$(solana-keygen pubkey "$KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR")"
``` ```
3. Dériver puis créer lATA destination si elle nexiste pas : 3. Dériver puis créer lATA destination si elle nexiste pas :
```bash ```bash
export KB_DEVNET_CLASSIC_DESTINATION_ATA="$(spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" address --verbose --token "$KB_DEVNET_CLASSIC_MINT" --owner "$KB_DEVNET_CLASSIC_RECIPIENT" | awk -F': ' '/Associated token address/ {print $2}')" && test -n "$KB_DEVNET_CLASSIC_DESTINATION_ATA" && { solana account "$KB_DEVNET_CLASSIC_DESTINATION_ATA" --url "$KB_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" create-account "$KB_DEVNET_CLASSIC_MINT" --owner "$KB_DEVNET_CLASSIC_RECIPIENT" --fee-payer "$KB_DEVNET_WALLET"; } export KS_DEVNET_CLASSIC_DESTINATION_ATA="$(spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" address --verbose --token "$KS_DEVNET_CLASSIC_MINT" --owner "$KS_DEVNET_CLASSIC_RECIPIENT" | awk -F': ' '/Associated token address/ {print $2}')" && test -n "$KS_DEVNET_CLASSIC_DESTINATION_ATA" && { solana account "$KS_DEVNET_CLASSIC_DESTINATION_ATA" --url "$KS_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" create-account "$KS_DEVNET_CLASSIC_MINT" --owner "$KS_DEVNET_CLASSIC_RECIPIENT" --fee-payer "$KS_DEVNET_WALLET"; }
``` ```
4. Créditer le compte source. Cette commande ajoute `10` tokens à chaque exécution ; ne la relancer que si le solde source est insuffisant : 4. Créditer le compte source. Cette commande ajoute `10` tokens à chaque exécution ; ne la relancer que si le solde source est insuffisant :
```bash ```bash
spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" mint "$KB_DEVNET_CLASSIC_MINT" 10 "$KB_DEVNET_CLASSIC_SOURCE_ATA" --owner "$KB_DEVNET_WALLET" --fee-payer "$KB_DEVNET_WALLET" spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" mint "$KS_DEVNET_CLASSIC_MINT" 10 "$KS_DEVNET_CLASSIC_SOURCE_ATA" --owner "$KS_DEVNET_WALLET" --fee-payer "$KS_DEVNET_WALLET"
``` ```
5. Afficher les comptes par leur adresse. Avec cette version du CLI, utiliser `display` plutôt que `account-info <adresse>`, car largument positionnel de `account-info` est interprété comme un mint : 5. Afficher les comptes par leur adresse. Avec cette version du CLI, utiliser `display` plutôt que `account-info <adresse>`, car largument positionnel de `account-info` est interprété comme un mint :
```bash ```bash
spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_DESTINATION_ATA" spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_DESTINATION_ATA"
``` ```
6. Capturer la fixture : 6. Capturer la fixture :
```bash ```bash
{ printf 'mint=%s\n' "$KB_DEVNET_CLASSIC_MINT"; printf 'source=%s\n' "$KB_DEVNET_CLASSIC_SOURCE_ATA"; printf 'destination=%s\n' "$KB_DEVNET_CLASSIC_DESTINATION_ATA"; printf 'authority=%s\n' "$KB_DEVNET_WALLET_PUBKEY"; printf 'amount_raw=1000000000\n'; printf 'decimals=9\n'; } | tee "$KB_DEVNET_VALIDATION_DIR/40-spl-token-fixture.txt" { printf 'mint=%s\n' "$KS_DEVNET_CLASSIC_MINT"; printf 'source=%s\n' "$KS_DEVNET_CLASSIC_SOURCE_ATA"; printf 'destination=%s\n' "$KS_DEVNET_CLASSIC_DESTINATION_ATA"; printf 'authority=%s\n' "$KS_PUBLIC_DEVNET_WALLET_ADDRESS"; printf 'amount_raw=1000000000\n'; printf 'decimals=9\n'; } | tee "$KS_DEVNET_VALIDATION_DIR/40-spl-token-fixture.txt"
``` ```
La création du compte destination par CLI est acceptable ici : `S03A` et `S03B` ont déjà validé lexecutor ATA. `S04` doit isoler et valider lexecutor SPL Token `TransferChecked`. La création du compte destination par CLI est acceptable ici : `S03A` et `S03B` ont déjà validé lexecutor ATA. `S04` doit isoler et valider lexecutor SPL Token `TransferChecked`.
@@ -241,10 +241,10 @@ La création du compte destination par CLI est acceptable ici : `S03A` et `S03B`
Le workspace fournit une commande idempotente qui prépare les comptes publics requis par les huit scénarios Token-2022 : Le workspace fournit une commande idempotente qui prépare les comptes publics requis par les huit scénarios Token-2022 :
```bash ```bash
cargo run -p ks-pipeline-demo-scenarios --bin ks-pipeline-demo-scenarios-cli -- prepare-token-2022-fixture --rpc-url "$KB_DEVNET_RPC_URL" --wallet "$KB_DEVNET_WALLET" --wallet-dir "$PWD/wallets/temporary/local_devnet" --decimals 9 | tee "$KB_DEVNET_VALIDATION_DIR/50-spl-token-2022-fixture-preparation.json" cargo run -p ks-pipeline-demo-scenarios --bin ks-pipeline-demo-scenarios-cli -- prepare-token-2022-fixture --rpc-url "$KS_DEVNET_RPC_URL" --wallet "$KS_DEVNET_WALLET" --wallet-dir "$PWD/wallets/temporary/local_devnet" --decimals 9 | tee "$KS_DEVNET_VALIDATION_DIR/50-spl-token-2022-fixture-preparation.json"
``` ```
Lorsque `--rpc-url` et `--wallet` sont omis, la commande utilise respectivement `KB_DEVNET_RPC_URL` et `KB_DEVNET_WALLET`. Lorsque `--wallet-dir` est omis, elle utilise le répertoire parent du wallet. Lorsque `--rpc-url` et `--wallet` sont omis, la commande utilise respectivement `KS_DEVNET_RPC_URL` et `KS_DEVNET_WALLET`. Lorsque `--wallet-dir` est omis, elle utilise le répertoire parent du wallet.
La commande : La commande :
@@ -270,35 +270,35 @@ wallets/temporary/local_devnet/spl_token_2022_validation/fixture.env
Elle définit : Elle définit :
```text ```text
TOKEN_2022_PROGRAM KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID
TOKEN_2022_MINT KS_PUBLIC_DEVNET_TOKEN_2022_MINT
TOKEN_2022_SOURCE KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE
TOKEN_2022_DESTINATION KS_PUBLIC_DEVNET_TOKEN_2022_DESTINATION
TOKEN_2022_CLOSE_ACCOUNT KS_PUBLIC_DEVNET_TOKEN_2022_CLOSE_ACCOUNT
TOKEN_2022_DELEGATE KS_PUBLIC_DEVNET_TOKEN_2022_DELEGATE
TOKEN_2022_AUTHORITY KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY
TOKEN_2022_FREEZE_AUTHORITY KS_PUBLIC_DEVNET_TOKEN_2022_FREEZE_AUTHORITY
TOKEN_2022_DECIMALS KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS
TOKEN_2022_MINT_AMOUNT_RAW KS_PUBLIC_DEVNET_TOKEN_2022_MINT_AMOUNT_RAW
TOKEN_2022_TRANSFER_AMOUNT_RAW KS_PUBLIC_DEVNET_TOKEN_2022_TRANSFER_AMOUNT_RAW
TOKEN_2022_APPROVE_AMOUNT_RAW KS_PUBLIC_DEVNET_TOKEN_2022_APPROVE_AMOUNT_RAW
TOKEN_2022_BURN_AMOUNT_RAW KS_PUBLIC_DEVNET_TOKEN_2022_BURN_AMOUNT_RAW
KB_DEVNET_WALLET_ADDRESS KS_PUBLIC_DEVNET_WALLET_ADDRESS
``` ```
Vérifier puis charger uniquement les valeurs publiques dans le terminal B : Vérifier puis charger uniquement les valeurs publiques dans le terminal B :
```bash ```bash
export KB_DEVNET_TOKEN_2022_FIXTURE="$PWD/wallets/temporary/local_devnet/spl_token_2022_validation/fixture.env" && test -f "$KB_DEVNET_TOKEN_2022_FIXTURE" && sed -n '/^export [A-Z0-9_]*=/p' "$KB_DEVNET_TOKEN_2022_FIXTURE" | sed 's/=.*$/=<défini>/' | tee "$KB_DEVNET_VALIDATION_DIR/50-spl-token-2022-fixture-keys.txt" && source "$KB_DEVNET_TOKEN_2022_FIXTURE" export KS_DEVNET_TOKEN_2022_FIXTURE="$PWD/wallets/temporary/local_devnet/spl_token_2022_validation/fixture.env" && test -f "$KS_DEVNET_TOKEN_2022_FIXTURE" && sed -n '/^export [A-Z0-9_]*=/p' "$KS_DEVNET_TOKEN_2022_FIXTURE" | sed 's/=.*$/=<défini>/' | tee "$KS_DEVNET_VALIDATION_DIR/50-spl-token-2022-fixture-keys.txt" && source "$KS_DEVNET_TOKEN_2022_FIXTURE"
``` ```
Afficher le mint et les trois comptes Token-2022 avec le Program ID explicite : Afficher le mint et les trois comptes Token-2022 avec le Program ID explicite :
```bash ```bash
spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$TOKEN_2022_PROGRAM" display "$TOKEN_2022_MINT" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$TOKEN_2022_PROGRAM" display "$TOKEN_2022_SOURCE" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$TOKEN_2022_PROGRAM" display "$TOKEN_2022_DESTINATION" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$TOKEN_2022_PROGRAM" display "$TOKEN_2022_CLOSE_ACCOUNT" spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID" display "$KS_PUBLIC_DEVNET_TOKEN_2022_MINT" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID" display "$KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID" display "$KS_PUBLIC_DEVNET_TOKEN_2022_DESTINATION" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID" display "$KS_PUBLIC_DEVNET_TOKEN_2022_CLOSE_ACCOUNT"
``` ```
Le compte `TOKEN_2022_CLOSE_ACCOUNT` doit rester vide jusqu'au scénario `CloseAccount`. Ne pas utiliser `account-info <adresse>` dans cette campagne : avec `spl-token-cli 5.5.0`, cette forme peut interpréter l'adresse comme un mint. Le compte `KS_PUBLIC_DEVNET_TOKEN_2022_CLOSE_ACCOUNT` doit rester vide jusqu'au scénario `CloseAccount`. Ne pas utiliser `account-info <adresse>` dans cette campagne : avec `spl-token-cli 5.5.0`, cette forme peut interpréter l'adresse comme un mint.
### C12 — Preuves applicatives communes ### C12 — Preuves applicatives communes
@@ -331,7 +331,7 @@ Un scénario nest validé que si le replay ne produit ni échec fonctionnel n
6. Dans le terminal B, exécuter le contrôle de tables de `C05`. 6. Dans le terminal B, exécuter le contrôle de tables de `C05`.
7. Financer la pubkey par un faucet Web Devnet si le solde est insuffisant. 7. Financer la pubkey par un faucet Web Devnet si le solde est insuffisant.
8. Réexécuter `C04` dans le terminal B après financement. 8. Réexécuter `C04` dans le terminal B après financement.
9. Avant chaque scénario, définir `KB_DEVNET_SCENARIO` dans le terminal B, puis exécuter `C06`. 9. Avant chaque scénario, définir `KS_DEVNET_SCENARIO` dans le terminal B, puis exécuter `C06`.
## 6. Scénario S01 — Solana Core System Transfer ## 6. Scénario S01 — Solana Core System Transfer
@@ -344,7 +344,7 @@ Valider la chaîne complète : préparation, simulation, envoi, confirmation, st
1. Définir puis exécuter `C06` : 1. Définir puis exécuter `C06` :
```bash ```bash
export KB_DEVNET_SCENARIO="10-system-transfer" export KS_DEVNET_SCENARIO="10-system-transfer"
``` ```
2. Dans la fenêtre **Exécution Devnet — Solana Core** : 2. Dans la fenêtre **Exécution Devnet — Solana Core** :
@@ -359,13 +359,13 @@ export KB_DEVNET_SCENARIO="10-system-transfer"
4. Capturer séparément le solde du destinataire : 4. Capturer séparément le solde du destinataire :
```bash ```bash
export KB_DEVNET_RECIPIENT="COLLER_LE_DESTINATAIRE" export KS_DEVNET_RECIPIENT="COLLER_LE_DESTINATAIRE"
solana balance \ solana balance \
"$KB_DEVNET_RECIPIENT" \ "$KS_DEVNET_RECIPIENT" \
--url "$KB_DEVNET_RPC_URL" \ --url "$KS_DEVNET_RPC_URL" \
--commitment confirmed \ --commitment confirmed \
| tee "$KB_DEVNET_VALIDATION_DIR/${KB_DEVNET_SCENARIO}-recipient-after.txt" | tee "$KS_DEVNET_VALIDATION_DIR/${KS_DEVNET_SCENARIO}-recipient-after.txt"
``` ```
5. Exécuter les contrôles applicatifs `C08` sur la signature. 5. Exécuter les contrôles applicatifs `C08` sur la signature.
@@ -398,7 +398,7 @@ Valider lopération exécutable `spl.memo.add_memo`, lévénement observé
1. Définir puis exécuter `C06` : 1. Définir puis exécuter `C06` :
```bash ```bash
export KB_DEVNET_SCENARIO="20-spl-memo-v4" export KS_DEVNET_SCENARIO="20-spl-memo-v4"
``` ```
2. Dans la fenêtre **Exécution Devnet — SPL** : 2. Dans la fenêtre **Exécution Devnet — SPL** :
@@ -407,7 +407,7 @@ export KB_DEVNET_SCENARIO="20-spl-memo-v4"
- vérifier le Program ID `Memo4c2pN8afCj432Lb7RMVKi9PbQnnW7ewFFaV3oAH` ; - vérifier le Program ID `Memo4c2pN8afCj432Lb7RMVKi9PbQnnW7ewFFaV3oAH` ;
- vérifier le wallet signer ; - vérifier le wallet signer ;
- simuler puis confirmer lenvoi. - simuler puis confirmer lenvoi.
3. Définir `KB_DEVNET_SIGNATURE` et exécuter `C07`. 3. Définir `KS_DEVNET_SIGNATURE` et exécuter `C07`.
4. Exécuter `C08` et vérifier précisément : 4. Exécuter `C08` et vérifier précisément :
- `processor_name = materializer.transaction.annotations` ; - `processor_name = materializer.transaction.annotations` ;
- `surface_code = spl.memo.v4` ; - `surface_code = spl.memo.v4` ;
@@ -441,22 +441,22 @@ Valider la dérivation et la création idempotente dune ATA dont le mint appa
2. Définir le scénario et capturer le solde : 2. Définir le scénario et capturer le solde :
```bash ```bash
export KB_DEVNET_SCENARIO="30a-spl-ata-classic" export KS_DEVNET_SCENARIO="30a-spl-ata-classic"
``` ```
3. Exécuter `C06`. 3. Exécuter `C06`.
4. Copier la valeur affichée par : 4. Copier la valeur affichée par :
```bash ```bash
printf '%s\n' "$KB_DEVNET_CLASSIC_MINT" printf '%s\n' "$KS_DEVNET_CLASSIC_MINT"
``` ```
#### Procédure dans lapplication #### Procédure dans lapplication
1. Ouvrir la fenêtre **SPL Associated Token Account**. 1. Ouvrir la fenêtre **SPL Associated Token Account**.
2. Utiliser : 2. Utiliser :
- owner : wallet opérateur `KB_DEVNET_WALLET_PUBKEY` ; - owner : wallet opérateur `KS_PUBLIC_DEVNET_WALLET_ADDRESS` ;
- mint : `KB_DEVNET_CLASSIC_MINT` ; - mint : `KS_DEVNET_CLASSIC_MINT` ;
- token program : SPL Token classique ; - token program : SPL Token classique ;
- payer : wallet opérateur. - payer : wallet opérateur.
3. Dériver lATA et conserver son adresse. 3. Dériver lATA et conserver son adresse.
@@ -464,7 +464,7 @@ printf '%s\n' "$KB_DEVNET_CLASSIC_MINT"
5. Simuler `spl.associated_token_account.create_idempotent`. 5. Simuler `spl.associated_token_account.create_idempotent`.
6. Contrôler le rent ceiling, le payer, lowner, le mint, le token program et ladresse ATA dérivée. 6. Contrôler le rent ceiling, le payer, lowner, le mint, le token program et ladresse ATA dérivée.
7. Confirmer explicitement lenvoi. 7. Confirmer explicitement lenvoi.
8. Définir `KB_DEVNET_SIGNATURE`, puis exécuter `C07`. 8. Définir `KS_DEVNET_SIGNATURE`, puis exécuter `C07`.
9. Exécuter `C12`. 9. Exécuter `C12`.
10. Réexécuter la création idempotente et vérifier quelle ne produit ni fausse création ni duplication des projections. 10. Réexécuter la création idempotente et vérifier quelle ne produit ni fausse création ni duplication des projections.
@@ -480,28 +480,28 @@ Valider la dérivation et la création idempotente dune ATA dont le mint appa
2. Définir le scénario et capturer le solde : 2. Définir le scénario et capturer le solde :
```bash ```bash
export KB_DEVNET_SCENARIO="30b-spl-ata-token-2022" export KS_DEVNET_SCENARIO="30b-spl-ata-token-2022"
``` ```
3. Exécuter `C06`. 3. Exécuter `C06`.
4. Copier la valeur affichée par : 4. Copier la valeur affichée par :
```bash ```bash
printf '%s\n' "$KB_DEVNET_TOKEN_2022_MINT" printf '%s\n' "$KS_PUBLIC_DEVNET_TOKEN_2022_MINT"
``` ```
#### Procédure dans lapplication #### Procédure dans lapplication
1. Utiliser : 1. Utiliser :
- owner : le même wallet opérateur ; - owner : le même wallet opérateur ;
- mint : `KB_DEVNET_TOKEN_2022_MINT` ; - mint : `KS_PUBLIC_DEVNET_TOKEN_2022_MINT` ;
- token program : Token-2022 ; - token program : Token-2022 ;
- payer : wallet opérateur. - payer : wallet opérateur.
2. Dériver lATA et conserver son adresse. 2. Dériver lATA et conserver son adresse.
3. Vérifier que le Program ID sélectionné est `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`. 3. Vérifier que le Program ID sélectionné est `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`.
4. Vérifier que ladresse dérivée diffère de lATA classique de S03A. 4. Vérifier que ladresse dérivée diffère de lATA classique de S03A.
5. Simuler puis envoyer `spl.associated_token_account.create_idempotent`. 5. Simuler puis envoyer `spl.associated_token_account.create_idempotent`.
6. Définir `KB_DEVNET_SIGNATURE`, puis exécuter `C07`. 6. Définir `KS_DEVNET_SIGNATURE`, puis exécuter `C07`.
7. Exécuter `C12`. 7. Exécuter `C12`.
8. Rejouer la création idempotente. 8. Rejouer la création idempotente.
9. Vérifier séparément les faits parent ATA et les éventuels enfants CPI Token-2022, sans duplication. 9. Vérifier séparément les faits parent ATA et les éventuels enfants CPI Token-2022, sans duplication.
@@ -533,13 +533,13 @@ Elle ne permet pas encore denchaîner depuis linterface `InitializeMint`,
1. Réutiliser le mint classique de `C08` : 1. Réutiliser le mint classique de `C08` :
```bash ```bash
export KB_SPL_TOKEN_PROGRAM_ID="TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" && export KB_DEVNET_CLASSIC_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-classic-mint.json" && export KB_DEVNET_CLASSIC_MINT="$(solana-keygen pubkey "$KB_DEVNET_CLASSIC_MINT_KEYPAIR")" export KS_PUBLIC_SPL_TOKEN_PROGRAM_ID="TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" && export KS_DEVNET_CLASSIC_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-classic-mint.json" && export KS_DEVNET_CLASSIC_MINT="$(solana-keygen pubkey "$KS_DEVNET_CLASSIC_MINT_KEYPAIR")"
``` ```
2. Définir le scénario : 2. Définir le scénario :
```bash ```bash
export KB_DEVNET_SCENARIO="40-spl-token" export KS_DEVNET_SCENARIO="40-spl-token"
``` ```
3. Exécuter `C06`. 3. Exécuter `C06`.
@@ -547,7 +547,7 @@ export KB_DEVNET_SCENARIO="40-spl-token"
5. Vérifier les comptes token avant lopération : 5. Vérifier les comptes token avant lopération :
```bash ```bash
spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_DESTINATION_ATA" spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_DESTINATION_ATA"
``` ```
### Valeurs à saisir dans lapplication ### Valeurs à saisir dans lapplication
@@ -556,17 +556,17 @@ Dans **Décodeur spl_token — TransferChecked** :
| Champ | Valeur | | Champ | Valeur |
|--------------------|--------------------------------------------| |--------------------|--------------------------------------------|
| Compte source | `$KB_DEVNET_CLASSIC_SOURCE_ATA` | | Compte source | `$KS_DEVNET_CLASSIC_SOURCE_ATA` |
| Mint | `$KB_DEVNET_CLASSIC_MINT` | | Mint | `$KS_DEVNET_CLASSIC_MINT` |
| Compte destination | `$KB_DEVNET_CLASSIC_DESTINATION_ATA` | | Compte destination | `$KS_DEVNET_CLASSIC_DESTINATION_ATA` |
| Autorité simple | `$KB_DEVNET_WALLET_PUBKEY` | | Autorité simple | `$KS_PUBLIC_DEVNET_WALLET_ADDRESS` |
| Montant brut exact | `1000000000` pour 1 token avec 9 décimales | | Montant brut exact | `1000000000` pour 1 token avec 9 décimales |
| Decimals | `9` | | Decimals | `9` |
Afficher les valeurs à copier : Afficher les valeurs à copier :
```bash ```bash
printf 'source=%s\nmint=%s\ndestination=%s\nauthority=%s\namount_raw=1000000000\ndecimals=9\n' "$KB_DEVNET_CLASSIC_SOURCE_ATA" "$KB_DEVNET_CLASSIC_MINT" "$KB_DEVNET_CLASSIC_DESTINATION_ATA" "$KB_DEVNET_WALLET_PUBKEY" printf 'source=%s\nmint=%s\ndestination=%s\nauthority=%s\namount_raw=1000000000\ndecimals=9\n' "$KS_DEVNET_CLASSIC_SOURCE_ATA" "$KS_DEVNET_CLASSIC_MINT" "$KS_DEVNET_CLASSIC_DESTINATION_ATA" "$KS_PUBLIC_DEVNET_WALLET_ADDRESS"
``` ```
### Exécution ### Exécution
@@ -584,14 +584,14 @@ printf 'source=%s\nmint=%s\ndestination=%s\nauthority=%s\namount_raw=1000000000\
5. Copier la signature dans : 5. Copier la signature dans :
```bash ```bash
export KB_DEVNET_SIGNATURE="SIGNATURE_SPL_TOKEN" export KS_DEVNET_SIGNATURE="SIGNATURE_SPL_TOKEN"
``` ```
6. Exécuter `C07`, puis `C12`. 6. Exécuter `C07`, puis `C12`.
7. Vérifier les comptes après transfert : 7. Vérifier les comptes après transfert :
```bash ```bash
spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KB_DEVNET_RPC_URL" --program-id "$KB_SPL_TOKEN_PROGRAM_ID" display "$KB_DEVNET_CLASSIC_DESTINATION_ATA" spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_DESTINATION_ATA"
``` ```
### Critères de validation ### Critères de validation
@@ -614,7 +614,7 @@ Le journal métier SPL Token peut rester à `empty` après une simulation seule.
1. Définir le scénario et exécuter `C06` : 1. Définir le scénario et exécuter `C06` :
```bash ```bash
export KB_DEVNET_SCENARIO="50-spl-token-2022" export KS_DEVNET_SCENARIO="50-spl-token-2022"
``` ```
2. Exécuter `C11` pour créer ou réutiliser la fixture. 2. Exécuter `C11` pour créer ou réutiliser la fixture.
@@ -647,7 +647,7 @@ Champs utilisés :
- source/cible : compte token à créditer ; - source/cible : compte token à créditer ;
- mint : mint Token-2022 ; - mint : mint Token-2022 ;
- autorité : mint authority ; - autorité : mint authority ;
- montant brut : `TOKEN_2022_MINT_AMOUNT_RAW` chargé depuis la fixture ; - montant brut : `KS_PUBLIC_DEVNET_TOKEN_2022_MINT_AMOUNT_RAW` chargé depuis la fixture ;
- décimales : valeur de la fixture. - décimales : valeur de la fixture.
Avec la fixture par défaut, le mint initial est `10000000000` unités brutes, soit 10 tokens avec 9 décimales. Cette quantité couvre ensuite le transfert, l'approbation et le burn prévus. Avec la fixture par défaut, le mint initial est `10000000000` unités brutes, soit 10 tokens avec 9 décimales. Cette quantité couvre ensuite le transfert, l'approbation et le burn prévus.
@@ -732,13 +732,13 @@ Le compte doit être vide et satisfaire toutes les préconditions de fermeture.
4. contrôler le plan, les owners, les autorités, le montant et les extensions ; 4. contrôler le plan, les owners, les autorités, le montant et les extensions ;
5. cocher la confirmation opérateur ; 5. cocher la confirmation opérateur ;
6. envoyer ; 6. envoyer ;
7. définir immédiatement `KB_DEVNET_SIGNATURE` avec la signature affichée pour cette sous-opération ; 7. définir immédiatement `KS_DEVNET_SIGNATURE` avec la signature affichée pour cette sous-opération ;
8. vérifier qu'elle diffère de la signature du scénario précédent, puis exécuter `C07` ; 8. vérifier qu'elle diffère de la signature du scénario précédent, puis exécuter `C07` ;
9. appliquer `C12` ; 9. appliquer `C12` ;
10. conserver un fichier de preuve distinct en modifiant temporairement le préfixe, par exemple : 10. conserver un fichier de preuve distinct en modifiant temporairement le préfixe, par exemple :
```bash ```bash
export KB_DEVNET_SCENARIO="50a-token-2022-mint-to-checked" export KS_DEVNET_SCENARIO="50a-token-2022-mint-to-checked"
``` ```
puis `50b`, `50c`, etc., avant chaque appel à `C07`. puis `50b`, `50c`, etc., avant chaque appel à `C07`.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/CRATE_MAP.md --> <!-- file: docs/architecture/CRATE_MAP.md -->
<!-- version: 4 --> <!-- version: 5 -->
# Carte des crates # Carte des crates
@@ -13,13 +13,13 @@
| `ks-logging` | bibliothèque | initialisation du logging et du tracing | README/TODO/USAGE/CHANGELOG présents | | `ks-logging` | bibliothèque | initialisation du logging et du tracing | README/TODO/USAGE/CHANGELOG présents |
| `ks-program-ids` | bibliothèque | registre des programmes et comptes Solana connus | README/TODO/USAGE/CHANGELOG présents | | `ks-program-ids` | bibliothèque | registre des programmes et comptes Solana connus | README/TODO/USAGE/CHANGELOG présents |
| `ks-pipeline` | bibliothèque | backfill, extraction, replay, stateful, préflight et orchestration | README/TODO/USAGE/CHANGELOG présents | | `ks-pipeline` | bibliothèque | backfill, extraction, replay, stateful, préflight et orchestration | README/TODO/USAGE/CHANGELOG présents |
| `ks-pipeline-demo-scenarios` | bibliothèque + binaire | scénarios Devnet réutilisables et CLI | renommage `0.5.1`, audit `0.5.4` | | `ks-pipeline-demo-scenarios` | bibliothèque + binaire | scénarios Devnet réutilisables et CLI | nom `ks-*` actif ; audit `0.5.4` |
| `ks-onchain-transport` | bibliothèque | transports RPC HTTP/WebSocket et pools dendpoints | README/TODO/USAGE/CHANGELOG présents | | `ks-onchain-transport` | bibliothèque | transports RPC HTTP/WebSocket et pools dendpoints | README/TODO/USAGE/CHANGELOG présents |
| `ks-store` | bibliothèque | contrats de stockage et adaptateur PostgreSQL | renommage `0.5.1`, normalisation `0.5.3` | | `ks-store` | bibliothèque | contrats de stockage et adaptateur PostgreSQL | nom `ks-*` actif ; normalisation `0.5.3` |
| `ks-wallet` | bibliothèque | wallet temporaire et frontière de signataire | renommage `0.5.1`, refonte `0.5.2` | | `ks-wallet` | bibliothèque | wallet temporaire et frontière de signataire | nom `ks-*` actif ; refonte `0.5.2` |
| `kb-app-demo-desktop` | bibliothèque + binaire | application de démonstration Tauri | documentée ; réconciliation en `0.5.4` | | `kb-app-demo-desktop` | bibliothèque + binaire | application de démonstration Tauri | documentée ; réconciliation en `0.5.4` |
La table décrit les noms physiques du workspace `0.5.0`. La migration `0.5.1` renomme les dix crates généralistes en `ks-core`, `ks-config`, `ks-lib`, `ks-logging`, `ks-program-ids`, `ks-pipeline`, `ks-pipeline-demo-scenarios`, `ks-onchain-transport`, `ks-store` et `ks-wallet`. `kb-app-demo-desktop` conserve son nom parce quil appartient au domaine applicatif Bot. Voir [`../decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md`](../decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md). La table décrit les noms physiques actifs depuis `0.5.1-pre.002`. La migration a renommé les dix crates généralistes en `ks-core`, `ks-config`, `ks-lib`, `ks-logging`, `ks-program-ids`, `ks-pipeline`, `ks-pipeline-demo-scenarios`, `ks-onchain-transport`, `ks-store` et `ks-wallet`. `kb-app-demo-desktop` conserve son nom parce quil appartient au domaine applicatif Bot. Voir [`../decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md`](../decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md).
## 2. Consolidations principales depuis bot2 ## 2. Consolidations principales depuis bot2

View File

@@ -1,5 +1,5 @@
<!-- file: docs/decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md --> <!-- file: docs/decisions/KHADHROONY_SOLANA_NAMESPACE_POLICY.md -->
<!-- version: 4 --> <!-- version: 5 -->
# Politique de namespace Khadhroony Solana # Politique de namespace Khadhroony Solana
@@ -7,7 +7,7 @@
Cette décision est adoptée pendant la clôture de `0.5.0` et devient la cible normative des migrations de fondation `0.5.1` à `0.5.3`. Cette décision est adoptée pendant la clôture de `0.5.0` et devient la cible normative des migrations de fondation `0.5.1` à `0.5.3`.
À partir de `0.5.1-pre.002`, les dix crates Solana généralistes sont physiquement nommées `ks-*` et leurs identifiants Rust `ks_*`. `0.5.1-pre.003` migre également les identités techniques `kb-lib.*` vers `ks-lib-*`. Les namespaces historiques `KB_*` et `kb_sol_*` restent temporairement présents jusqu'aux prereleases dédiées ; leur présence pendant cette migration bornée ne remet pas en cause la cible ci-dessous. À partir de `0.5.1-pre.002`, les dix crates Solana généralistes sont physiquement nommées `ks-*` et leurs identifiants Rust `ks_*`. `0.5.1-pre.003` migre également les identités techniques `kb-lib.*` vers `ks-lib-*`. `0.5.1-pre.004` migre les variables possédées par Khadhroony Solana vers `KS_*` et réserve explicitement `KB_*` aux composants réellement possédés par Khadhroony Bot. Le namespace SQL `kb_sol_*` reste temporairement présent jusqu'à `0.5.3`.
Le renommage des bibliothèques internes ne renomme pas le workspace, le dépôt ni le répertoire racine : ils restent `khadhroony-bot3` pendant toute la série pré-`1.0`. Un éventuel renommage du workspace racine est explicitement hors périmètre de `0.5.x` et ne doit intervenir qu'en `1.0` ou ultérieurement sur décision dédiée. Le renommage des bibliothèques internes ne renomme pas le workspace, le dépôt ni le répertoire racine : ils restent `khadhroony-bot3` pendant toute la série pré-`1.0`. Un éventuel renommage du workspace racine est explicitement hors périmètre de `0.5.x` et ne doit intervenir qu'en `1.0` ou ultérieurement sur décision dédiée.
@@ -44,17 +44,22 @@ La migration doit couvrir les manifests, chemins de workspace, imports, exports,
## 4. Variables d'environnement ## 4. Variables d'environnement
Toutes les variables d'environnement appartenant aux contrats Khadhroony Solana/Bot doivent utiliser le namespace `KS_` après la migration `0.5.1`. Le namespace d'une variable est déterminé par **la responsabilité qui possède le contrat**, et non par l'exécutable qui la lit.
Trois classes sont retenues : - les crates et contrats généralistes Khadhroony Solana utilisent `KS_*` ;
- `kb-app-demo-desktop` et les futures crates réellement spécifiques au Bot utilisent `KB_*` pour leurs propres contrats ;
- une variable d'un scénario Solana réutilisable reste donc `KS_*` même lorsqu'elle est consommée par `kb-app-demo-desktop` ;
- les variables standard du système, de Cargo, de Rust ou d'un outil externe ne sont pas renommées artificiellement tant qu'elles ne deviennent pas un contrat de configuration du workspace.
- `KS_SECRET_*` : secret absolu ; la valeur peut être utilisée côté backend mais ne doit jamais être loggée, sérialisée vers une surface publique, renvoyée par Tauri ni affichée en diagnostic, même en mode debug ; Chaque domaine possède les trois mêmes classes :
- `KS_PUBLIC_*` : valeur explicitement classée comme publiable ; le préfixe ne suffit pas à lui seul à autoriser une exposition, qui doit rester définie par un DTO ou une surface publique explicite ;
- `KS_*` hors sous-préfixes précédents : valeur interne ; elle n'est pas exposée en fonctionnement normal mais peut être incluse dans un diagnostic explicitement demandé si sa sémantique n'est pas sensible.
Une variable appartenant au workspace qui ne commence pas par `KS_` est non conforme après migration. Les variables standard du système ou de dépendances externes ne sont pas reclassées artificiellement comme variables de configuration Khadhroony. - `KS_SECRET_*` / `KB_SECRET_*` : secret absolu ; la valeur peut être utilisée côté backend mais ne doit jamais être loggée, sérialisée vers une surface publique, renvoyée par Tauri ni affichée en diagnostic, même en mode debug ;
- `KS_PUBLIC_*` / `KB_PUBLIC_*` : valeur explicitement classée comme publiable ; le préfixe ne suffit pas à lui seul à autoriser une exposition, qui doit rester définie par un DTO ou une surface publique explicite ;
- `KS_*` / `KB_*` hors sous-préfixes précédents : valeur interne ; elle n'est pas exposée en fonctionnement normal mais peut être incluse dans un diagnostic explicitement demandé si sa sémantique n'est pas sensible.
La classification d'une valeur sensible doit survivre à la substitution. Une chaîne composée contenant une valeur issue de `KS_SECRET_*` reste sensible dans son ensemble et ne doit pas redevenir une simple valeur publiable après résolution. Une variable appartenant à un contrat `ks-*` qui utilise `KB_*`, ou l'inverse pour un contrat réellement spécifique `kb-*`, est non conforme. `0.5.1-pre.004` ne laisse actuellement aucun contrat d'environnement propre au desktop : les variables qu'il consomme appartiennent toutes aux composants ou scénarios Solana et utilisent donc `KS_*`.
La classification d'une valeur sensible doit survivre à la substitution. Une chaîne composée contenant une valeur issue de `KS_SECRET_*` ou `KB_SECRET_*` reste sensible dans son ensemble et ne doit pas redevenir une simple valeur publiable après résolution. Cette propagation et le camouflage effectif sont implémentés après le split config/logging, pas dans la prerelease de renommage.
## 5. Configuration source, runtime et publique ## 5. Configuration source, runtime et publique
@@ -67,7 +72,7 @@ D'autres documents spécialisés ne sont créés que si l'audit démontre une re
La conception doit distinguer : La conception doit distinguer :
1. la représentation source, qui peut contenir des références `${KS_*}` ; 1. la représentation source, qui peut contenir des références `${KS_*}` ou `${KB_*}` selon le propriétaire du contrat ;
2. la représentation runtime résolue, qui peut porter des secrets ; 2. la représentation runtime résolue, qui peut porter des secrets ;
3. la représentation publique/diagnostique, construite explicitement et incapable d'exposer une valeur secrète résolue. 3. la représentation publique/diagnostique, construite explicitement et incapable d'exposer une valeur secrète résolue.
@@ -111,7 +116,7 @@ La migration `kb_sol_*` → `k_sol_*` doit être traitée avec les contrats temp
## 8. Ordre des migrations ## 8. Ordre des migrations
- `0.5.1` : crates `ks-*`, identifiants Rust `ks_*`, variables `KS_*`, identités runtime/persistées Khadhroony Solana et restructuration sûre de la configuration/logging ; - `0.5.1` : crates `ks-*`, identifiants Rust `ks_*`, variables `KS_*` pour Solana avec `KB_*` réservé aux contrats Bot, identités runtime/persistées Khadhroony Solana et restructuration sûre de la configuration/logging ;
- `0.5.2` : restructuration de `ks-wallet` sur la nouvelle fondation de configuration ; - `0.5.2` : restructuration de `ks-wallet` sur la nouvelle fondation de configuration ;
- `0.5.3` : normalisation de `ks-store`, y compris migration du préfixe SQL vers `k_sol_*` et contrats temporels/provenance ; - `0.5.3` : normalisation de `ks-store`, y compris migration du préfixe SQL vers `k_sol_*` et contrats temporels/provenance ;
- `0.5.4` : centralisation finale des scénarios dans `ks-pipeline-demo-scenarios` et audit de complétude des exécuteurs/validations. - `0.5.4` : centralisation finale des scénarios dans `ks-pipeline-demo-scenarios` et audit de complétude des exécuteurs/validations.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/guides/CONFIGURATION.md --> <!-- file: docs/guides/CONFIGURATION.md -->
<!-- version: 3 --> <!-- version: 4 -->
# Guide de configuration # Guide de configuration
@@ -11,32 +11,28 @@ Ce guide décrit le chargement et lutilisation de la configuration bot3. La r
- `config/example.config.json` : exemple utilisateur complet ; - `config/example.config.json` : exemple utilisateur complet ;
- `config/schema.config.json` : contrat JSON formel ; - `config/schema.config.json` : contrat JSON formel ;
- `.env` et variantes locales : valeurs denvironnement non versionnées ; - `.env`, ou le fichier sélectionné par `KS_ENV_FILE` : valeurs denvironnement non versionnées ;
- `.env.example` : noms de variables attendues sans secrets. - `.env.example` : noms de variables attendues sans secrets.
Le format actif est JSON. Le futur split de configuration prévu en `0.5.x` ne modifie pas le contrat actuel. Le format actif est JSON. Le futur split de configuration prévu en `0.5.x` ne modifie pas le contrat actuel.
## Séquence de chargement ## Séquence de chargement
1. charger les fichiers denvironnement autorisés avec `load_workspace_environment` ; LAPI recommandée est `read_config_json_file_with_environment`. Elle :
2. lire le fichier JSON ;
3. résoudre les placeholders `${NAME}` ou `${NAME:-fallback}` ; 1. charge `.env`, ou le fichier explicitement sélectionné par `KS_ENV_FILE`, sans écraser les variables du processus ;
4. parser avec `load_config_from_str` ou `load_config_from_path` ; 2. lit le JSON ;
5. valider le schéma et les invariants typés ; 3. résout les placeholders namespacés `${KS_*}` / `${KB_*}` et les fallbacks éventuels ;
6. sélectionner le profil actif avec `active_profile`. 4. valide le schéma JSON ;
5. désérialise les types de configuration et applique les invariants métier ;
6. laisse ensuite `active_profile` sélectionner le profil actif.
## Exemple opérateur ## Exemple opérateur
```rust ```rust
let environment = match ks_config::load_workspace_environment( let config = match ks_config::read_config_json_file_with_environment(
std::path::Path::new("."),
) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let config = match ks_config::load_config_from_path(
std::path::Path::new("config/example.config.json"), std::path::Path::new("config/example.config.json"),
std::path::Path::new("."),
) { ) {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
@@ -47,7 +43,6 @@ let profile = match ks_config::active_profile(&config) {
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}; };
println!("loaded environment files={}", environment.loaded_files.len());
println!("active profile={}", profile.name); println!("active profile={}", profile.name);
``` ```
@@ -56,7 +51,7 @@ println!("active profile={}", profile.name);
- aucun secret ne doit être ajouté à lexemple versionné ; - aucun secret ne doit être ajouté à lexemple versionné ;
- les placeholders non résolus doivent provoquer un diagnostic explicite ; - les placeholders non résolus doivent provoquer un diagnostic explicite ;
- le schéma embarqué et `config/schema.config.json` doivent rester identiques ; - le schéma embarqué et `config/schema.config.json` doivent rester identiques ;
- une sérialisation publique doit être précédée dune validation ; - tant que `0.5.1-pre.006` na pas introduit les DTO publics sûrs, la configuration runtime résolue reste strictement backend et ne doit pas être exposée telle quelle ;
- les noms de profils et rôles dendpoints doivent rester cohérents avec leurs consommateurs. - les noms de profils et rôles dendpoints doivent rester cohérents avec leurs consommateurs.
## Quotas HTTP cumulés ## Quotas HTTP cumulés

View File

@@ -1,13 +1,13 @@
<!-- file: docs/plans/V0_5_1_KHADHROONY_SOLANA_NAMESPACE_AND_CONFIG_PLAN.md --> <!-- file: docs/plans/V0_5_1_KHADHROONY_SOLANA_NAMESPACE_AND_CONFIG_PLAN.md -->
<!-- version: 3 --> <!-- version: 4 -->
# Plan temporaire `0.5.1` — namespace Khadhroony Solana et configuration sûre # Plan temporaire `0.5.1` — namespace Khadhroony Solana et configuration sûre
## 1. Statut et règle de cette prerelease ## 1. Statut et règle de cette prerelease
Ce document est le plan temporaire de `0.5.1`. `0.5.1-pre.001` a fermé l'inventaire et les contrats de migration. `0.5.1-pre.002` a renommé physiquement les dix crates Solana généralistes vers `ks-*` / `ks_*`. `0.5.1-pre.003` migre maintenant les identités runtime et persistables hiérarchiques de `ks-lib`, leurs routes de logging, matrices, tests et garde-fous, sans toucher aux variables d'environnement ni au namespace SQL. `kb-app-demo-desktop` et le workspace racine restent nommés comme avant. Ce document est le plan temporaire de `0.5.1`. `0.5.1-pre.001` a fermé l'inventaire et les contrats de migration. `0.5.1-pre.002` a renommé physiquement les dix crates Solana généralistes vers `ks-*` / `ks_*`. `0.5.1-pre.003` a migré les identités runtime et persistables hiérarchiques de `ks-lib`. `0.5.1-pre.004` migre maintenant les contrats denvironnement vers les namespaces downership `KS_*` / `KB_*`, sans toucher au namespace SQL ni encore scinder les fichiers de configuration. `kb-app-demo-desktop` et le workspace racine restent nommés comme avant.
La base `0.5.0-pre.004` puis `0.5.1-pre.001` ont été validées par `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --all-targets`, `python3 scripts/audit_rust_workspace_rules.py` et `cargo test --workspace`. `pre.002` a ensuite été acceptée après validation opérateur du renommage physique. `pre.003` doit à nouveau rejouer ces contrôles, car les identités migrées alimentent les registres, matrices, diagnostics, routes de logging et contrats de replay. La base `0.5.0-pre.004` puis `0.5.1-pre.001` ont été validées par `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --all-targets`, `python3 scripts/audit_rust_workspace_rules.py` et `cargo test --workspace`. `pre.002` a ensuite été acceptée après validation opérateur du renommage physique. `pre.003` a été acceptée après validation opérateur. `pre.004` doit rejouer les contrôles de référence, car les noms denvironnement sont consommés par les tests optionnels, les scénarios, le store, la configuration et le desktop.
## 2. Invariant du workspace racine ## 2. Invariant du workspace racine
@@ -19,7 +19,7 @@ Pendant toute la série pré-`1.0`, sauf décision ultérieure explicite :
workspace / repository / root directory = khadhroony-bot3 workspace / repository / root directory = khadhroony-bot3
``` ```
Les bibliothèques internes Solana migrent vers `ks-*` / `ks_*` et leurs variables vers `KS_*`, mais elles restent membres du workspace `khadhroony-bot3`. Un éventuel renommage du workspace racine ne doit pas être entrepris avant `khadhroony-bot3` `1.0` ou une version ultérieure explicitement dédiée à cette opération. Les bibliothèques internes Solana utilisent `ks-*` / `ks_*` et leurs variables possédées utilisent `KS_*`; les futurs contrats réellement spécifiques au Bot utiliseront `KB_*`. Elles restent toutes membres du workspace `khadhroony-bot3`. Un éventuel renommage du workspace racine ne doit pas être entrepris avant `khadhroony-bot3` `1.0` ou une version ultérieure explicitement dédiée à cette opération.
## 3. Frontière des domaines ## 3. Frontière des domaines
@@ -33,7 +33,7 @@ Les bibliothèques internes Solana migrent vers `ks-*` / `ks_*` et leurs variabl
## 4. Inventaire des crates et ordre de migration ## 4. Inventaire des crates et ordre de migration
| Package actuel | Identifiant Rust actuel | Package cible | Identifiant Rust cible | Dépendances workspace directes actuelles | Ordre | | Package actuel | Identifiant Rust actuel | Package cible | Identifiant Rust cible | Dépendances workspace directes actuelles | Ordre |
|------------------------------|------------------------------|------------------------------|------------------------------|----------------------------------------------------------------------------------------------------|------:| |---|---|---|---|---|---:|
| `kb-core` | `kb_core` | `ks-core` | `ks_core` | — | 1 | | `kb-core` | `kb_core` | `ks-core` | `ks_core` | — | 1 |
| `kb-program-ids` | `kb_program_ids` | `ks-program-ids` | `ks_program_ids` | — | 2 | | `kb-program-ids` | `kb_program_ids` | `ks-program-ids` | `ks_program_ids` | — | 2 |
| `kb-config` | `kb_config` | `ks-config` | `ks_config` | kb-core | 3 | | `kb-config` | `kb_config` | `ks-config` | `ks_config` | kb-core | 3 |
@@ -59,7 +59,7 @@ bin : kb-pipeline-demo-scenarios-cli -> ks-pipeline-demo-scenarios-cli
Les valeurs suivantes sont des métriques d'orientation sur les fichiers actifs, hors archives et artefacts générés. Elles montrent qu'un renommage massif en une seule opération serait difficile à diagnostiquer. Les valeurs suivantes sont des métriques d'orientation sur les fichiers actifs, hors archives et artefacts générés. Elles montrent qu'un renommage massif en une seule opération serait difficile à diagnostiquer.
| Crate | Références package / fichiers | Références identifiant Rust / fichiers | | Crate | Références package / fichiers | Références identifiant Rust / fichiers |
|------------------------------|------------------------------:|---------------------------------------:| |---|---:|---:|
| `kb-core` | 51 / 32 | 3165 / 407 | | `kb-core` | 51 / 32 | 3165 / 407 |
| `kb-config` | 56 / 33 | 201 / 44 | | `kb-config` | 56 / 33 | 201 / 44 |
| `kb-lib` | 3145 / 550 | 2785 / 97 | | `kb-lib` | 3145 / 550 | 2785 / 97 |
@@ -146,7 +146,7 @@ Les targets de tracing de crates génériques doivent également migrer vers `ks
### 6.1 Inventaire exhaustif des identités `kb-lib.*` ### 6.1 Inventaire exhaustif des identités `kb-lib.*`
| Identité actuelle | Identité cible | | Identité actuelle | Identité cible |
|----------------------------------------------------------------|----------------------------------------------------------------| |---|---|
| `kb-lib.decoder.adapter.saber_decimal_wrapper` | `ks-lib-decoder.adapter.saber_decimal_wrapper` | | `kb-lib.decoder.adapter.saber_decimal_wrapper` | `ks-lib-decoder.adapter.saber_decimal_wrapper` |
| `kb-lib.decoder.adapter.spl_token_wrap` | `ks-lib-decoder.adapter.spl_token_wrap` | | `kb-lib.decoder.adapter.spl_token_wrap` | `ks-lib-decoder.adapter.spl_token_wrap` |
| `kb-lib.decoder.admin.jupiter_lock` | `ks-lib-decoder.admin.jupiter_lock` | | `kb-lib.decoder.admin.jupiter_lock` | `ks-lib-decoder.admin.jupiter_lock` |
@@ -408,9 +408,9 @@ Les targets de tracing de crates génériques doivent également migrer vers `ks
L'audit distingue trois ensembles afin de ne pas transformer des exemples historiques en contrats runtime : L'audit distingue trois ensembles afin de ne pas transformer des exemples historiques en contrats runtime :
- **82 noms** actuellement utilisés/référencés par le code, les tests, `.env.example` ou `config/example.config.json` ; - **85 noms** actuellement utilisés/référencés par le code, les tests, `.env.example`, les fixtures ou `config/example.config.json` ;
- **17 noms supplémentaires** présents uniquement dans le guide opérateur Devnet actif ; - **17 noms supplémentaires** présents uniquement dans le guide opérateur Devnet actif ;
- soit **99 noms historiques actifs à migrer ou consolider**. - soit **102 noms historiques actifs à migrer ou consolider**, dont plusieurs convergent volontairement vers une même cible canonique.
Le chiffre `84` mentionné dans un audit `0.5.0` était une estimation antérieure et ne doit plus être utilisé comme contrat. Le chiffre `84` mentionné dans un audit `0.5.0` était une estimation antérieure et ne doit plus être utilisé comme contrat.
@@ -419,15 +419,19 @@ Le chiffre `84` mentionné dans un audit `0.5.0` était une estimation antérieu
### 7.1 Politique cible ### 7.1 Politique cible
```text ```text
KS_SECRET_* -> secret absolu, jamais exposé, jamais loggé, jamais diagnostic en clair Khadhroony Solana / ks-* : KS_SECRET_* / KS_PUBLIC_* / KS_*
KS_PUBLIC_* -> publiable uniquement via un DTO/surface explicitement autorisé Khadhroony Bot / kb-* : KB_SECRET_* / KB_PUBLIC_* / KB_*
KS_* -> interne, non exposé normalement, diagnostic explicite seulement si non sensible
autre -> interdit pour une variable appartenant au workspace
``` ```
La classification par préfixe est une barrière supplémentaire, pas la seule détection de sensibilité. Une URL `KS_*` contenant après substitution une clé API ou des credentials doit rester classée sensible dans son ensemble. Le namespace suit le **propriétaire fonctionnel** du contrat. `kb-app-demo-desktop` peut donc lire une variable `KS_*` lorsqu'il adapte une capacité Solana ; cela ne transforme pas cette variable en contrat Bot. À l'issue de `pre.004`, aucun besoin d'environnement actuellement propre au desktop n'a été identifié : tous les noms runtime existants appartiennent à `ks-config`, `ks-store`, `ks-pipeline` ou `ks-pipeline-demo-scenarios`.
Aucune variable actuelle ne justifie d'être migrée par défaut en `KS_PUBLIC_*`. La migration part donc d'une politique fail-closed : quatre secrets certains deviennent `KS_SECRET_*`, les autres deviennent internes `KS_*`, puis une surface publique pourra être ajoutée plus tard seulement si son utilité est démontrée. Dans chaque namespace :
- `*_SECRET_*` : jamais exposable ;
- `*_PUBLIC_*` : candidate explicite à une surface publique, mais seulement via un DTO/surface autorisé ;
- autre `KS_*` / `KB_*` : interne, diagnostic explicite seulement si non sensible.
La migration reste fail-closed. Les URLs PostgreSQL et la clé Helius sont des secrets certains. Les fixtures Token-2022 effectivement retournées au desktop sont classées `KS_PUBLIC_*`. Les autres contrôles de scénario restent internes. La propagation de sensibilité dans les valeurs composées et le camouflage effectif sont reportés après le split config/logging afin de ne pas mélanger renommage, restructuration et politique de sortie dans une seule prerelease.
Secrets certains : Secrets certains :
@@ -438,12 +442,12 @@ KB_POSTGRES_MAINNET_URL -> KS_SECRET_POSTGRES_MAINNET_URL
KB_POSTGRES_TEST_URL -> KS_SECRET_POSTGRES_TEST_URL KB_POSTGRES_TEST_URL -> KS_SECRET_POSTGRES_TEST_URL
``` ```
Les treize variables historiques `TOKEN_2022_*` sont des fixtures Devnet et convergent vers `KS_DEVNET_TOKEN_2022_*`. Lorsque cette convergence rencontre déjà une ancienne variable `KB_DEVNET_TOKEN_2022_*`, l'implémentation doit choisir **une seule variable cible** et détecter les conflits pendant la migration ; aucun double alias permanent n'est conservé. Les anciennes fixtures `TOKEN_2022_*` et les alias opérateur déjà préfixés convergent vers **un seul vocabulaire**. Par exemple `TOKEN_2022_MINT` et `KB_DEVNET_TOKEN_2022_MINT` convergent vers `KS_PUBLIC_DEVNET_TOKEN_2022_MINT`; `TOKEN_2022_PROGRAM` et `KB_SPL_TOKEN_2022_PROGRAM_ID` convergent vers `KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID`; `KB_DEVNET_WALLET_ADDRESS` et `KB_DEVNET_WALLET_PUBKEY` convergent vers `KS_PUBLIC_DEVNET_WALLET_ADDRESS`. Aucun alias legacy permanent n'est conservé.
### 7.2 Mapping code/config/tests — 82 noms ### 7.2 Mapping code/config/tests — 85 noms
| Nom actuel | Nom cible | Classe | | Nom actuel | Nom cible | Classe |
|--------------------------------------------------------------|--------------------------------------------------------------|------------| |---|---|---|
| `HELIUS_API_KEY` | `KS_SECRET_HELIUS_API_KEY` | `secret` | | `HELIUS_API_KEY` | `KS_SECRET_HELIUS_API_KEY` | `secret` |
| `KB_CONFIG_PATH` | `KS_CONFIG_PATH` | `internal` | | `KB_CONFIG_PATH` | `KS_CONFIG_PATH` | `internal` |
| `KB_CONFIG_TEST_MISSING` | `KS_CONFIG_TEST_MISSING` | `internal` | | `KB_CONFIG_TEST_MISSING` | `KS_CONFIG_TEST_MISSING` | `internal` |
@@ -507,30 +511,33 @@ Les treize variables historiques `TOKEN_2022_*` sont des fixtures Devnet et conv
| `KB_DEVNET_TOKEN_2022_METADATA_OPERATOR_CONFIRMED` | `KS_DEVNET_TOKEN_2022_METADATA_OPERATOR_CONFIRMED` | `internal` | | `KB_DEVNET_TOKEN_2022_METADATA_OPERATOR_CONFIRMED` | `KS_DEVNET_TOKEN_2022_METADATA_OPERATOR_CONFIRMED` | `internal` |
| `KB_DEVNET_TRANSFER_LAMPORTS` | `KS_DEVNET_TRANSFER_LAMPORTS` | `internal` | | `KB_DEVNET_TRANSFER_LAMPORTS` | `KS_DEVNET_TRANSFER_LAMPORTS` | `internal` |
| `KB_DEVNET_WALLET` | `KS_DEVNET_WALLET` | `internal` | | `KB_DEVNET_WALLET` | `KS_DEVNET_WALLET` | `internal` |
| `KB_DEVNET_WALLET_ADDRESS` | `KS_DEVNET_WALLET_ADDRESS` | `internal` | | `KB_DEVNET_WALLET_ADDRESS` | `KS_PUBLIC_DEVNET_WALLET_ADDRESS` | `public` |
| `KB_DEVNET_WALLET_DIR` | `KS_DEVNET_WALLET_DIR` | `internal` | | `KB_DEVNET_WALLET_DIR` | `KS_DEVNET_WALLET_DIR` | `internal` |
| `KB_ENV_FILE` | `KS_ENV_FILE` | `internal` | | `KB_ENV_FILE` | `KS_ENV_FILE` | `internal` |
| `KB_POSTGRES_DEVNET_URL` | `KS_SECRET_POSTGRES_DEVNET_URL` | `secret` | | `KB_POSTGRES_DEVNET_URL` | `KS_SECRET_POSTGRES_DEVNET_URL` | `secret` |
| `KB_POSTGRES_MAINNET_URL` | `KS_SECRET_POSTGRES_MAINNET_URL` | `secret` | | `KB_POSTGRES_MAINNET_URL` | `KS_SECRET_POSTGRES_MAINNET_URL` | `secret` |
| `KB_POSTGRES_TEST_URL` | `KS_SECRET_POSTGRES_TEST_URL` | `secret` | | `KB_POSTGRES_TEST_URL` | `KS_SECRET_POSTGRES_TEST_URL` | `secret` |
| `TOKEN_2022_APPROVE_AMOUNT_RAW` | `KS_DEVNET_TOKEN_2022_APPROVE_AMOUNT_RAW` | `internal` | | `TOKEN_2022_APPROVE_AMOUNT_RAW` | `KS_PUBLIC_DEVNET_TOKEN_2022_APPROVE_AMOUNT_RAW` | `public` |
| `TOKEN_2022_AUTHORITY` | `KS_DEVNET_TOKEN_2022_AUTHORITY` | `internal` | | `TOKEN_2022_AUTHORITY` | `KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY` | `public` |
| `TOKEN_2022_BURN_AMOUNT_RAW` | `KS_DEVNET_TOKEN_2022_BURN_AMOUNT_RAW` | `internal` | | `TOKEN_2022_BURN_AMOUNT_RAW` | `KS_PUBLIC_DEVNET_TOKEN_2022_BURN_AMOUNT_RAW` | `public` |
| `TOKEN_2022_CLOSE_ACCOUNT` | `KS_DEVNET_TOKEN_2022_CLOSE_ACCOUNT` | `internal` | | `TOKEN_2022_CLOSE_ACCOUNT` | `KS_PUBLIC_DEVNET_TOKEN_2022_CLOSE_ACCOUNT` | `public` |
| `TOKEN_2022_DECIMALS` | `KS_DEVNET_TOKEN_2022_DECIMALS` | `internal` | | `TOKEN_2022_DECIMALS` | `KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS` | `public` |
| `TOKEN_2022_DELEGATE` | `KS_DEVNET_TOKEN_2022_DELEGATE` | `internal` | | `TOKEN_2022_DELEGATE` | `KS_PUBLIC_DEVNET_TOKEN_2022_DELEGATE` | `public` |
| `TOKEN_2022_DESTINATION` | `KS_DEVNET_TOKEN_2022_DESTINATION` | `internal` | | `TOKEN_2022_DESTINATION` | `KS_PUBLIC_DEVNET_TOKEN_2022_DESTINATION` | `public` |
| `TOKEN_2022_FREEZE_AUTHORITY` | `KS_DEVNET_TOKEN_2022_FREEZE_AUTHORITY` | `internal` | | `TOKEN_2022_FREEZE_AUTHORITY` | `KS_PUBLIC_DEVNET_TOKEN_2022_FREEZE_AUTHORITY` | `public` |
| `TOKEN_2022_MINT` | `KS_DEVNET_TOKEN_2022_MINT` | `internal` | | `TOKEN_2022_MINT` | `KS_PUBLIC_DEVNET_TOKEN_2022_MINT` | `public` |
| `TOKEN_2022_MINT_AMOUNT_RAW` | `KS_DEVNET_TOKEN_2022_MINT_AMOUNT_RAW` | `internal` | | `TOKEN_2022_MINT_AMOUNT_RAW` | `KS_PUBLIC_DEVNET_TOKEN_2022_MINT_AMOUNT_RAW` | `public` |
| `TOKEN_2022_PROGRAM` | `KS_DEVNET_TOKEN_2022_PROGRAM` | `internal` | | `TOKEN_2022_PROGRAM` | `KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID` | `public` |
| `TOKEN_2022_SOURCE` | `KS_DEVNET_TOKEN_2022_SOURCE` | `internal` | | `TOKEN_2022_SOURCE` | `KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE` | `public` |
| `TOKEN_2022_TRANSFER_AMOUNT_RAW` | `KS_DEVNET_TOKEN_2022_TRANSFER_AMOUNT_RAW` | `internal` | | `TOKEN_2022_TRANSFER_AMOUNT_RAW` | `KS_PUBLIC_DEVNET_TOKEN_2022_TRANSFER_AMOUNT_RAW` | `public` |
| `ELGAMAL_REGISTRY_ADDRESS` | `KS_PUBLIC_DEVNET_ELGAMAL_REGISTRY_ADDRESS` | `public` |
| `ELGAMAL_PUBKEY_BASE64` | `KS_PUBLIC_DEVNET_ELGAMAL_PUBKEY_BASE64` | `public` |
| `PUBKEY_VALIDITY_PROOF_CONTEXT` | `KS_PUBLIC_DEVNET_PUBKEY_VALIDITY_PROOF_CONTEXT` | `public` |
### 7.3 Mapping guide opérateur Devnet — 17 noms ### 7.3 Mapping guide opérateur Devnet — 17 noms
| Nom actuel | Nom cible | Classe | | Nom actuel | Nom cible | Classe |
|---------------------------------------|---------------------------------------|------------| |---|---|---|
| `KB_CONFIRM_DEVNET_DATABASE_RESET` | `KS_CONFIRM_DEVNET_DATABASE_RESET` | `internal` | | `KB_CONFIRM_DEVNET_DATABASE_RESET` | `KS_CONFIRM_DEVNET_DATABASE_RESET` | `internal` |
| `KB_DEVNET_CLASSIC_DESTINATION_ATA` | `KS_DEVNET_CLASSIC_DESTINATION_ATA` | `internal` | | `KB_DEVNET_CLASSIC_DESTINATION_ATA` | `KS_DEVNET_CLASSIC_DESTINATION_ATA` | `internal` |
| `KB_DEVNET_CLASSIC_MINT` | `KS_DEVNET_CLASSIC_MINT` | `internal` | | `KB_DEVNET_CLASSIC_MINT` | `KS_DEVNET_CLASSIC_MINT` | `internal` |
@@ -542,12 +549,12 @@ Les treize variables historiques `TOKEN_2022_*` sont des fixtures Devnet et conv
| `KB_DEVNET_SCENARIO` | `KS_DEVNET_SCENARIO` | `internal` | | `KB_DEVNET_SCENARIO` | `KS_DEVNET_SCENARIO` | `internal` |
| `KB_DEVNET_SIGNATURE` | `KS_DEVNET_SIGNATURE` | `internal` | | `KB_DEVNET_SIGNATURE` | `KS_DEVNET_SIGNATURE` | `internal` |
| `KB_DEVNET_TOKEN_2022_FIXTURE` | `KS_DEVNET_TOKEN_2022_FIXTURE` | `internal` | | `KB_DEVNET_TOKEN_2022_FIXTURE` | `KS_DEVNET_TOKEN_2022_FIXTURE` | `internal` |
| `KB_DEVNET_TOKEN_2022_MINT` | `KS_DEVNET_TOKEN_2022_MINT` | `internal` | | `KB_DEVNET_TOKEN_2022_MINT` | `KS_PUBLIC_DEVNET_TOKEN_2022_MINT` | `public` |
| `KB_DEVNET_TOKEN_2022_MINT_KEYPAIR` | `KS_DEVNET_TOKEN_2022_MINT_KEYPAIR` | `internal` | | `KB_DEVNET_TOKEN_2022_MINT_KEYPAIR` | `KS_DEVNET_TOKEN_2022_MINT_KEYPAIR` | `internal` |
| `KB_DEVNET_VALIDATION_DIR` | `KS_DEVNET_VALIDATION_DIR` | `internal` | | `KB_DEVNET_VALIDATION_DIR` | `KS_DEVNET_VALIDATION_DIR` | `internal` |
| `KB_DEVNET_WALLET_PUBKEY` | `KS_DEVNET_WALLET_PUBKEY` | `internal` | | `KB_DEVNET_WALLET_PUBKEY` | `KS_PUBLIC_DEVNET_WALLET_ADDRESS` | `public` |
| `KB_SPL_TOKEN_2022_PROGRAM_ID` | `KS_SPL_TOKEN_2022_PROGRAM_ID` | `internal` | | `KB_SPL_TOKEN_2022_PROGRAM_ID` | `KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID` | `public` |
| `KB_SPL_TOKEN_PROGRAM_ID` | `KS_SPL_TOKEN_PROGRAM_ID` | `internal` | | `KB_SPL_TOKEN_PROGRAM_ID` | `KS_PUBLIC_SPL_TOKEN_PROGRAM_ID` | `public` |
## 8. Split configuration / logging ## 8. Split configuration / logging
@@ -562,7 +569,7 @@ config/schema.logging.json
Les profils applicatifs/réseau et les profils logging sont sélectionnables indépendamment. Un profil `devnet` n'impose donc pas un profil logging `debug`, et `mainnet` n'impose pas mécaniquement un profil logging `release`. Les profils applicatifs/réseau et les profils logging sont sélectionnables indépendamment. Un profil `devnet` n'impose donc pas un profil logging `debug`, et `mainnet` n'impose pas mécaniquement un profil logging `release`.
Le code duplique actuellement dans `kb-config` et `kb-logging` les concepts : Le code duplique actuellement dans `ks-config` et `ks-logging` les concepts :
- `LoggingConfig` ; - `LoggingConfig` ;
- `LogTargetConfig` ; - `LogTargetConfig` ;
@@ -618,7 +625,7 @@ Avant chaque changement structurel correspondant, conserver ou ajouter des tests
- le maintien de `khadhroony-bot3` comme nom racine ; - le maintien de `khadhroony-bot3` comme nom racine ;
- la cohérence entre targets de tracing et routes de logging ; - la cohérence entre targets de tracing et routes de logging ;
- la résolution des anciennes fixtures/env pendant la phase de migration uniquement, puis leur suppression ; - la résolution des anciennes fixtures/env pendant la phase de migration uniquement, puis leur suppression ;
- l'interdiction des variables de configuration workspace hors `KS_*` ; - l'interdiction des variables de configuration possédées par le workspace hors namespace d'ownership `KS_*` ou `KB_*` ;
- la propagation de sensibilité depuis `KS_SECRET_*` vers les valeurs composées ; - la propagation de sensibilité depuis `KS_SECRET_*` vers les valeurs composées ;
- l'impossibilité pour une sentinelle secrète d'apparaître dans `Debug`, logs, erreurs, payloads Tauri, sérialisation publique ou diagnostic ; - l'impossibilité pour une sentinelle secrète d'apparaître dans `Debug`, logs, erreurs, payloads Tauri, sérialisation publique ou diagnostic ;
- la validation indépendante de `schema.config.json` et `schema.logging.json` ; - la validation indépendante de `schema.config.json` et `schema.logging.json` ;
@@ -653,13 +660,15 @@ Les tests ne doivent pas figer comme comportement légitime la fuite actuelle de
- synchroniser routes de logging, matrices, diagnostics, tests et provenance/replay ; - synchroniser routes de logging, matrices, diagnostics, tests et provenance/replay ;
- ne pas renommer encore les tables SQL `kb_sol_*`. - ne pas renommer encore les tables SQL `kb_sol_*`.
### `0.5.1-pre.004` — environnement `KS_*` et classification ### `0.5.1-pre.004` — namespaces denvironnement et classification
- migrer code, tests, `.env.example`, configuration et guides vers `KS_*` ; - migrer code, tests, `.env.example`, configuration et guides vers le namespace downership `KS_*` ou `KB_*` ;
- consolider les aliases historiques Token-2022 ; - consolider les aliases historiques Token-2022 ;
- introduire classification secret/public/internal et propagation de sensibilité ; - matérialiser la classification secret/public/internal dans les noms et fermer les alias legacy ;
- reporter la propagation de sensibilité et le camouflage effectif après le split config/logging ;
- supprimer les anciens noms une fois la migration vérifiée ; - supprimer les anciens noms une fois la migration vérifiée ;
- ajouter les canaris de non-divulgation. - étendre laudit workspace pour refuser la réintroduction de variables applicatives hors `KS_*` / `KB_*` dans le code, `.env.example`, la configuration exemple et le guide opérateur ;
- ne pas encore modifier les DTO publics ni implémenter le camouflage, qui appartiennent à `pre.006`.
### `0.5.1-pre.005` — split config/logging ### `0.5.1-pre.005` — split config/logging
@@ -715,7 +724,7 @@ Le desktop n'est lancé avec `cargo tauri dev` que lorsqu'une frontière runtime
- les dix bibliothèques Solana utilisent `ks-*` / `ks_*` ; - les dix bibliothèques Solana utilisent `ks-*` / `ks_*` ;
- le workspace racine s'appelle toujours `khadhroony-bot3` ; - le workspace racine s'appelle toujours `khadhroony-bot3` ;
- les variables propres au workspace ont migré vers `KS_*` avec classification sûre ; - les variables Solana ont migré vers `KS_*` avec classification nominale sûre et `KB_*` reste réservé aux futurs contrats Bot ;
- les identités techniques `kb-lib.*` ciblées ont disparu au profit de `ks-lib-*` ; - les identités techniques `kb-lib.*` ciblées ont disparu au profit de `ks-lib-*` ;
- la configuration généraliste et logging sont séparées et validées indépendamment ; - la configuration généraliste et logging sont séparées et validées indépendamment ;
- aucune configuration runtime résolue complète ne traverse Tauri ; - aucune configuration runtime résolue complète ne traverse Tauri ;

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_GENERAL.md --> <!-- file: docs/rules/RULES_GENERAL.md -->
<!-- version: 5 --> <!-- version: 6 -->
# Règles générales du projet # Règles générales du projet
@@ -63,7 +63,7 @@
- Après le squelette initial, livrer uniquement des ZIP delta sauf demande explicite darchive complète. - Après le squelette initial, livrer uniquement des ZIP delta sauf demande explicite darchive complète.
- Un delta touchant la racine ou plusieurs modules se nomme `khadhroony-bot3_vX.Y.Z-pre.abc-delta.zip`. - Un delta touchant la racine ou plusieurs modules se nomme `khadhroony-bot3_vX.Y.Z-pre.abc-delta.zip`.
- Un delta limité à un package Rust se nomme `kb-modulename_vX.Y.Z-pre.abc-delta.zip`. - Un delta limité à un package Rust utilise le nom Cargo courant du package : `<package>_vX.Y.Z-pre.abc-delta.zip` (par exemple `ks-config_vX.Y.Z-pre.abc-delta.zip` ou un futur package applicatif `kb-*`).
- Un correctif dun delta déjà livré conserve le même numéro de prerelease et utilise `-delta-fix-001.zip`, puis `-fix-002.zip`, etc. - Un correctif dun delta déjà livré conserve le même numéro de prerelease et utilise `-delta-fix-001.zip`, puis `-fix-002.zip`, etc.
- La numérotation des correctifs recommence à `fix-001` pour chaque nouvelle prerelease. - La numérotation des correctifs recommence à `fix-001` pour chaque nouvelle prerelease.
- Le numéro de prerelease suivant est réservé à une nouvelle tranche fonctionnelle. - Le numéro de prerelease suivant est réservé à une nouvelle tranche fonctionnelle.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_SPECIFIC_KHADHROONY.md --> <!-- file: docs/rules/RULES_SPECIFIC_KHADHROONY.md -->
<!-- version: 14 --> <!-- version: 15 -->
# Règles spécifiques à `khadhroony-bot3` # Règles spécifiques à `khadhroony-bot3`
@@ -54,7 +54,7 @@ Toute divergence avec une règle générale doit être explicitement documentée
- Les matérialisateurs doivent refuser les transactions non commitées pour les mutations d'état, tout en pouvant conserver séparément une intention non commitée lorsque le modèle métier le prévoit explicitement. - Les matérialisateurs doivent refuser les transactions non commitées pour les mutations d'état, tout en pouvant conserver séparément une intention non commitée lorsque le modèle métier le prévoit explicitement.
- Toute absence volontaire de projection doit être documentée avec une justification technique précise. Un matérialisateur ne doit inventer ni état final, ni montant, ni autorité, ni frais, ni agrégation que l'observation ne prouve pas. - Toute absence volontaire de projection doit être documentée avec une justification technique précise. Un matérialisateur ne doit inventer ni état final, ni montant, ni autorité, ni frais, ni agrégation que l'observation ne prouve pas.
- Chaque matérialisateur concret possède un composant structuré avec une façade limitée aux déclarations de sous-modules et réexports, un `constants.rs` et un `materializer.rs`. Les fichiers spécialisés `state.rs`, `account.rs` ou équivalents sont ajoutés seulement lorsque leur responsabilité est distincte. - Chaque matérialisateur concret possède un composant structuré avec une façade limitée aux déclarations de sous-modules et réexports, un `constants.rs` et un `materializer.rs`. Les fichiers spécialisés `state.rs`, `account.rs` ou équivalents sont ajoutés seulement lorsque leur responsabilité est distincte.
- Lidentité runtime suit `ks-lib-materializer.<domain>[.<subsystem>]`. Le `processorName` persisté suit `materializer.<domain>[.<subsystem>]` et doit être exactement lidentité runtime sans le préfixe `kb-lib.`. Le tracing target dun composant actif est identique à son identité runtime. - Lidentité runtime suit `ks-lib-materializer.<domain>[.<subsystem>]`. Le `processorName` persisté suit `materializer.<domain>[.<subsystem>]` et doit être exactement lidentité runtime sans le préfixe `ks-lib-materializer`. Le tracing target dun composant actif est identique à son identité runtime.
- Les constantes dun composant utilisent le préfixe `MT_<COMPONENT>_`, résident dans son `constants.rs`, sont réexportées par chaque façade jusquà `ks-lib/src/lib.rs` et sont consommées par `crate::`, y compris dans les tests lorsquelles sont `pub` ou `pub(crate)`. - Les constantes dun composant utilisent le préfixe `MT_<COMPONENT>_`, résident dans son `constants.rs`, sont réexportées par chaque façade jusquà `ks-lib/src/lib.rs` et sont consommées par `crate::`, y compris dans les tests lorsquelles sont `pub` ou `pub(crate)`.
- Toute sortie persistée contient un `processorName` issu de la constante du composant et une `projectionVersion` explicite. Une correction de provenance persistée impose une nouvelle version de projection. - Toute sortie persistée contient un `processorName` issu de la constante du composant et une `projectionVersion` explicite. Une correction de provenance persistée impose une nouvelle version de projection.
- Une coquille réservée implémente `MtMaterializer` et `MtApiEventMaterializer`, expose une constante `MT_*_ACCEPTED_FAMILIES` vide, refuse tous les événements, retourne une liste legacy vide et un résultat contextuel `Ignored`. Elle ne doit jamais créer un faux événement de transition. - Une coquille réservée implémente `MtMaterializer` et `MtApiEventMaterializer`, expose une constante `MT_*_ACCEPTED_FAMILIES` vide, refuse tous les événements, retourne une liste legacy vide et un résultat contextuel `Ignored`. Elle ne doit jamais créer un faux événement de transition.
@@ -241,6 +241,9 @@ Aucun renommage massif de modules n'est autorisé sans étape de contrôle dédi
- Les fichiers JSON de configuration ne doivent pas contenir de commentaires. - Les fichiers JSON de configuration ne doivent pas contenir de commentaires.
- Les secrets ne doivent pas être écrits en clair dans le dépôt. - Les secrets ne doivent pas être écrits en clair dans le dépôt.
- Les valeurs sensibles doivent utiliser des variables d'environnement ou un stockage chiffré dédié. - Les valeurs sensibles doivent utiliser des variables d'environnement ou un stockage chiffré dédié.
- Les variables possédées par les composants généralistes `ks-*` utilisent obligatoirement `KS_SECRET_*`, `KS_PUBLIC_*` ou `KS_*` ; les variables réellement spécifiques à `kb-app-demo-desktop` ou à de futures crates `kb-*` utilisent `KB_SECRET_*`, `KB_PUBLIC_*` ou `KB_*`.
- Le namespace est déterminé par le propriétaire fonctionnel du contrat et non par son consommateur : une variable de scénario `ks-pipeline-demo-scenarios` reste `KS_*` même si le desktop la lit.
- Les sous-préfixes `SECRET` sont toujours non exposables ; les sous-préfixes `PUBLIC` ne sont exposables que par une surface explicitement autorisée ; les autres variables du domaine sont internes.
- Les structures de configuration exposées à Tauri doivent dériver `TS`. - Les structures de configuration exposées à Tauri doivent dériver `TS`.
## Ordre de développement cible ## Ordre de développement cible

View File

@@ -1,8 +1,14 @@
<!-- file: kb-app-demo-desktop/CHANGELOG.md --> <!-- file: kb-app-demo-desktop/CHANGELOG.md -->
<!-- version: 43 --> <!-- version: 44 -->
# CHANGELOG — kb-app-demo-desktop # CHANGELOG — kb-app-demo-desktop
## `0.5.1-pre.004`
- lit désormais le chemin de configuration Solana via `KS_CONFIG_PATH` et les fixtures Token-2022 via leurs noms `KS_PUBLIC_*` canoniques ;
- conserve le namespace applicatif `KB_*` disponible pour de futurs besoins réellement spécifiques au Bot, sans créer de variable Bot artificielle dans cette prerelease ;
- ne modifie aucun payload Tauri de configuration résolue : le camouflage et les DTO sûrs restent réservés à la prerelease dédiée après le split config/logging.
## `0.5.1-pre.002` ## `0.5.1-pre.002`
- adapte les dépendances Rust et tous les appels de crates Solana vers `ks_*` sans renommer l'application ; - adapte les dépendances Rust et tous les appels de crates Solana vers `ks_*` sans renommer l'application ;

View File

@@ -1,5 +1,5 @@
// file: kb-app-demo-desktop/src/app_state.rs // file: kb-app-demo-desktop/src/app_state.rs
// version: 11 // version: 12
//! Shared Tauri application state and startup initialization. //! Shared Tauri application state and startup initialization.
@@ -228,7 +228,7 @@ fn convert_logging_config(config: &ks_config::LoggingConfig) -> ks_logging::Logg
} }
fn resolve_config_path() -> std::path::PathBuf { fn resolve_config_path() -> std::path::PathBuf {
let configured = std::env::var("KB_CONFIG_PATH").ok(); let configured = std::env::var("KS_CONFIG_PATH").ok();
return resolve_config_path_from_value(configured.as_deref()); return resolve_config_path_from_value(configured.as_deref());
} }

View File

@@ -1,5 +1,5 @@
// file: kb-app-demo-desktop/src/demo_spl_token_2022.rs // file: kb-app-demo-desktop/src/demo_spl_token_2022.rs
// version: 13 // version: 14
//! Thin Tauri adapter for independent public Token-2022 Devnet validation scenarios. //! Thin Tauri adapter for independent public Token-2022 Devnet validation scenarios.
@@ -247,46 +247,46 @@ pub(crate) fn demo_spl_token_2022_fixture(
_ => std::result::Result::Err(format!("Token-2022 fixture is missing {name}")), _ => std::result::Result::Err(format!("Token-2022 fixture is missing {name}")),
}; };
}; };
let program_id = match required("TOKEN_2022_PROGRAM") { let program_id = match required("KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}; };
let mint = match required("TOKEN_2022_MINT") { let mint = match required("KS_PUBLIC_DEVNET_TOKEN_2022_MINT") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}; };
let source = match required("TOKEN_2022_SOURCE") { let source = match required("KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}; };
let destination = match required("TOKEN_2022_DESTINATION") { let destination = match required("KS_PUBLIC_DEVNET_TOKEN_2022_DESTINATION") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}; };
let close_account = match required("TOKEN_2022_CLOSE_ACCOUNT") { let close_account = match required("KS_PUBLIC_DEVNET_TOKEN_2022_CLOSE_ACCOUNT") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}; };
let delegate = match required("TOKEN_2022_DELEGATE") { let delegate = match required("KS_PUBLIC_DEVNET_TOKEN_2022_DELEGATE") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}; };
let authority = match required("TOKEN_2022_AUTHORITY") { let authority = match required("KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}; };
let freeze_authority = match required("TOKEN_2022_FREEZE_AUTHORITY") { let freeze_authority = match required("KS_PUBLIC_DEVNET_TOKEN_2022_FREEZE_AUTHORITY") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}; };
let decimals_text = match required("TOKEN_2022_DECIMALS") { let decimals_text = match required("KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}; };
let decimals = match decimals_text.parse::<u8>() { let decimals = match decimals_text.parse::<u8>() {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
return std::result::Result::Err(format!("invalid TOKEN_2022_DECIMALS value: {error}")); return std::result::Result::Err(format!("invalid KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS value: {error}"));
}, },
}; };
return std::result::Result::Ok(crate::DemoSplToken2022FixturePayload { return std::result::Result::Ok(crate::DemoSplToken2022FixturePayload {
@@ -300,19 +300,19 @@ pub(crate) fn demo_spl_token_2022_fixture(
authority, authority,
freeze_authority, freeze_authority,
decimals, decimals,
mint_amount_raw: match required("TOKEN_2022_MINT_AMOUNT_RAW") { mint_amount_raw: match required("KS_PUBLIC_DEVNET_TOKEN_2022_MINT_AMOUNT_RAW") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}, },
transfer_amount_raw: match required("TOKEN_2022_TRANSFER_AMOUNT_RAW") { transfer_amount_raw: match required("KS_PUBLIC_DEVNET_TOKEN_2022_TRANSFER_AMOUNT_RAW") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}, },
approve_amount_raw: match required("TOKEN_2022_APPROVE_AMOUNT_RAW") { approve_amount_raw: match required("KS_PUBLIC_DEVNET_TOKEN_2022_APPROVE_AMOUNT_RAW") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}, },
burn_amount_raw: match required("TOKEN_2022_BURN_AMOUNT_RAW") { burn_amount_raw: match required("KS_PUBLIC_DEVNET_TOKEN_2022_BURN_AMOUNT_RAW") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error), std::result::Result::Err(error) => return std::result::Result::Err(error),
}, },

View File

@@ -1,8 +1,14 @@
<!-- file: ks-config/CHANGELOG.md --> <!-- file: ks-config/CHANGELOG.md -->
<!-- version: 13 --> <!-- version: 14 -->
# CHANGELOG — ks-config # CHANGELOG — ks-config
## `0.5.1-pre.004`
- migre le sélecteur d'environnement vers `KS_ENV_FILE` et les placeholders PostgreSQL/Helius vers `KS_SECRET_*` ;
- aligne `.env.example`, `config/example.config.json`, les tests et la documentation sur le namespace Khadhroony Solana ;
- ne met pas encore en œuvre le camouflage ou la propagation de sensibilité, réservés à la frontière runtime/public après le split config/logging.
## `0.5.1-pre.003` ## `0.5.1-pre.003`
- aligne `config/example.config.json` sur les identités hiérarchiques `ks-lib-*` afin que les routes de logging de référence suivent les producteurs renommés ; - aligne `config/example.config.json` sur les identités hiérarchiques `ks-lib-*` afin que les routes de logging de référence suivent les producteurs renommés ;

View File

@@ -1,5 +1,5 @@
<!-- file: ks-config/README.md --> <!-- file: ks-config/README.md -->
<!-- version: 6 --> <!-- version: 7 -->
# ks-config # ks-config
@@ -10,8 +10,8 @@
- exposer `AppConfig` et les sections de configuration publiques ; - exposer `AppConfig` et les sections de configuration publiques ;
- valider le JSON contre le schéma embarqué ; - valider le JSON contre le schéma embarqué ;
- appliquer les invariants métier après désérialisation ; - appliquer les invariants métier après désérialisation ;
- charger `.env` et `.env.local` depuis la racine du workspace ; - charger `.env`, ou le fichier explicitement sélectionné par `KS_ENV_FILE`, depuis la racine du workspace ;
- résoudre les placeholders `${NAME}` et `${NAME:-fallback}` ; - résoudre les placeholders namespacés `${KS_*}` / `${KB_*}` et leurs fallbacks ;
- sélectionner le profil actif ; - sélectionner le profil actif ;
- exporter les types nécessaires au frontend avec `ts-rs`. - exporter les types nécessaires au frontend avec `ts-rs`.
@@ -31,7 +31,7 @@ Les principales fonctions sont `read_config_json_file_with_environment`, `parse_
## Statut ## Statut
La configuration actuelle est fonctionnelle et validée, mais son format `0.4.8` reste monolithique. Le cadrage `0.5.0-pre.002` confirme que `0.5.1` séparera la configuration générale et le logging en documents et schémas distincts, introduira le namespace denvironnement `KS_*` et séparera les représentations source, runtime et publiques afin quaucun secret résolu ne soit exposé. La configuration actuelle est fonctionnelle et validée, mais son format `0.4.8` reste monolithique. Le cadrage `0.5.0-pre.002` confirme que `0.5.1` séparera la configuration générale et le logging en documents et schémas distincts, applique les namespaces denvironnement `KS_*` / `KB_*` par ownership et séparera les représentations source, runtime et publiques afin quaucun secret résolu ne soit exposé.
## Documents ## Documents

View File

@@ -1,5 +1,5 @@
<!-- file: ks-config/TODO.md --> <!-- file: ks-config/TODO.md -->
<!-- version: 5 --> <!-- version: 6 -->
# TODO — ks-config # TODO — ks-config
@@ -8,12 +8,10 @@
- [ ] `0.5.1` - séparer la configuration générale et le logging en documents et schémas JSON distincts. - [ ] `0.5.1` - séparer la configuration générale et le logging en documents et schémas JSON distincts.
- [ ] `0.5.1` - rendre la sélection du profil logging indépendante du profil généraliste. - [ ] `0.5.1` - rendre la sélection du profil logging indépendante du profil généraliste.
- [ ] `0.5.1` - définir un propriétaire unique du contrat source logging et supprimer la conversion manuelle du desktop. - [ ] `0.5.1` - définir un propriétaire unique du contrat source logging et supprimer la conversion manuelle du desktop.
- [ ] `0.5.1` - migrer toutes les variables denvironnement propres au projet vers le namespace `KS_*`. - [ ] `0.5.1` - appliquer à lexécution les classes `KS_SECRET_*` / `KB_SECRET_*`, `KS_PUBLIC_*` / `KB_PUBLIC_*` et internes, avec propagation de sensibilité aux valeurs composées.
- [ ] `0.5.1` - appliquer les classes `KS_SECRET_*`, `KS_PUBLIC_*` et `KS_*` interne avec propagation de sensibilité aux valeurs composées.
- [ ] `0.5.1` - séparer les représentations source, runtime résolue, publique et diagnostic. - [ ] `0.5.1` - séparer les représentations source, runtime résolue, publique et diagnostic.
- [ ] `0.5.1` - interdire quun secret résolu soit sérialisé, loggé, inclus dans une erreur ou transmis via Tauri. - [ ] `0.5.1` - interdire quun secret résolu soit sérialisé, loggé, inclus dans une erreur ou transmis via Tauri.
- [ ] `0.5.1` - supprimer lexposition frontend de `AppConfig` et `ProfileConfig` résolus complets. - [ ] `0.5.1` - supprimer lexposition frontend de `AppConfig` et `ProfileConfig` résolus complets.
- [ ] Migration - fournir une table exhaustive des anciens noms denvironnement vers `KS_*` et une stratégie explicite pour le format `0.4.8`.
- [ ] Contrat - maintenir lidentité entre chaque schéma embarqué et son fichier sous `config/`. - [ ] Contrat - maintenir lidentité entre chaque schéma embarqué et son fichier sous `config/`.
- [ ] Tests - ajouter les tests dAPI externe, de migration multi-fichiers et les canaris de non-divulgation. - [ ] Tests - ajouter les tests dAPI externe, de migration multi-fichiers et les canaris de non-divulgation.
- [ ] Documentation - mettre à jour guides, exemples et `.env.example` seulement avec limplémentation correspondante. - [ ] Documentation - mettre à jour guides, exemples et `.env.example` seulement avec limplémentation correspondante.

View File

@@ -1,5 +1,5 @@
<!-- file: ks-config/USAGE.md --> <!-- file: ks-config/USAGE.md -->
<!-- version: 5 --> <!-- version: 6 -->
# Utilisation de ks-config # Utilisation de ks-config
@@ -30,17 +30,17 @@ let report = match ks_config::load_workspace_environment(std::path::Path::new(".
Err(error) => return Err(error), Err(error) => return Err(error),
}; };
for path in report.loaded_files { if let Some(path) = report.loaded_path {
println!("environment file: {}", path.display()); println!("environment file: {}", path.display());
} }
``` ```
`EnvironmentLoadReport` indique les fichiers chargés. Les placeholders non résolus sans fallback restent visibles afin que la validation ou le consommateur puisse les signaler explicitement. Le format `0.4.8` accepte encore les anciens noms denvironnement ; la migration `0.5.1` imposera le namespace `KS_*`. `EnvironmentLoadReport` indique le fichier chargé, sil existe. Par défaut, `ks-config` sélectionne `.env`; `KS_ENV_FILE` permet de choisir explicitement un autre fichier sans écraser les variables déjà présentes dans le processus. Les placeholders non résolus sans fallback restent visibles afin que la validation ou le consommateur puisse les signaler explicitement. Les contrats denvironnement du workspace utilisent désormais `KS_*` pour Khadhroony Solana et `KB_*` pour les futurs besoins réellement propres au Bot.
## Résolution explicite des placeholders ## Résolution explicite des placeholders
```rust ```rust
let raw = r#"{"databaseUrl":"${KB_DATABASE_URL:-postgres://localhost/kb}"}"#; let raw = r#"{"databaseUrl":"${KS_SECRET_POSTGRES_DEVNET_URL:-postgres://localhost/kb}"}"#;
let resolved = ks_config::resolve_environment_placeholders(raw); let resolved = ks_config::resolve_environment_placeholders(raw);
assert!(resolved.contains("databaseUrl")); assert!(resolved.contains("databaseUrl"));

View File

@@ -1,5 +1,5 @@
// file: ks-config/src/environment.rs // file: ks-config/src/environment.rs
// version: 4 // version: 5
//! Environment-file loading and configuration placeholder resolution. //! Environment-file loading and configuration placeholder resolution.
@@ -17,7 +17,7 @@ pub struct EnvironmentLoadReport {
pub fn load_workspace_environment( pub fn load_workspace_environment(
workspace_root: &std::path::Path, workspace_root: &std::path::Path,
) -> ks_core::Result<EnvironmentLoadReport> { ) -> ks_core::Result<EnvironmentLoadReport> {
let explicit_path = std::env::var("KB_ENV_FILE").ok(); let explicit_path = std::env::var("KS_ENV_FILE").ok();
let selected_path = match explicit_path { let selected_path = match explicit_path {
std::option::Option::Some(path) if !path.trim().is_empty() => { std::option::Option::Some(path) if !path.trim().is_empty() => {
let candidate = std::path::PathBuf::from(path); let candidate = std::path::PathBuf::from(path);
@@ -82,14 +82,14 @@ mod tests {
#[test] #[test]
fn fallback_is_used_when_variable_is_absent() { fn fallback_is_used_when_variable_is_absent() {
let resolved = let resolved =
super::resolve_environment_placeholders("${KB_CONFIG_TEST_MISSING:-fallback}"); super::resolve_environment_placeholders("${KS_CONFIG_TEST_MISSING:-fallback}");
assert_eq!(resolved, "fallback"); assert_eq!(resolved, "fallback");
} }
#[test] #[test]
fn unresolved_required_placeholder_is_preserved() { fn unresolved_required_placeholder_is_preserved() {
let resolved = let resolved =
super::resolve_environment_placeholders("prefix-${KB_CONFIG_TEST_MISSING}-suffix"); super::resolve_environment_placeholders("prefix-${KS_CONFIG_TEST_MISSING}-suffix");
assert_eq!(resolved, "prefix-${KB_CONFIG_TEST_MISSING}-suffix"); assert_eq!(resolved, "prefix-${KS_CONFIG_TEST_MISSING}-suffix");
} }
} }

View File

@@ -1,5 +1,5 @@
// file: ks-config/src/settings.rs // file: ks-config/src/settings.rs
// version: 18 // version: 19
//! Typed configuration models shared by applications and workers. //! Typed configuration models shared by applications and workers.
@@ -1453,15 +1453,15 @@ mod tests {
let value = parse_example_value(); let value = parse_example_value();
assert_eq!( assert_eq!(
value["profiles"][0]["database"]["postgres"]["url"], value["profiles"][0]["database"]["postgres"]["url"],
serde_json::Value::String("${KB_POSTGRES_DEVNET_URL}".to_string()) serde_json::Value::String("${KS_SECRET_POSTGRES_DEVNET_URL}".to_string())
); );
assert_eq!( assert_eq!(
value["profiles"][1]["database"]["postgres"]["url"], value["profiles"][1]["database"]["postgres"]["url"],
serde_json::Value::String("${KB_POSTGRES_MAINNET_URL}".to_string()) serde_json::Value::String("${KS_SECRET_POSTGRES_MAINNET_URL}".to_string())
); );
assert_eq!( assert_eq!(
value["profiles"][2]["database"]["postgres"]["url"], value["profiles"][2]["database"]["postgres"]["url"],
serde_json::Value::String("${KB_POSTGRES_MAINNET_URL}".to_string()) serde_json::Value::String("${KS_SECRET_POSTGRES_MAINNET_URL}".to_string())
); );
} }
@@ -1487,7 +1487,7 @@ mod tests {
fn schema_rejects_unknown_endpoint_secret_field() { fn schema_rejects_unknown_endpoint_secret_field() {
let mut value = parse_example_value(); let mut value = parse_example_value();
value["profiles"][0]["solana"]["http_endpoints"][0]["secret_env_field"] = value["profiles"][0]["solana"]["http_endpoints"][0]["secret_env_field"] =
serde_json::Value::String("HELIUS_API_KEY".to_string()); serde_json::Value::String("KS_SECRET_HELIUS_API_KEY".to_string());
let raw_json = value_to_json(&value); let raw_json = value_to_json(&value);
let result = super::validate_config_json_schema(&raw_json); let result = super::validate_config_json_schema(&raw_json);
assert!(result.is_err()); assert!(result.is_err());

View File

@@ -1,8 +1,14 @@
<!-- file: ks-pipeline-demo-scenarios/CHANGELOG.md --> <!-- file: ks-pipeline-demo-scenarios/CHANGELOG.md -->
<!-- version: 74 --> <!-- version: 75 -->
# CHANGELOG — ks-pipeline-demo-scenarios # CHANGELOG — ks-pipeline-demo-scenarios
## `0.5.1-pre.004`
- migre les paramètres d'environnement des scénarios réutilisables vers `KS_*` et les DSN de test vers `KS_SECRET_*` ;
- consolide les fixtures Token-2022 exposées au desktop sous `KS_PUBLIC_*`, sans conserver les anciens aliases `TOKEN_2022_*` / `KB_*` ;
- aligne le CLI, les campagnes Devnet, le rendu `fixture.env` et le guide d'utilisation sans rejouer ni requalifier les scénarios réseau.
## `0.5.1-pre.002` ## `0.5.1-pre.002`
- renomme `kb-pipeline-demo-scenarios` en `ks-pipeline-demo-scenarios`, sa bibliothèque en `ks_pipeline_demo_scenarios` et son CLI en `ks-pipeline-demo-scenarios-cli` ; - renomme `kb-pipeline-demo-scenarios` en `ks-pipeline-demo-scenarios`, sa bibliothèque en `ks_pipeline_demo_scenarios` et son CLI en `ks-pipeline-demo-scenarios-cli` ;

View File

@@ -1,5 +1,5 @@
<!-- file: ks-pipeline-demo-scenarios/USAGE.md --> <!-- file: ks-pipeline-demo-scenarios/USAGE.md -->
<!-- version: 27 --> <!-- version: 28 -->
# Utilisation de ks-pipeline-demo-scenarios # Utilisation de ks-pipeline-demo-scenarios
@@ -107,13 +107,13 @@ La campagne `0.4.8-pre.012` prépare un mint Token-2022 frais, initialise son `M
Le test opt-in est le chemin opérateur recommandé : Le test opt-in est le chemin opérateur recommandé :
```bash ```bash
KB_DEVNET_TOKEN_2022_METADATA_CAMPAIGN_TEST=1 \ KS_DEVNET_TOKEN_2022_METADATA_CAMPAIGN_TEST=1 \
KB_DEVNET_TOKEN_2022_METADATA_OPERATOR_CONFIRMED=1 \ KS_DEVNET_TOKEN_2022_METADATA_OPERATOR_CONFIRMED=1 \
KB_POSTGRES_TEST_URL='postgresql://…' \ KS_SECRET_POSTGRES_TEST_URL='postgresql://…' \
cargo test -p ks-pipeline-demo-scenarios optional_devnet_token_2022_metadata_campaign_from_env -- --nocapture cargo test -p ks-pipeline-demo-scenarios optional_devnet_token_2022_metadata_campaign_from_env -- --nocapture
``` ```
`KB_DEVNET_PROFILE` peut sélectionner explicitement le profil Devnet et `KB_DEVNET_CONFIG_PATH` peut remplacer `config/example.config.json`. Le profil doit utiliser un wallet persistant, autoriser les soumissions Devnet et respecter les plafonds de dépense et de frais. `KS_DEVNET_PROFILE` peut sélectionner explicitement le profil Devnet et `KS_DEVNET_CONFIG_PATH` peut remplacer `config/example.config.json`. Le profil doit utiliser un wallet persistant, autoriser les soumissions Devnet et respecter les plafonds de dépense et de frais.
La sortie `TOKEN_2022_METADATA_FIXTURE` conserve le mint et la signature de préparation. Chaque ligne `TOKEN_2022_METADATA_STEP` conserve lopération, la signature, le slot, la postcondition, le nombre de matérialisations et, pour `Emit`, la taille du `returnData`. La campagne de référence de `pre.012` a été exécutée avec succès et ses preuves sont conservées dans `SPL_TOKEN_2022_METADATA_DEVNET_VALIDATION_MATRIX.json` et dans le rapport `docs/validation/V0_4_8_METADATA_VALIDATION_REPORT.md` ; le rapport détaillé `pre.012` est archivé sous `olddocs/archivekbot3/docs/validation/`. Une nouvelle exécution produit de nouvelles transactions et ne remplace ces preuves quaprès validation explicite. La sortie `TOKEN_2022_METADATA_FIXTURE` conserve le mint et la signature de préparation. Chaque ligne `TOKEN_2022_METADATA_STEP` conserve lopération, la signature, le slot, la postcondition, le nombre de matérialisations et, pour `Emit`, la taille du `returnData`. La campagne de référence de `pre.012` a été exécutée avec succès et ses preuves sont conservées dans `SPL_TOKEN_2022_METADATA_DEVNET_VALIDATION_MATRIX.json` et dans le rapport `docs/validation/V0_4_8_METADATA_VALIDATION_REPORT.md` ; le rapport détaillé `pre.012` est archivé sous `olddocs/archivekbot3/docs/validation/`. Une nouvelle exécution produit de nouvelles transactions et ne remplace ces preuves quaprès validation explicite.
@@ -299,22 +299,22 @@ La matrice ne transforme jamais une implémentation disponible en validation ré
Le runner Devnet commun accepte toute variante non dépréciée de `ExMetaplexTokenMetadataOperation`. Le test opt-in peut être lancé avec : Le runner Devnet commun accepte toute variante non dépréciée de `ExMetaplexTokenMetadataOperation`. Le test opt-in peut être lancé avec :
```bash ```bash
KB_DEVNET_METAPLEX_EXECUTION_TEST=1 \ KS_DEVNET_METAPLEX_EXECUTION_TEST=1 \
KB_DEVNET_METAPLEX_OPERATION_JSON='{"operation":"..."}' \ KS_DEVNET_METAPLEX_OPERATION_JSON='{"operation":"..."}' \
cargo test -p ks-pipeline-demo-scenarios optional_devnet_current_operation_from_env -- --nocapture cargo test -p ks-pipeline-demo-scenarios optional_devnet_current_operation_from_env -- --nocapture
``` ```
Variables optionnelles : Variables optionnelles :
- `KB_DEVNET_WALLET_DIR` pour sélectionner le répertoire du wallet persistant ; - `KS_DEVNET_WALLET_DIR` pour sélectionner le répertoire du wallet persistant ;
- `KB_POSTGRES_TEST_URL` est obligatoire pour le test opt-in afin de permettre lhydratation canonique, lextraction Core, le replay et la vérification didempotence après une soumission ; - `KS_SECRET_POSTGRES_TEST_URL` est obligatoire pour le test opt-in afin de permettre lhydratation canonique, lextraction Core, le replay et la vérification didempotence après une soumission ;
- `KB_DEVNET_METAPLEX_PREFLIGHT_READS_JSON` pour fournir les lectures stateful avant simulation ; - `KS_DEVNET_METAPLEX_PREFLIGHT_READS_JSON` pour fournir les lectures stateful avant simulation ;
- `KB_DEVNET_METAPLEX_POSTCONDITION_READS_JSON` pour fournir les lectures après confirmation ; - `KS_DEVNET_METAPLEX_POSTCONDITION_READS_JSON` pour fournir les lectures après confirmation ;
- `KB_DEVNET_METAPLEX_MATERIALIZE_AFTER_CONFIRMATION=1` pour rendre obligatoire la preuve de matérialisation et produire les snapshots stateful demandés ; - `KS_DEVNET_METAPLEX_MATERIALIZE_AFTER_CONFIRMATION=1` pour rendre obligatoire la preuve de matérialisation et produire les snapshots stateful demandés ;
- `KB_DEVNET_METAPLEX_SUBMIT=1` pour autoriser la soumission ; - `KS_DEVNET_METAPLEX_SUBMIT=1` pour autoriser la soumission ;
- `KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1` pour confirmer explicitement la soumission. - `KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1` pour confirmer explicitement la soumission.
La soumission reste impossible si `KB_DEVNET_METAPLEX_SUBMIT` et `KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED` ne sont pas activées ensemble. Après confirmation, le runner hydrate la transaction canonique, exécute lextraction Core, rejoue le décodeur Metaplex avec ses matérialiseurs puis effectue une seconde passe qui doit être idempotente. Les opérations dépréciées sont rejetées avant tout appel RPC. La soumission reste impossible si `KS_DEVNET_METAPLEX_SUBMIT` et `KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED` ne sont pas activées ensemble. Après confirmation, le runner hydrate la transaction canonique, exécute lextraction Core, rejoue le décodeur Metaplex avec ses matérialiseurs puis effectue une seconde passe qui doit être idempotente. Les opérations dépréciées sont rejetées avant tout appel RPC.
## Préparer une campagne Metaplex courante ## Préparer une campagne Metaplex courante
@@ -354,7 +354,7 @@ fn creator_verify_request(
`devnet_metaplex_creator_unverify_request` fournit le parcours inverse. Les deux requêtes restent en simulation-only par défaut. `devnet_metaplex_creator_unverify_request` fournit le parcours inverse. Les deux requêtes restent en simulation-only par défaut.
Le test générique accepte toujours `KB_DEVNET_METAPLEX_OPERATION_JSON`, mais rejette explicitement le placeholder documentaire `...`. Les opérations plus complexes recevront des préparateurs de fixtures dédiés au lieu dexiger de longs JSON écrits à la main. Le test générique accepte toujours `KS_DEVNET_METAPLEX_OPERATION_JSON`, mais rejette explicitement le placeholder documentaire `...`. Les opérations plus complexes recevront des préparateurs de fixtures dédiés au lieu dexiger de longs JSON écrits à la main.
## Préparer `Create` puis `Mint` avec un ATA canonique ## Préparer `Create` puis `Mint` avec un ATA canonique
@@ -374,13 +374,13 @@ Le token record pNFT est uniquement dérivé pendant la préparation. Sa créati
La campagne est volontairement exécutée **une famille à la fois**. Elle prépare une fixture fraîche, soumet `Create`, vérifie que la supply et lATA restent à zéro, puis soumet `Mint` et exige la transition exacte vers `mint_amount_raw`. Pour NFT, collection et pNFT, la validation SPL exige après `Create` que les mint/freeze authorities aient été transférées au PDA Master Edition ; pour SFT et fungible, elles restent sur lopérateur. Après `Mint`, NFT/SFT/fungible/collection exigent un ATA `Initialized` (`state=1`), alors que pNFT exige un ATA `Frozen` (`state=2`) et un Token Record Metaplex présent. Toutes les lectures Metaplex postcondition sont automatiquement bornées au slot de confirmation. La campagne est volontairement exécutée **une famille à la fois**. Elle prépare une fixture fraîche, soumet `Create`, vérifie que la supply et lATA restent à zéro, puis soumet `Mint` et exige la transition exacte vers `mint_amount_raw`. Pour NFT, collection et pNFT, la validation SPL exige après `Create` que les mint/freeze authorities aient été transférées au PDA Master Edition ; pour SFT et fungible, elles restent sur lopérateur. Après `Mint`, NFT/SFT/fungible/collection exigent un ATA `Initialized` (`state=1`), alors que pNFT exige un ATA `Frozen` (`state=2`) et un Token Record Metaplex présent. Toutes les lectures Metaplex postcondition sont automatiquement bornées au slot de confirmation.
Le test opt-in utilise `nft` par défaut. Les valeurs acceptées par `KB_DEVNET_METAPLEX_CREATE_MINT_FAMILY` sont `nft`, `sft`, `fungible`, `collection`, `programmable_nft` et lalias `pnft`. Le test opt-in utilise `nft` par défaut. Les valeurs acceptées par `KS_DEVNET_METAPLEX_CREATE_MINT_FAMILY` sont `nft`, `sft`, `fungible`, `collection`, `programmable_nft` et lalias `pnft`.
```bash ```bash
KB_DEVNET_METAPLEX_CREATE_MINT_CAMPAIGN_TEST=1 \ KS_DEVNET_METAPLEX_CREATE_MINT_CAMPAIGN_TEST=1 \
KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \ KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \
KB_DEVNET_METAPLEX_CREATE_MINT_FAMILY=nft \ KS_DEVNET_METAPLEX_CREATE_MINT_FAMILY=nft \
KB_POSTGRES_TEST_URL='postgresql://…' \ KS_SECRET_POSTGRES_TEST_URL='postgresql://…' \
cargo test -p ks-pipeline-demo-scenarios \ cargo test -p ks-pipeline-demo-scenarios \
optional_devnet_metaplex_create_mint_campaign_from_env \ optional_devnet_metaplex_create_mint_campaign_from_env \
-- --nocapture -- --nocapture
@@ -403,9 +403,9 @@ La preuve stateful exige simultanément :
Le parcours ne soumet pas `SetCollectionSize` : cette opération est obsolète et ne doit pas fabriquer artificiellement la postcondition de taille. Le parcours ne soumet pas `SetCollectionSize` : cette opération est obsolète et ne doit pas fabriquer artificiellement la postcondition de taille.
```bash ```bash
KB_DEVNET_METAPLEX_COLLECTION_VERIFY_CAMPAIGN_TEST=1 \ KS_DEVNET_METAPLEX_COLLECTION_VERIFY_CAMPAIGN_TEST=1 \
KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \ KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \
KB_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \ KS_SECRET_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \
cargo test -p ks-pipeline-demo-scenarios \ cargo test -p ks-pipeline-demo-scenarios \
optional_devnet_metaplex_collection_verify_campaign_from_env \ optional_devnet_metaplex_collection_verify_campaign_from_env \
-- --nocapture -- --nocapture
@@ -426,9 +426,9 @@ Une exécution réussie imprime `METAPLEX_COLLECTION_VERIFY_FIXTURE`, deux ligne
Le runner exige que le Token Record source passe `Unlocked/Staking -> Locked/Staking -> Unlocked/Staking -> delegate cleared -> Unlocked/Transfer`. Après le transfert, lATA source doit contenir `0` et rester `Initialized`, tandis que lATA destination doit contenir `1` et rester `Frozen`; le Token Record destination doit être `Unlocked` sans delegate. Ce contrat suit le handler courant, qui thaw la source avant transfert puis freeze uniquement la destination. Les wallets temporaires ne remplacent jamais le wallet persistant du profil comme fee payer ; seul le delegate explicitement déclaré est ajouté aux signataires des étapes qui lexigent. Le runner exige que le Token Record source passe `Unlocked/Staking -> Locked/Staking -> Unlocked/Staking -> delegate cleared -> Unlocked/Transfer`. Après le transfert, lATA source doit contenir `0` et rester `Initialized`, tandis que lATA destination doit contenir `1` et rester `Frozen`; le Token Record destination doit être `Unlocked` sans delegate. Ce contrat suit le handler courant, qui thaw la source avant transfert puis freeze uniquement la destination. Les wallets temporaires ne remplacent jamais le wallet persistant du profil comme fee payer ; seul le delegate explicitement déclaré est ajouté aux signataires des étapes qui lexigent.
```bash ```bash
KB_DEVNET_METAPLEX_PNFT_LIFECYCLE_CAMPAIGN_TEST=1 \ KS_DEVNET_METAPLEX_PNFT_LIFECYCLE_CAMPAIGN_TEST=1 \
KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \ KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \
KB_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \ KS_SECRET_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \
cargo test -p ks-pipeline-demo-scenarios \ cargo test -p ks-pipeline-demo-scenarios \
optional_devnet_metaplex_pnft_lifecycle_campaign_from_env \ optional_devnet_metaplex_pnft_lifecycle_campaign_from_env \
-- --nocapture -- --nocapture
@@ -441,9 +441,9 @@ Une exécution qualifiante doit terminer `ok` et produire `METAPLEX_PNFT_LIFECYC
La campagne escrow prépare un NFT classique parent et un token fungible attribut, puis exécute un cycle `TokenOwner` strictement contrôlé. Elle crée le PDA escrow, crée son ATA SPL classique pour le mint attribut, y dépose exactement une unité brute, transfère cette unité vers lATA de lopérateur puis ferme le compte escrow. La campagne escrow prépare un NFT classique parent et un token fungible attribut, puis exécute un cycle `TokenOwner` strictement contrôlé. Elle crée le PDA escrow, crée son ATA SPL classique pour le mint attribut, y dépose exactement une unité brute, transfère cette unité vers lATA de lopérateur puis ferme le compte escrow.
```bash ```bash
KB_DEVNET_METAPLEX_ESCROW_CAMPAIGN_TEST=1 \ KS_DEVNET_METAPLEX_ESCROW_CAMPAIGN_TEST=1 \
KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \ KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \
KB_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \ KS_SECRET_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \
cargo test -p ks-pipeline-demo-scenarios \ cargo test -p ks-pipeline-demo-scenarios \
optional_devnet_metaplex_escrow_campaign_from_env \ optional_devnet_metaplex_escrow_campaign_from_env \
-- --nocapture -- --nocapture
@@ -456,9 +456,9 @@ Une exécution qualifiante doit produire `METAPLEX_ESCROW_FIXTURE`, deux lignes
La campagne `maintenance_campaign` ferme les opérations courantes qui ne relèvent pas des parcours précédents. Elle crée un NFT classique frais, soumet réellement `Update` avec la transition bornée `primary_sale_happened: false -> true`, puis traite les surfaces non qualifiables positivement avec des probes **simulation-only**. Une simulation négative n'autorise jamais une soumission. La campagne `maintenance_campaign` ferme les opérations courantes qui ne relèvent pas des parcours précédents. Elle crée un NFT classique frais, soumet réellement `Update` avec la transition bornée `primary_sale_happened: false -> true`, puis traite les surfaces non qualifiables positivement avec des probes **simulation-only**. Une simulation négative n'autorise jamais une soumission.
```bash ```bash
KB_DEVNET_METAPLEX_MAINTENANCE_CAMPAIGN_TEST=1 \ KS_DEVNET_METAPLEX_MAINTENANCE_CAMPAIGN_TEST=1 \
KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \ KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \
KB_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \ KS_SECRET_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \
cargo test -p ks-pipeline-demo-scenarios \ cargo test -p ks-pipeline-demo-scenarios \
optional_devnet_metaplex_maintenance_campaign_from_env \ optional_devnet_metaplex_maintenance_campaign_from_env \
-- --nocapture -- --nocapture
@@ -484,9 +484,9 @@ Les cinq familles NFT, SFT, fungible, collection et pNFT sont confirmées. `Crea
La surface courante `Use` est classée `unavailable` sur Devnet : la simulation exacte du discriminant 51 retourne `InvalidInstructionData` et aucune transaction n'est soumise. Le test opt-in reste utile comme contrôle de non-régression du runtime : La surface courante `Use` est classée `unavailable` sur Devnet : la simulation exacte du discriminant 51 retourne `InvalidInstructionData` et aucune transaction n'est soumise. Le test opt-in reste utile comme contrôle de non-régression du runtime :
```bash ```bash
KB_DEVNET_METAPLEX_USE_PROBE_TEST=1 \ KS_DEVNET_METAPLEX_USE_PROBE_TEST=1 \
KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \ KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \
KB_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \ KS_SECRET_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \
cargo test -p ks-pipeline-demo-scenarios \ cargo test -p ks-pipeline-demo-scenarios \
optional_devnet_metaplex_use_probe_from_env \ optional_devnet_metaplex_use_probe_from_env \
-- --nocapture -- --nocapture

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/bin/ks_pipeline_demo_scenarios_cli.rs // file: ks-pipeline-demo-scenarios/src/bin/ks_pipeline_demo_scenarios_cli.rs
// version: 2 // version: 3
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![deny(unreachable_pub)] #![deny(unreachable_pub)]
@@ -84,21 +84,21 @@ fn parse_prepare_options(
} }
index += 2; index += 2;
} }
let rpc_url = match rpc_url.or_else(|| return std::env::var("KB_DEVNET_RPC_URL").ok()) { let rpc_url = match rpc_url.or_else(|| return std::env::var("KS_DEVNET_RPC_URL").ok()) {
std::option::Option::Some(value) => value, std::option::Option::Some(value) => value,
std::option::Option::None => { std::option::Option::None => {
return std::result::Result::Err(ks_core::Error::config( return std::result::Result::Err(ks_core::Error::config(
"missing --rpc-url or KB_DEVNET_RPC_URL", "missing --rpc-url or KS_DEVNET_RPC_URL",
)); ));
}, },
}; };
let wallet_path = match wallet_path let wallet_path = match wallet_path
.or_else(|| return std::env::var("KB_DEVNET_WALLET").ok().map(std::path::PathBuf::from)) .or_else(|| return std::env::var("KS_DEVNET_WALLET").ok().map(std::path::PathBuf::from))
{ {
std::option::Option::Some(value) => value, std::option::Option::Some(value) => value,
std::option::Option::None => { std::option::Option::None => {
return std::result::Result::Err(ks_core::Error::config( return std::result::Result::Err(ks_core::Error::config(
"missing --wallet or KB_DEVNET_WALLET", "missing --wallet or KS_DEVNET_WALLET",
)); ));
}, },
}; };

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/environment.rs // file: ks-pipeline-demo-scenarios/src/environment.rs
// version: 3 // version: 4
//! Environment initialization for opt-in demonstration scenarios. //! Environment initialization for opt-in demonstration scenarios.
@@ -12,7 +12,7 @@ pub fn initialize_demo_scenario_environment(
/// Resolves one compatible Devnet profile for demo scenarios. /// Resolves one compatible Devnet profile for demo scenarios.
/// ///
/// An explicit name has priority, followed by `KB_DEVNET_PROFILE`, then the /// An explicit name has priority, followed by `KS_DEVNET_PROFILE`, then the
/// first compatible Devnet profile declared by the configuration. /// first compatible Devnet profile declared by the configuration.
pub fn resolve_demo_devnet_profile( pub fn resolve_demo_devnet_profile(
config: &ks_config::AppConfig, config: &ks_config::AppConfig,
@@ -24,7 +24,7 @@ pub fn resolve_demo_devnet_profile(
.map(std::string::ToString::to_string); .map(std::string::ToString::to_string);
let selected_name = match explicit { let selected_name = match explicit {
std::option::Option::Some(value) => std::option::Option::Some(value), std::option::Option::Some(value) => std::option::Option::Some(value),
std::option::Option::None => std::env::var("KB_DEVNET_PROFILE") std::option::Option::None => std::env::var("KS_DEVNET_PROFILE")
.ok() .ok()
.map(|value| return value.trim().to_string()) .map(|value| return value.trim().to_string())
.filter(|value| return !value.is_empty()), .filter(|value| return !value.is_empty()),

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/collection_verify_campaign.rs // file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/collection_verify_campaign.rs
// version: 2 // version: 3
//! Confirmed Devnet collection parent/member `Verify -> Unverify` campaign. //! Confirmed Devnet collection parent/member `Verify -> Unverify` campaign.
@@ -627,23 +627,23 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_metaplex_collection_verify_campaign_from_env() { async fn optional_devnet_metaplex_collection_verify_campaign_from_env() {
if std::env::var("KB_DEVNET_METAPLEX_COLLECTION_VERIFY_CAMPAIGN_TEST") if std::env::var("KS_DEVNET_METAPLEX_COLLECTION_VERIFY_CAMPAIGN_TEST")
.ok() .ok()
.as_deref() .as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
if std::env::var("KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref() if std::env::var("KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
panic!("KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 is required for the spending campaign"); panic!("KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 is required for the spending campaign");
} }
let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() { let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() {
std::option::Option::Some(value) => value, std::option::Option::Some(value) => value,
std::option::Option::None => panic!("workspace root cannot be resolved"), std::option::Option::None => panic!("workspace root cannot be resolved"),
}; };
let config_path = match std::env::var("KB_DEVNET_CONFIG_PATH") { let config_path = match std::env::var("KS_DEVNET_CONFIG_PATH") {
std::result::Result::Ok(value) => { std::result::Result::Ok(value) => {
let path = std::path::PathBuf::from(value); let path = std::path::PathBuf::from(value);
if path.is_absolute() { path } else { workspace_root.join(path) } if path.is_absolute() { path } else { workspace_root.join(path) }
@@ -655,11 +655,11 @@ mod tests {
workspace_root, workspace_root,
) )
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}")); .unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
let profile_name = std::env::var("KB_DEVNET_PROFILE").ok(); let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref()) let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}")); .unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
let database_url = std::env::var("KB_POSTGRES_TEST_URL") let database_url = std::env::var("KS_SECRET_POSTGRES_TEST_URL")
.unwrap_or_else(|error| panic!("KB_POSTGRES_TEST_URL is required: {error}")); .unwrap_or_else(|error| panic!("KS_SECRET_POSTGRES_TEST_URL is required: {error}"));
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url; profile.database.postgres.url = database_url;
let pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile) let pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile)

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/create_mint_campaign.rs // file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/create_mint_campaign.rs
// version: 10 // version: 11
//! Confirmed Devnet `Create -> Mint` campaign for one Metaplex asset family. //! Confirmed Devnet `Create -> Mint` campaign for one Metaplex asset family.
@@ -669,7 +669,7 @@ mod tests {
"fungible" => crate::MetaplexTokenMetadataAssetFamily::Fungible, "fungible" => crate::MetaplexTokenMetadataAssetFamily::Fungible,
"collection" => crate::MetaplexTokenMetadataAssetFamily::Collection, "collection" => crate::MetaplexTokenMetadataAssetFamily::Collection,
"programmable_nft" | "pnft" => crate::MetaplexTokenMetadataAssetFamily::ProgrammableNft, "programmable_nft" | "pnft" => crate::MetaplexTokenMetadataAssetFamily::ProgrammableNft,
_ => panic!("unsupported KB_DEVNET_METAPLEX_CREATE_MINT_FAMILY `{value}`"), _ => panic!("unsupported KS_DEVNET_METAPLEX_CREATE_MINT_FAMILY `{value}`"),
}; };
} }
@@ -794,21 +794,21 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_metaplex_create_mint_campaign_from_env() { async fn optional_devnet_metaplex_create_mint_campaign_from_env() {
if std::env::var("KB_DEVNET_METAPLEX_CREATE_MINT_CAMPAIGN_TEST").ok().as_deref() if std::env::var("KS_DEVNET_METAPLEX_CREATE_MINT_CAMPAIGN_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
if std::env::var("KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref() if std::env::var("KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
panic!("KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 is required for the spending campaign"); panic!("KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 is required for the spending campaign");
} }
let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() { let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() {
std::option::Option::Some(value) => value, std::option::Option::Some(value) => value,
std::option::Option::None => panic!("workspace root cannot be resolved"), std::option::Option::None => panic!("workspace root cannot be resolved"),
}; };
let config_path = match std::env::var("KB_DEVNET_CONFIG_PATH") { let config_path = match std::env::var("KS_DEVNET_CONFIG_PATH") {
std::result::Result::Ok(value) => { std::result::Result::Ok(value) => {
let path = std::path::PathBuf::from(value); let path = std::path::PathBuf::from(value);
if path.is_absolute() { path } else { workspace_root.join(path) } if path.is_absolute() { path } else { workspace_root.join(path) }
@@ -820,11 +820,11 @@ mod tests {
workspace_root, workspace_root,
) )
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}")); .unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
let profile_name = std::env::var("KB_DEVNET_PROFILE").ok(); let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref()) let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}")); .unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
let database_url = std::env::var("KB_POSTGRES_TEST_URL") let database_url = std::env::var("KS_SECRET_POSTGRES_TEST_URL")
.unwrap_or_else(|error| panic!("KB_POSTGRES_TEST_URL is required: {error}")); .unwrap_or_else(|error| panic!("KS_SECRET_POSTGRES_TEST_URL is required: {error}"));
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url; profile.database.postgres.url = database_url;
let pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile) let pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile)
@@ -848,7 +848,7 @@ mod tests {
} else { } else {
workspace_root.join(configured_wallet_dir) workspace_root.join(configured_wallet_dir)
}; };
let family = std::env::var("KB_DEVNET_METAPLEX_CREATE_MINT_FAMILY") let family = std::env::var("KS_DEVNET_METAPLEX_CREATE_MINT_FAMILY")
.map(|value| return family_from_env(value.as_str())) .map(|value| return family_from_env(value.as_str()))
.unwrap_or(crate::MetaplexTokenMetadataAssetFamily::Nft); .unwrap_or(crate::MetaplexTokenMetadataAssetFamily::Nft);
let options = crate::MetaplexCreateFixturePreparationOptions::new(wallet_dir) let options = crate::MetaplexCreateFixturePreparationOptions::new(wallet_dir)

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/devnet_execution.rs // file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/devnet_execution.rs
// version: 18 // version: 19
//! Real Devnet simulation and submission for current Metaplex Token Metadata operations. //! Real Devnet simulation and submission for current Metaplex Token Metadata operations.
@@ -1403,29 +1403,29 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_current_operation_from_env() { async fn optional_devnet_current_operation_from_env() {
if std::env::var("KB_DEVNET_METAPLEX_EXECUTION_TEST").ok().as_deref() if std::env::var("KS_DEVNET_METAPLEX_EXECUTION_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
let operation_json = match std::env::var("KB_DEVNET_METAPLEX_OPERATION_JSON") { let operation_json = match std::env::var("KS_DEVNET_METAPLEX_OPERATION_JSON") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
panic!("KB_DEVNET_METAPLEX_OPERATION_JSON is required: {error}"); panic!("KS_DEVNET_METAPLEX_OPERATION_JSON is required: {error}");
}, },
}; };
let mut profile = example_devnet_profile(); let mut profile = example_devnet_profile();
if let std::result::Result::Ok(directory) = std::env::var("KB_DEVNET_WALLET_DIR") { if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory; profile.wallet.wallet_dir = directory;
} }
let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) { let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("HTTP pool creation failed: {error}"), std::result::Result::Err(error) => panic!("HTTP pool creation failed: {error}"),
}; };
let database_url = match std::env::var("KB_POSTGRES_TEST_URL") { let database_url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
panic!("KB_POSTGRES_TEST_URL is required for Metaplex execution: {error}") panic!("KS_SECRET_POSTGRES_TEST_URL is required for Metaplex execution: {error}")
}, },
}; };
let store_options = match ks_store::PostgresStoreOptions::new(database_url, 5, 5_000, false) let store_options = match ks_store::PostgresStoreOptions::new(database_url, 5, 5_000, false)
@@ -1455,16 +1455,16 @@ mod tests {
}, },
}; };
request.preflight_reads = request.preflight_reads =
optional_stateful_reads_from_env("KB_DEVNET_METAPLEX_PREFLIGHT_READS_JSON"); optional_stateful_reads_from_env("KS_DEVNET_METAPLEX_PREFLIGHT_READS_JSON");
request.postcondition_reads = request.postcondition_reads =
optional_stateful_reads_from_env("KB_DEVNET_METAPLEX_POSTCONDITION_READS_JSON"); optional_stateful_reads_from_env("KS_DEVNET_METAPLEX_POSTCONDITION_READS_JSON");
request.submit = std::env::var("KB_DEVNET_METAPLEX_SUBMIT").ok().as_deref() request.submit = std::env::var("KS_DEVNET_METAPLEX_SUBMIT").ok().as_deref()
== std::option::Option::Some("1"); == std::option::Option::Some("1");
request.operator_confirmed = request.submit request.operator_confirmed = request.submit
&& std::env::var("KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref() && std::env::var("KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref()
== std::option::Option::Some("1"); == std::option::Option::Some("1");
request.materialize_after_confirmation = request.submit request.materialize_after_confirmation = request.submit
&& std::env::var("KB_DEVNET_METAPLEX_MATERIALIZE_AFTER_CONFIRMATION") && std::env::var("KS_DEVNET_METAPLEX_MATERIALIZE_AFTER_CONFIRMATION")
.ok() .ok()
.as_deref() .as_deref()
== std::option::Option::Some("1"); == std::option::Option::Some("1");

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/escrow_campaign.rs // file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/escrow_campaign.rs
// version: 2 // version: 3
//! Confirmed Devnet Token Owned Escrow campaign for current Metaplex escrow operations. //! Confirmed Devnet Token Owned Escrow campaign for current Metaplex escrow operations.
@@ -954,21 +954,21 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_metaplex_escrow_campaign_from_env() { async fn optional_devnet_metaplex_escrow_campaign_from_env() {
if std::env::var("KB_DEVNET_METAPLEX_ESCROW_CAMPAIGN_TEST").ok().as_deref() if std::env::var("KS_DEVNET_METAPLEX_ESCROW_CAMPAIGN_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
assert_eq!( assert_eq!(
std::env::var("KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref(), std::env::var("KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref(),
std::option::Option::Some("1"), std::option::Option::Some("1"),
"set KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 before the escrow campaign" "set KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 before the escrow campaign"
); );
let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() { let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() {
std::option::Option::Some(value) => value, std::option::Option::Some(value) => value,
std::option::Option::None => panic!("workspace root cannot be resolved"), std::option::Option::None => panic!("workspace root cannot be resolved"),
}; };
let config_path = match std::env::var("KB_DEVNET_CONFIG_PATH") { let config_path = match std::env::var("KS_DEVNET_CONFIG_PATH") {
std::result::Result::Ok(value) => { std::result::Result::Ok(value) => {
let path = std::path::PathBuf::from(value); let path = std::path::PathBuf::from(value);
if path.is_absolute() { path } else { workspace_root.join(path) } if path.is_absolute() { path } else { workspace_root.join(path) }
@@ -980,11 +980,11 @@ mod tests {
workspace_root, workspace_root,
) )
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}")); .unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
let profile_name = std::env::var("KB_DEVNET_PROFILE").ok(); let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref()) let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}")); .unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
let database_url = std::env::var("KB_POSTGRES_TEST_URL") let database_url = std::env::var("KS_SECRET_POSTGRES_TEST_URL")
.unwrap_or_else(|error| panic!("KB_POSTGRES_TEST_URL is required: {error}")); .unwrap_or_else(|error| panic!("KS_SECRET_POSTGRES_TEST_URL is required: {error}"));
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url; profile.database.postgres.url = database_url;
let http_pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile) let http_pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile)

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/maintenance_campaign.rs // file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/maintenance_campaign.rs
// version: 4 // version: 5
//! Final bounded Devnet qualification campaign for current Metaplex maintenance operations. //! Final bounded Devnet qualification campaign for current Metaplex maintenance operations.
@@ -558,21 +558,21 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_metaplex_maintenance_campaign_from_env() { async fn optional_devnet_metaplex_maintenance_campaign_from_env() {
if std::env::var("KB_DEVNET_METAPLEX_MAINTENANCE_CAMPAIGN_TEST").ok().as_deref() if std::env::var("KS_DEVNET_METAPLEX_MAINTENANCE_CAMPAIGN_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
assert_eq!( assert_eq!(
std::env::var("KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref(), std::env::var("KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref(),
std::option::Option::Some("1"), std::option::Option::Some("1"),
"set KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 before the maintenance campaign" "set KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 before the maintenance campaign"
); );
let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() { let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() {
std::option::Option::Some(value) => value, std::option::Option::Some(value) => value,
std::option::Option::None => panic!("workspace root cannot be resolved"), std::option::Option::None => panic!("workspace root cannot be resolved"),
}; };
let config_path = match std::env::var("KB_DEVNET_CONFIG_PATH") { let config_path = match std::env::var("KS_DEVNET_CONFIG_PATH") {
std::result::Result::Ok(value) => { std::result::Result::Ok(value) => {
let path = std::path::PathBuf::from(value); let path = std::path::PathBuf::from(value);
if path.is_absolute() { path } else { workspace_root.join(path) } if path.is_absolute() { path } else { workspace_root.join(path) }
@@ -584,11 +584,11 @@ mod tests {
workspace_root, workspace_root,
) )
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}")); .unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
let profile_name = std::env::var("KB_DEVNET_PROFILE").ok(); let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref()) let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}")); .unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
let database_url = std::env::var("KB_POSTGRES_TEST_URL") let database_url = std::env::var("KS_SECRET_POSTGRES_TEST_URL")
.unwrap_or_else(|error| panic!("KB_POSTGRES_TEST_URL is required: {error}")); .unwrap_or_else(|error| panic!("KS_SECRET_POSTGRES_TEST_URL is required: {error}"));
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url; profile.database.postgres.url = database_url;
let http_pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile) let http_pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile)

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/pnft_lifecycle_campaign.rs // file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/pnft_lifecycle_campaign.rs
// version: 4 // version: 5
//! Confirmed Devnet pNFT delegate, lock, unlock, revoke and transfer campaign. //! Confirmed Devnet pNFT delegate, lock, unlock, revoke and transfer campaign.
@@ -1052,21 +1052,21 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_metaplex_pnft_lifecycle_campaign_from_env() { async fn optional_devnet_metaplex_pnft_lifecycle_campaign_from_env() {
if std::env::var("KB_DEVNET_METAPLEX_PNFT_LIFECYCLE_CAMPAIGN_TEST").ok().as_deref() if std::env::var("KS_DEVNET_METAPLEX_PNFT_LIFECYCLE_CAMPAIGN_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
assert_eq!( assert_eq!(
std::env::var("KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref(), std::env::var("KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref(),
std::option::Option::Some("1"), std::option::Option::Some("1"),
"set KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 before submitting the pNFT lifecycle campaign" "set KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 before submitting the pNFT lifecycle campaign"
); );
let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() { let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() {
std::option::Option::Some(value) => value, std::option::Option::Some(value) => value,
std::option::Option::None => panic!("workspace root cannot be resolved"), std::option::Option::None => panic!("workspace root cannot be resolved"),
}; };
let config_path = match std::env::var("KB_DEVNET_CONFIG_PATH") { let config_path = match std::env::var("KS_DEVNET_CONFIG_PATH") {
std::result::Result::Ok(value) => { std::result::Result::Ok(value) => {
let path = std::path::PathBuf::from(value); let path = std::path::PathBuf::from(value);
if path.is_absolute() { path } else { workspace_root.join(path) } if path.is_absolute() { path } else { workspace_root.join(path) }
@@ -1078,11 +1078,11 @@ mod tests {
workspace_root, workspace_root,
) )
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}")); .unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
let profile_name = std::env::var("KB_DEVNET_PROFILE").ok(); let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref()) let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}")); .unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
let database_url = std::env::var("KB_POSTGRES_TEST_URL") let database_url = std::env::var("KS_SECRET_POSTGRES_TEST_URL")
.unwrap_or_else(|error| panic!("KB_POSTGRES_TEST_URL is required: {error}")); .unwrap_or_else(|error| panic!("KS_SECRET_POSTGRES_TEST_URL is required: {error}"));
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url; profile.database.postgres.url = database_url;
let http_pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile) let http_pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile)

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/print_burn_campaign.rs // file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/print_burn_campaign.rs
// version: 5 // version: 6
//! Devnet printable master NFT `Print -> Burn` campaign. //! Devnet printable master NFT `Print -> Burn` campaign.
@@ -1161,21 +1161,21 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_metaplex_print_burn_campaign_from_env() { async fn optional_devnet_metaplex_print_burn_campaign_from_env() {
if std::env::var("KB_DEVNET_METAPLEX_PRINT_BURN_CAMPAIGN_TEST").ok().as_deref() if std::env::var("KS_DEVNET_METAPLEX_PRINT_BURN_CAMPAIGN_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
if std::env::var("KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref() if std::env::var("KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
panic!("KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 is required for the spending campaign"); panic!("KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 is required for the spending campaign");
} }
let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() { let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() {
std::option::Option::Some(value) => value, std::option::Option::Some(value) => value,
std::option::Option::None => panic!("workspace root cannot be resolved"), std::option::Option::None => panic!("workspace root cannot be resolved"),
}; };
let config_path = match std::env::var("KB_DEVNET_CONFIG_PATH") { let config_path = match std::env::var("KS_DEVNET_CONFIG_PATH") {
std::result::Result::Ok(value) => { std::result::Result::Ok(value) => {
let path = std::path::PathBuf::from(value); let path = std::path::PathBuf::from(value);
if path.is_absolute() { path } else { workspace_root.join(path) } if path.is_absolute() { path } else { workspace_root.join(path) }
@@ -1187,11 +1187,11 @@ mod tests {
workspace_root, workspace_root,
) )
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}")); .unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
let profile_name = std::env::var("KB_DEVNET_PROFILE").ok(); let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref()) let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}")); .unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
let database_url = std::env::var("KB_POSTGRES_TEST_URL") let database_url = std::env::var("KS_SECRET_POSTGRES_TEST_URL")
.unwrap_or_else(|error| panic!("KB_POSTGRES_TEST_URL is required: {error}")); .unwrap_or_else(|error| panic!("KS_SECRET_POSTGRES_TEST_URL is required: {error}"));
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url; profile.database.postgres.url = database_url;
let pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile) let pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile)

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/use_campaign.rs // file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/use_campaign.rs
// version: 2 // version: 3
//! Bounded Devnet availability probe for the current Metaplex `Use` surface. //! Bounded Devnet availability probe for the current Metaplex `Use` surface.
@@ -406,21 +406,21 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_metaplex_use_probe_from_env() { async fn optional_devnet_metaplex_use_probe_from_env() {
if std::env::var("KB_DEVNET_METAPLEX_USE_PROBE_TEST").ok().as_deref() if std::env::var("KS_DEVNET_METAPLEX_USE_PROBE_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
assert_eq!( assert_eq!(
std::env::var("KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref(), std::env::var("KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED").ok().as_deref(),
std::option::Option::Some("1"), std::option::Option::Some("1"),
"set KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 before submitting an accepted Use probe" "set KS_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 before submitting an accepted Use probe"
); );
let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() { let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() {
std::option::Option::Some(value) => value, std::option::Option::Some(value) => value,
std::option::Option::None => panic!("workspace root cannot be resolved"), std::option::Option::None => panic!("workspace root cannot be resolved"),
}; };
let config_path = match std::env::var("KB_DEVNET_CONFIG_PATH") { let config_path = match std::env::var("KS_DEVNET_CONFIG_PATH") {
std::result::Result::Ok(value) => { std::result::Result::Ok(value) => {
let path = std::path::PathBuf::from(value); let path = std::path::PathBuf::from(value);
if path.is_absolute() { path } else { workspace_root.join(path) } if path.is_absolute() { path } else { workspace_root.join(path) }
@@ -432,11 +432,11 @@ mod tests {
workspace_root, workspace_root,
) )
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}")); .unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
let profile_name = std::env::var("KB_DEVNET_PROFILE").ok(); let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref()) let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}")); .unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
let database_url = std::env::var("KB_POSTGRES_TEST_URL") let database_url = std::env::var("KS_SECRET_POSTGRES_TEST_URL")
.unwrap_or_else(|error| panic!("KB_POSTGRES_TEST_URL is required: {error}")); .unwrap_or_else(|error| panic!("KS_SECRET_POSTGRES_TEST_URL is required: {error}"));
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url; profile.database.postgres.url = database_url;
let http_pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile) let http_pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile)

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/solana.rs // file: ks-pipeline-demo-scenarios/src/solana.rs
// version: 12 // version: 13
//! Devnet Solana execution orchestration with canonical post-validation. //! Devnet Solana execution orchestration with canonical post-validation.
@@ -1332,21 +1332,21 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_system_transfer_from_env() { async fn optional_devnet_system_transfer_from_env() {
if std::env::var("KB_DEVNET_EXECUTION_TEST").ok().as_deref() if std::env::var("KS_DEVNET_EXECUTION_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
let database_url = match std::env::var("KB_POSTGRES_TEST_URL") { let database_url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
panic!("KB_POSTGRES_TEST_URL is required: {error}"); panic!("KS_SECRET_POSTGRES_TEST_URL is required: {error}");
}, },
}; };
let mut profile = example_devnet_profile(); let mut profile = example_devnet_profile();
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url; profile.database.postgres.url = database_url;
if let std::result::Result::Ok(directory) = std::env::var("KB_DEVNET_WALLET_DIR") { if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory; profile.wallet.wallet_dir = directory;
} }
let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) { let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) {
@@ -1374,11 +1374,11 @@ mod tests {
std::result::Result::Err(error) => panic!("recipient alias failed: {error}"), std::result::Result::Err(error) => panic!("recipient alias failed: {error}"),
}; };
let recipient_wallet = ks_wallet::TemporaryWallet::generate(recipient_alias); let recipient_wallet = ks_wallet::TemporaryWallet::generate(recipient_alias);
let transfer_lamports = std::env::var("KB_DEVNET_TRANSFER_LAMPORTS") let transfer_lamports = std::env::var("KS_DEVNET_TRANSFER_LAMPORTS")
.ok() .ok()
.and_then(|value| return value.parse::<u64>().ok()) .and_then(|value| return value.parse::<u64>().ok())
.unwrap_or(1_000_000); .unwrap_or(1_000_000);
let airdrop_lamports = std::env::var("KB_DEVNET_AIRDROP_LAMPORTS") let airdrop_lamports = std::env::var("KS_DEVNET_AIRDROP_LAMPORTS")
.ok() .ok()
.and_then(|value| return value.parse::<u64>().ok()) .and_then(|value| return value.parse::<u64>().ok())
.unwrap_or(100_000_000); .unwrap_or(100_000_000);

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/associated_token_account.rs // file: ks-pipeline-demo-scenarios/src/spl/associated_token_account.rs
// version: 11 // version: 12
//! Devnet ATA execution with stateful and canonical post-validation. //! Devnet ATA execution with stateful and canonical post-validation.
@@ -1071,14 +1071,14 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_operation_from_env() { async fn optional_devnet_operation_from_env() {
if std::env::var("KB_DEVNET_SPL_ATA_EXECUTION_TEST").ok().as_deref() if std::env::var("KS_DEVNET_SPL_ATA_EXECUTION_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
let operation_code = std::env::var("KB_DEVNET_SPL_ATA_OPERATION") let operation_code = std::env::var("KS_DEVNET_SPL_ATA_OPERATION")
.unwrap_or_else(|_| return "create_idempotent".to_string()); .unwrap_or_else(|_| return "create_idempotent".to_string());
let token_program = match std::env::var("KB_DEVNET_SPL_ATA_TOKEN_PROGRAM").ok().as_deref() { let token_program = match std::env::var("KS_DEVNET_SPL_ATA_TOKEN_PROGRAM").ok().as_deref() {
std::option::Option::Some("token_2022") => { std::option::Option::Some("token_2022") => {
ks_lib::ExSplAssociatedTokenProgram::Token2022 ks_lib::ExSplAssociatedTokenProgram::Token2022
}, },
@@ -1087,7 +1087,7 @@ mod tests {
}, },
std::option::Option::Some(value) => panic!("unsupported Token Program {value}"), std::option::Option::Some(value) => panic!("unsupported Token Program {value}"),
}; };
let submit = std::env::var("KB_DEVNET_SPL_ATA_SUBMIT").ok().as_deref() let submit = std::env::var("KS_DEVNET_SPL_ATA_SUBMIT").ok().as_deref()
== std::option::Option::Some("1"); == std::option::Option::Some("1");
let profile = example_devnet_profile(); let profile = example_devnet_profile();
let workspace_root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) let workspace_root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
@@ -1101,16 +1101,16 @@ mod tests {
let operation = match operation_code.as_str() { let operation = match operation_code.as_str() {
"create_idempotent" => ks_lib::ExSplAssociatedTokenAccountOperation::CreateIdempotent { "create_idempotent" => ks_lib::ExSplAssociatedTokenAccountOperation::CreateIdempotent {
wallet_owner: ks_lib::MdPubkey(wallet_pubkey), wallet_owner: ks_lib::MdPubkey(wallet_pubkey),
mint: ks_lib::MdPubkey(required_environment_value("KB_DEVNET_SPL_ATA_MINT")), mint: ks_lib::MdPubkey(required_environment_value("KS_DEVNET_SPL_ATA_MINT")),
token_program, token_program,
}, },
"recover_nested" => ks_lib::ExSplAssociatedTokenAccountOperation::RecoverNested { "recover_nested" => ks_lib::ExSplAssociatedTokenAccountOperation::RecoverNested {
wallet_owner: ks_lib::MdPubkey(wallet_pubkey), wallet_owner: ks_lib::MdPubkey(wallet_pubkey),
owner_mint: ks_lib::MdPubkey(required_environment_value( owner_mint: ks_lib::MdPubkey(required_environment_value(
"KB_DEVNET_SPL_ATA_OWNER_MINT", "KS_DEVNET_SPL_ATA_OWNER_MINT",
)), )),
nested_mint: ks_lib::MdPubkey(required_environment_value( nested_mint: ks_lib::MdPubkey(required_environment_value(
"KB_DEVNET_SPL_ATA_NESTED_MINT", "KS_DEVNET_SPL_ATA_NESTED_MINT",
)), )),
token_program, token_program,
}, },

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/memo.rs // file: ks-pipeline-demo-scenarios/src/spl/memo.rs
// version: 7 // version: 8
//! Devnet SPL Memo v4 execution with canonical post-validation. //! Devnet SPL Memo v4 execution with canonical post-validation.
@@ -810,21 +810,21 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_memo_execution_from_env() { async fn optional_devnet_memo_execution_from_env() {
if std::env::var("KB_DEVNET_MEMO_EXECUTION_TEST").ok().as_deref() if std::env::var("KS_DEVNET_MEMO_EXECUTION_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
let database_url = match std::env::var("KB_POSTGRES_TEST_URL") { let database_url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
panic!("KB_POSTGRES_TEST_URL is required: {error}"); panic!("KS_SECRET_POSTGRES_TEST_URL is required: {error}");
}, },
}; };
let mut profile = example_devnet_profile(); let mut profile = example_devnet_profile();
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url; profile.database.postgres.url = database_url;
if let std::result::Result::Ok(directory) = std::env::var("KB_DEVNET_WALLET_DIR") { if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory; profile.wallet.wallet_dir = directory;
} }
let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) { let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) {
@@ -852,7 +852,7 @@ mod tests {
format!("khadhroony-bot3 memo validation {}", uuid::Uuid::new_v4()), format!("khadhroony-bot3 memo validation {}", uuid::Uuid::new_v4()),
); );
request.post_validation_max_retries = 20; request.post_validation_max_retries = 20;
if std::env::var("KB_DEVNET_MEMO_SUBMIT").ok().as_deref() == std::option::Option::Some("1") if std::env::var("KS_DEVNET_MEMO_SUBMIT").ok().as_deref() == std::option::Option::Some("1")
{ {
request.submit = true; request.submit = true;
request.operator_confirmed = true; request.operator_confirmed = true;

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/token/execution.rs // file: ks-pipeline-demo-scenarios/src/spl/token/execution.rs
// version: 11 // version: 12
//! Devnet classic SPL Token execution with stateful and canonical post-validation. //! Devnet classic SPL Token execution with stateful and canonical post-validation.
@@ -1071,28 +1071,28 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_checked_transfer_simulation_and_submission_from_env() { async fn optional_devnet_checked_transfer_simulation_and_submission_from_env() {
if std::env::var("KB_DEVNET_SPL_TOKEN_EXECUTION_TEST").ok().as_deref() if std::env::var("KS_DEVNET_SPL_TOKEN_EXECUTION_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
let source = required_pubkey_env("KB_DEVNET_SPL_TOKEN_SOURCE"); let source = required_pubkey_env("KS_DEVNET_SPL_TOKEN_SOURCE");
let mint = required_pubkey_env("KB_DEVNET_SPL_TOKEN_MINT"); let mint = required_pubkey_env("KS_DEVNET_SPL_TOKEN_MINT");
let destination = required_pubkey_env("KB_DEVNET_SPL_TOKEN_DESTINATION"); let destination = required_pubkey_env("KS_DEVNET_SPL_TOKEN_DESTINATION");
let authority = required_pubkey_env("KB_DEVNET_SPL_TOKEN_AUTHORITY"); let authority = required_pubkey_env("KS_DEVNET_SPL_TOKEN_AUTHORITY");
let decimals = match std::env::var("KB_DEVNET_SPL_TOKEN_DECIMALS") { let decimals = match std::env::var("KS_DEVNET_SPL_TOKEN_DECIMALS") {
std::result::Result::Ok(value) => match value.parse::<u8>() { std::result::Result::Ok(value) => match value.parse::<u8>() {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("invalid Token decimals: {error}"), std::result::Result::Err(error) => panic!("invalid Token decimals: {error}"),
}, },
std::result::Result::Err(_) => 9, std::result::Result::Err(_) => 9,
}; };
let amount = match std::env::var("KB_DEVNET_SPL_TOKEN_AMOUNT") { let amount = match std::env::var("KS_DEVNET_SPL_TOKEN_AMOUNT") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => "1".to_string(), std::result::Result::Err(_) => "1".to_string(),
}; };
let mut profile = example_devnet_profile(); let mut profile = example_devnet_profile();
if let std::result::Result::Ok(directory) = std::env::var("KB_DEVNET_WALLET_DIR") { if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory; profile.wallet.wallet_dir = directory;
} }
let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) { let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) {
@@ -1119,7 +1119,7 @@ mod tests {
}, },
}, },
); );
if std::env::var("KB_DEVNET_SPL_TOKEN_SUBMIT").ok().as_deref() if std::env::var("KS_DEVNET_SPL_TOKEN_SUBMIT").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
let summary = match crate::simulate_devnet_spl_token( let summary = match crate::simulate_devnet_spl_token(
@@ -1146,10 +1146,10 @@ mod tests {
request.submit = true; request.submit = true;
request.operator_confirmed = true; request.operator_confirmed = true;
request.post_validation_max_retries = 20; request.post_validation_max_retries = 20;
let database_url = match std::env::var("KB_POSTGRES_TEST_URL") { let database_url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
panic!("KB_POSTGRES_TEST_URL is required for submission: {error}"); panic!("KS_SECRET_POSTGRES_TEST_URL is required for submission: {error}");
}, },
}; };
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
@@ -1244,17 +1244,17 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_recent_instruction_probe_from_env() { async fn optional_devnet_recent_instruction_probe_from_env() {
if std::env::var("KB_DEVNET_SPL_TOKEN_RECENT_PROBE_TEST").ok().as_deref() if std::env::var("KS_DEVNET_SPL_TOKEN_RECENT_PROBE_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
let source = required_pubkey_env("KB_DEVNET_SPL_TOKEN_SOURCE"); let source = required_pubkey_env("KS_DEVNET_SPL_TOKEN_SOURCE");
let mint = required_pubkey_env("KB_DEVNET_SPL_TOKEN_MINT"); let mint = required_pubkey_env("KS_DEVNET_SPL_TOKEN_MINT");
let destination = required_pubkey_env("KB_DEVNET_SPL_TOKEN_DESTINATION"); let destination = required_pubkey_env("KS_DEVNET_SPL_TOKEN_DESTINATION");
let authority = required_pubkey_env("KB_DEVNET_SPL_TOKEN_AUTHORITY"); let authority = required_pubkey_env("KS_DEVNET_SPL_TOKEN_AUTHORITY");
let native_account = required_pubkey_env("KB_DEVNET_SPL_TOKEN_NATIVE_ACCOUNT"); let native_account = required_pubkey_env("KS_DEVNET_SPL_TOKEN_NATIVE_ACCOUNT");
let decimals = match std::env::var("KB_DEVNET_SPL_TOKEN_DECIMALS") { let decimals = match std::env::var("KS_DEVNET_SPL_TOKEN_DECIMALS") {
std::result::Result::Ok(value) => match value.parse::<u8>() { std::result::Result::Ok(value) => match value.parse::<u8>() {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("invalid Token decimals: {error}"), std::result::Result::Err(error) => panic!("invalid Token decimals: {error}"),
@@ -1262,7 +1262,7 @@ mod tests {
std::result::Result::Err(_) => 9, std::result::Result::Err(_) => 9,
}; };
let mut profile = example_devnet_profile(); let mut profile = example_devnet_profile();
if let std::result::Result::Ok(directory) = std::env::var("KB_DEVNET_WALLET_DIR") { if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory; profile.wallet.wallet_dir = directory;
} }
let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) { let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/token/lifecycle.rs // file: ks-pipeline-demo-scenarios/src/spl/token/lifecycle.rs
// version: 10 // version: 11
//! Controlled Devnet lifecycle for freshly prepared classic SPL Token accounts. //! Controlled Devnet lifecycle for freshly prepared classic SPL Token accounts.
@@ -1500,24 +1500,24 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_controlled_lifecycle_from_env() { async fn optional_devnet_controlled_lifecycle_from_env() {
if std::env::var("KB_DEVNET_SPL_TOKEN_LIFECYCLE_TEST").ok().as_deref() if std::env::var("KS_DEVNET_SPL_TOKEN_LIFECYCLE_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
if std::env::var("KB_DEVNET_SPL_TOKEN_LIFECYCLE_SUBMIT").ok().as_deref() if std::env::var("KS_DEVNET_SPL_TOKEN_LIFECYCLE_SUBMIT").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
panic!("controlled lifecycle requires KB_DEVNET_SPL_TOKEN_LIFECYCLE_SUBMIT=1"); panic!("controlled lifecycle requires KS_DEVNET_SPL_TOKEN_LIFECYCLE_SUBMIT=1");
} }
let mut profile = example_devnet_profile(); let mut profile = example_devnet_profile();
if let std::result::Result::Ok(directory) = std::env::var("KB_DEVNET_WALLET_DIR") { if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory; profile.wallet.wallet_dir = directory;
} }
let database_url = match std::env::var("KB_POSTGRES_TEST_URL") { let database_url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
panic!("KB_POSTGRES_TEST_URL is required for lifecycle submission: {error}"); panic!("KS_SECRET_POSTGRES_TEST_URL is required for lifecycle submission: {error}");
}, },
}; };
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
@@ -1547,7 +1547,7 @@ mod tests {
std::option::Option::None => panic!("workspace root cannot be resolved"), std::option::Option::None => panic!("workspace root cannot be resolved"),
}; };
let observer = LifecycleTestObserver; let observer = LifecycleTestObserver;
let prepared_accounts = if std::env::var("KB_DEVNET_SPL_TOKEN_LIFECYCLE_PREPARE") let prepared_accounts = if std::env::var("KS_DEVNET_SPL_TOKEN_LIFECYCLE_PREPARE")
.ok() .ok()
.as_deref() .as_deref()
== std::option::Option::Some("1") == std::option::Option::Some("1")
@@ -1589,7 +1589,7 @@ mod tests {
}; };
if prepared_accounts.is_some() { if prepared_accounts.is_some() {
tokio::time::sleep(std::time::Duration::from_millis(optional_u64_env( tokio::time::sleep(std::time::Duration::from_millis(optional_u64_env(
"KB_DEVNET_SPL_TOKEN_LIFECYCLE_PREPARATION_SETTLE_DELAY_MS", "KS_DEVNET_SPL_TOKEN_LIFECYCLE_PREPARATION_SETTLE_DELAY_MS",
10_000, 10_000,
))) )))
.await; .await;
@@ -1603,11 +1603,11 @@ mod tests {
value.authority.clone(), value.authority.clone(),
), ),
std::option::Option::None => ( std::option::Option::None => (
required_pubkey_env("KB_DEVNET_SPL_TOKEN_LIFECYCLE_MINT"), required_pubkey_env("KS_DEVNET_SPL_TOKEN_LIFECYCLE_MINT"),
required_pubkey_env("KB_DEVNET_SPL_TOKEN_LIFECYCLE_SOURCE"), required_pubkey_env("KS_DEVNET_SPL_TOKEN_LIFECYCLE_SOURCE"),
required_pubkey_env("KB_DEVNET_SPL_TOKEN_LIFECYCLE_DESTINATION"), required_pubkey_env("KS_DEVNET_SPL_TOKEN_LIFECYCLE_DESTINATION"),
required_pubkey_env("KB_DEVNET_SPL_TOKEN_LIFECYCLE_DELEGATE"), required_pubkey_env("KS_DEVNET_SPL_TOKEN_LIFECYCLE_DELEGATE"),
required_pubkey_env("KB_DEVNET_SPL_TOKEN_LIFECYCLE_AUTHORITY"), required_pubkey_env("KS_DEVNET_SPL_TOKEN_LIFECYCLE_AUTHORITY"),
), ),
}; };
let mut request = crate::DevnetSplTokenLifecycleRequest::new( let mut request = crate::DevnetSplTokenLifecycleRequest::new(
@@ -1618,33 +1618,33 @@ mod tests {
delegate, delegate,
authority, authority,
); );
request.decimals = optional_u8_env("KB_DEVNET_SPL_TOKEN_LIFECYCLE_DECIMALS", 9); request.decimals = optional_u8_env("KS_DEVNET_SPL_TOKEN_LIFECYCLE_DECIMALS", 9);
request.mint_amount = ks_lib::ExSplClassicTokenAmount(optional_string_env( request.mint_amount = ks_lib::ExSplClassicTokenAmount(optional_string_env(
"KB_DEVNET_SPL_TOKEN_LIFECYCLE_MINT_AMOUNT", "KS_DEVNET_SPL_TOKEN_LIFECYCLE_MINT_AMOUNT",
"10", "10",
)); ));
request.transfer_amount = ks_lib::ExSplClassicTokenAmount(optional_string_env( request.transfer_amount = ks_lib::ExSplClassicTokenAmount(optional_string_env(
"KB_DEVNET_SPL_TOKEN_LIFECYCLE_TRANSFER_AMOUNT", "KS_DEVNET_SPL_TOKEN_LIFECYCLE_TRANSFER_AMOUNT",
"4", "4",
)); ));
request.approve_amount = ks_lib::ExSplClassicTokenAmount(optional_string_env( request.approve_amount = ks_lib::ExSplClassicTokenAmount(optional_string_env(
"KB_DEVNET_SPL_TOKEN_LIFECYCLE_APPROVE_AMOUNT", "KS_DEVNET_SPL_TOKEN_LIFECYCLE_APPROVE_AMOUNT",
"2", "2",
)); ));
request.submit = true; request.submit = true;
request.operator_confirmed = true; request.operator_confirmed = true;
request.post_validation_max_retries = 20; request.post_validation_max_retries = 20;
request.first_step_index = request.first_step_index =
optional_u8_env("KB_DEVNET_SPL_TOKEN_LIFECYCLE_FIRST_STEP_INDEX", 0); optional_u8_env("KS_DEVNET_SPL_TOKEN_LIFECYCLE_FIRST_STEP_INDEX", 0);
request.resume_predecessor_signature = if request.first_step_index > 0 { request.resume_predecessor_signature = if request.first_step_index > 0 {
std::option::Option::Some(ks_lib::MdSignature(required_string_env( std::option::Option::Some(ks_lib::MdSignature(required_string_env(
"KB_DEVNET_SPL_TOKEN_LIFECYCLE_RESUME_PREDECESSOR_SIGNATURE", "KS_DEVNET_SPL_TOKEN_LIFECYCLE_RESUME_PREDECESSOR_SIGNATURE",
))) )))
} else { } else {
std::option::Option::None std::option::Option::None
}; };
request.inter_step_delay_ms = request.inter_step_delay_ms =
optional_u64_env("KB_DEVNET_SPL_TOKEN_LIFECYCLE_INTER_STEP_DELAY_MS", 2_000); optional_u64_env("KS_DEVNET_SPL_TOKEN_LIFECYCLE_INTER_STEP_DELAY_MS", 2_000);
let decoders: std::vec::Vec<std::sync::Arc<dyn ks_lib::DcApiInstructionDecoder>> = let decoders: std::vec::Vec<std::sync::Arc<dyn ks_lib::DcApiInstructionDecoder>> =
std::vec![std::sync::Arc::new(ks_lib::DcSplTokenDecoder)]; std::vec![std::sync::Arc::new(ks_lib::DcSplTokenDecoder)];
let materializers: std::vec::Vec<std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>> = let materializers: std::vec::Vec<std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>> =

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/token_2022/devnet_scenarios.rs // file: ks-pipeline-demo-scenarios/src/spl/token_2022/devnet_scenarios.rs
// version: 9 // version: 10
//! Stable Devnet validation scenarios required to close milestone 0.4.6. //! Stable Devnet validation scenarios required to close milestone 0.4.6.
@@ -53,17 +53,17 @@ pub struct DevnetSplValidationScenario {
/// Returns the complete ordered Devnet scenario inventory for milestone 0.4.6. /// Returns the complete ordered Devnet scenario inventory for milestone 0.4.6.
pub fn devnet_spl_validation_scenarios() -> std::vec::Vec<crate::DevnetSplValidationScenario> { pub fn devnet_spl_validation_scenarios() -> std::vec::Vec<crate::DevnetSplValidationScenario> {
return vec![ return vec![
public_scenario("token_2022_mint_to_checked", "Token-2022 MintToChecked", ks_lib::EX_SPL_TOKEN_2022_MINT_TO_CHECKED_OPERATION, &["TOKEN_2022_MINT", "TOKEN_2022_SOURCE", "TOKEN_2022_AUTHORITY", "TOKEN_2022_DECIMALS", "TOKEN_2022_MINT_AMOUNT_RAW"]), public_scenario("token_2022_mint_to_checked", "Token-2022 MintToChecked", ks_lib::EX_SPL_TOKEN_2022_MINT_TO_CHECKED_OPERATION, &["KS_PUBLIC_DEVNET_TOKEN_2022_MINT", "KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE", "KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY", "KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS", "KS_PUBLIC_DEVNET_TOKEN_2022_MINT_AMOUNT_RAW"]),
public_scenario("token_2022_transfer_checked", "Token-2022 TransferChecked", ks_lib::EX_SPL_TOKEN_2022_TRANSFER_CHECKED_OPERATION, &["TOKEN_2022_SOURCE", "TOKEN_2022_MINT", "TOKEN_2022_DESTINATION", "TOKEN_2022_AUTHORITY", "TOKEN_2022_DECIMALS", "TOKEN_2022_TRANSFER_AMOUNT_RAW"]), public_scenario("token_2022_transfer_checked", "Token-2022 TransferChecked", ks_lib::EX_SPL_TOKEN_2022_TRANSFER_CHECKED_OPERATION, &["KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE", "KS_PUBLIC_DEVNET_TOKEN_2022_MINT", "KS_PUBLIC_DEVNET_TOKEN_2022_DESTINATION", "KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY", "KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS", "KS_PUBLIC_DEVNET_TOKEN_2022_TRANSFER_AMOUNT_RAW"]),
public_scenario("token_2022_approve_checked", "Token-2022 ApproveChecked", ks_lib::EX_SPL_TOKEN_2022_APPROVE_CHECKED_OPERATION, &["TOKEN_2022_SOURCE", "TOKEN_2022_MINT", "TOKEN_2022_DELEGATE", "TOKEN_2022_AUTHORITY", "TOKEN_2022_DECIMALS", "TOKEN_2022_APPROVE_AMOUNT_RAW"]), public_scenario("token_2022_approve_checked", "Token-2022 ApproveChecked", ks_lib::EX_SPL_TOKEN_2022_APPROVE_CHECKED_OPERATION, &["KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE", "KS_PUBLIC_DEVNET_TOKEN_2022_MINT", "KS_PUBLIC_DEVNET_TOKEN_2022_DELEGATE", "KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY", "KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS", "KS_PUBLIC_DEVNET_TOKEN_2022_APPROVE_AMOUNT_RAW"]),
public_scenario("token_2022_revoke", "Token-2022 Revoke", ks_lib::EX_SPL_TOKEN_2022_REVOKE_OPERATION, &["TOKEN_2022_SOURCE", "TOKEN_2022_AUTHORITY"]), public_scenario("token_2022_revoke", "Token-2022 Revoke", ks_lib::EX_SPL_TOKEN_2022_REVOKE_OPERATION, &["KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE", "KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY"]),
public_scenario("token_2022_burn_checked", "Token-2022 BurnChecked", ks_lib::EX_SPL_TOKEN_2022_BURN_CHECKED_OPERATION, &["TOKEN_2022_SOURCE", "TOKEN_2022_MINT", "TOKEN_2022_AUTHORITY", "TOKEN_2022_DECIMALS", "TOKEN_2022_BURN_AMOUNT_RAW"]), public_scenario("token_2022_burn_checked", "Token-2022 BurnChecked", ks_lib::EX_SPL_TOKEN_2022_BURN_CHECKED_OPERATION, &["KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE", "KS_PUBLIC_DEVNET_TOKEN_2022_MINT", "KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY", "KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS", "KS_PUBLIC_DEVNET_TOKEN_2022_BURN_AMOUNT_RAW"]),
public_scenario("token_2022_freeze_account", "Token-2022 FreezeAccount", ks_lib::EX_SPL_TOKEN_2022_FREEZE_ACCOUNT_OPERATION, &["TOKEN_2022_SOURCE", "TOKEN_2022_MINT", "TOKEN_2022_FREEZE_AUTHORITY"]), public_scenario("token_2022_freeze_account", "Token-2022 FreezeAccount", ks_lib::EX_SPL_TOKEN_2022_FREEZE_ACCOUNT_OPERATION, &["KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE", "KS_PUBLIC_DEVNET_TOKEN_2022_MINT", "KS_PUBLIC_DEVNET_TOKEN_2022_FREEZE_AUTHORITY"]),
public_scenario("token_2022_thaw_account", "Token-2022 ThawAccount", ks_lib::EX_SPL_TOKEN_2022_THAW_ACCOUNT_OPERATION, &["TOKEN_2022_SOURCE", "TOKEN_2022_MINT", "TOKEN_2022_FREEZE_AUTHORITY"]), public_scenario("token_2022_thaw_account", "Token-2022 ThawAccount", ks_lib::EX_SPL_TOKEN_2022_THAW_ACCOUNT_OPERATION, &["KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE", "KS_PUBLIC_DEVNET_TOKEN_2022_MINT", "KS_PUBLIC_DEVNET_TOKEN_2022_FREEZE_AUTHORITY"]),
public_scenario("token_2022_close_destination", "Token-2022 CloseAccount destination", ks_lib::EX_SPL_TOKEN_2022_CLOSE_ACCOUNT_OPERATION, &["TOKEN_2022_DESTINATION", "KB_DEVNET_WALLET_ADDRESS", "TOKEN_2022_AUTHORITY"]), public_scenario("token_2022_close_destination", "Token-2022 CloseAccount destination", ks_lib::EX_SPL_TOKEN_2022_CLOSE_ACCOUNT_OPERATION, &["KS_PUBLIC_DEVNET_TOKEN_2022_DESTINATION", "KS_PUBLIC_DEVNET_WALLET_ADDRESS", "KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY"]),
registry_scenario("elgamal_registry_create", "ElGamal Registry CreateRegistry", "spl.elgamal_registry.create_registry", &["ELGAMAL_REGISTRY_ADDRESS", "ELGAMAL_PUBKEY_BASE64", "PUBKEY_VALIDITY_PROOF_CONTEXT"]), registry_scenario("elgamal_registry_create", "ElGamal Registry CreateRegistry", "spl.elgamal_registry.create_registry", &["KS_PUBLIC_DEVNET_ELGAMAL_REGISTRY_ADDRESS", "KS_PUBLIC_DEVNET_ELGAMAL_PUBKEY_BASE64", "KS_PUBLIC_DEVNET_PUBKEY_VALIDITY_PROOF_CONTEXT"]),
registry_scenario("elgamal_registry_update", "ElGamal Registry UpdateRegistry", "spl.elgamal_registry.update_registry", &["ELGAMAL_REGISTRY_ADDRESS", "ELGAMAL_PUBKEY_BASE64", "PUBKEY_VALIDITY_PROOF_CONTEXT"]), registry_scenario("elgamal_registry_update", "ElGamal Registry UpdateRegistry", "spl.elgamal_registry.update_registry", &["KS_PUBLIC_DEVNET_ELGAMAL_REGISTRY_ADDRESS", "KS_PUBLIC_DEVNET_ELGAMAL_PUBKEY_BASE64", "KS_PUBLIC_DEVNET_PUBKEY_VALIDITY_PROOF_CONTEXT"]),
confidential_scenario("token_2022_configure_confidential_account", "Token-2022 ConfigureAccountWithRegistry", ks_lib::EX_SPL_TOKEN_2022_CONFIGURE_CONFIDENTIAL_TRANSFER_ACCOUNT_WITH_REGISTRY_OPERATION, &["TOKEN_2022_SOURCE", "TOKEN_2022_MINT", "ELGAMAL_REGISTRY_ADDRESS", "PUBKEY_VALIDITY_PROOF_CONTEXT"]), confidential_scenario("token_2022_configure_confidential_account", "Token-2022 ConfigureAccountWithRegistry", ks_lib::EX_SPL_TOKEN_2022_CONFIGURE_CONFIDENTIAL_TRANSFER_ACCOUNT_WITH_REGISTRY_OPERATION, &["KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE", "KS_PUBLIC_DEVNET_TOKEN_2022_MINT", "KS_PUBLIC_DEVNET_ELGAMAL_REGISTRY_ADDRESS", "KS_PUBLIC_DEVNET_PUBKEY_VALIDITY_PROOF_CONTEXT"]),
]; ];
} }

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/token_2022/fixture.rs // file: ks-pipeline-demo-scenarios/src/spl/token_2022/fixture.rs
// version: 4 // version: 5
//! Idempotent Token-2022 public scenario fixture preparation. //! Idempotent Token-2022 public scenario fixture preparation.
@@ -376,7 +376,7 @@ fn path_text(path: &std::path::Path) -> ks_core::Result<std::string::String> {
fn render_fixture(summary: &crate::Token2022FixturePreparationSummary) -> std::string::String { fn render_fixture(summary: &crate::Token2022FixturePreparationSummary) -> std::string::String {
return format!( return format!(
"export TOKEN_2022_PROGRAM={}\nexport TOKEN_2022_MINT={}\nexport TOKEN_2022_SOURCE={}\nexport TOKEN_2022_DESTINATION={}\nexport TOKEN_2022_CLOSE_ACCOUNT={}\nexport TOKEN_2022_DELEGATE={}\nexport TOKEN_2022_AUTHORITY={}\nexport TOKEN_2022_FREEZE_AUTHORITY={}\nexport TOKEN_2022_DECIMALS={}\nexport TOKEN_2022_MINT_AMOUNT_RAW={}\nexport TOKEN_2022_TRANSFER_AMOUNT_RAW={}\nexport TOKEN_2022_APPROVE_AMOUNT_RAW={}\nexport TOKEN_2022_BURN_AMOUNT_RAW={}\nexport KB_DEVNET_WALLET_ADDRESS={}\n", "export KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_MINT={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_DESTINATION={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_CLOSE_ACCOUNT={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_DELEGATE={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_FREEZE_AUTHORITY={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_MINT_AMOUNT_RAW={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_TRANSFER_AMOUNT_RAW={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_APPROVE_AMOUNT_RAW={}\nexport KS_PUBLIC_DEVNET_TOKEN_2022_BURN_AMOUNT_RAW={}\nexport KS_PUBLIC_DEVNET_WALLET_ADDRESS={}\n",
summary.program_id, summary.program_id,
summary.mint, summary.mint,
summary.source, summary.source,
@@ -444,8 +444,8 @@ mod tests {
assert!(fixture.lines().any(|line| return line.starts_with(format!("export {variable}=").as_str())), "missing {variable}"); assert!(fixture.lines().any(|line| return line.starts_with(format!("export {variable}=").as_str())), "missing {variable}");
} }
} }
assert!(fixture.contains("export TOKEN_2022_CLOSE_ACCOUNT=close\n")); assert!(fixture.contains("export KS_PUBLIC_DEVNET_TOKEN_2022_CLOSE_ACCOUNT=close\n"));
assert!(fixture.contains("export KB_DEVNET_WALLET_ADDRESS=authority\n")); assert!(fixture.contains("export KS_PUBLIC_DEVNET_WALLET_ADDRESS=authority\n"));
} }
#[test] #[test]

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/token_2022/metadata/campaign.rs // file: ks-pipeline-demo-scenarios/src/spl/token_2022/metadata/campaign.rs
// version: 5 // version: 6
//! Ordered confirmed Devnet campaign for the five Token-2022 Token Metadata instructions. //! Ordered confirmed Devnet campaign for the five Token-2022 Token Metadata instructions.
@@ -479,25 +479,25 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_token_2022_metadata_campaign_from_env() { async fn optional_devnet_token_2022_metadata_campaign_from_env() {
if std::env::var("KB_DEVNET_TOKEN_2022_METADATA_CAMPAIGN_TEST").ok().as_deref() if std::env::var("KS_DEVNET_TOKEN_2022_METADATA_CAMPAIGN_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
if std::env::var("KB_DEVNET_TOKEN_2022_METADATA_OPERATOR_CONFIRMED") if std::env::var("KS_DEVNET_TOKEN_2022_METADATA_OPERATOR_CONFIRMED")
.ok() .ok()
.as_deref() .as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
panic!( panic!(
"KB_DEVNET_TOKEN_2022_METADATA_OPERATOR_CONFIRMED=1 is required for the spending campaign" "KS_DEVNET_TOKEN_2022_METADATA_OPERATOR_CONFIRMED=1 is required for the spending campaign"
); );
} }
let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() { let workspace_root = match std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent() {
std::option::Option::Some(value) => value, std::option::Option::Some(value) => value,
std::option::Option::None => panic!("workspace root cannot be resolved"), std::option::Option::None => panic!("workspace root cannot be resolved"),
}; };
let config_path = match std::env::var("KB_DEVNET_CONFIG_PATH") { let config_path = match std::env::var("KS_DEVNET_CONFIG_PATH") {
std::result::Result::Ok(value) => { std::result::Result::Ok(value) => {
let path = std::path::PathBuf::from(value); let path = std::path::PathBuf::from(value);
if path.is_absolute() { path } else { workspace_root.join(path) } if path.is_absolute() { path } else { workspace_root.join(path) }
@@ -509,11 +509,11 @@ mod tests {
workspace_root, workspace_root,
) )
.unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}")); .unwrap_or_else(|error| panic!("Devnet configuration loading failed: {error}"));
let profile_name = std::env::var("KB_DEVNET_PROFILE").ok(); let profile_name = std::env::var("KS_DEVNET_PROFILE").ok();
let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref()) let mut profile = crate::resolve_demo_devnet_profile(&config, profile_name.as_deref())
.unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}")); .unwrap_or_else(|error| panic!("Devnet profile resolution failed: {error}"));
let database_url = std::env::var("KB_POSTGRES_TEST_URL") let database_url = std::env::var("KS_SECRET_POSTGRES_TEST_URL")
.unwrap_or_else(|error| panic!("KB_POSTGRES_TEST_URL is required: {error}")); .unwrap_or_else(|error| panic!("KS_SECRET_POSTGRES_TEST_URL is required: {error}"));
profile.database.backend = "postgres".to_string(); profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url; profile.database.postgres.url = database_url;
let pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile) let pool = ks_onchain_transport::HttpEndpointPool::from_profile(&profile)

View File

@@ -1,8 +1,13 @@
<!-- file: ks-pipeline/CHANGELOG.md --> <!-- file: ks-pipeline/CHANGELOG.md -->
<!-- version: 32 --> <!-- version: 33 -->
# CHANGELOG — ks-pipeline # CHANGELOG — ks-pipeline
## `0.5.1-pre.004`
- migre les variables des tests Devnet SPL Token vers le namespace interne `KS_*` ;
- ne modifie aucune orchestration, opération, simulation ou postcondition.
## `0.5.1-pre.003` ## `0.5.1-pre.003`
- aligne les tests d'orchestration sur les nouvelles identités d'exécuteurs `ks-lib-executor.*` ; - aligne les tests d'orchestration sur les nouvelles identités d'exécuteurs `ks-lib-executor.*` ;

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline/src/spl_token_stateful.rs // file: ks-pipeline/src/spl_token_stateful.rs
// version: 3 // version: 4
//! Stateful Localnet and Devnet readiness checks for classic SPL Token operations. //! Stateful Localnet and Devnet readiness checks for classic SPL Token operations.
@@ -1614,45 +1614,45 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_devnet_checked_transfer_readiness_from_env() { async fn optional_devnet_checked_transfer_readiness_from_env() {
if std::env::var("KB_DEVNET_SPL_TOKEN_PREFLIGHT_TEST").ok().as_deref() if std::env::var("KS_DEVNET_SPL_TOKEN_PREFLIGHT_TEST").ok().as_deref()
!= std::option::Option::Some("1") != std::option::Option::Some("1")
{ {
return; return;
} }
let source = match std::env::var("KB_DEVNET_SPL_TOKEN_SOURCE") { let source = match std::env::var("KS_DEVNET_SPL_TOKEN_SOURCE") {
std::result::Result::Ok(value) => ks_lib::MdPubkey(value), std::result::Result::Ok(value) => ks_lib::MdPubkey(value),
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
panic!("KB_DEVNET_SPL_TOKEN_SOURCE is required: {error}"); panic!("KS_DEVNET_SPL_TOKEN_SOURCE is required: {error}");
}, },
}; };
let mint = match std::env::var("KB_DEVNET_SPL_TOKEN_MINT") { let mint = match std::env::var("KS_DEVNET_SPL_TOKEN_MINT") {
std::result::Result::Ok(value) => ks_lib::MdPubkey(value), std::result::Result::Ok(value) => ks_lib::MdPubkey(value),
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
panic!("KB_DEVNET_SPL_TOKEN_MINT is required: {error}"); panic!("KS_DEVNET_SPL_TOKEN_MINT is required: {error}");
}, },
}; };
let destination = match std::env::var("KB_DEVNET_SPL_TOKEN_DESTINATION") { let destination = match std::env::var("KS_DEVNET_SPL_TOKEN_DESTINATION") {
std::result::Result::Ok(value) => ks_lib::MdPubkey(value), std::result::Result::Ok(value) => ks_lib::MdPubkey(value),
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
panic!("KB_DEVNET_SPL_TOKEN_DESTINATION is required: {error}"); panic!("KS_DEVNET_SPL_TOKEN_DESTINATION is required: {error}");
}, },
}; };
let authority = match std::env::var("KB_DEVNET_SPL_TOKEN_AUTHORITY") { let authority = match std::env::var("KS_DEVNET_SPL_TOKEN_AUTHORITY") {
std::result::Result::Ok(value) => ks_lib::MdPubkey(value), std::result::Result::Ok(value) => ks_lib::MdPubkey(value),
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
panic!("KB_DEVNET_SPL_TOKEN_AUTHORITY is required: {error}"); panic!("KS_DEVNET_SPL_TOKEN_AUTHORITY is required: {error}");
}, },
}; };
let decimals = match std::env::var("KB_DEVNET_SPL_TOKEN_DECIMALS") { let decimals = match std::env::var("KS_DEVNET_SPL_TOKEN_DECIMALS") {
std::result::Result::Ok(value) => match value.parse::<u8>() { std::result::Result::Ok(value) => match value.parse::<u8>() {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => { std::result::Result::Err(error) => {
panic!("KB_DEVNET_SPL_TOKEN_DECIMALS must be a u8: {error}"); panic!("KS_DEVNET_SPL_TOKEN_DECIMALS must be a u8: {error}");
}, },
}, },
std::result::Result::Err(_) => 9, std::result::Result::Err(_) => 9,
}; };
let amount = match std::env::var("KB_DEVNET_SPL_TOKEN_AMOUNT") { let amount = match std::env::var("KS_DEVNET_SPL_TOKEN_AMOUNT") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => "1".to_string(), std::result::Result::Err(_) => "1".to_string(),
}; };

View File

@@ -1,8 +1,14 @@
<!-- file: ks-store/CHANGELOG.md --> <!-- file: ks-store/CHANGELOG.md -->
<!-- version: 14 --> <!-- version: 15 -->
# CHANGELOG — ks-store # CHANGELOG — ks-store
## `0.5.1-pre.004`
- migre la variable des tests PostgreSQL optionnels vers `KS_SECRET_POSTGRES_TEST_URL` ;
- renomme le helper SQL de rollback réservé aux tests de `kb_test_reject_decode_ledger` vers `ks_test_reject_decode_ledger` ;
- ne modifie aucune migration, table, requête SQL ou identité persistée.
## `0.5.1-pre.003` ## `0.5.1-pre.003`
- aligne le contrat de test de persistance/replay sur l'identité de décodeur `ks-lib-decoder.*` ; - aligne le contrat de test de persistance/replay sur l'identité de décodeur `ks-lib-decoder.*` ;

View File

@@ -1,5 +1,5 @@
// file: ks-store/src/postgres/query/core_extraction_queries.rs // file: ks-store/src/postgres/query/core_extraction_queries.rs
// version: 3 // version: 4
//! PostgreSQL queries for atomic canonical transaction to core extraction. //! PostgreSQL queries for atomic canonical transaction to core extraction.
@@ -779,7 +779,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_postgres_core_extraction_rolls_back_partial_graph_from_env() { async fn optional_postgres_core_extraction_rolls_back_partial_graph_from_env() {
let database_url = match std::env::var("KB_POSTGRES_TEST_URL") { let database_url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(_error) => return, std::result::Result::Err(_error) => return,
}; };

View File

@@ -1,5 +1,5 @@
// file: ks-store/src/postgres/query/core_queries.rs // file: ks-store/src/postgres/query/core_queries.rs
// version: 3 // version: 4
//! PostgreSQL queries for normalized Solana core storage. //! PostgreSQL queries for normalized Solana core storage.
@@ -986,7 +986,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_postgres_core_store_roundtrip_from_env() { async fn optional_postgres_core_store_roundtrip_from_env() {
let database_url = match std::env::var("KB_POSTGRES_TEST_URL") { let database_url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(_error) => return, std::result::Result::Err(_error) => return,
}; };

View File

@@ -1,5 +1,5 @@
// file: ks-store/src/postgres/query/decode_pipeline_queries.rs // file: ks-store/src/postgres/query/decode_pipeline_queries.rs
// version: 6 // version: 7
//! PostgreSQL queries for contextual decode, coverage and materialization persistence. //! PostgreSQL queries for contextual decode, coverage and materialization persistence.
@@ -1029,7 +1029,7 @@ mod tests {
} }
async fn test_pool_from_env() -> std::option::Option<sqlx::PgPool> { async fn test_pool_from_env() -> std::option::Option<sqlx::PgPool> {
let url = match std::env::var("KB_POSTGRES_TEST_URL") { let url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) if !value.trim().is_empty() => value, std::result::Result::Ok(value) if !value.trim().is_empty() => value,
_ => return std::option::Option::None, _ => return std::option::Option::None,
}; };
@@ -1207,7 +1207,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn decoded_events_and_ledger_roll_back_together() { async fn decoded_events_and_ledger_roll_back_together() {
let url = match std::env::var("KB_POSTGRES_TEST_URL") { let url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) if !value.trim().is_empty() => value, std::result::Result::Ok(value) if !value.trim().is_empty() => value,
_ => return, _ => return,
}; };
@@ -1236,17 +1236,17 @@ mod tests {
.await; .await;
execute_sql( execute_sql(
&pool, &pool,
"CREATE OR REPLACE FUNCTION kb_test_reject_decode_ledger() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF NEW.processor_name = 'decode_atomic_rollback_test' THEN RAISE EXCEPTION 'forced decode ledger failure'; END IF; RETURN NEW; END; $$", "CREATE OR REPLACE FUNCTION ks_test_reject_decode_ledger() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF NEW.processor_name = 'decode_atomic_rollback_test' THEN RAISE EXCEPTION 'forced decode ledger failure'; END IF; RETURN NEW; END; $$",
) )
.await; .await;
execute_sql( execute_sql(
&pool, &pool,
"DROP TRIGGER IF EXISTS kb_test_reject_decode_ledger_trigger ON kb_sol_ops_processing_ledger", "DROP TRIGGER IF EXISTS ks_test_reject_decode_ledger_trigger ON kb_sol_ops_processing_ledger",
) )
.await; .await;
execute_sql( execute_sql(
&pool, &pool,
"CREATE TRIGGER kb_test_reject_decode_ledger_trigger BEFORE INSERT OR UPDATE ON kb_sol_ops_processing_ledger FOR EACH ROW EXECUTE FUNCTION kb_test_reject_decode_ledger()", "CREATE TRIGGER ks_test_reject_decode_ledger_trigger BEFORE INSERT OR UPDATE ON kb_sol_ops_processing_ledger FOR EACH ROW EXECUTE FUNCTION ks_test_reject_decode_ledger()",
) )
.await; .await;
let identity_result = crate::ProcessingLedgerIdentity::new( let identity_result = crate::ProcessingLedgerIdentity::new(
@@ -1332,9 +1332,9 @@ mod tests {
assert_eq!(ledger_count, 0); assert_eq!(ledger_count, 0);
execute_sql( execute_sql(
&pool, &pool,
"DROP TRIGGER IF EXISTS kb_test_reject_decode_ledger_trigger ON kb_sol_ops_processing_ledger", "DROP TRIGGER IF EXISTS ks_test_reject_decode_ledger_trigger ON kb_sol_ops_processing_ledger",
) )
.await; .await;
execute_sql(&pool, "DROP FUNCTION IF EXISTS kb_test_reject_decode_ledger()").await; execute_sql(&pool, "DROP FUNCTION IF EXISTS ks_test_reject_decode_ledger()").await;
} }
} }

View File

@@ -1,5 +1,5 @@
// file: ks-store/src/postgres/query/raw_queries.rs // file: ks-store/src/postgres/query/raw_queries.rs
// version: 3 // version: 4
//! PostgreSQL canonical transaction and acquisition observation SQL queries. //! PostgreSQL canonical transaction and acquisition observation SQL queries.
@@ -374,7 +374,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_postgres_canonical_store_roundtrip_from_env() { async fn optional_postgres_canonical_store_roundtrip_from_env() {
let database_url = match std::env::var("KB_POSTGRES_TEST_URL") { let database_url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(_error) => return, std::result::Result::Err(_error) => return,
}; };

View File

@@ -1,5 +1,5 @@
// file: ks-store/src/postgres/query/replay_candidate_queries.rs // file: ks-store/src/postgres/query/replay_candidate_queries.rs
// version: 3 // version: 4
//! Read-only PostgreSQL queries for replay candidate discovery. //! Read-only PostgreSQL queries for replay candidate discovery.
@@ -396,7 +396,7 @@ fn optional_sql_bigint(
mod tests { mod tests {
#[tokio::test] #[tokio::test]
async fn optional_postgres_replay_candidate_queries_from_env() { async fn optional_postgres_replay_candidate_queries_from_env() {
let database_url = match std::env::var("KB_POSTGRES_TEST_URL") { let database_url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(_error) => return, std::result::Result::Err(_error) => return,
}; };

View File

@@ -1,5 +1,5 @@
// file: ks-store/src/postgres/store.rs // file: ks-store/src/postgres/store.rs
// version: 3 // version: 4
//! Store implementation scaffold for the `ks-store` crate. //! Store implementation scaffold for the `ks-store` crate.
@@ -467,7 +467,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn optional_postgres_healthcheck_from_env() { async fn optional_postgres_healthcheck_from_env() {
let database_url = match std::env::var("KB_POSTGRES_TEST_URL") { let database_url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) => value, std::result::Result::Ok(value) => value,
std::result::Result::Err(_error) => return, std::result::Result::Err(_error) => return,
}; };

View File

@@ -1,5 +1,5 @@
<!-- file: prompts/030_v0_5_1_khadhroony_solana_namespace_and_config.md --> <!-- file: prompts/030_v0_5_1_khadhroony_solana_namespace_and_config.md -->
<!-- version: 2 --> <!-- version: 3 -->
# Khadhroony Bot3 — `0.5.1` — migration Khadhroony Solana et configuration sûre # Khadhroony Bot3 — `0.5.1` — migration Khadhroony Solana et configuration sûre
@@ -10,7 +10,7 @@ Reprendre `khadhroony-bot3` après la clôture validée de `0.5.0` et exécuter
`0.5.1` doit accomplir deux objectifs liés : `0.5.1` doit accomplir deux objectifs liés :
1. séparer explicitement le domaine des bibliothèques Solana généralistes du domaine applicatif Khadhroony Bot en migrant les bibliothèques vers les namespaces `ks-*` / `ks_*` ; 1. séparer explicitement le domaine des bibliothèques Solana généralistes du domaine applicatif Khadhroony Bot en migrant les bibliothèques vers les namespaces `ks-*` / `ks_*` ;
2. restructurer la configuration sur cette nouvelle fondation, avec namespace d'environnement `KS_*`, séparation du logging et politique stricte de non-divulgation des secrets. 2. restructurer la configuration sur cette nouvelle fondation, avec `KS_*` pour les contrats Solana, `KB_*` réservé aux contrats Bot, séparation du logging et politique stricte de non-divulgation des secrets.
Cette version est une migration de fondation. Elle ne doit pas ouvrir de nouveau programme Anchor/DEX et ne doit pas absorber prématurément les chantiers `ks-wallet`, `ks-store` ou de complétude des scénarios réservés respectivement à `0.5.2`, `0.5.3` et `0.5.4`. Cette version est une migration de fondation. Elle ne doit pas ouvrir de nouveau programme Anchor/DEX et ne doit pas absorber prématurément les chantiers `ks-wallet`, `ks-store` ou de complétude des scénarios réservés respectivement à `0.5.2`, `0.5.3` et `0.5.4`.
@@ -21,7 +21,7 @@ La release `0.5.0` est une version de cadrage sans restructuration runtime majeu
- la séparation de domaine entre `khadhroony-solana` et `khadhroony-bot` ; - la séparation de domaine entre `khadhroony-solana` et `khadhroony-bot` ;
- l'inventaire des frontières de configuration, logging, wallet, store, scénarios et desktop ; - l'inventaire des frontières de configuration, logging, wallet, store, scénarios et desktop ;
- la cible de renommage des dix crates Solana généralistes ; - la cible de renommage des dix crates Solana généralistes ;
- la convention d'environnement `KS_*` ; - la convention d'environnement par ownership : `KS_*` pour Khadhroony Solana et `KB_*` pour les futurs contrats spécifiques au Bot ;
- le split obligatoire de la configuration généraliste et de la configuration logging ; - le split obligatoire de la configuration généraliste et de la configuration logging ;
- la nécessité de séparer configuration source, runtime résolue et surfaces publiques/diagnostiques ; - la nécessité de séparer configuration source, runtime résolue et surfaces publiques/diagnostiques ;
- la migration future des identités techniques `kb-lib.*` vers le domaine `ks-lib-*` ; - la migration future des identités techniques `kb-lib.*` vers le domaine `ks-lib-*` ;
@@ -76,8 +76,8 @@ Elle doit produire au minimum :
- la table exhaustive des dix crates et identifiants Rust à migrer ; - la table exhaustive des dix crates et identifiants Rust à migrer ;
- la table des dépendances workspace et ordre de renommage ; - la table des dépendances workspace et ordre de renommage ;
- l'inventaire des noms de packages, bins, libs, imports, exports, tests externes, scripts et documentation concernés ; - l'inventaire des noms de packages, bins, libs, imports, exports, tests externes, scripts et documentation concernés ;
- l'inventaire exhaustif des variables d'environnement actuellement utilisées et leur nouveau nom `KS_*` ; - l'inventaire exhaustif des variables d'environnement actuellement utilisées, leur propriétaire `KS` ou `KB` et leur nom canonique ;
- la classification de chaque variable en `KS_SECRET_*`, `KS_PUBLIC_*` ou `KS_*` interne ; - la classification de chaque variable en `*_SECRET_*`, `*_PUBLIC_*` ou interne dans le namespace de son propriétaire ;
- l'inventaire des identités runtime/persistées et targets techniques à migrer ; - l'inventaire des identités runtime/persistées et targets techniques à migrer ;
- l'inventaire des payloads Tauri/TS-RS pouvant actuellement transporter de la configuration résolue ; - l'inventaire des payloads Tauri/TS-RS pouvant actuellement transporter de la configuration résolue ;
- l'inventaire des structures dupliquées entre configuration et logging ; - l'inventaire des structures dupliquées entre configuration et logging ;
@@ -172,45 +172,22 @@ Cependant, le renommage physique des tables et la normalisation des migrations a
## Namespace obligatoire des variables d'environnement ## Namespace obligatoire des variables d'environnement
Après migration, toute variable d'environnement appartenant au workspace doit commencer par `KS_`. Le namespace suit le propriétaire fonctionnel du contrat :
La convention retenue est :
```text ```text
KS_SECRET_* secret absolu Khadhroony Solana / ks-* : KS_SECRET_* / KS_PUBLIC_* / KS_*
KS_PUBLIC_* valeur explicitement candidate à une surface publique Khadhroony Bot / kb-* : KB_SECRET_* / KB_PUBLIC_* / KB_*
KS_* valeur interne/diagnostique
``` ```
Une ancienne variable `KB_*` ou une variable projet sans préfixe `KS_` ne doit pas subsister dans le code, les exemples, tests ou documentation après fermeture de la migration. Une variable de scénario ou de configuration Solana reste `KS_*` même si `kb-app-demo-desktop` la consomme. `KB_*` est réservé aux besoins réellement propres au desktop ou aux futures crates du Bot. Les variables standard de l'OS, de Cargo ou d'outils tiers ne sont pas renommées artificiellement.
Les variables du système d'exploitation ou de dépendances tierces ne sont pas renommées artificiellement si elles ne constituent pas un contrat de configuration Khadhroony. Les classes ont la même sémantique dans les deux namespaces :
### `KS_SECRET_*` - `*_SECRET_*` : secret absolu, jamais exposé ni loggé ;
- `*_PUBLIC_*` : candidate explicite à une surface publique, sans autorisation automatique d'exposition ;
- autres `KS_*` / `KB_*` : internes, absentes des payloads normaux.
Une valeur issue de `KS_SECRET_*` : La migration des noms et la fermeture des alias legacy appartiennent à `pre.004`. La propagation de sensibilité dans les valeurs composées, le camouflage et les DTO publics sûrs sont réalisés après le split config/logging.
- peut être utilisée côté backend lorsque nécessaire ;
- ne doit jamais apparaître dans les logs ;
- ne doit jamais apparaître dans une erreur publique ;
- ne doit jamais être sérialisée vers Tauri ;
- ne doit jamais être exposée dans un diagnostic, même debug ;
- ne doit jamais être exportée par TS-RS comme valeur résolue ;
- doit rester secrète lorsqu'elle est incorporée dans une URL, DSN ou autre valeur composée.
Un diagnostic peut indiquer qu'un secret est configuré ou absent sans exposer sa valeur.
### `KS_PUBLIC_*`
Le préfixe `KS_PUBLIC_*` classe la variable comme publiable, mais ne constitue pas une autorisation automatique de parcourir l'environnement et de l'envoyer au frontend.
L'exposition doit être explicitement définie par un DTO ou une API publique.
### autres `KS_*`
Les autres variables `KS_*` sont internes. Elles ne sont pas exposées par les payloads normaux. Elles peuvent apparaître dans un diagnostic explicitement demandé lorsque leur sémantique n'est pas sensible.
Le simple fait de compiler en mode debug ne doit pas automatiquement exposer toutes les valeurs internes.
## Split obligatoire de la configuration ## Split obligatoire de la configuration
@@ -248,7 +225,7 @@ La restructuration doit empêcher qu'une configuration résolue complète puisse
Distinguer au minimum : Distinguer au minimum :
1. représentation source : fichiers, placeholders et références `${KS_*}` ; 1. représentation source : fichiers, placeholders et références `${KS_*}` / `${KB_*}` ;
2. représentation runtime : valeurs validées et résolues nécessaires au backend ; 2. représentation runtime : valeurs validées et résolues nécessaires au backend ;
3. représentation publique/diagnostique : DTO explicitement construits pour l'UI, les diagnostics ou une API externe. 3. représentation publique/diagnostique : DTO explicitement construits pour l'UI, les diagnostics ou une API externe.
@@ -302,12 +279,12 @@ Les commandes Tauri restent des adaptateurs minces :
Ajouter des tests prouvant notamment que : Ajouter des tests prouvant notamment que :
- une sentinelle issue de `KS_SECRET_*` n'apparaît dans aucune sérialisation publique ; - une sentinelle issue de `KS_SECRET_*` ou `KB_SECRET_*` n'apparaît dans aucune sérialisation publique ;
- elle n'apparaît pas dans les erreurs publiques ; - elle n'apparaît pas dans les erreurs publiques ;
- elle n'apparaît pas dans les diagnostics debug ; - elle n'apparaît pas dans les diagnostics debug ;
- une URL ou DSN composée avec un secret est entièrement traitée comme sensible ; - une URL ou DSN composée avec un secret est entièrement traitée comme sensible ;
- `KS_PUBLIC_*` n'est exposé que par une surface explicitement autorisée ; - `KS_PUBLIC_*` / `KB_PUBLIC_*` n'est exposé que par une surface explicitement autorisée ;
- une variable `KS_*` interne n'apparaît pas dans le payload normal ; - une variable interne `KS_*` / `KB_*` n'apparaît pas dans le payload normal ;
- les anciens noms d'environnement sont absents après migration ; - les anciens noms d'environnement sont absents après migration ;
- les schémas JSON général et logging valident leurs documents respectifs ; - les schémas JSON général et logging valident leurs documents respectifs ;
- le choix d'un profil logging est indépendant du profil général ; - le choix d'un profil logging est indépendant du profil général ;
@@ -336,29 +313,36 @@ Le détail doit être confirmé par `0.5.1-pre.001`, mais la trajectoire cible e
- maintenir un workspace compilable et auditable ; - maintenir un workspace compilable et auditable ;
- conserver `kb-app-demo-desktop`. - conserver `kb-app-demo-desktop`.
### `0.5.1-pre.003` — identités techniques et environnement `KS_*` ### `0.5.1-pre.003` — identités techniques `ks-lib-*`
- migrer les targets/processor identities généralistes ; - migrer les targets et identités runtime/persistables généralistes ;
- migrer les variables d'environnement ; - synchroniser matrices, tracing, diagnostics et provenance/replay ;
- mettre en place la classification Secret/Public/Internal ; - conserver encore les variables d'environnement pour la prerelease suivante.
- mettre à jour exemples et tests sans encore réinventer le store SQL.
### `0.5.1-pre.004` — split configuration/logging ### `0.5.1-pre.004` — environnement et classification nominale
- migrer les contrats Solana vers `KS_*` et réserver `KB_*` aux futurs contrats Bot ;
- classer les secrets en `*_SECRET_*`, les valeurs explicitement publiques en `*_PUBLIC_*` et le reste en interne ;
- consolider les alias historiques Token-2022 ;
- mettre à jour `.env.example`, configuration, fixtures, scénarios, store, desktop et guides ;
- ne pas encore implémenter le camouflage ou la propagation de sensibilité.
### `0.5.1-pre.005` — split configuration/logging
- documents et schémas indépendants ; - documents et schémas indépendants ;
- profils logging indépendants ; - profils logging indépendants ;
- propriété unique des contrats logging ; - propriété unique des contrats logging ;
- migration/compatibilité explicite des fichiers `0.5.0`. - migration/compatibilité explicite du document monolithique précédent.
### `0.5.1-pre.005` — runtime/public et Tauri sûr ### `0.5.1-pre.006` — runtime/public, camouflage et Tauri sûr
- séparer source/runtime/public ; - séparer source/runtime/public/diagnostic ;
- propager la sensibilité des valeurs composées ;
- supprimer les payloads de config complète ; - supprimer les payloads de config complète ;
- diagnostics sûrs ; - diagnostics sûrs et camouflage systématique ;
- tests de non-divulgation ; - tests de non-divulgation et TS-RS aligné.
- TS-RS aligné.
### `0.5.1-pre.006` — réconciliation et clôture ### `0.5.1-pre.007` — réconciliation et clôture
- audit exhaustif des anciens préfixes ; - audit exhaustif des anciens préfixes ;
- documentation finale ; - documentation finale ;
@@ -367,7 +351,7 @@ Le détail doit être confirmé par `0.5.1-pre.001`, mais la trajectoire cible e
- archivage du plan/prompt ; - archivage du plan/prompt ;
- préparation de `0.5.2`. - préparation de `0.5.2`.
Ce découpage peut évoluer si `pre.001` démontre qu'une étape doit être scindée pour garder chaque prerelease compilable et bornée. Ce découpage reste borné : aucun chantier SQL `k_sol_*`, wallet ou DEX n'est absorbé dans `0.5.1`.
## Règles de développement à conserver ## Règles de développement à conserver

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# file: scripts/audit_khadhroony_workspace_rules.py # file: scripts/audit_khadhroony_workspace_rules.py
# version: 19 # version: 20
"""Audit mechanically verifiable rules specific to khadhroony-bot3.""" """Audit mechanically verifiable rules specific to khadhroony-bot3."""
@@ -864,6 +864,83 @@ def audit_private_ks_lib_paths_in_active_docs(root: pathlib.Path) -> list[Violat
return violations return violations
def audit_environment_namespaces(root: pathlib.Path) -> list[Violation]:
"""Require workspace-owned environment variables to use KS_* or KB_* namespaces."""
violations: list[Violation] = []
rust_pattern = re.compile(
r'std::env::(?:var|var_os|set_var|remove_var)\(\s*"([A-Z][A-Z0-9_]*)"'
)
rust_roots = [path.parent for path in sorted(root.glob("ks-*/Cargo.toml"))]
desktop = root / "kb-app-demo-desktop"
if desktop.is_dir():
rust_roots.append(desktop)
for rust_root in rust_roots:
for path in sorted((rust_root / "src").rglob("*.rs")):
relative = path.relative_to(root).as_posix()
text = path.read_text(encoding="utf-8")
for match in rust_pattern.finditer(text):
name = match.group(1)
if name.startswith(("KS_", "KB_")):
continue
violations.append(
Violation(
"KH_ENV001",
relative,
text[: match.start()].count("\n") + 1,
f"workspace-owned environment variable `{name}` must use a `KS_*` or `KB_*` namespace",
)
)
env_example = root / ".env.example"
if env_example.is_file():
assignment = re.compile(r"^\s*#?\s*([A-Z][A-Z0-9_]*)=")
for index, line in enumerate(env_example.read_text(encoding="utf-8").splitlines(), 1):
match = assignment.match(line)
if match is None or match.group(1).startswith(("KS_", "KB_")):
continue
violations.append(
Violation(
"KH_ENV002",
".env.example",
index,
f"workspace environment example `{match.group(1)}` must use a `KS_*` or `KB_*` namespace",
)
)
config = root / "config/example.config.json"
if config.is_file():
text = config.read_text(encoding="utf-8")
placeholder = re.compile(r"\$\{([A-Z][A-Z0-9_]*)")
for match in placeholder.finditer(text):
name = match.group(1)
if name.startswith(("KS_", "KB_")):
continue
violations.append(
Violation(
"KH_ENV003",
"config/example.config.json",
text[: match.start()].count("\n") + 1,
f"configuration placeholder `{name}` must use a `KS_*` or `KB_*` namespace",
)
)
guide = root / "docs/DEVNET_EXECUTION_GUIDE.md"
if guide.is_file():
text = guide.read_text(encoding="utf-8")
exported = re.compile(r"\bexport\s+([A-Z][A-Z0-9_]*)=")
for match in exported.finditer(text):
name = match.group(1)
if name.startswith(("KS_", "KB_")):
continue
violations.append(
Violation(
"KH_ENV004",
"docs/DEVNET_EXECUTION_GUIDE.md",
text[: match.start()].count("\n") + 1,
f"operator environment variable `{name}` must use a `KS_*` or `KB_*` namespace",
)
)
return violations
def audit_wincode_resolution(root: pathlib.Path) -> list[Violation]: def audit_wincode_resolution(root: pathlib.Path) -> list[Violation]:
"""Require the currently compatible Solana wincode dependency family.""" """Require the currently compatible Solana wincode dependency family."""
@@ -946,6 +1023,7 @@ def main() -> int:
+audit_token_2022_naming(root) +audit_token_2022_naming(root)
+audit_private_ks_lib_paths_in_active_docs(root) +audit_private_ks_lib_paths_in_active_docs(root)
+audit_solana_types(root) +audit_solana_types(root)
+audit_environment_namespaces(root)
+audit_wincode_resolution(root) +audit_wincode_resolution(root)
) )
violations.sort(key=lambda item: (item.code, item.path, item.line, item.message)) violations.sort(key=lambda item: (item.code, item.path, item.line, item.message))