Runs code quality checks on one or more integration directories.
This script performs nine sequential code quality checks on each given integration directory:
- Python syntax check — uses
py_compile.compile()directly to catch syntax errors - Import availability check — imports
check_imports()as a function to verify modules exist - JSON validity check — uses
json.load()directly to ensure all.jsonfiles are parseable - Lint check — runs
ruff checkto catch code quality issues (undefined names, unused imports, style errors) - Format check — runs
ruff format --checkto enforce consistent code formatting - Security scan — runs
banditto flag hardcoded secrets, unsafe eval/exec, insecure HTTP calls - Dependency vulnerability scan — runs
pip-auditto check requirements.txt for packages with known CVEs - Config-code sync — runs
check_config_sync.pyto verify config.json actions and input schemas match the code
Before running checks, it installs the integration's dependencies from requirements.txt so that import checks can find third-party packages.
python scripts/check_code.py <dir> [dir ...]| Argument | Required | Description |
|---|---|---|
dir |
Yes (one or more) | Path to an integration directory to check |
| Code | Meaning |
|---|---|
0 |
All checks passed for all directories |
1 |
One or more checks failed (includes nonexistent directories) |
2 |
No directories provided (usage error) |
# Check a single integration
python scripts/check_code.py my-integration
# Check multiple integrations
python scripts/check_code.py my-integration another-api
# Combine with get_changed_dirs.py
python scripts/check_code.py $(python scripts/get_changed_dirs.py origin/main)pip install -r <dir>/requirements.txt -q- Runs only if
requirements.txtexists - Uses
-q(quiet) to reduce output noise - Failures are silently ignored (
|| true) to allow checks to continue
python -m py_compile <file.py>- Finds all
.pyfiles recursively in the directory usingpathlib.glob() - Uses
py_compilemodule to check syntax without executing code - Reports each file with syntax errors individually
On failure:
🐍 Checking Python syntax...
❌ my-integration/broken_file.py
Fix: Check the Python files above for syntax errors
Run locally: python -m py_compile <file.py>
python scripts/check_imports.py <dir>/<entry_point>- Reads
entry_pointfromconfig.jsonto determine the main Python file - Temporarily adds the integration directory to
sys.pathso local imports (e.g.import actions) are resolvable, mirroring Python's runtime behaviour for entry points - Calls
check_imports()directly as a function (see check_imports.md) to verify all imports - Skips gracefully if
config.jsonor the entry point file doesn't exist
On failure:
📥 Checking imports...
❌ Import errors in my-integration/main.py
Fix: Install missing packages in requirements.txt
Or check if package name is spelled correctly
python -m json.tool <file.json>- Finds all
.jsonfiles recursively in the directory usingpathlib.glob() - Uses Python's built-in
json.load()to validate syntax - Reports each invalid JSON file individually
On failure:
📄 Checking JSON files...
❌ my-integration/config.json
Fix: Check for missing commas, quotes, or brackets
Validate at: https://jsonlint.com/
ruff check <dir>- Runs ruff linter on all Python files in the directory
- Checks for pyflakes errors (F), pycodestyle errors (E), and pycodestyle warnings (W)
- Configuration is defined in
ruff.tomlat the repository root - Ruff is installed automatically if not already available
On failure:
🔍 Linting with ruff...
my-integration/main.py:5:1: F401 `os` imported but unused
❌ Lint errors found
Fix: Run 'ruff check --fix' to auto-fix some issues
ruff format --check <dir>- Checks that all Python files are formatted consistently
- Uses the same ruff tool (already installed for linting)
- Does not modify files — only reports which files would be reformatted
On failure:
🎨 Checking formatting with ruff...
Would reformat: my-integration/main.py
❌ Formatting issues found
Fix: Run 'ruff format' to auto-format
bandit -r <dir> -x .venv,venv,__pycache__,site-packages,dependencies -s B101 -q- Runs bandit security linter on all Python files
- Excludes virtual environment, cache, and dependency directories from scanning
- Flags hardcoded passwords, use of
eval/exec, insecure HTTP calls, and other security anti-patterns - Skips B101 (assert_used) since test files use assertions
- Uses
-q(quiet) to only show findings
On failure:
🔒 Scanning for security issues with bandit...
>> Issue: [B105:hardcoded_password_string] Possible hardcoded password: 'secret123'
Severity: Low Confidence: Medium
Location: my-integration/main.py:15:0
❌ Security issues found
Fix: Review flagged code for security risks
Run locally: bandit -r <dir> -x .venv,venv,__pycache__,site-packages,dependencies -s B101
pip-audit -r <dir>/requirements.txt- Runs pip-audit against the integration's requirements.txt
- Checks all listed dependencies for known CVEs (Common Vulnerabilities and Exposures)
- Only runs if
requirements.txtexists
On failure:
🛡️ Checking dependencies for vulnerabilities with pip-audit...
Name Version ID Fix Versions
------- ------- -------------- ------------
requests 2.25.0 PYSEC-2023-XXX 2.31.0
❌ Vulnerable dependencies found
Fix: Update affected packages in requirements.txt
check_config_sync.py <dir>- Uses AST parsing to extract
@actiondecorators andinputsaccess patterns from the entry point - Cross-validates action names and input parameters between
config.jsonand code - Detects undocumented parameters, dead schema fields, and required/optional mismatches
On failure:
🔗 Checking config-code sync...
⚠️ Action 'send_email' in config.json but not found in code
❌ Input 'recipient' declared in config.json but never accessed in code
❌ Input 'priority' accessed in code but missing from config.json schema
❌ Config-code sync errors found
Fix: Ensure config.json actions and input schemas match the code
Run locally: python scripts/check_config_sync.py <dir>
flowchart TD
A[For each directory] --> B{requirements.txt exists?}
B -->|Yes| C[pip install dependencies]
B -->|No| D[Skip]
C --> D
D --> E[Find all .py files]
E --> F[py_compile each file]
F --> G{Syntax OK?}
G -->|No| H[Mark FAILED]
G -->|Yes| I[Read entry_point from config.json]
H --> I
I --> J[Run check_imports.py on entry point]
J --> K{Imports OK?}
K -->|No| H
K -->|Yes| L[Find all .json files]
L --> M[Validate each with json.tool]
M --> N{JSON OK?}
N -->|No| H
N -->|Yes| R[Run ruff check on directory]
R --> S{Lint OK?}
S -->|No| H
S -->|Yes| T[Run ruff format --check]
T --> U{Format OK?}
U -->|No| H
U -->|Yes| V[Run bandit security scan]
V --> W{Security OK?}
W -->|No| H
W -->|Yes| X{requirements.txt exists?}
X -->|No| AA
X -->|Yes| Y[Run pip-audit on requirements.txt]
Y --> Z{Deps OK?}
Z -->|No| H
Z -->|Yes| AA[Run config-code sync check]
AA --> AB{Sync OK?}
AB -->|No| H
AB -->|Yes| A
A --> O{Any failures?}
O -->|Yes| P[Exit 1]
O -->|No| Q[Exit 0]
The script produces formatted output with emoji indicators for each check:
----------------------------------------
Checking: my-integration
----------------------------------------
📦 Installing dependencies...
🐍 Checking Python syntax...
✅ Syntax OK
📥 Checking imports...
✅ Imports OK
📄 Checking JSON files...
✅ JSON files OK
🔍 Linting with ruff...
✅ Lint OK
🎨 Checking formatting with ruff...
✅ Formatting OK
🔒 Scanning for security issues with bandit...
✅ Security OK
🛡️ Checking dependencies for vulnerabilities with pip-audit...
✅ Dependencies OK
🔗 Checking config-code sync...
✅ Config-code sync OK
========================================
✅ CODE CHECK PASSED
========================================
- Python — for
py_compile,json, andcheck_imports - pip — for installing integration dependencies
- check_imports — imported as a module for import validation
- ruff — installed automatically for linting and formatting (configured via
ruff.toml) - bandit — installed automatically for security scanning
- pip-audit — installed automatically for dependency vulnerability checking
- check_config_sync — imported as a module for config-code sync validation
Called by the validate-integration.yml workflow (on pull requests):
- name: Code Check
if: steps.changed.outputs.dirs != ''
run: python scripts/check_code.py ${{ steps.changed.outputs.dirs }}Also exercised by the self-test.yml workflow against test examples in tests/examples/ as a regression guard.