feat(tests): add more tests and make them pass
This commit is contained in:
+291
-22
@@ -1,30 +1,299 @@
|
||||
-- ============================================================================
|
||||
-- MORBAC PostgreSQL Extension - Cross-Organizational Rules Tests
|
||||
-- ============================================================================
|
||||
-- This test file covers cross-organizational authorization including:
|
||||
-- - Cross-organization rules (access between different orgs)
|
||||
-- - Inter-organizational collaboration scenarios
|
||||
-- - Cross-org permission validation
|
||||
-- =============================================================================
|
||||
-- Cross-Organization Rules Tests
|
||||
-- =============================================================================
|
||||
-- Tests inter-organizational access via the cross_org_rules table.
|
||||
--
|
||||
-- Prerequisites: Assumes 00_setup.sql has been run to set up base data
|
||||
-- ============================================================================
|
||||
-- Scenarios:
|
||||
-- 1. No cross-org rule: users in org A cannot access org B resources
|
||||
-- 2. Cross-org permission: specific role in source org can access target org
|
||||
-- 3. User must hold role in source org (not just any role)
|
||||
-- 4. Cross-org prohibition: blocks access even if there's a regular permission
|
||||
-- 5. Cross-org rules combine with activity hierarchy
|
||||
-- 6. Cross-org rules combine with view hierarchy
|
||||
-- 7. Temporal cross-org rules (valid_from / valid_until)
|
||||
--
|
||||
-- Company context:
|
||||
-- Judy (sales_rep at Sales) is allowed to read GlobalTech reports via cross-org rule
|
||||
-- Nina (eng_auditor at Engineering) has a temporal cross-org rule to read GlobalTech audit_logs
|
||||
-- Diana (sales_manager at Sales) has a cross-org prohibition on writing Engineering docs
|
||||
--
|
||||
-- Prerequisites: 00_setup.sql -> 05_temporal.sql
|
||||
-- =============================================================================
|
||||
|
||||
\echo ''
|
||||
\echo '=== Cross-Organization Rules ==='
|
||||
\echo '================================================================'
|
||||
\echo '06 — CROSS-ORGANIZATIONAL RULES'
|
||||
\echo '================================================================'
|
||||
|
||||
-- Allow Beta managers to read Acme documents (inter-org collaboration)
|
||||
INSERT INTO morbac.cross_org_rules (source_org_id, target_org_id, role_id, activity, view, context_id, modality) VALUES
|
||||
('22222222-2222-2222-2222-222222222222', '11111111-1111-1111-1111-111111111111', 'dddddddd-dddd-dddd-dddd-dddddddddddd', 'read', 'documents', (SELECT id FROM morbac.contexts WHERE name = 'always'), 'permission');
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Setup: additional roles and users for cross-org scenarios
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
\echo 'Diana (manager at Beta) can read Acme documents via cross-org rule:'
|
||||
SELECT
|
||||
'read Acme documents from Beta' as action,
|
||||
morbac.is_allowed(
|
||||
'dddddddd-0000-0000-0000-000000000004'::uuid,
|
||||
'11111111-1111-1111-1111-111111111111'::uuid,
|
||||
'read',
|
||||
'documents'
|
||||
) as allowed;
|
||||
-- Nina: eng_auditor role in Engineering Dept
|
||||
INSERT INTO morbac.roles (id, org_id, name, description) VALUES
|
||||
('20000000-0002-0000-0000-000000000003', '10000000-0000-0000-0000-000000000002', 'eng_auditor', 'Engineering Auditor');
|
||||
|
||||
INSERT INTO morbac.user_roles (user_id, role_id, org_id) VALUES
|
||||
('30000000-0000-0000-0000-000000000014', '20000000-0002-0000-0000-000000000003', '10000000-0000-0000-0000-000000000002');
|
||||
|
||||
-- Policies for eng_auditor in Engineering
|
||||
INSERT INTO morbac.policy (org_name, role_name, activity, view, modality, context_name)
|
||||
VALUES ('Engineering Dept', 'eng_auditor', 'read', 'audit_logs', 'permission', 'always');
|
||||
SELECT * FROM morbac.compile_policy();
|
||||
|
||||
-- Verify nina's role was set up correctly
|
||||
SELECT morbac.t('Nina has eng_auditor role at Engineering',
|
||||
morbac.user_has_role(
|
||||
'30000000-0000-0000-0000-000000000014'::uuid,
|
||||
'10000000-0000-0000-0000-000000000002'::uuid,
|
||||
'eng_auditor'
|
||||
), TRUE);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 1: No cross-org rule — access between orgs is denied by default
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 1. No cross-org rule: access denied by default ---'
|
||||
|
||||
-- Dave (employee at GlobalTech) has no role in Engineering and no cross-org rule
|
||||
SELECT morbac.t('Dave (GlobalTech employee) reads Engineering documents [no cross-org rule]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000004'::uuid,
|
||||
'10000000-0000-0000-0000-000000000002'::uuid,
|
||||
'read', 'documents'
|
||||
), FALSE);
|
||||
|
||||
-- Judy (Engineering engineer) accesses GlobalTech financial_data (no cross-org rule yet)
|
||||
SELECT morbac.t('Judy (Engineering engineer) reads GlobalTech financial_data [no cross-org rule]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000010'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'financial_data'
|
||||
), FALSE);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 2: Cross-org permission — Sales sales_rep reads GlobalTech reports
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 2. Cross-org permission ---'
|
||||
|
||||
-- Judy is sales_rep at Sales. Add a cross-org rule:
|
||||
-- Sales sales_rep can read GlobalTech reports
|
||||
INSERT INTO morbac.cross_org_rules
|
||||
(source_org_id, target_org_id, role_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'10000000-0000-0000-0000-000000000003', -- source: Sales Dept
|
||||
'10000000-0000-0000-0000-000000000001', -- target: GlobalTech HQ
|
||||
'20000000-0003-0000-0000-000000000002', -- sales_rep role
|
||||
'read', 'reports',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
|
||||
-- Cross-org rule grants access
|
||||
SELECT morbac.t('Judy (Sales sales_rep) reads GlobalTech reports via cross-org rule',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000010'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'reports'
|
||||
), TRUE);
|
||||
|
||||
-- Judy at Sales can still read Sales docs normally (local rule, no cross-org needed)
|
||||
SELECT morbac.t('Judy (Sales sales_rep) reads Sales documents [local rule]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000010'::uuid,
|
||||
'10000000-0000-0000-0000-000000000003'::uuid,
|
||||
'read', 'documents'
|
||||
), TRUE);
|
||||
|
||||
-- Judy does NOT have permission to read GlobalTech documents (cross-org rule only covers reports)
|
||||
SELECT morbac.t('Judy (Sales sales_rep) reads GlobalTech documents [no rule for documents]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000010'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'documents'
|
||||
), FALSE);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 3: User must hold role in source org
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 3. Role must be held in source org ---'
|
||||
|
||||
-- Karl has no role anywhere — cannot use the Sales->GlobalTech cross-org rule
|
||||
SELECT morbac.t('Karl (no role) reads GlobalTech reports via cross-org rule [no role in source]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'reports'
|
||||
), FALSE);
|
||||
|
||||
-- Karl also has no access to GlobalTech documents
|
||||
SELECT morbac.t('Karl (no role) reads GlobalTech documents [no access anywhere]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000011'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'documents'
|
||||
), FALSE);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 4: Cross-org prohibition — blocks access even with regular permission
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 4. Cross-org prohibition ---'
|
||||
|
||||
-- Engineering engineer can normally read Engineering documents (local perm)
|
||||
SELECT morbac.t('Judy (Engineering engineer) reads Engineering documents [local perm]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000010'::uuid,
|
||||
'10000000-0000-0000-0000-000000000002'::uuid,
|
||||
'read', 'documents'
|
||||
), TRUE);
|
||||
|
||||
-- Add Diana (sales_manager at Sales) for cross-org prohibition test
|
||||
INSERT INTO morbac.user_roles (user_id, role_id, org_id) VALUES
|
||||
('30000000-0000-0000-0000-000000000015', '20000000-0003-0000-0000-000000000001', '10000000-0000-0000-0000-000000000003');
|
||||
|
||||
-- Add cross-org prohibition: Sales sales_manager prohibited from writing Engineering documents
|
||||
INSERT INTO morbac.cross_org_rules
|
||||
(source_org_id, target_org_id, role_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'10000000-0000-0000-0000-000000000003', -- source: Sales Dept
|
||||
'10000000-0000-0000-0000-000000000002', -- target: Engineering Dept
|
||||
'20000000-0003-0000-0000-000000000001', -- sales_manager role
|
||||
'write', 'documents',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'prohibition'
|
||||
);
|
||||
|
||||
-- Also give a cross-org permission that would otherwise allow the write
|
||||
INSERT INTO morbac.cross_org_rules
|
||||
(source_org_id, target_org_id, role_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'10000000-0000-0000-0000-000000000003', -- source: Sales Dept
|
||||
'10000000-0000-0000-0000-000000000002', -- target: Engineering Dept
|
||||
'20000000-0003-0000-0000-000000000001', -- sales_manager role
|
||||
'write', 'documents',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
|
||||
-- Cross-org prohibition takes precedence over permission
|
||||
SELECT morbac.t('Diana (Sales sales_manager) writes Engineering documents [cross-org prohibition wins]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000015'::uuid,
|
||||
'10000000-0000-0000-0000-000000000002'::uuid,
|
||||
'write', 'documents'
|
||||
), FALSE);
|
||||
|
||||
-- Diana can read Engineering documents (no prohibition for read)
|
||||
INSERT INTO morbac.cross_org_rules
|
||||
(source_org_id, target_org_id, role_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'10000000-0000-0000-0000-000000000003', -- source: Sales Dept
|
||||
'10000000-0000-0000-0000-000000000002', -- target: Engineering Dept
|
||||
'20000000-0003-0000-0000-000000000001', -- sales_manager role
|
||||
'read', 'documents',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
|
||||
-- No prohibition for read, permission applies
|
||||
SELECT morbac.t('Diana (Sales sales_manager) reads Engineering documents [cross-org permission]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000015'::uuid,
|
||||
'10000000-0000-0000-0000-000000000002'::uuid,
|
||||
'read', 'documents'
|
||||
), TRUE);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 5: Cross-org + activity hierarchy
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 5. Cross-org with activity hierarchy ---'
|
||||
|
||||
-- The sales_rep cross-org rule grants 'read reports' in GlobalTech.
|
||||
-- With activity hierarchy (write->read), requesting 'write reports' also matches
|
||||
-- the 'read' rule (get_effective_activities('write') = {write, read}).
|
||||
SELECT morbac.t('Judy (Sales sales_rep) writes GlobalTech reports via cross-org + activity hierarchy',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000010'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'write', 'reports'
|
||||
), TRUE);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 6: Cross-org + view hierarchy
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 6. Cross-org with view hierarchy ---'
|
||||
|
||||
-- Add a cross-org rule for 'read documents' (not financial_data directly)
|
||||
-- With view hierarchy (financial_data->documents), 'read documents' cross-org rule
|
||||
-- also covers 'read financial_data' requests
|
||||
INSERT INTO morbac.cross_org_rules
|
||||
(source_org_id, target_org_id, role_id, activity, view, context_id, modality)
|
||||
VALUES (
|
||||
'10000000-0000-0000-0000-000000000003', -- source: Sales Dept
|
||||
'10000000-0000-0000-0000-000000000001', -- target: GlobalTech HQ
|
||||
'20000000-0003-0000-0000-000000000002', -- sales_rep role
|
||||
'read', 'documents',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission'
|
||||
);
|
||||
|
||||
-- get_effective_views('financial_data') = {financial_data, documents}
|
||||
-- so 'read documents' cross-org rule covers 'read financial_data' request
|
||||
SELECT morbac.t('Judy (Sales sales_rep) reads GlobalTech financial_data via cross-org + view hierarchy',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000010'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'financial_data'
|
||||
), TRUE);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Section 7: Temporal cross-org rule
|
||||
-- ---------------------------------------------------------------------------
|
||||
\echo ''
|
||||
\echo '--- 7. Temporal cross-org rule ---'
|
||||
|
||||
-- Add a time-limited cross-org rule for eng_auditor to read GlobalTech audit_logs
|
||||
INSERT INTO morbac.cross_org_rules
|
||||
(source_org_id, target_org_id, role_id, activity, view, context_id, modality, valid_from, valid_until)
|
||||
VALUES (
|
||||
'10000000-0000-0000-0000-000000000002', -- source: Engineering
|
||||
'10000000-0000-0000-0000-000000000001', -- target: GlobalTech HQ
|
||||
'20000000-0002-0000-0000-000000000003', -- eng_auditor role
|
||||
'read', 'audit_logs',
|
||||
(SELECT id FROM morbac.contexts WHERE name = 'always'),
|
||||
'permission',
|
||||
now() - interval '1 hour',
|
||||
now() + interval '1 day'
|
||||
);
|
||||
|
||||
-- Nina (Engineering eng_auditor) reads GlobalTech audit_logs within window
|
||||
SELECT morbac.t('Nina (Engineering eng_auditor) reads GlobalTech audit_logs [temporal cross-org, active]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000014'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'audit_logs'
|
||||
), TRUE);
|
||||
|
||||
-- Expire the cross-org rule
|
||||
UPDATE morbac.cross_org_rules
|
||||
SET valid_until = now() - interval '1 second'
|
||||
WHERE source_org_id = '10000000-0000-0000-0000-000000000002'
|
||||
AND target_org_id = '10000000-0000-0000-0000-000000000001'
|
||||
AND role_id = '20000000-0002-0000-0000-000000000003'
|
||||
AND activity = 'read' AND view = 'audit_logs';
|
||||
|
||||
-- Temporal rule expired
|
||||
SELECT morbac.t('Nina (Engineering eng_auditor) reads GlobalTech audit_logs [temporal cross-org, expired]',
|
||||
morbac.is_allowed_nocache(
|
||||
'30000000-0000-0000-0000-000000000014'::uuid,
|
||||
'10000000-0000-0000-0000-000000000001'::uuid,
|
||||
'read', 'audit_logs'
|
||||
), FALSE);
|
||||
|
||||
\echo ''
|
||||
\echo '=== Cross-Organization Rules Tests Completed ==='
|
||||
|
||||
Reference in New Issue
Block a user