Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/workflows/conventional-commits-check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Conventional commits check

on:
pull_request:
types: [opened, ready_for_review, reopened, synchronize]

permissions:
contents: read

jobs:
conventional-commits-check:
name: Check commit messages

runs-on: self-hosted

steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Check for conventional commits
uses: webiny/action-conventional-commits@8bc41ff4e7d423d56fa4905f6ff79209a78776c7 # v1.3.0
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Includes type with the customization prefix "c/".
# Since all non-letters are removed from the type string
# c/feat would become "cfeat" in the validation process.
allowed-commit-types: "feat,fix,docs,style,refactor,refac,test,build,perf,ci,chore,revert,cfeat,cfix,cdocs,cstyle,crefactor,crefac,ctest,cbuild,cperf,cci,cchore,crevert"

- name: Check for referenced issue IDs
run: |
if [ -z "${{ github.base_ref }}" ]; then
echo "Not a pull request, don't know the base. Skipped."
exit 0
fi

echo "Checking commit range ${from}..${to} for presence of \"Refs:\" ..."
# Debug
git branch -a

ok=0
nok=0
for c in $( git rev-list "${from}..${to}" ); do
if [ -z "$( git log -1 --pretty="SHA=%h %s%n%b" ${c} | grep -E '^Refs:' )" ]; then
git log -1 --pretty="Not OK: %h %s" ${c}
(( nok++ ))
else
(( ok++ ))
fi
done

echo "${ok} OK, ${nok} not OK"

if [ ${nok} -ne 0 ]; then
echo 'Add Refs: <comma separated list of issue IDs>; consider using "Refs: -" where not applicable.'
exit 1
fi
env:
from: refs/heads/${{ github.base_ref }}
to: ${{ github.ref }}
3 changes: 2 additions & 1 deletion backend/open_webui/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,5 +430,6 @@ def parse_section(section):
# Comma separated list of emails (default: empty)
IONOS_ACCOUNT_DELETE_ALLOW_LIST = os.environ.get("IONOS_ACCOUNT_DELETE_ALLOW_LIST", "")

IONOS_USER_ID_PSEUDONYMIZATION_SALT = os.environ.get("IONOS_USER_ID_PSEUDONYMIZATION_SALT", None)
IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX = os.environ.get("IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX", None)
IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX = os.environ.get("IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX", None)
IONOS_SURVEY_NEW_USERS_URL = os.environ.get("IONOS_SURVEY_NEW_USERS_URL", None)
7 changes: 4 additions & 3 deletions backend/open_webui/services/ionos.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import hashlib
from open_webui.models.users import User
from open_webui.env import (
IONOS_USER_ID_PSEUDONYMIZATION_SALT,
IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX,
IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX,
)

def get_oauth_sub(user: User) -> str:
Expand Down Expand Up @@ -32,13 +33,13 @@ def pseudonymized_user_id(user: User) -> Optional[str]:
Generate pseudonymized user ID for aggregation in surveys
"""

if not IONOS_USER_ID_PSEUDONYMIZATION_SALT:
if not IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX or not IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX:
return None

if not user.oauth_sub:
return None

sub = get_oauth_sub(user)

salted = f"{sub}{IONOS_USER_ID_PSEUDONYMIZATION_SALT}"
salted = f"{IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX}{sub}{IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX}"
return hashlib.md5(salted.encode("ascii")).hexdigest()
36 changes: 26 additions & 10 deletions backend/open_webui/test/services/ionos_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,40 +27,56 @@ def around_tests(self, monkeypatch):
"""
Cleanup environments
"""
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT", None, raising = True)
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX", None, raising = True)
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX", None, raising = True)
yield
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT", None, raising = True)
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX", None, raising = True)
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX", None, raising = True)

def test_pseudonymized_user_id_salt_defined(self, monkeypatch):
"""
echo -n "SOMEUUIDsomesalt" | md5sum
echo -n "somesaltprefixSOMEUUIDsomesaltsuffix" | md5sum
"""

salt = "somesalt"
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT", salt, raising = True)
salt_prefix = "somesaltprefix"
salt_suffix = "somesaltsuffix"
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX", salt_prefix, raising = True)
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX", salt_suffix, raising = True)

oauth_sub = "oidc@SOMEUUID"

expected_hash = "3c810acae41ee75abfae48d53abbcee5"
# Note the nice nerdy start of the hex sequence :)
expected_hash = "f00c899879750f2398c315bf8e89d1a8"

assert pseudonymized_user_id(get_mock_user(oauth_sub = oauth_sub)) == expected_hash

def test_pseudonymized_user_id_salt_undefined(self, monkeypatch):
def test_pseudonymized_user_id_salt_prefix_and_suffix_undefined(self, monkeypatch):
assert pseudonymized_user_id(get_mock_user(oauth_sub = "dont-care")) == None

def test_pseudonymized_user_id_salt_prefix_undefined(self, monkeypatch):
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX", "dont-care", raising = True)
assert pseudonymized_user_id(get_mock_user(oauth_sub = "dont-care")) == None

def test_pseudonymized_user_id_salt_suffix_undefined(self, monkeypatch):
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX", "dont-care", raising = True)
assert pseudonymized_user_id(get_mock_user(oauth_sub = "dont-care")) == None

def test_pseudonymized_user_id_oauth_sub_undefined(self, monkeypatch):
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT", "dont-care", raising = True)
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX", "dont-care", raising = True)
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX", "dont-care", raising = True)

assert pseudonymized_user_id(get_mock_user()) == None

def test_pseudonymized_user_id_oauth_sub_malformed(self, monkeypatch):
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT", "dont-care", raising = True)
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX", "dont-care", raising = True)
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX", "dont-care", raising = True)

with pytest.raises(Exception):
pseudonymized_user_id(get_mock_user(oauth_sub = 'oidc'))

def test_pseudonymized_user_id_oauth_sub_missing_sub(self, monkeypatch):
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT", "dont-care", raising = True)
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX", "dont-care", raising = True)
monkeypatch.setattr(open_webui.services.ionos, "IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX", "dont-care", raising = True)

with pytest.raises(Exception):
pseudonymized_user_id(get_mock_user(oauth_sub = 'oidc@'))
3 changes: 2 additions & 1 deletion docs/IONOS/.env.ionos.sample
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_ACCESS=true
# Set this to http://localhost:3000/auth to see the default Open WebUI login page.
IONOS_REGISTRATION_URL=https://localhost:9999/ionos-gpt-shop

IONOS_USER_ID_PSEUDONYMIZATION_SALT=saltysalt
IONOS_USER_ID_PSEUDONYMIZATION_SALT_PREFIX=saltysaltprefix
IONOS_USER_ID_PSEUDONYMIZATION_SALT_SUFFIX=saltysaltsuffix
IONOS_SURVEY_NEW_USERS_URL=https:/localhost:9001/survey/47.1