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 astrid-sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ use astrid_sys::astrid::ipc::host as wit_ipc;
use astrid_sys::astrid::kv::host as wit_kv;
use astrid_sys::astrid::net::host as wit_net;
use astrid_sys::astrid::process1_1_0::host as wit_process;
use astrid_sys::astrid::request_context::host as wit_request_context;
use astrid_sys::astrid::sys::host as wit_sys;
use astrid_sys::astrid::uplink::host as wit_uplink;
use borsh::{BorshDeserialize, BorshSerialize};
Expand Down
31 changes: 31 additions & 0 deletions astrid-sdk/src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@

use super::*;

/// Opaque host-minted owner of an authenticated local connection.
///
/// This is a comparison handle, not a credential. It carries no authority on
/// its own and cannot be constructed from client payloads through the SDK.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ConnectionOwner(String);

impl ConnectionOwner {
/// Borrow the opaque owner value for equality checks and routing.
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}

/// Direction argument for [`TcpStream::shutdown`] — mirror of
/// [`std::net::Shutdown`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -169,6 +184,16 @@ pub struct TcpStream {
}

impl TcpStream {
/// Return the host-minted owner of this authenticated local connection.
///
/// Outbound, remotely accepted, and unauthenticated streams return
/// `None`. Interactive request routing must fail closed in that case.
pub fn connection_owner(&self) -> Result<Option<ConnectionOwner>, SysError> {
wit_request_context::connection_owner(&self.inner)
.map(|owner| owner.map(ConnectionOwner))
.map_err(host_err)
}

/// Open an outbound TCP connection to `host:port`.
///
/// DNS resolution and the SSRF airlock run host-side; the WASM
Expand Down Expand Up @@ -589,6 +614,12 @@ fn parse_port(port_str: &str) -> std::io::Result<u16> {
mod tests {
use super::*;

#[test]
fn connection_owner_exposes_only_an_opaque_comparison_value() {
let owner = ConnectionOwner("request-owner-1".to_owned());
assert_eq!(owner.as_str(), "request-owner-1");
}

#[test]
fn parse_host_port_basic() {
let (h, p) = parse_host_port("example.com:443").unwrap();
Expand Down
1 change: 1 addition & 0 deletions astrid-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ mod generated {
import astrid:ipc/host@1.0.0;
import astrid:kv/host@1.0.0;
import astrid:net/host@1.0.0;
import astrid:request-context/host@1.0.0;
import astrid:http/host@1.1.0;
import astrid:sys/host@1.0.0;
import astrid:process/host@1.1.0;
Expand Down
11 changes: 5 additions & 6 deletions astrid-sys/wit-staging/deps/astrid-net@1.0.0/net@1.0.0.wit
Original file line number Diff line number Diff line change
Expand Up @@ -337,12 +337,11 @@ interface host {

/// Bind a TCP listener for inbound connections.
///
/// `"0.0.0.0"` / `"::"` exposes the listener to every network
/// interface (server posture) — restrict in `Capsule.toml
/// [capabilities] net_tcp_bind` to loopback-only patterns unless
/// the capsule genuinely needs to serve. Port `0` selects an
/// ephemeral port. Gated by a `net_tcp_bind` capability allowlist
/// distinct from `net_connect`.
/// Astrid confines TCP listeners to loopback hosts: `localhost`,
/// `127.0.0.0/8`, or `::1`. Wildcard and non-loopback interfaces are
/// rejected. Port `0` selects an ephemeral port. The requested
/// `host:port` must match the capsule's `[capabilities].net_bind`
/// allowlist; this authority is distinct from `net_connect`.
bind-tcp: func(host: string, port: u16) -> result<tcp-listener, error-code>;

/// Open an outbound TCP connection to `host:port`. Goes through
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/// Authenticated request context for host-local client connections.
///
/// This package exposes only an opaque comparison handle. The value is minted
/// by the host when an authenticated local connection is accepted; it is not a
/// credential, carries no authority by itself, and must never be accepted from
/// guest payloads as proof of ownership.

package astrid:request-context@1.0.0;

interface host {
use astrid:net/host@1.0.0.{error-code, tcp-stream};

/// Return the opaque owner of an authenticated accepted local connection.
///
/// `none` means the stream is outbound, remotely accepted, or was not
/// authenticated strongly enough to own interactive requests. Consumers
/// must fail closed for owner-scoped prompts when this is `none`.
connection-owner: func(connection: borrow<tcp-stream>) -> result<option<string>, error-code>;
}
2 changes: 1 addition & 1 deletion contracts
Loading