{"files": {"main.ts": "import {run} from './core.ts';\nimport {POLICY} from './policy.ts';\nexport function evaluate(payload: any): any { return run(payload, POLICY); }\n", "core.ts": "import {asciiLower, parentRoles} from './helpers.ts';\nfunction result(allowed: boolean, reason: string, matched: number[], policy: any): any { return {allowed: allowed, reason: reason, matched: matched, audit: (!allowed && policy.audit_denials) ? [reason] : []}; }\nfunction grantEffect(g: any): string { const e = g.effect ?? g.decision ?? g.type ?? g.kind; if (typeof e === 'string') { const v = asciiLower(e); if (v === 'deny' || v === 'denied' || v === 'reject') return 'deny'; return 'allow'; } if (typeof g.allow === 'boolean') return g.allow ? 'allow' : 'deny'; if (typeof g.deny === 'boolean') return g.deny ? 'deny' : 'allow'; if (typeof g.allowed === 'boolean') return g.allowed ? 'allow' : 'deny'; return 'allow'; }\nfunction grantScope(g: any): any { if (g.scope !== undefined) return g.scope; if (g.resource !== undefined && typeof g.resource !== 'object') return g.resource; if (g.resource_id !== undefined) return g.resource_id; if (g.resourceId !== undefined) return g.resourceId; if (g.scope_id !== undefined) return g.scope_id; if (g.resource !== undefined && g.resource !== null && typeof g.resource === 'object') return g.resource.id; return undefined; }\nexport function run(payload: any, policy: any): any { const subject: any = (payload && payload.subject) ? payload.subject : {}; const resource: any = (payload && payload.resource) ? payload.resource : {}; const now: any = payload ? payload.now : undefined; const issuedAt: any = payload ? (payload.issued_at ?? payload.issuedAt) : undefined; const actionReq: any = payload ? payload.action : undefined; if (subject.tenant !== resource.tenant) return result(false, 'tenant', [], policy); if (now - issuedAt > policy.token_ttl) return result(false, 'token', [], policy); const suspended: any = subject.suspended ?? subject.is_suspended ?? subject.isSuspended; if (policy.suspended_denies && suspended) return result(false, 'suspended', [], policy); const owner: any = subject.owner ?? subject.is_owner ?? subject.isOwner; if (policy.owner_bypass && owner) return result(true, 'owner', [], policy); const roleSet = new Set<string>(); const initial: any[] = []; const subjectRoles: any[] = Array.isArray(subject.roles) ? subject.roles : []; for (const r of subjectRoles) initial.push(r); if (policy.group_union) { const groups: any[] = Array.isArray(subject.groups) ? subject.groups : []; for (const g of groups) initial.push(g); } for (const r of initial) roleSet.add(r); if (policy.inherit_roles) { const queue: any[] = Array.from(roleSet); let idx = 0; while (idx < queue.length) { const cur: any = queue[idx]; idx++; const parents: any[] = parentRoles(payload ? payload.role_parents : undefined, cur); for (const p of parents) { if (!roleSet.has(p)) { roleSet.add(p); queue.push(p); } } } } const grants: any[] = (payload && Array.isArray(payload.grants)) ? payload.grants : []; const resourceId: any = resource.id ?? resource.resource_id ?? resource.resourceId; const matched: number[] = []; let anyAllow = false; let anyDeny = false; for (let i = 0; i < grants.length; i++) { const g: any = grants[i] || {}; const grole: any = g.role ?? g.role_name ?? g.roleName; if (!roleSet.has(grole)) continue; const gaction: any = g.action; let actionOk = false; if (typeof gaction === 'string' && typeof actionReq === 'string') { if (policy.action_casefold) { if (asciiLower(gaction) === asciiLower(actionReq)) actionOk = true; } else if (gaction === actionReq) actionOk = true; if (!actionOk && policy.wildcard_action && gaction === '*') actionOk = true; } else if (gaction === actionReq) actionOk = true; if (!actionOk) continue; const scope: any = grantScope(g); let scopeOk = false; if (scope === undefined || scope === null) scopeOk = true; else if (policy.resource_scope === 'prefix') scopeOk = typeof resourceId === 'string' && typeof scope === 'string' ? resourceId.startsWith(scope) : String(resourceId).startsWith(String(scope)); else scopeOk = scope === resourceId; if (!scopeOk) continue; const expires: any = g.expires ?? g.expires_at ?? g.expiry ?? g.expiresAt ?? null; let expiryOk = false; if (expires === null || expires === undefined) expiryOk = true; else if (policy.expiry_inclusive) expiryOk = now <= expires; else expiryOk = now < expires; if (!expiryOk) continue; matched.push(i); const eff = grantEffect(g); if (eff === 'deny') anyDeny = true; else anyAllow = true; } if (matched.length === 0) return result(!!policy.default_allow, 'default', [], policy); let allowed: boolean; if (policy.deny_wins) allowed = anyAllow && !anyDeny; else allowed = anyAllow; return result(allowed, 'grants', matched.slice(), policy); }\n", "policy.ts": "export const POLICY: any = {\"action_casefold\": true, \"audit_denials\": true, \"default_allow\": true, \"deny_wins\": true, \"expiry_inclusive\": true, \"group_union\": true, \"inherit_roles\": true, \"owner_bypass\": true, \"resource_scope\": \"exact\", \"suspended_denies\": true, \"token_ttl\": 100, \"wildcard_action\": true};\n", "helpers.ts": "export function asciiLower(s: string): string { let out = ''; for (let i = 0; i < s.length; i++) { const c = s.charCodeAt(i); if (c >= 65 && c <= 90) out += String.fromCharCode(c + 32); else out += s[i]; } return out; }\nexport function parentRoles(roleParents: any, role: any): any[] { const out: any[] = []; if (!roleParents) return out; if (!Array.isArray(roleParents) && typeof roleParents === 'object') { const v = roleParents[role]; if (Array.isArray(v)) { for (const x of v) out.push(x); } else if (v !== undefined && v !== null) out.push(v); return out; } if (Array.isArray(roleParents)) { for (const e of roleParents) { if (Array.isArray(e) && e.length >= 2 && e[0] === role) { if (Array.isArray(e[1])) { for (const x of e[1]) out.push(x); } else out.push(e[1]); } else if (e && typeof e === 'object') { const child = e.role ?? e.child ?? e.from ?? e.name; if (child === role) { const p = e.parents ?? e.parent ?? e.inherits ?? e.parent_roles ?? e.to; if (Array.isArray(p)) { for (const x of p) out.push(x); } else if (p !== undefined && p !== null) out.push(p); } } } return out; } return out; }\n"}}