Skip to content
This repository was archived by the owner on Feb 6, 2026. It is now read-only.

Commit 57ce43e

Browse files
merge: #3463
3463: Do not allow panics in the dal by default (ENG-2411) r=nickgerace a=nickgerace ## Description This PR disallows panics in the `dal` by default. It fixes or permits existing panic locations along the way. <img src="https://media1.giphy.com/media/HUkOv6BNWc1HO/giphy.gif"/> Co-authored-by: Nick Gerace <nick@systeminit.com>
2 parents 030a772 + bae64c7 commit 57ce43e

16 files changed

Lines changed: 69 additions & 35 deletions

File tree

lib/dal/src/code_view.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,14 @@ impl CodeView {
8888
};
8989

9090
let code_gen_entry: CodeGenerationEntry = serde_json::from_value(func_execution)?;
91-
if code_gen_entry.code.is_none() || code_gen_entry.format.is_none() {
92-
return Ok(None);
93-
}
94-
95-
// Safe unwraps because of the above check
96-
let format = code_gen_entry.format.as_ref().unwrap();
97-
let code = code_gen_entry.code.as_ref().unwrap();
91+
let format = match code_gen_entry.format {
92+
Some(found) => found,
93+
None => return Ok(None),
94+
};
95+
let code = match code_gen_entry.code {
96+
Some(found) => found,
97+
None => return Ok(None),
98+
};
9899

99100
let language = if format.is_empty() {
100101
CodeLanguage::Unknown

lib/dal/src/component.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,14 @@ pub enum ComponentError {
9797
LayerDb(#[from] si_layer_cache::LayerDbError),
9898
#[error("component {0} missing attribute value for code")]
9999
MissingCodeValue(ComponentId),
100+
#[error("missing controlling func data for parent attribute value id: {0}")]
101+
MissingControllingFuncDataForParentAttributeValue(AttributeValueId),
100102
#[error("component {0} missing attribute value for qualifications")]
101103
MissingQualificationsValue(ComponentId),
102104
#[error("component {0} missing attribute value for root")]
103105
MissingRootProp(ComponentId),
106+
#[error("more than one schema variant found for component: {0}")]
107+
MoreThanOneSchemaVariantFound(ComponentId),
104108
#[error("found multiple parents for component: {0}")]
105109
MultipleParentsForComponent(ComponentId),
106110
#[error("found multiple root attribute values ({0} and {1}, at minimum) for component: {2}")]
@@ -607,12 +611,12 @@ impl Component {
607611
let content_hash_discriminants: ContentAddressDiscriminants =
608612
content.content_address().into();
609613
if let ContentAddressDiscriminants::SchemaVariant = content_hash_discriminants {
610-
// TODO(nick): consider creating a new edge weight kind to make this easier.
611-
// We also should use a proper error here.
612614
schema_variant_id = match schema_variant_id {
613615
None => Some(content.id().into()),
614616
Some(_already_found_schema_variant_id) => {
615-
panic!("already found a schema variant")
617+
return Err(ComponentError::MoreThanOneSchemaVariantFound(
618+
component_id,
619+
));
616620
}
617621
};
618622
}
@@ -1120,8 +1124,9 @@ impl Component {
11201124
// if av has a parent and parent is controlled by dynamic func, that's the controller
11211125
// else av controls itself
11221126
let controlling_tuple = if let Some(parent_av_id) = maybe_parent_av_id {
1123-
// We can unwrap because if we're on the child, we've added the parent to result
1124-
let parent_controlling_data = *result.get(&parent_av_id).unwrap();
1127+
let parent_controlling_data = *result.get(&parent_av_id).ok_or(
1128+
ComponentError::MissingControllingFuncDataForParentAttributeValue(parent_av_id),
1129+
)?;
11251130

11261131
if parent_controlling_data.is_dynamic_func {
11271132
parent_controlling_data

lib/dal/src/context.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ impl ConnectionState {
183183
matches!(self, Self::Connections(_))
184184
}
185185

186+
#[allow(clippy::panic)]
186187
fn txns(&mut self) -> &mut Transactions {
187188
match self {
188189
Self::Transactions(txns) => txns,
@@ -625,20 +626,19 @@ impl DalContext {
625626
new
626627
}
627628

628-
pub async fn parent_is_head(&self) -> bool {
629+
pub async fn parent_is_head(&self) -> Result<bool, TransactionsError> {
629630
if let Some(workspace_pk) = self.tenancy.workspace_pk() {
630631
let workspace = Workspace::get_by_pk(self, &workspace_pk)
631632
.await
632-
.unwrap()
633-
.unwrap();
634-
workspace.default_change_set_id()
635-
== self
636-
.change_set_pointer()
637-
.unwrap()
638-
.base_change_set_id
639-
.unwrap()
633+
.map_err(|err| TransactionsError::Workspace(err.to_string()))?
634+
.ok_or(TransactionsError::WorkspaceNotFound(workspace_pk))?;
635+
let change_set = self.change_set_pointer()?;
636+
let base_change_set_id = change_set
637+
.base_change_set_id
638+
.ok_or(TransactionsError::NoBaseChangeSet(change_set.id))?;
639+
Ok(workspace.default_change_set_id() == base_change_set_id)
640640
} else {
641-
false
641+
Ok(false)
642642
}
643643
}
644644

@@ -1028,6 +1028,8 @@ pub enum TransactionsError {
10281028
JobQueueProcessor(#[from] JobQueueProcessorError),
10291029
#[error(transparent)]
10301030
Nats(#[from] NatsError),
1031+
#[error("no base change set for change set: {0}")]
1032+
NoBaseChangeSet(ChangeSetId),
10311033
#[error(transparent)]
10321034
Pg(#[from] PgError),
10331035
#[error(transparent)]

lib/dal/src/func.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub enum FuncError {
3232
Base64Decode(#[from] base64::DecodeError),
3333
#[error("change set error: {0}")]
3434
ChangeSet(#[from] ChangeSetPointerError),
35+
#[error("chrono parse error: {0}")]
36+
ChronoParse(#[from] chrono::ParseError),
3537
#[error("edge weight error: {0}")]
3638
EdgeWeight(#[from] EdgeWeightError),
3739
#[error("cannot find intrinsic func {0}")]

lib/dal/src/func/backend/js_action.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ impl FuncDispatch for FuncBackendJsAction {
3838
execution_id: "ayrtonsennajscommand".to_string(),
3939
handler: handler.into(),
4040
code_base64: code_base64.into(),
41-
args: serde_json::to_value(args).unwrap(),
41+
args: serde_json::to_value(args)
42+
.expect("should be impossible to fail serialization here"),
4243
before,
4344
};
4445

lib/dal/src/func/backend/js_reconciliation.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ impl FuncDispatch for FuncBackendJsReconciliation {
5151
execution_id: "freeronaldinhogauchojsreconciliation".to_string(),
5252
handler: handler.into(),
5353
code_base64: code_base64.into(),
54-
args: serde_json::to_value(args).unwrap(),
54+
args: serde_json::to_value(args)
55+
.expect("should be impossible to fail serialization here"),
5556
before,
5657
};
5758

lib/dal/src/func/intrinsics.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,9 @@ impl IntrinsicFunc {
2727
let mut builder = PkgSpec::builder();
2828
builder.name("si-intrinsic-funcs");
2929
builder.version("2023-05-24");
30-
builder.created_at(
31-
DateTime::parse_from_rfc2822("Wed, 24 May 2023 00:00:00 PST")
32-
.expect("able to parse default datetime"),
33-
);
30+
builder.created_at(DateTime::parse_from_rfc2822(
31+
"Wed, 24 May 2023 00:00:00 PST",
32+
)?);
3433
builder.created_by("System Initiative");
3534
for instrinsic in IntrinsicFunc::iter() {
3635
builder.func(instrinsic.to_spec()?);

lib/dal/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
//! The Data Access Layer (DAL) for System Initiative.
22
3+
#![warn(
4+
clippy::panic,
5+
clippy::panic_in_result_fn,
6+
clippy::unwrap_in_result,
7+
clippy::unwrap_used
8+
)]
9+
310
use std::time::Duration;
411

512
use rand::Rng;

lib/dal/src/pkg.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ pub enum PkgError {
8585
SchemaVariant(#[from] SchemaVariantError),
8686
#[error("json serialization error: {0}")]
8787
SerdeJson(#[from] serde_json::Error),
88+
#[error("taking output socket as input for a prop is unsupported for name ({0}) and socket name ({1})")]
89+
TakingOutputSocketAsInputForPropUnsupported(String, String),
8890
#[error("transactions error: {0}")]
8991
Transactions(#[from] TransactionsError),
9092
#[error(transparent)]

lib/dal/src/pkg/import.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3069,9 +3069,13 @@ async fn create_attr_proto_arg(
30693069
.await?;
30703070
apa_id
30713071
}
3072-
_ => {
3073-
// xxx: make this an error
3074-
panic!("unsupported taking output socket as input for prop");
3072+
SiPkgAttrFuncInputView::OutputSocket {
3073+
name, socket_name, ..
3074+
} => {
3075+
return Err(PkgError::TakingOutputSocketAsInputForPropUnsupported(
3076+
name.to_owned(),
3077+
socket_name.to_owned(),
3078+
));
30753079
}
30763080
})
30773081
}

0 commit comments

Comments
 (0)