diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 264b718..673b3ff 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -19,10 +19,10 @@ jobs: - name: Install ldap dependencies run: sudo apt-get install libldap2-dev libsasl2-dev - uses: actions/checkout@v2 - - name: Set up Python 3.8 + - name: Set up Python 3.13 uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: 3.13 - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.pylintrc b/.pylintrc index 52376fb..e76c0ae 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,7 +1,6 @@ [MASTER] ignore = ,input persistent = yes -load-plugins = pylint_quotes [MESSAGES CONTROL] disable = @@ -10,7 +9,6 @@ disable = duplicate-code, no-member, parse-error, - bad-continuation, too-few-public-methods, global-statement, cyclic-import, @@ -28,23 +26,21 @@ disable = consider-iterating-dictionary, inconsistent-return-statements, consider-using-dict-items, - modified-iterating-dict + modified-iterating-dict, + too-many-arguments, + too-many-positional-arguments, + broad-exception-caught, +check-quote-consistency=yes [REPORTS] output-format = text -files-output = no reports = no [FORMAT] max-line-length = 120 -max-statement-lines = 75 single-line-if-stmt = no -no-space-check = trailing-comma,dict-separator max-module-lines = 1000 indent-string = ' ' -string-quote=single-avoid-escape -triple-quote=single -docstring-quote=double [MISCELLANEOUS] notes = FIXME,XXX,TODO @@ -91,7 +87,6 @@ good-names=logger,id,ID bad-names=foo,bar,baz,toto,tutu,tata # List of builtins function names that should not be used, separated by a comma -bad-functions=apply,input [DESIGN] max-args = 10 @@ -106,4 +101,4 @@ min-public-methods = 2 max-public-methods = 20 [EXCEPTIONS] -overgeneral-exceptions = Exception +overgeneral-exceptions = builtins.Exception diff --git a/Dockerfile b/Dockerfile index 42eff77..ad53cce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9-trixie +FROM python:3.13-trixie WORKDIR /opt/proxstar RUN apt-get update -y && apt-get install -y python3-dev libldap2-dev libsasl2-dev ldap-utils git COPY requirements.txt . diff --git a/HACKING/docker-compose.yml b/HACKING/docker-compose.yml index 331e0ee..d25713e 100644 --- a/HACKING/docker-compose.yml +++ b/HACKING/docker-compose.yml @@ -21,7 +21,7 @@ services: proxstar-rq-scheduler: build: context: .. - env_file: .env.local + env_file: .env entrypoint: ./start_scheduler.sh networks: - proxstar @@ -30,7 +30,7 @@ services: proxstar-rq: build: context: .. - env_file: .env.local + env_file: .env entrypoint: ./start_worker.sh networks: - proxstar @@ -42,7 +42,7 @@ services: ports: - "8000:8000" - "8001:8001" - env_file: .env.local + env_file: .env entrypoint: ["gunicorn", "proxstar:app", "--bind=0.0.0.0:8000"] networks: - proxstar diff --git a/README.md b/README.md index a50747b..3203d78 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ Proxstar =========== -[![Python 3.8](https://img.shields.io/badge/python-3.8-blue.svg)](https://www.python.org/downloads/release/python-380/) +[![Python 3.13](https://img.shields.io/badge/python-3.13-blue.svg)](https://www.python.org/downloads/release/python-3130/) +[![Proxstar](https://github.com/ComputerScienceHouse/proxstar/actions/workflows/python-app.yml/badge.svg)](https://github.com/ComputerScienceHouse/proxstar/actions/workflows/python-app.yml) Proxstar is a proxmox VM web management tool used by [Rochester Institute of Technology](https://rit.edu/)'s [Computer Science House](https://csh.rit.edu). diff --git a/config.py b/config.py index 95a8891..30270fe 100644 --- a/config.py +++ b/config.py @@ -23,13 +23,8 @@ # OIDC OIDC_ISSUER = environ.get('PROXSTAR_OIDC_ISSUER', 'https://sso.csh.rit.edu/auth/realms/csh') -OIDC_CLIENT_CONFIG = { - 'client_id': environ.get('PROXSTAR_CLIENT_ID', 'proxstar'), - 'client_secret': environ.get('PROXSTAR_CLIENT_SECRET', ''), - 'post_logout_redirect_uris': [ - environ.get('PROXSTAR_REDIRECT_URI', 'https://proxstar.csh.rit.edu/logout') - ], -} +OIDC_CLIENT_ID = environ.get('PROXSTAR_CLIENT_ID', 'proxstar') +OIDC_CLIENT_SECRET = environ.get('PROXSTAR_CLIENT_SECRET', '') # Proxmox PROXMOX_HOSTS = [host.strip() for host in environ.get('PROXSTAR_PROXMOX_HOSTS', '').split(',')] @@ -55,7 +50,10 @@ # REDIS REDIS_HOST = environ.get('PROXSTAR_REDIS_HOST', 'localhost') -RQ_DASHBOARD_REDIS_HOST = environ.get('PROXSTAR_REDIS_HOST', 'localhost') +RQ_DASHBOARD_REDIS_URL = ( + "redis://" + environ.get('PROXSTAR_REDIS_HOST', 'localhost') + ":" + + environ.get('PROXSTAR_REDIS_PORT', '6379') + "/0" +) REDIS_PORT = int(environ.get('PROXSTAR_REDIS_PORT', '6379')) # VNC diff --git a/gunicorn.conf.py b/gunicorn.conf.py index dcfadfe..82d2349 100644 --- a/gunicorn.conf.py +++ b/gunicorn.conf.py @@ -14,7 +14,7 @@ def start_websockify(websockify_path, target_file): - result = subprocess.run(['pgrep', 'websockify'], stdout=subprocess.PIPE) + result = subprocess.run(['pgrep', 'websockify'], stdout=subprocess.PIPE, check=False) if not result.stdout: print("Websockify is stopped. Starting websockify.") proxstar_port = app.config.get('WEBSOCKIFY_PORT') @@ -34,6 +34,6 @@ def start_websockify(websockify_path, target_file): print("Websockify started.") -def on_starting(server): +def on_starting(server): # pylint: disable=unused-argument print("Booting Websockify server in daemon mode...") start_websockify(app.config['WEBSOCKIFY_PATH'], app.config['WEBSOCKIFY_TARGET_FILE']) diff --git a/proxstar/__init__.py b/proxstar/__init__.py index 8f2795a..0efd28e 100644 --- a/proxstar/__init__.py +++ b/proxstar/__init__.py @@ -29,6 +29,7 @@ from sentry_sdk.integrations.flask import FlaskIntegration from sentry_sdk.integrations.rq import RqIntegration from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration +from proxstar import util from proxstar.db import ( Base, datetime, @@ -48,6 +49,7 @@ get_shared_pool, get_shared_pools, ) +from proxstar.ldapdb import is_rtp from proxstar.vnc import ( add_vnc_target, get_vnc_targets, @@ -100,6 +102,8 @@ app.config['STARRS_DB_PASS'], ) ) +else: + starrs = None from proxstar.vm import VM from proxstar.user import User @@ -137,14 +141,16 @@ def add_rq_dashboard_auth(blueprint): @blueprint.before_request - @auth.oidc_auth + @auth.oidc_auth('default') def rq_dashboard_auth(*args, **kwargs): # pylint: disable=unused-argument,unused-variable - if 'rtp' not in session['userinfo']['groups']: + user = User(session['userinfo']['preferred_username']) + if not user.rtp: abort(403) rq_dashboard_blueprint = rq_dashboard.blueprint add_rq_dashboard_auth(rq_dashboard_blueprint) +rq_dashboard.web.setup_rq_connection(app) app.register_blueprint(rq_dashboard_blueprint, url_prefix='/rq') @@ -170,7 +176,7 @@ def forbidden(e): @app.route('/') @app.route('/user/') -@auth.oidc_auth +@auth.oidc_auth('default') def list_vms(user_view=None): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -204,7 +210,7 @@ def list_vms(user_view=None): @app.route('/pool/shared/') -@auth.oidc_auth +@auth.oidc_auth('default') def list_shared_vms(name=None): user = User(session['userinfo']['preferred_username']) pool = get_shared_pool(db, name) @@ -242,7 +248,7 @@ def list_pools(): @app.route('/isos') -@auth.oidc_auth +@auth.oidc_auth('default') def isos(): proxmox = connect_proxmox() stored_isos = get_isos(proxmox, app.config['PROXMOX_ISO_STORAGE']) @@ -250,7 +256,7 @@ def isos(): @app.route('/hostname/') -@auth.oidc_auth +@auth.oidc_auth('default') def hostname(name): valid, available = check_hostname(starrs, name) if app.config['USE_STARRS'] else (True, True) if not valid: @@ -262,7 +268,7 @@ def hostname(name): @app.route('/vm/') -@auth.oidc_auth +@auth.oidc_auth('default') def vm_details(vmid): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -282,7 +288,7 @@ def vm_details(vmid): @app.route('/vm//power/', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def vm_power(vmid, action): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -328,7 +334,7 @@ def vm_power(vmid, action): @app.route('/console/vm/', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def vm_console(vmid): user = User(session['userinfo']['preferred_username']) proxmox = connect_proxmox() @@ -352,7 +358,7 @@ def vm_console(vmid): @app.route('/vm//cpu/', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def vm_cpu(vmid, cores): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -373,7 +379,7 @@ def vm_cpu(vmid, cores): @app.route('/vm//mem/', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def vm_mem(vmid, mem): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -394,7 +400,7 @@ def vm_mem(vmid, mem): @app.route('/vm//renew', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def vm_renew(vmid): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -410,7 +416,7 @@ def vm_renew(vmid): @app.route('/vm//disk/create/', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def create_disk(vmid, size): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -426,7 +432,7 @@ def create_disk(vmid, size): @app.route('/vm//disk//resize/', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def resize_disk(vmid, disk, size): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -442,7 +448,7 @@ def resize_disk(vmid, disk, size): @app.route('/vm//disk//delete', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def delete_disk(vmid, disk): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -455,7 +461,7 @@ def delete_disk(vmid, disk): @app.route('/vm//iso/create', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def iso_create(vmid): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -468,7 +474,7 @@ def iso_create(vmid): @app.route('/vm//iso//delete', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def iso_delete(vmid, iso_drive): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -481,7 +487,7 @@ def iso_delete(vmid, iso_drive): @app.route('/vm//iso//eject', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def iso_eject(vmid, iso_drive): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -494,7 +500,7 @@ def iso_eject(vmid, iso_drive): @app.route('/vm//iso//mount/', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def iso_mount(vmid, iso_drive, iso): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -508,7 +514,7 @@ def iso_mount(vmid, iso_drive, iso): @app.route('/vm//net/create', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def create_net_interface(vmid): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -521,7 +527,7 @@ def create_net_interface(vmid): @app.route('/vm//net//delete', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def delete_net_interface(vmid, netid): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -534,7 +540,7 @@ def delete_net_interface(vmid, netid): @app.route('/vm//delete', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def delete(vmid): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -548,7 +554,7 @@ def delete(vmid): @app.route('/vm//boot_order', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def set_boot_order(vmid): user = User(session['userinfo']['preferred_username']) connect_proxmox() @@ -564,7 +570,7 @@ def set_boot_order(vmid): @app.route('/vm/create', methods=['GET', 'POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def create(): user = User(session['userinfo']['preferred_username']) proxmox = connect_proxmox() @@ -642,9 +648,10 @@ def create(): @app.route('/limits/', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def set_limits(user): - if 'rtp' in session['userinfo']['groups']: + authuser = User(session['userinfo']['preferred_username']) + if authuser.rtp: cpu = request.form['cpu'] mem = request.form['mem'] disk = request.form['disk'] @@ -655,9 +662,10 @@ def set_limits(user): @app.route('/user//delete', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def delete_user(user): - if 'rtp' in session['userinfo']['groups']: + authuser = User(session['userinfo']['preferred_username']) + if authuser.rtp: connect_proxmox() User(user).delete() return '', 200 @@ -666,7 +674,7 @@ def delete_user(user): @app.route('/settings') -@auth.oidc_auth +@auth.oidc_auth('default') def settings(): user = User(session['userinfo']['preferred_username']) if user.rtp: @@ -685,9 +693,10 @@ def settings(): @app.route('/pool//ignore', methods=['POST', 'DELETE']) -@auth.oidc_auth +@auth.oidc_auth('default') def ignored_pools(pool): - if 'rtp' in session['userinfo']['groups']: + user = User(session['userinfo']['preferred_username']) + if user.rtp: if request.method == 'POST': add_ignored_pool(db, pool) elif request.method == 'DELETE': @@ -698,7 +707,7 @@ def ignored_pools(pool): @app.route('/pool/shared/create', methods=['GET', 'POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def create_shared_pool(): user = User(session['userinfo']['preferred_username']) if request.method == 'GET': @@ -707,7 +716,7 @@ def create_shared_pool(): name = request.form['name'] members = request.form['members'].split(',') description = request.form['description'] - if 'rtp' in session['userinfo']['groups']: + if user.rtp: try: proxmox = connect_proxmox() proxmox.pools.post(poolid=name, comment=description) @@ -720,10 +729,11 @@ def create_shared_pool(): @app.route('/pool/shared//modify', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def modify_shared_pool(name): + user = User(session['userinfo']['preferred_username']) members = request.form['members'].split(',') - if 'rtp' in session['userinfo']['groups']: + if user.rtp: pool = get_shared_pool(db, name) if pool: pool.members = members @@ -735,9 +745,10 @@ def modify_shared_pool(name): @app.route('/pool/shared//delete', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def delete_shared_pool(name): - if 'rtp' in session['userinfo']['groups']: + user = User(session['userinfo']['preferred_username']) + if user.rtp: pool = get_shared_pool(db, name) if pool: db.delete(pool) @@ -751,9 +762,10 @@ def delete_shared_pool(name): @app.route('/user//allow', methods=['POST', 'DELETE']) -@auth.oidc_auth +@auth.oidc_auth('default') def allowed_users(user): - if 'rtp' in session['userinfo']['groups']: + authuser = User(session['userinfo']['preferred_username']) + if authuser.rtp: if request.method == 'POST': add_allowed_user(db, user) elif request.method == 'DELETE': @@ -782,7 +794,7 @@ def cleanup_vnc(): @app.route('/template//disk') -@auth.oidc_auth +@auth.oidc_auth('default') def template_disk(template_id): if template_id == 'none': return '0' @@ -790,9 +802,10 @@ def template_disk(template_id): @app.route('/template//edit', methods=['POST']) -@auth.oidc_auth +@auth.oidc_auth('default') def template_edit(template_id): - if 'rtp' in session['userinfo']['groups']: + user = User(session['userinfo']['preferred_username']) + if user.rtp: name = request.form['name'] disk = request.form['disk'] set_template_info(db, template_id, name, disk) diff --git a/proxstar/auth.py b/proxstar/auth.py index 3405903..eea411e 100644 --- a/proxstar/auth.py +++ b/proxstar/auth.py @@ -1,12 +1,20 @@ -from flask_pyoidc.flask_pyoidc import OIDCAuthentication +from flask_pyoidc import OIDCAuthentication +from flask_pyoidc.provider_configuration import ClientMetadata, ProviderConfiguration from tenacity import retry @retry def get_auth(app): auth = OIDCAuthentication( - app, - issuer=app.config['OIDC_ISSUER'], - client_registration_info=app.config['OIDC_CLIENT_CONFIG'], + provider_configurations={ + 'default': ProviderConfiguration( + issuer=app.config['OIDC_ISSUER'], + client_metadata=ClientMetadata( + client_id=app.config['OIDC_CLIENT_ID'], + client_secret=app.config['OIDC_CLIENT_SECRET'], + ), + ), + }, + app=app, ) return auth diff --git a/proxstar/ldapdb.py b/proxstar/ldapdb.py index c737310..def6915 100644 --- a/proxstar/ldapdb.py +++ b/proxstar/ldapdb.py @@ -3,14 +3,19 @@ from proxstar import logging +_ldap = None + def connect_ldap(): + global _ldap try: - ldap = CSHLDAP(app.config['LDAP_BIND_DN'], app.config['LDAP_BIND_PW']) + # This is fine because CSHLDAP functions are decorated with @reconnect_on_fail + if _ldap is None: + _ldap = CSHLDAP(app.config['LDAP_BIND_DN'], app.config['LDAP_BIND_PW']) except Exception as e: logging.error('unable to connect to LDAP: %s', e) raise - return ldap + return _ldap def is_rtp(user): diff --git a/proxstar/starrs.py b/proxstar/starrs.py index 5d1e663..f5c92ab 100644 --- a/proxstar/starrs.py +++ b/proxstar/starrs.py @@ -1,6 +1,3 @@ -import psycopg2 - - def get_next_ip(starrs, range_name): c = starrs.cursor() try: diff --git a/proxstar/tasks.py b/proxstar/tasks.py index de0b882..5304862 100644 --- a/proxstar/tasks.py +++ b/proxstar/tasks.py @@ -60,7 +60,7 @@ def set_job_status(job, status): job.save_meta() -def create_vm_task(user, name, cores, memory, disk, iso): +def create_vm_task(user, name, cores, memory, disk, iso): # pylint: disable=too-many-arguments with app.app_context(): job = get_current_job() proxmox = connect_proxmox() @@ -177,7 +177,9 @@ def generate_pool_cache_task(): store_pool_cache(db, pools) -def setup_template_task(template_id, name, user, ssh_key, cores, memory): +def setup_template_task( + template_id, name, user, ssh_key, cores, memory +): # pylint: disable=too-many-arguments with app.app_context(): job = get_current_job() proxmox = connect_proxmox() @@ -249,6 +251,7 @@ def cleanup_vnc_task(): 'https://{}/console/cleanup'.format(app.config['SERVER_NAME']), data={'token': app.config['VNC_CLEANUP_TOKEN']}, verify=False, + timeout=30, ) except Exception as e: # pylint: disable=W0703 print(e) diff --git a/proxstar/util.py b/proxstar/util.py index 989f64a..6d5e096 100644 --- a/proxstar/util.py +++ b/proxstar/util.py @@ -31,7 +31,7 @@ def default_repr(cls): def __repr__(self): fields = [f'{key}={val}' for key, val in self.__dict__.items()] - return f'{type(self).__name__}({", ".join(fields)})' + return f'{type(self).__name__}({', '.join(fields)})' setattr(cls, '__repr__', __repr__) diff --git a/proxstar/vm.py b/proxstar/vm.py index 289daa4..89471dc 100644 --- a/proxstar/vm.py +++ b/proxstar/vm.py @@ -13,7 +13,7 @@ def check_in_gb(size): if size[-1] == 'M': - size = f'{int(size.rstrip("M")) / 1000}G' + size = f'{int(size.rstrip('M')) / 1000}G' return size @@ -372,7 +372,7 @@ def set_ci_network(self): # Will create a new VM with the given parameters, does not guarantee # the VM is done provisioning when returning -def create_vm(proxmox, user, name, cores, memory, disk, iso): +def create_vm(proxmox, user, name, cores, memory, disk, iso): # pylint: disable=too-many-arguments node = proxmox.nodes(get_node_least_mem(proxmox)) vmid = get_free_vmid(proxmox) # Make sure lingering expirations are deleted diff --git a/requirements.txt b/requirements.txt index 5d58b07..06ffddf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,26 +1,25 @@ -black~=21.9b0 -csh-ldap==2.4.0 -click~=7.1.2 -flask==1.1.4 -jinja2==2.11.3 -flask-pyoidc==1.3.0 -gunicorn==20.0.4 -markupsafe==2.0.1 +black~=25.1.0 +csh_ldap @ git+https://github.com/ComputerScienceHouse/csh_ldap@2.5.0 +flask==3.1.2 +jinja2==3.1.6 +flask-pyoidc==3.14.3 +gunicorn==23.0.0 +markupsafe==3.0.2 paramiko==2.11.0 -proxmoxer==1.1.1 -psutil==5.8.0 -psycopg2-binary==2.9.3 -python-dateutil==2.8.1 -redis==3.5.3 -requests==2.25.1 -rq==1.10.1 -rq-dashboard==0.6.1 -rq-scheduler==0.10.0 -sqlalchemy==1.3.22 -tenacity==5.0.2 -websockify==0.9.0 -pylint==2.13.9 -pylint-quotes==0.2.3 +proxmoxer==2.2.0 +psutil==7.0.0 +psycopg2-binary==2.9.10 +python-dateutil==2.9.0 +redis==6.4.0 +requests==2.32.5 +rq==2.6.0 +rq-dashboard==0.8.5 +rq-scheduler==0.14.0 +sqlalchemy==2.0.43 +tenacity==9.1.2 +websockify==0.13.0 +pylint==3.3.8 +sentry-sdk[rq] sentry-sdk[flask] -sentry-sdk~=1.5.12 -python-dotenv==0.19.1 +sentry-sdk~=2.38.0 +python-dotenv==1.1.1 diff --git a/rqsettings.py b/rqsettings.py index 31786d8..fc4be05 100644 --- a/rqsettings.py +++ b/rqsettings.py @@ -5,7 +5,10 @@ from sentry_sdk.integrations.redis import RedisIntegration if os.path.exists('config_local.py'): - import config_local as config + try: + import config_local as config # pylint: disable=import-error + except ImportError: + import config else: import config diff --git a/start_worker.sh b/start_worker.sh index ab291ff..ab90bba 100755 --- a/start_worker.sh +++ b/start_worker.sh @@ -2,4 +2,4 @@ PROXSTAR_REDIS_URL=redis://$PROXSTAR_REDIS_HOST:$PROXSTAR_REDIS_PORT -rq worker -u "$PROXSTAR_REDIS_URL" --sentry-dsn "" -c rqsettings +rq worker -u "$PROXSTAR_REDIS_URL" -c rqsettings