mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Merge branch 'dev' of https://github.com/YunoHost/yunohost into dev
This commit is contained in:
commit
75f1b26ee1
13 changed files with 152 additions and 42 deletions
|
@ -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 *
|
||||
|
|
76
data/hooks/diagnosis/80-apps.py
Normal file
76
data/hooks/diagnosis/80-apps.py
Normal 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()
|
|
@ -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.",
|
||||
|
|
|
@ -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."
|
||||
}
|
||||
}
|
|
@ -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.",
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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}"
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -81,7 +81,8 @@ def pytest_cmdline_main(config):
|
|||
import yunohost
|
||||
|
||||
yunohost.init(debug=config.option.yunodebug)
|
||||
class DummyInterface():
|
||||
|
||||
class DummyInterface:
|
||||
|
||||
type = "test"
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue