This commit is contained in:
Weblate 2021-08-31 09:54:08 +00:00
commit 75f1b26ee1
13 changed files with 152 additions and 42 deletions

View file

@ -17,19 +17,16 @@ Pin-Priority: -1" >> "${pending_dir}/etc/apt/preferences.d/extra_php_version"
done
echo "
# Yes !
# This is what's preventing you from installing apache2 !
#
# Maybe take two fucking minutes to realize that if you try to install
# apache2, this will break nginx and break the entire YunoHost ecosystem.
# on your server.
#
# So, *NO*
# DO NOT do this.
# DO NOT remove these lines.
#
# I warned you. I WARNED YOU! But did you listen to me?
# Oooooh, noooo. You knew it all, didn't you?
# PLEASE READ THIS WARNING AND DON'T EDIT THIS FILE
# You are probably reading this file because you tried to install apache2 or
# bind9. These 2 packages conflict with YunoHost.
# Installing apache2 will break nginx and break the entire YunoHost ecosystem
# on your server, therefore don't remove those lines!
# You have been warned.
Package: apache2
Pin: release *
@ -39,9 +36,9 @@ Package: apache2-bin
Pin: release *
Pin-Priority: -1
# Also yes, bind9 will conflict with dnsmasq.
# Same story than for apache2.
# Don't fucking install it.
# Also bind9 will conflict with dnsmasq.
# Same story as for apache2.
# Don't install it, don't remove those lines.
Package: bind9
Pin: release *

View file

@ -0,0 +1,76 @@
#!/usr/bin/env python
import os
from yunohost.app import app_list
from yunohost.diagnosis import Diagnoser
class AppDiagnoser(Diagnoser):
id_ = os.path.splitext(os.path.basename(__file__))[0].split("-")[1]
cache_duration = 300
dependencies = []
def run(self):
apps = app_list(full=True)["apps"]
for app in apps:
app["issues"] = list(self.issues(app))
if not any(app["issues"] for app in apps):
yield dict(
meta={"test": "apps"},
status="SUCCESS",
summary="diagnosis_apps_allgood",
)
else:
for app in apps:
if not app["issues"]:
continue
level = "ERROR" if any(issue[0] == "error" for issue in app["issues"]) else "WARNING"
yield dict(
meta={"test": "apps", "app": app["name"]},
status=level,
summary="diagnosis_apps_issue",
details=[issue[1] for issue in app["issues"]]
)
def issues(self, app):
# Check quality level in catalog
if not app.get("from_catalog") or app["from_catalog"].get("state") != "working":
yield ("error", "diagnosis_apps_not_in_app_catalog")
elif not isinstance(app["from_catalog"].get("level"), int) or app["from_catalog"]["level"] == 0:
yield ("error", "diagnosis_apps_broken")
elif app["from_catalog"]["level"] <= 4:
yield ("warning", "diagnosis_apps_bad_quality")
# Check for super old, deprecated practices
yunohost_version_req = app["manifest"].get("requirements", {}).get("yunohost", "").strip(">= ")
if yunohost_version_req.startswith("2."):
yield ("error", "diagnosis_apps_outdated_ynh_requirement")
deprecated_helpers = [
"yunohost app setting",
"yunohost app checkurl",
"yunohost app checkport",
"yunohost app initdb",
"yunohost tools port-available",
]
for deprecated_helper in deprecated_helpers:
if os.system(f"grep -nr -q '{deprecated_helper}' {app['setting_path']}/scripts/") == 0:
yield ("error", "diagnosis_apps_deprecated_practices")
old_arg_regex = r'^domain=\${?[0-9]'
if os.system(f"grep -q '{old_arg_regex}' {app['setting_path']}/scripts/install") == 0:
yield ("error", "diagnosis_apps_deprecated_practices")
def main(args, env, loggers):
return AppDiagnoser(args, env, loggers).diagnose()

View file

@ -249,6 +249,14 @@
"diagnosis_description_web": "Web",
"diagnosis_description_mail": "Email",
"diagnosis_description_regenconf": "System configurations",
"diagnosis_description_apps": "Applications",
"diagnosis_apps_allgood": "All installed apps respect basic packaging practices",
"diagnosis_apps_issue": "An issue was found for app {app}",
"diagnosis_apps_not_in_app_catalog": "This application is not in YunoHost's application catalog. If it was in the past and got removed, you should consider uninstalling this app as it won't receive upgrade, and may compromise the integrity and security of your system.",
"diagnosis_apps_broken": "This application is currently flagged as broken on YunoHost's application catalog. This may be a temporary issue while the maintainers attempt to fix the issue. In the meantime, upgrading this app is disabled.",
"diagnosis_apps_bad_quality": "This application is currently flagged as broken on YunoHost's application catalog. This may be a temporary issue while the maintainers attempt to fix the issue. In the meantime, upgrading this app is disabled.",
"diagnosis_apps_outdated_ynh_requirement": "This app's installed version only requires yunohost >= 2.x, which tends to indicate that it's not up to date with recommended packaging practices and helpers. You should really consider upgrading it.",
"diagnosis_apps_deprecated_practices": "This app's installed version still uses some super-old deprecated packaging practices. You should really consider upgrading it.",
"diagnosis_ports_could_not_diagnose": "Could not diagnose if ports are reachable from outside in IPv{ipversion}.",
"diagnosis_ports_could_not_diagnose_details": "Error: {error}",
"diagnosis_ports_unreachable": "Port {port} is not reachable from outside.",

View file

@ -638,4 +638,4 @@
"global_settings_setting_security_webadmin_allowlist_enabled": "Autorisez seulement certaines IP à accéder à la page web du portail d'administration (webadmin).",
"diagnosis_http_localdomain": "Le domaine {domain}, avec un TLD .local, ne devrait pas être atteint depuis l'extérieur du réseau local.",
"diagnosis_dns_specialusedomain": "Le domaine {domain} est basé sur un domaine de premier niveau (TLD) à usage spécial et ne devrait donc pas avoir d'enregistrements DNS réels."
}
}

View file

@ -449,7 +449,7 @@
"migration_0019_slapd_config_will_be_overwritten": "Semella que editaches manualmente a configuración slapd. Para esta migración crítica YunoHost precisa forzar a actualización da configuración slapd. Os ficheiros orixinais van ser copiados en {conf_backup_folder}.",
"migration_0019_add_new_attributes_in_ldap": "Engadir novos atributos para os permisos na base de datos LDAP",
"migration_0018_failed_to_reset_legacy_rules": "Fallou o restablecemento das regras antigas de iptables: {error}",
"migration_0018_failed_to_migrate_iptables_rules": "Fallou a migración das regras antigas de iptables a nftables: {erro}",
"migration_0018_failed_to_migrate_iptables_rules": "Fallou a migración das regras antigas de iptables a nftables: {error}",
"migration_0017_not_enough_space": "Crea espazo suficiente en {path} para executar a migración.",
"migration_0017_postgresql_11_not_installed": "PostgreSQL 9.6 está instado, pero non postgresql 11? Algo raro debeu acontecer no teu sistema :(...",
"migration_0017_postgresql_96_not_installed": "PostgreSQL non está instalado no teu sistema. Nada que facer.",

View file

@ -635,4 +635,4 @@
"global_settings_setting_security_webadmin_allowlist_enabled": "Permetti solo ad alcuni IP di accedere al webadmin.",
"disk_space_not_sufficient_update": "Non c'è abbastanza spazio libero per aggiornare questa applicazione",
"disk_space_not_sufficient_install": "Non c'è abbastanza spazio libero per installare questa applicazione"
}
}

View file

@ -141,4 +141,4 @@
"app_install_failed": "Não foi possível instalar {app}: {error}",
"app_full_domain_unavailable": "Desculpe, esse app deve ser instalado num domínio próprio mas já há outros apps instalados no domínio '{domain}'. Você pode usar um subdomínio dedicado a esse aplicativo.",
"app_change_url_success": "A URL agora é {domain}{path}"
}
}

View file

@ -194,7 +194,8 @@ def app_info(app, full=False):
"app_not_installed", app=app, all_apps=_get_all_installed_apps_id()
)
local_manifest = _get_manifest_of_app(os.path.join(APPS_SETTING_PATH, app))
setting_path = os.path.join(APPS_SETTING_PATH, app)
local_manifest = _get_manifest_of_app(setting_path)
permissions = user_permission_list(full=True, absolute_urls=True, apps=[app])[
"permissions"
]
@ -213,6 +214,7 @@ def app_info(app, full=False):
if not full:
return ret
ret["setting_path"] = setting_path
ret["manifest"] = local_manifest
ret["manifest"]["arguments"] = _set_default_ask_questions(
ret["manifest"].get("arguments", {})
@ -223,11 +225,11 @@ def app_info(app, full=False):
ret["from_catalog"] = _load_apps_catalog()["apps"].get(absolute_app_name, {})
ret["upgradable"] = _app_upgradable(ret)
ret["supports_change_url"] = os.path.exists(
os.path.join(APPS_SETTING_PATH, app, "scripts", "change_url")
os.path.join(setting_path, "scripts", "change_url")
)
ret["supports_backup_restore"] = os.path.exists(
os.path.join(APPS_SETTING_PATH, app, "scripts", "backup")
) and os.path.exists(os.path.join(APPS_SETTING_PATH, app, "scripts", "restore"))
os.path.join(setting_path, "scripts", "backup")
) and os.path.exists(os.path.join(setting_path, "scripts", "restore"))
ret["supports_multi_instance"] = is_true(
local_manifest.get("multi_instance", False)
)

View file

@ -12,6 +12,7 @@ from yunohost.utils.error import YunohostError
logger = logging.getLogger("yunohost.authenticators.ldap_admin")
class Authenticator(BaseAuthenticator):
name = "ldap_admin"
@ -57,7 +58,10 @@ class Authenticator(BaseAuthenticator):
raise
else:
if who != self.admindn:
raise YunohostError(f"Not logged with the appropriate identity ? Found {who}, expected {self.admindn} !?", raw_msg=True)
raise YunohostError(
f"Not logged with the appropriate identity ? Found {who}, expected {self.admindn} !?",
raw_msg=True,
)
finally:
# Free the connection, we don't really need it to keep it open as the point is only to check authentication...
if con:

View file

@ -81,7 +81,8 @@ def pytest_cmdline_main(config):
import yunohost
yunohost.init(debug=config.option.yunodebug)
class DummyInterface():
class DummyInterface:
type = "test"

View file

@ -180,7 +180,9 @@ def test_parse_args_in_yunohost_format_string_input_test_ask():
]
answers = {}
with patch.object(Moulinette.interface, "prompt", return_value="some_value") as prompt:
with patch.object(
Moulinette.interface, "prompt", return_value="some_value"
) as prompt:
_parse_args_in_yunohost_format(answers, questions)
prompt.assert_called_with(ask_text, False)
@ -197,7 +199,9 @@ def test_parse_args_in_yunohost_format_string_input_test_ask_with_default():
]
answers = {}
with patch.object(Moulinette.interface, "prompt", return_value="some_value") as prompt:
with patch.object(
Moulinette.interface, "prompt", return_value="some_value"
) as prompt:
_parse_args_in_yunohost_format(answers, questions)
prompt.assert_called_with("%s (default: %s)" % (ask_text, default_text), False)
@ -215,7 +219,9 @@ def test_parse_args_in_yunohost_format_string_input_test_ask_with_example():
]
answers = {}
with patch.object(Moulinette.interface, "prompt", return_value="some_value") as prompt:
with patch.object(
Moulinette.interface, "prompt", return_value="some_value"
) as prompt:
_parse_args_in_yunohost_format(answers, questions)
assert ask_text in prompt.call_args[0][0]
assert example_text in prompt.call_args[0][0]
@ -234,7 +240,9 @@ def test_parse_args_in_yunohost_format_string_input_test_ask_with_help():
]
answers = {}
with patch.object(Moulinette.interface, "prompt", return_value="some_value") as prompt:
with patch.object(
Moulinette.interface, "prompt", return_value="some_value"
) as prompt:
_parse_args_in_yunohost_format(answers, questions)
assert ask_text in prompt.call_args[0][0]
assert help_text in prompt.call_args[0][0]
@ -462,7 +470,9 @@ def test_parse_args_in_yunohost_format_password_input_test_ask():
]
answers = {}
with patch.object(Moulinette.interface, "prompt", return_value="some_value") as prompt:
with patch.object(
Moulinette.interface, "prompt", return_value="some_value"
) as prompt:
_parse_args_in_yunohost_format(answers, questions)
prompt.assert_called_with(ask_text, True)
@ -481,7 +491,9 @@ def test_parse_args_in_yunohost_format_password_input_test_ask_with_example():
]
answers = {}
with patch.object(Moulinette.interface, "prompt", return_value="some_value") as prompt:
with patch.object(
Moulinette.interface, "prompt", return_value="some_value"
) as prompt:
_parse_args_in_yunohost_format(answers, questions)
assert ask_text in prompt.call_args[0][0]
assert example_text in prompt.call_args[0][0]
@ -501,7 +513,9 @@ def test_parse_args_in_yunohost_format_password_input_test_ask_with_help():
]
answers = {}
with patch.object(Moulinette.interface, "prompt", return_value="some_value") as prompt:
with patch.object(
Moulinette.interface, "prompt", return_value="some_value"
) as prompt:
_parse_args_in_yunohost_format(answers, questions)
assert ask_text in prompt.call_args[0][0]
assert help_text in prompt.call_args[0][0]
@ -697,7 +711,9 @@ def test_parse_args_in_yunohost_format_path_input_test_ask():
]
answers = {}
with patch.object(Moulinette.interface, "prompt", return_value="some_value") as prompt:
with patch.object(
Moulinette.interface, "prompt", return_value="some_value"
) as prompt:
_parse_args_in_yunohost_format(answers, questions)
prompt.assert_called_with(ask_text, False)
@ -715,7 +731,9 @@ def test_parse_args_in_yunohost_format_path_input_test_ask_with_default():
]
answers = {}
with patch.object(Moulinette.interface, "prompt", return_value="some_value") as prompt:
with patch.object(
Moulinette.interface, "prompt", return_value="some_value"
) as prompt:
_parse_args_in_yunohost_format(answers, questions)
prompt.assert_called_with("%s (default: %s)" % (ask_text, default_text), False)
@ -734,7 +752,9 @@ def test_parse_args_in_yunohost_format_path_input_test_ask_with_example():
]
answers = {}
with patch.object(Moulinette.interface, "prompt", return_value="some_value") as prompt:
with patch.object(
Moulinette.interface, "prompt", return_value="some_value"
) as prompt:
_parse_args_in_yunohost_format(answers, questions)
assert ask_text in prompt.call_args[0][0]
assert example_text in prompt.call_args[0][0]
@ -754,7 +774,9 @@ def test_parse_args_in_yunohost_format_path_input_test_ask_with_help():
]
answers = {}
with patch.object(Moulinette.interface, "prompt", return_value="some_value") as prompt:
with patch.object(
Moulinette.interface, "prompt", return_value="some_value"
) as prompt:
_parse_args_in_yunohost_format(answers, questions)
assert ask_text in prompt.call_args[0][0]
assert help_text in prompt.call_args[0][0]

View file

@ -7,6 +7,7 @@ from yunohost.tools import tools_adminpw
from moulinette import m18n
from moulinette.core import MoulinetteError
def setup_function(function):
if os.system("systemctl is-active slapd") != 0:
@ -23,7 +24,7 @@ def test_authenticate_with_wrong_password():
with pytest.raises(MoulinetteError) as exception:
LDAPAuth().authenticate_credentials(credentials="bad_password_lul")
translation = m18n.g("invalid_password")
translation = m18n.n("invalid_password")
expected_msg = translation.format()
assert expected_msg in str(exception)
@ -51,7 +52,7 @@ def test_authenticate_change_password():
with pytest.raises(MoulinetteError) as exception:
LDAPAuth().authenticate_credentials(credentials="yunohost")
translation = m18n.g("invalid_password")
translation = m18n.n("invalid_password")
expected_msg = translation.format()
assert expected_msg in str(exception)

View file

@ -56,7 +56,7 @@ def _get_ldap_interface():
def _ldap_path_extract(path, info):
for element in path.split(","):
if element.startswith(info + "="):
return element[len(info + "="):]
return element[len(info + "=") :]
# Add this to properly close / delete the ldap interface / authenticator
@ -72,8 +72,7 @@ def _destroy_ldap_interface():
atexit.register(_destroy_ldap_interface)
class LDAPInterface():
class LDAPInterface:
def __init__(self):
logger.debug("initializing ldap interface")