mirror of
https://github.com/chatmail/relay.git
synced 2026-05-10 16:04:37 +00:00
Update iroh and remove iroh. subdomain
This commit is contained in:
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
## untagged
|
## untagged
|
||||||
|
|
||||||
- deploy `iroh-relay` (requires new "iroh.{mail_domain}" DNS entry),
|
- deploy `iroh-relay` and also update "realtime relay services" in privacy policy.
|
||||||
also update "realtime relay services" in privacy policy.
|
|
||||||
([#434](https://github.com/deltachat/chatmail/pull/434))
|
([#434](https://github.com/deltachat/chatmail/pull/434))
|
||||||
|
([#451](https://github.com/deltachat/chatmail/pull/451))
|
||||||
|
|
||||||
- add guide to migrate chatmail to a new server
|
- add guide to migrate chatmail to a new server
|
||||||
([#429](https://github.com/deltachat/chatmail/pull/429))
|
([#429](https://github.com/deltachat/chatmail/pull/429))
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class Config:
|
|||||||
self.disable_ipv6 = params.get("disable_ipv6", "false").lower() == "true"
|
self.disable_ipv6 = params.get("disable_ipv6", "false").lower() == "true"
|
||||||
self.imap_rawlog = params.get("imap_rawlog", "false").lower() == "true"
|
self.imap_rawlog = params.get("imap_rawlog", "false").lower() == "true"
|
||||||
if "iroh_relay" not in params:
|
if "iroh_relay" not in params:
|
||||||
self.iroh_relay = "https://iroh." + params["mail_domain"]
|
self.iroh_relay = "https://" + params["mail_domain"]
|
||||||
self.enable_iroh_relay = True
|
self.enable_iroh_relay = True
|
||||||
else:
|
else:
|
||||||
self.iroh_relay = params["iroh_relay"].strip()
|
self.iroh_relay = params["iroh_relay"].strip()
|
||||||
|
|||||||
@@ -481,8 +481,14 @@ def deploy_mtail(config):
|
|||||||
|
|
||||||
def deploy_iroh_relay(config) -> None:
|
def deploy_iroh_relay(config) -> None:
|
||||||
(url, sha256sum) = {
|
(url, sha256sum) = {
|
||||||
"x86_64": ("https://github.com/n0-computer/iroh/releases/download/v0.27.0/iroh-relay-v0.27.0-x86_64-unknown-linux-musl.tar.gz", "8af7f6d29d17476ce5c3053c3161db5793cb2ac49057d0bcaf689436cdccbeab"),
|
"x86_64": (
|
||||||
"aarch64": ("https://github.com/n0-computer/iroh/releases/download/v0.27.0/iroh-relay-v0.27.0-aarch64-unknown-linux-musl.tar.gz", "18039f0d39df78922a5055a0d4a5a8fa98a2a0e19b1eaa4c3fe6db73b8698697")
|
"https://github.com/n0-computer/iroh/releases/download/v0.28.1/iroh-relay-v0.28.1-x86_64-unknown-linux-musl.tar.gz",
|
||||||
|
"2ffacf7c0622c26b67a5895ee8e07388769599f60e5f52a3bd40a3258db89b2c",
|
||||||
|
),
|
||||||
|
"aarch64": (
|
||||||
|
"https://github.com/n0-computer/iroh/releases/download/v0.28.1/iroh-relay-v0.28.1-aarch64-unknown-linux-musl.tar.gz",
|
||||||
|
"b915037bcc1ff1110cc9fcb5de4a17c00ff576fd2f568cd339b3b2d54c420dc4",
|
||||||
|
),
|
||||||
}[host.get_fact(facts.server.Arch)]
|
}[host.get_fact(facts.server.Arch)]
|
||||||
|
|
||||||
apt.packages(
|
apt.packages(
|
||||||
@@ -493,7 +499,7 @@ def deploy_iroh_relay(config) -> None:
|
|||||||
server.shell(
|
server.shell(
|
||||||
name="Download iroh-relay",
|
name="Download iroh-relay",
|
||||||
commands=[
|
commands=[
|
||||||
f"(echo '{sha256sum} /usr/local/bin/iroh-relay' | sha256sum -c) || curl -L {url} | gunzip | tar -x -f - ./iroh-relay -O >/usr/local/bin/iroh-relay",
|
f"(echo '{sha256sum} /usr/local/bin/iroh-relay' | sha256sum -c) || (curl -L {url} | gunzip | tar -x -f - ./iroh-relay -O >/usr/local/bin/iroh-relay.new && mv /usr/local/bin/iroh-relay.new /usr/local/bin/iroh-relay)",
|
||||||
"chmod 755 /usr/local/bin/iroh-relay",
|
"chmod 755 /usr/local/bin/iroh-relay",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -502,9 +508,7 @@ def deploy_iroh_relay(config) -> None:
|
|||||||
|
|
||||||
systemd_unit = files.put(
|
systemd_unit = files.put(
|
||||||
name="Upload iroh-relay systemd unit",
|
name="Upload iroh-relay systemd unit",
|
||||||
src=importlib.resources.files(__package__).joinpath(
|
src=importlib.resources.files(__package__).joinpath("iroh-relay.service"),
|
||||||
"iroh-relay.service"
|
|
||||||
),
|
|
||||||
dest="/etc/systemd/system/iroh-relay.service",
|
dest="/etc/systemd/system/iroh-relay.service",
|
||||||
user="root",
|
user="root",
|
||||||
group="root",
|
group="root",
|
||||||
@@ -514,13 +518,11 @@ def deploy_iroh_relay(config) -> None:
|
|||||||
|
|
||||||
iroh_config = files.put(
|
iroh_config = files.put(
|
||||||
name=f"Upload iroh-relay config",
|
name=f"Upload iroh-relay config",
|
||||||
src=importlib.resources.files(__package__).joinpath(
|
src=importlib.resources.files(__package__).joinpath("iroh-relay.toml"),
|
||||||
"iroh-relay.toml"
|
|
||||||
),
|
|
||||||
dest=f"/etc/iroh-relay.toml",
|
dest=f"/etc/iroh-relay.toml",
|
||||||
user="iroh",
|
user="root",
|
||||||
group="iroh",
|
group="root",
|
||||||
mode="600",
|
mode="644",
|
||||||
)
|
)
|
||||||
need_restart |= iroh_config.changed
|
need_restart |= iroh_config.changed
|
||||||
|
|
||||||
@@ -533,12 +535,11 @@ def deploy_iroh_relay(config) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def deploy_chatmail(config_path: Path, disable_mail: bool, require_iroh: bool) -> None:
|
def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
|
||||||
"""Deploy a chat-mail instance.
|
"""Deploy a chat-mail instance.
|
||||||
|
|
||||||
:param config_path: path to chatmail.ini
|
:param config_path: path to chatmail.ini
|
||||||
:param disable_mail: whether to disable postfix & dovecot
|
:param disable_mail: whether to disable postfix & dovecot
|
||||||
:param require_iroh: whether to request a TLS certificate for iroh.$mail_domain
|
|
||||||
"""
|
"""
|
||||||
config = read_config(config_path)
|
config = read_config(config_path)
|
||||||
check_config(config)
|
check_config(config)
|
||||||
@@ -616,8 +617,6 @@ def deploy_chatmail(config_path: Path, disable_mail: bool, require_iroh: bool) -
|
|||||||
|
|
||||||
# Deploy acmetool to have TLS certificates.
|
# Deploy acmetool to have TLS certificates.
|
||||||
tls_domains = [mail_domain, f"mta-sts.{mail_domain}", f"www.{mail_domain}"]
|
tls_domains = [mail_domain, f"mta-sts.{mail_domain}", f"www.{mail_domain}"]
|
||||||
if require_iroh:
|
|
||||||
tls_domains.append(f"iroh.{mail_domain}")
|
|
||||||
deploy_acmetool(
|
deploy_acmetool(
|
||||||
domains=tls_domains,
|
domains=tls_domains,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
_mta-sts.{{ mail_domain }}. TXT "v=STSv1; id={{ sts_id }}"
|
_mta-sts.{{ mail_domain }}. TXT "v=STSv1; id={{ sts_id }}"
|
||||||
mta-sts.{{ mail_domain }}. CNAME {{ mail_domain }}.
|
mta-sts.{{ mail_domain }}. CNAME {{ mail_domain }}.
|
||||||
www.{{ mail_domain }}. CNAME {{ mail_domain }}.
|
www.{{ mail_domain }}. CNAME {{ mail_domain }}.
|
||||||
iroh.{{ mail_domain }}. CNAME {{ mail_domain }}.
|
|
||||||
{{ dkim_entry }}
|
{{ dkim_entry }}
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ def run_cmd(args, out):
|
|||||||
|
|
||||||
sshexec = args.get_sshexec()
|
sshexec = args.get_sshexec()
|
||||||
require_iroh = args.config.enable_iroh_relay
|
require_iroh = args.config.enable_iroh_relay
|
||||||
remote_data = dns.get_initial_remote_data(sshexec, args.config.mail_domain, require_iroh)
|
remote_data = dns.get_initial_remote_data(sshexec, args.config.mail_domain)
|
||||||
if not dns.check_initial_remote_data(remote_data, require_iroh, print=out.red):
|
if not dns.check_initial_remote_data(remote_data, print=out.red):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
@@ -111,8 +111,7 @@ def dns_cmd_options(parser):
|
|||||||
def dns_cmd(args, out):
|
def dns_cmd(args, out):
|
||||||
"""Check DNS entries and optionally generate dns zone file."""
|
"""Check DNS entries and optionally generate dns zone file."""
|
||||||
sshexec = args.get_sshexec()
|
sshexec = args.get_sshexec()
|
||||||
require_iroh = args.config.enable_iroh_relay
|
remote_data = dns.get_initial_remote_data(sshexec, args.config.mail_domain)
|
||||||
remote_data = dns.get_initial_remote_data(sshexec, args.config.mail_domain, require_iroh)
|
|
||||||
if not remote_data:
|
if not remote_data:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,8 @@ def main():
|
|||||||
importlib.resources.files("cmdeploy").joinpath("../../../chatmail.ini"),
|
importlib.resources.files("cmdeploy").joinpath("../../../chatmail.ini"),
|
||||||
)
|
)
|
||||||
disable_mail = bool(os.environ.get('CHATMAIL_DISABLE_MAIL'))
|
disable_mail = bool(os.environ.get('CHATMAIL_DISABLE_MAIL'))
|
||||||
require_iroh = bool(os.environ.get('CHATMAIL_REQUIRE_IROH'))
|
|
||||||
|
|
||||||
deploy_chatmail(config_path, disable_mail, require_iroh)
|
deploy_chatmail(config_path, disable_mail)
|
||||||
|
|
||||||
|
|
||||||
if pyinfra.is_cli:
|
if pyinfra.is_cli:
|
||||||
|
|||||||
@@ -6,22 +6,19 @@ from jinja2 import Template
|
|||||||
from . import remote
|
from . import remote
|
||||||
|
|
||||||
|
|
||||||
def get_initial_remote_data(sshexec, mail_domain, iroh_enabled):
|
def get_initial_remote_data(sshexec, mail_domain):
|
||||||
return sshexec.logged(
|
return sshexec.logged(
|
||||||
call=remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=mail_domain, iroh_enabled=iroh_enabled)
|
call=remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=mail_domain)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def check_initial_remote_data(remote_data, require_iroh, *, print=print):
|
def check_initial_remote_data(remote_data, *, print=print):
|
||||||
mail_domain = remote_data["mail_domain"]
|
mail_domain = remote_data["mail_domain"]
|
||||||
if not remote_data["A"] and not remote_data["AAAA"]:
|
if not remote_data["A"] and not remote_data["AAAA"]:
|
||||||
print(f"Missing A and/or AAAA DNS records for {mail_domain}!")
|
print(f"Missing A and/or AAAA DNS records for {mail_domain}!")
|
||||||
elif remote_data["MTA_STS"] != f"{mail_domain}.":
|
elif remote_data["MTA_STS"] != f"{mail_domain}.":
|
||||||
print("Missing MTA-STS CNAME record:")
|
print("Missing MTA-STS CNAME record:")
|
||||||
print(f"mta-sts.{mail_domain}. CNAME {mail_domain}.")
|
print(f"mta-sts.{mail_domain}. CNAME {mail_domain}.")
|
||||||
elif require_iroh and remote_data["IROH"] != f"{mail_domain}.":
|
|
||||||
print("Missing iroh CNAME record:")
|
|
||||||
print(f"iroh.{mail_domain}. CNAME {mail_domain}.")
|
|
||||||
elif remote_data["WWW"] != f"{mail_domain}.":
|
elif remote_data["WWW"] != f"{mail_domain}.":
|
||||||
print("Missing www CNAME record:")
|
print("Missing www CNAME record:")
|
||||||
print(f"www.{mail_domain}. CNAME {mail_domain}.")
|
print(f"www.{mail_domain}. CNAME {mail_domain}.")
|
||||||
|
|||||||
@@ -96,6 +96,26 @@ http {
|
|||||||
include /etc/nginx/fastcgi_params;
|
include /etc/nginx/fastcgi_params;
|
||||||
fastcgi_param SCRIPT_FILENAME /usr/lib/cgi-bin/newemail.py;
|
fastcgi_param SCRIPT_FILENAME /usr/lib/cgi-bin/newemail.py;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Proxy to iroh-relay service.
|
||||||
|
location /relay {
|
||||||
|
proxy_pass http://127.0.0.1:3340;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
# Upgrade header is normally set to "iroh derp http" or "websocket".
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
}
|
||||||
|
|
||||||
|
location /relay/probe {
|
||||||
|
proxy_pass http://127.0.0.1:3340;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /generate_204 {
|
||||||
|
proxy_pass http://127.0.0.1:3340;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Redirect www. to non-www
|
# Redirect www. to non-www
|
||||||
@@ -108,16 +128,4 @@ http {
|
|||||||
return 301 $scheme://{{ config.domain_name }}$request_uri;
|
return 301 $scheme://{{ config.domain_name }}$request_uri;
|
||||||
access_log syslog:server=unix:/dev/log,facility=local7;
|
access_log syslog:server=unix:/dev/log,facility=local7;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Pass iroh. to iroh-relay service.
|
|
||||||
server {
|
|
||||||
listen 8443 ssl;
|
|
||||||
{% if not disable_ipv6 %}
|
|
||||||
listen [::]:8443 ssl;
|
|
||||||
{% endif %}
|
|
||||||
server_name iroh.{{ config.domain_name }};
|
|
||||||
location / {
|
|
||||||
proxy_pass http://127.0.0.1:3340;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import re
|
|||||||
from .rshell import CalledProcessError, shell
|
from .rshell import CalledProcessError, shell
|
||||||
|
|
||||||
|
|
||||||
def perform_initial_checks(mail_domain, iroh_enabled):
|
def perform_initial_checks(mail_domain):
|
||||||
"""Collecting initial DNS settings."""
|
"""Collecting initial DNS settings."""
|
||||||
assert mail_domain
|
assert mail_domain
|
||||||
if not shell("dig", fail_ok=True):
|
if not shell("dig", fail_ok=True):
|
||||||
@@ -23,14 +23,13 @@ def perform_initial_checks(mail_domain, iroh_enabled):
|
|||||||
A = query_dns("A", mail_domain)
|
A = query_dns("A", mail_domain)
|
||||||
AAAA = query_dns("AAAA", mail_domain)
|
AAAA = query_dns("AAAA", mail_domain)
|
||||||
MTA_STS = query_dns("CNAME", f"mta-sts.{mail_domain}")
|
MTA_STS = query_dns("CNAME", f"mta-sts.{mail_domain}")
|
||||||
IROH = query_dns("CNAME", f"iroh.{mail_domain}")
|
|
||||||
WWW = query_dns("CNAME", f"www.{mail_domain}")
|
WWW = query_dns("CNAME", f"www.{mail_domain}")
|
||||||
|
|
||||||
res = dict(mail_domain=mail_domain, A=A, AAAA=AAAA, MTA_STS=MTA_STS, IROH=IROH, WWW=WWW)
|
res = dict(mail_domain=mail_domain, A=A, AAAA=AAAA, MTA_STS=MTA_STS, WWW=WWW)
|
||||||
res["acme_account_url"] = shell("acmetool account-url", fail_ok=True)
|
res["acme_account_url"] = shell("acmetool account-url", fail_ok=True)
|
||||||
res["dkim_entry"] = get_dkim_entry(mail_domain, dkim_selector="opendkim")
|
res["dkim_entry"] = get_dkim_entry(mail_domain, dkim_selector="opendkim")
|
||||||
|
|
||||||
if not MTA_STS or (not IROH and not iroh_enabled) or not WWW or (not A and not AAAA):
|
if not MTA_STS or not WWW or (not A and not AAAA):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
# parse out sts-id if exists, example: "v=STSv1; id=2090123"
|
# parse out sts-id if exists, example: "v=STSv1; id=2090123"
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ class TestSSHExecutor:
|
|||||||
|
|
||||||
def test_perform_initial(self, sshexec, maildomain):
|
def test_perform_initial(self, sshexec, maildomain):
|
||||||
res = sshexec(
|
res = sshexec(
|
||||||
remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain, iroh_enabled=True)
|
remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain)
|
||||||
)
|
)
|
||||||
assert res["A"] or res["AAAA"]
|
assert res["A"] or res["AAAA"]
|
||||||
|
|
||||||
def test_logged(self, sshexec, maildomain, capsys):
|
def test_logged(self, sshexec, maildomain, capsys):
|
||||||
sshexec.logged(
|
sshexec.logged(
|
||||||
remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain, iroh_enabled=True)
|
remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain)
|
||||||
)
|
)
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
assert err.startswith("Collecting")
|
assert err.startswith("Collecting")
|
||||||
@@ -33,7 +33,7 @@ class TestSSHExecutor:
|
|||||||
|
|
||||||
sshexec.verbose = True
|
sshexec.verbose = True
|
||||||
sshexec.logged(
|
sshexec.logged(
|
||||||
remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain, iroh_enabled=True)
|
remote.rdns.perform_initial_checks, kwargs=dict(mail_domain=maildomain)
|
||||||
)
|
)
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
lines = err.split("\n")
|
lines = err.split("\n")
|
||||||
@@ -44,7 +44,7 @@ class TestSSHExecutor:
|
|||||||
try:
|
try:
|
||||||
sshexec.logged(
|
sshexec.logged(
|
||||||
remote.rdns.perform_initial_checks,
|
remote.rdns.perform_initial_checks,
|
||||||
kwargs=dict(mail_domain=None, iroh_enabled=True),
|
kwargs=dict(mail_domain=None),
|
||||||
)
|
)
|
||||||
except sshexec.FuncError as e:
|
except sshexec.FuncError as e:
|
||||||
assert "rdns.py" in str(e)
|
assert "rdns.py" in str(e)
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ def mockdns(mockdns_base):
|
|||||||
"AAAA": {"some.domain": "fde5:cd7a:9e1c:3240:5a99:936f:cdac:53ae"},
|
"AAAA": {"some.domain": "fde5:cd7a:9e1c:3240:5a99:936f:cdac:53ae"},
|
||||||
"CNAME": {
|
"CNAME": {
|
||||||
"mta-sts.some.domain": "some.domain.",
|
"mta-sts.some.domain": "some.domain.",
|
||||||
"iroh.some.domain": "some.domain.",
|
|
||||||
"www.some.domain": "some.domain.",
|
"www.some.domain": "some.domain.",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -36,31 +35,30 @@ def mockdns(mockdns_base):
|
|||||||
|
|
||||||
class TestPerformInitialChecks:
|
class TestPerformInitialChecks:
|
||||||
def test_perform_initial_checks_ok1(self, mockdns):
|
def test_perform_initial_checks_ok1(self, mockdns):
|
||||||
remote_data = remote.rdns.perform_initial_checks("some.domain", iroh_enabled=True)
|
remote_data = remote.rdns.perform_initial_checks("some.domain")
|
||||||
assert remote_data["A"] == mockdns["A"]["some.domain"]
|
assert remote_data["A"] == mockdns["A"]["some.domain"]
|
||||||
assert remote_data["AAAA"] == mockdns["AAAA"]["some.domain"]
|
assert remote_data["AAAA"] == mockdns["AAAA"]["some.domain"]
|
||||||
assert remote_data["MTA_STS"] == mockdns["CNAME"]["mta-sts.some.domain"]
|
assert remote_data["MTA_STS"] == mockdns["CNAME"]["mta-sts.some.domain"]
|
||||||
assert remote_data["IROH"] == mockdns["CNAME"]["iroh.some.domain"]
|
|
||||||
assert remote_data["WWW"] == mockdns["CNAME"]["www.some.domain"]
|
assert remote_data["WWW"] == mockdns["CNAME"]["www.some.domain"]
|
||||||
|
|
||||||
@pytest.mark.parametrize("drop", ["A", "AAAA"])
|
@pytest.mark.parametrize("drop", ["A", "AAAA"])
|
||||||
def test_perform_initial_checks_with_one_of_A_AAAA(self, mockdns, drop):
|
def test_perform_initial_checks_with_one_of_A_AAAA(self, mockdns, drop):
|
||||||
del mockdns[drop]
|
del mockdns[drop]
|
||||||
remote_data = remote.rdns.perform_initial_checks("some.domain", iroh_enabled=True)
|
remote_data = remote.rdns.perform_initial_checks("some.domain")
|
||||||
assert not remote_data[drop]
|
assert not remote_data[drop]
|
||||||
|
|
||||||
l = []
|
l = []
|
||||||
res = check_initial_remote_data(remote_data, require_iroh=True, print=l.append)
|
res = check_initial_remote_data(remote_data, print=l.append)
|
||||||
assert res
|
assert res
|
||||||
assert not l
|
assert not l
|
||||||
|
|
||||||
def test_perform_initial_checks_no_mta_sts(self, mockdns):
|
def test_perform_initial_checks_no_mta_sts(self, mockdns):
|
||||||
del mockdns["CNAME"]["mta-sts.some.domain"]
|
del mockdns["CNAME"]["mta-sts.some.domain"]
|
||||||
remote_data = remote.rdns.perform_initial_checks("some.domain", iroh_enabled=True)
|
remote_data = remote.rdns.perform_initial_checks("some.domain")
|
||||||
assert not remote_data["MTA_STS"]
|
assert not remote_data["MTA_STS"]
|
||||||
|
|
||||||
l = []
|
l = []
|
||||||
res = check_initial_remote_data(remote_data, require_iroh=True, print=l.append)
|
res = check_initial_remote_data(remote_data, print=l.append)
|
||||||
assert not res
|
assert not res
|
||||||
assert len(l) == 2
|
assert len(l) == 2
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user