diff --git a/bin/installcheck b/bin/installcheck index f3e887c..2d78838 100755 --- a/bin/installcheck +++ b/bin/installcheck @@ -52,7 +52,7 @@ else fi # Execute the test fixtures -psql -v ON_ERROR_STOP= -f test/fixtures.sql -f lints/0001*.sql -f lints/0002*.sql -f lints/0003*.sql -f lints/0004*.sql -f lints/0005*.sql -f lints/0006*.sql -f lints/0007*.sql -f lints/0008*.sql -f lints/0009*.sql -f lints/0010*.sql -f lints/0011*.sql -f lints/0013*.sql -f lints/0014*.sql -f lints/0015*.sql -f lints/0016*.sql -f lints/0017*.sql -f lints/0018*.sql -f lints/0019*.sql -f lints/0020*.sql -f lints/0021*.sql -d contrib_regression +psql -v ON_ERROR_STOP= -f test/fixtures.sql -f lints/0001*.sql -f lints/0002*.sql -f lints/0003*.sql -f lints/0004*.sql -f lints/0005*.sql -f lints/0006*.sql -f lints/0007*.sql -f lints/0008*.sql -f lints/0009*.sql -f lints/0010*.sql -f lints/0011*.sql -f lints/0013*.sql -f lints/0014*.sql -f lints/0015*.sql -f lints/0016*.sql -f lints/0017*.sql -f lints/0018*.sql -f lints/0019*.sql -f lints/0020*.sql -f lints/0021*.sql -f lints/0022*.sql -d contrib_regression # Run tests ${REGRESS} --use-existing --dbname=contrib_regression --inputdir=${TESTDIR} ${TESTS} diff --git a/docs/0022_extension_versions_outdated.md b/docs/0022_extension_versions_outdated.md new file mode 100644 index 0000000..5eaf0e0 --- /dev/null +++ b/docs/0022_extension_versions_outdated.md @@ -0,0 +1,74 @@ +Level: WARN + +### Rationale + +Keeping PostgreSQL extensions up to date is important for maintaining database security and stability. Extension developers regularly release updates that include: + +- **Security patches** that fix known vulnerabilities +- **Bug fixes** that resolve functional issues +- **Performance improvements** that optimize database operations + +Using outdated extension versions can expose your database to security risks and prevent you from benefiting from the latest improvements. Additionally, Supabase's Service Level Agreement (SLA) for issues resulting from extensions only applies to the default (recommended) version of each extension. + +### Why Keep Extensions Updated? + +**Security**: Outdated extensions may contain known security vulnerabilities that have been patched in newer versions. These vulnerabilities could potentially be exploited by malicious actors. + +**Support**: Supabase provides support and SLA coverage only for the default (recommended) versions of extensions. Running outdated versions may result in limited support options if issues arise. + +**Consistency**: Maintaining consistent extension versions across all projects helps ensure predictable behavior and reduces compatibility issues. + +**Performance**: Newer versions frequently include performance optimizations and improvements that can benefit your database operations. + +### Warning + +- Always test extension updates in a development environment before applying them to production +- Some extension updates may include breaking changes, so review the extension's changelog before updating +- Back up your database before performing extension updates + +### How to Resolve + +To update an extension to its default (recommended) version, use the `ALTER EXTENSION` command: + +```sql +ALTER EXTENSION extension_name UPDATE; +``` + +For example, to update the `uuid-ossp` extension: + +First, check the version of the extension taht is installed: + +```sql +-- Check current extension version +SELECT name, installed_version, default_version +FROM pg_available_extensions +WHERE name = 'uuid-ossp'; +``` + +This could return: +``` + name | installed_version | default_version +-------------+-------------------+----------------- + uuid-ossp | 1.0 | 1.1 +``` + +To update to the installed version: + +```sql +ALTER EXTENSION "uuid-ossp" UPDATE; +``` + +After updating, verify the installed version matches default: + +```sql +SELECT name, installed_version, default_version +FROM pg_available_extensions +WHERE name = 'uuid-ossp'; +``` + +Should now return: +``` + name | installed_version | default_version +-------------+-------------------+----------------- + uuid-ossp | 1.1 | 1.1 +``` \ No newline at end of file diff --git a/lints/0022_extension_versions_outdated.sql b/lints/0022_extension_versions_outdated.sql new file mode 100644 index 0000000..9c098f2 --- /dev/null +++ b/lints/0022_extension_versions_outdated.sql @@ -0,0 +1,34 @@ +create view lint."0022_extension_versions_outdated" as + +select + 'extension_versions_outdated' as name, + 'Extension Versions Outdated' as title, + 'WARN' as level, + 'EXTERNAL' as facing, + array['SECURITY'] as categories, + 'Detects extensions that are not using the default (recommended) version.' as description, + format( + 'Extension `%s` is using version `%s` but version `%s` is available. Using outdated extension versions may expose the database to security vulnerabilities.', + ext.name, + ext.installed_version, + ext.default_version + ) as detail, + 'https://supabase.com/docs/guides/database/database-linter?lint=0022_extension_versions_outdated' as remediation, + jsonb_build_object( + 'extension_name', ext.name, + 'installed_version', ext.installed_version, + 'default_version', ext.default_version + ) as metadata, + format( + 'extension_versions_outdated_%s_%s', + ext.name, + ext.installed_version + ) as cache_key +from + pg_catalog.pg_available_extensions ext +where + ext.installed_version is not null + and ext.default_version is not null + and ext.installed_version != ext.default_version +order by + ext.name; \ No newline at end of file diff --git a/splinter.sql b/splinter.sql index 73ee7ef..d65c5eb 100644 --- a/splinter.sql +++ b/splinter.sql @@ -1108,4 +1108,38 @@ from where c.contype = 'f' and cn.nspname = 'auth' and i.indisunique - and not i.indisprimary) \ No newline at end of file + and not i.indisprimary) +union all +( +select + 'extension_versions_outdated' as name, + 'Extension Versions Outdated' as title, + 'WARN' as level, + 'EXTERNAL' as facing, + array['SECURITY'] as categories, + 'Detects extensions that are not using the default (recommended) version.' as description, + format( + 'Extension `%s` is using version `%s` but version `%s` is available. Using outdated extension versions may expose the database to security vulnerabilities.', + ext.name, + ext.installed_version, + ext.default_version + ) as detail, + 'https://supabase.com/docs/guides/database/database-linter?lint=0022_extension_versions_outdated' as remediation, + jsonb_build_object( + 'extension_name', ext.name, + 'installed_version', ext.installed_version, + 'default_version', ext.default_version + ) as metadata, + format( + 'extension_versions_outdated_%s_%s', + ext.name, + ext.installed_version + ) as cache_key +from + pg_catalog.pg_available_extensions ext +where + ext.installed_version is not null + and ext.default_version is not null + and ext.installed_version != ext.default_version +order by + ext.name) \ No newline at end of file diff --git a/test/expected/0022_extension_versions_outdated.out b/test/expected/0022_extension_versions_outdated.out new file mode 100644 index 0000000..4fcfedd --- /dev/null +++ b/test/expected/0022_extension_versions_outdated.out @@ -0,0 +1,41 @@ +begin; + -- 0 issues initially (all extensions should be up to date) + select * from lint."0022_extension_versions_outdated"; + name | title | level | facing | categories | description | detail | remediation | metadata | cache_key +------+-------+-------+--------+------------+-------------+--------+-------------+----------+----------- +(0 rows) + + -- Note: We cannot easily create a test that shows outdated extensions + -- because we cannot install older versions of extensions in a test environment. + -- Our test image doesn't have multiple extension versions available. + -- The test will primarily verify that the query executes without error + -- and returns the expected column structure. + -- This lint was tested manually with real outdated extensions. + -- Verify the query structure and column names + select + count(*) as total_outdated_extensions + from lint."0022_extension_versions_outdated"; + total_outdated_extensions +--------------------------- + 0 +(1 row) + + -- Test that the query returns proper column structure + -- This will help ensure the lint is properly formed + select + name, + title, + level, + facing, + categories, + description, + detail, + remediation, + metadata, + cache_key + from lint."0022_extension_versions_outdated"; + name | title | level | facing | categories | description | detail | remediation | metadata | cache_key +------+-------+-------+--------+------------+-------------+--------+-------------+----------+----------- +(0 rows) + +rollback; diff --git a/test/expected/queries_are_unionable.out b/test/expected/queries_are_unionable.out index cc2f33b..cf0e50e 100644 --- a/test/expected/queries_are_unionable.out +++ b/test/expected/queries_are_unionable.out @@ -36,7 +36,11 @@ begin; union all select * from lint."0019_insecure_queue_exposed_in_api" union all - select * from lint."0020_table_bloat"; + select * from lint."0020_table_bloat" + union all + select * from lint."0021_fkey_to_auth_unique" + union all + select * from lint."0022_extension_versions_outdated"; name | title | level | facing | categories | description | detail | remediation | metadata | cache_key ------+-------+-------+--------+------------+-------------+--------+-------------+----------+----------- (0 rows) diff --git a/test/sql/0022_extension_versions_outdated.sql b/test/sql/0022_extension_versions_outdated.sql new file mode 100644 index 0000000..1297d95 --- /dev/null +++ b/test/sql/0022_extension_versions_outdated.sql @@ -0,0 +1,33 @@ +begin; + + -- 0 issues initially (all extensions should be up to date) + select * from lint."0022_extension_versions_outdated"; + + -- Note: We cannot easily create a test that shows outdated extensions + -- because we cannot install older versions of extensions in a test environment. + -- Our test image doesn't have multiple extension versions available. + -- The test will primarily verify that the query executes without error + -- and returns the expected column structure. + -- This lint was tested manually with real outdated extensions. + + -- Verify the query structure and column names + select + count(*) as total_outdated_extensions + from lint."0022_extension_versions_outdated"; + + -- Test that the query returns proper column structure + -- This will help ensure the lint is properly formed + select + name, + title, + level, + facing, + categories, + description, + detail, + remediation, + metadata, + cache_key + from lint."0022_extension_versions_outdated"; + +rollback; \ No newline at end of file diff --git a/test/sql/queries_are_unionable.sql b/test/sql/queries_are_unionable.sql index 87d091e..fadfda1 100644 --- a/test/sql/queries_are_unionable.sql +++ b/test/sql/queries_are_unionable.sql @@ -38,6 +38,10 @@ begin; union all select * from lint."0019_insecure_queue_exposed_in_api" union all - select * from lint."0020_table_bloat"; + select * from lint."0020_table_bloat" + union all + select * from lint."0021_fkey_to_auth_unique" + union all + select * from lint."0022_extension_versions_outdated"; rollback;