Files
OmniRoute/src/lib/accessTokens/scopes.ts
Diego Rodrigues de Sa e Souza 3c9883bb73 Release v3.8.29 (#4126)
OmniRoute v3.8.29 — 115 commits since v3.8.28. Full CHANGELOG + 41 i18n mirrors. All content quality gates green (build, unit 8/8, vitest 188/188, PR test policy, quality gates extended, docs sync, quality ratchet). Remaining red CI checks are pre-existing release flakes (coverage-shard/integration/node-compat teardown), a new transitive undici advisory in electron devDeps, and a workflow-level CodeQL fail (0 open alerts). VPS-validated by the operator.
2026-06-19 06:49:01 -03:00

52 lines
2.1 KiB
TypeScript

/**
* CLI access-token scopes — the 3-level hierarchy used by remote mode.
*
* These tokens authorize the `omniroute` CLI (and dashboard) to run *management*
* commands against a (possibly remote) OmniRoute server. They are distinct from
* inference API keys (`api_keys`), which authorize `/v1/chat/completions` traffic.
*
* Hierarchy (admin ⊃ write ⊃ read):
* - read : list/inspect only (models list, providers status, logs, usage, cost)
* - write : read + configure/apply (setup-codex, keys add, config set, combo edit)
* - admin : write + sensitive management (tokens create/revoke, providers add,
* services install/start, policy, oauth)
*
* Loopback-only routes that spawn processes (`isLocalOnlyPath`) are NEVER reachable
* by a remote token regardless of scope — that enforcement happens before auth.
*/
export const ACCESS_SCOPES = ["read", "write", "admin"] as const;
export type AccessScope = (typeof ACCESS_SCOPES)[number];
/** Numeric rank for hierarchy comparisons. Higher = more privileged. */
const SCOPE_RANK: Record<AccessScope, number> = {
read: 1,
write: 2,
admin: 3,
};
/** Type guard: is `value` one of the three valid scopes? */
export function isAccessScope(value: unknown): value is AccessScope {
return typeof value === "string" && (ACCESS_SCOPES as readonly string[]).includes(value);
}
/**
* True when a token holding `have` is allowed to perform an action that requires
* `need`. Hierarchy is inclusive: an `admin` token satisfies `write` and `read`;
* a `write` token satisfies `read`. Unknown scopes never satisfy anything.
*/
export function scopeSatisfies(have: unknown, need: AccessScope): boolean {
if (!isAccessScope(have)) return false;
return SCOPE_RANK[have] >= SCOPE_RANK[need];
}
/**
* Normalize an arbitrary input into a valid scope, falling back to the safest
* default (`read`) when the value is missing or invalid. Used when reading a
* stored/declared scope that must never silently widen privileges.
*/
export function normalizeScope(value: unknown, fallback: AccessScope = "read"): AccessScope {
return isAccessScope(value) ? value : fallback;
}