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

Commit 5220fb3

Browse files
committed
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>
1 parent 659fe34 commit 5220fb3

6 files changed

Lines changed: 73 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: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from jumpstarter_driver_composite.client import CompositeClient
1010
from jumpstarter_driver_network.adapters.novnc import NovncAdapter
1111

12+
from jumpstarter.client import DriverClient
1213
from jumpstarter.client.decorators import driver_click_group
1314

1415
if typing.TYPE_CHECKING:
@@ -32,11 +33,15 @@ async def stream_async(self, method="connect"):
3233
return await self.tcp.stream_async(method)
3334

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

41+
def get_default_encrypt(self) -> bool:
42+
"""Fetch the default encryption setting from the remote driver."""
43+
return self.portal.call(DriverClient.call_async, self, "get_default_encrypt")
44+
4045
def cli(self) -> click.Command:
4146
"""Return a click command handler for this driver."""
4247

@@ -46,12 +51,26 @@ def vnc():
4651

4752
@vnc.command()
4853
@click.option("--browser/--no-browser", default=True, help="Open the session in a web browser.")
49-
def session(browser: bool):
54+
@click.option(
55+
"--encrypt",
56+
"encrypt_override",
57+
flag_value=True,
58+
default=None,
59+
help="Force an encrypted connection (wss://). Overrides the driver default.",
60+
)
61+
@click.option(
62+
"--no-encrypt",
63+
"encrypt_override",
64+
flag_value=False,
65+
help="Force an unencrypted connection (ws://). Overrides the driver default.",
66+
)
67+
def session(browser: bool, encrypt_override: bool | None):
5068
"""Open a VNC session."""
69+
encrypt = encrypt_override if encrypt_override is not None else self.get_default_encrypt()
5170
# The NovncAdapter is a blocking context manager that runs in a thread.
5271
# We can enter it, open the browser, and then just wait for the user
5372
# to press Ctrl+C to exit. The adapter handles the background work.
54-
with self.session() as url:
73+
with self.session(encrypt=encrypt) as url:
5574
click.echo(f"To connect, please visit: {url}")
5675
if browser:
5776
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)