Skip to content

feat: add S3 Configuration - BED-9174 - #3116

Merged
mykeelium merged 5 commits into
mainfrom
mcuomo/BED-9174
Aug 7, 2026
Merged

feat: add S3 Configuration - BED-9174#3116
mykeelium merged 5 commits into
mainfrom
mcuomo/BED-9174

Conversation

@mykeelium

@mykeelium mykeelium commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Description

Adding S3 configuration to be able to use as storage backend for FileServices.

Motivation and Context

Resolves BED-9174

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

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

Checklist:

Summary by CodeRabbit

  • New Features
    • Added client artifact upload workflows, including session creation, status retrieval, multipart uploads, and completion.
    • Added support for downloading artifacts as binary data.
    • Added configurable local and S3-backed storage services.
    • Added validation for storage providers, names, prefixes, and upload checksums.
  • Documentation
    • Expanded API documentation with artifact upload endpoints, request/response schemas, statuses, checksum algorithms, and error responses.
  • Tests
    • Added coverage for storage configuration, S3 providers, invalid settings, and artifact upload scenarios.

@mykeelium mykeelium self-assigned this Aug 7, 2026
@mykeelium mykeelium added the api A pull request containing changes affecting the API code. label Aug 7, 2026
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds configurable local and S3 file services, passes contexts during initialization, adds storage configuration tests, and documents client artifact upload-session, multipart upload, completion, and download contracts.

Changes

Artifact storage and upload API

Layer / File(s) Summary
Configurable file-service resolution
cmd/api/src/config/config.go, cmd/api/src/config/config_test.go, cmd/api/src/services/storage/*
Storage configuration now defines instance-bucket and file-service settings. NewDefaultFileServices validates providers, names, prefixes, and configuration entries, then creates local or S3 stores. Tests cover S3 configuration and invalid definitions.
Context-aware service wiring
cmd/api/src/services/entrypoint.go, cmd/api/src/daemons/datapipe/datapipe_integration_test.go, cmd/api/src/services/graphify/graphify_integration_test.go
Runtime and integration-test setup now passes explicit contexts to file-service initialization.
Client artifact upload contract
cmd/api/src/api/constant.go, packages/go/openapi/src/openapi.yaml, packages/go/openapi/src/paths/*artifacts*, packages/go/openapi/src/schemas/*artifact*, packages/go/openapi/doc/openapi.json
OpenAPI definitions now cover upload-session creation and retrieval, binary part upload, completion, artifact schemas, and binary artifact downloads.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Entrypoint
  participant FileServiceResolver
  participant AWSConfig
  participant LocalStore
  participant S3Store
  Entrypoint->>FileServiceResolver: initialize with context and configuration
  FileServiceResolver->>AWSConfig: load configuration when S3 is required
  FileServiceResolver->>LocalStore: create local stores
  FileServiceResolver->>S3Store: create S3 stores
  FileServiceResolver-->>Entrypoint: return services or validation error
Loading

Possibly related PRs

Suggested labels: enhancement, documentation, infrastructure, go

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% 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
Title check ✅ Passed The title clearly identifies the primary change: adding S3 configuration, and includes the associated ticket.
Description check ✅ Passed The description follows the required template and identifies the change, ticket, feature type, documentation updates, and testing checklist.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mcuomo/BED-9174

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 oasdiff (1.27.0)
packages/go/openapi/src/openapi.yaml

Error: failed to load base spec from "/tmp/coderabbit-oasdiff-base.hoam1y": encountered disallowed external reference: "./paths/eula.accept-eula.yaml"


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

@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation enhancement New feature or request go Pull requests that update go code infrastructure A pull request containing changes affecting the infrastructure code. labels Aug 7, 2026

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (3)
cmd/api/src/services/storage/fileserviceresolver.go (1)

169-169: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a descriptive configuration parameter name.

Rename cfg at Line 169 and Line 258 to configuration. This improves clarity in the configuration-resolution path.

As per coding guidelines, “Prefer descriptive variable names, such as databaseInterface, instead of abbreviated names such as di or dbi.”

Also applies to: 258-258

🤖 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 `@cmd/api/src/services/storage/fileserviceresolver.go` at line 169, Rename the
configuration parameter `cfg` to `configuration` in
`resolveFileServiceDefinitions` and the additionally referenced declaration at
line 258, updating all usages within their respective scopes while preserving
behavior.

Source: Coding guidelines

packages/go/openapi/src/schemas/model.client-artifact-upload-session.yaml (1)

19-59: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value

Consider adding artifact_type to the session model.

The create request requires artifact_type, and the create response returns client_id. The session model returns neither. A client that only calls GET /api/v2/clients/management/artifacts/{artifact_id} cannot read the artifact type it declared. Add artifact_type if the session response is meant to be a complete view of the artifact.

♻️ Proposed addition
   - type: object
     properties:
       storage_key:
         type: string
+      artifact_type:
+        $ref: './enum.artifact-type.yaml'
       content_type:
         type: string
🤖 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 `@packages/go/openapi/src/schemas/model.client-artifact-upload-session.yaml`
around lines 19 - 59, Update the client artifact upload session schema to
include an artifact_type property, matching the type and naming used by the
create request, so GET session responses expose the declared artifact type
alongside the existing session fields.
packages/go/openapi/doc/openapi.json (1)

17573-17599: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Document the two checksum encodings and the two algorithm spellings.

The upload flow now uses two different representations of the same algorithm set:

  • enum.checksum-algorithm uses sha256 and sha512 in the create request and in the session response.
  • The Content-Digest header uses sha-256 and sha-512, as required by RFC 9530.

The encodings also differ. checksum fields are hex-encoded. The Content-Digest value is base64 inside a structured field byte sequence. Do not rename the enum, because that changes the JSON contract. Instead, state the mapping in the operation description so a client author can convert correctly.

Apply the change in the source file packages/go/openapi/src/paths/clients.clients.management.artifacts.id.parts.part-number.yaml and regenerate openapi.json.

🤖 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 `@packages/go/openapi/doc/openapi.json` around lines 17573 - 17599, The
upload-part operation description should explicitly map enum.checksum-algorithm
values sha256/sha512 to Content-Digest algorithm names sha-256/sha-512, and
distinguish hex-encoded checksum fields from base64 structured-field
Content-Digest values. Update the operation description in the source YAML
without renaming the enum, then regenerate the derived openapi.json.
🤖 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 `@packages/go/openapi/src/schemas/model.client-artifact-upload-session.yaml`:
- Around line 21-22: Remove the storage_key property from the client-facing
upload session, upload session part, and create-response schemas, retaining
artifact_id, part_number, and operation_id as the client contract; then
regenerate packages/go/openapi/doc/openapi.json to reflect these schema changes.

---

Nitpick comments:
In `@cmd/api/src/services/storage/fileserviceresolver.go`:
- Line 169: Rename the configuration parameter `cfg` to `configuration` in
`resolveFileServiceDefinitions` and the additionally referenced declaration at
line 258, updating all usages within their respective scopes while preserving
behavior.

In `@packages/go/openapi/doc/openapi.json`:
- Around line 17573-17599: The upload-part operation description should
explicitly map enum.checksum-algorithm values sha256/sha512 to Content-Digest
algorithm names sha-256/sha-512, and distinguish hex-encoded checksum fields
from base64 structured-field Content-Digest values. Update the operation
description in the source YAML without renaming the enum, then regenerate the
derived openapi.json.

In `@packages/go/openapi/src/schemas/model.client-artifact-upload-session.yaml`:
- Around line 19-59: Update the client artifact upload session schema to include
an artifact_type property, matching the type and naming used by the create
request, so GET session responses expose the declared artifact type alongside
the existing session fields.
🪄 Autofix

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: 3d78e421-678c-4620-87a8-6284ca64c5cf

📥 Commits

Reviewing files that changed from the base of the PR and between 9ba52d8 and f362ce0.

📒 Files selected for processing (23)
  • cmd/api/src/api/constant.go
  • cmd/api/src/config/config.go
  • cmd/api/src/config/config_test.go
  • cmd/api/src/daemons/datapipe/datapipe_integration_test.go
  • cmd/api/src/services/entrypoint.go
  • cmd/api/src/services/graphify/graphify_integration_test.go
  • cmd/api/src/services/storage/fileserviceresolver.go
  • cmd/api/src/services/storage/fileserviceresolver_test.go
  • packages/go/openapi/doc/openapi.json
  • packages/go/openapi/src/openapi.yaml
  • packages/go/openapi/src/paths/clients.clients.id.artifacts.id.yaml
  • packages/go/openapi/src/paths/clients.clients.management.artifacts.id.complete.yaml
  • packages/go/openapi/src/paths/clients.clients.management.artifacts.id.parts.part-number.yaml
  • packages/go/openapi/src/paths/clients.clients.management.artifacts.id.yaml
  • packages/go/openapi/src/paths/clients.clients.management.artifacts.yaml
  • packages/go/openapi/src/schemas/enum.artifact-status.yaml
  • packages/go/openapi/src/schemas/enum.artifact-type.yaml
  • packages/go/openapi/src/schemas/enum.checksum-algorithm.yaml
  • packages/go/openapi/src/schemas/model.client-artifact-upload-session-complete-request.yaml
  • packages/go/openapi/src/schemas/model.client-artifact-upload-session-create-request.yaml
  • packages/go/openapi/src/schemas/model.client-artifact-upload-session-create-response.yaml
  • packages/go/openapi/src/schemas/model.client-artifact-upload-session-part.yaml
  • packages/go/openapi/src/schemas/model.client-artifact-upload-session.yaml

Comment on lines +21 to +22
storage_key:
type: string

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.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Determine how storage keys are generated and whether client-facing code reads them.
set -euo pipefail

rg -n --type=go -C3 '\bStorageKey\b'
rg -n --iglob '*.yaml' -C2 'storage_key'

Repository: SpecterOps/BloodHound

Length of output: 159


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(model\.client-artifact-upload-session(-part)?\.yaml|openapi\.json)$'

printf '%s\n' '--- schema definitions ---'
for f in $(git ls-files | rg '(^|/)model\.client-artifact-upload-session(-part)?\.yaml$'); do
  echo "### $f"
  cat -n "$f"
done

printf '%s\n' '--- storage_key references ---'
rg -n -C3 --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' 'storage_key|StorageKey|storageKey' .

printf '%s\n' '--- upload-session references ---'
rg -n -C2 --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' 'artifact-upload-session|ArtifactUploadSession|upload session|part_number|artifact_id' packages

Repository: SpecterOps/BloodHound

Length of output: 31309


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- client artifact upload response paths ---'
for f in \
  packages/go/openapi/src/paths/clients.clients.management.artifacts.yaml \
  packages/go/openapi/src/paths/clients.clients.management.artifacts.id.yaml \
  packages/go/openapi/src/paths/clients.clients.management.artifacts.id.parts.part-number.yaml \
  packages/go/openapi/src/paths/clients.clients.management.artifacts.id.complete.yaml \
  packages/go/openapi/src/schemas/model.client-artifact-upload-session-create-response.yaml; do
  echo "### $f"
  cat -n "$f"
done

printf '%s\n' '--- all artifact-upload implementation references ---'
rg -n -i -C3 --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' \
  'artifact.?upload|upload.?session|storage[_-]?key|storagekey' .

printf '%s\n' '--- generated OpenAPI storage_key schema contexts ---'
sed -n '24985,25080p' packages/go/openapi/doc/openapi.json

printf '%s\n' '--- tracked generated/client artifacts ---'
git ls-files | rg -i 'openapi|artifact|upload|generated|client' | head -300

Repository: SpecterOps/BloodHound

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- working-tree summary ---'
git diff --stat

printf '%s\n' '--- targeted diff for upload schemas and generated contract ---'
git diff --no-ext-diff --unified=8 -- \
  packages/go/openapi/src/schemas/model.client-artifact-upload-session.yaml \
  packages/go/openapi/src/schemas/model.client-artifact-upload-session-part.yaml \
  packages/go/openapi/src/schemas/model.client-artifact-upload-session-create-response.yaml \
  packages/go/openapi/doc/openapi.json

printf '%s\n' '--- exact storage_key occurrences outside OpenAPI files ---'
rg -n --glob '!packages/go/openapi/**' --glob '!node_modules/**' \
  'storage_key|StorageKey|storageKey' . || true

printf '%s\n' '--- storage-related schema and path names ---'
git ls-files packages/go/openapi/src | rg -i 'artifact|upload|storage|object' | head -120

Repository: SpecterOps/BloodHound

Length of output: 1921


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- upload request schemas ---'
for f in \
  packages/go/openapi/src/schemas/model.client-artifact-upload-session-create-request.yaml \
  packages/go/openapi/src/schemas/model.client-artifact-upload-session-complete-request.yaml; do
  echo "### $f"
  cat -n "$f"
done

printf '%s\n' '--- all client-facing references to storage_key schemas ---'
rg -n -C2 'model\.client-artifact-upload-session(-create-response|-part)?|storage_key' \
  packages/go/openapi/src packages/go/openapi/doc/openapi.json

Repository: SpecterOps/BloodHound

Length of output: 13237


Remove storage_key from client-facing upload responses. Upload endpoints use artifact_id, part_number, and operation_id; clients do not send storage_key.

Remove it from the session, part, and create-response schemas. If clients require it, document that contract and its purpose. Regenerate packages/go/openapi/doc/openapi.json.

📍 Affects 2 files
  • packages/go/openapi/src/schemas/model.client-artifact-upload-session.yaml#L21-L22 (this comment)
  • packages/go/openapi/src/schemas/model.client-artifact-upload-session-part.yaml#L31-L32
🤖 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 `@packages/go/openapi/src/schemas/model.client-artifact-upload-session.yaml`
around lines 21 - 22, Remove the storage_key property from the client-facing
upload session, upload session part, and create-response schemas, retaining
artifact_id, part_number, and operation_id as the client contract; then
regenerate packages/go/openapi/doc/openapi.json to reflect these schema changes.

@mykeelium
mykeelium merged commit e63c647 into main Aug 7, 2026
13 checks passed
@mykeelium
mykeelium deleted the mcuomo/BED-9174 branch August 7, 2026 20:18
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

api A pull request containing changes affecting the API code. documentation Improvements or additions to documentation enhancement New feature or request go Pull requests that update go code infrastructure A pull request containing changes affecting the infrastructure code.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants