Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ bbin
/sql/pgtap--0.97.0--0.98.0.sql
/sql/pgtap--0.98.0--0.99.0.sql
/sql/pgtap--0.99.0--1.0.0.sql
/sql/pgtap--1.3.4--1.3.5.sql
/sql/pgtap-static.sql
/sql/pgtap-static.sql.tmp*
*.sql.orig
Expand Down
2 changes: 2 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Revision history for pgTAP
and `hasnt_check()`. Also changed `has_unique()` argument types from `TEXT`
to `NAME` so they can share a consistent overload order with the other
constraint assertions. Thanks to @RampantDespair for the PR (#370).
* Added `has_rls()` to test whether row-level security is enabled on a table.
Thanks to @RampantDespair for the PR (#371).

1.3.4 2025-10-04T17:20:28Z
--------------------------
Expand Down
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,13 @@ endif
mv sql/pgtap.tmp sql/pgtap.sql

# Ugly hacks for now... TODO: script that understands $VERSION and will apply all the patch files for that version
EXTRA_CLEAN += sql/pgtap--1.3.4--1.3.5.sql
sql/pgtap--1.3.4--1.3.5.sql: sql/pgtap--1.3.4--1.3.5.sql.in
cp $< $@
ifeq ($(shell echo $(VERSION) | grep -qE "^9[.][01234]" && echo yes || echo no),yes)
patch -p0 < compat/9.4/pgtap--1.3.4--1.3.5.patch
endif

EXTRA_CLEAN += sql/pgtap--0.99.0--1.0.0.sql
sql/pgtap--0.99.0--1.0.0.sql: sql/pgtap--0.99.0--1.0.0.sql.in
cp $< $@
Expand Down
58 changes: 58 additions & 0 deletions compat/9.4/pgtap--1.3.4--1.3.5.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
--- sql/pgtap--1.3.4--1.3.5.sql
+++ sql/pgtap--1.3.4--1.3.5.sql
@@ -99,55 +99,4 @@
CREATE OR REPLACE FUNCTION hasnt_check ( NAME )
RETURNS TEXT AS $$
SELECT hasnt_check( $1, 'Table ' || quote_ident($1) || ' should not have a check constraint' );
$$ LANGUAGE sql;
-
--- has_rls( schema, table, description )
-CREATE OR REPLACE FUNCTION has_rls( NAME, NAME, TEXT )
-RETURNS TEXT AS $$
- SELECT ok(
- EXISTS(
- SELECT true
- FROM pg_catalog.pg_class c
- JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
- WHERE n.nspname = $1
- AND c.relname = $2
- AND c.relrowsecurity = TRUE
- ),
- $3
- );
-$$ LANGUAGE SQL;
-
--- has_rls( schema, table )
-CREATE OR REPLACE FUNCTION has_rls( NAME, NAME )
-RETURNS TEXT AS $$
- SELECT has_rls(
- $1,
- $2,
- 'Table ' || quote_ident($1) || '.' || quote_ident($2)
- || ' should have row-level security enabled'
- );
-$$ LANGUAGE SQL;
-
--- has_rls( table, description )
-CREATE OR REPLACE FUNCTION has_rls( NAME, TEXT )
-RETURNS TEXT AS $$
- SELECT ok(
- EXISTS(
- SELECT true
- FROM pg_catalog.pg_class c
- WHERE pg_catalog.pg_table_is_visible(c.oid)
- AND c.relname = $1
- AND c.relrowsecurity = TRUE
- ),
- $2
- );
-$$ LANGUAGE SQL;
-
--- has_rls( table )
-CREATE OR REPLACE FUNCTION has_rls( NAME )
-RETURNS TEXT AS $$
- SELECT has_rls(
- $1,
- 'Table ' || quote_ident($1) || ' should have row-level security enabled'
- );
-$$ LANGUAGE SQL;
55 changes: 55 additions & 0 deletions compat/install-9.4.patch
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,58 @@
/******************** INHERITANCE ***********************************************/
/*
* Internal function to test whether the specified table in the specified schema
@@ -11596,54 +11369,3 @@
'Function ' || quote_ident($1) || '() should not be a procedure'
);
$$ LANGUAGE sql;
-
--- has_rls( schema, table, description )
-CREATE OR REPLACE FUNCTION has_rls( NAME, NAME, TEXT )
-RETURNS TEXT AS $$
- SELECT ok(
- EXISTS(
- SELECT true
- FROM pg_catalog.pg_class c
- JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
- WHERE n.nspname = $1
- AND c.relname = $2
- AND c.relrowsecurity = TRUE
- ),
- $3
- );
-$$ LANGUAGE SQL;
-
--- has_rls( schema, table )
-CREATE OR REPLACE FUNCTION has_rls( NAME, NAME )
-RETURNS TEXT AS $$
- SELECT has_rls(
- $1,
- $2,
- 'Table ' || quote_ident($1) || '.' || quote_ident($2)
- || ' should have row-level security enabled'
- );
-$$ LANGUAGE SQL;
-
--- has_rls( table, description )
-CREATE OR REPLACE FUNCTION has_rls( NAME, TEXT )
-RETURNS TEXT AS $$
- SELECT ok(
- EXISTS(
- SELECT true
- FROM pg_catalog.pg_class c
- WHERE pg_catalog.pg_table_is_visible(c.oid)
- AND c.relname = $1
- AND c.relrowsecurity = TRUE
- ),
- $2
- );
-$$ LANGUAGE SQL;
-
--- has_rls( table )
-CREATE OR REPLACE FUNCTION has_rls( NAME )
-RETURNS TEXT AS $$
- SELECT has_rls(
- $1,
- 'Table ' || quote_ident($1) || ' should have row-level security enabled'
- );
-$$ LANGUAGE SQL;
32 changes: 32 additions & 0 deletions doc/pgtap.md
Original file line number Diff line number Diff line change
Expand Up @@ -8794,6 +8794,38 @@ missing policy command, like so:
# have: INSERT
# want: ALL

### `has_rls()` ###

```sql
SELECT has_rls( :schema, :table, :description );
SELECT has_rls( :schema, :table );
SELECT has_rls( :table, :description );
SELECT has_rls( :table );
```

**Parameters**

`:schema`
: Name of a schema in which to find the table.

`:table`
: Name of a table.

`:description`
: A short description of the test.

This function tests whether or not row-level security is enabled for a table.
The first argument is a schema name, the second is a table name, and the third
is the test description. If you omit the schema, the table must be visible in
the search path. Example:

```sql
SELECT has_rls('myschema'::name, 'sometable'::name);
```

If you omit the test description, it will be set to "Table `:table` should
have row-level security enabled".

No Test for the Wicked
======================

Expand Down
51 changes: 51 additions & 0 deletions sql/pgtap--1.3.4--1.3.5.sql → sql/pgtap--1.3.4--1.3.5.sql.in
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,54 @@ CREATE OR REPLACE FUNCTION hasnt_check ( NAME )
RETURNS TEXT AS $$
SELECT hasnt_check( $1, 'Table ' || quote_ident($1) || ' should not have a check constraint' );
$$ LANGUAGE sql;

-- has_rls( schema, table, description )
CREATE OR REPLACE FUNCTION has_rls( NAME, NAME, TEXT )
RETURNS TEXT AS $$
SELECT ok(
EXISTS(
SELECT true
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
WHERE n.nspname = $1
AND c.relname = $2
AND c.relrowsecurity = TRUE
),
$3
);
$$ LANGUAGE SQL;

-- has_rls( schema, table )
CREATE OR REPLACE FUNCTION has_rls( NAME, NAME )
RETURNS TEXT AS $$
SELECT has_rls(
$1,
$2,
'Table ' || quote_ident($1) || '.' || quote_ident($2)
|| ' should have row-level security enabled'
);
$$ LANGUAGE SQL;

-- has_rls( table, description )
CREATE OR REPLACE FUNCTION has_rls( NAME, TEXT )
RETURNS TEXT AS $$
SELECT ok(
EXISTS(
SELECT true
FROM pg_catalog.pg_class c
WHERE pg_catalog.pg_table_is_visible(c.oid)
AND c.relname = $1
AND c.relrowsecurity = TRUE
),
$2
);
$$ LANGUAGE SQL;

-- has_rls( table )
CREATE OR REPLACE FUNCTION has_rls( NAME )
RETURNS TEXT AS $$
SELECT has_rls(
$1,
'Table ' || quote_ident($1) || ' should have row-level security enabled'
);
$$ LANGUAGE SQL;
51 changes: 51 additions & 0 deletions sql/pgtap.sql.in
Original file line number Diff line number Diff line change
Expand Up @@ -11596,3 +11596,54 @@ RETURNS TEXT AS $$
'Function ' || quote_ident($1) || '() should not be a procedure'
);
$$ LANGUAGE sql;

-- has_rls( schema, table, description )
CREATE OR REPLACE FUNCTION has_rls( NAME, NAME, TEXT )
RETURNS TEXT AS $$
SELECT ok(
EXISTS(
SELECT true
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
WHERE n.nspname = $1
AND c.relname = $2
AND c.relrowsecurity = TRUE
),
$3
);
$$ LANGUAGE SQL;

-- has_rls( schema, table )
CREATE OR REPLACE FUNCTION has_rls( NAME, NAME )
RETURNS TEXT AS $$
SELECT has_rls(
$1,
$2,
'Table ' || quote_ident($1) || '.' || quote_ident($2)
|| ' should have row-level security enabled'
);
$$ LANGUAGE SQL;

-- has_rls( table, description )
CREATE OR REPLACE FUNCTION has_rls( NAME, TEXT )
RETURNS TEXT AS $$
SELECT ok(
EXISTS(
SELECT true
FROM pg_catalog.pg_class c
WHERE pg_catalog.pg_table_is_visible(c.oid)
AND c.relname = $1
AND c.relrowsecurity = TRUE
),
$2
);
$$ LANGUAGE SQL;

-- has_rls( table )
CREATE OR REPLACE FUNCTION has_rls( NAME )
RETURNS TEXT AS $$
SELECT has_rls(
$1,
'Table ' || quote_ident($1) || ' should have row-level security enabled'
);
$$ LANGUAGE SQL;
26 changes: 25 additions & 1 deletion test/expected/policy.out
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
\unset ECHO
1..180
1..204
ok 1 - policies_are(schema, table, policies, desc) should pass
ok 2 - policies_are(schema, table, policies, desc) should have the proper description
ok 3 - policies_are(schema, table, policies, desc) should have the proper diagnostics
Expand Down Expand Up @@ -180,3 +180,27 @@ ok 177 - policy_cmd_is(table, policy, command, desc) for ALL should fail should
ok 178 - policy_cmd_is(table, policy, command) for ALL should fail should fail
ok 179 - policy_cmd_is(table, policy, command) for ALL should fail should have the proper description
ok 180 - policy_cmd_is(table, policy, command) for ALL should fail should have the proper diagnostics
ok 181 - has_rls(schema, table, desc) should pass
ok 182 - has_rls(schema, table, desc) should have the proper description
ok 183 - has_rls(schema, table, desc) should have the proper diagnostics
ok 184 - has_rls(schema, table) should pass
ok 185 - has_rls(schema, table) should have the proper description
ok 186 - has_rls(schema, table) should have the proper diagnostics
ok 187 - has_rls(table, desc) should pass
ok 188 - has_rls(table, desc) should have the proper description
ok 189 - has_rls(table, desc) should have the proper diagnostics
ok 190 - has_rls(table) should pass
ok 191 - has_rls(table) should have the proper description
ok 192 - has_rls(table) should have the proper diagnostics
ok 193 - has_rls(schema, table, desc) without RLS should fail
ok 194 - has_rls(schema, table, desc) without RLS should have the proper description
ok 195 - has_rls(schema, table, desc) without RLS should have the proper diagnostics
ok 196 - has_rls(schema, table) without RLS should fail
ok 197 - has_rls(schema, table) without RLS should have the proper description
ok 198 - has_rls(schema, table) without RLS should have the proper diagnostics
ok 199 - has_rls(table, desc) without RLS should fail
ok 200 - has_rls(table, desc) without RLS should have the proper description
ok 201 - has_rls(table, desc) without RLS should have the proper diagnostics
ok 202 - has_rls(table) without RLS should fail
ok 203 - has_rls(table) without RLS should have the proper description
ok 204 - has_rls(table) without RLS should have the proper diagnostics
Loading