utils

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 13, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package utils provides shared helpers for the MCP server: TheHive query building, entity-scope permission checks, filter normalization, result date/untrusted-data processing, and the elicitation HTTP transport.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddPermissionsToContext

func AddPermissionsToContext(ctx context.Context, perms *permissions.Config) context.Context

AddPermissionsToContext adds permissions configuration to the context

func CreateFilterFromJSONString

func CreateFilterFromJSONString(filterString string) (thehive.InputQueryNamedOperation, error)

CreateFilterFromJSONString parses a JSON object string into a TheHive named filter operation.

func ExpandEntitiesWithQueries

func ExpandEntitiesWithQueries(
	ctx context.Context,
	entityType string,
	entities []map[string]any,
	additionalQueries []string,
	permFilters map[string]any,
) ([]map[string]any, error)

ExpandEntitiesWithQueries expands each entity with its related data inline. When permission filters are configured for the calling tool, every parent entity must be within the filtered scope before its children are fetched.

func GetAttachmentsFromAlertID

func GetAttachmentsFromAlertID(ctx context.Context, client *thehive.APIClient, alertID string) ([]map[string]any, error)

GetAttachmentsFromAlertID returns the attachments of the given alert.

func GetAttachmentsFromCaseID

func GetAttachmentsFromCaseID(ctx context.Context, client *thehive.APIClient, caseID string) ([]map[string]any, error)

GetAttachmentsFromCaseID returns the attachments of the given case.

func GetCommentsFromAlertID

func GetCommentsFromAlertID(ctx context.Context, client *thehive.APIClient, alertID string) ([]map[string]any, error)

GetCommentsFromAlertID returns the comments of the given alert.

func GetCommentsFromCaseID

func GetCommentsFromCaseID(ctx context.Context, client *thehive.APIClient, caseID string) ([]map[string]any, error)

GetCommentsFromCaseID returns the comments of the given case.

func GetDefaultCortexIDFromContext added in v0.3.4

func GetDefaultCortexIDFromContext(ctx context.Context) string

GetDefaultCortexIDFromContext retrieves the default Cortex ID from the context

func GetEntityIDsInScope added in v1.0.0

func GetEntityIDsInScope(ctx context.Context, entityType string, entityIDs []string, permFilters map[string]any) (map[string]bool, error)

GetEntityIDsInScope reports which entity IDs match permFilters for the given type, resolved server-side in one list query. With no filters every ID is in scope. See scopedEntityIDsBatch for the query shape.

PRECONDITION: every id must be the ~-prefixed internal _id form. The single _in{_id} query does NOT match a bare id (a plain case number or a name), even one that get-by-idOrName would resolve — TheHive only honours _in on _id for the ~-prefixed form (DL-5764). This is safe for the similarity-expansion path, whose ids come straight from a prior search's _id field. Callers that accept user/LLM-supplied ids (which may be bare) must use ScopedEntityIDsTolerant instead, which resolves each id through the more forgiving get-by-idOrName path.

func GetHiveClientFromContext

func GetHiveClientFromContext(ctx context.Context) (*thehive.APIClient, error)

GetHiveClientFromContext returns the TheHive API client stored in the context, or an error when none is present.

func GetJSONFields

func GetJSONFields(v any) []string

GetJSONFields returns the json tag names of the exported fields of v (a struct or pointer to struct), skipping fields with no json tag or a "-" tag.

func GetObservablesFromAlertID

func GetObservablesFromAlertID(ctx context.Context, client *thehive.APIClient, alertID string) ([]map[string]any, error)

GetObservablesFromAlertID returns the observables of the given alert.

func GetObservablesFromCaseID

func GetObservablesFromCaseID(ctx context.Context, client *thehive.APIClient, caseID string) ([]map[string]any, error)

GetObservablesFromCaseID returns the observables of the given case.

func GetPagesFromAlertID

func GetPagesFromAlertID(ctx context.Context, client *thehive.APIClient, alertID string) ([]map[string]any, error)

GetPagesFromAlertID returns the pages of the given alert.

func GetPagesFromCaseID

func GetPagesFromCaseID(ctx context.Context, client *thehive.APIClient, caseID string) ([]map[string]any, error)

GetPagesFromCaseID returns the pages of the given case.

func GetPermissionsFromContext

func GetPermissionsFromContext(ctx context.Context) (*permissions.Config, error)

GetPermissionsFromContext retrieves permissions configuration from the context

func GetProceduresFromAlertID added in v0.3.3

func GetProceduresFromAlertID(ctx context.Context, client *thehive.APIClient, alertID string) ([]map[string]any, error)

GetProceduresFromAlertID returns the procedures of the given alert.

func GetProceduresFromCaseID added in v0.3.3

func GetProceduresFromCaseID(ctx context.Context, client *thehive.APIClient, caseID string) ([]map[string]any, error)

GetProceduresFromCaseID returns the procedures of the given case.

func GetScopedEntityIDsBatch added in v1.0.0

func GetScopedEntityIDsBatch(ctx context.Context, entityType string, entityIDs []string, permFilters map[string]any) (map[string]bool, error)

GetScopedEntityIDsBatch is an alias of GetEntityIDsInScope: both resolve the in-scope set with the same single list query (DL-5764). The distinct name is kept because callers document intent as a batch re-check on the similarity-expansion path.

func GetSimilarAlertsFromAlertID added in v1.0.0

func GetSimilarAlertsFromAlertID(ctx context.Context, client *thehive.APIClient, alertID string) ([]map[string]any, error)

GetSimilarAlertsFromAlertID returns other alerts that share observables with this alert (alert-to-alert correlation / deduplication).

func GetSimilarAlertsFromCaseID added in v1.0.0

func GetSimilarAlertsFromCaseID(ctx context.Context, client *thehive.APIClient, caseID string) ([]map[string]any, error)

GetSimilarAlertsFromCaseID returns alerts that share observables with the given case.

func GetSimilarCasesFromAlertID added in v1.0.0

func GetSimilarCasesFromAlertID(ctx context.Context, client *thehive.APIClient, alertID string) ([]map[string]any, error)

GetSimilarCasesFromAlertID returns cases that share observables with the given alert.

func GetSimilarCasesFromCaseID added in v1.0.0

func GetSimilarCasesFromCaseID(ctx context.Context, client *thehive.APIClient, caseID string) ([]map[string]any, error)

GetSimilarCasesFromCaseID is the classic "Similar Cases": other cases that share observables with this case.

func GetSupportedQueries

func GetSupportedQueries(entityType string) []string

GetSupportedQueries returns the list of supported queries for an entity type

func GetTaskLogsFromTaskID

func GetTaskLogsFromTaskID(ctx context.Context, client *thehive.APIClient, taskID string) ([]map[string]any, error)

GetTaskLogsFromTaskID returns the logs of the given task.

func GetTasksFromCaseID

func GetTasksFromCaseID(ctx context.Context, client *thehive.APIClient, caseID string) ([]map[string]any, error)

GetTasksFromCaseID returns the tasks of the given case.

func IsEntityInScope added in v1.0.0

func IsEntityInScope(ctx context.Context, entityType, entityID string, permFilters map[string]any) (bool, error)

IsEntityInScope is the single-ID form of GetEntityIDsInScope and shares its ~-prefixed-id precondition. For a possibly-bare user/LLM id use IsEntityInScopeTolerant.

func IsEntityInScopeTolerant added in v1.0.0

func IsEntityInScopeTolerant(ctx context.Context, entityType, entityID string, permFilters map[string]any) (bool, error)

IsEntityInScopeTolerant is the single-ID form of ScopedEntityIDsTolerant: it resolves the id through the bare-id-tolerant get-by-idOrName path.

func IsJobObservableInScope added in v1.0.0

func IsJobObservableInScope(ctx context.Context, jobID string, permFilters map[string]any) (bool, error)

IsJobObservableInScope reports whether a Cortex job's target observable matches permFilters, resolved server-side (getJob -> observable -> filter). No filters: every job is in scope.

func ListOperationName added in v1.0.0

func ListOperationName(entityType string) string

ListOperationName returns the TheHive list operation for a type ("case" -> "listCase").

func NewToolResultJSONUnescaped

func NewToolResultJSONUnescaped(data any) *mcp.CallToolResult

NewToolResultJSONUnescaped builds an MCP tool result without escaping non-ASCII characters, so Unicode stays literal, not \uXXXX-escaped.

func NormalizeFilterKeys added in v1.0.0

func NormalizeFilterKeys(filterMap map[string]any) map[string]any

NormalizeFilterKeys recursively repairs malformed keys in a filter map (see normalizeFilterKey), walking nested maps/slices like TranslateDatesToTimestamps. Unrecoverable keys fall through so TheHive returns its field-listing 400. Mutates and returns filterMap.

Apply only to FILTER maps, never to entity-write payloads — a created entity may legitimately carry a field whose name needs no repair.

func ParseURIParameters added in v0.3.1

func ParseURIParameters(uri string) (string, map[string]any, error)

ParseURIParameters extracts query parameters from a parameters string

func ProcessDatesRecursive added in v0.3.1

func ProcessDatesRecursive(value any, wrapUntrusted bool) (any, error)

ProcessDatesRecursive recursively converts date fields in any Go value (structs, maps, slices, arrays, and nesting thereof). When wrapUntrusted is true, non-trusted fields are wrapped with [UNTRUSTED_DATA] boundary tags.

func ScopedEntityIDsByGetOneByOne added in v1.0.0

func ScopedEntityIDsByGetOneByOne(ctx context.Context, entityType string, entityIDs []string, permFilters map[string]any) (map[string]bool, error)

ScopedEntityIDsByGetOneByOne resolves scope per id through the canonical getX idOrName=<id> -> filter(permFilters) path. get-by-idOrName tolerates bare ids (a plain case number or a name), where the batched _in{_id} query matches only the ~-prefixed internal _id (DL-5764).

It is the implementation behind ScopedEntityIDsTolerant (the CRUD/manage and execute-automation paths) and also the independent differential oracle for TestGetScopedEntityIDsBatchHonorsIDFilter, which diffs the _in path against this one. Prefer the ScopedEntityIDsTolerant / IsEntityInScopeTolerant wrappers in callers so intent reads at the call site; this stays exported for the test.

func ScopedEntityIDsTolerant added in v1.0.0

func ScopedEntityIDsTolerant(ctx context.Context, entityType string, entityIDs []string, permFilters map[string]any) (map[string]bool, error)

ScopedEntityIDsTolerant reports which entity IDs match permFilters for the given type, resolving each id through the get-by-idOrName path (getX idOrName=<id> -> filter(permFilters)). Unlike GetEntityIDsInScope's single _in{_id} query, this tolerates BARE ids — a plain case number or a name that get-by-idOrName accepts, not only the ~-prefixed internal _id (DL-5764 regression).

Use this on the CRUD/manage and execute-automation paths, where entity ids are supplied by the user/LLM and may be bare. It costs N round-trips (one per id) instead of one; those paths address only a handful of ids, so the tolerance is worth the extra queries. The batched _in path stays on the similarity-expansion fan-out, where ids are provably ~-prefixed and the N-hit round-trip saving matters.

func TranslateDatesToTimestamps

func TranslateDatesToTimestamps(filterMap map[string]any) map[string]any

TranslateDatesToTimestamps recursively converts date strings in a filter map to epoch millis.

func UnwrapUnion added in v0.3.1

func UnwrapUnion(v any) any

UnwrapUnion returns the first non-nil pointer field of a union struct, or v itself if none. Union types opt in with a one-liner:

func (r T) Unwrap() any { return utils.UnwrapUnion(r) }

func ValidateQuery

func ValidateQuery(entityType, queryName string) error

ValidateQuery checks if a query is supported for an entity type

Types

type ElicitationTransport

type ElicitationTransport struct {
	Transport http.RoundTripper
}

ElicitationTransport wraps an http.RoundTripper to require user confirmation for modifying operations.

func (*ElicitationTransport) RoundTrip

func (e *ElicitationTransport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip elicits user confirmation for POST, PATCH, and DELETE before forwarding.

type EntityQueryConfig

type EntityQueryConfig map[string]QueryDescriptor

EntityQueryConfig maps query names to their descriptors.

type QueryDescriptor added in v1.0.0

type QueryDescriptor struct {
	Func QueryFunc
	// EntityType is the type of the RESULTS (e.g. similarCases returns cases),
	// used to project default fields and scope independent results.
	EntityType string
	// ResultsAreIndependent: re-scope these against permFilters (see above).
	ResultsAreIndependent bool
	// MetaFields are match-context fields (e.g. similarObservableCount) carried
	// FLAT alongside the entity by the *Light ops. Empty for queries with none.
	MetaFields []string
}

QueryDescriptor is the single source of truth for one additional query.

ResultsAreIndependent is security-critical: results TheHive returns as top-level entities (e.g. similar cases/alerts) get its .visible org/profile filter but NOT the MCP permFilters, so each hit must be re-checked against permFilters before surfacing or it leaks past the analyst's search scope (DL-6004). Child queries traverse from an already-scoped parent, so no re-check. Declaring it per-query (vs an out-of-band set) means a new independent query that forgets ResultsAreIndependent:true fails review at the registry / TestEveryRegisteredQueryDeclaresScopeIntent instead of failing open.

type QueryFunc

type QueryFunc func(ctx context.Context, client *thehive.APIClient, entityID string) ([]map[string]any, error)

QueryFunc queries data for a single entity.

type Unwrapper added in v0.3.1

type Unwrapper interface {
	Unwrap() any
}

Unwrapper is implemented by union/sum types wrapping a single active variant, so only that variant serializes instead of a struct full of nil siblings.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL