Skip to content

chore: automatically bundle latest collector versions in docker image BED-7545#2732

Open
lrfalslev wants to merge 15 commits into
mainfrom
lfalslev/bed-7545
Open

chore: automatically bundle latest collector versions in docker image BED-7545#2732
lrfalslev wants to merge 15 commits into
mainfrom
lfalslev/bed-7545

Conversation

@lrfalslev
Copy link
Copy Markdown
Contributor

@lrfalslev lrfalslev commented May 4, 2026

Description

BHCE should automatically fetch the latest collector versions to bundle into image.
Just recipes and cd workflow call github /releases/latest endpoints to fetch latest version, and use resolved version to fetch and bundle latest collector artifacts.

Motivation and Context

Resolves BED-7545

This removes the need for manual collector version bumps in dockerfile during release week. Once collectors are released the latest versions will be pulled automatically on next run.

How Has This Been Tested?

test workflow ran with automatic collector resolution.
just recipes resolve latest versions and docker commands succeed.

Screenshots (optional):

image Screenshot_2026-05-11_12-35-35

Types of changes

  • Chore (a change that does not modify the application functionality)

Checklist:

Summary by CodeRabbit

  • New Features

    • Automatic detection and resolution of latest SharpHound and AzureHound collector versions during builds.
    • Enhanced version validation with semver pattern enforcement.
    • Added checksum verification for downloaded collector artifacts to improve security.
  • Chores

    • Improved build tooling and local development workflow for collector version management.

Review Change Stack

@lrfalslev lrfalslev self-assigned this May 4, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

📝 Walkthrough

Walkthrough

This PR introduces dynamic resolution of SharpHound and AzureHound collector versions from GitHub releases, replacing hardcoded defaults. Changes flow through a new GitHub action for CI, Just task helpers for local development, Docker Compose configuration, and updated Dockerfiles that validate versions and download artifacts with checksum verification.

Changes

Dynamic Collector Version Resolution

Layer / File(s) Summary
GitHub Action: Version Resolution
.github/actions/resolve-collector-versions/action.yml
New composite action queries GitHub releases API for latest SpecterOps/SharpHound and SpecterOps/AzureHound tags, extracts version strings, exports them as outputs, and logs selected versions.
CI Pipeline: Version Resolution and Wiring
.github/workflows/cd.yml
CD workflow adds resolve-collector-versions job that calls the GitHub action, updates bloodhound-container-image to depend on it, and passes resolved sharphound_version and azurehound_version as container build arguments.
Just Task Helpers: Local Version Fetching
justfile
New _collector-version-env helper downloads latest collector tags from GitHub via wget and validates against vX.Y.Z pattern; _needs-collector-versions gates version fetching based on CLI args; _bh-compose wrapper conditionally injects versions into docker compose commands.
Just Task Wiring: Wrapper Updates
justfile
Four Docker Compose tasks (bh-dev, bh-debug, bh-api-only, bh-sso) delegate to the _bh-compose wrapper; bh-clean-docker-build and build-bhce-container rewritten as strict bash scripts that conditionally fetch versions before building.
Docker Compose: Build Argument Configuration
docker-compose.dev.yml
The bh-api and debug-api services accept SHARPHOUND_VERSION and AZUREHOUND_VERSION as build arguments from environment variables.
Bloodhound Dockerfile: Version Contract and Validation
dockerfiles/bloodhound.Dockerfile
Build arguments for SHARPHOUND_VERSION and AZUREHOUND_VERSION declared as required (no defaults); new version-validator stage enforces vX.Y.Z pattern before proceeding.
Bloodhound Dockerfile: Artifact Download and Verification
dockerfiles/bloodhound.Dockerfile
SharpHound and AzureHound stages download version-specific zips from GitHub releases via wget, verify checksums against .sha256 files, and repackage artifacts into /tmp/*/dist/ directories with accompanying checksums.
Bloodhound Dockerfile: LDFLAGS and Final Assembly
dockerfiles/bloodhound.Dockerfile
LDFLAGS generation script reformatted into multiple lines; final image stage copies collector zips and checksums from /dist/ directories into /etc/bloodhound/collectors/.
API Dockerfile: Version Contract and Validation
tools/docker-compose/api.Dockerfile
Build arguments for SHARPHOUND_VERSION and AZUREHOUND_VERSION declared as required; version-validator stage enforces vX.Y.Z pattern.
API Dockerfile: Artifact Download and Verification
tools/docker-compose/api.Dockerfile
SharpHound and AzureHound stages download version-specific artifacts, verify checksums, and repackage into /tmp/**/dist/ directories following bloodhound pattern.
API Dockerfile: Final Assembly
tools/docker-compose/api.Dockerfile
Final runtime stage copies collector zips and checksums from /tmp/**/dist/ paths into the image.
Neo4j Dockerfile: Style Fix
tools/docker-compose/neo4j.Dockerfile
Stage alias changed from lowercase as to uppercase AS.

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: automatically bundling latest collector versions in the Docker image, and references the associated ticket BED-7545.
Description check ✅ Passed The description covers all required sections: clear change description, motivation/context with ticket reference, testing details with workflow link and screenshots, change type identified, and contributing checklist completed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lfalslev/bed-7545

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

@lrfalslev lrfalslev added the infrastructure A pull request containing changes affecting the infrastructure code. label May 11, 2026
@lrfalslev lrfalslev marked this pull request as ready for review May 11, 2026 18:50
Copy link
Copy Markdown
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

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

Inline comments:
In @.github/actions/resolve-collector-versions/action.yml:
- Around line 36-46: Enable strict shell mode and validate the tag outputs
before writing to GITHUB_OUTPUT: add set -euo pipefail and IFS= to the script,
run the gh api calls in a way that detects failures (e.g., capture output and
check the exit status of the gh command that produces sharphound_version and
azurehound_version), then assert each resolved value is non-empty and not the
literal "null" and matches the expected semver tag regex (e.g.,
^v[0-9]+\.[0-9]+\.[0-9]+$) before echoing "sharphound_version=…" /
"azurehound_version=…" to GITHUB_OUTPUT; if validation fails, emit a clear error
via echo "::error::" and exit non-zero so the action fails fast.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: b94f357b-e6d7-40ed-ab01-68631088f301

📥 Commits

Reviewing files that changed from the base of the PR and between 633fe8e and 00499ff.

📒 Files selected for processing (7)
  • .github/actions/resolve-collector-versions/action.yml
  • .github/workflows/cd.yml
  • docker-compose.dev.yml
  • dockerfiles/bloodhound.Dockerfile
  • justfile
  • tools/docker-compose/api.Dockerfile
  • tools/docker-compose/neo4j.Dockerfile

Comment on lines +36 to +46
run: |
sharphound_version="$(gh api repos/SpecterOps/SharpHound/releases/latest --jq .tag_name)"
azurehound_version="$(gh api repos/SpecterOps/AzureHound/releases/latest --jq .tag_name)"

# Output versions
echo "sharphound_version=${sharphound_version}" >> "${GITHUB_OUTPUT}"
echo "azurehound_version=${azurehound_version}" >> "${GITHUB_OUTPUT}"

# Log for visibility
echo "::notice::Using SharpHound ${sharphound_version}"
echo "::notice::Using AzureHound ${azurehound_version}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Harden the resolver against silent gh api failures.

The shell block has no strict mode and never validates the resolved tags before writing them to GITHUB_OUTPUT. Two realistic failure modes leak through:

  • gh api non-zero exit: var=$(gh api …) does not propagate the failure to set -e (assignment masks the substitution exit), so the script proceeds with an empty value.
  • Missing tag_name: --jq .tag_name emits the literal string null, which then becomes the build arg.

In both cases the only signal is a downstream Dockerfile validation error ("must match vX.Y.Z"), which is far from the root cause. Fail fast inside the action instead.

🛡️ Proposed fix to add strict mode and format validation
     - id: fetch-collector-versions
       name: Fetch Collector Versions
       shell: bash
       run: |
+        set -euo pipefail
         sharphound_version="$(gh api repos/SpecterOps/SharpHound/releases/latest --jq .tag_name)"
         azurehound_version="$(gh api repos/SpecterOps/AzureHound/releases/latest --jq .tag_name)"

+        # Validate versions before emitting them so failures surface here, not in the downstream build.
+        version_regex='^v[0-9]+\.[0-9]+\.[0-9]+$'
+        if [[ ! "${sharphound_version}" =~ ${version_regex} ]]; then
+          echo "::error::Invalid SharpHound version resolved: '${sharphound_version:-<empty>}'"
+          exit 1
+        fi
+        if [[ ! "${azurehound_version}" =~ ${version_regex} ]]; then
+          echo "::error::Invalid AzureHound version resolved: '${azurehound_version:-<empty>}'"
+          exit 1
+        fi
+
         # Output versions
         echo "sharphound_version=${sharphound_version}" >> "${GITHUB_OUTPUT}"
         echo "azurehound_version=${azurehound_version}" >> "${GITHUB_OUTPUT}"
🤖 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 @.github/actions/resolve-collector-versions/action.yml around lines 36 - 46,
Enable strict shell mode and validate the tag outputs before writing to
GITHUB_OUTPUT: add set -euo pipefail and IFS= to the script, run the gh api
calls in a way that detects failures (e.g., capture output and check the exit
status of the gh command that produces sharphound_version and
azurehound_version), then assert each resolved value is non-empty and not the
literal "null" and matches the expected semver tag regex (e.g.,
^v[0-9]+\.[0-9]+\.[0-9]+$) before echoing "sharphound_version=…" /
"azurehound_version=…" to GITHUB_OUTPUT; if validation fails, emit a clear error
via echo "::error::" and exit non-zero so the action fails fast.

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

Labels

infrastructure A pull request containing changes affecting the infrastructure code.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant