Pure-function scope validation and wildcard matching for SkillKit.
Scope Format
Scopes are two-segment strings of the form "namespace:action", where both
segments must match ^[a-z][a-z0-9_-]*$ (lowercase ASCII, digits, hyphens,
underscores). Examples: "admin:read", "skills:execute", "tools:delete-all".
A wildcard scope "namespace:*" is valid format and means "any action within
the given namespace". The bare string "*" is NOT a valid scope.
Matching Rules
- Exact match:
"ns:action"covers"ns:action"only. - Wildcard match:
"ns:*"covers"ns:action"for any valid action. - No cross-namespace bypass:
"ns1:*"does NOT cover"ns2:action"even ifns1is a substring ofns2. - Segment boundary enforcement: Three-segment strings (e.g.
"a:b:c") are never matched, even by a wildcard.
Multi-Scope Semantics
any_covers?/2 checks whether ANY scope in a granted list covers the required
scope (OR semantics). ALL-of semantics — where a caller must hold every
required scope — are implemented in the SkillKit.Authorization module.
Examples
iex> SkillKit.Scope.Validation.valid?("admin:read")
true
iex> SkillKit.Scope.Validation.valid?("admin:*")
true
iex> SkillKit.Scope.Validation.valid?("*")
false
iex> SkillKit.Scope.Validation.covers?("admin:*", "admin:read")
true
iex> SkillKit.Scope.Validation.covers?("ski:*", "skills:read")
false
iex> SkillKit.Scope.Validation.any_covers?(["admin:*", "other:read"], "admin:write")
true
Summary
Functions
Returns true when any scope in granted_list covers required.
Returns true when granted covers required.
Returns true when scope is a syntactically valid scope string.
Validates scope and returns a tagged tuple.
Types
@type scope() :: String.t()
A scope string, e.g. "admin:read" or "admin:*"
Functions
Returns true when any scope in granted_list covers required.
granted_list must be a list; any other value (including nil) returns
false. Empty list returns false.
Returns true when granted covers required.
Supports exact match and wildcard match. Both arguments must be valid scope
strings; any malformed or non-binary input returns false without raising.
Returns true when scope is a syntactically valid scope string.
Accepts exact scopes ("ns:action") and wildcard scopes ("ns:*"). Rejects
non-binary values, whitespace-padded strings, bare "*", three-segment
strings, and strings with uppercase characters.
@spec validate(term()) :: {:ok, scope()} | {:error, :not_a_string | :leading_trailing_whitespace | {:invalid_scope_format, term()}}
Validates scope and returns a tagged tuple.
Returns {:ok, scope} for valid scopes, or one of:
{:error, :not_a_string}— input is not a binary{:error, :leading_trailing_whitespace}— binary has surrounding whitespace{:error, {:invalid_scope_format, scope}}— binary but invalid format