(dir: &Path, server_sans: &[String])
| 460 | } |
| 461 | |
| 462 | fn run_local(dir: &Path, server_sans: &[String]) -> Result<()> { |
| 463 | let paths = LocalPaths::resolve(dir); |
| 464 | |
| 465 | let bundle = match decide_local(paths.tls_existence_count(), paths.jwt_existence_count()) { |
| 466 | LocalAction::Skip => { |
| 467 | let missing_sans = missing_required_server_sans(&paths, server_sans)?; |
| 468 | if missing_sans.is_empty() { |
| 469 | info!(dir = %dir.display(), "PKI files already exist, skipping."); |
| 470 | } else { |
| 471 | let bundle = generate_pki(server_sans)?; |
| 472 | write_local_tls_bundle(&bundle, &paths)?; |
| 473 | info!( |
| 474 | dir = %dir.display(), |
| 475 | missing_sans = %format_cert_sans(&missing_sans), |
| 476 | "server TLS certificate refreshed for current SAN set.", |
| 477 | ); |
| 478 | } |
| 479 | read_local_bundle(&paths)? |
| 480 | } |
| 481 | LocalAction::CreateJwtOnly => { |
| 482 | let bundle = generate_pki(server_sans)?; |
| 483 | let missing_sans = missing_required_server_sans(&paths, server_sans)?; |
| 484 | if missing_sans.is_empty() { |
| 485 | write_local_jwt_bundle(&bundle, &paths)?; |
| 486 | info!(dir = %dir.display(), "JWT signing files created for existing TLS install."); |
| 487 | } else { |
| 488 | write_local_bundle(dir, &bundle, &paths)?; |
| 489 | info!( |
| 490 | dir = %dir.display(), |
| 491 | missing_sans = %format_cert_sans(&missing_sans), |
| 492 | "PKI files refreshed for current SAN set and JWT signing material.", |
| 493 | ); |
| 494 | } |
| 495 | read_local_bundle(&paths)? |
| 496 | } |
| 497 | LocalAction::PartialState => { |
| 498 | return Err(miette::miette!( |
| 499 | "partial PKI state in {dir}: some files exist but not all. \ |
| 500 | Recover with: rm -rf {dir} (the gateway will regenerate on next start)", |
| 501 | dir = dir.display(), |
| 502 | )); |
| 503 | } |
| 504 | LocalAction::CreateAll => { |
| 505 | let bundle = generate_pki(server_sans)?; |
| 506 | write_local_bundle(dir, &bundle, &paths)?; |
| 507 | info!(dir = %dir.display(), "PKI files created."); |
| 508 | bundle |
| 509 | } |
| 510 | }; |
| 511 | |
| 512 | // Always make sure the CLI auto-discovery copy is in place. This |
| 513 | // self-heals the case where the operator wiped ~/.config/openshell but |
| 514 | // left the gateway state directory intact. |
| 515 | if let Err(e) = openshell_bootstrap::mtls::store_pki_bundle("openshell", &bundle) { |
| 516 | warn!(error = %e, "failed to copy client mTLS materials for CLI auto-discovery"); |
| 517 | } |
| 518 | |
| 519 | Ok(()) |
no test coverage detected