Files
Samsara/tests/test_linux.py
oceans2alaska b4c0cf12ca Retain infrastructure names and share/mount roots behind policy switches
Add a `retain` block to privacy_policy.json (all on by default) so assessments
show software, services, processes, tasks, shares/mounts and private peer IPs.
Values pass an identifier-pattern filter (digit runs, SSN/phone, e-mail, charset,
length, path depth). Accounts, command lines, child paths, filenames and public
peer IPs stay omitted. Linux collector and Windows PowerShell collectors updated;
tests cover retention, withholding and all-switches-off.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 19:03:49 -08:00

130 lines
6.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import json
from pathlib import Path
import tempfile
import unittest
from unittest.mock import patch
from samsara.collectors.linux import (collect_local_linux, parse_connections,
parse_units, run_command, CollectionCancelled)
from samsara.collectors.demo import collect_demo, LINUX_DEMO_HOST
from samsara.analyzers.assessment import assess
from report_helpers import export_html
class LinuxTests(unittest.TestCase):
def test_service_states_and_startup(self):
rows = parse_units('nginx.service loaded active running Web server\nexample.service loaded inactive dead Example\n',
'nginx.service enabled enabled\nexample.service disabled disabled\n')
self.assertEqual(rows[0]['state'], 'Running')
self.assertEqual(rows[0]['startup'], 'enabled')
self.assertEqual(rows[1]['state'], 'inactive/dead')
def test_ipv4_ipv6_and_unprivileged_connections(self):
rows = parse_connections('LISTEN 0 128 0.0.0.0:22 0.0.0.0:*\nESTAB 0 0 [::1]:443 [::1]:51234 users:(("nginx",pid=123,fd=7))\n')
self.assertEqual(rows[0]['remote_port'], 0)
self.assertIsNone(rows[0]['pid'])
self.assertEqual(rows[1]['local_address'], '::1')
self.assertEqual(rows[1]['state'], 'Established')
self.assertEqual(rows[1]['process'], 'nginx')
self.assertEqual(rows[1]['direction'], 'Unknown')
@patch('samsara.collectors.linux.platform.system', return_value='Windows')
def test_wrong_execution_platform(self, system):
with self.assertRaises(ValueError):
collect_local_linux()
@patch('samsara.collectors.linux.platform.system', return_value='Linux')
def test_partial_failures_never_use_demo(self, system):
def unavailable(args, **kwargs):
raise RuntimeError('SECRET diagnostics must not be reported')
data = collect_local_linux(runner=unavailable)
self.assertFalse(data['synthetic'])
self.assertEqual(data['checks']['services']['status'], 'failed')
self.assertEqual(data['checks']['network']['status'], 'failed')
self.assertEqual(data['checks']['software']['status'], 'failed')
self.assertEqual(data['inventory']['services'], [])
self.assertNotIn('SECRET', json.dumps(data))
self.assertEqual(data['checks']['certificates']['status'], 'not_collected')
@patch('samsara.collectors.linux.platform.system', return_value='Linux')
def test_cancel(self, system):
with self.assertRaises(CollectionCancelled):
collect_local_linux(cancelled=lambda: True)
def test_mint_and_rhel_package_parsing(self):
for rpm in [False, True]:
def command(args, **kwargs):
if args[0] == 'ip':
return '[]'
if args[0] == 'rpm':
return 'nginx\t1.2-1\tExample vendor\n'
if args[0] == 'dpkg-query':
return 'installed\tnginx:amd64\t1.2\nconfig-files\tremoved\t1.0\n'
return ''
with self.subTest(rpm=rpm), patch('samsara.collectors.linux.platform.system', return_value='Linux'), patch('samsara.collectors.linux.Path.is_file', return_value=rpm):
data = collect_local_linux(runner=command)
self.assertEqual(len(data['inventory']['software']), 1)
self.assertIn('nginx', data['inventory']['software'][0]['name'])
self.assertEqual(data['checks']['software']['status'], 'partial')
def test_local_report_source_and_unclassified_services(self):
data = collect_demo(LINUX_DEMO_HOST)
data['synthetic'] = False
data['server']['collection_source'] = 'Local Linux read-only collection'
data['inventory']['services'] = [{'name': 'desktop-example.service', 'state': 'Running'}]
result = assess(data)
self.assertFalse(any(f['category'] == 'Active service' for f in result['findings']))
self.assertTrue(any(f['category'] == 'Unclassified services' for f in result['findings']))
with tempfile.TemporaryDirectory() as folder:
path = Path(folder) / 'report.html'
export_html(path, data, result)
self.assertIn('LOCAL LINUX INVENTORY', path.read_text())
self.assertNotIn('IMPORTED INVENTORY', path.read_text())
@unittest.skipUnless(__import__('sys').platform.startswith('linux'), 'Linux command test')
def test_command_timeout_and_cancellation(self):
with self.assertRaisesRegex(RuntimeError, 'timeout'):
run_command(['sleep', '1'], timeout=.05)
with self.assertRaises(CollectionCancelled):
run_command(['sleep', '1'], cancelled=lambda: True)
class RegressionReviewTests(unittest.TestCase):
def test_ss_states_map_to_canonical_names(self):
from samsara.collectors.linux import parse_connections
rows = parse_connections('TIME-WAIT 0 0 10.0.0.5:44321 10.0.0.9:443\nCLOSE-WAIT 0 0 10.0.0.5:1 10.0.0.9:2\nFIN-WAIT-1 0 0 10.0.0.5:3 10.0.0.9:4\n')
self.assertEqual([r['state'] for r in rows], ['TimeWait', 'CloseWait', 'FinWait1'])
def test_non_ascii_digits_and_cpp_product_label(self):
import json
from pathlib import Path
from samsara.core.privacy import minimize_inventory, numeric_version, safe_time
self.assertEqual(numeric_version('١٢.٣٤'), 'Not collected')
self.assertIsNone(safe_time('٢٠٢٦-٠١-٠١T٠٠:٠٠:٠٠Z'))
data = json.loads(Path('samsara/assets/demo_inventory.json').read_text())
data['server']['os_build'] = '١٢٣٤٥'
data['inventory']['software'] = [{'name': 'Microsoft Visual C++ 2015-2022 Redistributable (x64)', 'version': '14.38.33135'}]
from samsara.core.privacy import load_privacy_policy
strict = load_privacy_policy()
strict['retain'] = {key: False for key in strict['retain']}
clean = minimize_inventory(data, strict)
self.assertNotEqual(clean['server']['os_build'], '١٢٣٤٥')
self.assertEqual(clean['inventory']['software'][0]['name'], 'Microsoft Visual C++')
def test_remote_peer_addresses_are_masked_but_scoring_survives(self):
import copy
from samsara.core.privacy import minimize_inventory
from samsara.models.inventory import validate_inventory
data = json.loads(Path('tests/fixtures/scoring/active_sql_server.json').read_text())
before = assess(minimize_inventory(copy.deepcopy(data)))['score']
for row in data['inventory']['network']:
if row.get('remote_address') not in ('', '0.0.0.0', '::'):
row['remote_address'] = '93.184.216.34'
clean = minimize_inventory(data)
validate_inventory(clean)
self.assertNotIn('93.184.216.34', json.dumps(clean))
self.assertEqual(minimize_inventory(clean), clean)
self.assertEqual(assess(clean)['score'], before)
self.assertNotIn('93.184.216.34', json.dumps(assess(clean)))
self.assertIn('public', {r['remote_scope'] for r in clean['inventory']['network']})