Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions shared/connector_linter/connector_linter/checks/_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import ast
from pathlib import Path

from connector_linter.models import ConnectorContext

# ---------------------------------------------------------------------------
# Source reading
# ---------------------------------------------------------------------------


def read_all_python_sources(ctx: ConnectorContext) -> dict[Path, str]:
"""Read all Python source files from the connector's src/ directory."""
sources: dict[Path, str] = {}
# Convention: all connector Python code lives under <connector>/src/
src_dir = ctx.path / "src"
if not src_dir.exists():
return sources
for py_file in src_dir.rglob("*.py"):
# Key by relative path (from connector root) for portable reporting
rel_path = py_file.relative_to(ctx.path)
try:
# errors="replace" avoids UnicodeDecodeError on malformed files
sources[rel_path] = py_file.read_text(encoding="utf-8", errors="replace")
except OSError:
# Skip unreadable files (permissions, broken symlinks, etc.)
continue
return sources


# ---------------------------------------------------------------------------
# AST helpers — structural analysis of Python source
# ---------------------------------------------------------------------------


def parse_sources(sources: dict[Path, str]) -> dict[Path, ast.Module]:
"""Parse all source files into AST modules.

Files that fail to parse (syntax errors) are silently skipped.
"""
trees: dict[Path, ast.Module] = {}
for file_path, content in sources.items():
try:
trees[file_path] = ast.parse(content, filename=str(file_path))
except SyntaxError:
# Silently skip files with syntax errors — they can't be analyzed
# structurally, but other checks (regex-based) may still find issues.
continue
return trees
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""VC3xx — Code quality checks.

VC301: Connector must define an author identity.
VC302: Author must be referenced on STIX entities (created_by_ref).
VC303: CONNECTOR_TYPE must be defined in application code, not read from env.
VC304: Ensure TLP markings are checked (check_max_tlp).
VC305: Connector must implement Base Settings from connectors-sdk.
VC306: Connector log level should default to 'error'.
VC307: Except blocks should use error/warning logging, not debug/info.
VC308: Main entry point must use traceback for error handling.
VC309: Connector must use only absolute imports, no relative imports.
VC310: External references must not be added by default to non-Identity objects.
VC311: Connector should use TLP markings on entities with appropriate level.
VC312: send_stix2_bundle must use cleanup_inconsistent_bundle=True.
VC313: STIX SDO/SRO objects must use pycti.XXX.generate_id() for deterministic IDs.
VC314: External-import connectors must use schedule_process or schedule_iso.
VC315: Connector must call initiate_work before processing.
VC316: Connector must close work with to_processed after processing.
VC317: initiate_work should only be called when data is available.
VC318: Internal-enrichment connectors must use helper.listen().
VC319: Enrichment connector must return original bundle when not in scope.
VC320: Enrichment connector must enforce TLP access control.
VC321: Enrichment connector must be playbook-compatible.
VC322: Enrichment connector must read data['stix_objects'] (former bundle).
VC323: Stream connectors must use helper.listen_stream().
VC324: Relationship should not set both start_time and stop_time.
"""
Loading
Loading