Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Commit 7fd8626

Browse files
aesteve-rhgithub-actions[bot]
authored andcommitted
novnc: add encrypt parameter
Add encrypt parameter to novnc adapter class, so that it can be configured in the url params. This allows the VNC driver to set --encrypt/--no-encrypt parameter through command line (default False) for more flexibility on the type of connection the user needs. Signed-off-by: Albert Esteve <aesteve@redhat.com> (cherry picked from commit ff46bad)
1 parent be2f81a commit 7fd8626

6 files changed

Lines changed: 72 additions & 9 deletions

File tree

packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/novnc.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
@blocking
1212
@asynccontextmanager
13-
async def NovncAdapter(*, client: DriverClient, method: str = "connect"):
13+
async def NovncAdapter(*, client: DriverClient, method: str = "connect", encrypt: bool = True):
1414
async def handler(conn):
1515
async with conn:
1616
async with client.stream_async(method) as stream:
@@ -19,13 +19,21 @@ async def handler(conn):
1919
pass
2020

2121
async with TemporaryTcpListener(handler) as addr:
22+
params = {
23+
"encrypt": 1 if encrypt else 0,
24+
"autoconnect": 1,
25+
"reconnect": 1,
26+
"host": addr[0],
27+
"port": addr[1],
28+
}
29+
2230
yield urlunparse(
2331
(
2432
"https",
2533
"novnc.com",
2634
"/noVNC/vnc.html",
2735
"",
28-
urlencode({"autoconnect": 1, "reconnect": 1, "host": addr[0], "port": addr[1]}),
36+
urlencode(params),
2937
"",
3038
)
3139
)

packages/jumpstarter-driver-vnc/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ Example `exporter.yaml` configuration:
1818
export:
1919
vnc:
2020
type: jumpstarter_driver_vnc.driver.Vnc
21+
# You can set the default encryption behavior for the `j vnc session` command.
22+
# If not set, it defaults to False (unencrypted).
23+
default_encrypt: false
2124
children:
2225
tcp:
2326
type: jumpstarter_driver_network.driver.TcpNetwork
@@ -55,4 +58,11 @@ j vnc session
5558
5659
# To prevent it from opening a browser automatically:
5760
j vnc session --no-browser
61+
62+
# To force an encrypted (wss://) or unencrypted (ws://) connection, overriding
63+
# the default set in the exporter configuration:
64+
j vnc session --encrypt
65+
j vnc session --no-encrypt
5866
```
67+
68+
> **Note:** Using an encrypted connection is intended for advanced scenarios where the local proxy can be configured with a TLS certificate that your browser trusts. For standard local development, modern browsers will likely reject the self-signed certificate and the connection will fail.

packages/jumpstarter-driver-vnc/examples/exporter.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ token: "<token>"
88
export:
99
vnc:
1010
type: jumpstarter_driver_vnc.driver.Vnc
11+
# You can set the default encryption behavior for the `j vnc session` command.
12+
# If not set, it defaults to False (unencrypted).
13+
default_encrypt: false
1114
children:
1215
tcp:
1316
type: jumpstarter_driver_network.driver.TcpNetwork

packages/jumpstarter-driver-vnc/jumpstarter_driver_vnc/client.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@ async def stream_async(self, method="connect"):
3232
return await self.tcp.stream_async(method)
3333

3434
@contextlib.contextmanager
35-
def session(self) -> typing.Iterator[str]:
35+
def session(self, *, encrypt: bool = True) -> typing.Iterator[str]:
3636
"""Create a new VNC session."""
37-
with NovncAdapter(client=self.tcp, method="connect") as adapter:
37+
with NovncAdapter(client=self.tcp, method="connect", encrypt=encrypt) as adapter:
3838
yield adapter
3939

40+
def get_default_encrypt(self) -> bool:
41+
"""Fetch the default encryption setting from the remote driver."""
42+
return typing.cast(bool, self.call("get_default_encrypt"))
43+
4044
def cli(self) -> click.Command:
4145
"""Return a click command handler for this driver."""
4246

@@ -46,12 +50,26 @@ def vnc():
4650

4751
@vnc.command()
4852
@click.option("--browser/--no-browser", default=True, help="Open the session in a web browser.")
49-
def session(browser: bool):
53+
@click.option(
54+
"--encrypt",
55+
"encrypt_override",
56+
flag_value=True,
57+
default=None,
58+
help="Force an encrypted connection (wss://). Overrides the driver default.",
59+
)
60+
@click.option(
61+
"--no-encrypt",
62+
"encrypt_override",
63+
flag_value=False,
64+
help="Force an unencrypted connection (ws://). Overrides the driver default.",
65+
)
66+
def session(browser: bool, encrypt_override: bool | None):
5067
"""Open a VNC session."""
68+
encrypt = encrypt_override if encrypt_override is not None else self.get_default_encrypt()
5169
# The NovncAdapter is a blocking context manager that runs in a thread.
5270
# We can enter it, open the browser, and then just wait for the user
5371
# to press Ctrl+C to exit. The adapter handles the background work.
54-
with self.session() as url:
72+
with self.session(encrypt=encrypt) as url:
5573
click.echo(f"To connect, please visit: {url}")
5674
if browser:
5775
webbrowser.open(url)

packages/jumpstarter-driver-vnc/jumpstarter_driver_vnc/driver.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,34 @@
11
from __future__ import annotations
22

3+
from dataclasses import dataclass
4+
5+
from jumpstarter_driver_composite.driver import Composite
6+
37
from jumpstarter.common.exceptions import ConfigurationError
4-
from jumpstarter.driver import Driver
8+
from jumpstarter.driver import export
9+
510

11+
@dataclass
12+
class Vnc(Composite):
13+
"""A VNC driver.
614
7-
class Vnc(Driver):
8-
"""A driver for VNC."""
15+
Members:
16+
default_encrypt: Whether to default to an encrypted client connection.
17+
"""
18+
19+
default_encrypt: bool = False
920

1021
def __post_init__(self):
1122
"""Initialize the VNC driver."""
1223
super().__post_init__()
1324
if "tcp" not in self.children:
1425
raise ConfigurationError("A tcp child is required for Vnc")
1526

27+
@export
28+
async def get_default_encrypt(self) -> bool:
29+
"""Return the default encryption setting."""
30+
return self.default_encrypt
31+
1632
@classmethod
1733
def client(cls) -> str:
1834
"""Return the client class path for this driver."""

packages/jumpstarter-driver-vnc/jumpstarter_driver_vnc/driver_test.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,11 @@ def test_vnc_driver_raises_error_without_tcp_child():
3232
"""Test that the Vnc driver raises a ConfigurationError if the tcp child is missing."""
3333
with pytest.raises(ConfigurationError, match="A tcp child is required for Vnc"):
3434
Vnc(children={})
35+
36+
37+
@pytest.mark.parametrize("expected", [True, False])
38+
def test_vnc_driver_default_encrypt(expected):
39+
"""Test that the default_encrypt parameter is correctly handled."""
40+
instance = Vnc(children={"tcp": FakeTcpDriver()}, default_encrypt=expected)
41+
with serve(instance) as client:
42+
assert client.get_default_encrypt() is expected

0 commit comments

Comments
 (0)