@core/auth 기반 역할과 권한: 와일드카드, 본인 전용 규칙, 권한 상승 방지 부여
코드파일 10개컨텍스트약 615토큰검사 통과
설치
$
genpm add @core/rbac포함 내용
- src/lib/rbac/에 소스 코드, 파일 10개. (20.1kB)
- src/lib/rbac/AGENTS.md에 AI 규칙, 그리고 IDE 규칙 파일.
- @core/auth, @core/contracts, @core/db을(를) 자동으로 해결합니다.
README
이 패키지에는 README가 없습니다.
약 615토큰→ src/lib/rbac/AGENTS.md→ .cursor/rules/genpm-core-rbac.mdc
이것이 AI가 src/lib/rbac에서 작업할 때 읽는 내용 그대로입니다. 그 외에는 컨텍스트에 아무것도 추가되지 않습니다.
@core/rbac — rules for AI agents
Purpose
Authorization on top of @core/auth users: roles stored in the database, permissions resource:action with wildcards
(posts:*, *) and own-only grants (posts:update:own), and a role hierarchy (rank) that prevents privilege
escalation. Default roles: owner, admin, editor, support, author. Not authentication, not multi-tenancy.
Map
index.ts— public API:can,assertCan,getGrants,grantRole,revokeRole,bootstrapOwner,defineRole,ensureDefaultRoles.permissions.ts— pure matchergrants()(no DB).defaults.ts— default roles and their permissions.schema.ts— tablesroles,user_roles. Depends on../dband../auth.adapters/hono.ts—requirePermission(perm)middleware.adapters/next.ts—requirePermission(user, perm),permissionResponse(user, perm).admin.ts—usersAdminResourcefor @core/admin (users with roles; grant/revoke actions withusers:manage).
Integration
- Generate and apply migrations (see
src/lib/db/AGENTS.md). - At startup or in a setup script:
await ensureDefaultRoles(). - Make the first user owner once, e.g. in the
onLoginhook of @core/auth:onLogin: async ({ user, isNewUser }) => { if (isNewUser) await bootstrapOwner(user.id); }(only the first call wins). - Hono:
app.use(sessionMiddleware); app.post('/api/posts/:id/publish', requirePermission('posts:publish'), handler). Next.js:const user = await getUser(await cookies()); await requirePermission(user, 'posts:publish'); - Own-only checks:
await assertCan(user.id, 'posts:update', { ownerId: post.authorId }). - Verify: a user without roles gets 403; the owner gets 200.
Conventions
- Permission names: lowercase
resource:action(orders:refund). Actions in use: read, create, update, delete, publish, manage. - Check permissions on the server for every write and every private read; hiding UI is not authorization.
- Load
getGrants(userId)once per request and pass it tocan()when checking several permissions. - Change roles only through
grantRole/revokeRole(they enforce the hierarchy and keep at least one owner).
Don't
- Don't insert into
user_rolesdirectly, and don't add an env flag or "god mode" that bypassescan(). - Don't expose
defineRoleto users without checkingusers:manageand that the new rank is below the actor's. - Don't trust a role or permission sent by the client.
# @core/rbac — rules for AI agents
## Purpose
Authorization on top of @core/auth users: roles stored in the database, permissions `resource:action` with wildcards
(`posts:*`, `*`) and own-only grants (`posts:update:own`), and a role hierarchy (`rank`) that prevents privilege
escalation. Default roles: owner, admin, editor, support, author. Not authentication, not multi-tenancy.
## Map
- `index.ts` — public API: `can`, `assertCan`, `getGrants`, `grantRole`, `revokeRole`, `bootstrapOwner`, `defineRole`, `ensureDefaultRoles`.
- `permissions.ts` — pure matcher `grants()` (no DB).
- `defaults.ts` — default roles and their permissions.
- `schema.ts` — tables `roles`, `user_roles`. Depends on `../db` and `../auth`.
- `adapters/hono.ts` — `requirePermission(perm)` middleware. `adapters/next.ts` — `requirePermission(user, perm)`, `permissionResponse(user, perm)`.
- `admin.ts` — `usersAdminResource` for @core/admin (users with roles; grant/revoke actions with `users:manage`).
## Integration
1. Generate and apply migrations (see `src/lib/db/AGENTS.md`).
2. At startup or in a setup script: `await ensureDefaultRoles()`.
3. Make the first user owner once, e.g. in the `onLogin` hook of @core/auth:
`onLogin: async ({ user, isNewUser }) => { if (isNewUser) await bootstrapOwner(user.id); }` (only the first call wins).
4. Hono: `app.use(sessionMiddleware); app.post('/api/posts/:id/publish', requirePermission('posts:publish'), handler)`.
Next.js: `const user = await getUser(await cookies()); await requirePermission(user, 'posts:publish');`
5. Own-only checks: `await assertCan(user.id, 'posts:update', { ownerId: post.authorId })`.
6. Verify: a user without roles gets 403; the owner gets 200.
## Conventions
- Permission names: lowercase `resource:action` (`orders:refund`). Actions in use: read, create, update, delete, publish, manage.
- Check permissions on the server for every write and every private read; hiding UI is not authorization.
- Load `getGrants(userId)` once per request and pass it to `can()` when checking several permissions.
- Change roles only through `grantRole`/`revokeRole` (they enforce the hierarchy and keep at least one owner).
## Don't
- Don't insert into `user_roles` directly, and don't add an env flag or "god mode" that bypasses `can()`.
- Don't expose `defineRole` to users without checking `users:manage` and that the new rank is below the actor's.
- Don't trust a role or permission sent by the client.
.genpmignore 적용 후 주입될 정확한 트리입니다. 고정 대상:
// Adaptador Next.js (App Router), sin importar `next`.
// Server Component / Server Action: `const user = await getUser(await cookies()); await requirePermission(user, 'posts:publish');`
// Route handler: `const denied = await permissionResponse(user, 'orders:refund'); if (denied) return denied;`
import { can, type Grants, getGrants, type PermissionContext, RbacError } from '../index.ts';
type MaybeUser = { id: string } | null | undefined;
/** Lanza `RbacError` (`forbidden`) si no hay usuario o le falta el permiso; devuelve sus `Grants`. */
export async function requirePermission(user: MaybeUser, permission: string, ctx?: PermissionContext): Promise<Grants> {
if (!user) throw new RbacError('forbidden', 'not signed in');
const g = await getGrants(user.id);
if (!(await can(g, permission, ctx))) throw new RbacError('forbidden', `missing permission ${permission}`);
return g;
}
/** Para route handlers: `Response` 401/403 si no se puede, o `null` si se puede. */
export async function permissionResponse(
user: MaybeUser,
permission: string,
ctx?: PermissionContext,
): Promise<Response | null> {
if (!user) return Response.json({ error: 'unauthorized' }, { status: 401 });
return (await can(user.id, permission, ctx)) ? null : Response.json({ error: 'forbidden' }, { status: 403 });
}
이 패키지는 MCP 서버를 선언하지 않습니다.
| 버전 | 커밋 | 게시일 | 검사 |
|---|---|---|---|
| 1.0.1 | decbadd | 4시간 전 | 검사 통과 |
- npm
- 없음
- 제안됨
- GenPM은 npm 명령을 제안하고, 동의한 경우에만 실행합니다.
- 사용하는 패키지 (1)
- @core/admin ^1.0.0
- 검사
- 검사 통과 · 문제 0건
- 커밋
- v1.0.1 → decbadd748476defda5138e5dc02cd5b7086463b · 가져온 뒤 검증됨
- 스크립트
- 없음. GenPM은 패키지 코드를 절대 실행하지 않습니다.
- 라이선스
- MIT
- 품질
- 100/100
- 인정된 라이선스충족
- AGENTS.md에 목적 설명충족
- AGENTS.md에 통합 단계충족
- AGENTS.md에 규칙 또는 금지 사항충족
- 테스트 포함충족
- 보안 검사 통과충족
- 최근 6개월 내 게시충족
- 인증된 게시자충족
- 요약과 키워드충족
- 신고
- 문제가 있나요?