diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml
index ff8f0e6d2..fd1781d62 100644
--- a/.github/workflows/shellcheck.yml
+++ b/.github/workflows/shellcheck.yml
@@ -7,6 +7,7 @@ on:
- "!main" # excludes main
paths:
- "**.sh"
+ - "tools/sda-admin"
jobs:
shelcheck:
diff --git a/rabbitmq/docker-entrypoint.sh b/rabbitmq/docker-entrypoint.sh
index 6a2180cfc..0367a99fd 100644
--- a/rabbitmq/docker-entrypoint.sh
+++ b/rabbitmq/docker-entrypoint.sh
@@ -31,13 +31,14 @@ if [ -e "${RABBITMQ_SERVER_CERT}" ] && [ -e "${RABBITMQ_SERVER_KEY}" ]; then
management.ssl.port = 15671
management.ssl.certfile = ${RABBITMQ_SERVER_CERT}
management.ssl.keyfile = ${RABBITMQ_SERVER_KEY}
+ ssl_options.verify = verify_none
EOF
if [ -e "${RABBITMQ_SERVER_CACERT}" ] && [ "${RABBITMQ_SERVER_VERIFY}" = "verify_peer" ]; then
cat >>"/var/lib/rabbitmq/rabbitmq.conf" <<-EOF
ssl_options.verify = verify_peer
ssl_options.fail_if_no_peer_cert = true
- ssl_options.cacertfile = ${RABBITMQ_SERVER_CACERT}
+ ssl_options.cacertfile = ${RABBITMQ_SERVER_CACERT}
EOF
fi
fi
@@ -56,8 +57,7 @@ cat >/var/lib/rabbitmq/advanced.config<<-EOF
{rabbit, [
{consumer_timeout, ${RABBITMQ_CONSUMER_TIMEOUT:-14400000}},
{default_consumer_prefetch, {false,1}}
- ]
- }
+ ]}
].
EOF
diff --git a/sda-download/go.mod b/sda-download/go.mod
index e3dfe9ab2..d89295abd 100644
--- a/sda-download/go.mod
+++ b/sda-download/go.mod
@@ -4,14 +4,14 @@ go 1.21
require (
github.com/DATA-DOG/go-sqlmock v1.5.2
- github.com/aws/aws-sdk-go v1.51.2
+ github.com/aws/aws-sdk-go v1.51.7
github.com/dgraph-io/ristretto v0.1.1
github.com/gin-gonic/gin v1.9.1
github.com/google/uuid v1.6.0
github.com/johannesboyne/gofakes3 v0.0.0-20230914150226-f005f5cc03aa
github.com/lestrrat-go/jwx/v2 v2.0.21
github.com/lib/pq v1.10.9
- github.com/neicnordic/crypt4gh v1.9.1
+ github.com/neicnordic/crypt4gh v1.10.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/viper v1.18.2
github.com/stretchr/testify v1.9.0
diff --git a/sda-download/go.sum b/sda-download/go.sum
index aaf2e26bb..9b4af45b6 100644
--- a/sda-download/go.sum
+++ b/sda-download/go.sum
@@ -3,8 +3,8 @@ filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/aws/aws-sdk-go v1.44.256/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
-github.com/aws/aws-sdk-go v1.51.2 h1:Ruwgz5aqIXin5Yfcgc+PCzoqW5tEGb9aDL/JWDsre7k=
-github.com/aws/aws-sdk-go v1.51.2/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
+github.com/aws/aws-sdk-go v1.51.7 h1:RRjxHhx9RCjw5AhgpmmShq3F4JDlleSkyhYMQ2xUAe8=
+github.com/aws/aws-sdk-go v1.51.7/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
@@ -108,8 +108,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/neicnordic/crypt4gh v1.9.1 h1:NKeOmsZ1/0xDpLvBDjN8Ltoh3ODbLB+NeKulDaNo4Oc=
-github.com/neicnordic/crypt4gh v1.9.1/go.mod h1:C8jHyUkt3bnQg0EwdRRswzvLXfu4dyLQOPARDIQTU24=
+github.com/neicnordic/crypt4gh v1.10.0 h1:7G++KTSnKM0lGJQREHA0qR0pUAc4sdhnb2+5n9hqFw8=
+github.com/neicnordic/crypt4gh v1.10.0/go.mod h1:YTpSmA/avBJojbwGSlWVs5Gtc4D0kzdFomCV9kIIXPw=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
diff --git a/sda-sftp-inbox/pom.xml b/sda-sftp-inbox/pom.xml
index d2dca47b1..798ef4ba3 100644
--- a/sda-sftp-inbox/pom.xml
+++ b/sda-sftp-inbox/pom.xml
@@ -14,7 +14,7 @@
{{.ExpDate}}
{{end}}
- Download inbox s3cmd credentials
+ Download inbox s3cmd credentials
Continue
diff --git a/sda/go.mod b/sda/go.mod
index 836849566..1fcc3b129 100644
--- a/sda/go.mod
+++ b/sda/go.mod
@@ -5,9 +5,9 @@ go 1.21
require (
github.com/DATA-DOG/go-sqlmock v1.5.2
github.com/aws/aws-sdk-go-v2 v1.26.0
- github.com/aws/aws-sdk-go-v2/config v1.27.8
- github.com/aws/aws-sdk-go-v2/credentials v1.17.8
- github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.12
+ github.com/aws/aws-sdk-go-v2/config v1.27.9
+ github.com/aws/aws-sdk-go-v2/credentials v1.17.9
+ github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.13
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.0
github.com/aws/smithy-go v1.20.1
github.com/coreos/go-oidc v2.2.1+incompatible
@@ -21,7 +21,7 @@ require (
github.com/lib/pq v1.10.9
github.com/minio/minio-go/v6 v6.0.57
github.com/mocktools/go-smtp-mock v1.10.0
- github.com/neicnordic/crypt4gh v1.9.1
+ github.com/neicnordic/crypt4gh v1.10.0
github.com/oauth2-proxy/mockoidc v0.0.0-20240214162133-caebfff84d25
github.com/ory/dockertest v3.3.5+incompatible
github.com/ory/dockertest/v3 v3.10.0
@@ -50,7 +50,7 @@ require (
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 // indirect
- github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
@@ -75,7 +75,7 @@ require (
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/docker/cli v20.10.17+incompatible // indirect
- github.com/docker/docker v24.0.7+incompatible // indirect
+ github.com/docker/docker v24.0.9+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/fatih/structs v1.1.0 // indirect
diff --git a/sda/go.sum b/sda/go.sum
index 31759f967..138ac7ce9 100644
--- a/sda/go.sum
+++ b/sda/go.sum
@@ -29,14 +29,14 @@ github.com/aws/aws-sdk-go-v2 v1.26.0 h1:/Ce4OCiM3EkpW7Y+xUnfAFpchU78K7/Ug01sZni9
github.com/aws/aws-sdk-go-v2 v1.26.0/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 h1:gTK2uhtAPtFcdRRJilZPx8uJLL2J85xK11nKtWL0wfU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1/go.mod h1:sxpLb+nZk7tIfCWChfd+h4QwHNUR57d8hA1cleTkjJo=
-github.com/aws/aws-sdk-go-v2/config v1.27.8 h1:0r8epOsiJ7YJz65MGcb8i91ehFp4kvvFe2qkq5oYeRI=
-github.com/aws/aws-sdk-go-v2/config v1.27.8/go.mod h1:XsmYKxYNuIhLsFddpNds+j9H5XKzjWDdg/SZngiwFio=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.8 h1:WUdNLXbyNbU07V/WFrSOBXqZTDgmmMNMgUFzpYOKJhw=
-github.com/aws/aws-sdk-go-v2/credentials v1.17.8/go.mod h1:iPZzLpaBIfhyvVS/XGD3JvR1GP3YdHTqpySKDlqkfs8=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4 h1:S+L2QSKhUuShih3aq9P/mkzDBiOO5tTyVg+vXREfsfg=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA=
-github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.12 h1:rfAytUY7OgbOMDkzxdiigZkbTe9SDER2dIpO/Fzi9+0=
-github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.12/go.mod h1:BaY3WWSgUwV/zq0K3HePyXhRYZxGnDATYERkR0f1RTs=
+github.com/aws/aws-sdk-go-v2/config v1.27.9 h1:gRx/NwpNEFSk+yQlgmk1bmxxvQ5TyJ76CWXs9XScTqg=
+github.com/aws/aws-sdk-go-v2/config v1.27.9/go.mod h1:dK1FQfpwpql83kbD873E9vz4FyAxuJtR22wzoXn3qq0=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.9 h1:N8s0/7yW+h8qR8WaRlPQeJ6czVMNQVNtNdUqf6cItao=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.9/go.mod h1:446YhIdmSV0Jf/SLafGZalQo+xr2iw7/fzXGDPTU1yQ=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 h1:af5YzcLf80tv4Em4jWVD75lpnOHSBkPUZxZfGkrI3HI=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.13 h1:F+PUZee9mlfpEJVZdgyewRumKekS9O3fftj8fEMt0rQ=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.13/go.mod h1:Rl7i2dEWGHGsBIJCpUxlRt7VwK/HyXxICxdvIRssQHE=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 h1:0ScVK/4qZ8CIW0k8jOeFVsyS/sAiXpYxRBLolMkuLQM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4/go.mod h1:84KyjNZdHC6QZW08nfHI6yZgPd+qRgaWcYsyLUo3QY8=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 h1:sHmMWWX5E7guWEFQ9SVo6A3S4xpPrWnd77a6y4WM6PU=
@@ -100,8 +100,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etly
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M=
github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
-github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0=
+github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
@@ -278,8 +278,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/neicnordic/crypt4gh v1.9.1 h1:NKeOmsZ1/0xDpLvBDjN8Ltoh3ODbLB+NeKulDaNo4Oc=
-github.com/neicnordic/crypt4gh v1.9.1/go.mod h1:C8jHyUkt3bnQg0EwdRRswzvLXfu4dyLQOPARDIQTU24=
+github.com/neicnordic/crypt4gh v1.10.0 h1:7G++KTSnKM0lGJQREHA0qR0pUAc4sdhnb2+5n9hqFw8=
+github.com/neicnordic/crypt4gh v1.10.0/go.mod h1:YTpSmA/avBJojbwGSlWVs5Gtc4D0kzdFomCV9kIIXPw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oauth2-proxy/mockoidc v0.0.0-20240214162133-caebfff84d25 h1:9bCMuD3TcnjeqjPT2gSlha4asp8NvgcFRYExCaikCxk=
github.com/oauth2-proxy/mockoidc v0.0.0-20240214162133-caebfff84d25/go.mod h1:eDjgYHYDJbPLBLsyZ6qRaugP0mX8vePOhZ5id1fdzJw=
diff --git a/tools/sda-admin b/tools/sda-admin
new file mode 100755
index 000000000..6f6ebfdf5
--- /dev/null
+++ b/tools/sda-admin
@@ -0,0 +1,959 @@
+#!/bin/sh
+
+set -u -e
+
+myself=$0
+
+# Default values for global options. Values in the environment override
+# these hard-coded defaults, and values set via command line options
+# override these later.
+
+MQ_CREDENTIALS=${MQ_CREDENTIALS-test:test} # --mq-credentials user:pass
+MQ_URL=${MQ_URL-http://localhost:15672} # --mq-url URL
+MQ_EXCHANGE=${MQ_EXCHANGE-sda} # --mq-exchange string
+MQ_VHOST=${MQ_VHOST-sda} # --mq-vhost string
+
+S3_CONFIG=${S3_CONFIG-s3cmd.conf} # --s3-config pathname
+C4GH_PUB_KEY=${C4GH_PUB_KEY-crypt4gh_key.pub} # --c4gh-pub-key pathname
+
+# Allow a user to use the environment variable "SDA_CLI" to point
+# directly to the "sda-cli" executable. If this environment variable is
+# not set, the tool will be picked up from "$PATH" as usual.
+SDA_CLI=${SDA_CLI-sda-cli} # --sda-cli pathname
+
+# There is also S3_ACCESS_KEY (--s3-access-key and its alias, --user),
+# but since its value depends on the final value of "$S3_CONFIG", we
+# can't set it here.
+
+encrypt () {
+ # Encrypt the given files using "sda-cli".
+ #
+ # Files are encrypted unconditionally, regardless of whether
+ # there exists encrypted variants of the files or not. The only
+ # scenario wherein a file is not encrypted is when the user
+ # gives us the pathname of an encrypted file and we can't find
+ # the unencrypted variant of the file by simply removing the
+ # ".c4gh" filename suffix.
+ #
+ # Directories and other non-regular files are ignored.
+
+ for pathname do
+ shift
+
+ if [ ! -f "$pathname" ] || [ ! -f "${pathname%.c4gh}" ]
+ then
+ # Error out if we are given something that
+ # doesn't exist or isn't a regular file, or if
+ # the variant of the filename with no ".c4gh"
+ # suffix does not exist or isn't a regular file.
+
+ printf '%s: %s: No such file or directory\n' \
+ "$myself" "$pathname" >&2
+ return 1
+ fi
+
+ pathname=${pathname%.c4gh}
+
+ # Skip if the unencrypted pathname is already in the
+ # list.
+ #
+ for dup do
+ if [ "$pathname" = "$dup" ]; then
+ continue 2
+ fi
+ done
+
+ # Remove the encrypted variant of the file, if it
+ # exists.
+ #
+ rm -f "$pathname.c4gh"
+
+ # Remember the unencrypted variant of the file for
+ # encryption later.
+ #
+ set -- "$@" "$pathname"
+ done
+
+ # If there are files to encrypt, encrypt them.
+ #
+ if [ "$#" -gt 0 ]; then
+ "$SDA_CLI" encrypt -key "$C4GH_PUB_KEY" "$@"
+ fi
+}
+
+upload () {
+ # Encrypt+upload using "sda-cli".
+ #
+ # Files are uploaded to the top-level directory of the S3
+ # storage bucket, offset by the target directory path given by
+ # the option-argument of the "-t" option.
+ #
+ # Directories are handled recursively and will be uploaded to
+ # the target directory path given by the directory name, offset
+ # by the target path given by the option-argument of the "-t"
+ # option.
+
+ OPTIND=1
+ unset -v target_dir
+ while getopts t: opt; do
+ case $opt in
+ t)
+ target_dir=$OPTARG
+ ;;
+ *)
+ echo 'Error in command line parsing' >&2
+ exit 1
+ esac
+ done
+ shift "$(( OPTIND - 1 ))"
+
+ # Sanity check the target directory path.
+ #
+ case ${target_dir-} in
+ ../*|*/../*|*/..)
+ echo 'Target path contains ".."' >&2
+ exit 1
+ ;;
+ ./*|*/./*|*/.)
+ echo 'Target path contains "."' >&2
+ exit 1
+ ;;
+ /*)
+ echo 'Target path is absolute' >&2
+ exit 1
+ esac
+
+ for pathname do
+ shift
+ if [ -d "$pathname" ]; then
+ # Recursively encrypt and upload the directory.
+ # We do this in a subshell to isolate the
+ # changes made to the "target_dir" variable in
+ # the recursive call.
+ #
+ (
+ upload -t "${target_dir+$target_dir/}$(basename "$pathname")" \
+ "$pathname"/*
+ )
+ continue
+ fi
+ set -- "$@" "$pathname"
+ done
+
+ encrypt "$@"
+
+ # Ensure that our list of files to upload only consists of
+ # encrypted files that exists, and that this list does not
+ # contain duplicate entries.
+ #
+ for pathname do
+ shift
+ pathname=${pathname%.c4gh}.c4gh
+
+ if [ ! -f "$pathname" ]; then
+ continue
+ fi
+
+ for dup do
+ if [ "$pathname" = "$dup" ]; then
+ continue 2
+ fi
+ done
+
+ set -- "$@" "$pathname"
+ done
+
+ # If there are files to upload, upload them, possibly in a
+ # subdirectory of the user's S3 bucket.
+ #
+ if [ "$#" -gt 0 ]; then
+ "$SDA_CLI" upload \
+ -config "$S3_CONFIG" \
+ ${target_dir+-targetDir "$target_dir"} \
+ "$@"
+ fi
+}
+
+curl () {
+ # Helper function that makes curl calls a bit shorter.
+
+ command curl \
+ --silent \
+ --show-error \
+ --user "$MQ_CREDENTIALS" \
+ --request POST \
+ --header 'Content-Type: application/json' \
+ --header 'Accept: application/json' \
+ "$@" |
+ jq 'if type == "object" and has("error") then halt_error(1) else . end'
+}
+
+publish () {
+ # Will read base64-encoded messages from standard input, one
+ # per line, decode each message and publish it. Any output is
+ # explicitly discarded.
+
+ while IFS= read -r message; do
+ printf "%s\n" "$message" | base64 -d |
+ curl --data @- "$url_exchanges/publish"
+ done >/dev/null
+}
+
+jq_filter=$(cat <<'JQ_FILTER'
+map(
+ # Add an array of pathnames that would match this message. This
+ # includes the pathname of each parent directory, leading up to
+ # and including the pathname of the file itself.
+ #
+ .tmp_paths = [
+ # The file's full pathname is part of the message's
+ # payload (a JSON encoded object).
+ #
+ foreach (
+ .payload |
+ fromjson.filepath |
+ split("/")[]
+ ) as $elem (
+ null;
+ . += $elem + "/";
+ .
+ )
+ ] |
+ # The last element is the full file path and should not have a
+ # trailing slash.
+ #
+ .tmp_paths[-1] |= rtrimstr("/")
+) |
+[
+ # Match the pathnames given as positional arguments against the
+ # computed pathnames in the "tmp_paths" array in each message.
+ # Depending on the $yes boolean variable, extract or discard
+ # matching messages.
+ #
+ JOIN(
+ INDEX($ARGS.positional[]; .);
+ .[];
+ .tmp_paths[];
+ if (.[1:] | any | if $yes then . else not end) then
+ .[0]
+ else
+ empty
+ end
+ )
+] |
+# Deduplicate the extracted messages on the full pathname of the file,
+# then remove the "tmp_paths" array from each message and base64 encode
+# them.
+#
+unique_by(.tmp_paths[-1]) |
+map( del(.tmp_paths) | @base64 )[]
+JQ_FILTER
+)
+
+rotate_dump_files () {
+ # Given a RabbitMQ queue name, this function rotates the queue
+ # dump file "