From d0b9ca0e6ab7cc1360616df3d748b302565c0c9f9814a856b5d1e6cf60c55fd5 Mon Sep 17 00:00:00 2001 From: Tyler J King Date: Sat, 4 Apr 2026 14:15:05 -0400 Subject: [PATCH] feat: detect Windows Entra/local principal in WSL2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Session principal resolution chain: GSH_PRINCIPAL → BASCULE_DISPLAY_NAME → derive from DID → whoami() GSH_DID → BASCULE_USER_DID → whoami() .gshrc Windows identity detection: Entra-joined: whoami /upn → tking@guildhouse.dev → DID Domain-joined: USERNAME@USERDNSDOMAIN → DID Local: USERNAME only (no DID) Governed sessions (Bascule) override with authenticated identity. Non-WSL2 environments fall back silently. Co-Authored-By: Claude Opus 4.6 (1M context) --- libgsh/src/session.rs | 12 +++++++++--- scripts/build-substrate-wsl2.sh | 26 +++++++++++++++++++++++--- scripts/build-wsl2-image.sh | 22 +++++++++++++++++----- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/libgsh/src/session.rs b/libgsh/src/session.rs index dc6d724..7927556 100644 --- a/libgsh/src/session.rs +++ b/libgsh/src/session.rs @@ -65,9 +65,15 @@ impl SessionState { /// Create a minimal session for ungoverned mode. pub fn ungoverned(corpus_cid: &str) -> Self { - let principal = whoami(); - let display_name = std::env::var("BASCULE_DISPLAY_NAME") - .unwrap_or_else(|_| principal.clone()); + // Principal resolution: GSH_DID → BASCULE_USER_DID → whoami() + let principal = std::env::var("GSH_DID") + .or_else(|_| std::env::var("BASCULE_USER_DID")) + .unwrap_or_else(|_| whoami()); + + // Display name: GSH_PRINCIPAL → BASCULE_DISPLAY_NAME → derive from principal + let display_name = std::env::var("GSH_PRINCIPAL") + .or_else(|_| std::env::var("BASCULE_DISPLAY_NAME")) + .unwrap_or_else(|_| display_name_from_did(&principal)); let defcon_level = std::env::var("BASCULE_DEFCON_LEVEL") .ok().and_then(|v| v.parse().ok()).unwrap_or(5); let defcon_reason = std::env::var("BASCULE_DEFCON_REASON").ok(); diff --git a/scripts/build-substrate-wsl2.sh b/scripts/build-substrate-wsl2.sh index 4d06f3a..66a41fa 100755 --- a/scripts/build-substrate-wsl2.sh +++ b/scripts/build-substrate-wsl2.sh @@ -102,9 +102,29 @@ RUN mkdir -p /home/operator/.ssh && chmod 700 /home/operator/.ssh \ > /home/operator/.ssh/config \ && chmod 600 /home/operator/.ssh/config -# gsh environment -RUN printf 'export GSAP_CORPUS_CID="sha256:substrate-jumphost"\nexport GSH_CORPUS_DIR="$HOME/.gsh/corpus"\nexport PATH="$HOME/.local/bin:$PATH"\n' \ - > /home/operator/.gshrc \ +# gsh environment + Windows Entra identity detection +RUN printf 'export GSAP_CORPUS_CID="sha256:substrate-jumphost"\n\ +export GSH_CORPUS_DIR="$HOME/.gsh/corpus"\n\ +export PATH="$HOME/.local/bin:$PATH"\n\ +\n\ +# Detect Windows principal (WSL2 interop)\n\ +# Entra-joined: whoami /upn → tking@guildhouse.dev\n\ +# Domain-joined: USERNAME@USERDNSDOMAIN\n\ +# Local: USERNAME only\n\ +if command -v cmd.exe >/dev/null 2>&1; then\n\ + _UPN=$(cmd.exe /c "whoami /upn" 2>/dev/null | tr -d "\\r")\n\ + if [ -n "$_UPN" ] && echo "$_UPN" | grep -q "@"; then\n\ + _UPN_LC=$(echo "$_UPN" | tr "A-Z" "a-z")\n\ + export GSH_PRINCIPAL="$_UPN_LC"\n\ + _DOMAIN=$(echo "$_UPN_LC" | cut -d@ -f2)\n\ + _USER=$(echo "$_UPN_LC" | cut -d@ -f1)\n\ + export GSH_DID="did:web:${_DOMAIN}/user/${_USER}"\n\ + else\n\ + _WIN_USER=$(cmd.exe /c "echo %%USERNAME%%" 2>/dev/null | tr -d "\\r")\n\ + [ -n "$_WIN_USER" ] && export GSH_PRINCIPAL="$_WIN_USER"\n\ + fi\n\ + unset _UPN _UPN_LC _DOMAIN _USER _WIN_USER\n\ +fi\n' > /home/operator/.gshrc \ && printf '[ -f ~/.gshrc ] && source ~/.gshrc\n' >> /home/operator/.bashrc # Fix ownership diff --git a/scripts/build-wsl2-image.sh b/scripts/build-wsl2-image.sh index 8679fd7..fca8f37 100755 --- a/scripts/build-wsl2-image.sh +++ b/scripts/build-wsl2-image.sh @@ -138,15 +138,27 @@ add_ssh_host "stg.gsh" "178.104.110.197" "30222" echo "[7/7] Environment..." # .gshrc — governed shell defaults -cat > "$HOME/.gshrc" << GSHRC +cat > "$HOME/.gshrc" << 'GSHRC' # Guildhouse Governed Shell environment # Sourced by .bashrc -export GSAP_CORPUS_CID="$CORPUS_CID" -export GSH_CORPUS_DIR="\$HOME/.gsh/corpus" +export GSAP_CORPUS_CID="sha256:dev-jumphost" +export GSH_CORPUS_DIR="$HOME/.gsh/corpus" +export PATH="$HOME/.local/bin:$PATH" -# Add gsh to PATH -export PATH="\$HOME/.local/bin:\$PATH" +# Detect Windows principal (WSL2 interop) +if command -v cmd.exe >/dev/null 2>&1; then + _UPN=$(cmd.exe /c "whoami /upn" 2>/dev/null | tr -d '\r') + if [ -n "$_UPN" ] && echo "$_UPN" | grep -q "@"; then + _UPN_LC=$(echo "$_UPN" | tr 'A-Z' 'a-z') + export GSH_PRINCIPAL="$_UPN_LC" + export GSH_DID="did:web:$(echo "$_UPN_LC" | cut -d@ -f2)/user/$(echo "$_UPN_LC" | cut -d@ -f1)" + else + _WIN_USER=$(cmd.exe /c "echo %USERNAME%" 2>/dev/null | tr -d '\r') + [ -n "$_WIN_USER" ] && export GSH_PRINCIPAL="$_WIN_USER" + fi + unset _UPN _UPN_LC _WIN_USER +fi GSHRC echo " Created ~/.gshrc"