Orthanc can be installed using GNU Guix

Hello Sebastien and team

I’m posting to let you know that Orthanc can now be installed using GNU Guix (#476 - gnu: Add orthanc. - guix/guix - Codeberg.org). There’s also a PR to add the alternative database plugins (#480 - Add database plugins for Orthanc. - guix/guix - Codeberg.org).

I want to share a couple of minor issues that I found with the build system, in case it is useful to you.

  1. With Orthanc version 1.12.7, when passing the CMake flag “-DENABLE_GOOGLE_TEST=OFF”, googletest is still required and ‘UnitTests’ is still built.
  2. For the PostgreSQL plugin version 7.2, the UnitTests program takes the username as a command line argument, but the tests seem to fail with any username other than ‘postgres’. Is this expected?

Thank you for Orthanc.

All the best
Jake

1 Like

Dear Jake,

Thanks for this great news about GNU Guix packaging!

Regarding your question about unit tests, ENABLE_GOOGLE_TEST is an internal variable that is used to resolve dependencies in CMake. In Orthanc <= 1.12.8, there is no way to disable the building of the unit tests, as we felt like this could raise software quality concerns. That being said, I have just added a new -DBUILD_UNIT_TESTS=OFF option that can be passed to CMake, which will effectively disable the detection of Google Test and the building of unit tests (not recommended, thus). This option will be part of Orthanc 1.12.9.

Regarding the PostgreSQL plugin, I can confirm that the username is well taken into consideration by the unit tests. Would you be concerned about the following error if using another user than the default postgres user?

E0709 08:43:58.934753     78523e22fa00 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  permission denied for table pg_largeobject

If so, this indicates an issue with the permissions of large objects. Note that large objects are only used in the PostgreSQL storage area plugin (not the PostgreSQL index plugin). There is a whole literature about the security of large objects in PostgreSQL (check out discussions related to lo_compat_privileges). The easiest solution to get around this permission issue is to grant the “superuser” privilege to your PostgreSQL user, for instance using the command line:

$ sudo -i -u postgres psql -c "ALTER ROLE jodogne WITH SUPERUSER"

Kind Regards,
Sébastien-

Hi Sébastien

I have just added a new -DBUILD_UNIT_TESTS=OFF option

I think that’s nice to have. For what it’s worth, the Guix package does run the UnitTests binary as part of the package build, and all tests pass.

I can confirm that the username is well taken into consideration by the unit tests.

I’m not sure what you mean. At the end of this message, I’ll paste the error I get when I pass a username other than ‘postgres’ to the UnitTests binary.

Would you be concerned about the following error if using another user than the default postgres user?

With how I run the tests (see below), I find that permission to manage Large Objects is required even with the username postgres. Indeed, I had already employed that ‘ALTER ROLE’ command to get the tests to pass.

The following (Scheme) code shows everything we do to successfully run the test suite for orthanc-postgresql after the package is built, while still in Guix’s isolated build environment:

(let ((pgdata "/tmp/pgdata")
      (host "/tmp")
      (port "5432")
      ;; This username is hard-coded in tests.
      (username "postgres")
      (password "")
      (database "orthanctest"))
  (invoke "initdb" pgdata)
  (invoke "pg_ctl" "-D" pgdata "-o" (string-append "-k " host) "start")
  (invoke "createdb" "-h" host database)
  (invoke "createuser" "-h" host username)
  ;; The tests include managing Large Objects.
  (invoke "psql" "-h" host "-d" database "-c"
          (string-append "ALTER ROLE " username " WITH SUPERUSER;"))
  (invoke "./UnitTests" host port username password database))

This translates to the following commands being ran:

initdb /tmp/pgdata
pg_ctl -D /tmp/pgdata -o "-k /tmp" start
createdb -h /tmp orthanctest
createuser -h /tmp postgres
psql -h /tmp -d orthanctest -c "ALTER ROLE postgres WITH SUPERUSER;"
./UnitTests /tmp 5432 postgres "" orthanctest

In the above code, if we change the username from ‘postgres’ to anything else, 11 tests now fail. Here is the relevant part of the build log:

starting phase `check'
The files belonging to this database system will be owned by user "nixbld".
This user must also own the server process.

The database cluster will be initialized with locale "C.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".

Data page checksums are disabled.

creating directory /tmp/pgdata ... ok
creating subdirectories ... ok
selecting dynamic shared memory implementation ... posix
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default time zone ... UTC
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... 2025-07-10 11:57:59.427 UTC [1102] WARNING:  no usable system locales were found
ok
syncing data to disk ... ok

initdb: warning: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    pg_ctl -D /tmp/pgdata -l logfile start

waiting for server to start....2025-07-10 11:58:00.110 UTC [1106] LOG:  starting PostgreSQL 14.13 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 11.4.0, 64-bit
2025-07-10 11:58:00.110 UTC [1106] LOG:  listening on IPv4 address "127.0.0.1", port 5432
2025-07-10 11:58:00.120 UTC [1106] LOG:  listening on Unix socket "/tmp/.s.PGSQL.5432"
2025-07-10 11:58:00.136 UTC [1107] LOG:  database system was shut down at 2025-07-10 11:57:59 UTC
2025-07-10 11:58:00.144 UTC [1106] LOG:  database system is ready to accept connections
 done
server started
ALTER ROLE
[==========] Running 12 tests from 4 test suites.
[----------] Global test environment set-up.
[----------] 8 tests from PostgreSQL
[ RUN      ] PostgreSQL.Basic
2025-07-10 11:58:00.645 UTC [1121] ERROR:  role "postgres" does not exist
2025-07-10 11:58:00.645 UTC [1121] STATEMENT:  GRANT ALL ON SCHEMA public TO postgres;
E0710 11:58:00.645172     7ffff7a2d7c0 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  role "postgres" does not exist

I0710 11:58:00.648238     7ffff7a2d7c0 PostgreSQLTransaction.cpp:47] PostgreSQL: An active PostgreSQL transaction was dismissed
I0710 11:58:00.648314     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
unknown file: Failure
Unknown C++ exception thrown in the test body.
[  FAILED  ] PostgreSQL.Basic (8 ms)
[ RUN      ] PostgreSQL.String
2025-07-10 11:58:00.652 UTC [1122] ERROR:  role "postgres" does not exist
2025-07-10 11:58:00.652 UTC [1122] STATEMENT:  GRANT ALL ON SCHEMA public TO postgres;
E0710 11:58:00.652443     7ffff7a2d7c0 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  role "postgres" does not exist

I0710 11:58:00.652488     7ffff7a2d7c0 PostgreSQLTransaction.cpp:47] PostgreSQL: An active PostgreSQL transaction was dismissed
I0710 11:58:00.652537     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
unknown file: Failure
Unknown C++ exception thrown in the test body.
[  FAILED  ] PostgreSQL.String (4 ms)
[ RUN      ] PostgreSQL.Transaction
2025-07-10 11:58:00.656 UTC [1123] ERROR:  role "postgres" does not exist
2025-07-10 11:58:00.656 UTC [1123] STATEMENT:  GRANT ALL ON SCHEMA public TO postgres;
E0710 11:58:00.657025     7ffff7a2d7c0 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  role "postgres" does not exist

I0710 11:58:00.657061     7ffff7a2d7c0 PostgreSQLTransaction.cpp:47] PostgreSQL: An active PostgreSQL transaction was dismissed
I0710 11:58:00.657089     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
unknown file: Failure
Unknown C++ exception thrown in the test body.
[  FAILED  ] PostgreSQL.Transaction (4 ms)
[ RUN      ] PostgreSQL.LargeObject
2025-07-10 11:58:00.660 UTC [1124] ERROR:  role "postgres" does not exist
2025-07-10 11:58:00.660 UTC [1124] STATEMENT:  GRANT ALL ON SCHEMA public TO postgres;
E0710 11:58:00.660621     7ffff7a2d7c0 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  role "postgres" does not exist

I0710 11:58:00.660670     7ffff7a2d7c0 PostgreSQLTransaction.cpp:47] PostgreSQL: An active PostgreSQL transaction was dismissed
I0710 11:58:00.660710     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
unknown file: Failure
Unknown C++ exception thrown in the test body.
[  FAILED  ] PostgreSQL.LargeObject (3 ms)
[ RUN      ] PostgreSQL.StorageArea
2025-07-10 11:58:00.668 UTC [1126] ERROR:  role "postgres" does not exist
2025-07-10 11:58:00.668 UTC [1126] STATEMENT:  GRANT ALL ON SCHEMA public TO postgres;
E0710 11:58:00.668152     7ffff7a2d7c0 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  role "postgres" does not exist

I0710 11:58:00.668225     7ffff7a2d7c0 PostgreSQLTransaction.cpp:47] PostgreSQL: An active PostgreSQL transaction was dismissed
I0710 11:58:00.668542     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
I0710 11:58:00.668584     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
unknown file: Failure
Unknown C++ exception thrown in the test body.
[  FAILED  ] PostgreSQL.StorageArea (7 ms)
[ RUN      ] PostgreSQL.StorageReadRange
2025-07-10 11:58:00.677 UTC [1128] ERROR:  role "postgres" does not exist
2025-07-10 11:58:00.677 UTC [1128] STATEMENT:  GRANT ALL ON SCHEMA public TO postgres;
E0710 11:58:00.677164     7ffff7a2d7c0 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  role "postgres" does not exist

I0710 11:58:00.677238     7ffff7a2d7c0 PostgreSQLTransaction.cpp:47] PostgreSQL: An active PostgreSQL transaction was dismissed
I0710 11:58:00.677619     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
I0710 11:58:00.677663     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
unknown file: Failure
Unknown C++ exception thrown in the test body.
[  FAILED  ] PostgreSQL.StorageReadRange (9 ms)
[ RUN      ] PostgreSQL.ImplicitTransaction
2025-07-10 11:58:00.682 UTC [1129] ERROR:  role "postgres" does not exist
2025-07-10 11:58:00.682 UTC [1129] STATEMENT:  GRANT ALL ON SCHEMA public TO postgres;
E0710 11:58:00.682203     7ffff7a2d7c0 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  role "postgres" does not exist

I0710 11:58:00.682253     7ffff7a2d7c0 PostgreSQLTransaction.cpp:47] PostgreSQL: An active PostgreSQL transaction was dismissed
I0710 11:58:00.682295     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
unknown file: Failure
Unknown C++ exception thrown in the test body.
[  FAILED  ] PostgreSQL.ImplicitTransaction (4 ms)
[ RUN      ] PostgreSQL.Lock2
2025-07-10 11:58:00.686 UTC [1130] ERROR:  role "postgres" does not exist
2025-07-10 11:58:00.686 UTC [1130] STATEMENT:  GRANT ALL ON SCHEMA public TO postgres;
E0710 11:58:00.686206     7ffff7a2d7c0 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  role "postgres" does not exist

I0710 11:58:00.686262     7ffff7a2d7c0 PostgreSQLTransaction.cpp:47] PostgreSQL: An active PostgreSQL transaction was dismissed
I0710 11:58:00.686302     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
unknown file: Failure
Unknown C++ exception thrown in the test body.
[  FAILED  ] PostgreSQL.Lock2 (4 ms)
[----------] 8 tests from PostgreSQL (46 ms total)

[----------] 2 tests from PostgreSQLIndex
[ RUN      ] PostgreSQLIndex.CreateInstance
2025-07-10 11:58:00.689 UTC [1131] ERROR:  role "postgres" does not exist
2025-07-10 11:58:00.689 UTC [1131] STATEMENT:  GRANT ALL ON SCHEMA public TO postgres;
E0710 11:58:00.690022     7ffff7a2d7c0 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  role "postgres" does not exist

I0710 11:58:00.690092     7ffff7a2d7c0 PostgreSQLTransaction.cpp:47] PostgreSQL: An active PostgreSQL transaction was dismissed
I0710 11:58:00.690384     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
unknown file: Failure
Unknown C++ exception thrown in the test body.
[  FAILED  ] PostgreSQLIndex.CreateInstance (4 ms)
[ RUN      ] PostgreSQLIndex.Lock
2025-07-10 11:58:00.694 UTC [1132] ERROR:  role "postgres" does not exist
2025-07-10 11:58:00.694 UTC [1132] STATEMENT:  GRANT ALL ON SCHEMA public TO postgres;
E0710 11:58:00.694654     7ffff7a2d7c0 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  role "postgres" does not exist

I0710 11:58:00.694711     7ffff7a2d7c0 PostgreSQLTransaction.cpp:47] PostgreSQL: An active PostgreSQL transaction was dismissed
I0710 11:58:00.695074     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
unknown file: Failure
Unknown C++ exception thrown in the test body.
[  FAILED  ] PostgreSQLIndex.Lock (4 ms)
[----------] 2 tests from PostgreSQLIndex (8 ms total)

[----------] 1 test from IndexBackend
[ RUN      ] IndexBackend.Basic
2025-07-10 11:58:00.700 UTC [1133] ERROR:  role "postgres" does not exist
2025-07-10 11:58:00.700 UTC [1133] STATEMENT:  GRANT ALL ON SCHEMA public TO postgres;
E0710 11:58:00.700166     7ffff7a2d7c0 PostgreSQLDatabase.cpp:187] PostgreSQL error: ERROR:  role "postgres" does not exist

I0710 11:58:00.700211     7ffff7a2d7c0 PostgreSQLTransaction.cpp:47] PostgreSQL: An active PostgreSQL transaction was dismissed
I0710 11:58:00.700493     7ffff7a2d7c0 PostgreSQLDatabase.cpp:66] Closing connection to PostgreSQL
unknown file: Failure
Unknown C++ exception thrown in the test body.
[  FAILED  ] IndexBackend.Basic (5 ms)
[----------] 1 test from IndexBackend (5 ms total)

[----------] 1 test from PostgreSQLParameters
[ RUN      ] PostgreSQLParameters.Basic
[       OK ] PostgreSQLParameters.Basic (0 ms)
[----------] 1 test from PostgreSQLParameters (0 ms total)

[----------] Global test environment tear-down
[==========] 12 tests from 4 test suites ran. (61 ms total)
[  PASSED  ] 1 test.
[  FAILED  ] 11 tests, listed below:
[  FAILED  ] PostgreSQL.Basic
[  FAILED  ] PostgreSQL.String
[  FAILED  ] PostgreSQL.Transaction
[  FAILED  ] PostgreSQL.LargeObject
[  FAILED  ] PostgreSQL.StorageArea
[  FAILED  ] PostgreSQL.StorageReadRange
[  FAILED  ] PostgreSQL.ImplicitTransaction
[  FAILED  ] PostgreSQL.Lock2
[  FAILED  ] PostgreSQLIndex.CreateInstance
[  FAILED  ] PostgreSQLIndex.Lock
[  FAILED  ] IndexBackend.Basic

11 FAILED TESTS

I want to emphasise that it is not really a problem that the tests require the username to be ‘postgres’. It was just surprising – I assumed that it would not be restricted because it was a command line argument.

Kind regards
Jake