StaffRoleMap policy.staff-role-map@1

Generated at from openvibe-contracts v0.34.2 and openvibe-sdk v0.5.0.

Version
1.0.0
Owner
network
Visibility
public
Status
active
Compatibility
backward
Decision
ADR-022
Schema
https://openvibe.network/contracts/policy/staff-role-map.v1.json

The staff roles and the staff capabilities each one holds (ADR-022; roadmap W1 D7, D05). OpenVibe.Network owns the roles and issues the capabilities as claims in its user tokens; every service checks a staff capability instead of comparing role names. Roles are ordered lowest first, and a role holds every capability whose minRole is at or below it. Channel-scoped powers (a channel's owner and its moderators) are not staff capabilities: they stay with the product that owns the channel and are listed under local. The map in force is manifests/policy/staff-roles.json; contracts.staff reads it.

Fields

FieldTypeRequiredDescriptionConstraints
versionstringyesVersion of the map. Adding a capability or lowering a minRole is a minor; removing one or raising a minRole is a major.
  • pattern ^\d+\.\d+\.\d+$
rolesarray of objectyesLowest first. Each role holds every capability of the roles before it.
  • minItems 2
  • maxItems 16
  • items: no other fields
roles[].idstringyes
  • pattern ^[a-z][a-z0-9_]{1,31}$
roles[].staffbooleanyesWhether holders are staff. Non-staff roles hold no staff capability.
roles[].descriptionstringyes
  • minLength 1
  • maxLength 1000
roles[].sourcestringWhere the role is stored and how a token carries it today.
  • maxLength 1000
capabilitiesarray of objectyes
  • minItems 1
  • maxItems 200
  • items: no other fields
capabilities[].idstringyesstaff.<area>.<action>.
  • pattern ^staff\.[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*$
capabilities[].minRolestringyesThe lowest role that holds it; must be a staff role in roles.
  • pattern ^[a-z][a-z0-9_]{1,31}$
capabilities[].descriptionstringyes
  • minLength 1
  • maxLength 1000
capabilities[].gatesobjectWhere the raw role check this capability replaces lives today, per service (file:line and what it guards). Adoption swaps each for a capability check.
claimsobjectyesClaim names in OpenVibe.Network user tokens.
  • no other fields
claims.rolestringyesThe stored role (user, streamer, global_mod or admin). owner is never stored as a role.
  • pattern ^[a-z][a-z0-9_]{1,31}$
claims.ownerstringyesBoolean claim, true only for the owner account. With role admin it makes the effective role owner; on any other role it is ignored.
  • pattern ^[a-z][a-z0-9_]{1,31}$
claims.capabilitiesstringyesArray claim of the staff capabilities the effective role holds, issued only to staff.
  • pattern ^[a-z][a-z0-9_]{1,31}$
localarray of objectChannel-scoped or self-scoped powers that are not staff capabilities and stay with the product that owns the resource.
  • maxItems 50
  • items: no other fields
local[].idstringyes
  • pattern ^[a-z][a-z0-9_]*(\.[a-z0-9_]+){1,}$
local[].descriptionstringyes
  • minLength 1
  • maxLength 1000
local[].gatesobject
rulesarray of stringRules a capability check alone does not express, which every service applies on top.
  • maxItems 30
  • items: minLength 1
  • items: maxLength 1000

Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

Valid: minimal
{
  "version": "1.0.0",
  "roles": [
    {
      "id": "user",
      "staff": false,
      "description": "Everyone signed in."
    },
    {
      "id": "global_mod",
      "staff": true,
      "description": "Site-wide moderator."
    }
  ],
  "capabilities": [
    {
      "id": "staff.moderation.chat",
      "minRole": "global_mod",
      "description": "Moderate chat in any channel.",
      "gates": {
        "chat": [
          "chat/chat-server.js:511"
        ]
      }
    }
  ],
  "claims": {
    "role": "role",
    "owner": "is_owner",
    "capabilities": "staff_caps"
  },
  "local": [
    {
      "id": "live.channel.moderator",
      "description": "A channel moderator inside that channel."
    }
  ],
  "rules": [
    "Nobody acts against an equal or higher effective role."
  ]
}
Rejected: extra-field
{
  "version": "1.0.0",
  "roles": [
    {
      "id": "user",
      "staff": false,
      "description": "u"
    },
    {
      "id": "admin",
      "staff": true,
      "description": "a"
    }
  ],
  "claims": {
    "role": "role",
    "owner": "is_owner",
    "capabilities": "staff_caps"
  },
  "capabilities": [
    {
      "id": "staff.users.manage",
      "minRole": "admin",
      "description": "x",
      "grantedTo": [
        "app"
      ]
    }
  ]
}
Rejected: no-claims
{
  "version": "1.0.0",
  "roles": [
    {
      "id": "user",
      "staff": false,
      "description": "u"
    },
    {
      "id": "admin",
      "staff": true,
      "description": "a"
    }
  ],
  "capabilities": [
    {
      "id": "staff.users.manage",
      "minRole": "admin",
      "description": "x"
    }
  ]
}
Rejected: no-min-role
{
  "version": "1.0.0",
  "roles": [
    {
      "id": "user",
      "staff": false,
      "description": "u"
    },
    {
      "id": "admin",
      "staff": true,
      "description": "a"
    }
  ],
  "claims": {
    "role": "role",
    "owner": "is_owner",
    "capabilities": "staff_caps"
  },
  "capabilities": [
    {
      "id": "staff.users.manage",
      "description": "no minRole"
    }
  ]
}
Rejected: not-a-staff-id
{
  "version": "1.0.0",
  "roles": [
    {
      "id": "user",
      "staff": false,
      "description": "u"
    },
    {
      "id": "admin",
      "staff": true,
      "description": "a"
    }
  ],
  "claims": {
    "role": "role",
    "owner": "is_owner",
    "capabilities": "staff_caps"
  },
  "capabilities": [
    {
      "id": "moderation.chat.delete",
      "minRole": "admin",
      "description": "not a staff id"
    }
  ]
}
Rejected: two-segments
{
  "version": "1.0.0",
  "roles": [
    {
      "id": "user",
      "staff": false,
      "description": "u"
    },
    {
      "id": "admin",
      "staff": true,
      "description": "a"
    }
  ],
  "claims": {
    "role": "role",
    "owner": "is_owner",
    "capabilities": "staff_caps"
  },
  "capabilities": [
    {
      "id": "staff.moderation",
      "minRole": "admin",
      "description": "two segments"
    }
  ]
}

Validate

const contracts = require('openvibe-contracts');
contracts.validate('policy.staff-role-map@1', value);   // { valid, errors: [{ path, message }] }