diff --git a/doc/release-notes/rl-2611.section.md b/doc/release-notes/rl-2611.section.md index 0de5d13ed18a..aa316b4d774b 100644 --- a/doc/release-notes/rl-2611.section.md +++ b/doc/release-notes/rl-2611.section.md @@ -82,6 +82,8 @@ - `jmtpfs` has been removed due to lack of maintenance and fuse3 support. +- `postgresqlPackages.anonymizer` has been updated from 2.4.1 to 3.2.2. The extension must be dropped and recreated, and masking no longer runs as a superuser. See the [upgrade notes](https://postgresql-anonymizer.readthedocs.io/en/stable/UPGRADE/) for details. + - `landrun` was updated to `0.1.17`, which included breaking changes, reference the [breaking changes](https://github.com/Zouuup/landrun/releases/tag/v0.1.17) section in the `landrun` release notes. - `libgdata` has been removed, as it was archived upstream and relied on the insecure libsoup 2.4. diff --git a/nixos/tests/postgresql/anonymizer.nix b/nixos/tests/postgresql/anonymizer.nix index 4b37a4f8be5d..619e8f8b3cf7 100644 --- a/nixos/tests/postgresql/anonymizer.nix +++ b/nixos/tests/postgresql/anonymizer.nix @@ -19,7 +19,11 @@ let nodes.machine = { pkgs, ... }: { - environment.systemPackages = [ (pkgs.pg-dump-anon.override { postgresql = package; }) ]; + users.users.anon_dumper = { + isSystemUser = true; + group = "anon_dumper"; + }; + users.groups.anon_dumper = { }; services.postgresql = { inherit package; enable = true; @@ -44,6 +48,13 @@ let insert into player(id,name,points) values (2,'Bar',42); security label for anon on column player.name is 'MASKED WITH FUNCTION anon.fake_last_name()'; security label for anon on column player.points is 'MASKED WITH VALUE NULL'; + create role anon_dumper login; + alter role anon_dumper set anon.transparent_dynamic_masking = true; + security label for anon on role anon_dumper is 'MASKED'; + grant pg_read_all_data to anon_dumper; + create role player_owner; + alter table player owner to player_owner; + grant select on table anon.last_name to player_owner; ''}" ) @@ -54,20 +65,18 @@ let def check_anonymized_row(row, id, original_name): t.assertEqual(row[0], id) - t.assertNotEqual(row[1], original_name) - t.assertFalse(bool(row[2])) + t.assertNotIn(row[1], (original_name, "", "\\N")) + t.assertIn(row[2], ("", "\\N")) def find_xsv_in_dump(dump, sep=','): """ - Expecting to find a CSV (for pg_dump_anon) or TSV (for pg_dump) structure, looking like + Expecting to find pg_dump's COPY block, looking like COPY public.player ... - 1,Shields, - 2,Salazar, + \\. - in the given dump (the commas are tabs in case of pg_dump). - Extract the CSV lines and split by `sep`. + in the given dump. Extract the data lines and split by `sep`. """ try: @@ -100,12 +109,13 @@ let sep='\t' )) check_anonymized_rows(find_xsv_in_dump( - machine.succeed("sudo -u postgres pg_dump_anon -U postgres -h /run/postgresql -d demo"), - sep=',' + machine.succeed("sudo -u anon_dumper pg_dump demo --no-security-labels --extension plpgsql"), + sep='\t' )) with subtest("Anonymize"): - machine.succeed("sudo -u postgres psql -d demo --command 'select anon.anonymize_database();'") + # anon.nosuperuser forbids masking as a superuser + machine.succeed("sudo -u postgres psql -d demo --command 'set role player_owner; select anon.anonymize_database();'") check_anonymized_rows(get_player_table_contents()) ''; } diff --git a/pkgs/servers/sql/postgresql/ext/anonymizer.nix b/pkgs/servers/sql/postgresql/ext/anonymizer.nix index 84800cb5635a..66cb792244e8 100644 --- a/pkgs/servers/sql/postgresql/ext/anonymizer.nix +++ b/pkgs/servers/sql/postgresql/ext/anonymizer.nix @@ -1,30 +1,59 @@ { - cargo-pgrx_0_16_0, + cargo-pgrx_0_19_0, + fetchFromGitLab, jitSupport, lib, nixosTests, - pg-dump-anon, + nix-update-script, postgresql, buildPgrxExtension, runtimeShell, }: -buildPgrxExtension { +buildPgrxExtension (finalAttrs: { pname = "postgresql_anonymizer"; + version = "3.2.2"; - inherit (pg-dump-anon) version src; + src = fetchFromGitLab { + owner = "dalibo"; + repo = "postgresql_anonymizer"; + tag = finalAttrs.version; + hash = "sha256-no457Cb6SC6ji1iUbRARP9xESgWERjy8OTtGk8hzmrU="; + }; inherit postgresql; - cargo-pgrx = cargo-pgrx_0_16_0; - cargoHash = "sha256-Z1uH6Z2qLV1Axr8dXqPznuEZcacAZnv11tb3lWBh1yw="; + cargo-pgrx = cargo-pgrx_0_19_0; + cargoHash = "sha256-xQvBdLfxnPw+lvCM+sepfUyGyGK8WI+6kqk4DVY7+s8="; # Tries to copy extension into postgresql's store path. doCheck = false; - passthru.tests = nixosTests.postgresql.anonymizer.passthru.override postgresql; + # the pg_config view is empty in nixpkgs, so anon.init() cannot locate its data + postPatch = '' + substituteInPlace sql/init.sql \ + --replace-fail "SELECT setting AS sharedir" "SELECT '$out/share/postgresql' AS sharedir" \ + --replace-fail "FROM pg_catalog.pg_config" "" \ + --replace-fail "WHERE name = 'SHAREDIR'" "" + ''; + + # data loaded by anon.init(), installed by upstream's Makefile + postInstall = '' + install -Dm644 -t $out/share/postgresql/extension/anon data/*.csv data/en_US/fake/*.csv + ''; + + passthru = { + tests = nixosTests.postgresql.anonymizer.passthru.override postgresql; + updateScript = nix-update-script { }; + }; meta = { - inherit (pg-dump-anon.meta) homepage maintainers license; description = "Extension to mask or replace personally identifiable information (PII) or commercially sensitive data from a PostgreSQL database"; + homepage = "https://postgresql-anonymizer.readthedocs.io/en/stable/"; + changelog = "https://gitlab.com/dalibo/postgresql_anonymizer/-/blob/${finalAttrs.version}/CHANGELOG.md"; + maintainers = with lib.maintainers; [ + leona + osnyx + ]; + license = lib.licenses.postgresql; }; -} +})