Updated packaging documentation & scripts.

This commit is contained in:
Joe Testa
2026-07-05 13:08:39 -04:00
parent dbf8b69633
commit 33594a5caa
5 changed files with 78 additions and 22 deletions
+12 -4
View File
@@ -18,7 +18,7 @@ An executable can only be made on a Windows host because the PyInstaller tool (h
To create package and upload to test server (hint: use API token for test.pypi.org):
```
$ sudo apt install python3-virtualenv python3.12-venv
$ sudo apt install python3-virtualenv python3.14-venv
$ make -f Makefile.pypi
$ make -f Makefile.pypi uploadtest
```
@@ -48,7 +48,7 @@ To download from production server and verify:
# Snap
To create the Snap package, run a fully-updated Ubuntu Server 24.04 VM.
To create the Snap package, run a fully-updated Ubuntu Server 26.04 VM.
Create the Snap package with:
```
@@ -68,9 +68,17 @@ Upload the Snap with:
# Docker
Ensure that the `buildx` plugin is available by following the installation instructions available at: https://docs.docker.com/engine/install/ubuntu/
On an Ubuntu Server 26.06 VM, install dependencies with:
```
# apt install docker.io docker-buildx
```
Build a local image with:
Ensure that your non-root build user can access the docker daemon with by adding it to the `docker` group:
```
# usermod -a -G docker build_user
```
As a non-root user, build a local image with:
```
$ make -f Makefile.docker
+3 -3
View File
@@ -51,7 +51,7 @@ usage: ssh-audit.py [-h] [-4] [-6] [-b] [-c] [-d]
[--socks5 host:port] [--threads N]
[host]
# ssh-audit.py v3.4.0-dev, https://github.com/jtesta/ssh-audit
# ssh-audit.py v3.4.1-dev, https://github.com/jtesta/ssh-audit
positional arguments:
host target hostname or IPv4/IPv6 address
@@ -239,9 +239,9 @@ $ snap install ssh-audit
To install from Dockerhub:
```
$ docker pull positronsecurity/ssh-audit
$ docker pull docker.io/positronsecurity/ssh-audit
```
(Then run with: `docker run -it --rm -p 2222:2222 positronsecurity/ssh-audit 10.1.1.1`)
(Then run with: `docker run -it --rm -p 2222:2222 docker.io/positronsecurity/ssh-audit 10.1.1.1`)
The status of various other platform packages can be found below (via Repology):
+41 -6
View File
@@ -3,7 +3,7 @@
#
# The MIT License (MIT)
#
# Copyright (C) 2021-2024 Joe Testa (jtesta@positronsecurity.com)
# Copyright (C) 2021-2026 Joe Testa (jtesta@positronsecurity.com)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -32,19 +32,23 @@
# Pre-requisites
echo "Installing pre-requisites..."
sudo apt install -y make
sudo snap install snapcraft --classic
sudo snap install review-tools lxd
# Initialize LXD.
echo -e "\nInitializing LXD..."
sudo lxd init --auto
# Reset the filesystem from any previous runs.
rm -rf parts/ prime/ snap/ stage/ build/ dist/ src/*.egg-info/ ssh-audit*.snap
# Reset local files that may have been changed through a previous run.
echo "Resetting local files..."
rm -f ssh-audit*.snap
git checkout snapcraft.yaml 2> /dev/null
git checkout src/ssh_audit/globals.py 2> /dev/null
# Add the built-in manual page.
echo "Processing man page..."
./add_builtin_man_page.sh
# Get the version from the globals.py file.
@@ -67,10 +71,41 @@ if [[ ! $snap_version =~ ^[0-9]\.[0-9]\.[0-9]\-[0-9]$ ]]; then
exit 1
fi
# Append the version field to the end of the file. Not pretty, but it works.
echo -e "\nversion: '${snap_version}'" >> snapcraft.yaml
# Set the version field.
sed -i "s/version: \"\"/version: \"${snap_version}\"/" snapcraft.yaml
# Ensure we set the version field correctly.
grep "version: \"${snap_version}\"" snapcraft.yaml > /dev/null 2> /dev/null
if [[ $? != 0 ]]; then
echo "Failed to set version field in snapcraft.yaml."
exit 1
fi
# Set the SNAP_PACKAGE variable to True so that file permission errors give more user-friendly
sed -i 's/SNAP_PACKAGE = False/SNAP_PACKAGE = True/' src/ssh_audit/globals.py
snapcraft --use-lxd && echo -e "\nDone.\n"
# Clean any previous builds.
echo "Running 'snapcraft clean'..."
snapcraft clean
# Build the snap file.
echo "Running 'snapcraft pack --use-lxd'..."
snapcraft pack --use-lxd
if [[ $? != 0 ]]; then
echo -e "\nPack process failed: $?"
exit 1
else
echo -e "Pack process succeeded."
fi
# Run the linter on it.
echo "Running 'snapcraft lint' on *.snap..."
snapcraft lint --quiet *.snap
if [[ $? != 0 ]]; then
echo -e "\nLint process failed: $?"
exit 1
else
echo -e "Lint process succeeded."
fi
echo -e "\nDone!\n"
+16 -6
View File
@@ -1,15 +1,24 @@
name: ssh-audit
# 'version' field will be automatically added by build_snap.sh.
license: 'MIT'
title: ssh-audit
summary: ssh-audit
version: "" # Set at run-time by build_snap.sh.
license: 'MIT'
description: |
SSH server and client security configuration auditor. Official repository: <https://github.com/jtesta/ssh-audit>
base: core22
contact:
- https://github.com/jtesta/ssh-audit/issues
issues:
- https://github.com/jtesta/ssh-audit/issues
source-code:
- https://github.com/jtesta/ssh-audit
website:
- https://github.com/jtesta/ssh-audit
base: core26
grade: stable
confinement: strict
architectures:
- build-on: [amd64]
platforms:
all:
build-on: [amd64]
build-for: [all]
apps:
@@ -20,4 +29,5 @@ apps:
parts:
ssh-audit:
plugin: python
stage-packages: [python3.14, python3.14-venv]
source: .
+5 -2
View File
@@ -326,6 +326,9 @@ class DHEat:
del socket_dict[s]
# Check if this platform has socket.AF_UNIX. Windows does not.
has_af_unix = hasattr(socket, 'AF_UNIX')
# Resolve the target into an IP address
out.d("Resolving target %s..." % aconf.host)
target_address_family, target_ip_address = DHEat._resolve_hostname(aconf.host, aconf.ip_version_preference)
@@ -442,7 +445,7 @@ class DHEat:
s.setblocking(False)
# out.d("Creating socket (%u of %u already exist)..." % (len(socket_dict), concurrent_sockets), write_now=True)
if target_address_family == socket.AF_UNIX:
if has_af_unix and (target_address_family == socket.AF_UNIX):
ret = s.connect_ex(target_ip_address)
else:
ret = s.connect_ex((target_ip_address, aconf.port))
@@ -912,7 +915,7 @@ class DHEat:
now = time.time()
if (now - last_update) >= 1.0:
seconds_running = now - self.start_timer
print(f"{self.WHITEB}{spinner[spinner_index]}{self.CLEAR} TCP SYNs/sec: {self.BLUEB}{int(self.num_attempted_tcp_connections / seconds_running):,d}{self.CLEAR}; Compl. conns/sec: {self.BLUEB}{int(self.num_successful_tcp_connections / seconds_running):,d}{self.CLEAR}; Bytes sent/sec: {self.BLUEB}{DHEat.add_byte_units(self.num_bytes_written / seconds_running)}{self.CLEAR}; DH kex/sec: {self.PURPLEB}{self.num_successful_dh_kex / seconds_running:,.1f}{self.CLEAR} \r", end="")
print(f"{self.WHITEB}{spinner[spinner_index]}{self.CLEAR} TCP SYNs/sec: {self.BLUEB}{int(self.num_attempted_tcp_connections / seconds_running):,d}{self.CLEAR}; Compl. conns/sec: {self.BLUEB}{self.num_successful_tcp_connections / seconds_running:,.1f}{self.CLEAR}; Bytes sent/sec: {self.BLUEB}{DHEat.add_byte_units(self.num_bytes_written / seconds_running)}{self.CLEAR}; DH kex/sec: {self.PURPLEB}{self.num_successful_dh_kex / seconds_running:,.1f}{self.CLEAR} \r", end="")
last_update = now
spinner_index = (spinner_index + 1) % 4