-
-
Notifications
You must be signed in to change notification settings - Fork 1
Testing Framework & `tests ` Structure
NetSentinel is modular and written for testability. This guide covers the structure and examples of how to implement basic functional and unit tests using Python's built-in unittest framework.
/NetSentinel
βββ core/
βββ utils/
βββ tests/
β βββ **init**.py
β βββ test\_logger.py
β βββ test\_config.py
β βββ test\_smb\_enum.py
β βββ test\_kerberos\_enum.py
β βββ test\_recon.py
All test modules should be placed under
/tests, mirroring the structure of/coreand/utils.
All tests use Pythonβs standard library:
python -m unittest discover tests/For test coverage reporting (optional):
pip install coverage
coverage run -m unittest discover tests/
coverage report -mimport unittest
from utils.logger import Logger
class TestLogger(unittest.TestCase):
def test_info_output(self):
logger = Logger()
try:
logger.info("Test log")
except Exception as e:
self.fail(f"Logger raised an exception: {e}")import os
import unittest
from utils.config import Config
class TestConfig(unittest.TestCase):
def test_env_override(self):
os.environ['NetSentinel_DOMAIN'] = 'test.local'
os.environ['NetSentinel_USER'] = 'testuser'
os.environ['NetSentinel_PASS'] = 'pass123'
os.environ['NetSentinel_DC'] = '192.168.1.1'
config = Config()
self.assertEqual(config.domain, 'test.local')
self.assertEqual(config.username, 'testuser')- Mocking Kerberos server responses (using
unittest.mock) - Simulated SMB hosts with Metasploitβs auxiliary modules (manual or scripted)
- Tests for valid/invalid CIDR ranges in
NetworkScanner
- Always test modules in isolation
- Avoid requiring live targets unless integration testing
- Include exception-handling tests where external input is parsed (e.g. SMB/LDAP/KRB)
- File:
test_<module>.py - Class:
Test<ClassName> - Method:
test_<condition>_<expected_result>
Future versions may include GitHub Actions support for:
- Linting (
flake8,black) - Automated tests on pull requests
- Artifact generation (e.g., JSON diff or output logs)
---
## π Threat Modeling for New Modules (e.g., SNMP) (`Threat-Modeling.md`)
```markdown
# π Threat Modeling: Adding New Modules Safely
NetSentinel is used in red team and assessment environments where operational security (OPSEC), stealth, and safety are paramount. This document outlines how to evaluate and design new modules such as SNMP enumeration while minimizing detection and misuse risk.
---
## π§ Threat Model Goals
When adding a new module (e.g., `snmp_enum.py`), consider:
| Goal | Description |
|------------------------------|------------------------------------------------|
| OPSEC safety | Avoid obvious or noisy traffic |
| Abuse resistance | Prevent unauthorized misuse or abuse |
| Controlled output | Ensure all logs are sanitized and timestamped |
| Fail gracefully | Modules should not crash or hang |
| Predictable behavior | Avoid background threads or unbounded loops |
---
## π Module Threat Assessment Checklist
### 1. β What Protocol Is Used?
- SNMP uses UDP/161
- Stateless and high-traffic probes may resemble scans or floods
- Detectable by NIDS/flow collectors
### 2. β What Authentication Is Required?
- SNMPv1 and SNMPv2c use community strings (e.g., `public`)
- Avoid brute-forcing β default to common strings only
- Do not allow user-provided lists unless explicit
### 3. β How Are Timeouts Handled?
- Use socket-level timeouts (UDP can "hang" in poor networks)
- Example:
```python
sock.settimeout(1.5)
- Only sanitized output (e.g., device name, sysDescr, OID list)
- Avoid dumping full raw SNMP walks unless in verbose/debug mode
Goal: Create a module that scans for SNMP-capable hosts and extracts system name, description, and interface list (read-only).
class SNMPEnumerator:
def __init__(self, logger, targets):
self.logger = logger
self.targets = targets
self.community_strings = ['public', 'private']
def enumerate(self):
for host in self.targets:
for community in self.community_strings:
try:
# Issue SNMP GET
info = self.snmp_get(host, community)
self.logger.success(f"[{host}] SNMP sysDescr: {info}")
except TimeoutError:
self.logger.warn(f"[{host}] No SNMP response")| Principle | Application |
|---|---|
| Least privilege | Only query public-readable SNMP OIDs |
| Rate limiting | 1β2 queries per second |
| No storage of creds | Do not cache community strings |
| Test mode flag | Allow test runs with --dry-run
|
| Target validation | Ensure IPs are local or permitted subnets |
Never use SNMP enumeration on external or unauthorized networks.
Only run this module under the following conditions:
- Written Rules of Engagement
- Explicit permission to query SNMP
- Internal networks under authorized test scope
| OID | Description |
|---|---|
1.3.6.1.2.1.1.1.0 |
sysDescr (OS Info) |
1.3.6.1.2.1.1.5.0 |
sysName (Hostname) |
1.3.6.1.2.1.2.2.1.2 |
Interface Names |
Avoid full SNMP walks unless expressly approved.
| Checklist Item | Status |
|---|---|
| Safe OID targets | β |
| Community string whitelisting | β |
| Timeout enforcement | β |
| No credential storage | β |
| Output sanitation | β |
| OPSEC-conscious logging | β |
By modeling each new module this way, NetSentinel stays safe, lean, and engagement-respectful.