Files
Samsara/samsara/models/inventory.py
oceans2alaska 610a3bb447 Privacy hardening, remote-peer IP masking and review fixes
- Add privacy projection (core/privacy.py), private report storage, bounded
  process capture; omit identities, free text and unapproved paths
- Mask remote peer IPs: only loopback/host/wildcard stay numeric, others are
  reduced to remote_scope private/public (schema + scoring updated)
- Map ss TCP states to canonical names; ASCII-only numeric fields; fix
  "Microsoft Visual C++" product matching (Python and PowerShell)
- Merge 7fed3b9: -Diagnostic switch, serialization exit code 3, PS7 module
  path, UI error detail; keep hardened task/certificate collectors
- Add audit docs, privacy docs and regression tests

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 18:50:24 -08:00

50 lines
2.5 KiB
Python

"""The shared v1 inventory contract, used at live collection and import boundaries."""
import json
from functools import lru_cache
from pathlib import Path
from jsonschema import Draft202012Validator, FormatChecker
SCHEMA_PATH = Path(__file__).resolve().parents[2] / 'schemas' / 'inventory-v1.schema.json'
@lru_cache(maxsize=1)
def inventory_schema():
return json.loads(SCHEMA_PATH.read_text(encoding='utf-8'))
def validate_inventory(data):
# Validate depth and timestamps without optional third-party format plugins.
from samsara.core.privacy import safe_time
def visit(value, depth=0):
if depth>20: raise ValueError('Inventory nesting exceeds its limit.')
if isinstance(value,dict):
for key,item in value.items():
if key in ('collected_at','started_at','completed_at','activity_observed_at') and safe_time(item) is None:
raise ValueError('Inventory timestamp is invalid.')
visit(item,depth+1)
elif isinstance(value,list):
for item in value: visit(item,depth+1)
visit(data)
validator = Draft202012Validator(inventory_schema(), format_checker=FormatChecker())
if not validator.is_valid(data):
raise ValueError('Inventory does not match the v1 schema; required fields, types or check statuses are invalid.')
return data
ALLOWED = {
'roles': {'name', 'state', 'display_name', 'feature_type'},
'services': {'name', 'display_name', 'state', 'startup', 'account', 'pid'},
'network': {'state', 'local_address', 'local_port', 'remote_address', 'remote_port', 'pid', 'process', 'direction'},
'tasks': {'name', 'path', 'enabled', 'account', 'triggers', 'state', 'associated_unit', 'executables'},
'software': {'name', 'publisher', 'version', 'installation_date', 'registry_view'},
'storage': {'type', 'name', 'path', 'capacity_gib', 'free_gib', 'filesystem', 'special', 'observed_open_files', 'observed_client_count', 'activity_source', 'activity_observed_at'},
'certificates': {'subject', 'issuer', 'expires', 'thumbprint', 'store'},
}
SERVER_FIELDS = {'hostname', 'platform', 'operating_system', 'os_version', 'os_build', 'kernel_version', 'product_type', 'domain_joined', 'last_boot', 'ip_addresses', 'network_adapters', 'domain'}
def restrict_inventory_fields(data, local_source=None):
"""Compatibility entry point: all callers now receive the privacy projection."""
from samsara.core.privacy import minimize_inventory
return minimize_inventory(data, trusted_source=local_source)