Skip to content

Conversation

@dcairnsspecterops
Copy link
Contributor

@dcairnsspecterops dcairnsspecterops commented Jan 14, 2026

Description

Describe your changes in detail

Motivation and Context

Resolves BED-7144

Why is this change required? What problem does it solve?

How Has This Been Tested?

Please describe in detail how you tested your changes.
Include details of your testing environment, and the tests you ran to
see how your change affects other areas of the code, etc.

Screenshots (optional):

Types of changes

  • Chore (a change that does not modify the application functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Database Migrations

Checklist:

Summary by CodeRabbit

Bug Fixes

  • Asset group tag selector updates now properly validate empty seed arrays when explicitly provided, ensuring appropriate error handling for all seed input scenarios.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 14, 2026

Walkthrough

The UpdateAssetGroupTagSelector function now checks if Seeds is non-nil instead of checking if its length exceeds zero, causing empty seed slices to trigger validation logic rather than being skipped. A corresponding test case was added to verify this behavior.

Changes

Cohort / File(s) Summary
Asset Group Tags Implementation
cmd/api/src/api/v2/assetgrouptags.go
Modified condition in UpdateAssetGroupTagSelector from len(selUpdateReq.Seeds) > 0 to selUpdateReq.Seeds != nil, allowing empty slices to proceed to validation instead of skipping the update path.
Asset Group Tags Tests
cmd/api/src/api/v2/assetgrouptags_test.go
Added new test case "ExplicitlySuppliedEmptySeedArray" to TestResources_UpdateAssetGroupTagSelector that verifies empty seed arrays trigger a 404 error with "seeds are required" message.
Dependencies
go.mod
Minor dependency version adjustment.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • ALCooper12
  • AD7ZJ
  • sirisjo

Poem

🐰 A seed selector's journey, now complete,
Empty arrays make validation sweet,
Nil checks refine the logic's flow,
Tests bloom where edge cases grow,
Precision hops through every line! 🌱

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description follows the required template but contains only placeholder text without substantive details about the changes, motivation, testing approach, or type of change classification. Fill in all required sections: provide detailed description of the fix, explain the problem and why nil checking is required, describe testing methodology and environment, and explicitly select the bug fix type.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing the PATCH AssetTagSelector to handle explicit empty seeds arrays, referenced by ticket BED-7144.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

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

🤖 Fix all issues with AI agents
In `@cmd/api/src/api/v2/assetgrouptags_test.go`:
- Around line 946-963: The test fails early because UpdateAssetGroupTagSelector
parses api.URIPathVariableAssetGroupTagID using strconv.Atoi and "non-numeric"
causes a 404 before seed validation; update the test case
"ExplicitlySuppliedEmptySeedArray" to supply valid numeric URL vars (e.g.,
numeric strings for api.URIPathVariableAssetGroupTagID and
api.URIPathVariableAssetGroupTagSelectorID), set up any required mocks for
loading the asset group tag/selector so execution reaches validateSelectorSeeds,
and change the expected status to http.StatusBadRequest with the body assertion
still checking for "seeds are required".
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9501e2 and 94a44b5.

📒 Files selected for processing (2)
  • cmd/api/src/api/v2/assetgrouptags.go
  • cmd/api/src/api/v2/assetgrouptags_test.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mistahj67
Repo: SpecterOps/BloodHound PR: 1648
File: cmd/api/src/api/v2/assetgrouptags.go:763-766
Timestamp: 2025-07-09T00:36:54.112Z
Learning: In cmd/api/src/api/v2/assetgrouptags.go, the SearchAssetGroupTags method intentionally fetches all asset group tags and selectors without database-level filtering because it needs to build a complete `kinds` array from all relevant tags for the graph query filter. This allows members to be searched across all tags of the requested type while still filtering the returned tags/selectors by name match.
📚 Learning: 2025-07-09T00:36:54.112Z
Learnt from: mistahj67
Repo: SpecterOps/BloodHound PR: 1648
File: cmd/api/src/api/v2/assetgrouptags.go:763-766
Timestamp: 2025-07-09T00:36:54.112Z
Learning: In cmd/api/src/api/v2/assetgrouptags.go, the SearchAssetGroupTags method intentionally fetches all asset group tags and selectors without database-level filtering because it needs to build a complete `kinds` array from all relevant tags for the graph query filter. This allows members to be searched across all tags of the requested type while still filtering the returned tags/selectors by name match.

Applied to files:

  • cmd/api/src/api/v2/assetgrouptags.go
  • cmd/api/src/api/v2/assetgrouptags_test.go
🧬 Code graph analysis (1)
cmd/api/src/api/v2/assetgrouptags_test.go (1)
cmd/api/src/model/assetgrouptags.go (4)
  • AssetGroupTagSelector (225-241)
  • AssetGroupTagSelector (243-245)
  • SelectorSeed (202-206)
  • SelectorSeed (208-210)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build BloodHound Container Image / Build and Package Container
  • GitHub Check: build-ui
  • GitHub Check: run-tests
  • GitHub Check: run-analysis
  • GitHub Check: run-go-unit-tests
🔇 Additional comments (1)
cmd/api/src/api/v2/assetgrouptags.go (1)

303-313: LGTM! Correctly distinguishes nil vs empty slice.

The change from len(selUpdateReq.Seeds) > 0 to selUpdateReq.Seeds != nil properly handles the semantic difference between:

  • nil Seeds (field omitted from payload → preserve existing seeds)
  • Empty slice (explicit "seeds": [] in payload → validate and reject)

This ensures the API correctly validates explicitly provided empty arrays instead of silently ignoring them.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +946 to +963
{
Name: "ExplicitlySuppliedEmptySeedArray",
Input: func(input *apitest.Input) {
apitest.SetContext(input, userCtx)
apitest.SetURLVar(input, api.URIPathVariableAssetGroupTagID, "non-numeric")
apitest.SetURLVar(input, api.URIPathVariableAssetGroupTagSelectorID, "1")
apitest.BodyStruct(input, model.AssetGroupTagSelector{
Name: "TestSelector",
Description: "Test selector description",
Seeds: []model.SelectorSeed{},
AutoCertify: model.SelectorAutoCertifyMethodDisabled,
})
},
Test: func(output apitest.Output) {
apitest.StatusCode(output, http.StatusNotFound)
apitest.BodyContains(output, "seeds are required")
},
},
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 | 🔴 Critical

Test will fail at ID parsing, never reaching seeds validation.

The test sets api.URIPathVariableAssetGroupTagID to "non-numeric", which causes strconv.Atoi to fail at line 250-251 of UpdateAssetGroupTagSelector. This returns a 404 with "ID malformed" before the seeds validation logic is ever reached.

To properly test the empty seeds array scenario, use valid numeric IDs and set up the required mocks:

🐛 Proposed fix
 			{
 				Name: "ExplicitlySuppliedEmptySeedArray",
 				Input: func(input *apitest.Input) {
 					apitest.SetContext(input, userCtx)
-					apitest.SetURLVar(input, api.URIPathVariableAssetGroupTagID, "non-numeric")
+					apitest.SetURLVar(input, api.URIPathVariableAssetGroupTagID, "1")
 					apitest.SetURLVar(input, api.URIPathVariableAssetGroupTagSelectorID, "1")
 					apitest.BodyStruct(input, model.AssetGroupTagSelector{
 						Name:        "TestSelector",
 						Description: "Test selector description",
 						Seeds:       []model.SelectorSeed{},
 						AutoCertify: model.SelectorAutoCertifyMethodDisabled,
 					})
 				},
+				Setup: func() {
+					mockDB.EXPECT().GetAssetGroupTag(gomock.Any(), 1).
+						Return(model.AssetGroupTag{ID: 1}, nil).Times(1)
+					mockDB.EXPECT().GetAssetGroupTagSelectorBySelectorId(gomock.Any(), 1).
+						Return(model.AssetGroupTagSelector{AssetGroupTagId: 1}, nil).Times(1)
+				},
 				Test: func(output apitest.Output) {
-					apitest.StatusCode(output, http.StatusNotFound)
+					apitest.StatusCode(output, http.StatusBadRequest)
 					apitest.BodyContains(output, "seeds are required")
 				},
 			},

Note: The expected status code should be http.StatusBadRequest (400) since validateSelectorSeeds errors result in a BadRequest response (see line 305 in the production code).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
Name: "ExplicitlySuppliedEmptySeedArray",
Input: func(input *apitest.Input) {
apitest.SetContext(input, userCtx)
apitest.SetURLVar(input, api.URIPathVariableAssetGroupTagID, "non-numeric")
apitest.SetURLVar(input, api.URIPathVariableAssetGroupTagSelectorID, "1")
apitest.BodyStruct(input, model.AssetGroupTagSelector{
Name: "TestSelector",
Description: "Test selector description",
Seeds: []model.SelectorSeed{},
AutoCertify: model.SelectorAutoCertifyMethodDisabled,
})
},
Test: func(output apitest.Output) {
apitest.StatusCode(output, http.StatusNotFound)
apitest.BodyContains(output, "seeds are required")
},
},
{
Name: "ExplicitlySuppliedEmptySeedArray",
Input: func(input *apitest.Input) {
apitest.SetContext(input, userCtx)
apitest.SetURLVar(input, api.URIPathVariableAssetGroupTagID, "1")
apitest.SetURLVar(input, api.URIPathVariableAssetGroupTagSelectorID, "1")
apitest.BodyStruct(input, model.AssetGroupTagSelector{
Name: "TestSelector",
Description: "Test selector description",
Seeds: []model.SelectorSeed{},
AutoCertify: model.SelectorAutoCertifyMethodDisabled,
})
},
Setup: func() {
mockDB.EXPECT().GetAssetGroupTag(gomock.Any(), 1).
Return(model.AssetGroupTag{ID: 1}, nil).Times(1)
mockDB.EXPECT().GetAssetGroupTagSelectorBySelectorId(gomock.Any(), 1).
Return(model.AssetGroupTagSelector{AssetGroupTagId: 1}, nil).Times(1)
},
Test: func(output apitest.Output) {
apitest.StatusCode(output, http.StatusBadRequest)
apitest.BodyContains(output, "seeds are required")
},
},
🤖 Prompt for AI Agents
In `@cmd/api/src/api/v2/assetgrouptags_test.go` around lines 946 - 963, The test
fails early because UpdateAssetGroupTagSelector parses
api.URIPathVariableAssetGroupTagID using strconv.Atoi and "non-numeric" causes a
404 before seed validation; update the test case
"ExplicitlySuppliedEmptySeedArray" to supply valid numeric URL vars (e.g.,
numeric strings for api.URIPathVariableAssetGroupTagID and
api.URIPathVariableAssetGroupTagSelectorID), set up any required mocks for
loading the asset group tag/selector so execution reaches validateSelectorSeeds,
and change the expected status to http.StatusBadRequest with the body assertion
still checking for "seeds are required".

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.

2 participants