mirror of
https://github.com/jtesta/ssh-audit.git
synced 2026-05-25 07:21:23 +02:00
Compare commits
11 Commits
58c51e2c2c
...
0c5c0f8771
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c5c0f8771 | |||
| 3b8a75e407 | |||
| 67e11f82b3 | |||
| 2cd96f1785 | |||
| a4b78b752e | |||
| ac540c8b5f | |||
| e11492b7a3 | |||
| 02bc48c574 | |||
| 24d7d46c42 | |||
| e97bbd9782 | |||
| 3116c2e678 |
@@ -0,0 +1 @@
|
|||||||
|
github: jtesta
|
||||||
@@ -7,12 +7,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13.0-rc.2"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
# ssh-audit
|
# ssh-audit
|
||||||
[](https://github.com/jtesta/ssh-audit/blob/master/LICENSE)
|
[](https://github.com/jtesta/ssh-audit/blob/master/LICENSE)
|
||||||
[](https://pypi.org/project/ssh-audit/)
|
|
||||||
[](https://hub.docker.com/r/positronsecurity/ssh-audit)
|
|
||||||
[](https://github.com/jtesta/ssh-audit/actions)
|
[](https://github.com/jtesta/ssh-audit/actions)
|
||||||
[](https://github.com/jtesta/ssh-audit/blob/master/CONTRIBUTING.md)
|
[](https://github.com/jtesta/ssh-audit/blob/master/CONTRIBUTING.md)
|
||||||
|
|
||||||
|
[](https://pypi.org/project/ssh-audit/)
|
||||||
|
[](https://formulae.brew.sh/formula/ssh-audit)
|
||||||
|
[](https://hub.docker.com/r/positronsecurity/ssh-audit)
|
||||||
|
[](https://snapcraft.io/ssh-audit)
|
||||||
|
|
||||||
|
[](https://github.com/sponsors/jtesta)
|
||||||
|
|
||||||
**ssh-audit** is a tool for ssh server & client configuration auditing.
|
**ssh-audit** is a tool for ssh server & client configuration auditing.
|
||||||
|
|
||||||
[jtesta/ssh-audit](https://github.com/jtesta/ssh-audit/) (v2.0+) is the updated and maintained version of ssh-audit forked from [arthepsy/ssh-audit](https://github.com/arthepsy/ssh-audit) (v1.x) due to inactivity.
|
[jtesta/ssh-audit](https://github.com/jtesta/ssh-audit/) (v2.0+) is the updated and maintained version of ssh-audit forked from [arthepsy/ssh-audit](https://github.com/arthepsy/ssh-audit) (v1.x) due to inactivity.
|
||||||
@@ -32,7 +37,7 @@
|
|||||||
- historical information from OpenSSH, Dropbear SSH and libssh;
|
- historical information from OpenSSH, Dropbear SSH and libssh;
|
||||||
- policy scans to ensure adherence to a hardened/standard configuration;
|
- policy scans to ensure adherence to a hardened/standard configuration;
|
||||||
- runs on Linux and Windows;
|
- runs on Linux and Windows;
|
||||||
- supports Python 3.8 - 3.12;
|
- supports Python 3.8 - 3.13;
|
||||||
- no dependencies
|
- no dependencies
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -89,7 +94,9 @@ usage: ssh-audit.py [options] <host>
|
|||||||
-t, --timeout=<secs> timeout (in seconds) for connection and reading
|
-t, --timeout=<secs> timeout (in seconds) for connection and reading
|
||||||
(default: 5)
|
(default: 5)
|
||||||
-T, --targets=<hosts.txt> a file containing a list of target hosts (one
|
-T, --targets=<hosts.txt> a file containing a list of target hosts (one
|
||||||
per line, format HOST[:PORT])
|
per line, format HOST[:PORT]). Use -p/--port
|
||||||
|
to set the default port for all hosts. Use
|
||||||
|
--threads to control concurrent scans.
|
||||||
--threads=<threads> number of threads to use when scanning multiple
|
--threads=<threads> number of threads to use when scanning multiple
|
||||||
targets (-T/--targets) (default: 32)
|
targets (-T/--targets) (default: 32)
|
||||||
-v, --verbose verbose output
|
-v, --verbose verbose output
|
||||||
@@ -214,6 +221,7 @@ For convenience, a web front-end on top of the command-line tool is available at
|
|||||||
## ChangeLog
|
## ChangeLog
|
||||||
|
|
||||||
### v3.3.0-dev (???)
|
### v3.3.0-dev (???)
|
||||||
|
- Added Python 3.13 support.
|
||||||
- Added built-in policies for Ubuntu 24.04 LTS server & client, OpenSSH 9.8, and OpenSSH 9.9.
|
- Added built-in policies for Ubuntu 24.04 LTS server & client, OpenSSH 9.8, and OpenSSH 9.9.
|
||||||
- Added IPv6 support for DHEat and connection rate tests.
|
- Added IPv6 support for DHEat and connection rate tests.
|
||||||
- Added TCP port information to JSON policy scan results; credit [Fabian Malte Kopp](https://github.com/dreizehnutters).
|
- Added TCP port information to JSON policy scan results; credit [Fabian Malte Kopp](https://github.com/dreizehnutters).
|
||||||
@@ -223,6 +231,7 @@ For convenience, a web front-end on top of the command-line tool is available at
|
|||||||
- Fixed DHEat connection rate testing on MacOS X and BSD platforms; credit [Drew Noel](https://github.com/drewmnoel) and [Michael Osipov](https://github.com/michael-o).
|
- Fixed DHEat connection rate testing on MacOS X and BSD platforms; credit [Drew Noel](https://github.com/drewmnoel) and [Michael Osipov](https://github.com/michael-o).
|
||||||
- Fixed invalid JSON output when a socket error occurs while performing a client audit.
|
- Fixed invalid JSON output when a socket error occurs while performing a client audit.
|
||||||
- When scanning multiple targets (using `-T`/`--targets`), the `-p`/`--port` option will now be used as the default port (set to 22 if `-p`/`--port` is not given). Hosts specified in the file can override this default with an explicit port number (i.e.: "host1:1234"). For example, when using `-T targets.txt -p 222`, all hosts in `targets.txt` that do not explicitly include a port number will default to 222; when using `-T targets.txt` (without `-p`), all hosts will use a default of 22.
|
- When scanning multiple targets (using `-T`/`--targets`), the `-p`/`--port` option will now be used as the default port (set to 22 if `-p`/`--port` is not given). Hosts specified in the file can override this default with an explicit port number (i.e.: "host1:1234"). For example, when using `-T targets.txt -p 222`, all hosts in `targets.txt` that do not explicitly include a port number will default to 222; when using `-T targets.txt` (without `-p`), all hosts will use a default of 22.
|
||||||
|
- Now reports ECDSA and DSS fingerprints when in verbose mode; partial credit [Daniel Lenski](https://github.com/dlenskiSB).
|
||||||
- Added 1 new cipher: `grasshopper-ctr128`.
|
- Added 1 new cipher: `grasshopper-ctr128`.
|
||||||
- Added 2 new key exchanges: `mlkem768x25519-sha256`, `sntrup761x25519-sha512`.
|
- Added 2 new key exchanges: `mlkem768x25519-sha256`, `sntrup761x25519-sha512`.
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ classifiers =
|
|||||||
Programming Language :: Python :: 3.10
|
Programming Language :: Python :: 3.10
|
||||||
Programming Language :: Python :: 3.11
|
Programming Language :: Python :: 3.11
|
||||||
Programming Language :: Python :: 3.12
|
Programming Language :: Python :: 3.12
|
||||||
|
Programming Language :: Python :: 3.13
|
||||||
Programming Language :: Python :: Implementation :: CPython
|
Programming Language :: Python :: Implementation :: CPython
|
||||||
Programming Language :: Python :: Implementation :: PyPy
|
Programming Language :: Python :: Implementation :: PyPy
|
||||||
Topic :: Security
|
Topic :: Security
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (C) 2017-2023 Joe Testa (jtesta@positronsecurity.com)
|
Copyright (C) 2017-2024 Joe Testa (jtesta@positronsecurity.com)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -55,6 +55,17 @@ class HostKeyTest:
|
|||||||
|
|
||||||
'ssh-ed448': {'cert': False, 'variable_key_len': False},
|
'ssh-ed448': {'cert': False, 'variable_key_len': False},
|
||||||
# 'ssh-ed448-cert-v01@openssh.com': {'cert': True, 'variable_key_len': False},
|
# 'ssh-ed448-cert-v01@openssh.com': {'cert': True, 'variable_key_len': False},
|
||||||
|
|
||||||
|
'ecdsa-sha2-nistp256': {'cert': False, 'variable_key_len': False},
|
||||||
|
'ecdsa-sha2-nistp384': {'cert': False, 'variable_key_len': False},
|
||||||
|
'ecdsa-sha2-nistp521': {'cert': False, 'variable_key_len': False},
|
||||||
|
|
||||||
|
'ecdsa-sha2-nistp256-cert-v01@openssh.com': {'cert': True, 'variable_key_len': False},
|
||||||
|
'ecdsa-sha2-nistp384-cert-v01@openssh.com': {'cert': True, 'variable_key_len': False},
|
||||||
|
'ecdsa-sha2-nistp521-cert-v01@openssh.com': {'cert': True, 'variable_key_len': False},
|
||||||
|
|
||||||
|
'ssh-dss': {'cert': False, 'variable_key_len': True},
|
||||||
|
'ssh-dss-cert-v01@openssh.com': {'cert': True, 'variable_key_len': True},
|
||||||
}
|
}
|
||||||
|
|
||||||
TWO2K_MODULUS_WARNING = '2048-bit modulus only provides 112-bits of symmetric strength'
|
TWO2K_MODULUS_WARNING = '2048-bit modulus only provides 112-bits of symmetric strength'
|
||||||
@@ -140,7 +151,12 @@ class HostKeyTest:
|
|||||||
_, payload = s.read_packet()
|
_, payload = s.read_packet()
|
||||||
SSH2_Kex.parse(out, payload)
|
SSH2_Kex.parse(out, payload)
|
||||||
except Exception:
|
except Exception:
|
||||||
out.v("Failed to parse server's kex. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
|
msg = "Failed to parse server's kex."
|
||||||
|
if not out.debug:
|
||||||
|
msg += " Re-run in debug mode to see stack trace."
|
||||||
|
|
||||||
|
out.v(msg, write_now=True)
|
||||||
|
out.d("Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Do the initial DH exchange. The server responds back
|
# Do the initial DH exchange. The server responds back
|
||||||
@@ -151,7 +167,12 @@ class HostKeyTest:
|
|||||||
kex_reply = kex_group.recv_reply(s)
|
kex_reply = kex_group.recv_reply(s)
|
||||||
raw_hostkey_bytes = kex_reply if kex_reply is not None else b''
|
raw_hostkey_bytes = kex_reply if kex_reply is not None else b''
|
||||||
except KexDHException:
|
except KexDHException:
|
||||||
out.v("Failed to parse server's host key. Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
|
msg = "Failed to parse server's host key."
|
||||||
|
if not out.debug:
|
||||||
|
msg += " Re-run in debug mode to see stack trace."
|
||||||
|
|
||||||
|
out.v(msg, write_now=True)
|
||||||
|
out.d("Stack trace:\n%s" % str(traceback.format_exc()), write_now=True)
|
||||||
|
|
||||||
# Since parsing this host key failed, there's nothing more to do but close the socket and move on to the next host key type.
|
# Since parsing this host key failed, there's nothing more to do but close the socket and move on to the next host key type.
|
||||||
s.close()
|
s.close()
|
||||||
@@ -191,7 +212,7 @@ class HostKeyTest:
|
|||||||
cakey_warn_str = HostKeyTest.SMALL_ECC_MODULUS_WARNING
|
cakey_warn_str = HostKeyTest.SMALL_ECC_MODULUS_WARNING
|
||||||
|
|
||||||
# Keys smaller than 2048 result in a failure. Keys smaller 3072 result in a warning. Update the database accordingly.
|
# Keys smaller than 2048 result in a failure. Keys smaller 3072 result in a warning. Update the database accordingly.
|
||||||
if (cert is False) and (hostkey_modulus_size < hostkey_min_good):
|
if (cert is False) and (hostkey_modulus_size < hostkey_min_good) and (host_key_type != 'ssh-dss'): # Skip ssh-dss, otherwise we get duplicate failure messages (SSH2_KexDB will always flag it).
|
||||||
|
|
||||||
# If the key is under 2048, add to the failure list.
|
# If the key is under 2048, add to the failure list.
|
||||||
if hostkey_modulus_size < hostkey_min_warn:
|
if hostkey_modulus_size < hostkey_min_warn:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"""
|
"""
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
import copy
|
import copy
|
||||||
import getopt
|
import getopt # pylint: disable=deprecated-module
|
||||||
import json
|
import json
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
@@ -360,11 +360,19 @@ def output_fingerprints(out: OutputBuffer, algs: Algorithms, is_json_output: boo
|
|||||||
fp_types = sorted(fps.keys())
|
fp_types = sorted(fps.keys())
|
||||||
for fp_type in fp_types:
|
for fp_type in fp_types:
|
||||||
fp = fps[fp_type]
|
fp = fps[fp_type]
|
||||||
|
|
||||||
|
# Don't output any ECDSA or DSS fingerprints unless verbose mode is enabled.
|
||||||
|
if fp_type.startswith("ecdsa-") or (fp_type == "ssh-dss"):
|
||||||
|
if out.verbose:
|
||||||
|
out.warn('(fin) {}: {} -- [info] this fingerprint type is insecure and should not be relied upon'.format(fp_type, fp.sha256))
|
||||||
|
else:
|
||||||
|
continue # If verbose mode is not enabled, skip this type entirely.
|
||||||
|
else:
|
||||||
out.good('(fin) {}: {}'.format(fp_type, fp.sha256))
|
out.good('(fin) {}: {}'.format(fp_type, fp.sha256))
|
||||||
|
|
||||||
# Output the MD5 hash too if verbose mode is enabled.
|
# Output the MD5 hash too if verbose mode is enabled.
|
||||||
if out.verbose:
|
if out.verbose:
|
||||||
out.info('(fin) {}: {} -- [info] do not rely on MD5 fingerprints for server identification; it is insecure for this use case'.format(fp_type, fp.md5))
|
out.warn('(fin) {}: {} -- [info] do not rely on MD5 fingerprints for server identification; it is insecure for this use case'.format(fp_type, fp.md5))
|
||||||
|
|
||||||
if not out.is_section_empty() and not is_json_output:
|
if not out.is_section_empty() and not is_json_output:
|
||||||
out.head('# fingerprints')
|
out.head('# fingerprints')
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
|
|||||||
# then affected = 1 + 4 = 5.
|
# then affected = 1 + 4 = 5.
|
||||||
CVE: Dict[str, List[List[Any]]] = {
|
CVE: Dict[str, List[List[Any]]] = {
|
||||||
'Dropbear SSH': [
|
'Dropbear SSH': [
|
||||||
|
['0.0', '2022.83', 1, 'CVE-2023-48795', 5.9, 'Terrapin attack allows bypassing integrity checks in SSH protocol'],
|
||||||
['0.0', '2020.81', 2, 'CVE-2021-36369', 7.5, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
|
['0.0', '2020.81', 2, 'CVE-2021-36369', 7.5, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
|
||||||
['0.0', '2018.76', 1, 'CVE-2018-15599', 5.0, 'remote users may enumerate users on the system'],
|
['0.0', '2018.76', 1, 'CVE-2018-15599', 5.0, 'remote users may enumerate users on the system'],
|
||||||
['0.0', '2017.74', 5, 'CVE-2017-9079', 4.7, 'local users can read certain files as root'],
|
['0.0', '2017.74', 5, 'CVE-2017-9079', 4.7, 'local users can read certain files as root'],
|
||||||
@@ -67,6 +68,13 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
|
|||||||
['0.4.7', '0.5.2', 1, 'CVE-2012-4560', 7.5, 'cause DoS or execute arbitrary code (buffer overflow)'],
|
['0.4.7', '0.5.2', 1, 'CVE-2012-4560', 7.5, 'cause DoS or execute arbitrary code (buffer overflow)'],
|
||||||
['0.4.7', '0.5.2', 1, 'CVE-2012-4559', 6.8, 'cause DoS or execute arbitrary code (double free)']],
|
['0.4.7', '0.5.2', 1, 'CVE-2012-4559', 6.8, 'cause DoS or execute arbitrary code (double free)']],
|
||||||
'OpenSSH': [
|
'OpenSSH': [
|
||||||
|
['1.0', '9.6', 1, 'CVE-2023-51767', 7.0, 'Row hammer threat allows authentication bypass in shared DRAM'],
|
||||||
|
['1.0', '9.5', 2, 'CVE-2023-51385', 7.0, 'OS command injection through expansion tokens containing shell metacharacters'],
|
||||||
|
['1.0', '9.5', 2, 'CVE-2023-51384', 5.5, 'ssh-agent applies destination constraints only to the first PKCS#11 key'],
|
||||||
|
['1.0', '9.5', 1, 'CVE-2023-48795', 5.9, 'Terrapin attack allows bypassing integrity checks in SSH protocol'],
|
||||||
|
['1.0', '9.2', 1, 'CVE-2023-38408', 9.8, 'PKCS#11 feature has a vulnerable search path in ssh-agent, enabling remote code execution'],
|
||||||
|
['8.9', '9.2', 1, 'CVE-2023-28531', 9.8, 'ssh-add improperly adds smartcard keys to ssh-agent, bypassing intended destination restrictions'],
|
||||||
|
['9.1', '9.1', 1, 'CVE-2023-25136', 6.5, 'A double-free vulnerability allows unauthenticated remote attackers to potentially execute code by manipulating memory'],
|
||||||
['6.2', '8.7', 5, 'CVE-2021-41617', 7.0, 'privilege escalation via supplemental groups'],
|
['6.2', '8.7', 5, 'CVE-2021-41617', 7.0, 'privilege escalation via supplemental groups'],
|
||||||
['1.0', '8.8', 2, 'CVE-2021-36368', 3.7, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
|
['1.0', '8.8', 2, 'CVE-2021-36368', 3.7, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
|
||||||
['8.2', '8.4', 2, 'CVE-2021-28041', 7.1, 'double free via ssh-agent'],
|
['8.2', '8.4', 2, 'CVE-2021-28041', 7.1, 'double free via ssh-agent'],
|
||||||
@@ -140,6 +148,8 @@ class VersionVulnerabilityDB: # pylint: disable=too-few-public-methods
|
|||||||
['1.2.3', '2.1.1', 1, 'CVE-2001-0361', 4.0, 'recover plaintext from ciphertext'],
|
['1.2.3', '2.1.1', 1, 'CVE-2001-0361', 4.0, 'recover plaintext from ciphertext'],
|
||||||
['1.2', '2.1', 1, 'CVE-2000-0525', 10.0, 'execute arbitrary code (improper privileges)']],
|
['1.2', '2.1', 1, 'CVE-2000-0525', 10.0, 'execute arbitrary code (improper privileges)']],
|
||||||
'PuTTY': [
|
'PuTTY': [
|
||||||
|
['0.68', '0.80', 2, 'CVE-2024-31497', 0.0, 'ecdsa private key recovery by malicious remote server'],
|
||||||
|
['0.0', '0.79', 2, 'CVE-2023-48795', 5.9, 'Terrapin attack allows bypassing integrity checks in SSH protocol'],
|
||||||
# info for CVE-2021-36367 - only PuTTY up to 0.71 is affected - see https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/reject-trivial-auth.html
|
# info for CVE-2021-36367 - only PuTTY up to 0.71 is affected - see https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/reject-trivial-auth.html
|
||||||
['0.0', '0.71', 2, 'CVE-2021-36367', 8.1, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
|
['0.0', '0.71', 2, 'CVE-2021-36367', 8.1, 'trivial authentication attack to bypass FIDO tokens and SSH-ASKPASS'],
|
||||||
['0.0', '0.74', 2, 'CVE-2021-33500', 5.0, 'denial of service of the complete windows desktop'],
|
['0.0', '0.74', 2, 'CVE-2021-33500', 5.0, 'denial of service of the complete windows desktop'],
|
||||||
|
|||||||
@@ -78,6 +78,26 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fingerprints": [
|
"fingerprints": [
|
||||||
|
{
|
||||||
|
"hash": "jdUfqoGCDOY1drQcoqIJm/pEix2r09hqwOs9E9GimZQ",
|
||||||
|
"hash_alg": "SHA256",
|
||||||
|
"hostkey": "ecdsa-sha2-nistp256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "98:27:f3:12:20:f6:23:6d:1a:00:2a:6c:71:7c:1e:6b",
|
||||||
|
"hash_alg": "MD5",
|
||||||
|
"hostkey": "ecdsa-sha2-nistp256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "NBzry0uMAX8BRsn4mv9CHpeivMOdwzGFEKrf6Hg7tIQ",
|
||||||
|
"hash_alg": "SHA256",
|
||||||
|
"hostkey": "ssh-dss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "16:60:9e:54:d7:1e:b3:0d:97:60:12:ad:fe:83:a2:40",
|
||||||
|
"hash_alg": "MD5",
|
||||||
|
"hostkey": "ssh-dss"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"hash": "CDfAU12pjQS7/91kg7gYacza0U/6PDbE04Ic3IpYxkM",
|
"hash": "CDfAU12pjQS7/91kg7gYacza0U/6PDbE04Ic3IpYxkM",
|
||||||
"hash_alg": "SHA256",
|
"hash_alg": "SHA256",
|
||||||
|
|||||||
@@ -253,6 +253,16 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fingerprints": [
|
"fingerprints": [
|
||||||
|
{
|
||||||
|
"hash": "sqDDYhzYz7YIQeFDc0WF8SeXtrEz+iwsV7d/FdIgztM",
|
||||||
|
"hash_alg": "SHA256",
|
||||||
|
"hostkey": "ssh-dss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "5c:de:62:f0:60:c8:93:13:87:71:78:95:56:3f:61:51",
|
||||||
|
"hash_alg": "MD5",
|
||||||
|
"hostkey": "ssh-dss"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
|
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
|
||||||
"hash_alg": "SHA256",
|
"hash_alg": "SHA256",
|
||||||
|
|||||||
@@ -240,6 +240,16 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fingerprints": [
|
"fingerprints": [
|
||||||
|
{
|
||||||
|
"hash": "sqDDYhzYz7YIQeFDc0WF8SeXtrEz+iwsV7d/FdIgztM",
|
||||||
|
"hash_alg": "SHA256",
|
||||||
|
"hostkey": "ssh-dss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "5c:de:62:f0:60:c8:93:13:87:71:78:95:56:3f:61:51",
|
||||||
|
"hash_alg": "MD5",
|
||||||
|
"hostkey": "ssh-dss"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
|
"hash": "YZ457EBcJTSxRKI3yXRgtAj3PBf5B9/F36b1SVooml4",
|
||||||
"hash_alg": "SHA256",
|
"hash_alg": "SHA256",
|
||||||
|
|||||||
@@ -87,6 +87,16 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fingerprints": [
|
"fingerprints": [
|
||||||
|
{
|
||||||
|
"hash": "Q6Llm0o4TrcUen4tnT2h4BDf2f+ina6dIJmVH8c40bg",
|
||||||
|
"hash_alg": "SHA256",
|
||||||
|
"hostkey": "ecdsa-sha2-nistp256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hash": "cc:e0:80:84:5b:05:98:64:24:43:52:3b:17:c8:94:89",
|
||||||
|
"hash_alg": "MD5",
|
||||||
|
"hostkey": "ecdsa-sha2-nistp256"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU",
|
"hash": "UrnXIVH+7dlw8UqYocl48yUEcKrthGDQG2CPCgp7MxU",
|
||||||
"hash_alg": "SHA256",
|
"hash_alg": "SHA256",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist =
|
envlist =
|
||||||
py{py3}-{test,pylint,flake8}
|
py{py3}-{test,pylint,flake8}
|
||||||
py{38,39,310,311,312}-{test,mypy,pylint,flake8}
|
py{38,39,310,311,312,313}-{test,mypy,pylint,flake8}
|
||||||
cov
|
cov
|
||||||
skip_missing_interpreters = true
|
skip_missing_interpreters = true
|
||||||
|
|
||||||
@@ -9,10 +9,10 @@ skip_missing_interpreters = true
|
|||||||
deps =
|
deps =
|
||||||
test: pytest
|
test: pytest
|
||||||
test,cov: {[testenv:cov]deps}
|
test,cov: {[testenv:cov]deps}
|
||||||
test,py{38,39,310,311,312}-{type,mypy}: colorama
|
test,py{38,39,310,311,312,313}-{type,mypy}: colorama
|
||||||
py{38,39,310,311,312}-{type,mypy}: {[testenv:mypy]deps}
|
py{38,39,310,311,312,313}-{type,mypy}: {[testenv:mypy]deps}
|
||||||
py{py3,38,39,310,311,312}-{lint,pylint},lint: {[testenv:pylint]deps}
|
py{py3,38,39,310,311,312,313}-{lint,pylint},lint: {[testenv:pylint]deps}
|
||||||
py{py3,38,39,310,311,312}-{lint,flake8},lint: {[testenv:flake8]deps}
|
py{py3,38,39,310,311,312,313}-{lint,flake8},lint: {[testenv:flake8]deps}
|
||||||
setenv =
|
setenv =
|
||||||
SSHAUDIT = {toxinidir}/src
|
SSHAUDIT = {toxinidir}/src
|
||||||
test: COVERAGE_FILE = {toxinidir}/.coverage.{envname}
|
test: COVERAGE_FILE = {toxinidir}/.coverage.{envname}
|
||||||
@@ -24,9 +24,9 @@ commands =
|
|||||||
test: coverage combine
|
test: coverage combine
|
||||||
test: coverage report --show-missing
|
test: coverage report --show-missing
|
||||||
test: coverage html -d {toxinidir}/reports/html/coverage.{envname}
|
test: coverage html -d {toxinidir}/reports/html/coverage.{envname}
|
||||||
py{38,39,310,311,312}-{type,mypy}: {[testenv:mypy]commands}
|
py{38,39,310,311,312,313}-{type,mypy}: {[testenv:mypy]commands}
|
||||||
py{py3,38,39,310,311,312}-{lint,pylint},lint: {[testenv:pylint]commands}
|
py{py3,38,39,310,311,312,313}-{lint,pylint},lint: {[testenv:pylint]commands}
|
||||||
py{py3,38,39,310,311,312}-{lint,flake8},lint: {[testenv:flake8]commands}
|
py{py3,38,39,310,311,312,313}-{lint,flake8},lint: {[testenv:flake8]commands}
|
||||||
|
|
||||||
#ignore_outcome =
|
#ignore_outcome =
|
||||||
# type: true
|
# type: true
|
||||||
|
|||||||
Reference in New Issue
Block a user