Skip to content

Conversation

@rtpt-romankarwacik
Copy link

@rtpt-romankarwacik rtpt-romankarwacik commented Nov 26, 2025

Description

This pull requests adds an option for database management to delete HasSession edges. The pull request has been created using GitHub Copilot.
#853

Motivation and Context

When analyzing sessions the current state is very important. Currently, when ingesting new sessions, the old ones are not deleted. This resolves #853

How Has This Been Tested?

I tested it with dummy data from the UI, where i queried all sessions after insertion, and after deletion.

Screenshots (optional):

Screenshot From 2025-11-26 10-54-00

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist:

Summary by CodeRabbit

  • New Features

    • Add ability to specify relationship types to remove during database cleanup; UI adds a checkbox to remove HasSession edges.
    • Wipe operation logs audit outcomes for relationship deletions.
  • Documentation

    • API spec and client request schema updated with new deleteRelationships array.
  • Tests

    • UI tests updated for the additional checklist item.

✏️ Tip: You can customize this high-level summary in your review settings.

@github-actions
Copy link

github-actions bot commented Nov 26, 2025

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

Walkthrough

Adds a flexible relationship-deletion option to the clear-database flow: UI checkbox state, API payload field deleteRelationships []string, backend flow to locate and batch-delete named graph edges via a new Resources.deleteEdges method, OpenAPI/JS client schema updates, and audit logging for success/failure. (39 words)

Changes

Cohort / File(s) Summary
Backend API / Wipe Logic
cmd/api/src/api/v2/database_wipe.go
Added DeleteRelationships []string to DatabaseWipe; extended empty-request validation to consider DeleteRelationships; added Resources.deleteEdges(ctx, auditEntry, edgeNames) which finds relationships by name via graph query and batch-deletes them; integrated audit logging for per-edge-name success/failure; added graph ops and query imports.
React UI
cmd/ui/src/views/DatabaseManagement/DatabaseManagement.tsx, cmd/ui/src/views/DatabaseManagement/DatabaseManagement.test.tsx
Added deleteHasSessionEdges boolean state and reducer handling; added a FormControlLabel + Checkbox for HasSession edges (permission-gated); include deleteRelationships: ['HasSession'] in mutation payload when checked; updated tests to expect the new checklist item and checkbox count.
OpenAPI / API Schema
packages/go/openapi/doc/openapi.json, packages/go/openapi/src/paths/data-quality.clear-database.yaml
Request schema for DELETE /api/v2/clear-database extended with deleteRelationships (array of strings); operation descriptions updated to mention deletable relationship types.
JavaScript Client
packages/javascript/js-client-library/src/requests.ts
Added optional deleteRelationships?: string[] to the ClearDatabaseRequest interface.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as DatabaseManagement UI
    participant API as Backend API
    participant Graph as Graph DB
    participant Audit as Audit Log

    User->>UI: Check "HasSession" and submit clear-database
    UI->>API: DELETE /api/v2/clear-database { ..., deleteRelationships: ["HasSession"] }

    alt deleteRelationships contains names
        API->>API: validate request, create audit entry
        API->>Graph: Query relationships matching each name (by edge type/name)
        Graph-->>API: Return matching relationship ids
        API->>Graph: Batch-delete returned relationships
        Graph-->>API: Deletion results per edge-name
        API->>Audit: Record success/failure for each edge-name
    end

    API-->>UI: Return wipe result (including any edge-delete failures)
    UI->>User: Show confirmation/errors
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Check the graph query construction and matching criteria for edge names.
  • Verify batching/pagination and error handling in deleteEdges.
  • Confirm audit entries accurately reflect per-edge successes/failures.
  • Validate UI state-to-payload mapping (deleteHasSessionEdgesdeleteRelationships: ['HasSession']) and permission gating.
  • Ensure OpenAPI and JS client types match backend names (deleteRelationships as string[]).

Suggested labels

enhancement, user interface

Suggested reviewers

  • brandonshearin
  • cweidenkeller

Poem

🐰 I hopped the graph and found each thread,
A tiny nibble and the edges fled.
A checkbox flicked, the audit sang too,
Clean nodes, clear hops — a fresher view.
Hooray for tidy trees, from me to you! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main feature added: a new option to delete HasSession edges in database management.
Description check ✅ Passed The description covers main changes, motivation, and testing, but the contributing prerequisites checklist section is incomplete (not all items checked and some have outdated issue references).
Linked Issues check ✅ Passed The PR successfully implements the core requirement from issue #853: adds a deleteRelationships option to the /clear-database endpoint [#853], extends UI with HasSession edge deletion checkbox [#853], and updates API documentation [#853].
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing HasSession edge deletion functionality; no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rtpt-romankarwacik
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
cmd/api/src/api/v2/database_wipe.go (1)

251-276: Consider using a streaming pattern for better scalability.

The current implementation uses ops.FetchRelationships which loads all HasSession relationships into memory at once. For environments with many session edges, this could cause high memory consumption or OOM issues.

The existing DeleteCollectedGraphData function (referenced in relevant snippets) uses a more scalable streaming approach with ops.StartNewOperation, readers, writers, and channels to process IDs incrementally without loading everything into memory.

Consider refactoring to use the streaming pattern:

 func (s Resources) deleteHasSessionEdges(ctx context.Context, auditEntry *model.AuditEntry) (failure bool) {
-	// Use the graph batch API to find and delete all HasSession relationships
-	if err := s.Graph.BatchOperation(ctx, func(batch graph.Batch) error {
-		targetCriteria := query.Kind(query.Relationship(), ad.HasSession)
-
-		rels, err := ops.FetchRelationships(batch.Relationships().Filter(targetCriteria))
-		if err != nil {
-			return err
-		}
-
-		for _, rel := range rels {
-			if err := batch.DeleteRelationship(rel.ID); err != nil {
-				return err
-			}
-		}
-
-		return nil
-	}); err != nil {
+	operation := ops.StartNewOperation[graph.ID](ops.OperationContext{
+		Parent:     ctx,
+		DB:         s.Graph,
+		NumReaders: 1,
+		NumWriters: 1,
+	})
+
+	operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- graph.ID) error {
+		return tx.Relationships().Filter(
+			query.Kind(query.Relationship(), ad.HasSession),
+		).FetchIDs(func(cursor graph.Cursor[graph.ID]) error {
+			for id := range cursor.Chan() {
+				select {
+				case <-ctx.Done():
+					return ctx.Err()
+				case outC <- id:
+				}
+			}
+			return cursor.Error()
+		})
+	})
+
+	operation.SubmitWriter(func(ctx context.Context, batch graph.Batch, inC <-chan graph.ID) error {
+		for {
+			select {
+			case <-ctx.Done():
+				return ctx.Err()
+			case id, ok := <-inC:
+				if !ok {
+					return nil
+				}
+				if err := batch.DeleteRelationship(id); err != nil {
+					return err
+				}
+			}
+		}
+	})
+
+	if err := operation.Done(); err != nil {
 		slog.ErrorContext(ctx, fmt.Sprintf("%s: %s", "there was an error deleting HasSession edges", err.Error()))
 		s.handleAuditLogForDatabaseWipe(ctx, auditEntry, false, "HasSession edges")
 		return true
 	} else {
 		s.handleAuditLogForDatabaseWipe(ctx, auditEntry, true, "HasSession edges")
 		return false
 	}
 }
packages/go/openapi/doc/openapi.json (1)

13319-13319: Clarify description and align terminology with schema.

  • The description says “custom high value selectors,” but the request body uses deleteAssetGroupSelectors. Consider replacing with “asset group selectors” for consistency and to avoid ambiguity. Also, briefly state that deleteHasSessionEdges deletes only HasSession relationships, not nodes. Adding a small request example would help.

Example (description tweak only):

- Wipes your BloodHound data permanently. Specify the data to delete in the request body. Possible data includes collected graph data, HasSession relationship edges, custom high value selectors, file ingest history, and data quality history.
+ Wipes your BloodHound data permanently. Specify the data to delete in the request body. Possible data includes collected graph data, HasSession relationship edges, asset group selectors, file ingest history, and data quality history.

Optionally add a request example under requestBody.content.application/json.example:

{
  "deleteHasSessionEdges": true
}

Based on learnings, this JSON file is generated; please ensure the change is applied to the YAML under packages/go/openapi/src/schemas and the spec is regenerated.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c58475e and 44783e1.

📒 Files selected for processing (5)
  • cmd/api/src/api/v2/database_wipe.go (4 hunks)
  • cmd/ui/src/views/DatabaseManagement/DatabaseManagement.tsx (8 hunks)
  • packages/go/openapi/doc/openapi.json (2 hunks)
  • packages/go/openapi/src/paths/data-quality.clear-database.yaml (2 hunks)
  • packages/javascript/js-client-library/src/requests.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-09-08T19:01:53.112Z
Learnt from: jvacca-specterops
Repo: SpecterOps/BloodHound PR: 1823
File: packages/javascript/bh-shared-ui/src/views/Explore/ExploreSearch/CypherSearch.tsx:108-148
Timestamp: 2025-09-08T19:01:53.112Z
Learning: In BloodHound's CypherSearch component (packages/javascript/bh-shared-ui/src/views/Explore/ExploreSearch/CypherSearch.tsx), the sharing state reset for sharedIds and isPublic after the two-step permissions update is handled elsewhere in the codebase, so additional state reset callbacks in the updateQueryPermissions function are not needed.

Applied to files:

  • cmd/ui/src/views/DatabaseManagement/DatabaseManagement.tsx
📚 Learning: 2025-11-25T22:11:53.509Z
Learnt from: LawsonWillard
Repo: SpecterOps/BloodHound PR: 2107
File: cmd/api/src/database/graphschema.go:86-100
Timestamp: 2025-11-25T22:11:53.509Z
Learning: In cmd/api/src/database/graphschema.go, the CreateSchemaEdgeKind method intentionally does not use AuditableTransaction or audit logging because it would create too much noise in the audit log, unlike CreateGraphSchemaExtension which does use auditing.

Applied to files:

  • cmd/api/src/api/v2/database_wipe.go
📚 Learning: 2025-08-28T16:43:43.961Z
Learnt from: mvlipka
Repo: SpecterOps/BloodHound PR: 1784
File: packages/go/openapi/doc/openapi.json:18008-18029
Timestamp: 2025-08-28T16:43:43.961Z
Learning: In SpecterOps/BloodHound, packages/go/openapi/doc/openapi.json is generated from YAML under packages/go/openapi/src/schemas; edits must be made to the YAML and then the spec regenerated.

Applied to files:

  • packages/go/openapi/doc/openapi.json
📚 Learning: 2025-11-25T18:07:04.522Z
Learnt from: superlinkx
Repo: SpecterOps/BloodHound PR: 2083
File: cmd/api/src/model/graphschema.go:42-53
Timestamp: 2025-11-25T18:07:04.522Z
Learning: In the BloodHound codebase (SpecterOps/BloodHound), database models are moving toward a newer architecture where API validation is handled via `jsonschema` at the handler level, which obviates the need for json validation tags on database models themselves.

Applied to files:

  • packages/go/openapi/doc/openapi.json
🧬 Code graph analysis (1)
cmd/api/src/api/v2/database_wipe.go (2)
cmd/api/src/daemons/datapipe/delete.go (1)
  • DeleteCollectedGraphData (33-113)
packages/go/graphschema/ad/ad.go (2)
  • HasSession (53-53)
  • Relationships (1149-1151)
🔇 Additional comments (5)
packages/go/openapi/src/paths/data-quality.clear-database.yaml (1)

24-25: LGTM! Schema changes are correct and consistent.

The OpenAPI schema updates properly document and expose the new HasSession edge deletion capability. The field naming and structure follow the existing patterns for other deletion options.

Also applies to: 38-39

cmd/api/src/api/v2/database_wipe.go (1)

32-35: LGTM! Integration and validation changes are correct.

The struct field addition, imports, empty-request validation, and main workflow integration all follow the established patterns used by other deletion options in this file.

Also applies to: 41-41, 70-70, 195-200

packages/javascript/js-client-library/src/requests.ts (1)

241-241: LGTM! TypeScript interface update is correct.

The optional field addition properly mirrors the backend API and OpenAPI schema, maintaining type consistency across the stack.

cmd/ui/src/views/DatabaseManagement/DatabaseManagement.tsx (1)

42-42: LGTM! UI implementation is correct and consistent.

The React component changes properly integrate the new HasSession edges deletion option:

  • State management follows the established patterns for other checkboxes
  • The reducer correctly handles initialization, selection, reset, and validation
  • The UI checkbox respects permissions and is appropriately labeled
  • The mutation payload correctly includes the new field

All changes align with the existing implementation patterns in this component.

Also applies to: 59-59, 107-107, 137-137, 177-177, 224-224, 263-263, 371-381

packages/go/openapi/doc/openapi.json (1)

13334-13336: Based on my verification, I have sufficient information to assess the review comment. The key findings are:

  1. Context confirmed: The review is for proposed changes adding deleteHasSessionEdges to the clear-database endpoint—this field does not yet exist in the codebase.

  2. YAML source verified: The source file at packages/go/openapi/src/paths/data-quality.clear-database.yaml currently defines 4 properties without individual descriptions.

  3. Current properties: deleteCollectedGraphData, deleteFileIngestHistory, deleteDataQualityHistory, deleteAssetGroupSelectors

  4. Review concerns are valid:

    • Naming consistency across layers (Go, YAML, UI, JS client) is a legitimate concern
    • Input validation (ensuring at least one flag) is a reasonable schema pattern
    • Adding descriptions to properties follows API documentation best practices
    • Regenerating from YAML (not hand-editing JSON) is the correct process

The review comment is technically sound. However, I can streamline it by removing the overly complex verification script (which searches for typos that don't exist yet) and focusing on the core actionable items.


Verify the new deleteHasSessionEdges field is consistently named across all implementation layers and properly validated in the schema.

  • Field name follows existing camelCase pattern (good). Ensure it matches exactly in: Go request struct/handler, YAML schema, UI form key, and JS client.
  • Add a short description for this property in the YAML schema (other properties currently lack individual descriptions; consider adding for consistency).
  • Consider adding schema validation (e.g., anyOf constraint) to require at least one delete flag to prevent no-op requests.
  • Critical: Update packages/go/openapi/src/paths/data-quality.clear-database.yaml with this field, then regenerate packages/go/openapi/doc/openapi.json per project standards. Do not edit the JSON file directly.

@rvazarkar
Copy link
Contributor

This is a great PR. Going to take some time to review it and go through our workflow. Thank you!

@rvazarkar
Copy link
Contributor

recheck

@urangel urangel changed the title Add option to delete HasSession edges feat: Add option to delete HasSession edges #853 Dec 2, 2025
@rvazarkar
Copy link
Contributor

There is a failing test in the MR. Could you patch that up so it fixes the UI test run?

@rvazarkar
Copy link
Contributor

Also we require commit signing as part of our PR process. Can you set up commit signing and then use a squash to sign all of your commits into a single signed one?

The process for squashing is here:

https://www.freecodecamp.org/news/git-squash-commits/

And the process for setting up commit signing is here:

https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
cmd/api/src/api/v2/database_wipe.go (1)

41-41: DeleteHasSessionEdges flag wiring looks sound; clarify interaction with full graph deletion and feature flag

The new DeleteHasSessionEdges field is correctly:

  • Exposed on the DatabaseWipe payload with a safe default (false), so existing clients remain compatible.
  • Included in the “empty request” check, allowing a request that only deletes HasSession edges.
  • Plumbed into the handler with consistent error aggregation and audit logging via deleteHasSessionEdges.

Two behavioral points you may want to tighten up:

  1. Combination with full graph deletion
    Right now, a request can set both deleteCollectedGraphData (or deleteSourceKinds) and deleteHasSessionEdges. Functionally this means:

    • You enqueue a full collected-graph deletion job, and
    • You synchronously wipe HasSession edges in the same request.
      That’s redundant at best and could be confusing from an API/UX perspective. Consider either:
    • Explicitly rejecting this combination (similar to the existing deleteCollectedGraphData vs deleteSourceKinds guard), or
    • Clearly documenting that DeleteHasSessionEdges is ignored when a full graph delete is requested.
  2. Feature flag coverage
    The FeatureClearGraphData flag currently gates only DeleteCollectedGraphData / DeleteSourceKinds, not DeleteHasSessionEdges. If that feature flag is intended as a general “no destructive graph operations” kill switch, you may want to include DeleteHasSessionEdges under the same guard; otherwise, this is a deliberate carve‑out that should be documented.

These are semantics/UX clarifications rather than correctness issues, but addressing them now will prevent surprising behavior for API clients and operators.

Also applies to: 69-71, 195-200

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44783e1 and 0ffaec4.

📒 Files selected for processing (5)
  • cmd/api/src/api/v2/database_wipe.go (4 hunks)
  • cmd/ui/src/views/DatabaseManagement/DatabaseManagement.tsx (8 hunks)
  • packages/go/openapi/doc/openapi.json (2 hunks)
  • packages/go/openapi/src/paths/data-quality.clear-database.yaml (2 hunks)
  • packages/javascript/js-client-library/src/requests.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/javascript/js-client-library/src/requests.ts
  • packages/go/openapi/src/paths/data-quality.clear-database.yaml
  • cmd/ui/src/views/DatabaseManagement/DatabaseManagement.tsx
  • packages/go/openapi/doc/openapi.json
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-25T22:11:53.518Z
Learnt from: LawsonWillard
Repo: SpecterOps/BloodHound PR: 2107
File: cmd/api/src/database/graphschema.go:86-100
Timestamp: 2025-11-25T22:11:53.518Z
Learning: In cmd/api/src/database/graphschema.go, the CreateSchemaEdgeKind method intentionally does not use AuditableTransaction or audit logging because it would create too much noise in the audit log, unlike CreateGraphSchemaExtension which does use auditing.

Applied to files:

  • cmd/api/src/api/v2/database_wipe.go
🧬 Code graph analysis (1)
cmd/api/src/api/v2/database_wipe.go (2)
cmd/api/src/daemons/datapipe/delete.go (1)
  • DeleteCollectedGraphData (33-113)
packages/go/graphschema/ad/ad.go (1)
  • HasSession (53-53)
🔇 Additional comments (2)
cmd/api/src/api/v2/database_wipe.go (2)

32-36: New graph-related imports line up with the HasSession deletion helper

The added imports for ad graphschema, ops, and query are consistent with the new deleteHasSessionEdges implementation and appear correctly scoped and used; no issues here.


251-276: Implementation follows established patterns and is functionally correct

The core logic is correct and consistent with how HasSession relationships are deleted elsewhere in the codebase. The use of ops.FetchRelationships within s.Graph.BatchOperation is the standard pattern throughout BloodHound's migration code and batch relationship operations.

While DAWGS does provide cursor-based streaming via FetchIDs and Cursor[T] for incrementally processing results, the codebase consistently uses the FetchRelationships pattern for relationship batch deletions. The streaming/pipelined approach referenced in the comment is primarily used by DeleteCollectedGraphData for mass node deletions, not targeted relationship deletions.

There is no evidence of practical scalability issues with this pattern in the codebase, and the implementation aligns with established practices. This can be deferred as a future optimization if real-world performance data indicates a problem.

@rtpt-romankarwacik
Copy link
Author

There is a failing test in the MR. Could you patch that up so it fixes the UI test run?

Done 👍

Also we require commit signing as part of our PR process. Can you set up commit signing and then use a squash to sign all of your commits into a single signed one?

The process for squashing is here:

https://www.freecodecamp.org/news/git-squash-commits/

And the process for setting up commit signing is here:

https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits

Done 👍

Thank you for your review 😊

Copy link
Contributor

@rvazarkar rvazarkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fantastic, thank you for the extra effort. We're going to go through our final review process here and hopefully get this merged in soon!

Copy link
Contributor

@mistahj67 mistahj67 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM. Pulled and ran locally as well to confirm edges properly deleted and audit log was correctly inserted. 🚀

@rtpt-romankarwacik rtpt-romankarwacik force-pushed the main branch 3 times, most recently from ddfda34 to 70ff963 Compare December 17, 2025 08:27
Updated OpenAPI for new HasSession property

Generalized deleting of relatioships
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
cmd/ui/src/views/DatabaseManagement/DatabaseManagement.tsx (1)

371-381: Consider a more user-friendly label.

The label "HasSession edges" uses technical graph terminology that may not be intuitive for all users. Consider using more descriptive text like "User session data" or adding a tooltip to explain what HasSession edges represent.

Example with improved label:

 <FormControlLabel
-    label="HasSession edges"
+    label="User session data (HasSession edges)"
     control={
         <Checkbox
             checked={deleteHasSessionEdges}
             onChange={handleCheckbox}
             name='deleteHasSessionEdges'
             disabled={!hasPermission}
         />
     }
 />
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e765f3 and 677e98f.

📒 Files selected for processing (6)
  • cmd/api/src/api/v2/database_wipe.go (4 hunks)
  • cmd/ui/src/views/DatabaseManagement/DatabaseManagement.test.tsx (1 hunks)
  • cmd/ui/src/views/DatabaseManagement/DatabaseManagement.tsx (8 hunks)
  • packages/go/openapi/doc/openapi.json (2 hunks)
  • packages/go/openapi/src/paths/data-quality.clear-database.yaml (2 hunks)
  • packages/javascript/js-client-library/src/requests.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • cmd/ui/src/views/DatabaseManagement/DatabaseManagement.test.tsx
  • packages/go/openapi/doc/openapi.json
  • packages/go/openapi/src/paths/data-quality.clear-database.yaml
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-25T22:11:53.518Z
Learnt from: LawsonWillard
Repo: SpecterOps/BloodHound PR: 2107
File: cmd/api/src/database/graphschema.go:86-100
Timestamp: 2025-11-25T22:11:53.518Z
Learning: In cmd/api/src/database/graphschema.go, the CreateSchemaEdgeKind method intentionally does not use AuditableTransaction or audit logging because it would create too much noise in the audit log, unlike CreateGraphSchemaExtension which does use auditing.

Applied to files:

  • cmd/api/src/api/v2/database_wipe.go
📚 Learning: 2025-09-08T19:01:53.112Z
Learnt from: jvacca-specterops
Repo: SpecterOps/BloodHound PR: 1823
File: packages/javascript/bh-shared-ui/src/views/Explore/ExploreSearch/CypherSearch.tsx:108-148
Timestamp: 2025-09-08T19:01:53.112Z
Learning: In BloodHound's CypherSearch component (packages/javascript/bh-shared-ui/src/views/Explore/ExploreSearch/CypherSearch.tsx), the sharing state reset for sharedIds and isPublic after the two-step permissions update is handled elsewhere in the codebase, so additional state reset callbacks in the updateQueryPermissions function are not needed.

Applied to files:

  • cmd/ui/src/views/DatabaseManagement/DatabaseManagement.tsx
🔇 Additional comments (11)
packages/javascript/js-client-library/src/requests.ts (1)

241-241: LGTM!

The addition of the optional deleteRelationships field to the ClearDatabaseRequest interface is correct and aligns with the backend payload structure.

cmd/api/src/api/v2/database_wipe.go (4)

33-34: LGTM!

The new imports for ops and query packages are necessary for the edge deletion functionality.


38-40: LGTM!

The DeleteRelationships field properly extends the DatabaseWipe struct to support selective edge deletion by name.


69-69: LGTM!

The empty request validation correctly includes the new DeleteRelationships field.


194-199: LGTM!

The conditional block properly integrates edge deletion into the database wipe flow with appropriate error handling and audit logging.

cmd/ui/src/views/DatabaseManagement/DatabaseManagement.tsx (6)

42-42: LGTM!

The new deleteHasSessionEdges state is properly initialized in the initial state.


59-59: LGTM!

The deleteHasSessionEdges field is correctly added to the State type.


107-107: LGTM!

The state is properly reset to false after successful mutation, consistent with other checkbox states.


137-137: LGTM!

The deleteHasSessionEdges state is correctly included in the no-selection validation check.


177-177: LGTM!

The state is properly destructured for use in the component.


224-224: LGTM!

The mapping from deleteHasSessionEdges to deleteRelationships: ['HasSession'] correctly translates the UI state to the expected API payload format.

Comment on lines +250 to +277
func (s Resources) deleteEdges(ctx context.Context, auditEntry *model.AuditEntry, edgeNames []string) (failure bool) {
// Use the graph batch API to find and delete relationships matching the provided edge names
if err := s.Graph.BatchOperation(ctx, func(batch graph.Batch) error {
for _, name := range edgeNames {
targetCriteria := query.Kind(query.Relationship(), graph.StringKind(name))

rels, err := ops.FetchRelationships(batch.Relationships().Filter(targetCriteria))
if err != nil {
return err
}

for _, rel := range rels {
if err := batch.DeleteRelationship(rel.ID); err != nil {
return err
}
}
}

return nil
}); err != nil {
slog.ErrorContext(ctx, fmt.Sprintf("%s: %s", "there was an error deleting graph edges", err.Error()))
s.handleAuditLogForDatabaseWipe(ctx, auditEntry, false, strings.Join(edgeNames, ", "))
return true
} else {
s.handleAuditLogForDatabaseWipe(ctx, auditEntry, true, strings.Join(edgeNames, ", "))
return false
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for documentation or examples of batch relationship deletion patterns
# to understand if there are memory-efficient alternatives

# Look for other uses of ops.FetchRelationships to see if pagination is used
rg -n -C3 -A5 'ops\.FetchRelationships' --type=go

# Look for batch deletion patterns in the codebase
rg -n -C3 'batch\.DeleteRelationship' --type=go

# Check if there are examples of validating relationship kinds
rg -n -C3 'FetchKinds.*Relationship' --type=go

Repository: SpecterOps/BloodHound

Length of output: 23132


🏁 Script executed:

# Also look for how edgeNames parameter might be validated or constrained
rg -n -C3 'deleteEdges' --type=go

# Look for streaming or pagination patterns in batch operations
rg -n -C3 'batch.*Stream\|batch.*Pagina' --type=go

# Check the Graph.BatchOperation signature and documentation
rg -n -C5 'BatchOperation' --type=go | head -50

Repository: SpecterOps/BloodHound

Length of output: 4650


🏁 Script executed:

# Search for validation of relationship/edge types in the codebase
rg -n -C3 'Relationship.*Kind\|Kind.*Relationship' --type=go

# Look for any TODO/FIXME comments related to memory or validation
rg -n 'TODO|FIXME' cmd/api/src/api/v2/database_wipe.go

Repository: SpecterOps/BloodHound

Length of output: 47


🏁 Script executed:

# Find where payload.DeleteRelationships is defined
rg -n -A5 'DeleteRelationships' --type=go cmd/api/src/api/v2/database_wipe.go

# Look for the payload structure definition
rg -n -B5 -A10 'type.*[Pp]ayload.*struct' cmd/api/src/api/v2/database_wipe.go

# Check for any validation of edge names in the function or nearby
rg -n -B10 'deleteEdges' cmd/api/src/api/v2/database_wipe.go | head -50

Repository: SpecterOps/BloodHound

Length of output: 2093


🏁 Script executed:

# Look for relationship kind definitions to understand valid edge types
fd -n '\.go$' packages/go/analysis | xargs rg -l 'Relationship.*=.*string' | head -5

# Check if there are constants defining valid relationship kinds
rg -n -B2 -A2 'const.*Relationship' packages/go/analysis/ad/ | head -50

Repository: SpecterOps/BloodHound

Length of output: 492


🏁 Script executed:

# Inspect the complete deleteEdges function and surrounding context
sed -n '190,280p' cmd/api/src/api/v2/database_wipe.go

Repository: SpecterOps/BloodHound

Length of output: 3505


🏁 Script executed:

# Check if there's a list of valid relationship types that could be validated against
fd -type f '\.go$' packages/go/graphschema | head -10

# Look for relationship kind constants or definitions
rg -n 'const.*=' packages/go/graphschema/ad/identifiers.go | grep -i 'relationship\|raw\|owns' | head -20

Repository: SpecterOps/BloodHound

Length of output: 317


🏁 Script executed:

# Check if there's any API documentation or swagger definition for this endpoint
fd -name '*database*wipe*' --type f

# Look for test cases to understand expected behavior
rg -n 'deleteEdges\|DeleteRelationships' --type=go -A10 -B5 | grep -i test

Repository: SpecterOps/BloodHound

Length of output: 295


🏁 Script executed:

# Find graphschema files
fd 'identifiers\.go' packages/go/

# Look for relationship definitions
rg 'const.*=' packages/go/graphschema/ | grep -i 'own\|raw' | head -20

Repository: SpecterOps/BloodHound

Length of output: 109


🏁 Script executed:

# Search for test cases related to deleteEdges or DeleteRelationships
rg 'deleteEdges|DeleteRelationships' --type=go -B3 -A8 | grep -A8 -B3 'Test\|test' | head -50

Repository: SpecterOps/BloodHound

Length of output: 47


🏁 Script executed:

# Look at the complete payload structure in database_wipe.go to understand all context
cat cmd/api/src/api/v2/database_wipe.go | grep -A50 'type.*Payload.*struct'

Repository: SpecterOps/BloodHound

Length of output: 47


🏁 Script executed:

# Get the payload struct definition
sed -n '30,50p' cmd/api/src/api/v2/database_wipe.go

# Look for any validation logic before deleteEdges is called
sed -n '50,200p' cmd/api/src/api/v2/database_wipe.go | head -80

Repository: SpecterOps/BloodHound

Length of output: 3537


🏁 Script executed:

# Search for where relationship kind constants might be defined
fd identifiers.go

# Look at the graphschema structure
ls -la packages/go/graphschema/

Repository: SpecterOps/BloodHound

Length of output: 643


🏁 Script executed:

# Check if there are any known valid relationship types or validation logic
rg 'valid.*Relationship|Relationship.*valid|KindIn' cmd/api/src/api/v2/ -A3 -B3

Repository: SpecterOps/BloodHound

Length of output: 8272


Add input validation for edge names against known relationship types and consider memory efficiency for large deletions.

The deleteEdges function has two issues:

  1. Missing input validation: Edge names bypass the validation pattern established elsewhere in the codebase (e.g., pathfinding.go validates against graph.Kinds(ad.Relationships()).Concatenate(azure.Relationships())). Invalid edge names will silently result in zero deleted relationships without alerting the user.

  2. Memory inefficiency: The function loads all matching relationships into memory via ops.FetchRelationships before deletion. This pattern is consistent throughout the codebase but lacks pagination or streaming alternatives. For large relationship sets, this creates unnecessary memory pressure.

Consider validating edge names against valid relationship types and exploring whether the batch API supports more efficient deletion patterns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: More nuanced deletion of Data (specifically HasSession)

4 participants