Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 44 additions & 11 deletions crates/api-core/src/measured_boot/rpc/site.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
use std::str::FromStr;

use ::rpc::errors::RpcDataConversionError;
use carbide_uuid::machine::MachineId;
use carbide_uuid::measured_boot::TrustedMachineId;
use db::DatabaseError;
use db::measured_boot::interface::site::{
get_approved_machines, get_approved_profiles, insert_into_approved_machines,
insert_into_approved_profiles, list_attestation_summary,
Expand Down Expand Up @@ -52,6 +52,20 @@ use tonic::Status;
use crate::CarbideError;
use crate::api::Api;

fn measurement_trust_removal_error(
error: DatabaseError,
kind: &'static str,
id: String,
) -> CarbideError {
if error.is_not_found() {
CarbideError::NotFoundError { kind, id }
} else {
CarbideError::Internal {
message: format!("removal failed: {error}"),
}
}
}

/// handle_import_site_measurements handles the ImportSiteMeasurements
/// API endpoint.
pub async fn handle_import_site_measurements(
Expand Down Expand Up @@ -143,23 +157,32 @@ pub async fn handle_remove_measurement_trusted_machine(
let approval_record: MeasurementApprovedMachineRecord = match req.selector {
// Remove by approval ID.
Some(remove_measurement_trusted_machine_request::Selector::ApprovalId(approval_uuid)) => {
let id = approval_uuid.to_string();
remove_from_approved_machines_by_approval_id(&mut txn, approval_uuid)
.await
.map_err(|e| CarbideError::Internal {
message: format!("removal failed: {e}"),
.map_err(|error| {
measurement_trust_removal_error(
error,
"measurement trusted machine approval",
id,
)
})?
}
// Remove by machine ID.
Some(remove_measurement_trusted_machine_request::Selector::MachineId(machine_id)) => {
remove_from_approved_machines_by_machine_id(
&mut txn,
MachineId::from_str(&machine_id).map_err(|_| {
CarbideError::from(RpcDataConversionError::InvalidMachineId(machine_id))
TrustedMachineId::from_str(&machine_id).map_err(|_| {
CarbideError::from(RpcDataConversionError::InvalidMachineId(machine_id.clone()))
})?,
)
.await
.map_err(|e| CarbideError::Internal {
message: format!("removal failed: {e}"),
.map_err(|error| {
measurement_trust_removal_error(
error,
"measurement trusted machine approval",
machine_id,
)
})?
}
// Oops, forgot to set a selector.
Expand Down Expand Up @@ -233,18 +256,28 @@ pub async fn handle_remove_measurement_trusted_profile(
let approval_record: MeasurementApprovedProfileRecord = match req.selector {
// Remove by approval ID.
Some(remove_measurement_trusted_profile_request::Selector::ApprovalId(approval_uuid)) => {
let id = approval_uuid.to_string();
remove_from_approved_profiles_by_approval_id(&mut txn, approval_uuid)
.await
.map_err(|e| CarbideError::Internal {
message: format!("removal failed: {e}"),
.map_err(|error| {
measurement_trust_removal_error(
error,
"measurement trusted profile approval",
id,
)
})?
}
// Remove by profile ID.
Some(remove_measurement_trusted_profile_request::Selector::ProfileId(profile_id)) => {
let id = profile_id.to_string();
remove_from_approved_profiles_by_profile_id(&mut txn, profile_id)
.await
.map_err(|e| CarbideError::Internal {
message: format!("removal failed: {e}"),
.map_err(|error| {
measurement_trust_removal_error(
error,
"measurement trusted profile approval",
id,
)
})?
}
// Oops, forgot to set a selector.
Expand Down
97 changes: 96 additions & 1 deletion crates/api-core/src/measured_boot/tests/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ mod tests {

use ::rpc::measured_boot::{FromGrpc, FromGrpcOpt};
use carbide_uuid::machine::MachineId;
use carbide_uuid::measured_boot::TrustedMachineId;
use carbide_uuid::measured_boot::{
MeasurementApprovedMachineId, MeasurementApprovedProfileId, MeasurementSystemProfileId,
TrustedMachineId,
};
use measured_boot::pcr::PcrRegisterValue;
use measured_boot::records::MeasurementApprovedMachineRecord;
use model::machine::{CURRENT_STATE_MODEL_VERSION, ManagedHostState};
Expand Down Expand Up @@ -1641,6 +1644,98 @@ mod tests {
Ok(())
}

#[crate::sqlx_test]
async fn test_remove_measurement_trust_approvals(
db_conn: sqlx::PgPool,
) -> Result<(), Box<dyn std::error::Error>> {
let env = create_test_env(db_conn).await;
let api = &env.api;

let add_resp = site::handle_add_measurement_trusted_machine(
api,
mbrpc::AddMeasurementTrustedMachineRequest {
machine_id: "*".to_string(),
approval_type: mbrpc::MeasurementApprovedTypePb::Persist.into(),
pcr_registers: String::new(),
comments: String::new(),
},
)
.await?;
let remove_resp = site::handle_remove_measurement_trusted_machine(
api,
mbrpc::RemoveMeasurementTrustedMachineRequest {
selector: Some(
mbrpc::remove_measurement_trusted_machine_request::Selector::MachineId(
"*".to_string(),
),
),
},
)
.await?;
assert_eq!(
add_resp.approval_record.unwrap().approval_id,
remove_resp.approval_record.unwrap().approval_id
);

let missing_machine_id = site::handle_remove_measurement_trusted_machine(
api,
mbrpc::RemoveMeasurementTrustedMachineRequest {
selector: Some(
mbrpc::remove_measurement_trusted_machine_request::Selector::MachineId(
"*".to_string(),
),
),
},
)
.await
.unwrap_err();
assert_eq!(missing_machine_id.code(), tonic::Code::NotFound);

let missing_machine_approval = site::handle_remove_measurement_trusted_machine(
api,
mbrpc::RemoveMeasurementTrustedMachineRequest {
selector: Some(
mbrpc::remove_measurement_trusted_machine_request::Selector::ApprovalId(
MeasurementApprovedMachineId::new(),
),
),
},
)
.await
.unwrap_err();
assert_eq!(missing_machine_approval.code(), tonic::Code::NotFound);

let missing_profile_id = site::handle_remove_measurement_trusted_profile(
api,
mbrpc::RemoveMeasurementTrustedProfileRequest {
selector: Some(
mbrpc::remove_measurement_trusted_profile_request::Selector::ProfileId(
MeasurementSystemProfileId::new(),
),
),
},
)
.await
.unwrap_err();
assert_eq!(missing_profile_id.code(), tonic::Code::NotFound);

let missing_profile_approval = site::handle_remove_measurement_trusted_profile(
api,
mbrpc::RemoveMeasurementTrustedProfileRequest {
selector: Some(
mbrpc::remove_measurement_trusted_profile_request::Selector::ApprovalId(
MeasurementApprovedProfileId::new(),
),
),
},
)
.await
.unwrap_err();
assert_eq!(missing_profile_approval.code(), tonic::Code::NotFound);

Ok(())
}

// test_permissive_approvals is used to make sure that
// having a site-wide "permissive" approval of "*" works
// as intended.
Expand Down
3 changes: 1 addition & 2 deletions crates/api-db/src/measured_boot/interface/site.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
* tables in the database, leveraging the site-specific record types.
*/

use carbide_uuid::machine::MachineId;
use carbide_uuid::measured_boot::{
MeasurementApprovedMachineId, MeasurementApprovedProfileId, MeasurementSystemProfileId,
TrustedMachineId,
Expand Down Expand Up @@ -67,7 +66,7 @@ pub async fn remove_from_approved_machines_by_approval_id(

pub async fn remove_from_approved_machines_by_machine_id(
txn: &mut PgConnection,
machine_id: MachineId,
machine_id: TrustedMachineId,
) -> Result<MeasurementApprovedMachineRecord, DatabaseError> {
let query = "delete from measurement_approved_machines where machine_id = $1 returning *";
sqlx::query_as(query)
Expand Down
Loading
Loading