fix: resolve all ruff lint errors and SQLite UNIQUE constraint issue
Ruff fixes (20 errors → 0): - F401: Remove unused imports (DeckyConfig, random_hostname, IniConfig, COMPOSE_FILE, sys, patch) across cli.py, mutator/engine.py, templates/ftp, templates/rdp, test_mysql.py, test_postgres.py - F541: Remove extraneous f-prefixes on strings with no placeholders in templates/imap, test_ftp_live, test_http_live - E741: Rename ambiguous variable 'l' to descriptive names (line, entry, part) across conftest.py, test_ftp_live, test_http_live, test_mongodb_live, test_pop3, test_ssh SQLite fix: - Change _initialize_sync() admin seeding from SELECT-then-INSERT to INSERT OR IGNORE, preventing IntegrityError when admin user already exists from a previous run
This commit is contained in:
@@ -24,13 +24,11 @@ from decnet.env import (
|
|||||||
)
|
)
|
||||||
from decnet.archetypes import Archetype, all_archetypes, get_archetype
|
from decnet.archetypes import Archetype, all_archetypes, get_archetype
|
||||||
from decnet.config import (
|
from decnet.config import (
|
||||||
DeckyConfig,
|
|
||||||
DecnetConfig,
|
DecnetConfig,
|
||||||
random_hostname,
|
|
||||||
)
|
)
|
||||||
from decnet.distros import all_distros, get_distro
|
from decnet.distros import all_distros, get_distro
|
||||||
from decnet.fleet import all_service_names, build_deckies, build_deckies_from_ini
|
from decnet.fleet import all_service_names, build_deckies, build_deckies_from_ini
|
||||||
from decnet.ini_loader import IniConfig, load_ini
|
from decnet.ini_loader import load_ini
|
||||||
from decnet.network import detect_interface, detect_subnet, allocate_ips, get_host_ip
|
from decnet.network import detect_interface, detect_subnet, allocate_ips, get_host_ip
|
||||||
from decnet.services.registry import all_services
|
from decnet.services.registry import all_services
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from decnet.archetypes import get_archetype
|
|||||||
from decnet.fleet import all_service_names
|
from decnet.fleet import all_service_names
|
||||||
from decnet.composer import write_compose
|
from decnet.composer import write_compose
|
||||||
from decnet.config import DeckyConfig, load_state, save_state
|
from decnet.config import DeckyConfig, load_state, save_state
|
||||||
from decnet.engine import COMPOSE_FILE, _compose_with_retry
|
from decnet.engine import _compose_with_retry
|
||||||
|
|
||||||
import subprocess # nosec B404
|
import subprocess # nosec B404
|
||||||
|
|
||||||
|
|||||||
@@ -33,25 +33,20 @@ class SQLiteRepository(BaseRepository):
|
|||||||
from decnet.web.db.sqlite.database import get_sync_engine
|
from decnet.web.db.sqlite.database import get_sync_engine
|
||||||
engine = get_sync_engine(self.db_path)
|
engine = get_sync_engine(self.db_path)
|
||||||
with engine.connect() as conn:
|
with engine.connect() as conn:
|
||||||
result = conn.execute(
|
conn.execute(
|
||||||
text("SELECT uuid FROM users WHERE username = :u"),
|
text(
|
||||||
{"u": DECNET_ADMIN_USER},
|
"INSERT OR IGNORE INTO users (uuid, username, password_hash, role, must_change_password) "
|
||||||
|
"VALUES (:uuid, :u, :p, :r, :m)"
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"uuid": str(uuid.uuid4()),
|
||||||
|
"u": DECNET_ADMIN_USER,
|
||||||
|
"p": get_password_hash(DECNET_ADMIN_PASSWORD),
|
||||||
|
"r": "admin",
|
||||||
|
"m": 1,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if not result.fetchone():
|
conn.commit()
|
||||||
conn.execute(
|
|
||||||
text(
|
|
||||||
"INSERT INTO users (uuid, username, password_hash, role, must_change_password) "
|
|
||||||
"VALUES (:uuid, :u, :p, :r, :m)"
|
|
||||||
),
|
|
||||||
{
|
|
||||||
"uuid": str(uuid.uuid4()),
|
|
||||||
"u": DECNET_ADMIN_USER,
|
|
||||||
"p": get_password_hash(DECNET_ADMIN_PASSWORD),
|
|
||||||
"r": "admin",
|
|
||||||
"m": 1,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
async def initialize(self) -> None:
|
async def initialize(self) -> None:
|
||||||
"""Async warm-up / verification."""
|
"""Async warm-up / verification."""
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ forwards events as JSON to LOG_TARGET if set.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from twisted.internet import defer, reactor
|
from twisted.internet import defer, reactor
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ NODE_NAME = os.environ.get("NODE_NAME", "mailserver")
|
|||||||
SERVICE_NAME = "imap"
|
SERVICE_NAME = "imap"
|
||||||
LOG_TARGET = os.environ.get("LOG_TARGET", "")
|
LOG_TARGET = os.environ.get("LOG_TARGET", "")
|
||||||
PORT = int(os.environ.get("PORT", "143"))
|
PORT = int(os.environ.get("PORT", "143"))
|
||||||
IMAP_BANNER = os.environ.get("IMAP_BANNER", f"* OK Dovecot ready.\r\n")
|
IMAP_BANNER = os.environ.get("IMAP_BANNER", "* OK Dovecot ready.\r\n")
|
||||||
_RAW_USERS = os.environ.get("IMAP_USERS", "admin:admin123,root:toor,mail:mail,user:user")
|
_RAW_USERS = os.environ.get("IMAP_USERS", "admin:admin123,root:toor,mail:mail,user:user")
|
||||||
|
|
||||||
VALID_USERS: dict[str, str] = {
|
VALID_USERS: dict[str, str] = {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ LOG_TARGET if set.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
|
|
||||||
from twisted.internet import protocol, reactor
|
from twisted.internet import protocol, reactor
|
||||||
from twisted.python import log as twisted_log
|
from twisted.python import log as twisted_log
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ def assert_rfc5424(
|
|||||||
criteria = {"service": service, "event_type": event_type, **fields}
|
criteria = {"service": service, "event_type": event_type, **fields}
|
||||||
raise AssertionError(
|
raise AssertionError(
|
||||||
f"No RFC 5424 line matching {criteria!r} found among {len(lines)} lines:\n"
|
f"No RFC 5424 line matching {criteria!r} found among {len(lines)} lines:\n"
|
||||||
+ "\n".join(f" {l!r}" for l in lines[:20])
|
+ "\n".join(f" {line!r}" for line in lines[:20])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,5 +35,5 @@ class TestFTPLive:
|
|||||||
ftp.close()
|
ftp.close()
|
||||||
lines = drain()
|
lines = drain()
|
||||||
# At least one RFC 5424 line from the ftp service
|
# At least one RFC 5424 line from the ftp service
|
||||||
rfc_lines = [l for l in lines if "<" in l and ">1 " in l and "ftp" in l]
|
rfc_lines = [line for line in lines if "<" in line and ">1 " in line and "ftp" in line]
|
||||||
assert rfc_lines, f"No ftp RFC 5424 lines found. stdout:\n" + "\n".join(lines[:15])
|
assert rfc_lines, "No ftp RFC 5424 lines found. stdout:\n" + "\n".join(lines[:15])
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ class TestHTTPLive:
|
|||||||
)
|
)
|
||||||
lines = drain()
|
lines = drain()
|
||||||
# body field present in log line
|
# body field present in log line
|
||||||
assert any("body=" in l for l in lines if "request" in l), (
|
assert any("body=" in line for line in lines if "request" in line), (
|
||||||
f"Expected 'body=' in request log line. Got:\n" + "\n".join(lines[:10])
|
"Expected 'body=' in request log line. Got:\n" + "\n".join(lines[:10])
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_method_and_path_in_log(self, live_service):
|
def test_method_and_path_in_log(self, live_service):
|
||||||
|
|||||||
@@ -65,6 +65,6 @@ class TestMongoDBLive:
|
|||||||
client.close()
|
client.close()
|
||||||
lines = drain()
|
lines = drain()
|
||||||
# At least one message was exchanged
|
# At least one message was exchanged
|
||||||
assert any("mongodb" in l for l in lines), (
|
assert any("mongodb" in line for line in lines), (
|
||||||
"Expected at least one mongodb log line"
|
"Expected at least one mongodb log line"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ length fields that could cause huge buffer allocations.
|
|||||||
import importlib.util
|
import importlib.util
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from hypothesis import given, settings
|
from hypothesis import given, settings
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ def test_pop3_list_returns_10_entries(pop3_mod):
|
|||||||
resp = _replies(written).decode()
|
resp = _replies(written).decode()
|
||||||
assert resp.startswith("+OK 10")
|
assert resp.startswith("+OK 10")
|
||||||
# Count individual message lines: "N size\r\n"
|
# Count individual message lines: "N size\r\n"
|
||||||
entries = [l for l in resp.split("\r\n") if l and l[0].isdigit()]
|
entries = [entry for entry in resp.split("\r\n") if entry and entry[0].isdigit()]
|
||||||
assert len(entries) == 10
|
assert len(entries) == 10
|
||||||
|
|
||||||
|
|
||||||
@@ -225,7 +225,7 @@ def test_pop3_top_3_body_lines_count(pop3_mod):
|
|||||||
parts = resp.split("\r\n\r\n", 1)
|
parts = resp.split("\r\n\r\n", 1)
|
||||||
assert len(parts) == 2
|
assert len(parts) == 2
|
||||||
body_section = parts[1].rstrip("\r\n.")
|
body_section = parts[1].rstrip("\r\n.")
|
||||||
body_lines = [l for l in body_section.split("\r\n") if l != "."]
|
body_lines = [part for part in body_section.split("\r\n") if part != "."]
|
||||||
assert len(body_lines) <= 3
|
assert len(body_lines) <= 3
|
||||||
|
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ def test_pop3_uidl_returns_10_entries(pop3_mod):
|
|||||||
_send(proto, "UIDL")
|
_send(proto, "UIDL")
|
||||||
resp = _replies(written).decode()
|
resp = _replies(written).decode()
|
||||||
assert resp.startswith("+OK")
|
assert resp.startswith("+OK")
|
||||||
entries = [l for l in resp.split("\r\n") if l and l[0].isdigit()]
|
entries = [entry for entry in resp.split("\r\n") if entry and entry[0].isdigit()]
|
||||||
assert len(entries) == 10
|
assert len(entries) == 10
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ tests for zero/tiny/huge msg_len in both the startup and auth states.
|
|||||||
import importlib.util
|
import importlib.util
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from hypothesis import given, settings
|
from hypothesis import given, settings
|
||||||
|
|||||||
@@ -112,8 +112,8 @@ def test_dockerfile_has_rsyslog():
|
|||||||
|
|
||||||
|
|
||||||
def test_dockerfile_runs_as_root():
|
def test_dockerfile_runs_as_root():
|
||||||
lines = [l.strip() for l in _dockerfile_text().splitlines()]
|
lines = [line.strip() for line in _dockerfile_text().splitlines()]
|
||||||
user_lines = [l for l in lines if l.startswith("USER ")]
|
user_lines = [line for line in lines if line.startswith("USER ")]
|
||||||
assert user_lines == [], f"Unexpected USER directive(s): {user_lines}"
|
assert user_lines == [], f"Unexpected USER directive(s): {user_lines}"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user