Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Fix root cause. Unsure: read more code; if stuck, ask w/ short options. Unrecogn
| 013-python-package | Python package, PyPI wheels, platform matrix |
| 014-scripted-tool-orchestration | Compose ToolDef+callback pairs into OrchestratorTool via bash scripts |
| 016-zapcode-runtime | Embedded TypeScript via ZapCode, VFS bridging, resource limits |
| 017-request-signing | Transparent Ed25519 request signing (bot-auth) per RFC 9421 |

### Documentation

Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ md-5 = "0.11"
sha1 = "0.11"
sha2 = "0.11"

# Ed25519 signing (bot-auth request signing)
ed25519-dalek = { version = "2", features = ["rand_core"] }
rand = "0.8"

# CLI
clap = { version = "4", features = ["derive"] }

Expand Down
6 changes: 6 additions & 0 deletions crates/bashkit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ flate2 = { workspace = true }
# Base64 encoding (for base64 builtin and HTTP basic auth)
base64 = { workspace = true }

# Ed25519 signing for bot-auth request signing (optional)
ed25519-dalek = { workspace = true, optional = true }
rand = { workspace = true, optional = true }

# Checksums (for md5sum, sha1sum, sha256sum builtins)
md-5 = { workspace = true }
sha1 = { workspace = true }
Expand All @@ -75,6 +79,8 @@ zapcode-core = { version = "1.5", optional = true }
[features]
default = []
http_client = ["reqwest"]
# Enable Ed25519 request signing per RFC 9421 / web-bot-auth profile
bot-auth = ["http_client", "dep:ed25519-dalek", "dep:rand"]
# Enable fail points for security/fault injection testing
# Usage: FAILPOINTS="fail_point_name=action" cargo test --features failpoints
failpoints = ["fail/failpoints"]
Expand Down
39 changes: 39 additions & 0 deletions crates/bashkit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,9 @@ pub use network::{HttpClient, HttpHandler};
#[cfg(feature = "http_client")]
pub use network::Response as HttpResponse;

#[cfg(feature = "bot-auth")]
pub use network::{BotAuthConfig, BotAuthError, BotAuthPublicKey, derive_bot_auth_public_key};

#[cfg(feature = "git")]
pub use git::GitClient;

Expand Down Expand Up @@ -1027,6 +1030,9 @@ pub struct BashBuilder {
/// Custom HTTP handler for request interception
#[cfg(feature = "http_client")]
http_handler: Option<Box<dyn network::HttpHandler>>,
/// Bot-auth config for transparent request signing
#[cfg(feature = "bot-auth")]
bot_auth_config: Option<network::BotAuthConfig>,
/// Logging configuration
#[cfg(feature = "logging")]
log_config: Option<logging::LogConfig>,
Expand Down Expand Up @@ -1239,6 +1245,32 @@ impl BashBuilder {
self
}

/// Enable transparent request signing for all outbound HTTP requests.
///
/// When configured, every HTTP request made by curl/wget/http builtins
/// is signed with Ed25519 per RFC 9421 / web-bot-auth profile. No CLI
/// arguments or script changes needed — signing is fully transparent.
///
/// Signing failures are non-blocking: the request is sent unsigned.
///
/// # Example
///
/// ```rust,ignore
/// use bashkit::{Bash, NetworkAllowlist};
/// use bashkit::network::BotAuthConfig;
///
/// let bash = Bash::builder()
/// .network(NetworkAllowlist::new().allow("https://api.example.com"))
/// .bot_auth(BotAuthConfig::from_seed([42u8; 32])
/// .with_agent_fqdn("bot.example.com"))
/// .build();
/// ```
#[cfg(feature = "bot-auth")]
pub fn bot_auth(mut self, config: network::BotAuthConfig) -> Self {
self.bot_auth_config = Some(config);
self
}

/// Configure logging behavior.
///
/// When the `logging` feature is enabled, Bashkit can emit structured logs
Expand Down Expand Up @@ -1850,6 +1882,8 @@ impl BashBuilder {
self.network_allowlist,
#[cfg(feature = "http_client")]
self.http_handler,
#[cfg(feature = "bot-auth")]
self.bot_auth_config,
#[cfg(feature = "logging")]
self.log_config,
#[cfg(feature = "git")]
Expand Down Expand Up @@ -1936,6 +1970,7 @@ impl BashBuilder {
history_file: Option<PathBuf>,
#[cfg(feature = "http_client")] network_allowlist: Option<NetworkAllowlist>,
#[cfg(feature = "http_client")] http_handler: Option<Box<dyn network::HttpHandler>>,
#[cfg(feature = "bot-auth")] bot_auth_config: Option<network::BotAuthConfig>,
#[cfg(feature = "logging")] log_config: Option<logging::LogConfig>,
#[cfg(feature = "git")] git_config: Option<GitConfig>,
) -> Bash {
Expand Down Expand Up @@ -1984,6 +2019,10 @@ impl BashBuilder {
if let Some(handler) = http_handler {
client.set_handler(handler);
}
#[cfg(feature = "bot-auth")]
if let Some(bot_auth) = bot_auth_config {
client.set_bot_auth(bot_auth);
}
interpreter.set_http_client(client);
}

Expand Down
Loading
Loading