manta_server/service/
sat_file.rs

1//! SAT-file service wrappers.
2//!
3//! Thin forwarders from the HTTP handlers to the backend dispatcher,
4//! enforcing the CLAUDE.md boundary rule (handlers → service → backend).
5//!
6//! [`apply_session_template`] also consolidates the duplicate
7//! `get_group_name_available` fetch that the handlers previously
8//! performed twice (once inside `validate_user_group_vec_access`,
9//! once to build the `hsm_group_available_vec` argument): the service
10//! function fetches the group list once, validates it in-memory, and
11//! forwards it to the backend.
12
13use std::collections::HashMap;
14
15use manta_backend_dispatcher::error::Error;
16use manta_backend_dispatcher::interfaces::apply_sat_file::{
17  ApplyConfigurationParams, ApplyImageCreateSessionParams,
18  ApplyImageStampParams, ApplySessionTemplateParams, SatTrait,
19};
20use manta_backend_dispatcher::types::bos::{
21  session::BosSession, session_template::BosSessionTemplate,
22};
23use manta_backend_dispatcher::types::cfs::cfs_configuration_response::CfsConfigurationResponse;
24use manta_backend_dispatcher::types::cfs::session::CfsSessionGetResponse;
25use manta_backend_dispatcher::types::ims::Image;
26
27use crate::server::common::app_context::InfraContext;
28use crate::service::authorization;
29
30/// Apply a single SAT `configurations[]` entry.
31///
32/// CFS configurations are not HSM-group-scoped so no caller-access
33/// check is performed here. The backend's own RBAC layer enforces
34/// CSM-level authorization.
35#[allow(clippy::too_many_arguments)]
36pub async fn apply_configuration(
37  infra: &InfraContext<'_>,
38  token: &str,
39  vault_base_url: &str,
40  k8s_api_url: &str,
41  gitea_token: &str,
42  configuration: serde_json::Value,
43  dry_run: bool,
44  overwrite: bool,
45) -> Result<CfsConfigurationResponse, Error> {
46  infra
47    .backend
48    .apply_configuration(ApplyConfigurationParams {
49      shasta_token: token,
50      vault_base_url,
51      site_name: infra.site_name,
52      k8s_api_url,
53      gitea_base_url: infra.gitea_base_url,
54      gitea_token,
55      configuration,
56      dry_run,
57      overwrite,
58    })
59    .await
60}
61
62/// Translate one SAT `images[]` entry into a CFS session and create it.
63///
64/// Returns the created [`CfsSessionGetResponse`] without waiting for the
65/// session to complete (the CLI drives monitor + stamp steps itself).
66/// Caller-access validation for the image's target groups must be done
67/// BEFORE calling this function (see
68/// [`crate::service::authorization::validate_user_group_vec_access`]).
69#[allow(clippy::too_many_arguments)]
70pub async fn create_image_cfs_session(
71  infra: &InfraContext<'_>,
72  token: &str,
73  vault_base_url: &str,
74  k8s_api_url: &str,
75  image: serde_json::Value,
76  ref_lookup: HashMap<String, String>,
77  ansible_verbosity: Option<u8>,
78  ansible_passthrough: Option<&str>,
79  dry_run: bool,
80) -> Result<CfsSessionGetResponse, Error> {
81  infra
82    .backend
83    .apply_sat_image_create_session(ApplyImageCreateSessionParams {
84      shasta_token: token,
85      vault_base_url,
86      site_name: infra.site_name,
87      k8s_api_url,
88      image,
89      ref_lookup,
90      ansible_verbosity,
91      ansible_passthrough,
92      dry_run,
93    })
94    .await
95}
96
97/// Stamp `manta.image_session.*` provenance metadata onto the IMS image
98/// produced by a (terminal-complete) CFS session.
99///
100/// Session-access validation and result-image existence checks must be
101/// done BEFORE calling this; see
102/// [`crate::service::session::validate_session_access`] and
103/// [`crate::service::session::require_result_image`].
104pub async fn stamp_image_from_session(
105  infra: &InfraContext<'_>,
106  token: &str,
107  cfs_session_name: &str,
108) -> Result<Image, Error> {
109  infra
110    .backend
111    .apply_sat_image_stamp_from_session(ApplyImageStampParams {
112      shasta_token: token,
113      cfs_session_name,
114    })
115    .await
116}
117
118/// Apply a single SAT `session_templates[]` entry.
119///
120/// Fetches the caller's accessible group list once; for non-admin callers
121/// validates that every group in `target_groups` is accessible, then
122/// passes the full list to the backend as `hsm_group_available_vec`.
123/// This consolidates the two `get_group_name_available` calls that the
124/// handler previously performed (one inside `validate_user_group_vec_access`,
125/// one to build the backend param) into a single backend round-trip.
126pub async fn apply_session_template(
127  infra: &InfraContext<'_>,
128  token: &str,
129  session_template: serde_json::Value,
130  ref_lookup: HashMap<String, String>,
131  target_groups: &[String],
132  reboot: bool,
133  dry_run: bool,
134) -> Result<(BosSessionTemplate, Option<BosSession>), Error> {
135  let hsm_group_available_vec =
136    authorization::fetch_group_names_and_validate_access(
137      infra,
138      token,
139      target_groups,
140    )
141    .await?;
142  infra
143    .backend
144    .apply_session_template(ApplySessionTemplateParams {
145      shasta_token: token,
146      session_template,
147      ref_lookup,
148      hsm_group_available_vec: &hsm_group_available_vec,
149      reboot,
150      dry_run,
151    })
152    .await
153}