Skip to content

Add open vpn builder with validation#326

Open
stoutes wants to merge 6 commits intocachebag:dev-openvpnfrom
stoutes:add-OpenVpnBuilder-with-validation
Open

Add open vpn builder with validation#326
stoutes wants to merge 6 commits intocachebag:dev-openvpnfrom
stoutes:add-OpenVpnBuilder-with-validation

Conversation

@stoutes
Copy link
Copy Markdown
Collaborator

@stoutes stoutes commented Apr 4, 2026

Summary

Part of #288. Depends on OpenVpnConfig being merged into dev-openvpn.

Adds OpenVpnBuilder — a fluent, validated builder for OpenVpnConfig modelled
after the existing WireGuardBuilder.

Changes

api/builders/openvpn_builder.rs (new file)

Fluent builder that constructs OpenVpnConfig with validation at build() time:

  • remote must be set and non-empty
  • auth_type must be set
  • Password or PasswordTls: username required
  • Tls or PasswordTls: ca_cert, client_cert, client_key required
  • port must be 1–65535 (defaults to 1194 if not set)

Methods: new(name), remote(), auth_type(), username(), password(),
ca_cert(), client_cert(), client_key(), key_password(), port(), tcp(),
cipher(), auth(), dns(), mtu(), uuid(), autoconnect(), options(),
build() -> Result<OpenVpnConfig>

api/builders/mod.rs

  • Added pub mod openvpn_builder
  • Re-exported OpenVpnBuilder
  • Updated module doc comment to mention OpenVPN builders

Tests

17 unit tests mirroring wireguard_builder.rs structure:

  • Happy paths for all four auth types (Tls, Password, PasswordTls, StaticKey)
  • Required field validation (remote, auth_type)
  • Auth-type-specific validation (username for password auth, certs for TLS)
  • Optional field coverage (tcp, auth, cipher, mtu, dns, compression, proxy)
  • Port validation (zero port rejected, default to 1194)

@stoutes stoutes marked this pull request as ready for review April 4, 2026 21:44
@stoutes stoutes requested a review from cachebag April 4, 2026 23:16
@stoutes stoutes self-assigned this Apr 5, 2026
@cachebag cachebag added feature New feature or request nmrs Changes to nmrs vpn Changes to VPN surface labels Apr 5, 2026
Copy link
Copy Markdown
Owner

@cachebag cachebag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

Also just wanted to ask once again that you please name the prefixes of this commit category as feat, NOT feature. Ik it's minor, but I've never used feature in my commits and would like to keep style consistent

We could also probably do without the AI generated PR descriptions. Just a short sentence and a line of what issue this closes is good enough! :)

proxy: Option<OpenVpnProxy>,
autoconnect: bool,
autoconnect_priority: Option<i32>,
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you build these and never use them?

#[must_use]
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This happily produces a config with an empty name...The WireGuardBuilder runs validate_connection_name in its build(), so this builder should too.

Especially since from_ovpn_file and connect_vpn both validate the name downstream, so an invalid name would just blow up later with a less helpful error.

fn builds_static_key_connection() {
let config = OpenVpnBuilder::new("TestVPN")
.remote("vpn.example.com")
.auth_type(OpenVpnAuthType::StaticKey)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's zero validation on StaticKey here. You can build a StaticKey config with just a name and remote, no key path, no nothing?

That's probably not a usable connection. Even if you don't know exactly what StaticKey requires yet, a comment or todo!() acknowledging it would be better than silently accepting an empty config.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm questionable on your claims that you modeled this after the existing WireGuardBuilder. They're fundamentally different. WireGuardBuilder::build() returns HashMap<String, HashMap<String, Value>> (whcih are NM-ready D-Bus settings), while OpenVpnBuilder::build() returns Result<OpenVpnConfig, ConnectionError> (a domain struct).

This isn't necessarily wrong, OpenVpnConfig already has build_openvpn_connection to produce NM settings, but it DOES mean the two builders aren't interchangeable patterns.

Worth a sentence in the module doc or PR description acknowledging this so future contributors aren't confused.

@cachebag
Copy link
Copy Markdown
Owner

cachebag commented Apr 8, 2026

ping @stoutes

lmk if you can't finish so i can take over and close the PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request nmrs Changes to nmrs vpn Changes to VPN surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants