feat: detect Windows Entra/local principal in WSL2

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) <noreply@anthropic.com>
This commit is contained in:
Tyler J King 2026-04-04 14:15:05 -04:00
parent b363d1da3b
commit d0b9ca0e6a
3 changed files with 49 additions and 11 deletions

View file

@ -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();

View file

@ -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

View file

@ -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"