From 6bba3f9831b783a629029006f095b9bc743e4cfc Mon Sep 17 00:00:00 2001 From: rasmus Date: Thu, 7 Aug 2025 21:54:48 +0300 Subject: [PATCH 1/7] doorboy: merge status, success and approved --- inventory-app/doorboy.py | 4 ++-- inventory-app/templates/doorboy.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/inventory-app/doorboy.py b/inventory-app/doorboy.py index 785f852..d35fb3f 100644 --- a/inventory-app/doorboy.py +++ b/inventory-app/doorboy.py @@ -343,7 +343,7 @@ def view_swipe(): "timestamp": timestamp, "door": form["door"], "event": "card-swiped", - "success": form["success"], + "approved": form["approved"], "token": { "uid_hash": form["uid_hash"] }, @@ -355,7 +355,7 @@ def view_swipe(): db.eventlog.insert_one(event_swipe) - status = "Permitted" if form["success"] else "Denied" + status = "Permitted" if form["approved"] else "Denied" username = token.get("inventory", {}).get("owner", {}).get("username", None) if username and username in g.users_lookup: subject = g.users_lookup[username].display_name or username diff --git a/inventory-app/templates/doorboy.html b/inventory-app/templates/doorboy.html index ccf5c35..bf3652e 100644 --- a/inventory-app/templates/doorboy.html +++ b/inventory-app/templates/doorboy.html @@ -84,7 +84,7 @@ Does not include door opens by webhook. {{ o.door }} {% if o.inventory and o.inventory.owner %}{{ o.inventory.owner.username | display_name }}{% else %}Unknown{% endif %} {{ o.token.uid_hash[-6:] }} - + {% if o.inventory and o.inventory.owner %}{{ o.token.comment }}{% else %}Claim keycard{% endif %} {% endfor %} -- 2.49.1 From ee064bde2dd1f81c77fb4c3f3d8339b7b6e5ebee Mon Sep 17 00:00:00 2001 From: rasmus Date: Thu, 7 Aug 2025 23:59:11 +0300 Subject: [PATCH 2/7] move /m/doorboy/swipe to doorboy-proxy --- inventory-app/doorboy.py | 98 +++++----------------------------------- 1 file changed, 12 insertions(+), 86 deletions(-) diff --git a/inventory-app/doorboy.py b/inventory-app/doorboy.py index d35fb3f..066f305 100644 --- a/inventory-app/doorboy.py +++ b/inventory-app/doorboy.py @@ -10,7 +10,6 @@ from wtforms.validators import DataRequired import pytz import const -from api import check_api_key from common import slack_post, User from oidc import login_required, read_user @@ -144,6 +143,18 @@ def view_doorboy_hold(): }) return redirect("/m/doorboy") +@page_doorboy.route("/m/doorboy/slam", methods=["POST"]) +@login_required +def view_doorboy_slam(): + user = read_user() + db.eventlog.insert_one({ + "component": "doorboy", + "type": "hold", + "requester": user["name"], + "door": form.door_name.data, + "expires": datetime.utcnow() + timedelta(minutes=form.duration_min.data) + }) + return redirect("/m/doorboy") @page_doorboy.route("/m/doorboy//open") @login_required @@ -179,21 +190,6 @@ def view_doorboy_open(door): else: return "", 401 - -@page_doorboy.route("/m/doorboy/slam", methods=["POST"]) -@login_required -def view_doorboy_slam(): - user = read_user() - db.eventlog.insert_one({ - "component": "doorboy", - "type": "hold", - "requester": user["name"], - "door": form.door_name.data, - "expires": datetime.utcnow() + timedelta(minutes=form.duration_min.data) - }) - return redirect("/m/doorboy") - - @page_doorboy.route("/m/doorboy") @login_required def view_doorboy(): @@ -295,73 +291,3 @@ def view_doorboy_token_events(token_id): token = db.inventory.find_one({"_id": ObjectId(token_id)}) latest_events = db.eventlog.find({"component": "doorboy", "event":"card-swiped", "token.uid_hash": token.get("token").get("uid_hash")}).sort([("timestamp", -1)]) return render_template("doorboy.html", **locals()) - -class FormSwipe(FlaskForm): - class Meta: - csrf = False - uid = StringField('uid', validators=[]) - uid_hash = StringField('uid', validators=[]) - door = StringField('door', validators=[DataRequired()]) - success = BooleanField('success', validators=[]) - timestamp = DateTimeField('timestamp') - -@page_doorboy.route("/m/doorboy/swipe", methods=["POST"]) -@check_api_key -def view_swipe(): - form = request.json - print(form) - timestamp = parse(form["timestamp"]) if form.get("timestamp") else None - now = datetime.utcnow() - # Make sure token exists - db.inventory.update_one({ - "type": "token", - "component": "doorboy", - "token.uid_hash": form["uid_hash"] - }, { - "$set": { - "last_seen": timestamp or now - }, - "$setOnInsert": { - "component": "doorboy", - "type": "token", - "first_seen": now, - "inventory": { - "claimable": True, - } - } - }, upsert=True) - - # Fetch token to read owner - token = db.inventory.find_one({ - "type": "token", - "component": "doorboy", - "token.uid_hash": form["uid_hash"] - }) - - event_swipe = { - "component": "doorboy", - "timestamp": timestamp, - "door": form["door"], - "event": "card-swiped", - "approved": form["approved"], - "token": { - "uid_hash": form["uid_hash"] - }, - "inventory": {} - } - - if token.get("inventory", {}).get("owner", {}).get("username", None): - event_swipe["inventory"]["owner_id"] = token["inventory"]["owner"]["username"] - - db.eventlog.insert_one(event_swipe) - - status = "Permitted" if form["approved"] else "Denied" - username = token.get("inventory", {}).get("owner", {}).get("username", None) - if username and username in g.users_lookup: - subject = g.users_lookup[username].display_name or username - else: - subject = "Unknown" - msg = "%s %s door access for %s identified by keycard/keyfob" % (status, form["door"], subject) - slack_post(msg, "doorboy") - - return "ok" -- 2.49.1 From 76cc8e6883eeecffa860ae214f4caf5f549639f3 Mon Sep 17 00:00:00 2001 From: rasmus Date: Fri, 8 Aug 2025 03:34:06 +0300 Subject: [PATCH 3/7] move /cards to doorboy-proxy + refactor mongo format --- deployment.yaml | 4 --- inventory-app/api.py | 70 ++++++++-------------------------------- inventory-app/common.py | 31 ++++++------------ inventory-app/const.py | 2 -- inventory-app/doorboy.py | 65 +++++++++++++++---------------------- 5 files changed, 48 insertions(+), 124 deletions(-) diff --git a/deployment.yaml b/deployment.yaml index a08dbf2..40a0628 100644 --- a/deployment.yaml +++ b/deployment.yaml @@ -23,12 +23,8 @@ spec: env: - name: OIDC_USERS_NAMESPACE value: "default" - - name: SLACK_DOORLOG_CALLBACK - value: "changeme" - name: SLACK_VERIFICATION_TOKEN value: "changeme" - - name: INVENTORY_API_KEY - value: "sptWL6XFxl4b8" - name: PYTHONUNBUFFERED value: "1" # Google test key diff --git a/inventory-app/api.py b/inventory-app/api.py index 537b067..ff33127 100644 --- a/inventory-app/api.py +++ b/inventory-app/api.py @@ -1,57 +1,14 @@ -import re -import const -import time import threading +import time from datetime import datetime -from functools import wraps + +import const +from flask import Blueprint, g, request from pymongo import MongoClient -from flask import Blueprint, g, request, jsonify -from common import slack_post page_api = Blueprint("api", __name__) db = MongoClient(const.MONGO_URI).get_default_database() -def check_api_key(f): - @wraps(f) - def decorated_function(*args, **kwargs): - request_key = request.headers.get('Authorization', False) - if not request_key: - return "nope", 403 - found_key = re.search(r"Basic (.*)", request_key).group(1) - if not found_key or found_key != const.INVENTORY_API_KEY: - return "nope", 403 - return f(*args, **kwargs) - return decorated_function - -@page_api.route("/cards", methods=["POST"]) -@check_api_key -def get_group_cards(): - request_groups = request.json.get("groups", False) - if not request_groups: - return "must specify groups in parameter", 400 - print(f"found {len(g.users)} users for groups: {request_groups}") - keys = [] - for u in g.users: - for group in u.groups: - if group in request_groups: - keys.append(u.username) - break - print(f"{len(keys)} doorkeys") - flt = { - "token.uid_hash": {"$exists": True}, - "inventory.owner.username": {"$in": keys} - } - prj = { - "inventory.owner": True, - "token.uid_hash": True - } - found = [] - for obj in db.inventory.find(flt, prj): - found.append({"token": obj["token"]}) - fl = list(found) - print(f"{len(fl)} doorkey tokens") - return jsonify(fl) - @page_api.route("/api/slack/doorboy", methods=['POST']) def view_slack_doorboy(): begin_time = time.perf_counter() @@ -91,27 +48,26 @@ def view_slack_doorboy(): threading.Thread(target=handle_slack_door_event, args=(doors, approved, member, door, status, subject)).start() - return_message = "Opening %s for %s" % (door, subject) if approved else "Permission denied" end_time = time.perf_counter() print(f"view_slack_doorboy done in {end_time - begin_time:.4f} seconds") + + return_message = "Opening %s for %s" % (door, subject) if approved else "Permission denied" return return_message def handle_slack_door_event(doors, approved, member, door, status, subject): begin_time = time.perf_counter() for d in doors: db.eventlog.insert_one({ - "method": "slack", - "approved": approved, - "duration": 5, "component": "doorboy", - "type": "open-door", - "door": d, - "member_id": member.username, - "member": member.display_name, + "method": "slack", "timestamp": datetime.utcnow(), + "door": d, + "approved": approved, + "user": { + "id": member.username, + "name": member.display_name, + } }) - msg = "%s %s door access for %s via Slack bot" % (status, door, subject) - slack_post(msg, "doorboy") end_time = time.perf_counter() print(f"handle_slack_door_event done in {end_time - begin_time:.4f} seconds") diff --git a/inventory-app/common.py b/inventory-app/common.py index 7f36f5d..1e5cf69 100644 --- a/inventory-app/common.py +++ b/inventory-app/common.py @@ -1,17 +1,16 @@ -import os import collections.abc -from functools import wraps - -import requests -from bson.objectid import ObjectId -from flask import g, request -from flask_wtf import FlaskForm -from pymongo import MongoClient -from kubernetes import client, config -from typing import List +import os from dataclasses import dataclass, field +from functools import wraps +from typing import List import const +from bson.objectid import ObjectId +from common import read_user +from flask import g, request +from flask_wtf import FlaskForm +from kubernetes import client, config +from pymongo import MongoClient devenv = const.ENVIRONMENT_TYPE == "DEV" OIDC_USERS_NAMESPACE = os.getenv("OIDC_USERS_NAMESPACE") @@ -93,18 +92,6 @@ def flatten(d, parent_key='', sep='.'): items.append((new_key, v)) return dict(items) -def slack_post(msg, channel): - if devenv: - print(f"{channel}: {msg}") - return - - channels = { - "doorboy": const.SLACK_DOORLOG_CALLBACK, - } - url = channels.get(channel, const.SLACK_DOORLOG_CALLBACK) - - requests.post(url, json={"text": msg }) - def build_query(base_query, fields=[], sort_fields={}): top_usernames= ['k-space'] selectors = [] diff --git a/inventory-app/const.py b/inventory-app/const.py index 9b8fc7c..0fd32ba 100644 --- a/inventory-app/const.py +++ b/inventory-app/const.py @@ -18,6 +18,4 @@ BUCKET_NAME = os.environ["BUCKET_NAME"] INVENTORY_ASSETS_BASE_URL = os.environ["INVENTORY_ASSETS_BASE_URL"] MONGO_URI = os.environ["MONGO_URI"] SLACK_VERIFICATION_TOKEN = os.environ["SLACK_VERIFICATION_TOKEN"] # used to verify (deprecated) incoming requests from slack -SLACK_DOORLOG_CALLBACK = os.environ["SLACK_DOORLOG_CALLBACK"] # used for sending logs to private channel -INVENTORY_API_KEY = os.environ["INVENTORY_API_KEY"] # used by doorboy-proxy (@check_api_key) MACADDRESS_OUTLINK_BASEURL = os.environ["MACADDRESS_OUTLINK_BASEURL"] diff --git a/inventory-app/doorboy.py b/inventory-app/doorboy.py index 066f305..bad2ae8 100644 --- a/inventory-app/doorboy.py +++ b/inventory-app/doorboy.py @@ -1,17 +1,17 @@ from datetime import datetime, timedelta -from dateutil.parser import parse, ParserError -from bson.objectid import ObjectId -from flask import Blueprint, g, redirect, render_template, request, abort -from flask_wtf import FlaskForm -from pymongo import MongoClient -from wtforms import StringField, IntegerField, SelectField, BooleanField, DateTimeField, validators -from wtforms.validators import DataRequired - -import pytz import const -from common import slack_post, User +import pytz +from bson.objectid import ObjectId +from common import User +from dateutil.parser import ParserError, parse +from flask import Blueprint, abort, g, redirect, render_template, request +from flask_wtf import FlaskForm from oidc import login_required, read_user +from pymongo import MongoClient +from wtforms import (BooleanField, IntegerField, SelectField, StringField, + validators) +from wtforms.validators import DataRequired page_doorboy = Blueprint("doorboy", __name__) db = MongoClient(const.MONGO_URI).get_default_database() @@ -27,7 +27,7 @@ def view_doorboy_claim(event_id): }) # Find token object to associate with user - token = db.inventory.update_one({ + db.inventory.update_one({ "type": "token", "token.uid_hash": event["token"]["uid_hash"], "inventory.owner.username": { "$exists": False } @@ -127,35 +127,27 @@ class HoldDoorForm(FlaskForm): door_name = SelectField("Door name", choices=[(j,j) for j in ["grounddoor", "frontdoor", "backdoor"]], validators=[DataRequired()]) duration = IntegerField('Duration in seconds', validators=[DataRequired(), validators.NumberRange(min=5, max=21600)]) +# duration=0 to override and close right away @page_doorboy.route("/m/doorboy/hold", methods=["POST"]) @login_required def view_doorboy_hold(): user = read_user() form = HoldDoorForm(request.form) - now = datetime.utcnow() if form.validate_on_submit(): db.eventlog.insert_one({ "component": "doorboy", - "type": "hold", - "requester": user["name"], + "method": "hold", + "timestamp": datetime.utcnow(), "door": form.door_name.data, + "approved": True, + "user": { + "id": user["username"], + "name": user["name"] + }, "expires": datetime.utcnow() + timedelta(seconds=form.duration.data) }) return redirect("/m/doorboy") -@page_doorboy.route("/m/doorboy/slam", methods=["POST"]) -@login_required -def view_doorboy_slam(): - user = read_user() - db.eventlog.insert_one({ - "component": "doorboy", - "type": "hold", - "requester": user["name"], - "door": form.door_name.data, - "expires": datetime.utcnow() + timedelta(minutes=form.duration_min.data) - }) - return redirect("/m/doorboy") - @page_doorboy.route("/m/doorboy//open") @login_required def view_doorboy_open(door): @@ -169,22 +161,17 @@ def view_doorboy_open(door): access_group = "k-space:floor" approved = access_group in g.users_lookup.get(user["username"], User()).groups db.eventlog.insert_one({ - "method": "web", - "approved": approved, - "duration": 5, "component": "doorboy", - "type": "open-door", - "door": door, - "member_id": user["username"], - "member": user["name"], + "method": "web", "timestamp": datetime.utcnow(), + "door": door, + "approved": approved, + "user": { + "id": user["username"], + "name": user["name"] + } }) - status = "Permitted" if approved else "Denied" - subject = user["name"] - msg = "%s %s door access for %s via https://inventory.k-space.ee/m/doorboy" % (status, door, subject) - slack_post(msg, "doorboy") - if approved: return redirect("/m/doorboy") else: -- 2.49.1 From ac14ca1adf98a4b4fd80f73ecea7a6d89081676f Mon Sep 17 00:00:00 2001 From: rasmus Date: Fri, 8 Aug 2025 04:02:06 +0300 Subject: [PATCH 4/7] move slack_listen to doorboy-proxy --- inventory-app/api.py | 73 ------------------------------------------ inventory-app/const.py | 1 - inventory-app/main.py | 4 +-- 3 files changed, 1 insertion(+), 77 deletions(-) delete mode 100644 inventory-app/api.py diff --git a/inventory-app/api.py b/inventory-app/api.py deleted file mode 100644 index ff33127..0000000 --- a/inventory-app/api.py +++ /dev/null @@ -1,73 +0,0 @@ -import threading -import time -from datetime import datetime - -import const -from flask import Blueprint, g, request -from pymongo import MongoClient - -page_api = Blueprint("api", __name__) -db = MongoClient(const.MONGO_URI).get_default_database() - -@page_api.route("/api/slack/doorboy", methods=['POST']) -def view_slack_doorboy(): - begin_time = time.perf_counter() - if request.form.get("token") != const.SLACK_VERIFICATION_TOKEN: - return "Invalid token was supplied" - if request.form.get("channel_id") not in ("C01CWPF5H8W", "CDL9H8Q9W"): - return "Invalid channel was supplied" - command = request.form.get("command") - try: - door = { - "/open-all-doors": "outsidedoors", - "/open-back-door": "backdoor", - "/open-front-door": "frontdoor", - "/open-ground-door": "grounddoor", - "/open-workshop-door": "workshopdoor" - }[command] - except KeyError: - return "Invalid command was supplied" - - member = None - for user in g.users: - if user.slack_id == request.form.get("user_id"): - member = user - - if door == "workshopdoor": - access_group = "k-space:workshop" - else: - access_group = "k-space:floor" - approved = access_group in member.groups - - doors = [door] - if door == "outsidedoors": - doors = ["backdoor", "frontdoor", "grounddoor"] - - status = "Permitted" if approved else "Denied" - subject = member.display_name - - threading.Thread(target=handle_slack_door_event, args=(doors, approved, member, door, status, subject)).start() - - end_time = time.perf_counter() - print(f"view_slack_doorboy done in {end_time - begin_time:.4f} seconds") - - return_message = "Opening %s for %s" % (door, subject) if approved else "Permission denied" - return return_message - -def handle_slack_door_event(doors, approved, member, door, status, subject): - begin_time = time.perf_counter() - for d in doors: - db.eventlog.insert_one({ - "component": "doorboy", - "method": "slack", - "timestamp": datetime.utcnow(), - "door": d, - "approved": approved, - "user": { - "id": member.username, - "name": member.display_name, - } - }) - - end_time = time.perf_counter() - print(f"handle_slack_door_event done in {end_time - begin_time:.4f} seconds") diff --git a/inventory-app/const.py b/inventory-app/const.py index 0fd32ba..e9e1972 100644 --- a/inventory-app/const.py +++ b/inventory-app/const.py @@ -17,5 +17,4 @@ AWS_S3_ENDPOINT_URL = os.environ["AWS_S3_ENDPOINT_URL"] BUCKET_NAME = os.environ["BUCKET_NAME"] INVENTORY_ASSETS_BASE_URL = os.environ["INVENTORY_ASSETS_BASE_URL"] MONGO_URI = os.environ["MONGO_URI"] -SLACK_VERIFICATION_TOKEN = os.environ["SLACK_VERIFICATION_TOKEN"] # used to verify (deprecated) incoming requests from slack MACADDRESS_OUTLINK_BASEURL = os.environ["MACADDRESS_OUTLINK_BASEURL"] diff --git a/inventory-app/main.py b/inventory-app/main.py index 4ce1254..93078f8 100755 --- a/inventory-app/main.py +++ b/inventory-app/main.py @@ -25,9 +25,8 @@ from wtforms import ( import const from common import devenv, format_name, get_users, User from inventory import page_inventory -from oidc import page_oidc, login_required, read_user +from oidc import page_oidc, login_required from doorboy import page_doorboy -from api import page_api def check_foreign_key_format(item): owner = item.get("inventory", {}).get("owner", {}) @@ -124,7 +123,6 @@ app = Flask(__name__) app.wsgi_app = ReverseProxied(app.wsgi_app) app.register_blueprint(page_inventory) app.register_blueprint(page_oidc) -app.register_blueprint(page_api) app.register_blueprint(page_doorboy) metrics = PrometheusMetrics(app, group_by="path") -- 2.49.1 From f0109677b006fd36d223349231299d47fc1ffcea Mon Sep 17 00:00:00 2001 From: rasmus Date: Fri, 8 Aug 2025 05:42:11 +0300 Subject: [PATCH 5/7] doc k-space:floor hardcoded --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 69ff741..59335ea 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,5 @@ |k-space:inventory:audit|Update last time item information confirmed to be accurate| |k-space:inventory:edit|Edit all non-key items. Browse items with Protected visibility.| |k-space:inventory:keys|Edit keys| + +For door access, assumes `k-space:floor` and `k-space:workshop`, same in doorboy-proxy. -- 2.49.1 From 14a5e8e42de1bb49149c71cea45a65c24cc59852 Mon Sep 17 00:00:00 2001 From: rasmus Date: Fri, 8 Aug 2025 05:51:19 +0300 Subject: [PATCH 6/7] rm SECRET_KEY --- deployment.yaml | 2 -- inventory-app/const.py | 1 - inventory-app/main.py | 2 -- 3 files changed, 5 deletions(-) diff --git a/deployment.yaml b/deployment.yaml index 40a0628..35ed688 100644 --- a/deployment.yaml +++ b/deployment.yaml @@ -44,8 +44,6 @@ spec: secretKeyRef: name: miniobucket-inventory-app-owner-secrets key: MINIO_URI - - name: SECRET_KEY - value: "bad_secret" - name: ENVIRONMENT_TYPE value: "DEV" - name: MY_POD_NAME diff --git a/inventory-app/const.py b/inventory-app/const.py index e9e1972..5c2634f 100644 --- a/inventory-app/const.py +++ b/inventory-app/const.py @@ -12,7 +12,6 @@ def file_exists(path): ENVIRONMENT_TYPE = getenv_in("ENVIRONMENT_TYPE", "DEV", "PROD") -SECRET_KEY = os.environ["SECRET_KEY"] AWS_S3_ENDPOINT_URL = os.environ["AWS_S3_ENDPOINT_URL"] BUCKET_NAME = os.environ["BUCKET_NAME"] INVENTORY_ASSETS_BASE_URL = os.environ["INVENTORY_ASSETS_BASE_URL"] diff --git a/inventory-app/main.py b/inventory-app/main.py index 93078f8..fb89192 100755 --- a/inventory-app/main.py +++ b/inventory-app/main.py @@ -126,8 +126,6 @@ app.register_blueprint(page_oidc) app.register_blueprint(page_doorboy) metrics = PrometheusMetrics(app, group_by="path") -app.config['SECRET_KEY'] = const.SECRET_KEY - mongoclient = MongoClient(const.MONGO_URI) mongodb = mongoclient.get_default_database() mongodb.member.create_index("ad.username", sparse=True, unique=True) -- 2.49.1 From fb8c63e86f12c260c6bcb2514a4123aa5b3381c2 Mon Sep 17 00:00:00 2001 From: rasmus Date: Fri, 8 Aug 2025 06:11:55 +0300 Subject: [PATCH 7/7] move static env to dockerfile --- Dockerfile | 15 ++++++++++----- deployment.yaml | 5 +---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8aab025..b04cf2c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,12 +4,17 @@ RUN apt-get update \ curl ca-certificates iputils-ping \ python3-ldap python3-pip python3-ldap \ libjpeg-dev libturbojpeg0-dev \ - && rm -rf /var/lib/apt/lists/* \ - && apt-get clean -COPY requirements.txt ./ + && rm -rf /var/lib/apt/lists/* + + COPY requirements.txt ./ #necessary hack for cffi RUN pip3 install cffi RUN pip3 install -r requirements.txt -COPY inventory-app /app + +ENV PYTHONUNBUFFERED=1 +ENV ENVIRONMENT_TYPE=PROD + WORKDIR /app -ENTRYPOINT /app/main.py +COPY inventory-app . + +ENTRYPOINT ["python3", "/app/main.py"] diff --git a/deployment.yaml b/deployment.yaml index 35ed688..4dab086 100644 --- a/deployment.yaml +++ b/deployment.yaml @@ -1,3 +1,4 @@ +# This is unmaintained. See git.k-space.ee/k-space/kube//hackerspace/inventory.yaml --- apiVersion: apps/v1 kind: Deployment @@ -23,10 +24,6 @@ spec: env: - name: OIDC_USERS_NAMESPACE value: "default" - - name: SLACK_VERIFICATION_TOKEN - value: "changeme" - - name: PYTHONUNBUFFERED - value: "1" # Google test key - name: RECAPTCHA_PUBLIC_KEY value: 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI -- 2.49.1