0
# Scanning and Analysis
1
2
Safety CLI provides comprehensive vulnerability scanning and analysis capabilities for Python projects. The scanning system supports multiple ecosystems, file types, and analysis modes.
3
4
## Core Scanning Architecture
5
6
### File Discovery and Processing { .api }
7
8
The scanning system uses a modular architecture to discover and process dependency files:
9
10
**Import Statements:**
11
12
```python
13
from safety.scan.main import process_files, download_policy, load_policy_file
14
from safety.scan.finder import FileFinder
15
from safety.scan.ecosystems.base import InspectableFile, Inspectable, Remediable
16
from safety.scan.models import ScanExport
17
from safety_schemas.models import (
18
ConfigModel, FileType, PolicyFileModel,
19
ScanType, Stage, Ecosystem
20
)
21
```
22
23
#### FileFinder Class { .api }
24
25
**Description**: Discovers dependency files in project directories based on ecosystem and file type patterns.
26
27
**Constructor:**
28
29
```python
30
FileFinder(
31
max_level: int, # Maximum directory depth
32
ecosystems: List[Ecosystem], # Target ecosystems
33
target: Path, # Root directory to scan
34
live_status=None, # Progress status object
35
exclude: Optional[List[str]] = None, # Exclusion patterns
36
include_files: Optional[Dict[FileType, List[Path]]] = None, # Specific files
37
handlers: Optional[Set[FileHandler]] = None # Custom file handlers
38
)
39
```
40
41
**Methods:**
42
43
```python
44
def process_directory(
45
self,
46
dir_path: str,
47
max_deep: Optional[int] = None
48
) -> Tuple[str, Dict[str, Set[Path]]]
49
"""
50
Process directory and discover dependency files.
51
52
Args:
53
dir_path (str): Directory path to process
54
max_deep (Optional[int]): Maximum depth override
55
56
Returns:
57
Tuple[str, Dict[str, Set[Path]]]: Directory info and discovered files
58
"""
59
60
def should_exclude(
61
excludes: Set[Path],
62
to_analyze: Path
63
) -> bool
64
"""
65
Determine if path should be excluded from analysis.
66
67
Args:
68
excludes (Set[Path]): Set of exclusion paths
69
to_analyze (Path): Path to check
70
71
Returns:
72
bool: True if path should be excluded
73
"""
74
```
75
76
**Example Usage:**
77
78
```python
79
from safety.scan.finder import FileFinder
80
from safety_schemas.models import Ecosystem
81
from pathlib import Path
82
83
# Initialize file finder
84
finder = FileFinder(
85
max_level=10,
86
ecosystems=[Ecosystem.PYTHON],
87
target=Path("."),
88
exclude=["node_modules", ".git", "__pycache__"]
89
)
90
91
# Process directory
92
project_info, discovered_files = finder.process_directory("./my_project")
93
```
94
95
### File Processing Engine { .api }
96
97
#### process_files Function { .api }
98
99
**Description**: Main processing function that analyzes discovered dependency files and generates inspectable file objects.
100
101
**Signature:**
102
103
```python
104
def process_files(
105
paths: Dict[str, Set[Path]], # Discovered file paths by type
106
config: Optional[ConfigModel] = None, # Scan configuration
107
use_server_matching: bool = False, # Use server-side analysis
108
obj=None, # Context object
109
target: Path = Path(".") # Project root path
110
) -> Generator[Tuple[Path, InspectableFile], None, None]
111
"""
112
Process dependency files and yield inspectable file objects.
113
114
Args:
115
paths: Dictionary of file paths organized by file type
116
config: Configuration model for analysis settings
117
use_server_matching: Enable server-side vulnerability matching
118
obj: Context object with authentication and settings
119
target: Root directory path
120
121
Yields:
122
Tuple[Path, InspectableFile]: File path and corresponding inspectable file
123
"""
124
```
125
126
**Processing Modes:**
127
128
1. **Local Processing** (`use_server_matching=False`):
129
- Files processed locally using built-in analyzers
130
- Immediate dependency extraction and vulnerability matching
131
- Offline capability with cached vulnerability database
132
133
2. **Server Processing** (`use_server_matching=True`):
134
- Files uploaded to Safety platform for analysis
135
- Enhanced vulnerability intelligence and matching
136
- Requires authentication with Safety platform
137
138
**Example Usage:**
139
140
```python
141
from safety.scan.main import process_files
142
from safety_schemas.models import ConfigModel
143
144
# Configure scan settings
145
config = ConfigModel(
146
telemetry_enabled=True
147
)
148
149
# Process discovered files
150
for file_path, inspectable_file in process_files(
151
paths=discovered_files,
152
config=config,
153
use_server_matching=True,
154
target=Path(".")
155
):
156
# Access vulnerability results
157
results = inspectable_file.inspect(config=config)
158
print(f"File: {file_path}")
159
print(f"Dependencies: {len(results.dependencies)}")
160
print(f"Vulnerabilities: {len(results.vulnerabilities)}")
161
```
162
163
### Inspectable Files Interface { .api }
164
165
#### InspectableFile Class { .api }
166
167
**Description**: Represents a dependency file that can be analyzed for vulnerabilities and remediated.
168
169
**Base Classes:**
170
171
```python
172
class Inspectable(ABC):
173
@abstractmethod
174
def inspect(self, config: ConfigModel) -> DependencyResultModel:
175
"""Analyze file for dependencies and vulnerabilities."""
176
177
class Remediable(ABC):
178
@abstractmethod
179
def remediate(self):
180
"""Apply automatic fixes to detected vulnerabilities."""
181
```
182
183
**InspectableFile Interface:**
184
185
```python
186
class InspectableFile(Inspectable):
187
file_type: FileType # Type of dependency file
188
ecosystem: Ecosystem # Target ecosystem (Python, etc.)
189
190
def inspect(self, config: ConfigModel) -> DependencyResultModel:
191
"""
192
Analyze file for dependencies and vulnerabilities.
193
194
Args:
195
config: Configuration model with scan settings
196
197
Returns:
198
DependencyResultModel: Analysis results with dependencies and vulnerabilities
199
"""
200
201
def remediate(self) -> None:
202
"""
203
Apply automatic remediation to fix detected vulnerabilities.
204
Modifies dependency specifications to use secure versions.
205
"""
206
```
207
208
## Policy Management { .api }
209
210
### Policy File Loading
211
212
#### load_policy_file Function { .api }
213
214
**Description**: Load and validate Safety policy files from local filesystem.
215
216
**Signature:**
217
218
```python
219
def load_policy_file(path: Path) -> Optional[PolicyFileModel]:
220
"""
221
Load policy file from specified path.
222
223
Args:
224
path (Path): Path to policy file (.safety-policy.yml)
225
226
Returns:
227
Optional[PolicyFileModel]: Parsed policy model or None if invalid
228
229
Raises:
230
SafetyError: If policy file is invalid or unsupported version
231
"""
232
```
233
234
#### download_policy Function { .api }
235
236
**Description**: Download policy files from Safety platform for authenticated users.
237
238
**Signature:**
239
240
```python
241
def download_policy(
242
session: SafetyAuthSession, # Authenticated session
243
project_id: str, # Project identifier
244
stage: Stage, # Environment stage
245
branch: Optional[str] # Git branch name
246
) -> Optional[PolicyFileModel]:
247
"""
248
Download policy file from Safety platform.
249
250
Args:
251
session: Authenticated Safety session
252
project_id: Unique project identifier
253
stage: Development stage (development, production, etc.)
254
branch: Git branch for branch-specific policies
255
256
Returns:
257
Optional[PolicyFileModel]: Downloaded policy model
258
259
Raises:
260
SafetyError: If download fails or policy is invalid
261
"""
262
```
263
264
### Policy Models { .api }
265
266
```python
267
from safety_schemas.models import PolicyFileModel, PolicySource, Stage
268
269
class PolicyFileModel:
270
id: str # Policy identifier
271
source: PolicySource # Source (local, cloud)
272
location: Optional[Path] # Local file path
273
config: ConfigModel # Policy configuration
274
275
class PolicySource(Enum):
276
LOCAL = "local" # Local policy file
277
CLOUD = "cloud" # Platform policy
278
279
class Stage(Enum):
280
DEVELOPMENT = "development"
281
TESTING = "testing"
282
STAGING = "staging"
283
PRODUCTION = "production"
284
```
285
286
## Scan Configuration { .api }
287
288
### ConfigModel { .api }
289
290
**Description**: Central configuration model for scan behavior and policies.
291
292
```python
293
from safety_schemas.models import ConfigModel
294
295
class ConfigModel:
296
telemetry_enabled: bool = True # Enable usage telemetry
297
298
# Vulnerability filtering
299
ignore_vulnerabilities: List[str] = [] # Vulnerability IDs to ignore
300
ignore_unpinned_requirements: bool = False # Ignore unpinned dependencies
301
302
# Severity filtering
303
minimum_severity: Optional[str] = None # Minimum severity level
304
305
# Output configuration
306
output_format: str = "screen" # Output format preference
307
detailed_output: bool = False # Include detailed information
308
309
# Auto-remediation settings
310
auto_remediation_limit: Optional[int] = None # Max automatic fixes
311
continue_on_error: bool = False # Continue despite errors
312
313
@classmethod
314
def parse_policy_file(cls, raw_report: Path) -> "ConfigModel":
315
"""
316
Parse policy file and create configuration model.
317
318
Args:
319
raw_report (Path): Path to policy YAML file
320
321
Returns:
322
ConfigModel: Parsed configuration
323
324
Raises:
325
ValidationError: If policy file is invalid
326
"""
327
328
@classmethod
329
def from_v30(cls, obj) -> "ConfigModel":
330
"""
331
Create ConfigModel from v3.0 policy format.
332
333
Args:
334
obj: v3.0 format policy object
335
336
Returns:
337
ConfigModel: Converted configuration
338
"""
339
```
340
341
## Ecosystem Support { .api }
342
343
### Supported Ecosystems
344
345
```python
346
from safety_schemas.models import Ecosystem, FileType
347
348
class Ecosystem(Enum):
349
PYTHON = "python" # Python packages and requirements
350
# Additional ecosystems may be added in future versions
351
352
class FileType(Enum):
353
# Python ecosystem file types
354
REQUIREMENTS_TXT = "requirements.txt" # pip requirements files
355
PIPFILE = "Pipfile" # Pipenv files
356
PIPFILE_LOCK = "Pipfile.lock" # Pipenv lock files
357
PYPROJECT_TOML = "pyproject.toml" # PEP 518 project files
358
POETRY_LOCK = "poetry.lock" # Poetry lock files
359
SETUP_PY = "setup.py" # setuptools setup files
360
SETUP_CFG = "setup.cfg" # setuptools configuration
361
362
@property
363
def ecosystem(self) -> Optional[Ecosystem]:
364
"""Get the ecosystem associated with this file type."""
365
```
366
367
### File Handler Architecture { .api }
368
369
```python
370
from safety.scan.finder.handlers import FileHandler, ECOSYSTEM_HANDLER_MAPPING
371
372
class FileHandler(ABC):
373
"""Abstract base class for ecosystem-specific file handlers."""
374
375
@abstractmethod
376
def can_handle(self, file_path: Path) -> bool:
377
"""Determine if handler can process the given file."""
378
379
@abstractmethod
380
def process(self, file_path: Path) -> Set[FileType]:
381
"""Process file and return supported file types."""
382
383
# Handler mapping
384
ECOSYSTEM_HANDLER_MAPPING: Dict[Ecosystem, Type[FileHandler]] = {
385
Ecosystem.PYTHON: PythonHandler,
386
# Additional handlers for future ecosystems
387
}
388
```
389
390
## Scan Export and Results { .api }
391
392
### ScanExport Types { .api }
393
394
```python
395
from safety.scan.models import ScanExport
396
397
class ScanExport(Enum):
398
JSON = "json" # JSON format export
399
HTML = "html" # HTML report export
400
TEXT = "text" # Plain text export
401
SPDX = "spdx" # SPDX format (with spdx extra)
402
```
403
404
### Result Data Models { .api }
405
406
```python
407
from safety_schemas.models import DependencyResultModel
408
409
class DependencyResultModel:
410
"""Results from dependency analysis and vulnerability scanning."""
411
412
dependencies: List[DependencyModel] # Discovered dependencies
413
vulnerabilities: List[VulnerabilityModel] # Found vulnerabilities
414
metadata: Dict[str, Any] # Additional metadata
415
416
class DependencyModel:
417
"""Individual dependency information."""
418
419
name: str # Package name
420
version: str # Package version
421
ecosystem: Ecosystem # Package ecosystem
422
file_path: Path # Source file path
423
424
class VulnerabilityModel:
425
"""Vulnerability information for dependencies."""
426
427
vulnerability_id: str # Unique vulnerability ID
428
package_name: str # Affected package
429
severity: str # Vulnerability severity
430
advisory: str # Vulnerability description
431
fixed_versions: List[str] # Versions with fixes
432
```
433
434
## Advanced Scanning Features
435
436
### Git Integration { .api }
437
438
```python
439
from safety.scan.util import GIT
440
441
# Git metadata extraction for enhanced reporting
442
def build_meta(target: Path) -> Dict[str, Any]:
443
"""
444
Build metadata for scan context including Git information.
445
446
Args:
447
target (Path): Project root directory
448
449
Returns:
450
Dict[str, Any]: Metadata including Git branch, commit, etc.
451
"""
452
```
453
454
### Encoding Detection { .api }
455
456
```python
457
from safety.encoding import detect_encoding
458
459
def detect_encoding(file_path: Path) -> str:
460
"""
461
Detect file encoding for proper text processing.
462
463
Args:
464
file_path (Path): Path to file for encoding detection
465
466
Returns:
467
str: Detected encoding (e.g., 'utf-8', 'latin-1')
468
"""
469
```
470
471
## Usage Examples
472
473
### Basic Project Scan
474
475
```python
476
from safety.scan.finder import FileFinder
477
from safety.scan.main import process_files
478
from safety_schemas.models import Ecosystem, ConfigModel
479
from pathlib import Path
480
481
# Configure scan
482
config = ConfigModel(
483
telemetry_enabled=False,
484
detailed_output=True,
485
auto_remediation_limit=5
486
)
487
488
# Discover files
489
finder = FileFinder(
490
max_level=5,
491
ecosystems=[Ecosystem.PYTHON],
492
target=Path("./my_project"),
493
exclude=[".venv", ".git", "node_modules"]
494
)
495
496
_, discovered_files = finder.process_directory("./my_project")
497
498
# Process and analyze
499
vulnerabilities_found = []
500
for file_path, inspectable_file in process_files(
501
paths=discovered_files,
502
config=config,
503
target=Path("./my_project")
504
):
505
results = inspectable_file.inspect(config=config)
506
if results.vulnerabilities:
507
vulnerabilities_found.extend(results.vulnerabilities)
508
509
# Apply automatic remediation
510
inspectable_file.remediate()
511
512
print(f"Found {len(vulnerabilities_found)} vulnerabilities")
513
```
514
515
### Policy-Based Scanning
516
517
```python
518
from safety.scan.main import load_policy_file, download_policy
519
from safety.auth.utils import SafetyAuthSession
520
521
# Load local policy
522
policy = load_policy_file(Path("./.safety-policy.yml"))
523
524
if policy:
525
config = policy.config
526
else:
527
# Download from platform (requires authentication)
528
session = SafetyAuthSession()
529
policy = download_policy(
530
session=session,
531
project_id="my-project-id",
532
stage=Stage.PRODUCTION,
533
branch="main"
534
)
535
config = policy.config if policy else ConfigModel()
536
537
# Use policy configuration for scanning
538
for file_path, inspectable_file in process_files(
539
paths=discovered_files,
540
config=config
541
):
542
results = inspectable_file.inspect(config=config)
543
# Process results according to policy
544
```
545
546
### Custom File Inclusion
547
548
```python
549
from safety_schemas.models import FileType
550
551
# Include specific files in scan
552
include_files = {
553
FileType.REQUIREMENTS_TXT: [
554
Path("./requirements.txt"),
555
Path("./requirements-dev.txt")
556
],
557
FileType.PYPROJECT_TOML: [
558
Path("./pyproject.toml")
559
]
560
}
561
562
finder = FileFinder(
563
max_level=1,
564
ecosystems=[Ecosystem.PYTHON],
565
target=Path("."),
566
include_files=include_files
567
)
568
```
569
570
This comprehensive scanning documentation covers all aspects of Safety CLI's vulnerability scanning and analysis capabilities, enabling developers to integrate sophisticated dependency security checks into their development workflows.