v2-0002-Convert-sepgsql-tests-to-TAP.patch

text/plain

Filename: v2-0002-Convert-sepgsql-tests-to-TAP.patch
Type: text/plain
Part: 1
Message: Re: Convert sepgsql tests to TAP

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v2-0002
Subject: Convert sepgsql tests to TAP
File+
contrib/sepgsql/.gitignore 2 2
contrib/sepgsql/Makefile 2 0
contrib/sepgsql/meson.build 10 1
contrib/sepgsql/t/001_sepgsql.pl 246 0
contrib/sepgsql/test_sepgsql 6 6
doc/src/sgml/regress.sgml 11 0
doc/src/sgml/sepgsql.sgml 13 4
meson.build 2 0
src/Makefile.global.in 2 0
From 9322b87aad3d207731dc71853f39cb9651ea8a18 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Tue, 27 Aug 2024 09:52:45 +0200
Subject: [PATCH v2 2/2] Convert sepgsql tests to TAP

Add a TAP test for sepgsql.  This automates the previously required
manual setup before the test.  The actual tests are still run by
pg_regress, but not called from within the TAP Perl script.

The previous manual test script (test_sepgsql) is left in place, since
its purpose is (also) to test whether a running instance was properly
initialized for sepgsql.  But it has been changed to call pg_regress
directly and no longer require make.

Discussion: https://www.postgresql.org/message-id/flat/651a5baf-5c45-4a5a-a202-0c8453a4ebf8@eisentraut.org
---
 contrib/sepgsql/.gitignore       |   4 +-
 contrib/sepgsql/Makefile         |   2 +
 contrib/sepgsql/meson.build      |  11 +-
 contrib/sepgsql/t/001_sepgsql.pl | 246 +++++++++++++++++++++++++++++++
 contrib/sepgsql/test_sepgsql     |  12 +-
 doc/src/sgml/regress.sgml        |  11 ++
 doc/src/sgml/sepgsql.sgml        |  17 ++-
 meson.build                      |   2 +
 src/Makefile.global.in           |   2 +
 9 files changed, 294 insertions(+), 13 deletions(-)
 create mode 100644 contrib/sepgsql/t/001_sepgsql.pl

diff --git a/contrib/sepgsql/.gitignore b/contrib/sepgsql/.gitignore
index 31613e011f5..b1778d05bbd 100644
--- a/contrib/sepgsql/.gitignore
+++ b/contrib/sepgsql/.gitignore
@@ -3,5 +3,5 @@
 /sepgsql-regtest.if
 /sepgsql-regtest.pp
 /tmp
-# Generated subdirectories
-/results/
+# Generated by test suite
+/tmp_check/
diff --git a/contrib/sepgsql/Makefile b/contrib/sepgsql/Makefile
index afca75b693f..90b4585a9e2 100644
--- a/contrib/sepgsql/Makefile
+++ b/contrib/sepgsql/Makefile
@@ -15,6 +15,8 @@ OBJS = \
 DATA_built = sepgsql.sql
 PGFILEDESC = "sepgsql - SELinux integration"
 
+TAP_TESTS = 1
+
 # Note: because we don't tell the Makefile there are any regression tests,
 # we have to clean those result files explicitly
 EXTRA_CLEAN = -r $(pg_regress_clean_files) tmp/ *.pp sepgsql-regtest.if sepgsql-regtest.fc
diff --git a/contrib/sepgsql/meson.build b/contrib/sepgsql/meson.build
index acff379b4b6..56316e4882d 100644
--- a/contrib/sepgsql/meson.build
+++ b/contrib/sepgsql/meson.build
@@ -40,4 +40,13 @@ contrib_targets += custom_target('sepgsql.sql',
   install_dir: dir_data / 'contrib',
 )
 
-# TODO: implement sepgsql tests
+tests += {
+  'name': 'sepgsql',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_sepgsql.pl',
+    ],
+  },
+}
diff --git a/contrib/sepgsql/t/001_sepgsql.pl b/contrib/sepgsql/t/001_sepgsql.pl
new file mode 100644
index 00000000000..cba51403518
--- /dev/null
+++ b/contrib/sepgsql/t/001_sepgsql.pl
@@ -0,0 +1,246 @@
+
+# Copyright (c) 2024, PostgreSQL Global Development Group
+
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+if (!$ENV{PG_TEST_EXTRA} || $ENV{PG_TEST_EXTRA} !~ /\bsepgsql\b/)
+{
+	plan skip_all =>
+	  'Potentially unsafe test sepgsql not enabled in PG_TEST_EXTRA';
+}
+
+note "checking selinux environment";
+
+# matchpathcon must be present to assess whether the installation environment
+# is OK.
+note "checking for matchpathcon";
+if (system('matchpathcon -n . >/dev/null 2>&1') != 0)
+{
+	diag <<EOS;
+
+The matchpathcon command must be available.
+Please install it or update your PATH to include it
+(it is typically in '/usr/sbin', which might not be in your PATH).
+matchpathcon is typically included in the libselinux-utils package.
+EOS
+	die;
+}
+
+# runcon must be present to launch psql using the correct environment
+note "checking for runcon";
+if (system('runcon --help >/dev/null 2>&1') != 0)
+{
+	diag <<EOS;
+
+The runcon command must be available.
+runcon is typically included in the coreutils package.
+EOS
+	die;
+}
+
+# check sestatus too, since that lives in yet another package
+note "checking for sestatus";
+if (system('sestatus >/dev/null 2>&1') != 0)
+{
+	diag <<EOS;
+
+The sestatus command must be available.
+sestatus is typically included in the policycoreutils package.
+EOS
+	die;
+}
+
+# check that the user is running in the unconfined_t domain
+note "checking current user domain";
+my $DOMAIN = (split /:/, `id -Z 2>/dev/null`)[2];
+note "current user domain is '$DOMAIN'";
+if ($DOMAIN ne 'unconfined_t')
+{
+	diag <<'EOS';
+
+The regression tests must be launched from the unconfined_t domain.
+
+The unconfined_t domain is typically the default domain for user
+shell processes.  If the default has been changed on your system,
+you can revert the changes like this:
+
+  $ sudo semanage login -d `whoami`
+
+Or, you can add a setting to log in using the unconfined_t domain:
+
+  $ sudo semanage login -a -s unconfined_u -r s0-s0:c0.c255 `whoami`
+
+EOS
+	die;
+}
+
+# SELinux must be configured in enforcing mode
+note "checking selinux operating mode";
+my $CURRENT_MODE =
+  (split /: */, `LANG=C sestatus | grep '^Current mode:'`)[1];
+chomp $CURRENT_MODE;
+note "current operating mode is '$CURRENT_MODE'";
+if ($CURRENT_MODE eq 'enforcing')
+{
+	# OK
+}
+elsif ($CURRENT_MODE eq 'permissive' || $CURRENT_MODE eq 'disabled')
+{
+	diag <<'EOS';
+
+Before running the regression tests, SELinux must be enabled and
+must be running in enforcing mode.
+
+If SELinux is currently running in permissive mode, you can
+switch to enforcing mode using the 'setenforce' command.
+
+  $ sudo setenforce 1
+
+The system default setting is configured in /etc/selinux/config,
+or using a kernel boot parameter.
+EOS
+	die;
+}
+else
+{
+	diag <<EOS;
+
+Unable to determine the current selinux operating mode.  Please
+verify that the sestatus command is installed and in your PATH.
+EOS
+	die;
+}
+
+# 'sepgsql-regtest' policy module must be loaded
+note "checking for sepgsql-regtest policy";
+my $SELINUX_MNT = (split /: */, `sestatus | grep '^SELinuxfs mount:'`)[1];
+chomp $SELINUX_MNT;
+if ($SELINUX_MNT eq "")
+{
+	diag <<EOS;
+
+Unable to find SELinuxfs mount point.
+
+The sestatus command should report the location where SELinuxfs
+is mounted, but did not do so.
+EOS
+	die;
+}
+if (!-e "${SELINUX_MNT}/booleans/sepgsql_regression_test_mode")
+{
+	diag <<'EOS';
+
+The 'sepgsql-regtest' policy module appears not to be installed.
+Without this policy installed, the regression tests will fail.
+You can install this module using the following commands:
+
+  $ make -f /usr/share/selinux/devel/Makefile
+  $ sudo semodule -u sepgsql-regtest.pp
+
+To confirm that the policy package is installed, use this command:
+
+  $ sudo semodule -l | grep sepgsql
+
+EOS
+	die;
+}
+
+# Verify that sepgsql_regression_test_mode is active.
+note "checking whether policy is enabled";
+foreach
+  my $policy ('sepgsql_regression_test_mode', 'sepgsql_enable_users_ddl')
+{
+	my $POLICY_STATUS = (split ' ', `getsebool $policy`)[2];
+	note "$policy is '$POLICY_STATUS'";
+	if ($POLICY_STATUS ne "on")
+	{
+		diag <<EOS;
+
+The SELinux boolean '$policy' must be
+turned on in order to enable the rules necessary to run the
+regression tests.
+
+EOS
+
+		if ($POLICY_STATUS eq "")
+		{
+			diag <<EOS;
+We attempted to determine the state of this Boolean using
+'getsebool', but that command did not produce the expected
+output.  Please verify that getsebool is available and in
+your PATH.
+EOS
+		}
+		else
+		{
+			diag <<EOS;
+You can turn on this variable using the following commands:
+
+  \$ sudo setsebool $policy on
+
+For security reasons, it is suggested that you turn off this
+variable when regression testing is complete and the associated
+rules are no longer needed.
+EOS
+		}
+		die;
+	}
+}
+
+
+#
+# checking complete - let's run the tests
+#
+
+note "running sepgsql regression tests";
+
+my $node;
+
+$node = PostgreSQL::Test::Cluster->new('test');
+$node->init;
+$node->append_conf('postgresql.conf', 'log_statement=none');
+
+{
+	local %ENV = $node->_get_env();
+
+	my $result = run_log(
+		[
+			'postgres', '--single',
+			'-F', '-c',
+			'exit_on_error=true', '-D',
+			$node->data_dir, 'template0'
+		],
+		'<',
+		$ENV{share_contrib_dir} . '/sepgsql.sql');
+	ok($result, 'sepgsql installation script');
+}
+
+$node->append_conf('postgresql.conf', 'shared_preload_libraries=sepgsql');
+$node->start;
+
+my @tests = qw(label dml ddl alter misc);
+
+# Check if the truncate permission exists in the loaded policy, and if so,
+# run the truncate test
+#
+# Testing the TRUNCATE regression test can be done by manually adding
+# the permission with CIL if necessary:
+#     sudo semodule -cE base
+#     sudo sed -i -E 's/(class db_table.*?) \)/\1 truncate\)/' base.cil
+#     sudo semodule -i base.cil
+push @tests, 'truncate' if -f '/sys/fs/selinux/class/db_table/perms/truncate';
+
+$node->command_ok(
+	[
+		$ENV{PG_REGRESS}, '--bindir=', '--inputdir=.', '--launcher',
+		'./launcher', @tests
+	],
+	'sepgsql tests');
+
+done_testing();
diff --git a/contrib/sepgsql/test_sepgsql b/contrib/sepgsql/test_sepgsql
index 3a29556d1ff..23dae1bf037 100755
--- a/contrib/sepgsql/test_sepgsql
+++ b/contrib/sepgsql/test_sepgsql
@@ -4,10 +4,10 @@
 # to try to ensure that the SELinux environment is set up appropriately and
 # the database is configured correctly.
 #
-# Note that this must be run against an installed Postgres database.
-# There's no equivalent of "make check", and that wouldn't be terribly useful
-# since much of the value is in checking that you installed sepgsql into
-# your database correctly.
+# This must be run against an installed Postgres database.  The
+# purpose of this script is in checking that you installed sepgsql
+# into your database correctly.  For testing sepgsql during
+# development, "make check", "meson test", etc. are also available.
 #
 # This must be run in the contrib/sepgsql directory of a Postgres build tree.
 #
@@ -302,5 +302,5 @@ if [ -f /sys/fs/selinux/class/db_table/perms/truncate ]; then
 	tests+=" truncate"
 fi
 
-make REGRESS="$tests" REGRESS_OPTS="--launcher ./launcher" installcheck
-# exit with the exit code provided by "make"
+PGXS=`pg_config --pgxs`
+"$(dirname $PGXS)/../../src/test/regress/pg_regress" --inputdir=. --bindir="$PG_BINDIR" --launcher=./launcher $tests
diff --git a/doc/src/sgml/regress.sgml b/doc/src/sgml/regress.sgml
index d1042e02228..9aebd9f3bed 100644
--- a/doc/src/sgml/regress.sgml
+++ b/doc/src/sgml/regress.sgml
@@ -284,6 +284,17 @@ <title>Additional Test Suites</title>
      </listitem>
     </varlistentry>
 
+    <varlistentry>
+     <term><literal>sepgsql</literal></term>
+     <listitem>
+      <para>
+       Runs the test suite under <filename>contrib/sepgsql</filename>.  This
+       requires an SELinux environment that is set up in a specific way; see
+       <xref linkend="sepgsql-regression"/>.
+      </para>
+     </listitem>
+    </varlistentry>
+
     <varlistentry>
      <term><literal>ssl</literal></term>
      <listitem>
diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml
index bc308e3142d..9217c1b3d68 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -151,14 +151,23 @@ <title>Installation</title>
  <sect2 id="sepgsql-regression">
   <title>Regression Tests</title>
 
+  <para>
+   The <filename>sepgsql</filename> test suite is run if
+   <literal>PG_TEST_EXTRA</literal> contains <literal>sepgsql</literal> (see
+   <xref linkend="regress-additional"/>).  This method is suitable during
+   development of <productname>PostgreSQL</productname>.  Alternatively, there
+   is a way to run the tests to checks whether a database instance has been
+   set up properly for <literal>sepgsql</literal>.
+  </para>
+
   <para>
    Due to the nature of <productname>SELinux</productname>, running the
    regression tests for <filename>sepgsql</filename> requires several extra
    configuration steps, some of which must be done as root.
-   The regression tests will not be run by an ordinary
-   <literal>make check</literal> or <literal>make installcheck</literal> command; you must
-   set up the configuration and then invoke the test script manually.
-   The tests must be run in the <filename>contrib/sepgsql</filename> directory
+  </para>
+
+  <para>
+   The manual tests must be run in the <filename>contrib/sepgsql</filename> directory
    of a configured PostgreSQL build tree.  Although they require a build tree,
    the tests are designed to be executed against an installed server,
    that is they are comparable to <literal>make installcheck</literal> not
diff --git a/meson.build b/meson.build
index ea07126f78e..c18340adc90 100644
--- a/meson.build
+++ b/meson.build
@@ -3518,6 +3518,8 @@ foreach test_dir : tests
       # also test/ for non-installed test binaries built separately.
       env = test_env
       env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
+      temp_install_datadir = '@0@@1@'.format(test_install_destdir, dir_prefix / dir_data)
+      env.set('share_contrib_dir', temp_install_datadir / 'contrib')
 
       foreach name, value : t.get('env', {})
         env.set(name, value)
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 42f50b49761..190f5559acf 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -456,6 +456,7 @@ cd $(srcdir) && \
    PATH="$(bindir):$(CURDIR):$$PATH" \
    PGPORT='6$(DEF_PGPORT)' top_builddir='$(CURDIR)/$(top_builddir)' \
    PG_REGRESS='$(CURDIR)/$(top_builddir)/src/test/regress/pg_regress' \
+   share_contrib_dir='$(DESTDIR)$(datadir)/$(datamoduledir)' \
    $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) $(if $(PROVE_TESTS),$(PROVE_TESTS),t/*.pl)
 endef
 else # PGXS case
@@ -483,6 +484,7 @@ cd $(srcdir) && \
    $(with_temp_install) \
    PGPORT='6$(DEF_PGPORT)' top_builddir='$(CURDIR)/$(top_builddir)' \
    PG_REGRESS='$(CURDIR)/$(top_builddir)/src/test/regress/pg_regress' \
+   share_contrib_dir='$(abs_top_builddir)/tmp_install$(datadir)/$(datamoduledir)' \
    $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) $(if $(PROVE_TESTS),$(PROVE_TESTS),t/*.pl)
 endef
 
-- 
2.46.0