Skip to content

Commit cdcb1a3

Browse files
2000krysztofjohntmyers
authored andcommitted
fix(policy)!: use enums for endpoint security modes
Replace the public TLS, enforcement, and access strings with protobuf enums and carry the typed values through policy composition, provider profiles, drivers, and runtime conversion. Preserve the documented YAML spellings, reject unknown and invalid numeric enum values consistently, and update generated Go bindings, SDK conversions, tests, and policy documentation. Signed-off-by: Krzysztof Malczuk <[email protected]>
1 parent db43f4e commit cdcb1a3

33 files changed

Lines changed: 1104 additions & 458 deletions

File tree

‎architecture/security-policy.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,11 @@ connection metadata agrees. When request paths overlap, a path endpoint with a
241241
higher specificity rank deterministically overrides broader request-processing
242242
metadata. Equally specific overlapping endpoints must agree.
243243

244-
Endpoint `tls`, `enforcement`, `access`, and `protocol` strings are validated
245-
before persistence or activation. The supervisor also refuses unknown endpoint
246-
modes defensively; an unrecognized enforcement value never falls back to audit.
244+
Endpoint `tls`, `enforcement`, and `access` use protobuf enums and retain their
245+
named YAML spellings. `protocol` remains a string so the supported protocol set
246+
can evolve, but every ingress validates it before persistence or activation.
247+
The supervisor also refuses unknown enum numbers and protocol values
248+
defensively; an unrecognized enforcement value never falls back to audit.
247249

248250
Gateway mutation paths validate the complete effective candidate before
249251
persistence when the affected sandbox scope is known. Direct replacements,

‎crates/openshell-cli/src/policy_update.rs‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,10 @@ fn parse_add_endpoint_spec(spec: &str) -> Result<NetworkEndpoint> {
472472
port,
473473
ports: vec![port],
474474
protocol: protocol.to_string(),
475-
enforcement: enforcement.to_string(),
476-
access: access.to_string(),
475+
enforcement: openshell_policy::network_enforcement_mode_from_str(enforcement)
476+
.expect("validated enforcement") as i32,
477+
access: openshell_policy::network_access_preset_from_str(access).expect("validated access")
478+
as i32,
477479
..Default::default()
478480
};
479481
apply_add_endpoint_options(spec, &mut endpoint, options)?;
@@ -616,7 +618,7 @@ mod tests {
616618
port: 443,
617619
ports: vec![443],
618620
protocol: "rest".to_string(),
619-
access: "read-only".to_string(),
621+
access: openshell_core::proto::NetworkAccessPreset::ReadOnly as i32,
620622
..Default::default()
621623
}],
622624
},
@@ -733,8 +735,14 @@ mod tests {
733735
let endpoint = &rule.endpoints[0];
734736
assert_eq!(endpoint.host, "realtime.example.com");
735737
assert_eq!(endpoint.protocol, "websocket");
736-
assert_eq!(endpoint.access, "read-write");
737-
assert_eq!(endpoint.enforcement, "enforce");
738+
assert_eq!(
739+
endpoint.access,
740+
openshell_core::proto::NetworkAccessPreset::ReadWrite as i32
741+
);
742+
assert_eq!(
743+
endpoint.enforcement,
744+
openshell_core::proto::NetworkEnforcementMode::Enforce as i32
745+
);
738746
}
739747

740748
#[test]
@@ -754,7 +762,7 @@ mod tests {
754762
panic!("expected add-rule preview");
755763
};
756764
assert_eq!(rule.endpoints[0].protocol, "tcp");
757-
assert!(rule.endpoints[0].access.is_empty());
765+
assert_eq!(rule.endpoints[0].access, 0);
758766
}
759767

760768
#[test]

‎crates/openshell-cli/src/run.rs‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6194,8 +6194,11 @@ fn format_endpoint(endpoint: &openshell_core::proto::NetworkEndpoint) -> String
61946194
};
61956195
tags.push(layer_tag.to_string());
61966196

6197-
if !endpoint.access.is_empty() {
6198-
tags.push(format!("access={}", endpoint.access));
6197+
if endpoint.access != 0 {
6198+
tags.push(format!(
6199+
"access={}",
6200+
openshell_policy::network_access_preset_to_str(endpoint.access).unwrap_or("unknown")
6201+
));
61996202
}
62006203

62016204
for r in &endpoint.rules {
@@ -7352,7 +7355,7 @@ mod tests {
73527355
host: "host.example.test".to_string(),
73537356
port: 443,
73547357
protocol: "rest".to_string(),
7355-
access: "read-only".to_string(),
7358+
access: openshell_core::proto::NetworkAccessPreset::ReadOnly as i32,
73567359
..Default::default()
73577360
};
73587361
assert_eq!(

‎crates/openshell-cli/tests/sandbox_name_fallback_integration.rs‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,9 @@ impl OpenShell for TestOpenShell {
206206
host: "api.user.example.com".to_string(),
207207
port: 443,
208208
protocol: "rest".to_string(),
209-
enforcement: "enforce".to_string(),
210-
access: "read-only".to_string(),
209+
enforcement: openshell_core::proto::NetworkEnforcementMode::Enforce
210+
as i32,
211+
access: openshell_core::proto::NetworkAccessPreset::ReadOnly as i32,
211212
..Default::default()
212213
}],
213214
..Default::default()
@@ -221,8 +222,9 @@ impl OpenShell for TestOpenShell {
221222
host: "api.provider.example.com".to_string(),
222223
port: 443,
223224
protocol: "rest".to_string(),
224-
enforcement: "enforce".to_string(),
225-
access: "read-only".to_string(),
225+
enforcement: openshell_core::proto::NetworkEnforcementMode::Enforce
226+
as i32,
227+
access: openshell_core::proto::NetworkAccessPreset::ReadOnly as i32,
226228
..Default::default()
227229
}],
228230
..Default::default()
@@ -496,8 +498,8 @@ impl OpenShell for TestOpenShell {
496498
host: "api.example.com".to_string(),
497499
port: 443,
498500
protocol: "rest".to_string(),
499-
enforcement: "enforce".to_string(),
500-
access: "read-only".to_string(),
501+
enforcement: openshell_core::proto::NetworkEnforcementMode::Enforce as i32,
502+
access: openshell_core::proto::NetworkAccessPreset::ReadOnly as i32,
501503
..Default::default()
502504
}],
503505
..Default::default()

‎crates/openshell-driver-mxc/src/policy_map/map.rs‎

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -517,27 +517,25 @@ fn report_endpoint_l7_losses(endpoint: &NetworkEndpoint, path: &str, items: &mut
517517
);
518518
}
519519

520-
if !endpoint.tls.is_empty() {
521-
let severity = if endpoint.tls == "skip" {
522-
"warning"
523-
} else {
524-
"error"
525-
};
520+
if endpoint.tls != 0 {
521+
let tls = openshell_policy::network_tls_mode_to_str(endpoint.tls).unwrap_or("unknown");
522+
let severity = if tls == "skip" { "warning" } else { "error" };
526523
add_loss(
527524
items,
528525
&format!("{path}.tls"),
529526
severity,
530527
&format!(
531528
"MXC has no OpenShell TLS inspection mode equivalent for '{}'.",
532-
endpoint.tls
529+
tls
533530
),
534531
"TLS inspection mode",
535532
"MXC network policy is host-level only.",
536533
);
537534
}
538535

539-
if !endpoint.enforcement.is_empty() {
540-
if endpoint.enforcement == "audit" {
536+
if endpoint.enforcement != 0 {
537+
if openshell_policy::network_enforcement_mode_to_str(endpoint.enforcement) == Some("audit")
538+
{
541539
add_loss(
542540
items,
543541
&format!("{path}.enforcement"),
@@ -558,15 +556,14 @@ fn report_endpoint_l7_losses(endpoint: &NetworkEndpoint, path: &str, items: &mut
558556
}
559557
}
560558

561-
if !endpoint.access.is_empty() {
559+
if endpoint.access != 0 {
560+
let access =
561+
openshell_policy::network_access_preset_to_str(endpoint.access).unwrap_or("unknown");
562562
add_loss(
563563
items,
564564
&format!("{path}.access"),
565565
"error",
566-
&format!(
567-
"MXC has no access preset equivalent for '{}'.",
568-
endpoint.access
569-
),
566+
&format!("MXC has no access preset equivalent for '{}'.", access),
570567
"REST/WebSocket/GraphQL access preset",
571568
"MXC cannot enforce method or operation-level access.",
572569
);

‎crates/openshell-driver-mxc/tests/policy_mapper_matrix.rs‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ fn b_tls_skip_warning() {
442442
"r",
443443
NetworkEndpoint {
444444
host: "api.example.com".into(),
445-
tls: "skip".into(),
445+
tls: openshell_core::proto::NetworkTlsMode::Skip as i32,
446446
..Default::default()
447447
},
448448
);
@@ -457,7 +457,7 @@ fn b_tls_non_skip_error() {
457457
"r",
458458
NetworkEndpoint {
459459
host: "api.example.com".into(),
460-
tls: "terminate".into(),
460+
tls: openshell_core::proto::NetworkTlsMode::Terminate as i32,
461461
..Default::default()
462462
},
463463
);
@@ -472,7 +472,7 @@ fn b_enforcement_audit_error() {
472472
"r",
473473
NetworkEndpoint {
474474
host: "api.example.com".into(),
475-
enforcement: "audit".into(),
475+
enforcement: openshell_core::proto::NetworkEnforcementMode::Audit as i32,
476476
..Default::default()
477477
},
478478
);
@@ -492,7 +492,7 @@ fn b_enforcement_non_audit_warning() {
492492
"r",
493493
NetworkEndpoint {
494494
host: "api.example.com".into(),
495-
enforcement: "enforce".into(),
495+
enforcement: openshell_core::proto::NetworkEnforcementMode::Enforce as i32,
496496
..Default::default()
497497
},
498498
);
@@ -512,7 +512,7 @@ fn b_access_error() {
512512
"r",
513513
NetworkEndpoint {
514514
host: "api.example.com".into(),
515-
access: "read-only".into(),
515+
access: openshell_core::proto::NetworkAccessPreset::ReadOnly as i32,
516516
..Default::default()
517517
},
518518
);
@@ -1193,9 +1193,9 @@ fn handled_fields_inventory() {
11931193
// Two ports → serializes as `ports: [80, 443]` (array form).
11941194
ports: vec![80, 443],
11951195
protocol: "graphql".into(),
1196-
tls: "skip".into(),
1197-
enforcement: "enforce".into(),
1198-
access: "full".into(),
1196+
tls: openshell_core::proto::NetworkTlsMode::Skip as i32,
1197+
enforcement: openshell_core::proto::NetworkEnforcementMode::Enforce as i32,
1198+
access: openshell_core::proto::NetworkAccessPreset::Full as i32,
11991199
allowed_ips: vec!["10.0.0.1".into()],
12001200
allow_encoded_slash: true,
12011201
websocket_credential_rewrite: true,

‎crates/openshell-driver-mxc/tests/wxc_exec_real.rs‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
use base64::Engine as _;
3434
use openshell_core::proto::compute::v1::{DriverSandbox, DriverSandboxSpec, DriverSandboxTemplate};
3535
use openshell_core::proto::{
36-
FilesystemPolicy, NetworkBinary, NetworkEndpoint, NetworkPolicyRule, SandboxPolicy,
36+
FilesystemPolicy, NetworkAccessPreset, NetworkBinary, NetworkEndpoint, NetworkEnforcementMode,
37+
NetworkPolicyRule, NetworkTlsMode, SandboxPolicy,
3738
};
3839
use openshell_driver_mxc::{MxcComputeBackend, MxcComputeConfig};
3940
use std::path::PathBuf;
@@ -732,9 +733,9 @@ async fn pc_https_egress_reads_injected_ca_bundle() {
732733
host: "example.com".to_string(),
733734
ports: vec![443],
734735
protocol: "rest".to_string(),
735-
tls: "terminate".to_string(),
736-
enforcement: "enforce".to_string(),
737-
access: "read-only".to_string(),
736+
tls: NetworkTlsMode::Unspecified as i32,
737+
enforcement: NetworkEnforcementMode::Enforce as i32,
738+
access: NetworkAccessPreset::ReadOnly as i32,
738739
..Default::default()
739740
}],
740741
binaries: vec![NetworkBinary { path: cmd_string }],

0 commit comments

Comments
 (0)