dynamicpathdetector

package
v0.0.283 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (
	DynamicIdentifier  string = "⋯" // U+22EF: ⋯
	WildcardIdentifier string = "*"
)

--- Identifier constants --- DynamicIdentifier matches exactly one path segment (single-segment wildcard). WildcardIdentifier matches zero-or-more path segments (glob-style **).

View Source
const (
	OpenDynamicThreshold     = 50
	EndpointDynamicThreshold = 100
)

--- Default collapse thresholds --- OpenDynamicThreshold is the fallback threshold used by AnalyzeOpens when no more-specific CollapseConfig matches the walked path prefix. EndpointDynamicThreshold is the counterpart for AnalyzeEndpoints.

Variables

This section is empty.

Functions

func AnalyzeEndpoints

func AnalyzeEndpoints(endpoints *[]types.HTTPEndpoint, analyzer *PathAnalyzer) []types.HTTPEndpoint

func AnalyzeOpen added in v0.0.118

func AnalyzeOpen(path string, analyzer *PathAnalyzer) (string, error)

func AnalyzeOpens added in v0.0.118

func AnalyzeOpens(opens []types.OpenCalls, analyzer *PathAnalyzer, sbomSet mapset.Set[string]) ([]types.OpenCalls, error)

func AnalyzeURL

func AnalyzeURL(urlString string, analyzer *PathAnalyzer) (string, error)

func CollapseAdjacentDynamicIdentifiers added in v0.0.275

func CollapseAdjacentDynamicIdentifiers(p string) string

CollapseAdjacentDynamicIdentifiers replaces runs of adjacent DynamicIdentifier segments (e.g. "/a/⋯/⋯/b") with a single WildcardIdentifier ("/a/*/b"). Static segments between dynamic identifiers prevent collapsing. String wrapper over the internal byte-level collapseAdjacentDynamic, intended for test coverage.

func CompareDynamic added in v0.0.119

func CompareDynamic(dynamicPath, regularPath string) bool

CompareDynamic checks whether `regularPath` is matched by `dynamicPath`. The dynamic path may contain DynamicIdentifier (⋯, exactly-one-segment wildcard) or WildcardIdentifier (*, zero-or-more-segment mid-path / one-or-more-segment trailing wildcard). The node-agent R0002 rule (Files Access Anomalies) uses this at every file-open to decide whether the access is in-profile.

Anchoring contract:

  • Anchored patterns (start with `/`): `/etc/*` matches files UNDER /etc but NOT the bare `/etc` directory itself, mirroring shell glob semantics. This avoids R0002 silently allowing access to a profiled directory's parent.
  • Unanchored `*` (no leading slash): explicit catch-all that also matches the root path `/`. The only way to whitelist `/` itself is an explicit unanchored `*`.

Trailing-slash insensitivity: `/etc/` is treated as `/etc`, and `/etc/passwd/` as `/etc/passwd`. Trailing empty path components from `strings.Split` are trimmed so `len(regular) > 0` correctly reflects the presence of a real path tail when matching trailing `*`.

The empty regular path (`""`) is treated as "no path" and matches nothing — distinct from the root path `/`, which matches unanchored `*` per the contract above.

func CompareExecArgs added in v0.0.278

func CompareExecArgs(profileArgs, runtimeArgs []string) bool

CompareExecArgs reports whether a runtime exec argument vector matches a profile argument vector. The profile vector may contain two wildcard tokens:

DynamicIdentifier  ("⋯") — matches exactly one argument position.
WildcardIdentifier ("*") — matches zero or more consecutive arguments.

Anything else is a literal-equality match. The match is anchored at both ends: every runtime argument must be consumed by the profile vector, either by a literal, a DynamicIdentifier, or absorbed into a WildcardIdentifier run.

Empty profileArgs is treated as "no argv constraint" — i.e. matches any runtime arg vector. This keeps path-only Execs entries (the common case in user-defined ApplicationProfiles, which omit the Args field) from silently triggering R0040 just because the rule started consulting was_executed_with_args.

NOTE: callers that need to express "argv MUST be empty" cannot do so through this API alone, because v1beta1.ExecCalls.Args is declared `json:",omitempty"` and an explicit `args: []` round-trips back as nil. Use MatchExecArgs with the profile entry's ArgsRequired flag for that case. CompareExecArgs is preserved for back-compat with callers that have not migrated to the args-required-aware API.

func MatchExecArgs added in v0.0.278

func MatchExecArgs(profileArgs []string, argsRequired bool, runtimeArgs []string) bool

MatchExecArgs reports whether a runtime exec argument vector satisfies a profile entry's argv contract. argsRequired carries the profile entry's ExecCalls.ArgsRequired flag and disambiguates the two cases that CompareExecArgs alone cannot tell apart:

argsRequired = false → no argv constraint; matches any runtime args.
                       This is the back-compat path for profiles that
                       omit Args (the common case for path-only
                       Execs entries in user-authored profiles).
argsRequired = true  → strict anchored match against profileArgs.
                       An empty profileArgs means "argv MUST be
                       empty"; a non-empty profileArgs is matched
                       anchored with wildcard tokens (see below).

This resolves the round-trip ambiguity that v1beta1.ExecCalls.Args (declared `json:",omitempty"`) introduced: an explicit `args: []` round-trips back as nil, so the storage layer alone cannot persist the distinction between "no constraint" and "must have no args". ArgsRequired persists the operator's intent explicitly.

The match semantics for argsRequired=true are the anchored-with- wildcards form documented on CompareExecArgs.

func MergeDuplicateEndpoints

func MergeDuplicateEndpoints(endpoints []*types.HTTPEndpoint) []*types.HTTPEndpoint

MergeDuplicateEndpoints folds duplicates and merges same-path specific-port endpoints into a wildcard-port (:0) sibling. Folding is symmetric and is keyed on the same triple HTTPEndpoint.Equal compares — (Endpoint, Direction, Internal). An Internal=false endpoint will therefore NOT merge with an Internal=true sibling even if their path and direction match.

  • If a specific-port endpoint is encountered AFTER its :0 sibling, the specific-port methods/headers are merged INTO the wildcard entry.
  • If a specific-port endpoint is encountered BEFORE its :0 sibling, it is initially recorded; when the wildcard arrives we sweep `seen` for same-(path, direction, Internal) specific-port siblings, fold them into the wildcard, and remove them from the output.

This contract was tightened on the back of upstream review on kubescape/storage#316 — a single :0 entry must NOT cause unrelated concrete-port endpoints to be wildcarded; only same-path same-Internal siblings fold.

func MergeStrings added in v0.0.118

func MergeStrings(existing, new []string) []string

func ProcessEndpoint

func ProcessEndpoint(endpoint *types.HTTPEndpoint, analyzer *PathAnalyzer, newEndpoints []*types.HTTPEndpoint) (*types.HTTPEndpoint, error)

Types

type CollapseConfig added in v0.0.275

type CollapseConfig struct {
	Prefix    string
	Threshold int
}

--- Collapse configuration --- CollapseConfig controls the threshold at which children of a trie node (under the given path Prefix) are collapsed into a dynamic node (⋯). Longest-prefix wins at analysis time.

func DefaultCollapseConfig added in v0.0.275

func DefaultCollapseConfig() CollapseConfig

DefaultCollapseConfig returns a value copy of the package-private fallback. Mutating the returned struct does not affect package state. The accessor pattern matches DefaultCollapseConfigs() — both protect the threshold-tuning surface from accidental cross-test or cross-caller corruption.

func DefaultCollapseConfigs added in v0.0.275

func DefaultCollapseConfigs() []CollapseConfig

DefaultCollapseConfigs returns a defensive copy of the package-level default per-prefix collapse thresholds. Callers that mutate the result will not affect the package state or other callers.

type PathAnalyzer

type PathAnalyzer struct {
	RootNodes map[string]*SegmentNode
	// contains filtered or unexported fields
}

func NewPathAnalyzer

func NewPathAnalyzer(threshold int) *PathAnalyzer

NewPathAnalyzer builds an analyzer with a single global collapse threshold and no per-prefix overrides — equivalent behaviour to the pre-CollapseConfig world. Retained so existing callers don't need to change.

func NewPathAnalyzerWithConfigs added in v0.0.275

func NewPathAnalyzerWithConfigs(defaultThreshold int, configs []CollapseConfig) *PathAnalyzer

NewPathAnalyzerWithConfigs builds an analyzer whose collapse threshold can vary per path prefix. defaultThreshold applies when no CollapseConfig in configs matches; configs are checked longest-prefix-wins at walk time.

configs is copied so the caller can reuse or mutate the slice without affecting the analyzer.

func (*PathAnalyzer) AnalyzePath

func (ua *PathAnalyzer) AnalyzePath(p, identifier string) (string, error)

func (*PathAnalyzer) FindConfigForPath added in v0.0.275

func (ua *PathAnalyzer) FindConfigForPath(path string) CollapseConfig

FindConfigForPath returns a value copy of the CollapseConfig whose Prefix matches `path` with the longest match. Falls back to the analyzer's default config (Prefix:"/") when no per-prefix override applies, so the result is always meaningful — there is no "no match" signal.

Returning by value keeps the analyzer's internal state immutable from callers. NewPathAnalyzerWithConfigs already makes a defensive inbound copy of `configs`; this is its outbound twin. Without it, `cfg := analyzer.FindConfigForPath(p); cfg.Threshold = 1` would silently mutate the analyzer's threshold map for every future call.

type SegmentNode

type SegmentNode struct {
	SegmentName string
	Count       int
	Children    map[string]*SegmentNode
}

func (*SegmentNode) IsNextDynamic

func (sn *SegmentNode) IsNextDynamic() bool

Jump to

Keyboard shortcuts

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