analyzing-options
Analyzing different approaches for a task or problem with structured comparisons, effort…
Interactively authoring an access-manager permission-declaration manifest (permissions.yaml) for the access-manager "inversão de responsabilidade": drives a plugin team through discovering its real Authorize() surface, normalizing every action to the SEMANTIC standard (never
$ npx -y skills add LerianStudio/ring --skill declaring-plugin-permissions --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/declaring-plugin-permissionsContext preview
The summary Claude sees to decide when to auto-load this skill.
Interactively authoring an access-manager permission-declaration manifest (permissions.yaml) for the access-manager "inversão de responsabilidade": drives a plugin team through discovering its real Authorize() surface, normalizing every action to the SEMANTIC standard (never
name: ring:declaring-plugin-permissions description: >- Interactively authoring an access-manager permission-declaration manifest (permissions.yaml) for the access-manager "inversão de responsabilidade": drives a plugin team through discovering its real Authorize() surface, normalizing every action to the SEMANTIC standard (never HTTP verbs), declaring roles/group grants and the M2M contract, then emits and validates a manifest that matches the lib-auth/v3 auth/declaration schema. Use when a plugin must publish its own permissions at boot (WireFromEnv) instead of the access-manager seed owning them, or when writing/fixing a permissions.yaml. It also bumps the repo's github-actions-shared-workflows CI pin to the release carrying the permission-manifest nudge. Skip when the plugin has no auth guards, or you only need the wiring (see WireFromEnv) and the manifest already exists. allowed-tools: - AskUserQuestion - Read - Grep - Glob - Write - Edit - Bash
Drive a Lerian plugin team through authoring `permissions.yaml` — the client-side, SEMANTIC declaration the plugin PUBLISHES at boot under the access-manager inversion. This is an **interactive workflow**: follow the steps in order and use `AskUserQuestion` to gather every choice. Do not free-hand a manifest.
Schema authority: `lib-auth/v3 auth/declaration/manifest.go` (>= `v3.4.0-beta.1`), mirrored server-side by `plugin-access-manager identity/pkg/model/declaration.go`. The reconciler validates this exact shape at boot and refuses a bad manifest.
**THE CRITICAL INVARIANT:** every `(resource, action)` pair in the manifest MUST exactly match a real `AuthClient.Authorize(service, resource, action)` guard in the plugin (`lib-auth auth/middleware/middleware.go`). If they diverge, authz silently breaks — the guard demands a permission the manifest never declared. Adopting the semantic standard therefore means the **route guards AND the manifest move together**.
(`internal/auth/declaration/permissions.yaml`).
`Authorize("plugin-fees","estimates","post")`. Legacy. Never emit verb actions.
`permissions.yaml`.
standard.
`authdecl.WireFromEnv` and stop.
The schema doc comment says verbatim: *"The action is SEMANTIC (create/read/update/delete), never an HTTP verb."*
| HTTP verb (FORBIDDEN) | Semantic action (REQUIRED) | |-----------------------|----------------------------| | post | create | | get | read | | put / patch | update | | delete (method) | delete / remove |
Domain verbs are first-class and encouraged where CRUD does not fit: `rotate`, `trigger`, `justify`, `generate`, `reprocess`, `read_pii`, `request_read`, `request_write`, `receive`. Keep them; do not force them into CRUD.
**This is REQUIRED — and nothing downstream will hold it for you.** The HTTP-verb reject was removed from BOTH lib-auth and identity (lib-auth#145 / plugin-access-manager#310), so a manifest with `action: get` validates, boots and publishes without complaint — several in production do exactly that. What holds the standard is review plus the `check-manifest-actions` Makefile guard you add in Step 9. Only `delete` among HTTP methods is allowed — it is also a valid semantic action. Never emit `post`/`get`/`put`/`patch` as an `action`.
Top-level YAML: `service` (str, REQUIRED), `version` (int, REQUIRED), `permissions` (list), `roles` (list), `m2m` (object). All bare-name rules below: **the server composes the prefix — never pre-prefix.**
| Field | Rule | |-------|------| | `service` | REQUIRED, non-empty, no `.`/`..` segment. KEEP any `plugin-` prefix. MUST equal the M2M app slug AND DisplayName (BOLA, enforced at boot). Also the 1st arg of `Authorize`. | | `version` | REQUIRED int >= 1. ADVISORY — excluded from content hash; bumping alone is a no-op publish. | | `permissions[].resource` | REQUIRED, **BARE** (server composes `{service}/`). | | `permissions[].action` | REQUIRED, **SEMANTIC** — never an HTTP verb. | | `permissions[].effect` | `allow` ONLY. A `deny` is REJECTED — see below. | | `permissions[].roles` | >= 1 BARE role name, each MUST be declared in `roles:`. | | `roles[].name` | REQUIRED, BARE. `/` allowed as hierarchy separator (`fees/editor`). | | `roles[].granted_to` | list of `{ group: <bare-name> }`. **GROUP-ONLY** — there is no `user` grantee. Server composes the `{owner}/` prefix. | | `m2m.exposed` | bool — this plugin is callable as an M2M target. | | `m2m.needs` | list of target service slugs this plugin CALLS via M2M (e.g. `midaz`). |
**Why `deny` is refused and not merely discouraged.** The manifest used to accept it and the reconciler wrote it to Casdoor as a real permission, but no decision point ever applied it: every evaluator reads an effect other than `allow` as "did not match" and carries on, authorizing on the first `allow` that does match. There is no deny-wins pass. So a `deny` was a refusal you could read in the manifest, in review, and in the stored permission — while the runtime granted. Validation now refuses it at boot (fail-closed, lib-auth#183) and the declaration PUT answers 422 (plugin-access-manager#448).
Only the `effect` field is constrained. `deny` is still a fine ACTION name: `br-sfn/services/spb` declares `{ resource: str-emission-approvals, action: deny, effect: allow }`, because approving or denying an STR emission is that domain's verb.
Composed names the server builds: permissio
Proven engineering practices, enforced through skills. Ring is a comprehensive skills library and workflow system for AI agents that transforms how AI assistants approach software development.
Repo: LerianStudio/ring
Analyzing different approaches for a task or problem with structured comparisons, effort…
Auditing a service's production readiness against Ring engineering standards across base…
Cleaning redundant and obvious comments following clean code principles while preserving…
Commit changes with scope allowlist enforcement, atomic grouping, GPG-signed conventional…
Creating a handoff document that captures session state (completed work, decisions, open…
Creating an isolated git worktree for parallel branch work: selects the directory by priority…