Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
251ad63
feat(build): enhance JaCoCo reporting with coverage summary and enfor…
Ludy87 Jan 12, 2026
3c8fb8a
build(ci): pin base container images, switch npm install to npm ci, a…
Ludy87 Jan 13, 2026
3af5970
🤖 format everything with pre-commit by stirlingbot (#5426)
stirlingbot[bot] Jan 13, 2026
8632ed9
Updated ga-IE translations and added keys to ignore list (#5178)
aindriu80 Jan 13, 2026
65a5d05
feat(ui): prevent self-modification in People management and highligh…
Ludy87 Jan 13, 2026
cfe90cf
fix(ci): read workflow_dispatch PR number from inputs.pr in PR auto-d…
Ludy87 Jan 13, 2026
36e0fd5
build(deps): bump github/codeql-action from 4.31.5 to 4.31.10 (#5449)
dependabot[bot] Jan 13, 2026
a9ee7f6
build(deps): bump pypdf from 6.4.0 to 6.6.0 in /testing/cucumber (#5422)
dependabot[bot] Jan 13, 2026
7460e58
build(deps): bump io.micrometer:micrometer-core from 1.16.0 to 1.16.1…
dependabot[bot] Jan 13, 2026
818c30c
build(deps): bump docker/setup-qemu-action from 3.6.0 to 3.7.0 (#5326)
dependabot[bot] Jan 13, 2026
daf27b6
build(deps): bump step-security/harden-runner from 2.12.1 to 2.14.0 (…
dependabot[bot] Jan 13, 2026
84ed1d7
feat(conversion): refactor EML parser to use Simple Java Mail library…
balazs-szucs Jan 13, 2026
b266b50
fix(api): return JSON responses for admin settings + API key endpoint…
Ludy87 Jan 13, 2026
bfc029f
Update Backend 3rd Party Licenses (#5363)
stirlingbot[bot] Jan 13, 2026
646df1b
build(deps): bump node from 20-alpine to 25-alpine in /docker/fronten…
dependabot[bot] Jan 13, 2026
0a801fe
build(deps): bump nginx from `8491795` to `c083c37` in /docker/fronte…
dependabot[bot] Jan 13, 2026
392462a
build(deps): bump globals from 16.5.0 to 17.0.0 in /frontend (#5413)
dependabot[bot] Jan 13, 2026
83e96a9
Update user login conditions in workflow (#5457)
Frooodle Jan 13, 2026
e7b030e
Add Telegram bot integration for pipeline processing (#5185)
Ludy87 Jan 13, 2026
b00bd76
feat(conversion): add PDF to EPUB/AZW3 conversion support and setting…
balazs-szucs Jan 13, 2026
db049a3
fix(core): reinstall frontend dependencies when iconify package is mi…
Ludy87 Jan 14, 2026
472ee54
fix(translations): improve translation merger CLI and sync missing UI…
Ludy87 Jan 14, 2026
a366463
ci(build): scope Docker layer cache per artifact to avoid cross-conta…
Ludy87 Jan 14, 2026
e49793a
build(deps): bump urllib3 from 2.5.0 to 2.6.3 in /testing/cucumber in…
dependabot[bot] Jan 14, 2026
1a7fd6a
build(deps): bump alpine from 3.22.2 to 3.23.2 in /docker/backend (#5…
dependabot[bot] Jan 14, 2026
3eaccc1
build(deps): bump alpine from 3.22.1 to 3.23.2 in /docker/embedded (#…
dependabot[bot] Jan 14, 2026
aa39435
build(deps): bump debian from `1c25564` to `449673e` in /docker/embed…
dependabot[bot] Jan 14, 2026
0e8992e
build(deps): bump docker/setup-buildx-action from 3.11.1 to 3.12.0 (#…
dependabot[bot] Jan 14, 2026
8d6c8cb
build(deps): bump docker/login-action from 3.4.0 to 3.6.0 (#5464)
dependabot[bot] Jan 14, 2026
b7041cf
🤖 format everything with pre-commit by stirlingbot (#5462)
stirlingbot[bot] Jan 14, 2026
72cc4e4
Update Backend 3rd Party Licenses (#5458)
stirlingbot[bot] Jan 14, 2026
a7945da
translations (#5469)
Frooodle Jan 14, 2026
84e23ab
:globe_with_meridians: Sync Translations + Update README Progress Tab…
stirlingbot[bot] Jan 14, 2026
dbf72cf
fix(auth): remove unnecessary authentication requirement from Signatu…
balazs-szucs Jan 14, 2026
8fcee48
Make controls sticky (#5478)
reecebrowne Jan 15, 2026
884801e
fix: update broken enterprise docs link from /Pro to /Paid-Offerings …
krizhnaa Jan 15, 2026
8afbd0a
Docker use latest libreoffice and fonts (#5482)
Frooodle Jan 15, 2026
3e06151
Libre threads (#5303)
Frooodle Jan 15, 2026
e4ff0d6
chore: Test
seqradev Jan 21, 2026
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
4 changes: 3 additions & 1 deletion .github/config/repo_devs.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"reecebrowne",
"DarioGii",
"ConnorYoh",
"EthanHealy01"
"EthanHealy01",
"jbrunton96",
"balazs-szucs"
]
}
83 changes: 51 additions & 32 deletions .github/scripts/check_language_toml.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
Usage:
python check_language_toml.py --reference-file <path_to_reference_file> --branch <branch_name> [--actor <actor_name>] [--files <list_of_changed_files>]
"""

# Sample for Windows:
# python .github/scripts/check_language_toml.py --reference-file frontend/public/locales/en-GB/translation.toml --branch "" --files frontend/public/locales/de-DE/translation.toml frontend/public/locales/fr-FR/translation.toml

import argparse
import glob
import os
import argparse
import re
from pathlib import Path

import tomllib # Python 3.11+ (stdlib)
import tomli_w # For writing TOML files

Expand All @@ -36,7 +39,8 @@ def find_duplicate_keys(file_path, keys=None, prefix=""):
duplicates = []

# Load TOML file
with open(file_path, "rb") as file:
file_path = Path(file_path)
with file_path.open("rb") as file:
data = tomllib.load(file)

def process_dict(obj, current_prefix=""):
Expand All @@ -55,8 +59,8 @@ def process_dict(obj, current_prefix=""):
return duplicates


# Maximum size for TOML files (e.g., 500 KB)
MAX_FILE_SIZE = 500 * 1024
# Maximum size for TOML files (e.g., 570 KB)
MAX_FILE_SIZE = 570 * 1024


def parse_toml_file(file_path):
Expand All @@ -65,7 +69,8 @@ def parse_toml_file(file_path):
:param file_path: Path to the TOML file.
:return: Dictionary with flattened keys.
"""
with open(file_path, "rb") as file:
file_path = Path(file_path)
with file_path.open("rb") as file:
data = tomllib.load(file)

def flatten_dict(d, parent_key="", sep="."):
Expand Down Expand Up @@ -108,7 +113,8 @@ def write_toml_file(file_path, updated_properties):
"""
nested_data = unflatten_dict(updated_properties)

with open(file_path, "wb") as file:
file_path = Path(file_path)
with file_path.open("wb") as file:
tomli_w.dump(nested_data, file)


Expand All @@ -119,18 +125,23 @@ def update_missing_keys(reference_file, file_list, branch=""):
:param file_list: List of translation files to update.
:param branch: Branch where the files are located.
"""
reference_file = Path(reference_file)
reference_properties = parse_toml_file(reference_file)
branch_path = Path(branch) if branch else Path()

for file_path in file_list:
basename_current_file = os.path.basename(os.path.join(branch, file_path))
file_path = Path(file_path)
language_dir = file_path.parent.name
reference_lang_dir = reference_file.parent.name
if (
basename_current_file == os.path.basename(reference_file)
or not file_path.endswith(".toml")
or not os.path.dirname(file_path).endswith("locales")
language_dir == reference_lang_dir
or file_path.suffix != ".toml"
or file_path.parents[1].name != "locales"
):
print(f"Skipping file: {file_path}")
continue

current_properties = parse_toml_file(os.path.join(branch, file_path))
current_properties = parse_toml_file(branch_path / file_path)
updated_properties = {}

for ref_key, ref_value in reference_properties.items():
Expand All @@ -141,22 +152,25 @@ def update_missing_keys(reference_file, file_list, branch=""):
# Add missing key with reference value
updated_properties[ref_key] = ref_value

write_toml_file(os.path.join(branch, file_path), updated_properties)
write_toml_file(branch_path / file_path, updated_properties)


def check_for_missing_keys(reference_file, file_list, branch):
update_missing_keys(reference_file, file_list, branch)


def read_toml_keys(file_path):
if os.path.isfile(file_path) and os.path.exists(file_path):
file_path = Path(file_path)
if file_path.is_file():
return parse_toml_file(file_path)
return {}


def check_for_differences(reference_file, file_list, branch, actor):
reference_branch = branch
basename_reference_file = os.path.basename(reference_file)
reference_file = Path(reference_file)
basename_reference_file = reference_file.name
branch_path = Path(branch) if branch else Path()

report = []
report.append(f"#### 🔄 Reference Branch: `{reference_branch}`")
Expand All @@ -170,39 +184,44 @@ def check_for_differences(reference_file, file_list, branch, actor):
if len(file_list) == 1:
file_arr = file_list[0].split()

base_dir = os.path.abspath(
os.path.join(os.getcwd(), "frontend", "public", "locales")
)
base_dir = Path.cwd() / "frontend" / "public" / "locales"

for file_path in file_arr:
file_normpath = os.path.normpath(file_path)
absolute_path = os.path.abspath(file_normpath)
file_path = Path(file_path)
file_normpath = file_path
absolute_path = file_normpath.resolve()

basename_current_file = (branch_path / file_normpath).name
locale_dir = file_normpath.parent.name
report.append(f"#### 📃 **File Check:** `{locale_dir}/{basename_current_file}`")

# Verify that file is within the expected directory
if not absolute_path.startswith(base_dir):
raise ValueError(f"Unsafe file found: {file_normpath}")
if not absolute_path.is_relative_to(base_dir):
has_differences = True
report.append(
f"\n⚠️ Unsafe file found: `{locale_dir}/{basename_current_file}`\n\n---\n"
)
continue

# Verify file size before processing
if os.path.getsize(os.path.join(branch, file_normpath)) > MAX_FILE_SIZE:
raise ValueError(
f"The file {file_normpath} is too large and could pose a security risk."
if (branch_path / file_normpath).stat().st_size > MAX_FILE_SIZE:
has_differences = True
report.append(
f"\n⚠️ The file `{locale_dir}/{basename_current_file}` is too large and could pose a security risk.\n\n---\n"
)

basename_current_file = os.path.basename(os.path.join(branch, file_normpath))
locale_dir = os.path.basename(os.path.dirname(file_normpath))
continue

if basename_current_file == basename_reference_file and locale_dir == "en-GB":
continue

if (
not file_normpath.endswith(".toml")
file_normpath.suffix != ".toml"
or basename_current_file != "translation.toml"
):
continue

only_reference_file = False
report.append(f"#### 📃 **File Check:** `{locale_dir}/{basename_current_file}`")
current_keys = read_toml_keys(os.path.join(branch, file_path))
current_keys = read_toml_keys(branch_path / file_path)
reference_key_count = len(reference_keys)
current_key_count = len(current_keys)

Expand Down Expand Up @@ -247,13 +266,13 @@ def check_for_differences(reference_file, file_list, branch, actor):
else:
report.append("2. **Test Status:** ✅ **_Passed_**")

if find_duplicate_keys(os.path.join(branch, file_normpath)):
if find_duplicate_keys(branch_path / file_normpath):
has_differences = True
output = "\n".join(
[
f" - `{key}`: first at {first}, duplicate at `{duplicate}`"
for key, first, duplicate in find_duplicate_keys(
os.path.join(branch, file_normpath)
branch_path / file_normpath
)
]
)
Expand Down
Loading
Loading