Skip to content
Draft
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
11 changes: 7 additions & 4 deletions cmd/api/src/api/v2/graphschema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func TestResources_ListEdgeTypes(t *testing.T) {
Value: "true",
}},
}, model.Sort{}, 0, 0).Return(model.GraphSchemaRelationshipKindsWithNamedSchema{
model.GraphSchemaRelationshipKindWithNamedSchema{ID: 1, Name: "Edge_Kind_1", Description: "Edge Kind 1", IsTraversable: true, SchemaName: "extension_a"}, model.GraphSchemaRelationshipKindWithNamedSchema{ID: 2, Name: "Edge_Kind_2", Description: "Edge Kind 2", IsTraversable: true, SchemaName: "extension_a"}, model.GraphSchemaRelationshipKindWithNamedSchema{ID: 3, Name: "Edge_Kind_3", Description: "Edge Kind 3", IsTraversable: true, SchemaName: "extension_a"},
model.GraphSchemaRelationshipKindWithNamedSchema{ID: 1, Name: "Edge_Kind_1", Description: "Edge Kind 1", IsTraversable: true, SchemaName: "extension_a", IsBuiltin: true}, model.GraphSchemaRelationshipKindWithNamedSchema{ID: 2, Name: "Edge_Kind_2", Description: "Edge Kind 2", IsTraversable: true, SchemaName: "extension_a", IsBuiltin: true}, model.GraphSchemaRelationshipKindWithNamedSchema{ID: 3, Name: "Edge_Kind_3", Description: "Edge Kind 3", IsTraversable: true, SchemaName: "extension_a", IsBuiltin: true},
}, 3, nil)
},
expected: expected{
Expand All @@ -159,21 +159,24 @@ func TestResources_ListEdgeTypes(t *testing.T) {
"name": "Edge_Kind_1",
"description": "Edge Kind 1",
"is_traversable": true,
"schema_name": "extension_a"
"schema_name": "extension_a",
"is_builtin": true
},
{
"id": 2,
"name": "Edge_Kind_2",
"description": "Edge Kind 2",
"is_traversable": true,
"schema_name": "extension_a"
"schema_name": "extension_a",
"is_builtin": true
},
{
"id": 3,
"name": "Edge_Kind_3",
"description": "Edge Kind 3",
"is_traversable": true,
"schema_name": "extension_a"
"schema_name": "extension_a",
"is_builtin": true
}]}`,
},
}}
Expand Down
2 changes: 1 addition & 1 deletion cmd/api/src/database/graphschema.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ func (s *BloodhoundDB) GetGraphSchemaRelationshipKindsWithSchemaName(ctx context
if filterAndPagination, err := parseFiltersAndPagination(relationshipKindFilters, sort, skip, limit); err != nil {
return schemaRelationshipKinds, 0, err
} else {
sqlStr := fmt.Sprintf(`SELECT edge.id, k.name, edge.description, edge.is_traversable, schema.name as schema_name
sqlStr := fmt.Sprintf(`SELECT edge.id, k.name, edge.description, edge.is_traversable, schema.name as schema_name, schema.is_builtin
FROM %s edge JOIN %s schema ON edge.schema_extension_id = schema.id JOIN %s k ON edge.kind_id = k.id %s %s %s`,
model.GraphSchemaRelationshipKind{}.TableName(),
model.GraphSchemaExtension{}.TableName(),
Expand Down
34 changes: 32 additions & 2 deletions cmd/api/src/database/graphschema_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3609,7 +3609,8 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
if rk.Name == want.Name &&
rk.Description == want.Description &&
rk.IsTraversable == want.IsTraversable &&
rk.SchemaName == want.SchemaName {
rk.SchemaName == want.SchemaName &&
rk.IsBuiltin == want.IsBuiltin {

// Additional validations for the found item
assert.Greater(t, rk.ID, int32(0), "RelationshipKind %v - ID is invalid", rk.Name)
Expand All @@ -3629,7 +3630,8 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
if rk.Name == want.Name &&
rk.Description == want.Description &&
rk.IsTraversable == want.IsTraversable &&
rk.SchemaName == want.SchemaName {
rk.SchemaName == want.SchemaName &&
rk.IsBuiltin == want.IsBuiltin {

assert.Failf(t, "Unexpected relationship kind found", "Relationship kind %v should not be present", want.Name)
}
Expand Down Expand Up @@ -3692,13 +3694,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind1.Name,
Description: edgeKind1.Description,
IsTraversable: edgeKind1.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}
want2 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind2.ID,
SchemaName: extensionA.Name,
Name: edgeKind2.Name,
Description: edgeKind2.Description,
IsTraversable: edgeKind2.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}

want3 := model.GraphSchemaRelationshipKindWithNamedSchema{
Expand All @@ -3707,13 +3711,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind3.Name,
Description: edgeKind3.Description,
IsTraversable: edgeKind3.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}
want4 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind4.ID,
SchemaName: extensionB.Name,
Name: edgeKind4.Name,
Description: edgeKind4.Description,
IsTraversable: edgeKind4.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}

// Validate edge kinds are as expected
Expand Down Expand Up @@ -3774,13 +3780,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind1.Name,
Description: edgeKind1.Description,
IsTraversable: edgeKind1.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}
want2 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind2.ID,
SchemaName: extensionA.Name,
Name: edgeKind2.Name,
Description: edgeKind2.Description,
IsTraversable: edgeKind2.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}

want3 := model.GraphSchemaRelationshipKindWithNamedSchema{
Expand All @@ -3789,13 +3797,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind3.Name,
Description: edgeKind3.Description,
IsTraversable: edgeKind3.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}
want4 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind4.ID,
SchemaName: extensionB.Name,
Name: edgeKind4.Name,
Description: edgeKind4.Description,
IsTraversable: edgeKind4.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}

// Validate edge kinds are as expected
Expand Down Expand Up @@ -3844,6 +3854,7 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind1.Name,
Description: edgeKind1.Description,
IsTraversable: edgeKind1.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}

want2 := model.GraphSchemaRelationshipKindWithNamedSchema{
Expand All @@ -3852,6 +3863,7 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind2.Name,
Description: edgeKind2.Description,
IsTraversable: edgeKind2.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}

// Validate edge kinds are as expected
Expand Down Expand Up @@ -3907,13 +3919,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind1.Name,
Description: edgeKind1.Description,
IsTraversable: edgeKind1.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}
want2 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind2.ID,
SchemaName: extensionA.Name,
Name: edgeKind2.Name,
Description: edgeKind2.Description,
IsTraversable: edgeKind2.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}

want3 := model.GraphSchemaRelationshipKindWithNamedSchema{
Expand All @@ -3922,13 +3936,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind3.Name,
Description: edgeKind3.Description,
IsTraversable: edgeKind3.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}
want4 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind4.ID,
SchemaName: extensionB.Name,
Name: edgeKind4.Name,
Description: edgeKind4.Description,
IsTraversable: edgeKind4.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}

// Validate edge kinds are as expected
Expand Down Expand Up @@ -3991,13 +4007,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind1.Name,
Description: edgeKind1.Description,
IsTraversable: edgeKind1.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}
want2 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind2.ID,
SchemaName: extensionA.Name,
Name: edgeKind2.Name,
Description: edgeKind2.Description,
IsTraversable: edgeKind2.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}

want3 := model.GraphSchemaRelationshipKindWithNamedSchema{
Expand All @@ -4006,13 +4024,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind3.Name,
Description: edgeKind3.Description,
IsTraversable: edgeKind3.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}
want4 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind4.ID,
SchemaName: extensionB.Name,
Name: edgeKind4.Name,
Description: edgeKind4.Description,
IsTraversable: edgeKind4.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}

// Validate edge kinds are as expected
Expand Down Expand Up @@ -4068,13 +4088,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind1.Name,
Description: edgeKind1.Description,
IsTraversable: edgeKind1.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}
want2 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind2.ID,
SchemaName: extensionA.Name,
Name: edgeKind2.Name,
Description: edgeKind2.Description,
IsTraversable: edgeKind2.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}

want3 := model.GraphSchemaRelationshipKindWithNamedSchema{
Expand All @@ -4083,13 +4105,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind3.Name,
Description: edgeKind3.Description,
IsTraversable: edgeKind3.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}
want4 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind4.ID,
SchemaName: extensionB.Name,
Name: edgeKind4.Name,
Description: edgeKind4.Description,
IsTraversable: edgeKind4.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}

// Validate edge kinds are as expected
Expand Down Expand Up @@ -4145,13 +4169,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind1.Name,
Description: edgeKind1.Description,
IsTraversable: edgeKind1.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}
want2 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind2.ID,
SchemaName: extensionA.Name,
Name: edgeKind2.Name,
Description: edgeKind2.Description,
IsTraversable: edgeKind2.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}

want3 := model.GraphSchemaRelationshipKindWithNamedSchema{
Expand All @@ -4160,13 +4186,15 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind3.Name,
Description: edgeKind3.Description,
IsTraversable: edgeKind3.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}
want4 := model.GraphSchemaRelationshipKindWithNamedSchema{
ID: edgeKind4.ID,
SchemaName: extensionB.Name,
Name: edgeKind4.Name,
Description: edgeKind4.Description,
IsTraversable: edgeKind4.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}

// Validate edge kinds are as expected
Expand Down Expand Up @@ -4264,6 +4292,7 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind1.Name,
Description: edgeKind1.Description,
IsTraversable: edgeKind1.IsTraversable,
IsBuiltin: extensionA.IsBuiltin,
}

want2 := model.GraphSchemaRelationshipKindWithNamedSchema{
Expand All @@ -4272,6 +4301,7 @@ func TestDatabase_GetGraphSchemaRelationshipKindsWithSchemaName(t *testing.T) {
Name: edgeKind2.Name,
Description: edgeKind2.Description,
IsTraversable: edgeKind2.IsTraversable,
IsBuiltin: extensionB.IsBuiltin,
}

// Assert total is as expected
Expand Down
47 changes: 47 additions & 0 deletions cmd/api/src/database/migration/migrations/v8.7.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,50 @@ CREATE TABLE IF NOT EXISTS schema_list_findings (

CREATE INDEX IF NOT EXISTS idx_schema_list_findings_extension_id ON schema_list_findings (schema_extension_id);
CREATE INDEX IF NOT EXISTS idx_schema_list_findings_environment_id ON schema_list_findings(environment_id);

-- Drop unique name constraint before migrating to PZ in case AGT names are not unique
ALTER TABLE IF EXISTS asset_group_tag_selectors DROP CONSTRAINT IF EXISTS asset_group_tag_selectors_unique_name_asset_group_tag;

-- Remigrate old custom AGI selectors to PZ selectors for any instances without PZ feature flag enabled
DO $$
BEGIN
IF
(SELECT enabled FROM feature_flags WHERE key = 'tier_management_engine') = false
THEN
-- Delete custom selectors
DELETE FROM asset_group_tag_selectors WHERE is_default = false AND asset_group_tag_id IN ((SELECT id FROM asset_group_tags WHERE position = 1), (SELECT id FROM asset_group_tags WHERE type = 3));

-- Re-Migrate existing Tier Zero selectors
WITH inserted_selector AS (
INSERT INTO asset_group_tag_selectors (asset_group_tag_id, created_at, created_by, updated_at, updated_by, name, description, is_default, allow_disable, auto_certify)
SELECT (SELECT id FROM asset_group_tags WHERE position = 1), current_timestamp, 'BloodHound', current_timestamp, 'BloodHound', s.name, s.selector, false, true, 2
FROM asset_group_selectors s JOIN asset_groups ag ON ag.id = s.asset_group_id
WHERE ag.tag = 'admin_tier_0' and NOT EXISTS(SELECT 1 FROM asset_group_tag_selectors WHERE name = s.name)
RETURNING id, description
)
INSERT INTO asset_group_tag_selector_seeds (selector_id, type, value) SELECT id, 1, description FROM inserted_selector;

-- Re-Migrate existing Owned selectors
WITH inserted_selector AS (
INSERT INTO asset_group_tag_selectors (asset_group_tag_id, created_at, created_by, updated_at, updated_by, name, description, is_default, allow_disable, auto_certify)
SELECT (SELECT id FROM asset_group_tags WHERE type = 3), current_timestamp, 'BloodHound', current_timestamp, 'BloodHound', s.name, s.selector, false, true, 0
FROM asset_group_selectors s JOIN asset_groups ag ON ag.id = s.asset_group_id
WHERE ag.tag = 'owned' and NOT EXISTS(SELECT 1 FROM asset_group_tag_selectors WHERE name = s.name)
RETURNING id, description
)
INSERT INTO asset_group_tag_selector_seeds (selector_id, type, value) SELECT id, 1, description FROM inserted_selector;
END IF;
END;
$$;

-- Before we add unique constraint, rename any duplicates with `_X` to prevent constraint failing
WITH duplicate_selectors AS (
SELECT id, name, asset_group_tag_id, ROW_NUMBER() OVER (PARTITION BY name, asset_group_tag_id ORDER BY id) AS rowNumber
FROM asset_group_tag_selectors
)
UPDATE asset_group_tag_selectors agts
SET name = agts.name || '_' || rowNumber FROM duplicate_selectors
WHERE agts.id = duplicate_selectors.id AND duplicate_selectors.rowNumber > 1;

-- Reinstate unique constraint for asset group tag selectors name per asset group tag
ALTER TABLE IF EXISTS asset_group_tag_selectors ADD CONSTRAINT asset_group_tag_selectors_unique_name_asset_group_tag UNIQUE ("name",asset_group_tag_id,is_default);
1 change: 1 addition & 0 deletions cmd/api/src/model/graphschema.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ type GraphSchemaRelationshipKindWithNamedSchema struct {
Description string `json:"description"`
IsTraversable bool `json:"is_traversable"`
SchemaName string `json:"schema_name"`
IsBuiltin bool `json:"is_builtin"`
}

type GraphSchemaRelationshipKindsWithNamedSchema []GraphSchemaRelationshipKindWithNamedSchema
Expand Down
3 changes: 2 additions & 1 deletion packages/go/openapi/doc/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -22337,7 +22337,8 @@
"Groups",
"Data Quality",
"Datapipe",
"Cypher"
"Cypher",
"OpenGraph"
]
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ properties:
type: boolean
schema_name:
type: string
is_builtin:
type: boolean
2 changes: 1 addition & 1 deletion packages/javascript/bh-shared-ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ export { default as CollectorCard } from './CollectorCard';
export * from './CollectorCardList';
export { default as CollectorCardList } from './CollectorCardList';
export * from './ColumnHeaders';
export * from './ConditionalTooltip';
export * from './CommunityIcon';
export { default as CommunityIcon } from './CommunityIcon';
export * from './ConditionalTooltip';
export * from './ConfirmationDialog';
export { default as ConfirmationDialog } from './ConfirmationDialog';
export * from './CreateMenu';
Expand Down
Loading