Bascule shell runtime workspace — governed shell access layer for Substrate/Guildhouse FFC deployments. Crates: - bascule-agent: node agent with SSH server + command filtering - bascule-core: audit, grant engine, ceremony types, session - bascule-filter-core: log line filtering (stdio protocol) - bascule-gateway: OIDC auth, session management, SAT validation - bascule-node-agent: k8s DaemonSet agent (pod watcher, BPF manager) - bascule-proto: protobuf definitions - bascule-shell: governed SSH shell (commands, elevation, REPL) - bascule-tail: chronicle log tail + fanout - ceremony-engine: ceremony lifecycle (6 types + request/resolution) 172 tests passing. Implements SBS-SPEC-0001 shell model. Reference impl for SPEC-SHELLOPS-0001 Layer 1 (root shell).
93 lines
2.3 KiB
Rust
93 lines
2.3 KiB
Rust
//! sb — Substrate CLI
|
|
//!
|
|
//! Currently supports:
|
|
//! sb shell [--host HOST] [--port PORT] [--user USER]
|
|
//!
|
|
//! Connects to the bascule-agent's governed SSH shell.
|
|
|
|
use std::process::Command;
|
|
|
|
use clap::{Parser, Subcommand};
|
|
|
|
#[derive(Parser)]
|
|
#[command(name = "sb", about = "Substrate CLI", version)]
|
|
struct Cli {
|
|
#[command(subcommand)]
|
|
command: SubCmd,
|
|
}
|
|
|
|
#[derive(Subcommand)]
|
|
enum SubCmd {
|
|
/// Connect to the bascule-agent governed shell via SSH.
|
|
Shell {
|
|
/// SSH host to connect to.
|
|
#[arg(long, default_value = "localhost")]
|
|
host: String,
|
|
|
|
/// SSH port.
|
|
#[arg(short, long, default_value = "2222")]
|
|
port: u16,
|
|
|
|
/// SSH username.
|
|
#[arg(short, long, default_value_t = whoami())]
|
|
user: String,
|
|
|
|
/// SSH identity file (private key).
|
|
#[arg(short, long)]
|
|
identity: Option<String>,
|
|
},
|
|
|
|
/// Show agent status via IPC socket.
|
|
Status {
|
|
/// Path to the agent Unix socket.
|
|
#[arg(long, default_value = "/var/run/substrate/agent.sock")]
|
|
socket: String,
|
|
},
|
|
}
|
|
|
|
fn whoami() -> String {
|
|
std::env::var("USER").unwrap_or_else(|_| "substrate".to_string())
|
|
}
|
|
|
|
fn main() -> anyhow::Result<()> {
|
|
let cli = Cli::parse();
|
|
|
|
match cli.command {
|
|
SubCmd::Shell {
|
|
host,
|
|
port,
|
|
user,
|
|
identity,
|
|
} => {
|
|
let mut cmd = Command::new("ssh");
|
|
cmd.arg("-p").arg(port.to_string());
|
|
cmd.arg("-o").arg("StrictHostKeyChecking=no");
|
|
cmd.arg("-o").arg("UserKnownHostsFile=/dev/null");
|
|
cmd.arg("-o").arg("LogLevel=ERROR");
|
|
|
|
if let Some(ref key) = identity {
|
|
cmd.arg("-i").arg(key);
|
|
}
|
|
|
|
cmd.arg(format!("{user}@{host}"));
|
|
|
|
eprintln!("Connecting to bascule-agent shell at {host}:{port}...");
|
|
|
|
let status = cmd.status()?;
|
|
if !status.success() {
|
|
std::process::exit(status.code().unwrap_or(1));
|
|
}
|
|
}
|
|
|
|
SubCmd::Status { socket } => {
|
|
if std::path::Path::new(&socket).exists() {
|
|
println!("Agent socket: {} (active)", socket);
|
|
} else {
|
|
println!("Agent socket: {} (not found)", socket);
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|