@@ -617,6 +617,140 @@ def test_libpq5_version(host):
617
617
print ("✓ libpq5 version is >= 14" )
618
618
619
619
620
+ def test_jit_pam_module_installed (host ):
621
+ """Test that the JIT PAM module (pam_jit_pg.so) is properly installed."""
622
+ # Check if gatekeeper is installed via Nix
623
+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres ls -la /var/lib/postgresql/.nix-profile/lib/security/pam_jit_pg.so 2>/dev/null" )
624
+ if result ['succeeded' ]:
625
+ print (f"\n JIT PAM module found in Nix profile:\n { result ['stdout' ]} " )
626
+ else :
627
+ print ("\n JIT PAM module not found in postgres user's Nix profile" )
628
+ assert False , "JIT PAM module (pam_jit_pg.so) not found in expected location"
629
+
630
+ # Check if the symlink exists in the Linux PAM security directory
631
+ result = run_ssh_command (host ['ssh' ], "find /nix/store -type f -path '*/lib/security/pam_jit_pg.so' 2>/dev/null | head -5" )
632
+ if result ['succeeded' ] and result ['stdout' ].strip ():
633
+ print (f"\n JIT PAM module symlinks found:\n { result ['stdout' ]} " )
634
+ else :
635
+ print ("\n No JIT PAM module symlinks found in /nix/store" )
636
+
637
+ # Verify the module is a valid shared library
638
+ result = run_ssh_command (host ['ssh' ], "file /var/lib/postgresql/.nix-profile/lib/security/pam_jit_pg.so" )
639
+ if result ['succeeded' ]:
640
+ print (f"\n JIT PAM module file type:\n { result ['stdout' ]} " )
641
+ assert "shared object" in result ['stdout' ].lower () or "dynamically linked" in result ['stdout' ].lower (), \
642
+ "JIT PAM module is not a valid shared library"
643
+
644
+ print ("✓ JIT PAM module is properly installed" )
645
+
646
+
647
+ def test_pam_postgresql_config (host ):
648
+ """Test that the PAM configuration for PostgreSQL exists and is properly configured."""
649
+ # Check PostgreSQL version to determine if PAM config should exist
650
+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres psql --version | grep -oE '[0-9]+' | head -1" )
651
+ pg_major_version = 15 # Default
652
+ if result ['succeeded' ] and result ['stdout' ].strip ():
653
+ try :
654
+ pg_major_version = int (result ['stdout' ].strip ())
655
+ except ValueError :
656
+ pass
657
+
658
+ print (f"\n PostgreSQL major version: { pg_major_version } " )
659
+
660
+ # PAM config should exist for non-PostgreSQL 15 versions
661
+ if pg_major_version != 15 :
662
+ # Check if PAM config file exists
663
+ result = run_ssh_command (host ['ssh' ], "ls -la /etc/pam.d/postgresql" )
664
+ if result ['succeeded' ]:
665
+ print (f"\n PAM config file found:\n { result ['stdout' ]} " )
666
+
667
+ # Check file permissions
668
+ result = run_ssh_command (host ['ssh' ], "stat -c '%a %U %G' /etc/pam.d/postgresql" )
669
+ if result ['succeeded' ]:
670
+ perms = result ['stdout' ].strip ()
671
+ print (f"PAM config permissions: { perms } " )
672
+ # Should be owned by postgres:postgres with 664 permissions
673
+ assert "postgres postgres" in perms , "PAM config not owned by postgres:postgres"
674
+ else :
675
+ print ("\n PAM config file not found" )
676
+ assert False , "PAM configuration file /etc/pam.d/postgresql not found"
677
+ else :
678
+ print ("\n Skipping PAM config check for PostgreSQL 15" )
679
+ # For PostgreSQL 15, the PAM config should NOT exist
680
+ result = run_ssh_command (host ['ssh' ], "test -f /etc/pam.d/postgresql" )
681
+ if result ['succeeded' ]:
682
+ print ("\n WARNING: PAM config exists for PostgreSQL 15 (not expected)" )
683
+
684
+ print ("✓ PAM configuration is properly set up" )
685
+
686
+
687
+ def test_jit_pam_gatekeeper_profile (host ):
688
+ """Test that the gatekeeper package is properly installed in the postgres user's Nix profile."""
689
+ # Check if gatekeeper is in the postgres user's Nix profile
690
+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres nix profile list 2>/dev/null | grep -i gatekeeper" )
691
+ if result ['succeeded' ] and result ['stdout' ].strip ():
692
+ print (f"\n Gatekeeper found in Nix profile:\n { result ['stdout' ]} " )
693
+ else :
694
+ # Try alternative check
695
+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres ls -la /var/lib/postgresql/.nix-profile/ | grep -i gate" )
696
+ if result ['succeeded' ] and result ['stdout' ].strip ():
697
+ print (f"\n Gatekeeper-related files in profile:\n { result ['stdout' ]} " )
698
+ else :
699
+ print ("\n Gatekeeper not found in postgres user's Nix profile" )
700
+ # This might be expected if it's installed system-wide instead
701
+
702
+ # Check if we can find the gatekeeper derivation
703
+ result = run_ssh_command (host ['ssh' ], "find /nix/store -maxdepth 1 -type d -name '*gatekeeper*' 2>/dev/null | head -5" )
704
+ if result ['succeeded' ] and result ['stdout' ].strip ():
705
+ print (f"\n Gatekeeper derivations found:\n { result ['stdout' ]} " )
706
+ else :
707
+ print ("\n No gatekeeper derivations found in /nix/store" )
708
+
709
+ print ("✓ Gatekeeper package installation check completed" )
710
+
711
+
712
+ def test_jit_pam_module_dependencies (host ):
713
+ """Test that the JIT PAM module has all required dependencies."""
714
+ # Check dependencies of the PAM module
715
+ result = run_ssh_command (host ['ssh' ], "ldd /var/lib/postgresql/.nix-profile/lib/security/pam_jit_pg.so 2>/dev/null" )
716
+ if result ['succeeded' ]:
717
+ print (f"\n JIT PAM module dependencies:\n { result ['stdout' ]} " )
718
+
719
+ # Check for required libraries
720
+ required_libs = ["libpam" , "libc" ]
721
+ for lib in required_libs :
722
+ if lib not in result ['stdout' ].lower ():
723
+ print (f"WARNING: Required library { lib } not found in dependencies" )
724
+
725
+ # Check for any missing dependencies
726
+ if "not found" in result ['stdout' ].lower ():
727
+ assert False , "JIT PAM module has missing dependencies"
728
+ else :
729
+ print ("\n Could not check JIT PAM module dependencies" )
730
+
731
+ print ("✓ JIT PAM module dependencies are satisfied" )
732
+
733
+
734
+ def test_jit_pam_postgresql_integration (host ):
735
+ """Test that PostgreSQL can be configured to use PAM authentication."""
736
+ # Check if PAM is available as an authentication method in PostgreSQL
737
+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres psql -c \" SELECT name, setting FROM pg_settings WHERE name LIKE '%pam%';\" 2>/dev/null" )
738
+ if result ['succeeded' ]:
739
+ print (f"\n PostgreSQL PAM-related settings:\n { result ['stdout' ]} " )
740
+
741
+ # Check pg_hba.conf for potential PAM entries (even if not currently active)
742
+ result = run_ssh_command (host ['ssh' ], "grep -i pam /etc/postgresql/pg_hba.conf 2>/dev/null || echo 'No PAM entries in pg_hba.conf'" )
743
+ if result ['succeeded' ]:
744
+ print (f"\n PAM entries in pg_hba.conf:\n { result ['stdout' ]} " )
745
+
746
+ # Verify PostgreSQL was compiled with PAM support
747
+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres pg_config --configure 2>/dev/null | grep -i pam || echo 'PAM compile flag not found'" )
748
+ if result ['succeeded' ]:
749
+ print (f"\n PostgreSQL PAM compile flags:\n { result ['stdout' ]} " )
750
+
751
+ print ("✓ PostgreSQL PAM integration check completed" )
752
+
753
+
620
754
def test_postgrest_read_only_session_attrs (host ):
621
755
"""Test PostgREST with target_session_attrs=read-only and check for session errors."""
622
756
# First, check if PostgreSQL is configured for read-only mode
0 commit comments