1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-20 14:54:15 +01:00

fix conflict

This commit is contained in:
Du Peng 2022-06-07 16:57:02 +02:00
commit ac16eca60f
24 changed files with 174 additions and 71 deletions

View File

@ -42,6 +42,7 @@ Dockerfile
docker-compose*
test
.env
.docker
# Docs
*.md

View File

@ -5,6 +5,20 @@
- Fix a bug: admins are shown in select member for reservation by admin
- Fix a bug: unable to show tours in machines and spaces page
- Check shopping cart items is valid before pay online
- Updated sidekiq-unique-jobs to 7.1.23 to get rid of Sidekiq's default_worker_options deprecation warning
- Allow moving with arrows in the setup script's inputs
- Ability to ignore assets compilation errors in the upgrade script
- Fix a bug: unable to connect with OAuth2
- Fix a bug: when installing fab-manager as non-root user, most of the resulting installation directories were owned by root
- Fix a bug: unable to edit OIDC provider
- Fix a bug: list of OIDC scopes are loading indefinitely
- [TODO DEPLOY] `\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/scripts/use-relative-paths.sh | bash`
## v5.4.3 2022 June 6
- Updated translations
- Fix a bug: deprecated bundler arguments (#362)
- Fix a bug: unable to compile the assets when OIDC is enabled but the scopes were not set
## v5.4.2 2022 June 1

View File

@ -1,6 +1,9 @@
FROM ruby:2.6.10-alpine
MAINTAINER contact@fab-manager.com
RUN addgroup --gid 1000 fabmanager && \
adduser --uid 1000 -G fabmanager -s /bin/bash -D fabmanager
# Install upgrade system packages
RUN apk update && apk upgrade && \
# Install runtime apk dependencies
@ -46,7 +49,12 @@ RUN bundle config --global frozen 1
WORKDIR /tmp
COPY Gemfile /tmp/
COPY Gemfile.lock /tmp/
RUN bundle install --binstubs --without development test doc
RUN bundle config set --local without 'development test doc' && bundle install && bundle binstubs --all
# Prepare the application directory
RUN mkdir -p /usr/src/app && chown -R fabmanager:fabmanager /usr/src/app
# Change to non-root user
USER fabmanager
# Install Javascript packages
WORKDIR /usr/src/app
@ -55,6 +63,7 @@ COPY yarn.lock /usr/src/app/yarn.lock
RUN yarn install
# Clean up build deps, cached packages and temp files
USER root
RUN apk del .build-deps && \
yarn cache clean && \
rm -rf /tmp/* \
@ -63,24 +72,15 @@ RUN apk del .build-deps && \
/usr/lib/ruby/gems/*/cache/*
# Web app
RUN mkdir -p /usr/src/app && \
mkdir -p /usr/src/app/config && \
mkdir -p /usr/src/app/invoices && \
mkdir -p /usr/src/app/payment_schedules && \
mkdir -p /usr/src/app/exports && \
mkdir -p /usr/src/app/imports && \
mkdir -p /usr/src/app/log && \
mkdir -p /usr/src/app/public/uploads && \
mkdir -p /usr/src/app/public/packs && \
mkdir -p /usr/src/app/accounting && \
mkdir -p /usr/src/app/proof_of_identity_files && \
mkdir -p /usr/src/app/tmp/sockets && \
USER fabmanager
RUN mkdir -p /usr/src/app/tmp/sockets && \
mkdir -p /usr/src/app/tmp/pids
# Copy source files
COPY docker/database.yml /usr/src/app/config/database.yml
COPY . /usr/src/app
# Volumes
# Volumes (the folders are created by setup.sh)
VOLUME /usr/src/app/invoices
VOLUME /usr/src/app/payment_schedules
VOLUME /usr/src/app/exports

View File

@ -92,7 +92,7 @@ gem 'aasm'
gem 'sidekiq', '>= 6.0.7'
# Recurring jobs for Sidekiq
gem 'sidekiq-scheduler'
gem 'sidekiq-unique-jobs', '~> 7.1.15'
gem 'sidekiq-unique-jobs', '~> 7.1.23'
gem 'stripe', '5.29.0'

View File

@ -398,7 +398,7 @@ GEM
rufus-scheduler (~> 3.2)
sidekiq (>= 4)
tilt (>= 1.4.0)
sidekiq-unique-jobs (7.1.15)
sidekiq-unique-jobs (7.1.23)
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
concurrent-ruby (~> 1.0, >= 1.0.5)
sidekiq (>= 5.0, < 8.0)
@ -546,7 +546,7 @@ DEPENDENCIES
shakapacker (= 6.2.0)
sidekiq (>= 6.0.7)
sidekiq-scheduler
sidekiq-unique-jobs (~> 7.1.15)
sidekiq-unique-jobs (~> 7.1.23)
spring
spring-watcher-listen (~> 2.0.0)
stripe (= 5.29.0)

View File

@ -1,3 +1,3 @@
web: bundle exec rails server puma -p $PORT
#web: bundle exec rails server puma -p $PORT
worker: bundle exec sidekiq -C ./config/sidekiq.yml
webpack: bin/webpacker-dev-server

View File

@ -72,7 +72,7 @@ export const OpenidConnectForm = <TFieldValues extends FieldValues, TContext ext
const unlisted = difference(current, scopesAvailable);
callback(scopesAvailable.concat(unlisted).map(scope => ({ value: scope, label: scope })));
} else {
current.map(scope => ({ value: scope, label: scope }));
callback(current.map(scope => ({ value: scope, label: scope })));
}
};

View File

@ -18,7 +18,7 @@ class OpenIdConnectProvider < ApplicationRecord
validates :client_auth_method, inclusion: { in: %w[basic jwks] }
def scope
self[:scope].join(' ')
self[:scope]&.join(' ')
end
def config

View File

@ -12,9 +12,10 @@ end
if @provider.providable_type == OpenIdConnectProvider.name
json.providable_attributes do
json.extract! @provider.providable, :id, :issuer, :discovery, :client_auth_method, :scope,
json.extract! @provider.providable, :id, :issuer, :discovery, :client_auth_method,
:prompt, :send_scope_to_token_endpoint, :client__identifier, :client__secret, :client__authorization_endpoint,
:client__token_endpoint, :client__userinfo_endpoint, :client__jwks_uri, :client__end_session_endpoint, :profile_url
json.scope @provider.providable[:scope]
end
end

View File

@ -995,7 +995,7 @@ fr:
my_documents: "Mes documents"
my_documents_info: "Suite à la déclaration de votre profil, vous devez déclarer des justificatifs. Une fois déposés, ces documents vont être vérifiés par l'administrateur."
proof_of_identity_file_size_error: "La limite de poids est de {SIZE} Mo max"
my_documents_alert: "Attention !</br>Vous pouvez déposer vos documents en pdf ou en image (jpg) sous une limit de poids de {SIZE} Mo max"
my_documents_alert: "Attention !</br>Vous pouvez déposer vos documents en pdf ou en image (.jpg) sous une limite de poids de {SIZE} Mo max"
proof_of_identity_files: "Justificatifs"
find_below_the_proof_of_identity_files: "Retrouvez ci-dessous, les justificatifs déposés par le membre."
save: "Enregistrer"

View File

@ -527,3 +527,5 @@ de:
payzen_card_update_modal:
update_card: "Karte aktualisieren"
validate_button: "Neue Karte validieren"
form_multi_select:
create_label: "Add {VALUE}"

View File

@ -527,3 +527,5 @@ es:
payzen_card_update_modal:
update_card: "Update the card"
validate_button: "Validate the new card"
form_multi_select:
create_label: "Add {VALUE}"

View File

@ -527,3 +527,5 @@ fr:
payzen_card_update_modal:
update_card: "Mettre à jour la carte"
validate_button: "Valider la nouvelle carte"
form_multi_select:
create_label: "Ajouter {VALUE}"

View File

@ -527,3 +527,5 @@
payzen_card_update_modal:
update_card: "Oppdater kortet"
validate_button: "Valider det nye kortet"
form_multi_select:
create_label: "Add {VALUE}"

View File

@ -527,3 +527,5 @@ pt:
payzen_card_update_modal:
update_card: "Atualizar o cartão"
validate_button: "Verificar o novo cartão"
form_multi_select:
create_label: "Add {VALUE}"

View File

@ -527,3 +527,5 @@ zu:
payzen_card_update_modal:
update_card: "crwdns21512:0crwdne21512:0"
validate_button: "crwdns21514:0crwdne21514:0"
form_multi_select:
create_label: "crwdns23124:0{VALUE}crwdne23124:0"

View File

@ -346,7 +346,7 @@ fr:
date: "Ceci est un rappel pour vérifier que le prélèvement bancaire a bien été effectué."
confirm: "Veuillez confirmer la réception des fonds dans votre interface de gestion des échéanciers de paiement, afin que la facture correspondante soit générée."
notify_admin_user_proof_of_identity_files_created:
subject: "Justufucatif téléversé par un membre"
subject: "Justificatif téléversé par un membre"
body:
proof_of_identity_files_uploaded_below: "Le membre %{NAME} a téléversé le justificatif suivant :"
validate_user: "Veuillez valider ce compte"

View File

@ -8,7 +8,6 @@ logfile_maxbytes=10MB ; maximum size of logfile befor
logfile_backups=100 ; number of backed up logfiles
loglevel=info ; info, debug, warn, trace
pidfile=/var/run/supervisord.pid ; pidfile location
user=root ; default user
childlogdir=/var/log/supervisor/ ; where child log files will live
[supervisorctl]

View File

@ -30,7 +30,7 @@ module OmniAuth::Strategies
def authorize_params
super.tap do |params|
params[:scope] = active_provider.providable.scopes
params[:scope] = OmniAuth::Strategies::SsoOauth2Provider.active_provider.providable.scopes
end
end

View File

@ -1,6 +1,6 @@
{
"name": "fab-manager",
"version": "5.4.2",
"version": "5.4.3",
"description": "Fab-manager is the FabLab management solution. It provides a comprehensive, web-based, open-source tool to simplify your administrative tasks and your marker's projects.",
"keywords": [
"fablab",

30
scripts/use-relative-paths.sh Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env bash
# This script changes the paths in the docker-compose.yml file to use relative paths
# Previously, we were using ${PWD} to get the path to the current directory, but this
# caused issues when running a script from a different directory with "docker-compose -f".
config()
{
echo "Checking docker-compose file... "
FABMANAGER_PATH=$(pwd)
if [ ! -w "$FABMANAGER_PATH/docker-compose.yml" ]; then
echo "Fab-manager's docker-compose.yml file not found or not writable."
echo "Please run this script from the installation folder, and as a user having write access on docker-compose.yml"
exit 1
fi
}
rename()
{
echo "Renaming paths... "
sed -i.bak "s/\${PWD}/\./g" "$FABMANAGER_PATH/docker-compose.yml"
}
proceed()
{
config
rename
}
proceed "$@"

View File

@ -6,18 +6,18 @@ services:
RAILS_ENV: production
RACK_ENV: production
env_file:
- ${PWD}/config/env
- ./config/env
volumes:
- ${PWD}/public/packs:/usr/src/app/public/packs
- ${PWD}/public/uploads:/usr/src/app/public/uploads
- ${PWD}/invoices:/usr/src/app/invoices
- ${PWD}/payment_schedules:/usr/src/app/payment_schedules
- ${PWD}/exports:/usr/src/app/exports
- ${PWD}/imports:/usr/src/app/imports
- ${PWD}/proof_of_identity_files:/usr/src/app/proof_of_identity_files
- ${PWD}/log:/var/log/supervisor
- ${PWD}/plugins:/usr/src/app/plugins
- ${PWD}/accounting:/usr/src/app/accounting
- ./public/packs:/usr/src/app/public/packs
- ./public/uploads:/usr/src/app/public/uploads
- ./invoices:/usr/src/app/invoices
- ./payment_schedules:/usr/src/app/payment_schedules
- ./exports:/usr/src/app/exports
- ./imports:/usr/src/app/imports
- ./proof_of_identity_files:/usr/src/app/proof_of_identity_files
- ./log:/var/log/supervisor
- ./plugins:/usr/src/app/plugins
- ./accounting:/usr/src/app/accounting
depends_on:
- postgres
- redis
@ -27,7 +27,7 @@ services:
postgres:
image: postgres:9.6
volumes:
- ${PWD}/postgresql:/var/lib/postgresql/data
- ./postgresql:/var/lib/postgresql/data
restart: always
environment:
POSTGRES_HOST_AUTH_METHOD: trust
@ -41,14 +41,14 @@ services:
soft: -1
hard: -1
volumes:
- ${PWD}/elasticsearch/config:/usr/share/elasticsearch/config
- ${PWD}/elasticsearch:/usr/share/elasticsearch/data
- ./elasticsearch/config:/usr/share/elasticsearch/config
- ./elasticsearch:/usr/share/elasticsearch/data
restart: always
redis:
image: redis:6-alpine
volumes:
- ${PWD}/redis:/data
- ./redis:/data
restart: always
nginx:
@ -57,9 +57,9 @@ services:
- "80:80"
- "443:443"
volumes:
- ${PWD}/config/nginx:/etc/nginx/conf.d
- ${PWD}/letsencrypt/etc:/etc/letsencrypt
- ${PWD}/log:/var/log/nginx
- ./config/nginx:/etc/nginx/conf.d
- ./letsencrypt/etc:/etc/letsencrypt
- ./log:/var/log/nginx
volumes_from:
- fabmanager:ro
links:

View File

@ -117,7 +117,7 @@ elevate_cmd()
read_email()
{
local email
read -rp "Please input a valid email address > " email </dev/tty
read -rep "Please input a valid email address > " email </dev/tty
if [[ "$email" == *"@"*"."* ]]; then
EMAIL="$email"
else
@ -152,7 +152,7 @@ config()
read_domain()
{
read -rp 'Please input the domain name > ' domain </dev/tty
read -rep 'Please input the domain name > ' domain </dev/tty
if [[ "$domain" == *"."* ]]; then
DOMAINS+=("$domain")
else
@ -174,10 +174,15 @@ prepare_files()
read -rp "Continue? (Y/n) " confirm </dev/tty
if [[ "$confirm" = "n" ]]; then exit 1; fi
elevate_cmd mkdir -p "$FABMANAGER_PATH/config"
elevate_cmd chown -R "$(whoami)" "$FABMANAGER_PATH"
elevate_cmd mkdir -p "$FABMANAGER_PATH"
elevate_cmd chown -R "$(whoami):$(whoami)" "$FABMANAGER_PATH"
mkdir -p "$FABMANAGER_PATH/elasticsearch/config"
# create folders before starting the containers, otherwise root will own them
local folders=(accounting config elasticsearch/config exports imports invoices log payment_schedules plugins postgresql \
proof_of_identity_files public/packs public/uploads)
for folder in "${folders[@]}"; do
mkdir -p "$FABMANAGER_PATH/$folder"
done
# Fab-manager environment variables
\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/setup/env.example > "$FABMANAGER_PATH/config/env"
@ -228,7 +233,7 @@ prepare_nginx()
printf "The two following configurations are useful if you want to install Fab-manager behind a reverse proxy...\n"
read -rp "- Do you want to map the Fab-manager's service to an external network? (Y/n) " confirm </dev/tty
if [ "$confirm" != "n" ]; then
read -rp "Please input the name of the external network (default: web) " network </dev/tty
read -rep "Please input the name of the external network (default: web) " network </dev/tty
if [ "$network" = "" ]; then network="web"; fi
echo "Adding a network configuration to the docker-compose.yml file..."
@ -248,7 +253,7 @@ prepare_nginx()
if [ "$confirm" != "n" ]; then
current="$(yq eval '.services.*.image | select(. == "sleede/fab-manager*") | path | .[-2]' docker-compose.yml)"
printf "=======================\n- \e[1mCurrent value: %s\e[21m\n- New value? (leave empty to keep the current value)\n" "$current"
read -rp " > " value </dev/tty
read -rep " > " value </dev/tty
echo "======================="
if [ "$value" != "" ]; then
escaped=$(printf '%s\n' "$value" | iconv -f utf8 -t ascii//TRANSLIT//IGNORE | sed -e 's/[^a-zA-Z0-9-]/_/g')
@ -331,7 +336,7 @@ configure_env_file()
printf "**** \e[1mDocumentation:\e[21m ****\n"
echo "$var_doc"
printf "=======================\n- \e[1mCurrent value: %s\e[21m\n- New value? (leave empty to keep the current value)\n" "$current"
read -rp " > " value </dev/tty
read -rep " > " value </dev/tty
echo "======================="
if [ "$value" != "" ]; then
esc_val=$(printf '%s\n' "$value" | sed -e 's/\//\\\//g')
@ -340,7 +345,7 @@ configure_env_file()
fi
done
# we automatically generate the SECRET_KEY_BASE
secret=$(cd "$FABMANAGER_PATH" && docker-compose run --rm "$SERVICE" bundle exec rake secret)
secret=$(docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake secret)
sed -i.bak "s/SECRET_KEY_BASE=/SECRET_KEY_BASE=$secret/g" "$FABMANAGER_PATH/config/env"
}
@ -370,32 +375,32 @@ setup_assets_and_databases()
read -rp "Continue? (Y/n) " confirm </dev/tty
if [ "$confirm" = "n" ]; then return; fi
cd "$FABMANAGER_PATH" && docker-compose run --rm "$SERVICE" bundle exec rake db:create # create the database
cd "$FABMANAGER_PATH" && docker-compose run --rm "$SERVICE" bundle exec rake db:migrate # run all the migrations
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake db:create # create the database
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake db:migrate # run all the migrations
# prompt default admin email/password
printf "\n\nWe will now create the default administrator of Fab-manager.\n"
read_email
PASSWORD=$(read_password)
printf "\nOK. We will fill the database now...\n"
cd "$FABMANAGER_PATH" && docker-compose run --rm -e ADMIN_EMAIL="$EMAIL" -e ADMIN_PASSWORD="$PASSWORD" "$SERVICE" bundle exec rake db:seed # seed the database
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm -e ADMIN_EMAIL="$EMAIL" -e ADMIN_PASSWORD="$PASSWORD" "$SERVICE" bundle exec rake db:seed # seed the database
# now build the assets
if ! docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --rm "$SERVICE" bundle exec rake assets:precompile; then
if ! docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake assets:precompile; then
echo -e "\e[91m[ ❌ ] someting went wrong while compiling the assets, exiting...\e[39m" && exit 1
fi
# and prepare elasticsearch
cd "$FABMANAGER_PATH" && docker-compose run --rm "$SERVICE" bundle exec rake fablab:es:build_stats
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake fablab:es:build_stats
}
stop()
{
cd "$FABMANAGER_PATH" && docker-compose down
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" down
}
start()
{
cd "$FABMANAGER_PATH" && docker-compose up -d
docker-compose -f "$FABMANAGER_PATH/docker-compose.yml" up -d
}
enable_ssl()

View File

@ -40,7 +40,7 @@ yq() {
}
jq() {
docker run --rm -i -v "${PWD}:/data" imega/jq "$@"
docker run --rm -i -v "${PWD}:/data" --user "$UID" imega/jq "$@"
}
docker-compose()
@ -58,6 +58,43 @@ docker-compose()
fi
}
has_sudo()
{
local prompt
prompt=$(sudo -nv 2>&1)
if [ $? -eq 0 ]; then
echo "has_sudo__pass_set"
elif echo $prompt | grep -q '^sudo:'; then
echo "has_sudo__needs_pass"
else
echo "no_sudo"
fi
}
elevate_cmd()
{
local cmd=$@
HAS_SUDO=$(has_sudo)
case "$HAS_SUDO" in
has_sudo__pass_set)
sudo $cmd
;;
has_sudo__needs_pass)
echo "Please supply sudo password for the following command: sudo $cmd"
sudo $cmd
;;
*)
echo "Please supply root password for the following command: su -c \"$cmd\""
su -c "$cmd"
;;
esac
}
# set $SERVICE and $YES_ALL
config()
{
@ -125,9 +162,9 @@ version_error()
# set $VERSION
version_check()
{
VERSION=$(docker-compose exec -T "$SERVICE" cat .fabmanager-version 2>/dev/null)
VERSION=$(docker-compose exec --user "$(id -u):$(id -g)" -T "$SERVICE" cat .fabmanager-version 2>/dev/null)
if [[ $? = 1 ]]; then
VERSION=$(docker-compose exec -T "$SERVICE" cat package.json | jq -r '.version')
VERSION=$(docker-compose exec --user "$(id -u):$(id -g)" -T "$SERVICE" cat package.json | jq -r '.version')
fi
target_version
if [ "$TARGET" = 'custom' ]; then return; fi
@ -184,14 +221,18 @@ compile_assets()
fi
PG_NET_ID=$(docker inspect "$PG_ID" -f "{{json .NetworkSettings.Networks }}" | jq -r '.[] .NetworkID')
clean_env_file
mkdir -p public/new_packs
# shellcheck disable=SC2068
if ! docker run --rm --env-file ./config/env ${ENV_ARGS[@]} --link "$PG_ID" --net "$PG_NET_ID" -v "${PWD}/public/new_packs:/usr/src/app/public/packs" "$IMAGE" bundle exec rake assets:precompile; then
restore_tag
printf "\e[91m[ ❌ ] Something went wrong while compiling the assets, please check the logs above.\e[39m\nExiting...\n"
exit 4
if ! docker run --user "$(id -u):$(id -g)" --rm --env-file ./config/env ${ENV_ARGS[@]} --link "$PG_ID" --net "$PG_NET_ID" -v "${PWD}/public/new_packs:/usr/src/app/public/packs" "$IMAGE" bundle exec rake assets:precompile; then
printf "\e[93m[ ⚠ ] Something may have went wrong while compiling the assets, please check the logs above.\e[39m\n"
[[ "$YES_ALL" = "true" ]] && confirm="y" || read -rp ":: Ignore and continue? (Y/n) " confirm </dev/tty
if [[ "$confirm" = "n" ]]; then restore_tag; echo "Exiting..."; exit 4; fi
fi
docker-compose down
rm -rf public/packs
if ! rm -rf public/packs; then
# sometimes we can't delete the packs folder, because of a permission issue. In that case try with sudo
elevate_cmd rm -rf public/packs
fi
mv public/new_packs public/packs
}
@ -239,21 +280,21 @@ upgrade()
done
for PRE in "${PREPROCESSING[@]}"; do
printf "\e[91m::\e[0m \e[1mRunning preprocessing command %s...\e[0m\n" "$PRE"
if ! docker-compose run --rm "$SERVICE" bundle exec "$PRE" </dev/tty; then
if ! docker-compose run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec "$PRE" </dev/tty; then
restore_tag
printf "\e[91m[ ❌ ] Something went wrong while running \"%s\", please check the logs above.\e[39m\nExiting...\n" "$PRE"
exit 4
fi
done
compile_assets
if ! docker-compose run --rm "$SERVICE" bundle exec rake db:migrate; then
if ! docker-compose run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec rake db:migrate; then
restore_tag
printf "\e[91m[ ❌ ] Something went wrong while migrating the database, please check the logs above.\e[39m\nExiting...\n"
exit 4
fi
for COMMAND in "${COMMANDS[@]}"; do
printf "\e[91m::\e[0m \e[1mRunning command %s...\e[0m\n" "$COMMAND"
if ! docker-compose run --rm "$SERVICE" bundle exec "$COMMAND" </dev/tty; then
if ! docker-compose run --user "$(id -u):$(id -g)" --rm "$SERVICE" bundle exec "$COMMAND" </dev/tty; then
restore_tag
printf "\e[91m[ ❌ ] Something went wrong while running \"%s\", please check the logs above.\e[39m\nExiting...\n" "$COMMAND"
exit 4