06. Spécification des Scripts Normalisés, Contexte et Confinement Sécurisé
Navigation : Documentation > 06. Scripts Normalisés et Confinement
Sommaire
- Normalisation des Scripts de Cycle de Vie
- Règles de Normalisation
- Confinement de Sécurité Absolu (Zero Egress)
- Niveau 1 : Linter AST en CI/CD
- Niveau 2 : Assainissement d'Environnement (Environment Scrubbing)
- Niveau 3 : Confinement Réseau au Runtime (Zero Egress)
- Schéma et Évaluation du Contexte
$ctx - Évaluation sous Windows
- Évaluation sous macOS
1. Normalisation des Scripts de Cycle de Vie
Chaque paquet peut définir jusqu'à quatre scripts optionnels écrits en Nushell (nu) :
pre_install.nu: Exécuté avant le téléchargement et l'extraction des binaires.post_install.nu: Exécuté après l'extraction des binaires et le déploiement des trampolines.pre_uninstall.nu: Exécuté avant la suppression des fichiers du paquet lors de la désinstallation.post_uninstall.nu: Exécuté immédiatement après la purge et le nettoyage complet.
1.1 Règles de Normalisation
- Noms obligatoires stricts :
pre_install.nu,post_install.nu,pre_uninstall.nuetpost_uninstall.nu. - Emplacement obligatoire : À la racine du dossier du paquet (
packages/<initiale>/<paquet>/). - Signature normalisée obligatoire :
2. Confinement de Sécurité Absolu (Zero Egress)
Pour interdire toute exfiltration de données (clés SSH, tokens d'API, identifiants cloud), les scripts s'exécutent selon une défense en profondeur à 3 niveaux :
flowchart TD
subgraph Niveau1 ["Niveau 1 : Audit Statique Obligatoire en CI/CD (Dépôt)"]
PR["Pull Request Paquet (parts/ & scripts .nu)"]
LINT["Audit Statique Zero Egress (scripts/ci/audit_package_scripts.py)"]
DENY_RULES["Interdictions Formelles :<br>• http get / http post / curl / wget / nc / ssh<br>• Chemins : ~/.ssh, ~/.gnupg, ~/.aws, %USERPROFILE%\\.ssh<br>• Dynamique : eval, nu -c, run-external"]
ALLOW_RULES["Allowlist Stricte :<br>• FS local : mkdir, cp, mv, rm, path, open (local)<br>• Données : str, table, math, print, if, match"]
PR --> LINT
LINT --> DENY_RULES
LINT --> ALLOW_RULES
DENY_RULES -->|Violation| REJECT["Rejet Automatique Bloquant de la PR"]
ALLOW_RULES --> ACCEPT["Validation et Publication sur le Bucket"]
end
subgraph Niveau2 ["Niveau 2 : Assainissement d'Environnement (Client erable)"]
ACCEPT --> CLIENT["Poste Utilisateur"]
ENV_HOST["Environnement Hôte (SSH_AUTH_SOCK, AWS_*, TOKENS, SECRETS)"]
SCRUB["Scrubbing Sélectif :<br>Toutes les variables sensibles sont purgées"]
ENV_HOST --> SCRUB
SCRUB --> CLEAN_ENV["Environnement Épuré : Seuls $ctx et PATH/TEMP minimaux"]
end
subgraph Niveau3 ["Niveau 3 : Confinement Réseau au Runtime (Zero Egress)"]
CLEAN_ENV --> RUN["Lancement de pre/post_install.nu ou pre/post_uninstall.nu"]
LNX["Linux : unshare --net (Network Namespace Isolé)"]
MAC["macOS : sandbox-exec (deny network*)"]
WIN["Windows : AppContainer / Shadowing réseau Nushell"]
RUN --> LNX
RUN --> MAC
RUN --> WIN
LNX --> LOCAL_OK["Exécution Locale Hermétique<br>(Aucun paquet réseau émis)"]
MAC --> LOCAL_OK
WIN --> LOCAL_OK
end
2.1 Niveau 1 : Audit Statique Zero Egress en CI/CD (scripts/ci/audit_package_scripts.py)
Tout script (.nu) soumis dans un bucket est audité statiquement pour garantir le confinement Zero Egress :
- Interdiction des primitives et exécutables réseau :
http get,http post,curl,wget,nc,ncat,netcat,ssh,scp,sftp,telnet,ftp. - Interdiction d'accès aux répertoires et secrets sensibles :
.ssh,.gnupg,.aws,.azure,.kube,id_rsa,id_ed25519,credentials,token,.env,AppData/Roaming. - Interdiction d'évaluation dynamique :
eval,nu -c,bash,cmd.exe,powershell, etc. - Signature normalisée obligatoire :
def main [ctx: record].
2.2 Niveau 2 : Assainissement d'Environnement (Environment Scrubbing)
Avant d'invoquer nu pre_install.nu $ctx, le moteur purge systématiquement :
- Les clés et secrets cloud :
AWS_*,AZURE_*,GOOGLE_*,KUBECONFIG. - Les jetons d'accès :
GITHUB_TOKEN,GITLAB_TOKEN,NPM_TOKEN,*_KEY,*_SECRET,*_PASSWORD. - Les sockets d'agents :
SSH_AUTH_SOCK,GPG_AGENT_INFO.
2.3 Niveau 3 : Confinement Réseau au Runtime (Zero Egress)
- Linux : Invocation dans un namespace réseau vierge :
unshare --net -- nu post_install.nu $ctx. - macOS : Invocation sous profil Seatbelt interdisant les sockets :
sandbox-exec -p '(version 1)(allow default)(deny network*)' nu .... - Windows : Invocation sous profil Windows AppContainer (
CreateProcessavecSECURITY_CAPABILITIESomettantinternetClientetprivateNetworkClientServer), rejetant matériellement tout appel Winsock avecWSAEACCES(10013).
3. Schéma et Évaluation du Contexte $ctx
Le contexte typé $ctx: record injecté dans pre_install.nu et post_install.nu expose les chemins résolus et les variables d'environnement natives de l'OS hôte :
3.1 Évaluation sous Windows
$ctx = {
package: "ripgrep",
version: "14.1.0",
os: "windows",
arch: "x86_64",
paths: {
root: "C:/Users/User/.erable",
bin: "C:/Users/User/.erable/bin",
install: "C:/Users/User/.erable/packages/ripgrep/14.1.0",
package_store: "C:/Users/User/.erable/installed/ripgrep",
cache: "C:/Users/User/.erable/cache"
},
os_vars: {
appdata: "C:/Users/User/AppData/Roaming",
localappdata: "C:/Users/User/AppData/Local",
programdata: "C:/ProgramData",
userprofile: "C:/Users/User",
systemroot: "C:/Windows"
}
}
3.2 Évaluation sous macOS
$ctx = {
package: "ripgrep",
version: "14.1.0",
os: "macos",
arch: "aarch64",
paths: {
root: "/Users/user/Library/Application Support/erable",
bin: "/Users/user/Library/Application Support/erable/bin",
install: "/Users/user/Library/Application Support/erable/packages/ripgrep/14.1.0",
package_store: "/Users/user/Library/Application Support/erable/installed/ripgrep",
cache: "/Users/user/Library/Application Support/erable/cache"
},
os_vars: {
home: "/Users/user",
xdg_config_home: "/Users/user/.config",
xdg_data_home: "/Users/user/.local/share",
xdg_state_home: "/Users/user/.local/state",
xdg_cache_home: "/Users/user/.cache",
app_support: "/Users/user/Library/Application Support",
preferences: "/Users/user/Library/Preferences"
}
}