Skip to content

Commit b9ebd99

Browse files
pimlockdrew
authored andcommitted
fix(cli): use forward command for service forwarding
1 parent 9eee68f commit b9ebd99

5 files changed

Lines changed: 35 additions & 63 deletions

File tree

.agents/skills/debug-openshell-cluster/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,9 @@ helm -n openshell get values openshell | grep -E 'repository|tag|supervisorImage
128128

129129
The gateway image and `server.supervisorImage` should use the same build tag in branch and E2E deploys. A stale supervisor image can make sandbox behavior lag behind gateway policy or proto changes.
130130

131-
For local/external pull mode (the default local path via `mise run cluster`), local images are tagged to the configured local registry base, pushed to that registry, and pulled by k3s via the `registries.yaml` mirror endpoint. The `cluster` task rebuilds the local gateway image before tagging and pushing it, so a fresh bootstrap should not reuse stale `openshell/gateway:dev` bits from a previous source revision.
131+
For local/external pull mode (the default local path via `mise run cluster`), local images are tagged to the configured local registry base, pushed to that registry, and pulled by k3s via the `registries.yaml` mirror endpoint. The `cluster` task pushes prebuilt local tags (`openshell/*:dev`, falling back to `localhost:5000/openshell/*:dev` or `127.0.0.1:5000/openshell/*:dev`).
132132

133-
Gateway image builds stage a partial Rust workspace from `deploy/docker/Dockerfile.images`. If cargo fails with a missing manifest under `/build/crates/...`, or an imported symbol exists locally but is missing in the image build, verify that every current gateway dependency crate is copied into the staged workspace there.
133+
Gateway image builds stage a partial Rust workspace from `deploy/docker/Dockerfile.images`. If cargo fails with a missing manifest under `/build/crates/...`, or an imported symbol exists locally but is missing in the image build, verify that every current gateway dependency crate, including `openshell-driver-docker`, `openshell-driver-kubernetes`, and `openshell-ocsf`, is copied into the staged workspace there.
134134

135135
For plaintext local evaluation, confirm the chart has:
136136

crates/openshell-cli/src/main.rs

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,6 @@ const HELP_TEMPLATE: &str = "\
199199
\x1b[1mSANDBOX COMMANDS\x1b[0m
200200
sandbox: Manage sandboxes
201201
forward: Manage port forwarding to a sandbox
202-
service: Forward sandbox services over gRPC
203202
logs: View sandbox logs
204203
policy: Manage sandbox policy
205204
settings: Manage sandbox and global settings
@@ -268,16 +267,11 @@ const FORWARD_EXAMPLES: &str = "\x1b[1mALIAS\x1b[0m
268267
\x1b[1mEXAMPLES\x1b[0m
269268
$ openshell forward start 8080
270269
$ openshell forward start 3000 my-sandbox
270+
$ openshell forward service my-sandbox --target-port 8000 --local 8000
271271
$ openshell forward stop 8080
272272
$ openshell forward list
273273
";
274274

275-
const SERVICE_EXAMPLES: &str = "\x1b[1mEXAMPLES\x1b[0m
276-
$ openshell service forward my-sandbox --target-port 8080
277-
$ openshell service forward my-sandbox --target-port 5432 --local 15432
278-
$ openshell service forward my-sandbox --target-port 3000 --local 127.0.0.1:0
279-
";
280-
281275
const LOGS_EXAMPLES: &str = "\x1b[1mALIAS\x1b[0m
282276
lg
283277
@@ -415,13 +409,6 @@ enum Commands {
415409
command: Option<ForwardCommands>,
416410
},
417411

418-
/// Forward sandbox services over gRPC.
419-
#[command(after_help = SERVICE_EXAMPLES, help_template = SUBCOMMAND_HELP_TEMPLATE)]
420-
Service {
421-
#[command(subcommand)]
422-
command: Option<ServiceCommands>,
423-
},
424-
425412
/// View sandbox logs.
426413
#[command(alias = "lg", after_help = LOGS_EXAMPLES, help_template = LEAF_HELP_TEMPLATE, next_help_heading = "FLAGS")]
427414
Logs {
@@ -1626,13 +1613,10 @@ enum ForwardCommands {
16261613
/// List active port forwards.
16271614
#[command(help_template = LEAF_HELP_TEMPLATE, next_help_heading = "FLAGS")]
16281615
List,
1629-
}
16301616

1631-
#[derive(Subcommand, Debug)]
1632-
enum ServiceCommands {
16331617
/// Forward a local TCP port to a loopback service inside a sandbox over gRPC.
16341618
#[command(help_template = LEAF_HELP_TEMPLATE, next_help_heading = "FLAGS")]
1635-
Forward {
1619+
Service {
16361620
/// Sandbox name (defaults to last-used sandbox).
16371621
#[arg(add = ArgValueCompleter::new(completers::complete_sandbox_names))]
16381622
name: Option<String>,
@@ -1645,7 +1629,7 @@ enum ServiceCommands {
16451629
#[arg(long, default_value = "127.0.0.1")]
16461630
target_host: String,
16471631

1648-
/// Local bind address and port: [bind_address:]port. Use port 0 for dynamic assignment.
1632+
/// Local bind address and port: [bind_address:]port. Defaults to the target port. Use port 0 for dynamic assignment.
16491633
#[arg(long)]
16501634
local: Option<String>,
16511635
},
@@ -1815,38 +1799,6 @@ async fn main() -> Result<()> {
18151799
}
18161800
}
18171801

1818-
Some(Commands::Service {
1819-
command:
1820-
Some(ServiceCommands::Forward {
1821-
name,
1822-
target_port,
1823-
target_host,
1824-
local,
1825-
}),
1826-
}) => {
1827-
let ctx = resolve_gateway(&cli.gateway, &cli.gateway_endpoint)?;
1828-
let mut tls = tls.with_gateway_name(&ctx.name);
1829-
apply_edge_auth(&mut tls, &ctx.name);
1830-
let name = resolve_sandbox_name(name, &ctx.name)?;
1831-
run::service_forward_tcp(
1832-
&ctx.endpoint,
1833-
&name,
1834-
local.as_deref(),
1835-
&target_host,
1836-
target_port,
1837-
&tls,
1838-
)
1839-
.await?;
1840-
}
1841-
1842-
Some(Commands::Service { command: None }) => {
1843-
Cli::command()
1844-
.find_subcommand_mut("service")
1845-
.expect("service subcommand exists")
1846-
.print_help()
1847-
.expect("Failed to print help");
1848-
}
1849-
18501802
// -----------------------------------------------------------
18511803
// Top-level forward (was `sandbox forward`)
18521804
// -----------------------------------------------------------
@@ -1923,6 +1875,27 @@ async fn main() -> Result<()> {
19231875
}
19241876
}
19251877
}
1878+
ForwardCommands::Service {
1879+
name,
1880+
target_port,
1881+
target_host,
1882+
local,
1883+
} => {
1884+
let ctx = resolve_gateway(&cli.gateway, &cli.gateway_endpoint)?;
1885+
let mut tls = tls.with_gateway_name(&ctx.name);
1886+
apply_auth(&mut tls, &ctx.name);
1887+
let name = resolve_sandbox_name(name, &ctx.name)?;
1888+
let local = local.unwrap_or_else(|| target_port.to_string());
1889+
run::service_forward_tcp(
1890+
&ctx.endpoint,
1891+
&name,
1892+
Some(&local),
1893+
&target_host,
1894+
target_port,
1895+
&tls,
1896+
)
1897+
.await?;
1898+
}
19261899
ForwardCommands::Start {
19271900
port,
19281901
name,

crates/openshell-cli/src/run.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,12 @@ use openshell_bootstrap::{
2626
use openshell_core::proto::ProviderProfileCategory;
2727
use openshell_core::proto::{
2828
ApproveAllDraftChunksRequest, ApproveDraftChunkRequest, AttachSandboxProviderRequest,
29-
ClearDraftChunksRequest, CreateProviderRequest, CreateSandboxRequest,
30-
CreateSshSessionRequest, DeleteProviderProfileRequest, DeleteProviderRequest,
31-
DeleteSandboxRequest, DetachSandboxProviderRequest, ExecSandboxRequest,
32-
GetClusterInferenceRequest, GetDraftHistoryRequest, GetDraftPolicyRequest,
33-
GetGatewayConfigRequest, GetProviderProfileRequest, GetProviderRequest,
34-
GetSandboxConfigRequest, GetSandboxLogsRequest, GetSandboxPolicyStatusRequest,
35-
GetSandboxRequest, HealthRequest, ImportProviderProfilesRequest,
29+
ClearDraftChunksRequest, CreateProviderRequest, CreateSandboxRequest, CreateSshSessionRequest,
30+
DeleteProviderProfileRequest, DeleteProviderRequest, DeleteSandboxRequest,
31+
DetachSandboxProviderRequest, ExecSandboxRequest, GetClusterInferenceRequest,
32+
GetDraftHistoryRequest, GetDraftPolicyRequest, GetGatewayConfigRequest,
33+
GetProviderProfileRequest, GetProviderRequest, GetSandboxConfigRequest, GetSandboxLogsRequest,
34+
GetSandboxPolicyStatusRequest, GetSandboxRequest, HealthRequest, ImportProviderProfilesRequest,
3635
LintProviderProfilesRequest, ListProviderProfilesRequest, ListProvidersRequest,
3736
ListSandboxPoliciesRequest, ListSandboxProvidersRequest, ListSandboxesRequest, PolicySource,
3837
PolicyStatus, Provider, ProviderProfile, ProviderProfileDiagnostic, ProviderProfileImportItem,

crates/openshell-server/src/grpc/sandbox.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use openshell_core::proto::{
2020
ExecSandboxRequest, ExecSandboxStderr, ExecSandboxStdout, GetSandboxRequest,
2121
ListSandboxProvidersRequest, ListSandboxProvidersResponse, ListSandboxesRequest,
2222
ListSandboxesResponse, Provider, RevokeSshSessionRequest, RevokeSshSessionResponse,
23-
SandboxStreamEvent, TcpForwardFrame, TcpForwardInit, TcpRelayTarget, WatchSandboxRequest,
24-
relay_open, tcp_forward_init,
23+
SandboxResponse, SandboxStreamEvent, TcpForwardFrame, TcpForwardInit, TcpRelayTarget,
24+
WatchSandboxRequest, relay_open, tcp_forward_init,
2525
};
2626
use openshell_core::proto::{Sandbox, SandboxPhase, SandboxTemplate, SshSession};
2727
use prost::Message;

docs/sandboxes/manage-sandboxes.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ openshell forward stop 8000 my-sandbox
203203
Use the gRPC service-forwarding path when you want to test the OS-88 service relay path without SSH port forwarding:
204204
205205
```shell
206-
openshell service forward my-sandbox --target-port 8000 --local 8000
206+
openshell forward service my-sandbox --target-port 8000 --local 8000
207207
```
208208
209209
This binds a local listener and opens one authenticated gRPC stream to the gateway for each accepted local TCP connection. The target must be a loopback TCP service inside the sandbox. Use `--local 127.0.0.1:0` to let OpenShell choose a free local port.

0 commit comments

Comments
 (0)