Deleting an Artifact Field (finding custom field) skips dependency checking entirely. A user can delete a field that is actively referenced in workflow nodes, breaking running executions. Model Fields have full dependency protection; Artifact Fields have none.
| Metric | Count |
|---|---|
| Active finding workflows | 44 |
Finding workflows using custom_fields.finding.* in source |
28 |
| Organizations with finding custom fields defined | 30 / 122 |
| Active/waiting/scheduled finding executions | 209 |
Any of the 28 workflows referencing finding custom fields are vulnerable. Deleting a referenced field silently breaks workflow execution — run_save_fields, validate_form, and branch conditions that reference the deleted key will fail at runtime.
The CustomFieldsManager component renders two different delete modals based on type:
// frontend/src/components/CustomFieldsManager/index.tsx:1719-1737
// Artifact Fields — bare "Are you sure?" confirmation, NO dependency check
{type !== 'models' && (
<ConfirmationAlert
title={`Deleting field: ${deleteKeyModalOpen}`}
dialogBody={'Are you sure?'}
...
/>
)}
// Model Fields — full dependency check with blocking
{type === 'models' && (
<ModelCustomFieldDeleteModal .../> // calls GET /inventory-models/schema/{key}/dependencies
)}Backend:
InventoryModelSchema.get_usage(key)→ returns{calculation_fields, workflows, finding_type_configs}InventoryModelSchema.get_usage_in_workflows(key)→ scans latest version source forcustom_fields.model.{key}referencesGET /api/v1/inventory-models/schema/{key}/dependenciesendpoint
Frontend:
ModelCustomFieldDeleteModalcalls the dependency endpoint- Shows dependent workflows as blocking resources (delete button disabled)
- Shows dependent calculation fields as blocking
- Shows finding type configs as informational warning
FindingSchema has none of this:
- No
get_usage()method - No
get_usage_in_workflows()method - No
/findings/schema/{key}/dependenciesendpoint - Frontend just shows "Are you sure?"
| File | Role |
|---|---|
backend/src/backend/db/model_inventory.py |
InventoryModelSchema.get_usage_in_workflows() — exists for models |
backend/src/backend/db/finding_schema.py |
FindingSchema — missing get_usage* methods |
backend/src/backend/db/base_schema.py |
BaseSchemaMixin — defines key_model_prefix / key_base_path |
backend/src/backend/routes/internal/inventory_models.py:1004 |
/schema/{key}/dependencies — model only |
frontend/src/components/CustomFieldsManager/index.tsx:1719 |
Branching: type !== 'models' gets no check |
frontend/src/components/ModelCustomFieldDeleteModal/index.tsx |
Full dependency modal — model only |
- Lift
get_usage()andget_usage_in_workflows()toBaseSchemaMixin— useself.key_base_path(custom_fields.modelorcustom_fields.finding) instead of hardcodingcustom_fields.model.{key} - Add
GET /findings/schema/{key}/dependenciesendpoint mirroring the model one - Rename
ModelCustomFieldDeleteModal→CustomFieldDeleteModaland make it accept atypeprop that determines which API to call - Remove the
type !== 'models'branch inCustomFieldsManager— all types use the dependency-aware modal
The custom_fields prefix pattern is defined by BaseSchemaMixin.key_base_path:
# base_schema.py:302-304
@property
def key_base_path(self):
return f"custom_fields.{self.key_model_prefix}"| Schema | key_model_prefix |
Full path in workflow source |
|---|---|---|
InventoryModelSchema |
"model" |
custom_fields.model.{key} |
FindingSchema |
"finding" |
custom_fields.finding.{key} |