Skip to content

Commit c930d1c

Browse files
authored
[Connector-linter]: add VC3xx code checks [3/4]
1 parent 3c95b02 commit c930d1c

28 files changed

Lines changed: 4441 additions & 0 deletions
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import ast
2+
from pathlib import Path
3+
4+
from connector_linter.models import ConnectorContext
5+
6+
# ---------------------------------------------------------------------------
7+
# Source reading
8+
# ---------------------------------------------------------------------------
9+
10+
11+
def read_all_python_sources(ctx: ConnectorContext) -> dict[Path, str]:
12+
"""Read all Python source files from the connector's src/ directory."""
13+
sources: dict[Path, str] = {}
14+
# Convention: all connector Python code lives under <connector>/src/
15+
src_dir = ctx.path / "src"
16+
if not src_dir.exists():
17+
return sources
18+
for py_file in src_dir.rglob("*.py"):
19+
# Key by relative path (from connector root) for portable reporting
20+
rel_path = py_file.relative_to(ctx.path)
21+
try:
22+
# errors="replace" avoids UnicodeDecodeError on malformed files
23+
sources[rel_path] = py_file.read_text(encoding="utf-8", errors="replace")
24+
except OSError:
25+
# Skip unreadable files (permissions, broken symlinks, etc.)
26+
continue
27+
return sources
28+
29+
30+
# ---------------------------------------------------------------------------
31+
# AST helpers — structural analysis of Python source
32+
# ---------------------------------------------------------------------------
33+
34+
35+
def parse_sources(sources: dict[Path, str]) -> dict[Path, ast.Module]:
36+
"""Parse all source files into AST modules.
37+
38+
Files that fail to parse (syntax errors) are silently skipped.
39+
"""
40+
trees: dict[Path, ast.Module] = {}
41+
for file_path, content in sources.items():
42+
try:
43+
trees[file_path] = ast.parse(content, filename=str(file_path))
44+
except SyntaxError:
45+
# Silently skip files with syntax errors — they can't be analyzed
46+
# structurally, but other checks (regex-based) may still find issues.
47+
continue
48+
return trees
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""VC3xx — Code quality checks.
2+
3+
VC301: Connector must define an author identity.
4+
VC302: Author must be referenced on STIX entities (created_by_ref).
5+
VC303: CONNECTOR_TYPE must be defined in application code, not read from env.
6+
VC304: Ensure TLP markings are checked (check_max_tlp).
7+
VC305: Connector must implement Base Settings from connectors-sdk.
8+
VC306: Connector log level should default to 'error'.
9+
VC307: Except blocks should use error/warning logging, not debug/info.
10+
VC308: Main entry point must use traceback for error handling.
11+
VC309: Connector must use only absolute imports, no relative imports.
12+
VC310: External references must not be added by default to non-Identity objects.
13+
VC311: Connector should use TLP markings on entities with appropriate level.
14+
VC312: send_stix2_bundle must use cleanup_inconsistent_bundle=True.
15+
VC313: STIX SDO/SRO objects must use pycti.XXX.generate_id() for deterministic IDs.
16+
VC314: External-import connectors must use schedule_process or schedule_iso.
17+
VC315: Connector must call initiate_work before processing.
18+
VC316: Connector must close work with to_processed after processing.
19+
VC317: initiate_work should only be called when data is available.
20+
VC318: Internal-enrichment connectors must use helper.listen().
21+
VC319: Enrichment connector must return original bundle when not in scope.
22+
VC320: Enrichment connector must enforce TLP access control.
23+
VC321: Enrichment connector must be playbook-compatible.
24+
VC322: Enrichment connector must read data['stix_objects'] (former bundle).
25+
VC323: Stream connectors must use helper.listen_stream().
26+
VC324: Relationship should not set both start_time and stop_time.
27+
"""

0 commit comments

Comments
 (0)