pgmorbacMulti-OrBAC for PostgreSQL
    DocumentationDownloadSource
    Use cases
    • How do I...?
    Getting Started
    • Introduction
    • Quick start
    • How pgmorbac compares
    • Upgrade
    Concepts
    • Organizations
    • Roles
    • Activities
    • Views
    • Contexts
    • Rules & Modalities
    • Global Rules
    • System Principals
    • Constraints
    • Row-Level Security
    • Decision Cache
    Resolution
    • is_allowed
    Recipes
    • Org Hierarchies
    • Multi-Tenant Isolation
    • Wildcard Admin
    • Delegation
    • Service Accounts
    • Deny Rules
    • Separation of Duty
    • Derived Roles
    • Cross-Org Access
    • Obligations & Recommendations
    • Temporal Access
    Integration
    • Fastify
    • PostgREST & RLS Context
    • SQL Only
    Reference
    • Function Reference
    Recipes

    Obligations & Recommendations

    Compliance duties attached to permissions.

    Situation. Valmont's compliance officer wants two things recorded in the policy itself, not in a wiki: physicians must countersign lab results they read, and they should attach a motive when they write a prescription.

    Assumes the shared Valmont setup.

    Obligations and recommendations never block

    Both modalities are informational. is_allowed ignores them entirely; they exist so your application can read the duty out of the same policy store that grants the permission.

    -- duty: countersign lab results
    INSERT INTO morbac.rules (org_id, role_id, activity, view, context_id, modality)
    SELECT o.id, r.id, 'read', 'lab-results',
           (SELECT id FROM morbac.contexts WHERE name = 'always'), 'obligation'
    FROM morbac.orgs o JOIN morbac.roles r ON r.org_id = o.id AND r.name = 'physician'
    WHERE o.name = 'Clinique Valmont Nord'
    ON CONFLICT DO NOTHING;
     
    -- advice: motivate the prescription
    INSERT INTO morbac.rules (org_id, role_id, activity, view, context_id, modality)
    SELECT o.id, r.id, 'prescribe', 'prescriptions',
           (SELECT id FROM morbac.contexts WHERE name = 'always'), 'recommendation'
    FROM morbac.orgs o JOIN morbac.roles r ON r.org_id = o.id AND r.name = 'physician'
    WHERE o.name = 'Clinique Valmont Nord'
    ON CONFLICT DO NOTHING;

    Reading them back

    SELECT * FROM morbac.pending_obligations(
        '11111111-1111-4111-8111-111111111111',
        (SELECT id FROM morbac.orgs WHERE name = 'Clinique Valmont Nord'));
    -- rule_id | role_name | activity | view           | context_name | created_at
    --         | physician | read     | lab-results | always       | ...
     
    SELECT * FROM morbac.pending_recommendations(
        '11111111-1111-4111-8111-111111111111',
        (SELECT id FROM morbac.orgs WHERE name = 'Clinique Valmont Nord'));

    A UI typically renders obligations as a required checkbox and recommendations as a hint. The permission decision is separate and unchanged:

    SELECT morbac.is_allowed('11111111-1111-4111-8111-111111111111',
        (SELECT id FROM morbac.orgs WHERE name = 'Clinique Valmont Nord'),
        'read', 'lab-results');    -- depends only on permission rules

    Voiding semantics

    A duty that contradicts a ban is meaningless, so both listing functions filter themselves:

    • an obligation is voided by an applicable prohibition whose priority is greater than or equal to it;
    • a recommendation is voided by an applicable prohibition, and also by an applicable obligation, since a duty supersedes advice.

    Suspend the physicians from lab results and the obligation disappears from the list rather than nagging about an action they cannot take:

    INSERT INTO morbac.rules (org_id, role_id, activity, view, context_id, modality, priority)
    SELECT o.id, r.id, 'read', 'lab-results',
           (SELECT id FROM morbac.contexts WHERE name = 'always'), 'prohibition', 10
    FROM morbac.orgs o JOIN morbac.roles r ON r.org_id = o.id AND r.name = 'physician'
    WHERE o.name = 'Clinique Valmont Nord'
    ON CONFLICT DO NOTHING;
     
    SELECT count(*) FROM morbac.pending_obligations(
        '11111111-1111-4111-8111-111111111111',
        (SELECT id FROM morbac.orgs WHERE name = 'Clinique Valmont Nord'));   -- 0

    When to use which

    NeedModality
    block the actionprohibition
    allow the actionpermission
    allow, and record a mandatory follow-uppermission + obligation
    allow, and record advicepermission + recommendation

    Enforcement of an obligation stays in your application: pgmorbac tells you it exists, it does not stop the transaction.

    PreviousCross-Org AccessNext Temporal Access
    pgmorbac - Multi-OrBAC permission engine for PostgreSQL
    DocumentationDownloadGitea