Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Example configuration: https://bloodhound.specterops.io/openhound/enterprise#full-configuration-example
[openhound]
managed = false

[runtime]
http_show_error_body = true
log_cli_level = "WARNING"
Expand Down
32 changes: 32 additions & 0 deletions src/openhound/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""OpenHound managed-mode configuration."""

from dataclasses import dataclass

import dlt


@dataclass(frozen=True)
class ModeDefaults:
"""Placeholder for defaults that differ between OpenHound modes."""


_UNMANAGED_DEFAULTS = ModeDefaults()
_MANAGED_DEFAULTS = ModeDefaults()


def is_managed() -> bool:
"""Return whether OpenHound is configured to run in managed mode.

The value is resolved on every call so all platform code observes the current
DLT configuration. Missing configuration defaults to unmanaged mode. Invalid
boolean values raise DLT's configuration coercion error.
"""

configured = dlt.config.get("openhound.managed", bool)
return configured if configured is not None else False


def get_mode_defaults() -> ModeDefaults:
"""Return the defaults profile for the configured mode."""

return _MANAGED_DEFAULTS if is_managed() else _UNMANAGED_DEFAULTS
45 changes: 45 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import dlt
import pytest
from dlt.common.configuration.exceptions import ConfigValueCannotBeCoercedException

from openhound.config import ModeDefaults, get_mode_defaults, is_managed


def test_is_managed_defaults_to_unmanaged(monkeypatch):
monkeypatch.setattr(dlt.config, "get", lambda field, expected_type: None)

assert is_managed() is False


@pytest.mark.parametrize(
("value", "expected"),
[
("true", True),
("false", False),
],
)
def test_is_managed_resolves_environment_configuration(monkeypatch, value, expected):
monkeypatch.setenv("OPENHOUND__MANAGED", value)

assert is_managed() is expected


def test_is_managed_rejects_invalid_boolean(monkeypatch):
monkeypatch.setenv("OPENHOUND__MANAGED", "maybe")

with pytest.raises(ConfigValueCannotBeCoercedException):
is_managed()


def test_get_mode_defaults_selects_distinct_empty_profiles(monkeypatch):
monkeypatch.setattr("openhound.config.is_managed", lambda: False)
unmanaged = get_mode_defaults()

monkeypatch.setattr("openhound.config.is_managed", lambda: True)
managed = get_mode_defaults()

assert isinstance(unmanaged, ModeDefaults)
assert isinstance(managed, ModeDefaults)
assert unmanaged is not managed
assert vars(unmanaged) == {}
assert vars(managed) == {}
Loading