Create OPA engine from a typed proto policy with symlink resolution. When `entrypoint_pid` is non-zero, binary paths in the policy that are symlinks inside the container filesystem are resolved via `/proc/ /root/` and added as additional entries. This bridges the gap between user-specified symlink paths (e.g., `/usr/bin/python3`) and kernel-resolved canonical paths (e.g., `/usr/bin/python3.11
(proto: &ProtoSandboxPolicy, entrypoint_pid: u32)
| 193 | /// gap between user-specified symlink paths (e.g., `/usr/bin/python3`) and |
| 194 | /// kernel-resolved canonical paths (e.g., `/usr/bin/python3.11`). |
| 195 | pub fn from_proto_with_pid(proto: &ProtoSandboxPolicy, entrypoint_pid: u32) -> Result<Self> { |
| 196 | let data_json_str = proto_to_opa_data_json(proto, entrypoint_pid); |
| 197 | |
| 198 | // Parse back to Value for preprocessing, then re-serialize |
| 199 | let mut data: serde_json::Value = serde_json::from_str(&data_json_str) |
| 200 | .map_err(|e| miette::miette!("internal: failed to parse proto JSON: {e}"))?; |
| 201 | |
| 202 | // Validate BEFORE expanding presets |
| 203 | let (errors, warnings) = crate::l7::validate_l7_policies(&data); |
| 204 | for w in &warnings { |
| 205 | openshell_ocsf::ocsf_emit!( |
| 206 | openshell_ocsf::ConfigStateChangeBuilder::new(openshell_ocsf::ctx::ctx()) |
| 207 | .severity(openshell_ocsf::SeverityId::Medium) |
| 208 | .status(openshell_ocsf::StatusId::Success) |
| 209 | .state(openshell_ocsf::StateId::Enabled, "validated") |
| 210 | .unmapped("warning", serde_json::json!(w.clone())) |
| 211 | .message(format!("L7 policy validation warning: {w}")) |
| 212 | .build() |
| 213 | ); |
| 214 | } |
| 215 | if !errors.is_empty() { |
| 216 | return Err(miette::miette!( |
| 217 | "L7 policy validation failed:\n{}", |
| 218 | errors.join("\n") |
| 219 | )); |
| 220 | } |
| 221 | |
| 222 | normalize_l7_policy_rule_aliases(&mut data); |
| 223 | |
| 224 | // Expand access presets to explicit rules after validation |
| 225 | crate::l7::expand_access_presets(&mut data); |
| 226 | |
| 227 | let data_json = data.to_string(); |
| 228 | let mut engine = regorus::Engine::new(); |
| 229 | engine |
| 230 | .add_policy("policy.rego".into(), BAKED_POLICY_RULES.into()) |
| 231 | .map_err(|e| miette::miette!("{e}"))?; |
| 232 | engine |
| 233 | .add_data_json(&data_json) |
| 234 | .map_err(|e| miette::miette!("{e}"))?; |
| 235 | Ok(Self { |
| 236 | engine: Mutex::new(engine), |
| 237 | generation: Arc::new(AtomicU64::new(0)), |
| 238 | }) |
| 239 | } |
| 240 | |
| 241 | /// Evaluate a network access request against the loaded policy. |
| 242 | /// |
nothing calls this directly
no test coverage detected