REPOSITORY / ScuroNeko/Laniakea

Wiki

KNOWLEDGE REPOSITORY
2
Policies
ScuroNeko edited this page 2026-05-20 13:19:27 +03:00

Policies

Policies are Laniakea's first-class authorization rules. A policy runs against the normalized MessageContext and injected AppData, returns nil when access is allowed, and returns an error when access should be denied or when the check itself fails.

Policies do not introduce a second execution model. They plug into the existing middleware pipeline through RequirePolicy(...), so authorization stays on the same routing path as the rest of the framework.

What policies give you

  • A reusable Policy[T] abstraction for access checks.
  • Middleware integration through RequirePolicy(...).
  • Registration helpers on Bot and Plugin through UsePolicy(...).
  • Built-in Telegram-aware checks for common chat and permission constraints.
  • Composition helpers for all-of, any-of, and inverted rules.

Core API

type Policy[T laniakea.AppData] func(ctx *laniakea.MessageContext, data T) error

func RequirePolicy[T laniakea.AppData](name string, p Policy[T]) Middleware[T]

func AllPolicies[T laniakea.AppData](policies ...Policy[T]) Policy[T]
func AnyPolicy[T laniakea.AppData](policies ...Policy[T]) Policy[T]
func NotPolicy[T laniakea.AppData](policy Policy[T]) Policy[T]

The policy contract is intentionally small:

  • Return nil to allow execution.
  • Return a user-visible error to deny execution.
  • Return an internal error to stop execution without leaking the failure text to the user.

Because policies follow the normal error model, they work naturally with AsUserError(...) and AsInternalError(...).

Registration

Policies are attached through the same bot and plugin configuration surface as middleware.

bot.UsePolicy("human-callbacks", laniakea.RequireCallbackFromUser())

plugin.UsePolicy(
	"admin-only",
	laniakea.AllPolicies(
		laniakea.RequireGroupChat(),
		laniakea.RequireChatAdmin(),
	),
)

RequirePolicy(...) is the lower-level adapter if you want to add the resulting middleware manually.

Built-in policies

The current built-in helpers focus on common Telegram-specific access checks:

  • RequirePrivateChat(...)
  • RequireGroupChat(...)
  • RequireSupergroupChat(...)
  • RequireChatAdmin(...)
  • RequireChatCreator(...)
  • RequireBotAdmin(...)
  • RequireCallbackFromUser(...)

These helpers use normalized MessageContext data. In particular, chat-aware policies rely on Chat and ChatID, which are now populated for more update kinds than only message-backed ones.

Composition

Policies are intended to be small building blocks.

AllPolicies

AllPolicies(...) succeeds only when every nested policy succeeds.

plugin.UsePolicy(
	"moderation",
	laniakea.AllPolicies(
		laniakea.RequireGroupChat(),
		laniakea.RequireChatAdmin(),
		laniakea.RequireBotAdmin(),
	),
)

Evaluation stops on the first returned error.

AnyPolicy

AnyPolicy(...) succeeds when at least one nested policy succeeds.

policy := laniakea.AnyPolicy(
	isGlobalOwner,
	laniakea.RequireChatCreator(),
)

If no policy succeeds:

  • an internal error wins over ordinary deny errors;
  • otherwise the first deny error is returned.

This keeps the composition fail-closed without hiding operator-relevant failures.

NotPolicy

NotPolicy(...) inverts a deny result.

policy := laniakea.NotPolicy(laniakea.RequirePrivateChat())

If the wrapped policy succeeds, NotPolicy(...) returns a deny error. If the wrapped policy returns an internal error, that internal error is preserved instead of being inverted into success.

Error model

Policy errors follow the same centralized handling path as handler errors:

  • user-visible errors can produce a normal user reply;
  • internal errors are logged but do not automatically leak their text to the chat.

That means policy checks can safely fail closed without forcing handlers to duplicate authorization logic.

Current limits

  • Policies are executed through bot and plugin middleware; scenes do not currently expose their own middleware layer.
  • The built-in helpers are Telegram-aware authorization helpers, not a full role or capability system.
  • The framework does not yet provide a separate principal model, RBAC DSL, or permission cache layer.

Those features can be added later if the existing Policy[T] model proves too small, but the current design keeps authorization explicit without making Laniakea into a heavy auth framework.

Related pages: