Instruction file imported from demisto/demisto-sdk (
.github/instructions/lint.instructions.md). Copyright stays with the author.
Copilot instructions — content linters (lint, xsoar_linter)
Read together with the repo-wide
copilot-instructions.md and
commands.instructions.md. This file specialises
guidance for the linters the SDK ships for content code (not for the
SDK's own source).
Important: the SDK's own Python is linted by ruff + mypy (see
pyproject.toml). The commands documented here lint content — i.e. integration / script Python and PowerShell code shipped by content packs.
Scope
| Path | What it lints / what it is |
|---|---|
demisto_sdk/commands/lint/ |
Legacy demisto-sdk lint orchestrator (largely superseded by pre_commit but still consumed). Runs flake8 / pylint / mypy / bandit / pytest inside per-image Docker containers. |
demisto_sdk/commands/xsoar_linter/ |
XSOAR-specific pylint wrapper. Runs the custom XSOAR pylint plugins against integration / script Python and reports E/W codes. |
demisto_sdk/commands/pre_commit/resources/pylint_plugins/ |
The actual pylint plugins (base_checker, community_level_checker, partner_level_checker, certified_partner_level_checker, xsoar_level_checker). The xsoar_linter and pre_commit hooks both import these. |
Authoritative orchestrator: xsoar_linter.py
shows how the pylint command line is composed per support level
(base ⊂ community ⊂ partner ⊂ certified partner ⊂ xsoar).
Hard rules
- Do not add new linting features to
commands/lint/. It is in maintenance mode. New checks belong inpre_commitandxsoar_linter. - All container interactions go through
commands/common/docker/anddocker_helper.py. Don'timport dockerdirectly in lint code; use the existing wrappers so retry/auth/registry behaviour stays consistent. - Honour the support-level hierarchy. A check that applies to
baseautomatically applies tocommunity/partner/certified partner/xsoar. Don't duplicate a check across levels — put it at the lowest applicable level and let the level loader pick it up. - Honour
DEMISTO_SDK_OFFLINE_ENVand--no-docker. Linters that require a Docker image must skip cleanly with a clear log message when Docker is unavailable. - Errors are codes, not free text. Pylint plugin messages must use
stable
E####/W####IDs (orC####/R####) so content authors can suppress them precisely. Do not change an existing code's meaning. - No SDK self-linting from inside content linters. The plugins run inside the content Python environment (in a Docker image). They must not depend on SDK-only modules.
Adding a pylint check
- Decide which support level it belongs to (
baseis the strictest floor — every integration runs it). Pick the matching module undercommands/pre_commit/resources/pylint_plugins/. - Add a
BaseCheckersubclass with a freshname,priority, and amsgsdict mapping a new code (E####for errors,W####for warnings) to(message, symbol, description). - Implement the appropriate
visit_<node>methods (astroid). - Register it in the module's
register(linter)function. - Update the corresponding
<level>_msgconstant exposed for the xsoar_linter (base_msg,community_msg,partner_msg,cert_partner_msg,xsoar_msg) soxsoar_linter.pysurfaces the new code. - Add tests under
commands/xsoar_linter/tests/test_pylint_plugin/following the existing pylint-test pattern (load a sample integration, run the checker, assert messages). - Document the new code in the relevant content-author docs (xsoar.pan.dev
linked from
xsoar_linter/README.md). - Add a
feature(orfix) changelog entry.
Adding a Docker-based check (lint orchestrator)
If you really must extend commands/lint/
for a bug fix:
- Use the existing per-image Docker runner. Do not spawn raw containers.
- Cap timeouts. Linters running inside images must terminate; never wait indefinitely.
- Stream stdout/stderr through the project
logger. Do not buffer to a temp file unless the consumer downstream needs the file. - Surface non-zero exit codes from inside the container as a clear, parseable error in the parent process, with the image name and the inner command captured.
Don'ts
- Don't pin a specific Docker image tag in lint code. Image
selection is driven by the integration's
script.dockerimageand the native-image config incommands/common/native_image.py/docker_images_metadata.py. - Don't introduce parallelism primitives (
multiprocessing,concurrent.futures) without coordinating with the existing per-CPU bounds inxsoar_linter.pyandcommands/common/cpu_count.py. - Don't broaden the "skip" list silently. If a path or pattern is excluded, it must be documented in the README and in a changelog entry.
- Don't change the regex used to parse pylint output
(
ERROR_AND_WARNING_CODE_PATTERN) without updating downstream consumers (CI report parsers, the content build). - Don't embed colour or rich formatting in lint messages. Output is consumed by CI log scrapers and IDE problem matchers; plain text with stable codes is the contract.
Tests
- Use the small fixture content under
commands/xsoar_linter/tests/test_linter/andcommands/xsoar_linter/tests/test_pylint_plugin/. - Mock Docker — never pull an image in a unit test. The
tests.instructions.mdban applies here. - A check is considered tested when (a) a positive sample triggers the expected code exactly once and (b) a negative sample triggers nothing from this checker.