Skip to content

Apply custom --user-agent to BHE ingest requests#193

Open
ChrisJr404 wants to merge 1 commit intoSpecterOps:mainfrom
ChrisJr404:feat/custom-user-agent-135
Open

Apply custom --user-agent to BHE ingest requests#193
ChrisJr404 wants to merge 1 commit intoSpecterOps:mainfrom
ChrisJr404:feat/custom-user-agent-135

Conversation

@ChrisJr404
Copy link
Copy Markdown

@ChrisJr404 ChrisJr404 commented May 6, 2026

The --user-agent global flag added in f7bf368 only flows through rest.NewRequest. The BHE ingest path in BHEClient.Ingest builds its request inline and hardcodes the default azurehound/<version> value, so /api/v2/ingest still gets the default UA even when --user-agent is set.

This finishes plumbing the flag everywhere by:

  • pulling the resolution logic out of rest.NewRequest into a small rest.UserAgent() helper,
  • using that helper in both rest.NewRequest and BHEClient.Ingest.

Closes #135.

Tests

client/rest/http_test.go (new):

  • TestUserAgent_DefaultsWhenUnset / TestUserAgent_HonorsConfigValue
  • TestNewRequest_AppliesCustomUserAgent / TestNewRequest_DefaultUserAgentWhenConfigEmpty

client/bloodhound/client_test.go (added subtests on TestBHEClient_Ingest):

  • custom user agent applied — spins up an httptest server, sets config.UserAgent, verifies the recorded UA on /api/v2/ingest
  • default user agent when config empty — same harness with the flag unset, verifies fallback to constants.UserAgent()

Local run:

go build ./...
go test ./...
go vet ./...

All green.

Notes

  • No flag/CLI surface change; --user-agent (-U) was already in GlobalConfig.
  • Pure refactor + additional call site, no behavior change for the default path.
  • I left the existing inline comment intact in spirit but moved the implementation; happy to rename the helper or shape the diff differently if you'd prefer it.

Summary by CodeRabbit

  • Refactor

    • Improved User-Agent header handling to ensure consistent configuration across HTTP requests.
  • Tests

    • Added tests to validate User-Agent header behavior with custom configurations and default values.

The --user-agent flag added in f7bf368 only flowed through rest.NewRequest,
so requests built directly in BHEClient.Ingest still hardcoded the default
azurehound/<version> string. Anyone running azurehound against a hardened
BHE proxy or wanting consistent UA across all outbound traffic still saw
the default value on /api/v2/ingest.

Pull the resolution logic into a reusable rest.UserAgent() helper and
have both call sites use it. Tests cover default fallback, custom value,
and end-to-end on the BHE ingest path.

Closes SpecterOps#135.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

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

@ChrisJr404
Copy link
Copy Markdown
Author

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

Walkthrough

The PR centralizes User-Agent header selection into an exported rest.UserAgent() helper that returns a configured value or falls back to the default constant. BHEClient.Ingest now uses rest.UserAgent(). Tests were added to validate default and custom User-Agent behavior and NewRequest header application.

Changes

User-Agent Header Centralization

Layer / File(s) Summary
Core Abstraction
client/rest/http.go
Added exported UserAgent() string to return configured user-agent or default constant; NewRequest now calls this helper to set the header.
Consumer Integration
client/bloodhound/client.go
BHEClient.Ingest updated to use rest.UserAgent() instead of calling constants.UserAgent() directly.
Helper Tests
client/rest/http_test.go
New tests verifying default User-Agent, honoring configured custom User-Agent, and that NewRequest applies the configured header.
Consumer Tests
client/bloodhound/client_test.go
Added tests asserting custom User-Agent via config and default User-Agent when config value is empty for BHEClient.Ingest.

Estimated Code Review Effort

🎯 2 (Simple) | ⏱️ ~12 minutes

"I nibble code beneath the moon,
A header set, then set again,
Config whispers what to croon,
Defaults hold if silence reigns,
Hoppy tests ensure no pain." 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: applying custom User-Agent flag to BHE ingest requests, which is the core objective of this PR.
Linked Issues check ✅ Passed The PR fully addresses issue #135's requirements by extracting User-Agent logic into rest.UserAgent() and applying it to BHEClient.Ingest, enabling custom User-Agent configuration without recompilation.
Out of Scope Changes check ✅ Passed All changes are directly scoped to User-Agent handling: new rest.UserAgent() helper, BHEClient.Ingest integration, and corresponding tests. No unrelated modifications detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown

@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.

🧹 Nitpick comments (2)
client/rest/http_test.go (1)

30-31: ⚡ Quick win

Restore prior global config value instead of always resetting to empty.

Lines 30-31, 40-42, 50-52, and 64-65 currently force config.UserAgent to "" in cleanup. That can leak state assumptions across tests; restoring the prior value keeps tests hermetic.

Proposed change
 func TestUserAgent_HonorsConfigValue(t *testing.T) {
 	const custom = "my-custom-agent/1.2.3"
+	prev, _ := config.UserAgent.Value().(string)
 	config.UserAgent.Set(custom)
-	t.Cleanup(func() { config.UserAgent.Set("") })
+	t.Cleanup(func() { config.UserAgent.Set(prev) })
 func TestNewRequest_DefaultUserAgentWhenConfigEmpty(t *testing.T) {
+	prev, _ := config.UserAgent.Value().(string)
 	config.UserAgent.Set("")
-	t.Cleanup(func() { config.UserAgent.Set("") })
+	t.Cleanup(func() { config.UserAgent.Set(prev) })

Also applies to: 40-42, 50-52, 64-65

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/rest/http_test.go` around lines 30 - 31, Tests currently set
config.UserAgent to "" and unconditionally reset it to "" in the t.Cleanup
handlers, which can leak state; capture the prior value before calling
config.UserAgent.Set("") and in the t.Cleanup restore that saved value (i.e.
call config.UserAgent.Set(prevUserAgent)) instead of always setting "". Update
all places that set config.UserAgent.Set("") and register t.Cleanup (the
occurrences around config.UserAgent.Set("") / t.Cleanup in this test file) to
use this save-and-restore pattern so global state is preserved.
client/bloodhound/client_test.go (1)

149-150: ⚡ Quick win

Use prior-value restoration for config.UserAgent in cleanup.

Line 150 and Line 173 always reset to "". Restoring the previous value is safer for test isolation and avoids hidden order dependencies.

Proposed change
 	t.Run("custom user agent applied", func(t *testing.T) {
 		const custom = "test-agent/9.9.9"
+		prev, _ := config.UserAgent.Value().(string)
 		config.UserAgent.Set(custom)
-		t.Cleanup(func() { config.UserAgent.Set("") })
+		t.Cleanup(func() { config.UserAgent.Set(prev) })
 	t.Run("default user agent when config empty", func(t *testing.T) {
+		prev, _ := config.UserAgent.Value().(string)
 		config.UserAgent.Set("")
-		t.Cleanup(func() { config.UserAgent.Set("") })
+		t.Cleanup(func() { config.UserAgent.Set(prev) })

Also applies to: 172-173

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/bloodhound/client_test.go` around lines 149 - 150, The test currently
sets config.UserAgent.Set(custom) and unconditionally restores it to "" in
t.Cleanup, which can create test-ordering bugs; change the test to capture the
previous value (e.g., prev := config.UserAgent.Get()) before calling
config.UserAgent.Set(custom) and then in t.Cleanup restore that previous value
via config.UserAgent.Set(prev) (apply the same change for the second occurrence
around lines where config.UserAgent.Set(...) and t.Cleanup are used).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@client/bloodhound/client_test.go`:
- Around line 149-150: The test currently sets config.UserAgent.Set(custom) and
unconditionally restores it to "" in t.Cleanup, which can create test-ordering
bugs; change the test to capture the previous value (e.g., prev :=
config.UserAgent.Get()) before calling config.UserAgent.Set(custom) and then in
t.Cleanup restore that previous value via config.UserAgent.Set(prev) (apply the
same change for the second occurrence around lines where
config.UserAgent.Set(...) and t.Cleanup are used).

In `@client/rest/http_test.go`:
- Around line 30-31: Tests currently set config.UserAgent to "" and
unconditionally reset it to "" in the t.Cleanup handlers, which can leak state;
capture the prior value before calling config.UserAgent.Set("") and in the
t.Cleanup restore that saved value (i.e. call
config.UserAgent.Set(prevUserAgent)) instead of always setting "". Update all
places that set config.UserAgent.Set("") and register t.Cleanup (the occurrences
around config.UserAgent.Set("") / t.Cleanup in this test file) to use this
save-and-restore pattern so global state is preserved.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 59fc78de-02b0-4e00-90d5-ccd5a8cfd194

📥 Commits

Reviewing files that changed from the base of the PR and between 132897a and 3f1e13e.

📒 Files selected for processing (4)
  • client/bloodhound/client.go
  • client/bloodhound/client_test.go
  • client/rest/http.go
  • client/rest/http_test.go

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.

Improvement: Add a Feature to Allow Users to Specify Custom User Agents

1 participant