Tamanu is an open-source patient-level electronic health records system for mobile and desktop.
The Meta service provides:
- a server discovery service for the Tamanu mobile app
- a server list and health check page
- a range of active versions
- download URLs to available artifacts for active versions
We have a container image for linux/amd64 and linux/arm64:
ghcr.io/beyondessential/tamanu-meta:4.2.7
The public_server
binary serves the public API and views, which are expected to be exposed to
the internet (in production behind an ingress gateway or reverse proxy).
Routes marked with π require authentication; the word in (parens) after the emoji is the required role
; admin
role can do everything.
The mtls-certificate
(or ssl-client-cert
) header should contain a PEM-encoded (optionally URL-encoded) X509 certificate.
To get a certificate, run:
$ cargo run --bin identity
Which will write the identity.crt.pem
and identity.key.pem
.
You can then put it in an environment variable:
$ export MTLS_CERT="$(jq -sRr @uri identity.crt.pem)"
and then use curl like:
$ curl -H "mtls-certificate: $MTLS_CERT" ...
When you first connect to an authenticated API with a certificate, you'll get a 403.
Your public key will be added to the devices
table.
Open the database, e.g. with PSQL, and change the role to admin
(or as required).
UPDATE devices SET role = 'admin' WHERE id = '45886aa8-dff3-4cf7-92a9-31f42d4a0e1a';
In production, you need to do extra checks.
- Show untrusted devices with their public key in PEM-ish format:
SELECT id, created_at, encode(key_data, 'base64') as pem
FROM devices WHERE role = 'untrusted'
ORDER BY created_at DESC \gx
- Compare the provided public key to the list to find the right
id
. You can also filter by the last few characters of the key (the first characters will all be the same):
SELECT id, created_at, encode(key_data, 'base64') as pem
FROM devices WHERE role = 'untrusted'
AND encode(key_data, 'base64') LIKE '%NWwjGDiHVWrBA=='
ORDER BY created_at DESC \gx
- Once you have the
id
, look at the connection metadata to see if it matches what you know for additional verification:
SELECT * FROM device_connections
WHERE id = '45886aa8-dff3-4cf7-92a9-31f42d4a0e1a'
ORDER BY created_at DESC \gx
In production, the header should be set from a client certificate, as terminated by a reverse proxy or load balancer, and any matching header on the incoming requests should be stripped.
- Nginx: use the
$ssl_client_escaped_cert
variable. - Caddy: use the
{http.request.tls.client.certificate_pem}
placeholder.
Get the full list of servers as JSON.
[
{
"id":"8960470f-5282-496e-86f5-21df8cf67d62",
"name":"Dev (main)",
"host":"https://central.main.internal.tamanu.io/",
"rank":"dev"
}
]
Add a server to the list.
Pass a JSON body:
{
"name":"Dev (main)",
"host":"https://central.main.internal.tamanu.io/",
"rank":"dev"
}
Returns the server with its assigned ID:
{
"id":"8960470f-5282-496e-86f5-21df8cf67d62",
"name":"Dev (main)",
"host":"https://central.main.internal.tamanu.io/",
"rank":"dev"
}
Edit a server.
Pass a JSON body, all fields optional except for id
:
{
"id":"8960470f-5282-496e-86f5-21df8cf67d62",
"name":"Test server (main)"
}
Returns the edited server with its assigned ID:
{
"id":"8960470f-5282-496e-86f5-21df8cf67d62",
"name":"Test server (main)",
"host":"https://central.main.internal.tamanu.io/",
"rank":"dev"
}
There's a "hidden" feature in the UI where if you Shift-click a row, it will copy its ID to the clipboard.
Remove a server from the list.
Pass a JSON body with the id
field:
{
"id":"8960470f-5282-496e-86f5-21df8cf67d62"
}
Get a list of known Tamanu versions in JSON.
[
{
"id": "967c7d15-7046-459e-a448-6584f72e55ce",
"major": 2,
"minor": 27,
"patch": 0,
"published": true,
"changelog": "..."
},
// ...
]
Create the version <version>
(must be a semver version string).
Pass the changelog as the body (if using curl, use --data-binary
to preserve whitespace):
Blah
blah
blah
Returns the version with its assigned ID:
{
"id": "967c7d15-7046-459e-a448-6584f72e55ce",
"major": 2,
"minor": 27,
"patch": 0,
"published": true,
"changelog": "..."
}
TO BE DOCUMENTED
TO BE DOCUMENTED
TO BE DOCUMENTED
The private_server
binary serves the private API and views: it must not be exposed to the
internet (at BES we run it within our Tailscale network). By default this is served at the /$
prefix, but that can be changed with the --prefix
option.
Force a reload of the statuses.
- Install Rustup, which will install Rust and Cargo.
- Install the diesel CLI tool: https://diesel.rs/guides/getting-started.html#installing-diesel-cli
- Clone the repo via git:
$ git clone [email protected]:beyondessential/tamanu-meta-server.git
- Build the project:
$ cargo check
-
Create a new blank postgres database.
-
Set the
DATABASE_URL
environment variable. You can do that per diesel command, or for your entire shell session usingexport
(orset -x
in fish, or$env:DATABASE_URL =
in powershell) as usual for your preferred shell. -
Run migrations:
$ diesel migration run
- Run with:
$ cargo run
- Tests:
$ cargo test
We recommend using Rust Analyzer or Rust Rover for development.
- Create a migration
$ diesel migration generate some_name_here
-
Write the migration's
up.sql
anddown.sql
-
Run the pending migrations:
$ diesel migration run
- Test your down:
$ diesel migration redo
- Run formatter:
$ cargo fmt
(You need write access to the main branch directly)
On the main branch:
$ cargo release --execute minor // or patch, major
Install cargo-release
with:
$ cargo install cargo-release
Also install git-cliff
:
$ cargo install git-cliff