Skip to main content

nocobase-acl-manage

NocoBase 2 only; never use in a NocoBase 3 project. Task-driven ACL governance through nb CLI for role lifecycle, global role mode, permission policy, Portal entry access, user-role membership, and risk assessment. Use when users describe business permission outcomes instead of raw command arguments, including which roles may enter a Portal.

Source facts

Repository
Agents-Store/opencode-plugins
Last source activity
October 3, 2026 at 23:16
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
18 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
nocobase-acl-manage
description
NocoBase 2 only; never use in a NocoBase 3 project. Task-driven ACL governance through nb CLI for role lifecycle, global role mode, permission policy, Portal entry access, user-role membership, and risk assessment. Use when users describe business permission outcomes instead of raw command arguments, including which roles may enter a Portal.
# Goal Turn ACL and permission governance into a task-driven workflow so users can ask for business outcomes while the skill handles: - CLI command selection and argument shaping - capability checks and safety guards - write confirmation and readback evidence - risk-oriented explanation for high-impact changes # Scope - This skill is CLI-first for reads and writes. - Tasks are grouped into five domains: - role - global role mode - permission, including Portal entry access - user - risk assessment - Every write task follows `plan -> confirm -> apply -> readback`. - `global role mode` is treated as a global system policy, not a per-role field. # Non-Goals - Do not bypass CLI by calling direct REST endpoints. - Do not mutate ACL through ad-hoc database operations. - Do not create temporary script files to execute ACL writes. - Do not invoke other skills for env/plugin bootstrap; use direct `nb` commands in this skill. - Do not hide high-impact blast radius (global mode, broad snippets, broad strategy actions). - Do not claim one-click coverage for workflows that require governance review. # Canonical Task Model ## A) Role Domain | Task | User Outcome | Required Inputs | Optional Inputs | |---|---|---|---| | `role.audit-all` | list all roles with comparable policy summary | none | `data_source_key`, `output` | | `role.create-blank` | create a role with default read-only baseline (single creation mode) | `role_name` | `role_title`, `description`, `hidden`, `allow_configure`, `allow_new_menu`, `portal_uid` or `portal_hint` when creating it for a resolved Portal | | `role.compare` | explain differences between roles | `role_names[]` | `data_source_key`, `output` | ## B) Global Role-Mode Domain | Task | User Outcome | Required Inputs | Optional Inputs | |---|---|---|---| | `global.role-mode.get` | read current global role mode | none | `output` | | `global.role-mode.set` | switch global role mode | `role_mode` | `strict_mode` | `role_mode` enum mapping: - `default`: independent role usage (no union mode) - `allow-use-union`: union mode available, role switching still allowed - `only-use-union`: force union mode for multi-role users ## C) Permission Domain | Task | User Outcome | Required Inputs | Optional Inputs | |---|---|---|---| | `permission.system-snippets.set` | set role-level system snippets | `role_name`, (`snippet_preset` or `snippets`) | none | | `permission.route.desktop.set` | set desktop route permissions for a role | `role_name`, `route_ids[]` | `set_mode` (`set` or `add` or `remove`) | | `permission.portal.access.set` | grant or revoke one role's access to an existing Portal | `role_name`, (`portal_uid` or `portal_hint`), `access` | none | | `permission.data-source.global.set` | set global strategy actions for all tables in one data source | `role_name`, `global_actions[]` | `data_source_key` | | `permission.data-source.resource.set` | set independent actions for one or more collections | `role_name`, (`collection_hint` or `collection_hints[]`), `actions[]` | `data_source_key`, `fields_map`, `scope_map`, `resource_scope` (`all` by default) | | `permission.scope.manage` | create/update/list reusable scopes | `scope_task` | `data_source_key`, `scope_id`, `scope_payload` | ## D) User Domain | Task | User Outcome | Required Inputs | Optional Inputs | |---|---|---|---| | `user.assign-role` | assign one role to one or many users | `role_name`, (`user_ids[]` or `user_filter`) | `allow_generic_association_write` | | `user.unassign-role` | remove one role from one or many users | `role_name`, (`user_ids[]` or `user_filter`) | `allow_generic_association_write` | | `user.audit-role-membership` | inspect users bound to roles | (`role_name` or `user_id`) | `output` | ## E) Risk Domain | Task | User Outcome | Required Inputs | Optional Inputs | |---|---|---|---| | `risk.assess-role` | risk score and rationale for one role | `role_name` | `data_source_key`, `output` | | `risk.assess-user` | risk score based on user-role-permission relationship | `user_id` | `data_source_key`, `output` | | `risk.assess-system` | system-level ACL governance risk summary | none | `data_source_key`, `output` | Role creation interaction policy: - always create with the same default read-only baseline (`role.create-blank`) - `role_name` must use NocoBase role uid format with `r_` prefix - if user input has no `r_` prefix, normalize to `r_<normalized_name>` and show normalized value in confirmation/readback - do not ask users to choose role archetypes (for example, "employee/auditor/manager/custom") - if `role_name` is provided, execute creation directly - when the request includes the current resolved Portal, resolve it before confirmation; after role creation, immediately grant that role explicit entry to the Portal through `permission.portal.access.set`, then read back both the role and exact Portal association - treat a failed Portal grant as partial completion and do not claim the new role is ready for that Portal - when no Portal context is available, do not guess or grant access to an unrelated Portal; after creation succeeds, move to permission assignment guidance - permission follow-up options: system snippets, desktop routes, Portal entry access, data-source global strategy, data-source resource strategy Resource permission interaction policy: - before executing `permission.data-source.resource.set`, always confirm: - data source key (`main` by default unless user specifies another) - resolved target collection(s) - action list - data scope (`all` by default when user does not specify) - disambiguate operation verbs from ACL action names: - phrases like `add table permission` / `configure permission` describe the operation, not ACL action `create` - only treat `create` as selected action when user clearly asks for data-creation capability (`can create records` / `can add data`) - user does not need to provide exact technical collection names - accept business names or keywords as `collection_hint(s)` - resolve real collection names from the selected data source collection list - if matching is ambiguous, present candidates and ask user to choose - if no match is found, ask user for a clearer business keyword - resolve scope binding before write: - if user does not specify scope, default to `all` - `all` -> built-in scope `key=all` id in target data source - `own` -> built-in scope `key=own` id in target data source - `custom` -> user-specified scope id (or resolved scope key) - do not leave action scope as `null` when final scope is `all` or `own` - write completeness (hard rule): - for `permission.data-source.resource.set`, execute one complete write payload per target collection - the write payload must include `usingActionsConfig: true` - the same payload must include the final `actions[]` set, with explicit scope binding (`scopeId` or `scopeKey`) for `all|own` and explicit non-empty `fields` arrays for field-configurable actions - do not stage writes as "set actions first, then patch fields/scope/usingActionsConfig" - before any write, show confirmation summary (data source + resolved collections + actions + scope) - when scope is defaulted, confirmation must explicitly state `scope=all (default)` and allow user override - if any required item is missing or unresolved, ask user first and do not write - default field rule: all fields - full-field default must be written as explicit field-name lists resolved from target collection metadata - do not use `fields=[]` as a full-field default marker - if user did not provide field-level restrictions, apply full-field permission for each selected action - apply full-field default to every selected action that supports field configuration (`create`, `view`, `update`, `export`, `importXlsx`) - full-field default must include system fields returned by metadata (for example `sort`, `createdBy`, `createdById`, `updatedBy`, `updatedById`) unless user explicitly asks to exclude them - use technical field names (`field.name`) for writes, never display titles - do not auto-drop fields only because they are system/context/relation/hidden; only exclude when user intent explicitly restricts them - `view` action must default to all fields for that collection - if user explicitly asks for `all permissions` on a collection, resolve runtime available actions and confirm expanded action set before write Portal permission interaction policy: - manage only whether a role may enter an existing custom Portal; do not treat this task as Portal-internal route, menu, page, region, control, or data permission configuration - resolve one real enabled Portal with `nb portal list -j` before planning a write; accept a uid, name, path, title, or business hint, but require disambiguation when matches are not unique - use the official `roles.multiPortals:list/add/remove` association actions exposed as `nb api acl roles multi-portals ...`; do not write the `rolesMultiPortals` through table directly - Portal access for a union role is allowed when any effective role has the explicit Portal grant; `root` can enter all enabled Portals - `allowNewMultiPortal` is a separate future-Portal default policy and is not evidence that a role can enter a specific existing Portal - after a write, read back the role's Portal association and verify the exact Portal uid is present or absent - if the Multi-portal capability or `roles multi-portals` runtime commands are unavailable, stop with capability guidance; do not emulate Portal grants in another collection # Input Contract | Input | Required | Default | Validation | Clarification Question | |---|---|---|---|---| | `task` | yes | none | one of canonical tasks or alias | "Which ACL governance task should run?" | | `role_name` | conditional | none | role exists for update/audit tasks; write tasks normalize to `r_*` uid | "Which role should be targeted?" | | `role_mode` | conditional | none | one of `default/allow-use-union/only-use-union` | "Which global role mode should be set?" | | `collection_hint` / `collection_hints[]` | conditional | none | required for `permission.data-source.resource.set`; business name/keyword input is allowed | "Which business table(s) should be configured?" | | `resolved_collection_names[]` | conditional | runtime resolved | required before write for `permission.data-source.resource.set`; each collection must exist in selected data source | "I found these matching collections. Which should be used?" | | `actions[]` | conditional | none | required for `permission.data-source.resource.set` | "Which actions should be granted on these collections?" | | `portal_uid` / `portal_hint` | conditional | none | required for Portal permission tasks; must resolve to one enabled custom Portal | "Which Portal should this role access?" | | `access` | conditional | none | `allow` or `deny` for `permission.portal.access.set` | "Should this role be allowed or denied entry to the Portal?" | | `resource_scope` | no | `all` | one of `all` / `own` / `custom(scope_id or scope_filter)` | "Which data scope should be used? Default is all; choose own/custom only when needed." | | `data_source_key` | no | `main` | must exist at runtime | "Which data source key should be used? (default: main)" | | `strict_mode` | no | `safe` | `safe` or `fast` | "Use safe mode with full readback?" | | `allow_generic_association_write` | no | `false` | boolean | "Allow guarded generic association writes for user-role assignment?" | | `output` | no | `text+matrix` | `text`, `text+matrix`, `text+evidence` | "How detailed should the result be?" | Default behavior when user says `you decide`: - choose role tasks for role intent - choose permission tasks for policy intent - choose user tasks for assignment intent - choose risk tasks for assessment intent - for role creation intent, always use `role.create-blank` first - `data_source_key=main` - `strict_mode=safe` ## Filter Authoring Gate Before authoring any reusable custom ACL scope, `scope_filter`, `user_filter`, or other persisted permission filter, load the `nocobase-utils` skill with topic `filter`, then read [Filter Condition Format](../nocobase-utils/references/filter/index.md) in the current task. Resolve every terminal field's live frontend interface/type and use only that group's operator allowlist. Date fields use date-specific comparison operators; `$lt`, `$lte`, `$gt`, and `$gte` remain number-only even when the backend accepts them. Do not apply this UI-displayable allowlist mechanically to fixed CLI locator objects such as `--filter-by-tk` or direct control filters documented by a command. # Mandatory Clarification Gate - max clarification rounds: `2` - max questions per round: `3` - never execute writes before required inputs are complete - for `role.create-blank`, ask only for `role_name` when missing; do not ask role-type questions - for write tasks with `role_name`, normalize to `r_*` uid and echo normalized value in confirmation - for `permission.data-source.resource.set`, default `data_source_key=main` when omitted unless user explicitly provides another data source - for `permission.data-source.resource.set`, if collection hint cannot be resolved or is ambiguous, ask follow-up questions before write - for `permission.data-source.resource.set`, if actions are incomplete, ask follow-up questions before write - for `permission.data-source.resource.set`, if scope is omitted, apply default `all` and require confirmation before write - for `permission.data-source.resource.set`, if custom scope is requested but scope id/key is unresolved, ask follow-up questions before write - for Portal writes, do not continue until one enabled custom Portal is resolved - for `permission.data-source.resource.set`, if user has not confirmed the final write plan, do not write - if user asks to set role mode for a specific role, clarify and normalize to global mode change - if task implies writes and target identity is missing, stop and ask first - if CLI returns auth errors (`401`, `403`, `Auth required`), stop and instruct the agent to hand off environment/auth recovery to `nocobase-env-manage` # Workflow 1. Resolve intent and normalize task. - map aliases to canonical tasks - map natural-language role mode wording to `default/allow-use-union/only-use-union` - normalize create-role wording to `role.create-blank` baseline first, then permission assignment 2. Capability gate (CLI). - confirm direct `nb` CLI is available in PATH - command assembly guard: - command form must be `nb <command> [subcommand ...] [flags ...]` - first token after `nb` must be a command (for example `env` or `api`), not a flag such as `-e`/`-t`/`-j` - wrong: `nb -e local` - correct: `nb api resource list --resource users -e local -j` - raw JSON input guard (PowerShell/runtime): - prefer structured body flags (for example `--resources`, `--actions`) over inline `--body` when possible - if raw JSON body is required, prefer `--body-file` over inline `--body` - `--body-file` content must be valid JSON encoded as UTF-8 without BOM - if inline `--body` fails JSON parsing in PowerShell, regenerate payload as `--body-file` and retry once - avoid Bash-style escaped JSON in PowerShell (for example `{\"k\":\"v\"}`), it may be parsed as invalid JSON - policy payload guard (hard rule for independent resource writes): - preflight must block `api acl roles data-source-resources create|update` and `api acl roles apply-data-permissions` when payload is missing or invalid (`--body-file` preferred, `--body` compatible) - for those writes, payload must include `usingActionsConfig: true` and non-empty `actions[]` - for actions `create/view/update/export/importXlsx`, each action must carry non-empty `fields[]` - for every action item, scope binding must be explicit via one of: - `scopeId` (for explicit id binding) - `scopeKey` (for key-based resolution, such as `all`/`own`) - `scope.{id|key}` (compatibility readback payload) - if user intent is scope `all` or `own`, readback must show resolved non-null `scopeId` - if guard fails, stop before CLI execution and return a fixable error - parameter safety guard: - command shape guard for resource permissions: - `roles data-source-resources` only has `create|get|update`; do not call `list` - for `roles data-source-resources get|update`, locator must be one of: - `--filter-by-tk <resource_config_id>` - `--data-source-key <data_source_key> --name <collection_name>` - for action-level independent-permission readback, use `roles data-source-resources get ... --appends actions`
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub