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
2 changes: 1 addition & 1 deletion cmd/api/src/api/tools/pg.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ func (s *PGMigrator) MigrationStatus(response http.ResponseWriter, request *http
}

func (s *PGMigrator) OpenPostgresGraphConnection() (graph.Database, error) {
if pool, err := pg.NewPool(s.Cfg.Database.PostgreSQLConnectionString()); err != nil {
if pool, err := pg.NewPool(s.Cfg.Database); err != nil {
return nil, err
} else {
return dawgs.Open(s.ServerCtx, pg.DriverName, dawgs.Config{
Expand Down
2 changes: 1 addition & 1 deletion cmd/api/src/bootstrap/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func ConnectGraph(ctx context.Context, cfg config.Configuration) (*graph.Databas
slog.InfoContext(ctx, "Connecting to graph using PostgreSQL")
connectionString = cfg.Database.PostgreSQLConnectionString()

pool, err = pg.NewPool(connectionString)
pool, err = pg.NewPool(cfg.Database)
if err != nil {
return nil, err
}
Expand Down
22 changes: 16 additions & 6 deletions cmd/api/src/cmd/dawgs-harness/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ import (
"github.com/jackc/pgx/v5/pgxpool"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/specterops/bloodhound/cmd/api/src/cmd/dawgs-harness/tests"
"github.com/specterops/bloodhound/cmd/api/src/config"
"github.com/specterops/bloodhound/packages/go/bhlog"
schema "github.com/specterops/bloodhound/packages/go/graphschema"
"github.com/specterops/dawgs"
"github.com/specterops/dawgs/drivers"
"github.com/specterops/dawgs/drivers/neo4j"
"github.com/specterops/dawgs/drivers/pg"
"github.com/specterops/dawgs/graph"
Expand All @@ -44,14 +46,14 @@ func fatalf(format string, args ...any) {
os.Exit(1)
}

func RunTestSuite(ctx context.Context, connectionStr, driverName string) tests.TestSuite {
func RunTestSuite(ctx context.Context, connectionStr, driverName string, cfg drivers.DatabaseConfiguration) tests.TestSuite {
var (
pool *pgxpool.Pool
err error
)

if driverName == pg.DriverName {
pool, err = pg.NewPool(connectionStr)
pool, err = pg.NewPool(cfg)
if err != nil {
fatalf("Failed creating a new pgxpool: %s", err)
}
Expand Down Expand Up @@ -141,10 +143,18 @@ func main() {

bhlog.ConfigureDefaultText(os.Stdout)

cfg, err := config.NewDefaultConfiguration()
if err != nil {
fmt.Errorf("failed to create default configuration: %w", err)
}
Comment on lines +146 to +149
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

Critical: Error from NewDefaultConfiguration() is silently discarded.

fmt.Errorf creates an error value but doesn't do anything with it — the program continues with a zero-value cfg on failure. This should use fatalf (or similar) to halt execution.

Proposed fix
 	cfg, err := config.NewDefaultConfiguration()
 	if err != nil {
-		fmt.Errorf("failed to create default configuration: %w", err)
+		fatalf("failed to create default configuration: %v", err)
 	}
🤖 Prompt for AI Agents
In `@cmd/api/src/cmd/dawgs-harness/main.go` around lines 146 - 149, The call to
config.NewDefaultConfiguration() can fail but the code currently creates an
error value with fmt.Errorf and then continues with a nil/zero cfg; replace that
silent discard by checking err and terminating with a fatal log (e.g.,
log.Fatalf or fmt.Fatalf or panic) so the program doesn't continue with an
invalid cfg; update the error handling right after cfg, err :=
config.NewDefaultConfiguration() to log a descriptive message including the
wrapped err and exit (reference symbols: NewDefaultConfiguration, cfg, err).

cfg.Neo4J.Connection = neo4jConnectionStr
cfg.Database.Connection = pgConnectionStr

switch testType {
case "both":

n4jTestSuite := execSuite(neo4j.DriverName, func() tests.TestSuite {
return RunTestSuite(ctx, neo4jConnectionStr, neo4j.DriverName)
return RunTestSuite(ctx, neo4jConnectionStr, neo4j.DriverName, cfg.Neo4J)
})

fmt.Println()
Expand All @@ -153,20 +163,20 @@ func main() {
time.Sleep(time.Second * 3)

pgTestSuite := execSuite(pg.DriverName, func() tests.TestSuite {
return RunTestSuite(ctx, pgConnectionStr, pg.DriverName)
return RunTestSuite(ctx, pgConnectionStr, pg.DriverName, cfg.Database)
})
fmt.Println()

OutputTestSuiteDeltas(pgTestSuite, n4jTestSuite)

case "postgres":
execSuite(pg.DriverName, func() tests.TestSuite {
return RunTestSuite(ctx, pgConnectionStr, pg.DriverName)
return RunTestSuite(ctx, pgConnectionStr, pg.DriverName, cfg.Database)
})

case "neo4j":
execSuite(neo4j.DriverName, func() tests.TestSuite {
return RunTestSuite(ctx, neo4jConnectionStr, neo4j.DriverName)
return RunTestSuite(ctx, neo4jConnectionStr, neo4j.DriverName, cfg.Neo4J)
})
}
}
Expand Down
93 changes: 35 additions & 58 deletions cmd/api/src/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/specterops/bloodhound/cmd/api/src/serde"
"github.com/specterops/bloodhound/packages/go/bhlog/attr"
"github.com/specterops/bloodhound/packages/go/crypto"
Dawgs "github.com/specterops/dawgs/drivers"
)

const (
Expand All @@ -50,15 +51,6 @@ func (s TLSConfiguration) Enabled() bool {
return s.CertFile != "" && s.KeyFile != ""
}

type DatabaseConfiguration struct {
Connection string `json:"connection"`
Address string `json:"addr"`
Database string `json:"database"`
Username string `json:"username"`
Secret string `json:"secret"`
MaxConcurrentSessions int `json:"max_concurrent_sessions"`
}

type CollectorManifest struct {
Latest string `json:"latest"`
Versions []CollectorVersion `json:"versions"`
Expand All @@ -72,22 +64,6 @@ type CollectorVersion struct {

type CollectorManifests map[string]CollectorManifest

func (s DatabaseConfiguration) PostgreSQLConnectionString() string {
if s.Connection == "" {
return fmt.Sprintf("postgresql://%s:%s@%s/%s", s.Username, s.Secret, s.Address, s.Database)
}

return s.Connection
}

func (s DatabaseConfiguration) Neo4jConnectionString() string {
if s.Connection == "" {
return fmt.Sprintf("neo4j://%s:%s@%s/%s", s.Username, s.Secret, s.Address, s.Database)
}

return s.Connection
}

type CryptoConfiguration struct {
JWT JWTConfiguration `json:"jwt"`
Argon2 Argon2Configuration `json:"argon2"`
Expand Down Expand Up @@ -135,39 +111,40 @@ type DefaultAdminConfiguration struct {
}

type Configuration struct {
Version int `json:"version"`
BindAddress string `json:"bind_addr"`
SlowQueryThreshold int64 `json:"slow_query_threshold"`
MaxGraphQueryCacheSize int `json:"max_graphdb_cache_size"`
MaxAPICacheSize int `json:"max_api_cache_size"`
MetricsPort string `json:"metrics_port"`
RootURL serde.URL `json:"root_url"`
WorkDir string `json:"work_dir"`
LogLevel string `json:"log_level"`
LogPath string `json:"log_path"`
TLS TLSConfiguration `json:"tls"`
GraphDriver string `json:"graph_driver"`
Database DatabaseConfiguration `json:"database"`
Neo4J DatabaseConfiguration `json:"neo4j"`
Crypto CryptoConfiguration `json:"crypto"`
SAML SAMLConfiguration `json:"saml"`
DefaultAdmin DefaultAdminConfiguration `json:"default_admin"`
CollectorsBucketURL serde.URL `json:"collectors_bucket_url"`
CollectorsBasePath string `json:"collectors_base_path"`
DatapipeInterval int `json:"datapipe_interval"`
EnableStartupWaitPeriod bool `json:"enable_startup_wait_period"`
EnableAPILogging bool `json:"enable_api_logging"`
EnableCypherMutations bool `json:"enable_cypher_mutations"`
DisableAnalysis bool `json:"disable_analysis"`
DisableCypherComplexityLimit bool `json:"disable_cypher_complexity_limit"`
DisableIngest bool `json:"disable_ingest"`
DisableMigrations bool `json:"disable_migrations"`
GraphQueryMemoryLimit uint16 `json:"graph_query_memory_limit"`
EnableTextLogger bool `json:"enable_text_logger"`
RecreateDefaultAdmin bool `json:"recreate_default_admin"`
EnableUserAnalytics bool `json:"enable_user_analytics"`
ForceDownloadEmbeddedCollectors bool `json:"force_download_embedded_collectors"`
EnableAuditLogStdout bool `json:"enable_audit_log_stdout"`
Version int `json:"version"`
BindAddress string `json:"bind_addr"`
SlowQueryThreshold int64 `json:"slow_query_threshold"`
MaxGraphQueryCacheSize int `json:"max_graphdb_cache_size"`
MaxAPICacheSize int `json:"max_api_cache_size"`
MetricsPort string `json:"metrics_port"`
RootURL serde.URL `json:"root_url"`
WorkDir string `json:"work_dir"`
LogLevel string `json:"log_level"`
LogPath string `json:"log_path"`
TLS TLSConfiguration `json:"tls"`
GraphDriver string `json:"graph_driver"`
Database Dawgs.DatabaseConfiguration `json:"database"`
Neo4J Dawgs.DatabaseConfiguration `json:"neo4j"`
Crypto CryptoConfiguration `json:"crypto"`
SAML SAMLConfiguration `json:"saml"`
DefaultAdmin DefaultAdminConfiguration `json:"default_admin"`
CollectorsBucketURL serde.URL `json:"collectors_bucket_url"`
CollectorsBasePath string `json:"collectors_base_path"`
DatapipeInterval int `json:"datapipe_interval"`
EnableStartupWaitPeriod bool `json:"enable_startup_wait_period"`
EnableAPILogging bool `json:"enable_api_logging"`
EnableCypherMutations bool `json:"enable_cypher_mutations"`
DisableAnalysis bool `json:"disable_analysis"`
DisableCypherComplexityLimit bool `json:"disable_cypher_complexity_limit"`
DisableIngest bool `json:"disable_ingest"`
DisableMigrations bool `json:"disable_migrations"`
DisableTimeoutLimit bool `json:"disable_timeout_limit"`
GraphQueryMemoryLimit uint16 `json:"graph_query_memory_limit"`
EnableTextLogger bool `json:"enable_text_logger"`
RecreateDefaultAdmin bool `json:"recreate_default_admin"`
EnableUserAnalytics bool `json:"enable_user_analytics"`
ForceDownloadEmbeddedCollectors bool `json:"force_download_embedded_collectors"`
EnableAuditLogStdout bool `json:"enable_audit_log_stdout"`
}

func (s Configuration) TempDirectory() string {
Expand Down
5 changes: 3 additions & 2 deletions cmd/api/src/config/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package config
import (
"fmt"

Dawgs "github.com/specterops/dawgs/drivers"
"github.com/specterops/dawgs/drivers/neo4j"

"github.com/specterops/bloodhound/cmd/api/src/serde"
Expand Down Expand Up @@ -73,10 +74,10 @@ func NewDefaultConfiguration() (Configuration, error) {
TLS: TLSConfiguration{},
SAML: SAMLConfiguration{},
GraphDriver: neo4j.DriverName, // Default to PG as the graph driver
Database: DatabaseConfiguration{
Database: Dawgs.DatabaseConfiguration{
MaxConcurrentSessions: 10,
},
Neo4J: DatabaseConfiguration{
Neo4J: Dawgs.DatabaseConfiguration{
MaxConcurrentSessions: 10,
},
Crypto: CryptoConfiguration{
Expand Down
11 changes: 9 additions & 2 deletions cmd/api/src/daemons/changelog/changelog_e2e/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,14 @@ func newHarness() *Harness {
os.Exit(1)
}

pool, err := pg.NewPool(connStr)
cfg, err := config.NewDefaultConfiguration()
if err != nil {
slog.Error("Error creating new default configuration")
os.Exit(1)
}
cfg.Database.Connection = connStr

pool, err := pg.NewPool(cfg.Database)
if err != nil {
slog.Error("Failed to connect", attr.Error(err))
os.Exit(1)
Expand All @@ -91,7 +98,7 @@ func newHarness() *Harness {
os.Exit(1)
}

gormDB, err := database.OpenDatabase(connStr)
gormDB, err := database.OpenDatabase(cfg.Database)
if err != nil {
slog.Error("Failed to open", attr.Error(err))
os.Exit(1)
Expand Down
10 changes: 8 additions & 2 deletions cmd/api/src/daemons/changelog/ingestion_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,14 @@ func setupIntegrationTest(t *testing.T) IntegrationTestSuite {
connConf = pgtestdb.Custom(t, getPostgresConfig(t), pgtestdb.NoopMigrator{})
)

cfg, err := config.NewDefaultConfiguration()
if err != nil {
t.Logf("Error creating new default configuration: %v", err)
}
cfg.Database.Connection = connConf.URL()

// Create connection pool
pool, err := pg.NewPool(connConf.URL())
pool, err := pg.NewPool(cfg.Database)
require.NoError(t, err)

// Open graph database
Expand All @@ -113,7 +119,7 @@ func setupIntegrationTest(t *testing.T) IntegrationTestSuite {
err = graphDB.AssertSchema(ctx, schema())
require.NoError(t, err)

gormDB, err := database.OpenDatabase(connConf.URL())
gormDB, err := database.OpenDatabase(cfg.Database)
require.NoError(t, err)

db := database.NewBloodhoundDB(gormDB, auth.NewIdentityResolver(), cfg)
Expand Down
14 changes: 9 additions & 5 deletions cmd/api/src/daemons/datapipe/datapipe_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,17 @@ func setupIntegrationTestSuite(t *testing.T, fixturesPath string) IntegrationTes
workDir = t.TempDir()
)

cfg, err := config.NewDefaultConfiguration()
if err != nil {
t.Logf("Error creating new default configuration: %v", err)
}
cfg.Database.Connection = connConf.URL()

//#region Setup for dbs
pool, err := pg.NewPool(connConf.URL())
pool, err := pg.NewPool(cfg.Database)
require.NoError(t, err)

gormDB, err := database.OpenDatabase(connConf.URL())
gormDB, err := database.OpenDatabase(cfg.Database)
require.NoError(t, err)

db := database.NewBloodhoundDB(gormDB, auth.NewIdentityResolver(), config.Configuration{})
Expand Down Expand Up @@ -107,9 +113,7 @@ func setupIntegrationTestSuite(t *testing.T, fixturesPath string) IntegrationTes
err = os.Mkdir(path.Join(workDir, "tmp"), 0755)
require.NoError(t, err)

cfg := config.Configuration{
WorkDir: workDir,
}
cfg.WorkDir = workDir

cl := changelog.NewChangelog(graphDB, db, changelog.DefaultOptions())

Expand Down
8 changes: 7 additions & 1 deletion cmd/api/src/database/database_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,15 @@ func setupIntegrationTestSuite(t *testing.T) IntegrationTestSuite {
cfg = config.Configuration{}
)

cfg, err := config.NewDefaultConfiguration()
if err != nil {
t.Logf("Error creating new default configuration: %v", err)
}
cfg.Database.Connection = connConf.URL()

// #region Setup for dbs

gormDB, err := database.OpenDatabase(connConf.URL())
gormDB, err := database.OpenDatabase(cfg.Database)
require.NoError(t, err)

db := database.NewBloodhoundDB(gormDB, auth.NewIdentityResolver(), cfg)
Expand Down
14 changes: 12 additions & 2 deletions cmd/api/src/database/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ import (
"time"

"github.com/gofrs/uuid"
"github.com/jackc/pgx/v5/stdlib"
"github.com/specterops/bloodhound/cmd/api/src/auth"
"github.com/specterops/bloodhound/cmd/api/src/config"
"github.com/specterops/bloodhound/cmd/api/src/database/migration"
"github.com/specterops/bloodhound/cmd/api/src/model"
"github.com/specterops/bloodhound/cmd/api/src/model/appcfg"
"github.com/specterops/bloodhound/cmd/api/src/services/upload"
"github.com/specterops/bloodhound/packages/go/bhlog/attr"
"github.com/specterops/dawgs/drivers"
"github.com/specterops/dawgs/drivers/pg"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
Expand Down Expand Up @@ -227,15 +230,22 @@ func (s *BloodhoundDB) Transaction(ctx context.Context, fn func(tx *BloodhoundDB
}, opts...)
}

func OpenDatabase(connection string) (*gorm.DB, error) {
func OpenDatabase(cfg drivers.DatabaseConfiguration) (*gorm.DB, error) {
gormConfig := &gorm.Config{
Logger: &GormLogAdapter{
SlowQueryErrorThreshold: time.Second * 30,
SlowQueryWarnThreshold: time.Second * 10,
},
}

if db, err := gorm.Open(postgres.Open(connection), gormConfig); err != nil {
pool, err := pg.NewPool(cfg)
if err != nil {
return nil, err
}

dbPool := stdlib.OpenDBFromPool(pool)

if db, err := gorm.Open(postgres.New(postgres.Config{Conn: dbPool}), gormConfig); err != nil {
return nil, err
} else {
return db, nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ func setupIntegrationTestSuite(t *testing.T) IntegrationTestSuite {

// #region Setup for dbs

gormDB, err = database.OpenDatabase(connConf.URL())
cfg, err := config.NewDefaultConfiguration()
if err != nil {
t.Logf("Error creating new default configuration: %v", err)
}
cfg.Database.Connection = connConf.URL()

gormDB, err = database.OpenDatabase(cfg.Database)
require.NoError(t, err)

db = database.NewBloodhoundDB(gormDB, auth.NewIdentityResolver(), config.Configuration{})
Expand Down
Loading
Loading