Skip to content

WIP policy_is_permissive, policy_is_restrictive #344

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
101 changes: 101 additions & 0 deletions sql/pgtap.sql.in
Original file line number Diff line number Diff line change
Expand Up @@ -10624,6 +10624,107 @@ RETURNS TEXT AS $$
);
$$ LANGUAGE sql;

/*
* Internal function to test whether the specified policy on the specified
* table in the specified schema is permissive (true) or restrictive (false).
*/
CREATE OR REPLACE FUNCTION _permissive( NAME, NAME, NAME )
RETURNS BOOLEAN AS $$
-- restrictive policies did not exist before postgresql 10
SELECT CASE WHEN pg_version_num() >= 100000 THEN pp.polpermissive ELSE TRUE END AS permissive
FROM pg_catalog.pg_policy AS pp
JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid
JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace
WHERE pn.nspname = $1
AND pc.relname = $2
AND pp.polname = $3;
$$ LANGUAGE SQL;

/*
* Internal function to test whether the specified policy on the specified
* table is permissive (true) or restrictive (false).
*/
CREATE OR REPLACE FUNCTION _permissive( NAME, NAME )
RETURNS BOOLEAN AS $$
-- restrictive policies did not exist before postgresql 10
SELECT CASE WHEN pg_version_num() >= 100000 THEN pp.polpermissive ELSE TRUE END AS permissive
FROM pg_catalog.pg_policy AS pp
JOIN pg_catalog.pg_class AS pc ON pc.oid = pp.polrelid
JOIN pg_catalog.pg_namespace AS pn ON pn.oid = pc.relnamespace
WHERE pc.relname = $1
AND pp.polname = $2
AND pn.nspname NOT IN ('pg_catalog', 'information_schema');
$$ LANGUAGE SQL;

-- policy_is_permissive( schema, table, policy, description )
CREATE OR REPLACE FUNCTION policy_is_permissive( NAME, NAME, NAME, text )
RETURNS TEXT AS $$
SELECT ok( _permissive( $1, $2, $3 ), $4 );
$$ LANGUAGE SQL;

-- policy_is_permissive( schema, table, policy )
CREATE OR REPLACE FUNCTION policy_is_permissive( NAME, NAME, NAME )
RETURNS TEXT AS $$
SELECT policy_is_permissive(
$1, $2, $3,
'Policy ' || quote_ident($3)
|| ' for table ' || quote_ident($1) || '.' || quote_ident($2)
|| ' should be permissive, not restrictive'
);
$$ LANGUAGE SQL;

-- policy_is_permissive( table, policy, description )
CREATE OR REPLACE FUNCTION policy_is_permissive( NAME, NAME, text )
RETURNS TEXT AS $$
SELECT ok( _permissive( $1, $2 ), $3 );
$$ LANGUAGE SQL;

-- policy_is_permissive( table, policy )
CREATE OR REPLACE FUNCTION policy_is_permissive( NAME, NAME )
RETURNS TEXT AS $$
SELECT policy_is_permissive(
$1, $2,
'Policy ' || quote_ident($2)
|| ' for table ' || quote_ident($1)
|| ' should be permissive, not restrictive'
);
$$ LANGUAGE SQL;

-- policy_is_restrictive( schema, table, policy, description )
CREATE OR REPLACE FUNCTION policy_is_restrictive( NAME, NAME, NAME, text )
RETURNS TEXT AS $$
SELECT ok( NOT _permissive( $1, $2, $3 ), $4 );
END;
$$ LANGUAGE SQL;

-- policy_is_restrictive( schema, table, policy )
CREATE OR REPLACE FUNCTION policy_is_restrictive( NAME, NAME, NAME )
RETURNS TEXT AS $$
SELECT policy_is_restrictive(
$1, $2, $3,
'Policy ' || quote_ident($3)
|| ' for table ' || quote_ident($1) || '.' || quote_ident($2)
|| ' should be restrictive, not permissive'
);
$$ LANGUAGE SQL;

-- policy_is_restrictive( table, policy, description )
CREATE OR REPLACE FUNCTION policy_is_restrictive( NAME, NAME, text )
RETURNS TEXT AS $$
SELECT ok( NOT _permissive( $1, $2 ), $3 );
$$ LANGUAGE SQL;

-- policy_is_restrictive( table, policy )
CREATE OR REPLACE FUNCTION policy_is_restrictive( NAME, NAME )
RETURNS TEXT AS $$
SELECT policy_is_restrictive(
$1, $2,
'Policy ' || quote_ident($2)
|| ' for table ' || quote_ident($1)
|| ' should be restrictive, not permissive'
);
$$ LANGUAGE SQL;

/******************** INHERITANCE ***********************************************/
/*
* Internal function to test whether the specified table in the specified schema
Expand Down
104 changes: 103 additions & 1 deletion test/sql/policy.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
\unset ECHO
\i test/setup.sql

SELECT plan(180);
SELECT plan(192);
--SELECT * FROM no_plan();

-- This will be rolled back. :-)
Expand Down Expand Up @@ -579,6 +579,108 @@ SELECT * FROM check_test(
want: DELETE'
);

/****************************************************************************/
-- Test policy_is_permissive().

SELECT * FROM check_test(
policy_is_permissive( 'public', 'passwd', 'root_all'::NAME ),
true,
'policy_is_permissive(schema, table, policy)',
'Policy root_all for table public.passwd should be permissive, not restrictive',
''
);

SELECT * FROM check_test(
policy_is_permissive( 'public', 'passwd', 'doesnt_exist'::NAME ),
true,
'policy_is_permissive(schema, table, policy) for nonexistent policy',
'Policy root_all for table public.passwd should be permissive, not restrictive',
'(test result was NULL)'
);

SELECT * FROM check_test(
policy_is_permissive( 'public', 'passwd', 'root_all', 'whatever' ),
true,
'policy_is_permissive(schema, table, policy, desc)',
'whatever',
''
);

SELECT * FROM check_test(
policy_is_permissive( 'passwd', 'root_all' ),
true,
'policy_is_permissive(table, policy)',
'Policy root_all for table passwd should be permissive, not restrictive',
''
);

SELECT * FROM check_test(
policy_is_permissive( 'passwd', 'doesnt_exist' ),
true,
'policy_is_permissive(table, policy) for nonexistent policy',
'Policy root_all for table passwd should be permissive, not restrictive',
'(test result was NULL)'
);

SELECT * FROM check_test(
policy_is_permissive( 'passwd', 'root_all', 'whatever' ),
true,
'policy_is_permissive(table, policy, desc)',
'whatever',
''
);

/****************************************************************************/
-- Test policy_is_restrictive().

SELECT * FROM check_test(
policy_is_restrictive( 'public', 'passwd', 'root_all'::NAME ),
false,
'policy_is_permissive(schema, table, policy)',
'Policy root_all for table public.passwd should be permissive, not restrictive',
''
);

SELECT * FROM check_test(
policy_is_restrictive( 'public', 'passwd', 'doesnt_exist'::NAME ),
false,
'policy_is_permissive(schema, table, policy) for nonexistent policy',
'Policy doesnt_exist for table public.passwd should be permissive, not restrictive',
'(test result was NULL)'
);

SELECT * FROM check_test(
policy_is_restrictive( 'public', 'passwd', 'root_all', 'whatever' ),
false,
'policy_is_permissive(schema, table, policy, desc)',
'whatever',
''
);

SELECT * FROM check_test(
policy_is_restrictive( 'passwd', 'root_all' ),
false,
'policy_is_permissive(table, policy)',
'Policy root_all for table passwd should be permissive, not restrictive',
''
);

SELECT * FROM check_test(
policy_is_restrictive( 'passwd', 'doesnt_exist' ),
false,
'policy_is_permissive(table, policy) for nonexistent policy',
'Policy doesnt_exist for table passwd should be permissive, not restrictive',
'(test result was NULL)'
);

SELECT * FROM check_test(
policy_is_restrictive( 'passwd', 'root_all', 'whatever' ),
false,
'policy_is_permissive(table, policy, desc)',
'whatever',
''
);

/****************************************************************************/
-- Finish the tests and clean up.
SELECT * FROM finish();
Expand Down