From f5dd28a57548a3c30288b6491e0519a9b0e1120a Mon Sep 17 00:00:00 2001 From: Sergio Arroutbi Date: Thu, 18 May 2023 14:00:08 +0200 Subject: [PATCH] Include parameter to indicate endpoint This change allows specifying -e option, so that endpoint parameter is used. This parameter gives the possibility to change URL where Tang listens, so that endpoint provided is prepended between host port information and advertisement/recovery suffix (rec/adv). Without endpoint, advertisement URL is: http://localhost:port/adv Meanwhile, if using endpoint (-e this/is/endpoint), advertisement URL is: http://localhost:port/this/is/endpoint/adv For more information, check man page Resolves: #116 Signed-off-by: Sergio Arroutbi --- doc/tang.8.adoc | 21 ++++++++++++ src/socket.c | 27 +++++++++------- src/socket.h | 15 +++++++-- src/tang-show-keys | 15 +++++++-- src/tangd.c | 60 +++++++++++++++++++++++++---------- tests/adv | 46 +++++++++++++-------------- tests/adv-socat-endpoint | 33 +++++++++++++++++++ tests/adv-standalone-endpoint | 31 ++++++++++++++++++ tests/helpers | 15 ++++++++- tests/meson.build | 4 +++ tests/rec | 14 ++++++++ tests/rec-socat-endpoint | 34 ++++++++++++++++++++ tests/rec-standalone-endpoint | 34 ++++++++++++++++++++ 13 files changed, 292 insertions(+), 57 deletions(-) create mode 100644 tests/adv-socat-endpoint create mode 100644 tests/adv-standalone-endpoint create mode 100644 tests/rec-socat-endpoint create mode 100755 tests/rec-standalone-endpoint diff --git a/doc/tang.8.adoc b/doc/tang.8.adoc index e0c9f7d..f7ef06e 100644 --- a/doc/tang.8.adoc +++ b/doc/tang.8.adoc @@ -71,6 +71,27 @@ be changed with the *-p* option. tang -l -p 9090 +== ENDPOINT + +The Tang server can be provided an endpoint. This endpoint will act as a prefix +for the URL to be accessed by the client. This endpoint can be specified with +the *-e* option. + + tang -l -p 9090 -e this/is/an/endpoint + +When endpoint is specified, the endpoint will be prepended to the normal adv/rec +URL. If no endpoint is provided, and assuming port 9090 is used, Tang server +will listen on next URLs: + + http://localhost:9090/adv (GET) + http://localhost:9090/rec (POST) + +If endpoint is provided, and assuming endpoint is /this/is/an/endpoint/, and +assuming also port 9090 is used, Tang server will listen on next URLs: + + http://localhost:9090/this/is/an/endpoint/adv (GET) + http://localhost:9090/this/is/an/endpoint/rec (POST) + == KEY ROTATION In order to preserve the security of the system over the long run, you need to diff --git a/src/socket.c b/src/socket.c index df512cc..9614995 100644 --- a/src/socket.c +++ b/src/socket.c @@ -146,8 +146,8 @@ static int listen_port(socket_list **slist, int port) return r; } -static void spawn_process(int fd, const char *jwkdir, - process_request_func pfunc, +static void spawn_process(process_request_func pfunc, + process_request_func_args_t pfunc_args, socket_list *slist) { pid_t pid; @@ -159,21 +159,23 @@ static void spawn_process(int fd, const char *jwkdir, close(ptr->s); } /* Ensure that both stdout and stdin are set */ - if (dup2(fd, STDOUT_FILENO) < 0) { + if (dup2(pfunc_args.fileno, STDOUT_FILENO) < 0) { perror("dup2"); - close(fd); + close(pfunc_args.fileno); return; } - close(fd); + close(pfunc_args.fileno); - pfunc(jwkdir, STDOUT_FILENO); + process_request_func_args_t pf = + { pfunc_args.jwkdir, STDOUT_FILENO, pfunc_args.endpoint }; + pfunc(pf); free_socket_list(slist); exit(0); } else if (pid == -1) { perror("fork failed"); } - close(fd); + close(pfunc_args.fileno); } static void handle_child(int sig) @@ -183,7 +185,7 @@ static void handle_child(int sig) while ((waitpid(-1, &status, WNOHANG)) > 0); } -int run_service(const char *jwkdir, int port, process_request_func pfunc) +int run_service(run_service_args_t rserv, process_request_func pfunc) { socket_list *slist, *ptr; int r, n = 0, accept_fd; @@ -198,9 +200,9 @@ int run_service(const char *jwkdir, int port, process_request_func pfunc) new_action.sa_flags = 0; sigaction(SIGCHLD, &new_action, NULL); - r = listen_port(&slist, port); + r = listen_port(&slist, rserv.port); if (r < 0) { - fprintf(stderr, "Could not listen port (%d)\n", port); + fprintf(stderr, "Could not listen port (%d)\n", rserv.port); return -1; } @@ -233,8 +235,9 @@ int run_service(const char *jwkdir, int port, process_request_func pfunc) perror("accept"); continue; } - - spawn_process(accept_fd, jwkdir, pfunc, slist); + process_request_func_args_t pr_args = + {rserv.jwkdir, accept_fd,rserv.endpoint}; + spawn_process(pfunc, pr_args, slist); } } diff --git a/src/socket.h b/src/socket.h index 7cfd873..ebe1287 100644 --- a/src/socket.h +++ b/src/socket.h @@ -15,7 +15,18 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +typedef struct process_request_func_args { + const char* jwkdir; + const int fileno; + const char* endpoint; +} process_request_func_args_t; -typedef int (*process_request_func)(const char *jwkdir, int in_fileno); +typedef int (*process_request_func)(const process_request_func_args_t); -int run_service(const char *jwkdir, int port, process_request_func); +typedef struct run_service_args { + const char* jwkdir; + const int port; + const char* endpoint; +} run_service_args_t; + +int run_service(const run_service_args_t, process_request_func); diff --git a/src/tang-show-keys b/src/tang-show-keys index 0c33c3a..3ba82e7 100755 --- a/src/tang-show-keys +++ b/src/tang-show-keys @@ -20,14 +20,23 @@ set -e -if [ $# -gt 1 ]; then - echo "Usage: $0 []" >&2 +if [ $# -gt 2 ]; then + echo "Usage: $0 [] []" >&2 exit 1 fi port=${1-80} -adv=$(curl -sSf "localhost:$port/adv") +if test -n "$2"; then + first_letter=$(printf %.1s "$2") + if [ "${first_letter}" = "/" ]; then + adv=$(curl -sSf "localhost:$port$2/adv") + else + adv=$(curl -sSf "localhost:$port/$2/adv") + fi +else + adv=$(curl -sSf "localhost:$port/adv") +fi THP_DEFAULT_HASH=S256 # SHA-256. jose fmt --json "${adv}" -g payload -y -o- \ diff --git a/src/tangd.c b/src/tangd.c index 7f197f6..7f62d1c 100644 --- a/src/tangd.c +++ b/src/tangd.c @@ -32,8 +32,11 @@ #include "keys.h" #include "socket.h" +const unsigned int MAX_URL = 256; + static const struct option long_options[] = { {"port", 1, 0, 'p'}, + {"endpoint", 1, 0, 'e'}, {"listen", 0, 0, 'l'}, {"version", 0, 0, 'v'}, {"help", 0, 0, 'h'}, @@ -45,6 +48,7 @@ print_help(const char *name) { fprintf(stderr, "Usage: %s [OPTIONS] \n", name); fprintf(stderr, " -p, --port=PORT Specify the port to listen (default 9090)\n"); + fprintf(stderr, " -e, --endpoint=ENDPOINT Specify endpoint to listen (empty by default)\n"); fprintf(stderr, " -l, --listen Run as a service and wait for connections\n"); fprintf(stderr, " -v, --version Display program version\n"); fprintf(stderr, " -h, --help Show this help message\n"); @@ -184,19 +188,37 @@ rec(http_method_t method, const char *path, const char *body, "\r\n%s", strlen(enc), enc); } -static struct http_dispatch dispatch[] = { - { adv, 1 << HTTP_GET, 2, "^/+adv/+([0-9A-Za-z_-]+)$" }, - { adv, 1 << HTTP_GET, 2, "^/+adv/*$" }, - { rec, 1 << HTTP_POST, 2, "^/+rec/+([0-9A-Za-z_-]+)$" }, - {} -}; - #define DEFAULT_PORT 9090 static int -process_request(const char *jwkdir, int in_fileno) +process_request(const process_request_func_args_t pr_args) { - struct http_state state = { .dispatch = dispatch, .misc = (char*)jwkdir }; + char adv_endpoint[MAX_URL]; + char adv2_endpoint[MAX_URL]; + char rec_endpoint[MAX_URL]; + if (pr_args.endpoint != NULL) { + if (pr_args.endpoint[0] == '/') { + snprintf(adv_endpoint, MAX_URL, "^%s/+adv/+([0-9A-Za-z_-]+)$", pr_args.endpoint); + snprintf(adv2_endpoint, MAX_URL, "^%s/+adv/*$", pr_args.endpoint); + snprintf(rec_endpoint, MAX_URL, "^%s/+rec/+([0-9A-Za-z_-]+)$", pr_args.endpoint); + } else { + snprintf(adv_endpoint, MAX_URL, "^/%s/+adv/+([0-9A-Za-z_-]+)$", pr_args.endpoint); + snprintf(adv2_endpoint, MAX_URL, "^/%s/+adv/*$", pr_args.endpoint); + snprintf(rec_endpoint, MAX_URL, "^/%s/+rec/+([0-9A-Za-z_-]+)$", pr_args.endpoint); + } + } else { + strncpy(adv_endpoint, "^/+adv/+([0-9A-Za-z_-]+)$", MAX_URL); + strncpy(adv2_endpoint, "^/+adv/*$", MAX_URL); + strncpy(rec_endpoint, "^/+rec/+([0-9A-Za-z_-]+)$", MAX_URL); + } + struct http_dispatch dispatch[] = { + { adv, 1 << HTTP_GET, 2, adv_endpoint }, + { adv, 1 << HTTP_GET, 2, adv2_endpoint }, + { rec, 1 << HTTP_POST, 2, rec_endpoint }, + {} + }; + + struct http_state state = { .dispatch = dispatch, .misc = (char*)pr_args.jwkdir }; http_parser_t parser; struct stat st = {}; char req[4096] = {}; @@ -206,18 +228,18 @@ process_request(const char *jwkdir, int in_fileno) tang_http_parser_init(&parser, &http_settings); parser.data = &state; - if (stat(jwkdir, &st) != 0) { - fprintf(stderr, "Error calling stat() on path: %s: %m\n", jwkdir); + if (stat(pr_args.jwkdir, &st) != 0) { + fprintf(stderr, "Error calling stat() on path: %s: %m\n", pr_args.jwkdir); return EXIT_FAILURE; } if (!S_ISDIR(st.st_mode)) { - fprintf(stderr, "Path is not a directory: %s\n", jwkdir); + fprintf(stderr, "Path is not a directory: %s\n", pr_args.jwkdir); return EXIT_FAILURE; } for (;;) { - r = read(in_fileno, &req[rcvd], sizeof(req) - rcvd - 1); + r = read(pr_args.fileno, &req[rcvd], sizeof(req) - rcvd - 1); if (r == 0) return rcvd > 0 ? EXIT_FAILURE : EXIT_SUCCESS; if (r < 0) @@ -244,9 +266,10 @@ main(int argc, char *argv[]) int listen = 0; int port = DEFAULT_PORT; const char *jwkdir = NULL; + const char *endpoint = NULL; while (1) { - int c = getopt_long(argc, argv, "lp:vh", long_options, NULL); + int c = getopt_long(argc, argv, "lp:e:vh", long_options, NULL); if (c == -1) break; @@ -260,6 +283,9 @@ main(int argc, char *argv[]) case 'p': port = atoi(optarg); break; + case 'e': + endpoint = optarg; + break; case 'l': listen = 1; break; @@ -273,8 +299,10 @@ main(int argc, char *argv[]) jwkdir = argv[optind++]; if (listen == 0) { /* process one-shot query from stdin */ - return process_request(jwkdir, STDIN_FILENO); + process_request_func_args_t pr = {jwkdir, STDIN_FILENO, endpoint}; + return process_request(pr); } else { /* listen and process all incoming connections */ - return run_service(jwkdir, port, process_request); + run_service_args_t rs = {jwkdir, port, endpoint}; + return run_service(rs, process_request); } } diff --git a/tests/adv b/tests/adv index 8e6dd0e..416dc6e 100755 --- a/tests/adv +++ b/tests/adv @@ -36,47 +36,47 @@ adv_startup () { adv_second_phase () { # Make sure requests on the root fail - fetch / && expected_fail + fetch "${ENDPOINT}"/ && expected_fail # The request should fail (404) for non-signature key IDs - fetch /adv/`jose jwk thp -i $TMP/db/exc.jwk` && expected_fail - fetch /adv/`jose jwk thp -a S512 -i $TMP/db/exc.jwk` && expected_fail + fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/exc.jwk` && expected_fail + fetch "${ENDPOINT}"/adv/`jose jwk thp -a S512 -i $TMP/db/exc.jwk` && expected_fail # The default advertisement fetch should succeed and pass verification - fetch /adv - fetch /adv | ver $TMP/db/sig.jwk - fetch /adv/ | ver $TMP/db/sig.jwk + fetch "${ENDPOINT}"/adv + fetch "${ENDPOINT}"/adv | ver $TMP/db/sig.jwk + fetch "${ENDPOINT}"/adv/ | ver $TMP/db/sig.jwk # Fetching by any thumbprint should work - fetch /adv/`jose jwk thp -i $TMP/db/sig.jwk` | ver $TMP/db/sig.jwk - fetch /adv/`jose jwk thp -a S512 -i $TMP/db/sig.jwk` | ver $TMP/db/sig.jwk + fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/sig.jwk` | ver $TMP/db/sig.jwk + fetch "${ENDPOINT}"/adv/`jose jwk thp -a S512 -i $TMP/db/sig.jwk` | ver $TMP/db/sig.jwk # Requesting an adv by an advertised key ID should't be signed by hidden keys - fetch /adv/`jose jwk thp -i $TMP/db/sig.jwk` | ver $TMP/db/.sig.jwk && expected_fail - fetch /adv/`jose jwk thp -i $TMP/db/sig.jwk` | ver $TMP/db/.oth.jwk && expected_fail + fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/sig.jwk` | ver $TMP/db/.sig.jwk && expected_fail + fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/sig.jwk` | ver $TMP/db/.oth.jwk && expected_fail # Verify that the default advertisement is not signed with hidden signature keys - fetch /adv/ | ver $TMP/db/.oth.jwk && expected_fail - fetch /adv/ | ver $TMP/db/.sig.jwk && expected_fail + fetch "${ENDPOINT}"/adv/ | ver $TMP/db/.oth.jwk && expected_fail + fetch "${ENDPOINT}"/adv/ | ver $TMP/db/.sig.jwk && expected_fail # A private key advertisement is signed by all advertised keys and the requested private key - fetch /adv/`jose jwk thp -i $TMP/db/.sig.jwk` | ver $TMP/db/sig.jwk - fetch /adv/`jose jwk thp -i $TMP/db/.sig.jwk` | ver $TMP/db/.sig.jwk - fetch /adv/`jose jwk thp -i $TMP/db/.sig.jwk` | ver $TMP/db/.oth.jwk && expected_fail + fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/.sig.jwk` | ver $TMP/db/sig.jwk + fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/.sig.jwk` | ver $TMP/db/.sig.jwk + fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/.sig.jwk` | ver $TMP/db/.oth.jwk && expected_fail # Verify that the advertisements contain the cty parameter - fetch /adv | jose fmt -j- -Og protected -SyOg cty -Sq "jwk-set+json" -E - fetch /adv/`jose jwk thp -i $TMP/db/.sig.jwk` \ + fetch "${ENDPOINT}"/adv | jose fmt -j- -Og protected -SyOg cty -Sq "jwk-set+json" -E + fetch "${ENDPOINT}"/adv/`jose jwk thp -i $TMP/db/.sig.jwk` \ | jose fmt -j- -Og signatures -A \ -g 0 -Og protected -SyOg cty -Sq "jwk-set+json" -EUUUUU \ -g 1 -Og protected -SyOg cty -Sq "jwk-set+json" -EUUUUU THP_DEFAULT_HASH=S256 # SHA-256. - test "$(tang-show-keys $PORT)" = "$(jose jwk thp -a "${THP_DEFAULT_HASH}" -i $TMP/db/sig.jwk)" + test "$(tang-show-keys $PORT $ENDPOINT)" = "$(jose jwk thp -a "${THP_DEFAULT_HASH}" -i $TMP/db/sig.jwk)" # Check that new keys will be created if none exist. rm -rf "${TMP}/db" && mkdir -p "${TMP}/db" - fetch /adv + fetch "${ENDPOINT}"/adv # Now let's make sure the new keys were named using our default thumbprint # hash and then rotate them and check if we still create new keys. @@ -88,7 +88,7 @@ adv_second_phase () { mv -f -- "${k}" ".${k}" done cd - - fetch /adv + fetch "${ENDPOINT}"/adv # Lets's now test with multiple pairs of keys. for i in 1 2 3 4 5 6 7 8 9; do @@ -103,12 +103,12 @@ adv_second_phase () { done # Verify the advertisement is correct. - validate "$(fetch /adv)" + validate "$(fetch "${ENDPOINT}"/adv)" # And make sure we can fetch an adv by its thumbprint. for jwk in "${TMP}"/db/other-sig-*.jwk; do for alg in $(jose alg -k hash); do - fetch /adv/"$(jose jwk thp -a "${alg}" -i "${jwk}")" | ver "${jwk}" + fetch "${ENDPOINT}"/adv/"$(jose jwk thp -a "${alg}" -i "${jwk}")" | ver "${jwk}" done done @@ -130,5 +130,5 @@ adv_second_phase () { valid_key_perm "${jwk}" done [ -z "${thp}" ] && die "There should be valid keys after rotation" - test "$(tang-show-keys $PORT)" = "${thp}" + test "$(tang-show-keys $PORT $ENDPOINT)" = "${thp}" } diff --git a/tests/adv-socat-endpoint b/tests/adv-socat-endpoint new file mode 100644 index 0000000..c4deb88 --- /dev/null +++ b/tests/adv-socat-endpoint @@ -0,0 +1,33 @@ +#!/bin/sh -ex +# +# Copyright (c) 2023 Red Hat, Inc. +# Author: Sergio Arroutbi +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +. adv + +sanity_check + +adv_startup + +port=$(random_port) +export PORT=$((port+3)) +export ENDPOINT="/api/dee-hms" +start_server_endpoint "${PORT}" "${ENDPOINT}" +export PID=$! +wait_for_port ${PORT} + +adv_second_phase diff --git a/tests/adv-standalone-endpoint b/tests/adv-standalone-endpoint new file mode 100644 index 0000000..de7a7fe --- /dev/null +++ b/tests/adv-standalone-endpoint @@ -0,0 +1,31 @@ +#!/bin/sh -ex +# +# Copyright (c) 2023 Red Hat, Inc. +# Author: Sergio Arroutbi +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +. adv + +adv_startup + +port=$(random_port) +export PORT=$((port+1)) +export ENDPOINT="/api/dee-hms" +start_standalone_server_endpoint "${PORT}" "${ENDPOINT}" +export PID=$! +wait_for_port ${PORT} + +adv_second_phase diff --git a/tests/helpers b/tests/helpers index 55447ae..5ce3daf 100755 --- a/tests/helpers +++ b/tests/helpers @@ -30,7 +30,12 @@ random_port() { if [ -n "${TANG_BSD}" ]; then jot -r 1 1024 65536 else - shuf -i 1024-65536 -n 1 + if test -f /dev/urandom; + then + shuf -i 1024-65535 -n 1 --random-file=/dev/urandom + else + shuf -i 1024-65535 -n 1 + fi fi } @@ -62,10 +67,18 @@ start_server() { "${SOCAT}" TCP-LISTEN:"${1}",bind=127.0.0.1,fork SYSTEM:"${VALGRIND} tangd ${TMP}/db" & } +start_server_endpoint() { + "${SOCAT}" TCP-LISTEN:"${1}",bind=127.0.0.1,fork SYSTEM:"${VALGRIND} tangd ${TMP}/db -e ${ENDPOINT}" & +} + start_standalone_server() { ${VALGRIND} tangd -p ${1} -l ${TMP}/db & } +start_standalone_server_endpoint() { + ${VALGRIND} tangd -p ${1} -l ${TMP}/db -e ${2} & +} + on_exit() { if [ "${PID}" ]; then kill "${PID}" || true diff --git a/tests/meson.build b/tests/meson.build index 7d184f8..e2e9924 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -41,9 +41,13 @@ if socat.found() endif test('adv-standalone', find_program('adv-standalone'), env: env, timeout: 360) +test('adv-standalone-endpoint', find_program('adv-standalone-endpoint'), env: env, timeout: 360) test('adv-socat', find_program('adv-socat'), env: env, timeout: 360) +test('adv-socat-endpoint', find_program('adv-socat-endpoint'), env: env, timeout: 360) test('rec-standalone', find_program('rec-standalone'), env: env, timeout: 360) +test('rec-standalone-endpoint', find_program('rec-standalone-endpoint'), env: env, timeout: 360) test('rec-socat', find_program('rec-socat'), env: env, timeout: 360) +test('rec-socat-endpoint', find_program('rec-socat-endpoint'), env: env, timeout: 360) test('test-keys', test_keys, env: env, timeout: 360) # vim:set ts=2 sw=2 et: diff --git a/tests/rec b/tests/rec index f15637d..d30f72f 100755 --- a/tests/rec +++ b/tests/rec @@ -51,3 +51,17 @@ rec_second_phase () { http://127.0.0.1:$PORT/rec/${exc_kid} < $TMP/exc.pub.jwk` [ "$good" = "$test" ] } + +rec_second_phase_endpoint () { + # Make sure that GET fails + curl -sf http://127.0.0.1:$PORT/$ENDPOINT/rec && expected_fail + curl -sf http://127.0.0.1:$PORT/$ENDPOINT/rec/ && expected_fail + + # Make a recovery request (NOTE: this is insecure! Don't do this in real code!) + good=`jose jwk exc -i '{"alg":"ECMR","key_ops":["deriveKey"]}' -l $TMP/exc.jwk -r $TMP/db/exc.jwk` + test=`curl -sf -X POST \ + -H "Content-Type: application/jwk+json" \ + --data-binary @- \ + http://127.0.0.1:$PORT/$ENDPOINT/rec/${exc_kid} < $TMP/exc.pub.jwk` + [ "$good" = "$test" ] +} diff --git a/tests/rec-socat-endpoint b/tests/rec-socat-endpoint new file mode 100644 index 0000000..f62d919 --- /dev/null +++ b/tests/rec-socat-endpoint @@ -0,0 +1,34 @@ +#!/bin/sh -ex +# +# Copyright (c) 2023 Red Hat, Inc. +# Author: Sergio Arroutbi +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +. rec + +sanity_check + +rec_startup + +# Start the server +port=$(random_port) +export PORT=$((port+4)) +export ENDPOINT="api/dee-hms" +start_server_endpoint "${PORT}" "${ENDPOINT}" +export PID=$! +wait_for_port ${PORT} + +rec_second_phase_endpoint diff --git a/tests/rec-standalone-endpoint b/tests/rec-standalone-endpoint new file mode 100755 index 0000000..2e7e1b8 --- /dev/null +++ b/tests/rec-standalone-endpoint @@ -0,0 +1,34 @@ +#!/bin/sh -ex +# +# Copyright (c) 2023 Red Hat, Inc. +# Author: Sergio Arroutbi +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +. rec + +sanity_check + +rec_startup + +# Start the server +port=$(random_port) +export PORT=$((port+2)) +export ENDPOINT="api/dee-hms" +start_standalone_server_endpoint "${PORT}" "${ENDPOINT}" +export PID=$! +wait_for_port ${PORT} + +rec_second_phase_endpoint