diff --git a/1.14.5/bullseye/Dockerfile b/1.14.5/bullseye/Dockerfile index 0bd5d71..2d4762f 100644 --- a/1.14.5/bullseye/Dockerfile +++ b/1.14.5/bullseye/Dockerfile @@ -34,7 +34,8 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ && rm -rf /var/lib/apt/lists/* # fetch tools and setup signers -RUN git clone --depth 1 ${REPO_GITIAN_BUILDER} gitian \ +RUN bash -o pipefail \ + && git clone --depth 1 ${REPO_GITIAN_BUILDER} gitian \ && git clone --depth 1 ${REPO_GITIAN_SIGS} sigs \ && git clone --depth 1 -b v${RLS_VERSION} ${REPO_DOGECOIN_CORE} dogecoin \ && find dogecoin/contrib/gitian-keys -name "*.pgp" |xargs -n 1 gpg --import @@ -53,32 +54,46 @@ RUN set -ex && ARCHITECTURE=$(dpkg --print-architecture) \ | grep OK | shuf -n 1 | sed s/:.*// > random_signer.txt \ && grep ${RLS_FILE_NAME} sigs/${SIG_PATH}/$(cat random_signer.txt)/*assert | sha256sum -c \ && grep ${RLS_FILE_NAME} SHASUMS | sha256sum -c \ - && mv ${RLS_FILE_NAME} dogecoin.tar.gz + && tar -zxvf ${RLS_FILE_NAME} \ + dogecoin-${RLS_VERSION}/bin/dogecoind \ + dogecoin-${RLS_VERSION}/bin/dogecoin-cli \ + dogecoin-${RLS_VERSION}/bin/dogecoin-tx \ + --strip-components=1 + +COPY entrypoint.py /entrypoint.py FROM debian:bullseye-slim AS final -ENV USER=dogecoin -ENV DATADIR=/${USER}/.dogecoin +ARG USER= +ENV USER=${USER} +ARG APP_UID= +ENV APP_UID=${APP_UID} +ARG APP_GID= +ENV APP_GID=${APP_GID} +ENV DATADIR=/home/${USER}/.dogecoin -# Root configuration to mimic user -ENV HOME=/${USER} +# RUN echo ${USER} ${APP_UID} ${APP_GID} && exit 1 -RUN useradd ${USER} --home-dir ${HOME} +RUN echo ${USER} ${APP_UID} ${APP_GID} \ + && groupadd -g ${APP_GID} ${USER} \ + && useradd -m --uid ${APP_UID} ${USER} -g ${APP_GID} \ + && mkdir -p ${DATADIR} \ + && chgrp -R ${APP_GID} ${DATADIR} \ + && chown -R ${APP_UID}:${APP_GID} ${DATADIR} \ + && chmod -R 1007 ${DATADIR} -WORKDIR /tmp +WORKDIR /home/${USER} -# Copy the downloaded binary from the verify stage -COPY --from=verify /verify/dogecoin.tar.gz ./ +# Copy the downloaded binaries into the container system from the verify stage. +COPY --from=verify \ + /verify/bin/dogecoind \ + /verify/bin/dogecoin-cli \ + /verify/bin/dogecoin-tx /usr/local/bin/ -# Move downloaded binaries and man pages in the container system. -# Setuid on binaries with $USER rights, to limit root usage. -RUN tar -xvf dogecoin.tar.gz --strip-components=1 \ - && cp bin/dogecoind bin/dogecoin-cli bin/dogecoin-tx /usr/local/bin/ \ - && chown ${USER}:${USER} /usr/local/bin/dogecoin* \ - && chmod 4555 /usr/local/bin/dogecoin* \ - && rm -rf * +COPY /entrypoint.py /usr/local/bin/ -WORKDIR ${HOME} +# Set permissions on copied files +RUN chmod g+x /usr/local/bin/* # P2P network (mainnet, testnet & regnet respectively) EXPOSE 22556 44556 18444 @@ -86,15 +101,15 @@ EXPOSE 22556 44556 18444 # RPC interface (mainnet, testnet & regnet respectively) EXPOSE 22555 44555 18332 -VOLUME ["/dogecoin/.dogecoin"] +VOLUME ["${DATADIR}"] # Dependencies install RUN apt-get update && apt-get install --no-install-recommends -y \ python3 \ && rm -rf /var/lib/apt/lists/* -COPY entrypoint.py /usr/local/bin/entrypoint.py -RUN chmod 500 /usr/local/bin/entrypoint.py +USER ${APP_UID}:${APP_GID} ENTRYPOINT ["entrypoint.py"] + CMD ["dogecoind"] diff --git a/1.14.5/bullseye/build.sh b/1.14.5/bullseye/build.sh new file mode 100755 index 0000000..1f7330a --- /dev/null +++ b/1.14.5/bullseye/build.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +wget https://raw.githubusercontent.com/dogecoin/dogecoin/master/share/rpcuser/rpcuser.py +chmod +x rpcuser.py +./rpcuser.py dogecoin > auth +rpcauth=$(cat auth | grep "rpcauth") +rpcpassword=$(cat auth | sed '1,/Your password:/d') +echo daemon=1 > dogecoin.conf +echo server=1 >> dogecoin.conf +echo listen=1 >> dogecoin.conf +echo wallet=1 >> dogecoin.conf +echo bind=0.0.0.0:22556 >> dogecoin.conf +echo bind=[::]:22556 >> dogecoin.conf +echo rpcbind=127.0.0.1:22555 >> dogecoin.conf +echo rpcallowip=0.0.0.0/0 >> dogecoin.conf +echo rpcuser=dogecoin >> dogecoin.conf +echo $rpcauth >> dogecoin.conf +echo rpcpassword=$rpcpassword >> dogecoin.conf +echo harddustlimit=0.001 >> dogecoin.conf +rm rpcuser.py auth + +docker build --no-cache --build-arg "APP_UID=$(id -u $USER)" --build-arg "APP_GID=$(id -g $USER)" --build-arg "USER=dogecoin" -t xanimo/dogecoin:1.14.5 . diff --git a/1.14.5/bullseye/docker-compose.yml b/1.14.5/bullseye/docker-compose.yml new file mode 100644 index 0000000..c3a1327 --- /dev/null +++ b/1.14.5/bullseye/docker-compose.yml @@ -0,0 +1,19 @@ +version: "3.8" + +name: dogecoin +services: + dogecoin: + build: . + image: xanimo/dogecoin:1.14.5 + volumes: + - dogecoin:/home/dogecoin/.dogecoin + env_file: + - .env + +volumes: + dogecoin: + driver: local + driver_opts: + o: bind + type: none + device: /mnt/volumes/.dogecoin diff --git a/1.14.5/bullseye/dogecoin.conf b/1.14.5/bullseye/dogecoin.conf new file mode 100755 index 0000000..ae005f4 --- /dev/null +++ b/1.14.5/bullseye/dogecoin.conf @@ -0,0 +1,12 @@ +daemon=1 +server=1 +listen=1 +wallet=1 +bind=0.0.0.0:18444 +bind=[::]:18444 +rpcbind=127.0.0.1:18443 +rpcallowip=0.0.0.0/0 +rpcuser=dogecoin +rpcauth=dogecoin:b60e8cbd94e52a801ef34f1346422bd9$e6c36a71f0d353f225178dcd0efa576e32b06127184dce4a080d43f8be48ddfe +rpcpassword=DAN8LP5r5PnE-Q48B3JWiilmK5mbJb7zAcDAUC0ctxQ +harddustlimit=0.001 diff --git a/1.14.5/bullseye/entrypoint.py b/1.14.5/bullseye/entrypoint.py index ce56474..79b7460 100755 --- a/1.14.5/bullseye/entrypoint.py +++ b/1.14.5/bullseye/entrypoint.py @@ -4,7 +4,7 @@ """ import argparse import os -import pwd +# import pwd import shutil import sys import subprocess @@ -70,7 +70,6 @@ def executable_options(executable): def create_datadir(): """ Create data directory used by dogecoin daemon. - Create manually the directory while root at container creation, root rights needed to create folder with host volume. """ @@ -81,11 +80,15 @@ def create_datadir(): #Try to get datadir from environment datadir = argv.datadir or os.environ.get("DATADIR") - + print(datadir) + print(argv.datadir) os.makedirs(datadir, exist_ok=True) + app_uid = os.environ["APP_UID"] + app_gid = os.environ["APP_GID"] user = os.environ["USER"] - subprocess.run(["chown", "-R", f"{user}:{user}", datadir], check=True) + subprocess.run(["chmod", "-R", "1700", datadir], check=True) + subprocess.run(["chown", "-R", f"{app_uid}:{app_gid}", f"/home/{user}/.dogecoin"], check=True) def convert_env(executable): """ @@ -131,9 +134,9 @@ def run_executable(executable, executable_args): #Switch process from root to user. #Equivalent to use gosu or su-exec - user_info = pwd.getpwnam(os.environ['USER']) - os.setgid(user_info.pw_gid) - os.setuid(user_info.pw_uid) + # user_info = pwd.getpwnam(os.environ['USER']) + # os.setgid(user_info.pw_gid) + # os.setuid(user_info.pw_uid) #Run container command return execute(executable, executable_args) @@ -142,6 +145,7 @@ def main(): """ Main routine """ + if sys.argv[1].startswith("-"): executable = "dogecoind" else: diff --git a/1.14.5/bullseye/run.sh b/1.14.5/bullseye/run.sh new file mode 100755 index 0000000..274095d --- /dev/null +++ b/1.14.5/bullseye/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +if [[ -f .lock ]]; then + touch .lock + docker volume create dogecoin +fi + +if docker inspect dogecoin | grep '"Status":' | grep "running"; then + docker stop dogecoin +fi + +docker run -d -e APP_UID=$(id -u $USER) -e APP_GID=$(id -g $USER) -u "$(id -u $USER):$(id -g $USER)" -it --rm --name dogecoin -t xanimo/dogecoin:1.14.5 --regtest diff --git a/1.14.6/bullseye/.env b/1.14.6/bullseye/.env new file mode 100644 index 0000000..20b2f12 --- /dev/null +++ b/1.14.6/bullseye/.env @@ -0,0 +1,12 @@ +daemon=1 +server=1 +listen=1 +wallet=1 +bind=0.0.0.0:22556 +bind=[::]:22556 +rpcbind=127.0.0.1:22555 +rpcallowip=0.0.0.0/0 +rpcuser=dogecoin +rpcauth=dogecoin:a1300ebb8da7f280ad66b969264c22dd$0c9869c90bfc813708540a13146c63823463ee51b5d3d6abceb11674b5eb600a +rpcpassword=jdjKm44i1UpmTicidJiaSNmUc-klDlervv_U-8uInp4 +harddustlimit=0.001 diff --git a/1.14.6/bullseye/Dockerfile b/1.14.6/bullseye/Dockerfile new file mode 100644 index 0000000..5019515 --- /dev/null +++ b/1.14.6/bullseye/Dockerfile @@ -0,0 +1,109 @@ +FROM debian:bullseye-slim AS verify + +WORKDIR /verify + +# github repository locations +ARG REPO_GITIAN_BUILDER=https://github.com/devrandom/gitian-builder.git +ARG REPO_GITIAN_SIGS=https://github.com/dogecoin/gitian.sigs.git +ARG REPO_DOGECOIN_CORE=https://github.com/dogecoin/dogecoin.git + +# Specify release variables +ARG RLS_VERSION=1.14.6 +ARG RLS_OS=linux +ARG RLS_LIB=gnu +ARG RLS_ARCH= + +# static derived variables +ARG SIG_PATH=${RLS_VERSION}-${RLS_OS} +ARG DESCRIPTOR_PATH=dogecoin/contrib/gitian-descriptors/gitian-${RLS_OS}.yml +ARG RLS_LOCATION=https://github.com/dogecoin/dogecoin/releases/download/v${RLS_VERSION} + +# install system requirements +RUN apt-get update && apt-get install --no-install-recommends -y \ + wget \ + git \ + ruby \ + gpg \ + gpg-agent \ + && rm -rf /var/lib/apt/lists/* + +# fetch tools and setup signers +RUN bash -o pipefail \ + && git clone --depth 1 ${REPO_GITIAN_BUILDER} gitian \ + && git clone --depth 1 ${REPO_GITIAN_SIGS} sigs \ + && git clone --depth 1 -b v${RLS_VERSION} ${REPO_DOGECOIN_CORE} dogecoin \ + && find dogecoin/contrib/gitian-keys -name "*.pgp" |xargs -n 1 gpg --import + +# determine architecture, download release binary +# and verify against random OK signer and pinned shasums +RUN set -ex && ARCHITECTURE=$(dpkg --print-architecture) \ + && if [ "${ARCHITECTURE}" = "amd64" ]; then RLS_ARCH=x86_64 ; fi \ + && if [ "${ARCHITECTURE}" = "arm64" ]; then RLS_ARCH=aarch64; fi \ + && if [ "${ARCHITECTURE}" = "armhf" ]; then RLS_ARCH=arm && RLS_LIB=gnueabihf; fi \ + && if [ "${ARCHITECTURE}" = "i386" ]; then RLS_ARCH=i686-pc; fi \ + && if [ "${RLS_ARCH}" = "" ]; then echo "Could not determine architecture" >&2; exit 1; fi \ + && RLS_FILE_NAME=dogecoin-${RLS_VERSION}-${RLS_ARCH}-${RLS_OS}-${RLS_LIB}.tar.gz \ + && wget ${RLS_LOCATION}/${RLS_FILE_NAME} \ + && wget ${RLS_LOCATION}/SHA256SUMS.asc \ + && gitian/bin/gverify --no-markup -d sigs -r ${SIG_PATH} ${DESCRIPTOR_PATH} \ + | grep OK | shuf -n 1 | sed s/:.*// > random_signer.txt \ + && grep ${RLS_FILE_NAME} sigs/${SIG_PATH}/$(cat random_signer.txt)/*assert | sha256sum -c \ + && grep ${RLS_FILE_NAME} SHA256SUMS.asc | sha256sum -c \ + && tar -zxvf ${RLS_FILE_NAME} \ + dogecoin-${RLS_VERSION}/bin/dogecoind \ + dogecoin-${RLS_VERSION}/bin/dogecoin-cli \ + dogecoin-${RLS_VERSION}/bin/dogecoin-tx \ + --strip-components=1 + +COPY entrypoint.py /entrypoint.py + +FROM debian:bullseye-slim AS final + +ARG USER= +ENV USER=${USER:-"dogecoin"} +ARG APP_UID= +ENV APP_UID=${APP_UID} +ARG APP_GID= +ENV APP_GID=${APP_GID} +ENV DATADIR=/home/${USER}/.dogecoin + +# RUN echo ${USER} ${APP_UID} ${APP_GID} && exit 1 + +RUN groupadd -g ${APP_GID} ${USER} \ + && useradd -m --uid ${APP_UID} ${USER} -g ${APP_GID} \ + && mkdir -p ${DATADIR} \ + && chgrp -R ${APP_GID} ${DATADIR} \ + && chown -R "${APP_UID}:${APP_GID}" ${DATADIR} \ + && chmod -R 1007 ${DATADIR} + +WORKDIR /home/${USER} + +# Copy the downloaded binaries into the container system from the verify stage. +COPY --from=verify \ + /verify/bin/dogecoind \ + /verify/bin/dogecoin-cli \ + /verify/bin/dogecoin-tx /usr/local/bin/ + +COPY /entrypoint.py /usr/local/bin/ + +# Set permissions on copied files +RUN chmod g+x /usr/local/bin/* + +# P2P network (mainnet, testnet & regnet respectively) +EXPOSE 22556 44556 18444 + +# RPC interface (mainnet, testnet & regnet respectively) +EXPOSE 22555 44555 18332 + +VOLUME ["${DATADIR}"] + +# Dependencies install +RUN apt-get update && apt-get install --no-install-recommends -y \ + python3 \ + && rm -rf /var/lib/apt/lists/* + +USER "${APP_UID}:${APP_GID}" + +ENTRYPOINT ["entrypoint.py"] + +CMD ["dogecoind", "-reindex"] diff --git a/1.14.6/bullseye/PLATFORMS b/1.14.6/bullseye/PLATFORMS new file mode 100644 index 0000000..743dafe --- /dev/null +++ b/1.14.6/bullseye/PLATFORMS @@ -0,0 +1,4 @@ +linux/amd64 +linux/arm64 +linux/arm/v7 +linux/386 diff --git a/1.14.6/bullseye/build.sh b/1.14.6/bullseye/build.sh new file mode 100755 index 0000000..58159f2 --- /dev/null +++ b/1.14.6/bullseye/build.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +wget https://raw.githubusercontent.com/dogecoin/dogecoin/master/share/rpcuser/rpcuser.py +chmod +x rpcuser.py +./rpcuser.py dogecoin > auth +rpcauth=$(cat auth | grep "rpcauth") +rpcpassword=$(cat auth | sed '1,/Your password:/d') +echo daemon=1 > dogecoin.conf +echo server=1 >> dogecoin.conf +echo listen=1 >> dogecoin.conf +echo wallet=1 >> dogecoin.conf +echo bind=0.0.0.0:22556 >> dogecoin.conf +echo bind=[::]:22556 >> dogecoin.conf +echo rpcbind=127.0.0.1:22555 >> dogecoin.conf +echo rpcallowip=0.0.0.0/0 >> dogecoin.conf +echo rpcuser=dogecoin >> dogecoin.conf +echo $rpcauth >> dogecoin.conf +echo rpcpassword=$rpcpassword >> dogecoin.conf +echo harddustlimit=0.001 >> dogecoin.conf +echo reindex=1 +echo txindex=1 +cat dogecoin.conf > .env + +docker build --no-cache --build-arg "APP_UID=$(id -u $USER)" --build-arg "APP_GID=$(id -g $USER)" --build-arg "USER=dogecoin" -t xanimo/dogecoin:1.14.6 . +rm rpcuser.py auth dogecoin.conf diff --git a/1.14.6/bullseye/docker-compose.yml b/1.14.6/bullseye/docker-compose.yml new file mode 100644 index 0000000..13777c8 --- /dev/null +++ b/1.14.6/bullseye/docker-compose.yml @@ -0,0 +1,19 @@ +version: "3.8" + +name: dogecoin +services: + dogecoin: + build: . + image: xanimo/dogecoin:1.14.6 + volumes: + - dogecoin:/home/dogecoin/.dogecoin + env_file: + - .env + +volumes: + dogecoin: + driver: local + driver_opts: + o: bind + type: none + device: /mnt/volumes/.dogecoin \ No newline at end of file diff --git a/1.14.6/bullseye/entrypoint.py b/1.14.6/bullseye/entrypoint.py new file mode 100755 index 0000000..79b7460 --- /dev/null +++ b/1.14.6/bullseye/entrypoint.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 +""" + Docker entrypoint for Dogecoin Core +""" +import argparse +import os +# import pwd +import shutil +import sys +import subprocess + +CLI_EXECUTABLES = [ + "dogecoind", + "dogecoin-cli", + "dogecoin-tx", + ] + +def execute(executable, args): + """ + Run container command with execve(2). Use manually execve + to run the process as same pid and avoid to fork a child. + """ + executable_path = shutil.which(executable) + + if executable_path is None: + print(f"{sys.argv[0]}: {executable} not found.", file=sys.stderr) + return 1 + + #Prepare execve args & launch container command + execve_args = [executable_path] + args + return os.execve(executable_path, execve_args, os.environ) + +def get_help(command_arguments): + """Call any dogecoin executable help menu, retrieve its options""" + #Prepare menu call & grep command to pipe in a shell + menu_command = " ".join(command_arguments) + grep_command = "grep -E '^ -[a-z]+'" + + #Return a list of raw options of `-help` output + return subprocess.check_output( + f"{menu_command} | {grep_command}", + shell=True + ).decode("utf8").splitlines() + +def executable_options(executable): + """ + Retrieve available options of a dogecoin executable using help menu. + + Call executable with `-help` flag and parse output to detect available + Dogecoin Core options. + """ + command_arguments = [executable, "-help"] + + #`-help-debug` display extra flag in help menu for dogecoind & qt + if executable == "dogecoind": + command_arguments.append("-help-debug") + + help_options = get_help(command_arguments) + + #Clean raw option from the menu, keeping only variable name. + #For example, convert ` -rpcpassword=` in `rpcpassword`. + options = [] + for option_entry in help_options: + cleaned_option = option_entry.strip().split("=")[0] + cleaned_option = cleaned_option.replace("-", "", 1) + options.append(cleaned_option) + + return options + +def create_datadir(): + """ + Create data directory used by dogecoin daemon. + Create manually the directory while root at container creation, + root rights needed to create folder with host volume. + """ + #Try to get datadir from argv + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument("-datadir", "--datadir") + argv, _ = parser.parse_known_args() + + #Try to get datadir from environment + datadir = argv.datadir or os.environ.get("DATADIR") + print(datadir) + print(argv.datadir) + os.makedirs(datadir, exist_ok=True) + + app_uid = os.environ["APP_UID"] + app_gid = os.environ["APP_GID"] + user = os.environ["USER"] + subprocess.run(["chmod", "-R", "1700", datadir], check=True) + subprocess.run(["chown", "-R", f"{app_uid}:{app_gid}", f"/home/{user}/.dogecoin"], check=True) + +def convert_env(executable): + """ + Convert existing environment variables into command line arguments, + remove it from the environment. + + Options from executable man pages are searched in the environment, + converting options in upper case and convert "-" to "_". + + Exemple: + -rpcuser is RPCUSER + -help-debug is HELP_DEBUG + + Environment variables can be used with an empty value if the + corresponding option do not expect a value. + """ + man_options = executable_options(executable) + option_to_env = lambda opt_value : opt_value.upper().replace("-", "_") + + cli_arguments = [] + for option in man_options: + env_option = os.environ.pop(option_to_env(option), None) + + if env_option is not None: + cli_option = "-" + option + cli_option += "=" + env_option if env_option else "" + cli_arguments.append(cli_option) + + return cli_arguments + +def run_executable(executable, executable_args): + """ + Run selected dogecoin executable with arguments from environment and + command line. Switch manually from root rights needed at startup + to unprivileged user. + + Manually execve + setuid/setgid to run process as pid 1, + to manage a single process in a container & more predictive + signal handling. + """ + if executable == "dogecoind": + executable_args.append("-printtoconsole") + + #Switch process from root to user. + #Equivalent to use gosu or su-exec + # user_info = pwd.getpwnam(os.environ['USER']) + # os.setgid(user_info.pw_gid) + # os.setuid(user_info.pw_uid) + + #Run container command + return execute(executable, executable_args) + +def main(): + """ + Main routine + """ + + if sys.argv[1].startswith("-"): + executable = "dogecoind" + else: + executable = sys.argv.pop(1) + + #Container running arbitrary commands unrelated to dogecoin + if executable not in CLI_EXECUTABLES: + return execute(executable, sys.argv[1:]) + + create_datadir() + + executable_args = convert_env(executable) + executable_args += sys.argv[1:] + + return run_executable(executable, executable_args) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/1.14.6/bullseye/run.sh b/1.14.6/bullseye/run.sh new file mode 100755 index 0000000..60db02c --- /dev/null +++ b/1.14.6/bullseye/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +if [[ ! -d /mnt/volumes/.dogecoin ]]; then + mkdir -p /mnt/volumes/.dogecoin +fi + +if docker inspect dogecoin | grep '"Status":' | grep "running"; then + docker compose down +fi + +docker compose up diff --git a/1.14.7/bullseye/.env b/1.14.7/bullseye/.env new file mode 100644 index 0000000..20b2f12 --- /dev/null +++ b/1.14.7/bullseye/.env @@ -0,0 +1,12 @@ +daemon=1 +server=1 +listen=1 +wallet=1 +bind=0.0.0.0:22556 +bind=[::]:22556 +rpcbind=127.0.0.1:22555 +rpcallowip=0.0.0.0/0 +rpcuser=dogecoin +rpcauth=dogecoin:a1300ebb8da7f280ad66b969264c22dd$0c9869c90bfc813708540a13146c63823463ee51b5d3d6abceb11674b5eb600a +rpcpassword=jdjKm44i1UpmTicidJiaSNmUc-klDlervv_U-8uInp4 +harddustlimit=0.001 diff --git a/1.14.7/bullseye/Dockerfile b/1.14.7/bullseye/Dockerfile new file mode 100644 index 0000000..210eb41 --- /dev/null +++ b/1.14.7/bullseye/Dockerfile @@ -0,0 +1,109 @@ +FROM debian:bullseye-slim AS verify + +WORKDIR /verify + +# github repository locations +ARG REPO_GITIAN_BUILDER=https://github.com/devrandom/gitian-builder.git +ARG REPO_GITIAN_SIGS=https://github.com/dogecoin/gitian.sigs.git +ARG REPO_DOGECOIN_CORE=https://github.com/dogecoin/dogecoin.git + +# Specify release variables +ARG RLS_VERSION=1.14.7 +ARG RLS_OS=linux +ARG RLS_LIB=gnu +ARG RLS_ARCH= + +# static derived variables +ARG SIG_PATH=${RLS_VERSION}-${RLS_OS} +ARG DESCRIPTOR_PATH=dogecoin/contrib/gitian-descriptors/gitian-${RLS_OS}.yml +ARG RLS_LOCATION=https://github.com/dogecoin/dogecoin/releases/download/v${RLS_VERSION} + +# install system requirements +RUN apt-get update && apt-get install --no-install-recommends -y \ + wget \ + git \ + ruby \ + gpg \ + gpg-agent \ + && rm -rf /var/lib/apt/lists/* + +# fetch tools and setup signers +RUN bash -o pipefail \ + && git clone --depth 1 ${REPO_GITIAN_BUILDER} gitian \ + && git clone --depth 1 ${REPO_GITIAN_SIGS} sigs \ + && git clone --depth 1 -b v${RLS_VERSION} ${REPO_DOGECOIN_CORE} dogecoin \ + && find dogecoin/contrib/gitian-keys -name "*.pgp" |xargs -n 1 gpg --import + +# determine architecture, download release binary +# and verify against random OK signer and pinned shasums +RUN set -ex && ARCHITECTURE=$(dpkg --print-architecture) \ + && if [ "${ARCHITECTURE}" = "amd64" ]; then RLS_ARCH=x86_64 ; fi \ + && if [ "${ARCHITECTURE}" = "arm64" ]; then RLS_ARCH=aarch64; fi \ + && if [ "${ARCHITECTURE}" = "armhf" ]; then RLS_ARCH=arm && RLS_LIB=gnueabihf; fi \ + && if [ "${ARCHITECTURE}" = "i386" ]; then RLS_ARCH=i686-pc; fi \ + && if [ "${RLS_ARCH}" = "" ]; then echo "Could not determine architecture" >&2; exit 1; fi \ + && RLS_FILE_NAME=dogecoin-${RLS_VERSION}-${RLS_ARCH}-${RLS_OS}-${RLS_LIB}.tar.gz \ + && wget ${RLS_LOCATION}/${RLS_FILE_NAME} \ + && wget ${RLS_LOCATION}/SHA256SUMS.asc \ + && gitian/bin/gverify --no-markup -d sigs -r ${SIG_PATH} ${DESCRIPTOR_PATH} \ + | grep OK | shuf -n 1 | sed s/:.*// > random_signer.txt \ + && grep ${RLS_FILE_NAME} sigs/${SIG_PATH}/$(cat random_signer.txt)/*assert | sha256sum -c \ + && grep ${RLS_FILE_NAME} SHA256SUMS.asc | sha256sum -c \ + && tar -zxvf ${RLS_FILE_NAME} \ + dogecoin-${RLS_VERSION}/bin/dogecoind \ + dogecoin-${RLS_VERSION}/bin/dogecoin-cli \ + dogecoin-${RLS_VERSION}/bin/dogecoin-tx \ + --strip-components=1 + +COPY entrypoint.py /entrypoint.py + +FROM debian:bullseye-slim AS final + +ARG USER= +ENV USER=${USER:-"dogecoin"} +ARG APP_UID= +ENV APP_UID=${APP_UID} +ARG APP_GID= +ENV APP_GID=${APP_GID} +ENV DATADIR=/home/${USER}/.dogecoin + +# RUN echo ${USER} ${APP_UID} ${APP_GID} && exit 1 + +RUN groupadd -g ${APP_GID} ${USER} \ + && useradd -m --uid ${APP_UID} ${USER} -g ${APP_GID} \ + && mkdir -p ${DATADIR} \ + && chgrp -R ${APP_GID} ${DATADIR} \ + && chown -R "${APP_UID}:${APP_GID}" ${DATADIR} \ + && chmod -R 1007 ${DATADIR} + +WORKDIR /home/${USER} + +# Copy the downloaded binaries into the container system from the verify stage. +COPY --from=verify \ + /verify/bin/dogecoind \ + /verify/bin/dogecoin-cli \ + /verify/bin/dogecoin-tx /usr/local/bin/ + +COPY /entrypoint.py /usr/local/bin/ + +# Set permissions on copied files +RUN chmod g+x /usr/local/bin/* + +# P2P network (mainnet, testnet & regnet respectively) +EXPOSE 22556 44556 18444 + +# RPC interface (mainnet, testnet & regnet respectively) +EXPOSE 22555 44555 18332 + +VOLUME ["${DATADIR}"] + +# Dependencies install +RUN apt-get update && apt-get install --no-install-recommends -y \ + python3 \ + && rm -rf /var/lib/apt/lists/* + +USER "${APP_UID}:${APP_GID}" + +ENTRYPOINT ["entrypoint.py"] + +CMD ["dogecoind", "-reindex"] diff --git a/1.14.7/bullseye/PLATFORMS b/1.14.7/bullseye/PLATFORMS new file mode 100644 index 0000000..743dafe --- /dev/null +++ b/1.14.7/bullseye/PLATFORMS @@ -0,0 +1,4 @@ +linux/amd64 +linux/arm64 +linux/arm/v7 +linux/386 diff --git a/1.14.7/bullseye/build.sh b/1.14.7/bullseye/build.sh new file mode 100755 index 0000000..dc74dae --- /dev/null +++ b/1.14.7/bullseye/build.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +wget https://raw.githubusercontent.com/dogecoin/dogecoin/master/share/rpcuser/rpcuser.py +chmod +x rpcuser.py +./rpcuser.py dogecoin > auth +rpcauth=$(cat auth | grep "rpcauth") +rpcpassword=$(cat auth | sed '1,/Your password:/d') +echo daemon=1 > dogecoin.conf +echo server=1 >> dogecoin.conf +echo listen=1 >> dogecoin.conf +echo wallet=1 >> dogecoin.conf +echo bind=0.0.0.0:22556 >> dogecoin.conf +echo bind=[::]:22556 >> dogecoin.conf +echo rpcbind=127.0.0.1:22555 >> dogecoin.conf +echo rpcallowip=0.0.0.0/0 >> dogecoin.conf +echo rpcuser=dogecoin >> dogecoin.conf +echo $rpcauth >> dogecoin.conf +echo rpcpassword=$rpcpassword >> dogecoin.conf +echo harddustlimit=0.001 >> dogecoin.conf +echo reindex=1 +echo txindex=1 +cat dogecoin.conf > .env + +docker build --no-cache --build-arg "APP_UID=$(id -u $USER)" --build-arg "APP_GID=$(id -g $USER)" --build-arg "USER=dogecoin" -t xanimo/dogecoin:1.14.7 . +rm rpcuser.py auth dogecoin.conf diff --git a/1.14.7/bullseye/docker-compose.yml b/1.14.7/bullseye/docker-compose.yml new file mode 100644 index 0000000..956d7d2 --- /dev/null +++ b/1.14.7/bullseye/docker-compose.yml @@ -0,0 +1,19 @@ +version: "3.8" + +name: dogecoin +services: + dogecoin: + build: . + image: xanimo/dogecoin:1.14.7 + volumes: + - dogecoin:/home/dogecoin/.dogecoin + env_file: + - .env + +volumes: + dogecoin: + driver: local + driver_opts: + o: bind + type: none + device: /mnt/volumes/.dogecoin \ No newline at end of file diff --git a/1.14.7/bullseye/entrypoint.py b/1.14.7/bullseye/entrypoint.py new file mode 100755 index 0000000..79b7460 --- /dev/null +++ b/1.14.7/bullseye/entrypoint.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 +""" + Docker entrypoint for Dogecoin Core +""" +import argparse +import os +# import pwd +import shutil +import sys +import subprocess + +CLI_EXECUTABLES = [ + "dogecoind", + "dogecoin-cli", + "dogecoin-tx", + ] + +def execute(executable, args): + """ + Run container command with execve(2). Use manually execve + to run the process as same pid and avoid to fork a child. + """ + executable_path = shutil.which(executable) + + if executable_path is None: + print(f"{sys.argv[0]}: {executable} not found.", file=sys.stderr) + return 1 + + #Prepare execve args & launch container command + execve_args = [executable_path] + args + return os.execve(executable_path, execve_args, os.environ) + +def get_help(command_arguments): + """Call any dogecoin executable help menu, retrieve its options""" + #Prepare menu call & grep command to pipe in a shell + menu_command = " ".join(command_arguments) + grep_command = "grep -E '^ -[a-z]+'" + + #Return a list of raw options of `-help` output + return subprocess.check_output( + f"{menu_command} | {grep_command}", + shell=True + ).decode("utf8").splitlines() + +def executable_options(executable): + """ + Retrieve available options of a dogecoin executable using help menu. + + Call executable with `-help` flag and parse output to detect available + Dogecoin Core options. + """ + command_arguments = [executable, "-help"] + + #`-help-debug` display extra flag in help menu for dogecoind & qt + if executable == "dogecoind": + command_arguments.append("-help-debug") + + help_options = get_help(command_arguments) + + #Clean raw option from the menu, keeping only variable name. + #For example, convert ` -rpcpassword=` in `rpcpassword`. + options = [] + for option_entry in help_options: + cleaned_option = option_entry.strip().split("=")[0] + cleaned_option = cleaned_option.replace("-", "", 1) + options.append(cleaned_option) + + return options + +def create_datadir(): + """ + Create data directory used by dogecoin daemon. + Create manually the directory while root at container creation, + root rights needed to create folder with host volume. + """ + #Try to get datadir from argv + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument("-datadir", "--datadir") + argv, _ = parser.parse_known_args() + + #Try to get datadir from environment + datadir = argv.datadir or os.environ.get("DATADIR") + print(datadir) + print(argv.datadir) + os.makedirs(datadir, exist_ok=True) + + app_uid = os.environ["APP_UID"] + app_gid = os.environ["APP_GID"] + user = os.environ["USER"] + subprocess.run(["chmod", "-R", "1700", datadir], check=True) + subprocess.run(["chown", "-R", f"{app_uid}:{app_gid}", f"/home/{user}/.dogecoin"], check=True) + +def convert_env(executable): + """ + Convert existing environment variables into command line arguments, + remove it from the environment. + + Options from executable man pages are searched in the environment, + converting options in upper case and convert "-" to "_". + + Exemple: + -rpcuser is RPCUSER + -help-debug is HELP_DEBUG + + Environment variables can be used with an empty value if the + corresponding option do not expect a value. + """ + man_options = executable_options(executable) + option_to_env = lambda opt_value : opt_value.upper().replace("-", "_") + + cli_arguments = [] + for option in man_options: + env_option = os.environ.pop(option_to_env(option), None) + + if env_option is not None: + cli_option = "-" + option + cli_option += "=" + env_option if env_option else "" + cli_arguments.append(cli_option) + + return cli_arguments + +def run_executable(executable, executable_args): + """ + Run selected dogecoin executable with arguments from environment and + command line. Switch manually from root rights needed at startup + to unprivileged user. + + Manually execve + setuid/setgid to run process as pid 1, + to manage a single process in a container & more predictive + signal handling. + """ + if executable == "dogecoind": + executable_args.append("-printtoconsole") + + #Switch process from root to user. + #Equivalent to use gosu or su-exec + # user_info = pwd.getpwnam(os.environ['USER']) + # os.setgid(user_info.pw_gid) + # os.setuid(user_info.pw_uid) + + #Run container command + return execute(executable, executable_args) + +def main(): + """ + Main routine + """ + + if sys.argv[1].startswith("-"): + executable = "dogecoind" + else: + executable = sys.argv.pop(1) + + #Container running arbitrary commands unrelated to dogecoin + if executable not in CLI_EXECUTABLES: + return execute(executable, sys.argv[1:]) + + create_datadir() + + executable_args = convert_env(executable) + executable_args += sys.argv[1:] + + return run_executable(executable, executable_args) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/1.14.7/bullseye/run.sh b/1.14.7/bullseye/run.sh new file mode 100755 index 0000000..60db02c --- /dev/null +++ b/1.14.7/bullseye/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +if [[ ! -d /mnt/volumes/.dogecoin ]]; then + mkdir -p /mnt/volumes/.dogecoin +fi + +if docker inspect dogecoin | grep '"Status":' | grep "running"; then + docker compose down +fi + +docker compose up diff --git a/build b/build new file mode 100755 index 0000000..d3e053f --- /dev/null +++ b/build @@ -0,0 +1,5 @@ +#!/bin/bash + +pushd ./1.14.7/bullseye/ +./build.sh +popd diff --git a/run b/run new file mode 100755 index 0000000..d836aad --- /dev/null +++ b/run @@ -0,0 +1,5 @@ +#!/bin/bash + +pushd ./1.14.7/bullseye/ +docker compose up +popd diff --git a/tests/integration/version.py b/tests/integration/version.py index b8be289..524926d 100644 --- a/tests/integration/version.py +++ b/tests/integration/version.py @@ -19,7 +19,7 @@ def __init__(self): def add_options(self, parser): """Add test-specific --version option""" parser.add_argument("--version", dest="version", required=True, - help="The version that is expected to be installed, eg: '1.14.5'") + help="The version that is expected to be installed, eg: '1.14.7'") def run_test(self): """Check the version of each executable""" diff --git a/tests/integration_runner.py b/tests/integration_runner.py index 9506f5e..8f9a065 100644 --- a/tests/integration_runner.py +++ b/tests/integration_runner.py @@ -33,7 +33,7 @@ def __init__(self): def add_options(self, parser): """Add test-specific --version option""" parser.add_argument("--version", dest="version", required=True, - help="The version that is expected to be installed, eg: '1.14.5'") + help="The version that is expected to be installed, eg: '1.14.7'") def run_test(self): """Run all specified tests and inherit any failures"""