This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch sbp
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
The following commit(s) were added to refs/heads/sbp by this push:
new 030b4fc3 Use the intersection of algorithms from asyncssh and ssh-audit
030b4fc3 is described below
commit 030b4fc39add34172696cc0c222fa4751db38d00
Author: Sean B. Palmer <[email protected]>
AuthorDate: Fri Feb 20 16:52:06 2026 +0000
Use the intersection of algorithms from asyncssh and ssh-audit
---
atr/ssh.py | 18 ++++++++++++++++++
atr/util.py | 39 +++++++++++++++++++++++----------------
pyproject.toml | 1 +
requirements-for-pip-audit.txt | 4 +++-
uv.lock | 19 +++++++++++++++----
5 files changed, 60 insertions(+), 21 deletions(-)
diff --git a/atr/ssh.py b/atr/ssh.py
index 78876cba..6f9d1433 100644
--- a/atr/ssh.py
+++ b/atr/ssh.py
@@ -31,6 +31,10 @@ from typing import Any, Final
import aiofiles
import aiofiles.os
import asyncssh
+import asyncssh.encryption as encryption
+import asyncssh.kex as kex
+import asyncssh.mac as mac
+import ssh_audit.builtin_policies as builtin_policies
import atr.attestable as attestable
import atr.config as config
@@ -44,6 +48,17 @@ import atr.util as util
_CONFIG: Final = config.get()
+_SSH_AUDIT_POLICY: Final = builtin_policies.BUILTIN_POLICIES["Hardened OpenSSH
Server v9.9 (version 1)"]
+
+_ASYNCSSH_SUPPORTED_ENC: Final = {bytes(a) for a in
encryption.get_encryption_algs()}
+_ASYNCSSH_SUPPORTED_KEX: Final = {bytes(a) for a in kex.get_kex_algs()}
+_ASYNCSSH_SUPPORTED_MAC: Final = {bytes(a) for a in mac.get_mac_algs()}
+
+
+_APPROVED_CIPHERS: Final = util.intersect_algs(_SSH_AUDIT_POLICY, "ciphers",
_ASYNCSSH_SUPPORTED_ENC)
+_APPROVED_KEX: Final = util.intersect_algs(_SSH_AUDIT_POLICY, "kex",
_ASYNCSSH_SUPPORTED_KEX)
+_APPROVED_MACS: Final = util.intersect_algs(_SSH_AUDIT_POLICY, "macs",
_ASYNCSSH_SUPPORTED_MAC)
+
class RsyncArgsError(Exception):
"""Exception raised when the rsync arguments are invalid."""
@@ -179,6 +194,9 @@ async def server_start() -> asyncssh.SSHAcceptor:
host=_CONFIG.SSH_HOST,
port=_CONFIG.SSH_PORT,
encoding=None,
+ encryption_algs=_APPROVED_CIPHERS,
+ kex_algs=_APPROVED_KEX,
+ mac_algs=_APPROVED_MACS,
)
log.info(f"SSH server started on {_CONFIG.SSH_HOST}:{_CONFIG.SSH_PORT}")
diff --git a/atr/util.py b/atr/util.py
index 1c30d07b..f6f019ee 100644
--- a/atr/util.py
+++ b/atr/util.py
@@ -196,22 +196,6 @@ async def async_temporary_directory(
log.exception(f"Failed to remove temporary directory
{temp_dir_path}")
-async def atomic_write_file(file_path: pathlib.Path, content: str, encoding:
str = "utf-8") -> None:
- """Atomically write content to a file using a temporary file."""
- await aiofiles.os.makedirs(file_path.parent, exist_ok=True)
- temp_path = file_path.parent / f".{file_path.name}.{uuid.uuid4()}.tmp"
- try:
- async with aiofiles.open(temp_path, "w", encoding=encoding) as f:
- await f.write(content)
- await f.flush()
- await asyncio.to_thread(os.fsync, f.fileno())
- await aiofiles.os.rename(temp_path, file_path)
- except Exception:
- with contextlib.suppress(FileNotFoundError):
- await aiofiles.os.remove(temp_path)
- raise
-
-
async def atomic_modify_file(
file_path: pathlib.Path,
modify: Callable[[str], str],
@@ -233,6 +217,22 @@ async def atomic_modify_file(
await asyncio.to_thread(os.close, lock_fd)
+async def atomic_write_file(file_path: pathlib.Path, content: str, encoding:
str = "utf-8") -> None:
+ """Atomically write content to a file using a temporary file."""
+ await aiofiles.os.makedirs(file_path.parent, exist_ok=True)
+ temp_path = file_path.parent / f".{file_path.name}.{uuid.uuid4()}.tmp"
+ try:
+ async with aiofiles.open(temp_path, "w", encoding=encoding) as f:
+ await f.write(content)
+ await f.flush()
+ await asyncio.to_thread(os.fsync, f.fileno())
+ await aiofiles.os.rename(temp_path, file_path)
+ except Exception:
+ with contextlib.suppress(FileNotFoundError):
+ await aiofiles.os.remove(temp_path)
+ raise
+
+
def chmod_directories(path: pathlib.Path, permissions: int =
DIRECTORY_PERMISSIONS) -> None:
# codeql[py/overly-permissive-file]
os.chmod(path, permissions)
@@ -635,6 +635,13 @@ async def has_files(release: sql.Release) -> bool:
return False
+def intersect_algs(policy: dict[str, Any], policy_key: str, supported:
set[bytes]) -> list[str]:
+ algs = policy[policy_key]
+ if not isinstance(algs, list):
+ raise TypeError(f"ssh-audit policy '{policy_key}' is not a list")
+ return [a for a in algs if isinstance(a, str) and (a.encode("ascii") in
supported)]
+
+
def is_dev_environment() -> bool:
conf = config.get()
for development_host in ("127.0.0.1", "atr", "atr-dev",
"localhost.apache.org"):
diff --git a/pyproject.toml b/pyproject.toml
index 4e5e1e07..ad547edb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -50,6 +50,7 @@ dependencies = [
"rich~=14.0.0",
"semver>=3.0.4",
"sqlmodel~=0.0.24",
+ "ssh-audit>=3.3.0",
"standard-imghdr>=3.13.0",
"strictyaml>=1.7.3",
"structlog>=25.5.0",
diff --git a/requirements-for-pip-audit.txt b/requirements-for-pip-audit.txt
index 34aa6df2..9464aa0f 100644
--- a/requirements-for-pip-audit.txt
+++ b/requirements-for-pip-audit.txt
@@ -324,7 +324,9 @@ sqlalchemy==2.0.46
# via
# alembic
# sqlmodel
-sqlmodel==0.0.34
+sqlmodel==0.0.35
+ # via tooling-trusted-releases
+ssh-audit==3.3.0
# via tooling-trusted-releases
standard-imghdr==3.13.0
# via tooling-trusted-releases
diff --git a/uv.lock b/uv.lock
index f8650a0e..98d1be08 100644
--- a/uv.lock
+++ b/uv.lock
@@ -3,7 +3,7 @@ revision = 3
requires-python = "==3.13.*"
[options]
-exclude-newer = "2026-02-20T16:30:57Z"
+exclude-newer = "2026-02-20T16:45:38Z"
[[package]]
name = "aiofiles"
@@ -1826,15 +1826,24 @@ wheels = [
[[package]]
name = "sqlmodel"
-version = "0.0.34"
+version = "0.0.35"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pydantic" },
{ name = "sqlalchemy" },
]
-sdist = { url =
"https://files.pythonhosted.org/packages/3b/6a/b1b26d589063e53a08c10a2d7bc624cba63dec045a312758d68f550a4ea1/sqlmodel-0.0.34.tar.gz",
hash =
"sha256:577e4aae1ba96ee5038e03d8b1404c642dad1a92e628988cdf4ce68d27abe982", size
= 96236, upload-time = "2026-02-16T19:06:34.275Z" }
+sdist = { url =
"https://files.pythonhosted.org/packages/a6/fd/6f468f52977b85f8b1af3f0d7d4396ed77804a59bf589f2f47c524383388/sqlmodel-0.0.35.tar.gz",
hash =
"sha256:e0079a6ec569323587ffb7326bbbc9d9a1a92e9be271b18e83f54d4a4200d6ac", size
= 86087, upload-time = "2026-02-20T16:42:21.254Z" }
wheels = [
- { url =
"https://files.pythonhosted.org/packages/eb/ee/1910f4eee41af4268b0d8cd688a05fb8ea23e9e6c64b8710592df24a8c66/sqlmodel-0.0.34-py3-none-any.whl",
hash =
"sha256:aeabc8f0de32076a0ed9216e88568459d737fca1e7133bfc6d1c657920789a2d", size
= 27445, upload-time = "2026-02-16T19:06:35.709Z" },
+ { url =
"https://files.pythonhosted.org/packages/8f/f3/90f7b2eb86e590b74cf33e37a5313c074092684666355201afe9a1ae7ef5/sqlmodel-0.0.35-py3-none-any.whl",
hash =
"sha256:367c11719bc4967430d5aadc43ee1a6f7638b9c82ee7c8835401400e05ec9431", size
= 27221, upload-time = "2026-02-20T16:42:20.301Z" },
+]
+
+[[package]]
+name = "ssh-audit"
+version = "3.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/3b/ec/e89fdfaaa6f08813e1a5cf926bc0dc155761144ebcac57191b4c8001aae3/ssh_audit-3.3.0.tar.gz",
hash =
"sha256:b76e36ac9844f45d64986c9f293a4b46766a10412dc29fb43bd52d0f6661a5b0", size
= 116958, upload-time = "2024-10-15T21:08:28.632Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/4f/21/2b3cd275bc3c09fc765691f6c005a6683edf47f47c18d2f9eb78c39ca7e6/ssh_audit-3.3.0-py3-none-any.whl",
hash =
"sha256:8d2b22b7bb7c20c9d84452c9f13408015ec76eb025379cc70335e5315e4378d6", size
= 121789, upload-time = "2024-10-15T21:08:27.182Z" },
]
[[package]]
@@ -1920,6 +1929,7 @@ dependencies = [
{ name = "rich" },
{ name = "semver" },
{ name = "sqlmodel" },
+ { name = "ssh-audit" },
{ name = "standard-imghdr" },
{ name = "strictyaml" },
{ name = "structlog" },
@@ -1984,6 +1994,7 @@ requires-dist = [
{ name = "rich", specifier = "~=14.0.0" },
{ name = "semver", specifier = ">=3.0.4" },
{ name = "sqlmodel", specifier = "~=0.0.24" },
+ { name = "ssh-audit", specifier = ">=3.3.0" },
{ name = "standard-imghdr", specifier = ">=3.13.0" },
{ name = "strictyaml", specifier = ">=1.7.3" },
{ name = "structlog", specifier = ">=25.5.0" },
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]