snipe-auth-rbac 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snipe-auth-rbac",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Two-layer RBAC (system + company) for React, Next.js, and any modern TS app — paired with the Python sibling.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -509,4 +509,114 @@ DO $$ BEGIN
509
509
  END IF;
510
510
  END $$;
511
511
 
512
+ -- ─────────────────────────────────────────────────────────────────
513
+ -- 11. Table-level grants + Row-Level Security
514
+ --
515
+ -- The admin module under `snipe-auth-rbac/admin` reads + writes
516
+ -- rbac.* tables directly via PostgREST (`.from('roles').select()`)
517
+ -- so the matrix UI can render. That requires per-table grants —
518
+ -- USAGE on the schema isn't enough on its own.
519
+ --
520
+ -- Strategy:
521
+ -- * GRANT CRUD on every rbac.* table to `authenticated`.
522
+ -- * Layer RLS so reads are wide enough for the admin UI but
523
+ -- writes are super-admin only by default.
524
+ -- * service_role keeps full access (backend / migrations / admin
525
+ -- scripts use service_role).
526
+ --
527
+ -- Adopters who want a different access model (e.g. delegate role
528
+ -- editing to non-super admins) replace the WRITE policies after
529
+ -- this file applies.
530
+ -- ─────────────────────────────────────────────────────────────────
531
+
532
+ -- is_super_admin: convenience helper used by the policies below.
533
+ -- SECURITY DEFINER so a policy can call it without recursing into
534
+ -- RLS on the very tables it inspects.
535
+ CREATE OR REPLACE FUNCTION rbac.is_super_admin()
536
+ RETURNS boolean
537
+ LANGUAGE sql
538
+ STABLE
539
+ SECURITY DEFINER
540
+ SET search_path = rbac, public
541
+ AS $$
542
+ SELECT EXISTS (
543
+ SELECT 1
544
+ FROM rbac.user_system_roles usr
545
+ JOIN rbac.roles r ON r.id = usr.role_id
546
+ WHERE usr.user_id = auth.uid()
547
+ AND r.is_super
548
+ );
549
+ $$;
550
+
551
+ DO $$ BEGIN
552
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'authenticated') THEN
553
+ EXECUTE 'GRANT EXECUTE ON FUNCTION rbac.is_super_admin() TO authenticated';
554
+ EXECUTE 'GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA rbac TO authenticated';
555
+ END IF;
556
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'service_role') THEN
557
+ EXECUTE 'GRANT ALL ON ALL TABLES IN SCHEMA rbac TO service_role';
558
+ EXECUTE 'GRANT ALL ON ALL SEQUENCES IN SCHEMA rbac TO service_role';
559
+ EXECUTE 'ALTER DEFAULT PRIVILEGES IN SCHEMA rbac GRANT ALL ON TABLES TO service_role';
560
+ END IF;
561
+ END $$;
562
+
563
+ ALTER TABLE rbac.companies ENABLE ROW LEVEL SECURITY;
564
+ ALTER TABLE rbac.resources ENABLE ROW LEVEL SECURITY;
565
+ ALTER TABLE rbac.roles ENABLE ROW LEVEL SECURITY;
566
+ ALTER TABLE rbac.role_permissions ENABLE ROW LEVEL SECURITY;
567
+ ALTER TABLE rbac.user_system_roles ENABLE ROW LEVEL SECURITY;
568
+ ALTER TABLE rbac.user_company_roles ENABLE ROW LEVEL SECURITY;
569
+
570
+ -- READ — open to any authenticated user for static config tables;
571
+ -- own-row only on assignment tables (super-admin sees all).
572
+ DROP POLICY IF EXISTS rbac_companies_read ON rbac.companies;
573
+ CREATE POLICY rbac_companies_read ON rbac.companies FOR SELECT TO authenticated USING (true);
574
+
575
+ DROP POLICY IF EXISTS rbac_resources_read ON rbac.resources;
576
+ CREATE POLICY rbac_resources_read ON rbac.resources FOR SELECT TO authenticated USING (true);
577
+
578
+ DROP POLICY IF EXISTS rbac_roles_read ON rbac.roles;
579
+ CREATE POLICY rbac_roles_read ON rbac.roles FOR SELECT TO authenticated USING (true);
580
+
581
+ DROP POLICY IF EXISTS rbac_role_permissions_read ON rbac.role_permissions;
582
+ CREATE POLICY rbac_role_permissions_read ON rbac.role_permissions FOR SELECT TO authenticated USING (true);
583
+
584
+ DROP POLICY IF EXISTS rbac_user_system_roles_read ON rbac.user_system_roles;
585
+ CREATE POLICY rbac_user_system_roles_read ON rbac.user_system_roles FOR SELECT TO authenticated
586
+ USING (user_id = auth.uid() OR rbac.is_super_admin());
587
+
588
+ DROP POLICY IF EXISTS rbac_user_company_roles_read ON rbac.user_company_roles;
589
+ CREATE POLICY rbac_user_company_roles_read ON rbac.user_company_roles FOR SELECT TO authenticated
590
+ USING (user_id = auth.uid() OR rbac.is_super_admin());
591
+
592
+ -- WRITE — super-admin only across the board. Adopters override
593
+ -- after this file applies to delegate role editing further.
594
+ DROP POLICY IF EXISTS rbac_companies_write ON rbac.companies;
595
+ CREATE POLICY rbac_companies_write ON rbac.companies FOR ALL TO authenticated
596
+ USING (rbac.is_super_admin()) WITH CHECK (rbac.is_super_admin());
597
+
598
+ DROP POLICY IF EXISTS rbac_resources_write ON rbac.resources;
599
+ CREATE POLICY rbac_resources_write ON rbac.resources FOR ALL TO authenticated
600
+ USING (rbac.is_super_admin()) WITH CHECK (rbac.is_super_admin());
601
+
602
+ DROP POLICY IF EXISTS rbac_roles_write ON rbac.roles;
603
+ CREATE POLICY rbac_roles_write ON rbac.roles FOR ALL TO authenticated
604
+ USING (rbac.is_super_admin()) WITH CHECK (rbac.is_super_admin());
605
+
606
+ DROP POLICY IF EXISTS rbac_role_permissions_write ON rbac.role_permissions;
607
+ CREATE POLICY rbac_role_permissions_write ON rbac.role_permissions FOR ALL TO authenticated
608
+ USING (rbac.is_super_admin()) WITH CHECK (rbac.is_super_admin());
609
+
610
+ DROP POLICY IF EXISTS rbac_user_system_roles_write ON rbac.user_system_roles;
611
+ CREATE POLICY rbac_user_system_roles_write ON rbac.user_system_roles FOR ALL TO authenticated
612
+ USING (rbac.is_super_admin()) WITH CHECK (rbac.is_super_admin());
613
+
614
+ DROP POLICY IF EXISTS rbac_user_company_roles_write ON rbac.user_company_roles;
615
+ CREATE POLICY rbac_user_company_roles_write ON rbac.user_company_roles FOR ALL TO authenticated
616
+ USING (rbac.is_super_admin()) WITH CHECK (rbac.is_super_admin());
617
+
512
618
  COMMIT;
619
+
620
+ -- Tell PostgREST to refresh schema cache so the policies + grants
621
+ -- propagate without a manual reload.
622
+ NOTIFY pgrst, 'reload config';