Skip to content
Open
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
15 changes: 11 additions & 4 deletions .automation/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -1655,10 +1655,17 @@ def process_type(linters_by_type, type1, type_label, linters_tables_md):
]
if hasattr(linter, "activation_rules"):
for rule in linter.activation_rules:
linter_doc_md += [
f"| {rule['variable']} | For {linter.linter_name} to be active, {rule['variable']} must be "
f"`{rule['expected_value']}` | `{rule['default_value']}` |"
]
rule_doc = (
f"| {rule['variable']} | For {linter.linter_name} to be "
f"active, {rule['variable']} must be "
)
if rule.get("type") == "variable_is_set":
rule_doc += "defined and not empty | _(not set)_ |"
else:
rule_doc += (
f"`{rule['expected_value']}` | " f"`{rule['default_value']}` |"
)
linter_doc_md += [rule_doc]
if hasattr(linter, "variables"):
for variable in linter.variables:
linter_doc_md += [
Expand Down
1 change: 1 addition & 0 deletions .automation/generated/linters_matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"ruby_rubocop",
"rust_clippy",
"salesforce_code_analyzer_apex",
"salesforce_code_analyzer_apexguru",
"salesforce_code_analyzer_aura",
"salesforce_code_analyzer_lwc",
"salesforce_code_analyzer_flow",
Expand Down
1 change: 1 addition & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@
"anymatch",
"análises",
"ApexCSRF",
"apexguru",
"apeyrat",
"apheleia",
"apkadd",
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/deploy-BETA-linters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,17 @@ jobs:
DOCKER_IMAGE: ghcr.io/${{ github.repository }}-only-${{ matrix.linter }}@${{ steps.build.outputs.digest }}
GH_SHA: ${{ github.sha }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Salesforce org auth url used by SALESFORCE_CODE_ANALYZER_APEXGURU.
# Empty on pull requests from forks: the ApexGuru tests then skip themselves
SFDX_AUTH_URL: ${{ secrets.SFDX_AUTH_URL }}
run: |
GITHUB_REPOSITORY=$([ "$EVENT_NAME" == "pull_request" ] && echo "$PR_HEAD_REPO" || echo "$GH_REPOSITORY")
GITHUB_BRANCH=$([ "$EVENT_NAME" == "pull_request" ] && echo "$HEAD_REF" || echo "$REF_NAME")

TEST_KEYWORDS_TO_USE_UPPER="${MATRIX_LINTER}"
TEST_KEYWORDS_TO_USE="${TEST_KEYWORDS_TO_USE_UPPER,,}"
docker image ls
docker run -e TEST_CASE_RUN=true -e OUTPUT_FORMAT=text -e OUTPUT_FOLDER="${GH_SHA}" -e OUTPUT_DETAIL=detailed -e GITHUB_SHA="${GH_SHA}" -e GITHUB_REPOSITORY="${GITHUB_REPOSITORY}" -e GITHUB_BRANCH="${GITHUB_BRANCH}" -e GITHUB_TOKEN="${GITHUB_TOKEN}" -e TEST_KEYWORDS="${TEST_KEYWORDS_TO_USE}" -e MEGALINTER_VOLUME_ROOT="${GITHUB_WORKSPACE}" -v "/var/run/docker.sock:/var/run/docker.sock:rw" -v "${GITHUB_WORKSPACE}:/tmp/lint" "${DOCKER_IMAGE}"
docker run -e TEST_CASE_RUN=true -e OUTPUT_FORMAT=text -e OUTPUT_FOLDER="${GH_SHA}" -e OUTPUT_DETAIL=detailed -e GITHUB_SHA="${GH_SHA}" -e GITHUB_REPOSITORY="${GITHUB_REPOSITORY}" -e GITHUB_BRANCH="${GITHUB_BRANCH}" -e GITHUB_TOKEN="${GITHUB_TOKEN}" -e SFDX_AUTH_URL="${SFDX_AUTH_URL}" -e TEST_KEYWORDS="${TEST_KEYWORDS_TO_USE}" -e MEGALINTER_VOLUME_ROOT="${GITHUB_WORKSPACE}" -v "/var/run/docker.sock:/var/run/docker.sock:rw" -v "${GITHUB_WORKSPACE}:/tmp/lint" "${DOCKER_IMAGE}"
timeout-minutes: 30

# Docker Hub mirroring is disabled — MegaLinter is published to ghcr.io only.
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/deploy-DEV-linters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -322,14 +322,17 @@ jobs:
DOCKER_IMAGE: ${{ fromJson(steps.meta.outputs.json).tags[0] }}
GH_SHA: ${{ github.sha }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Salesforce org auth url used by SALESFORCE_CODE_ANALYZER_APEXGURU.
# Empty on pull requests from forks: the ApexGuru tests then skip themselves
SFDX_AUTH_URL: ${{ secrets.SFDX_AUTH_URL }}
run: |
GITHUB_REPOSITORY=$([ "$EVENT_NAME" == "pull_request" ] && echo "$PR_HEAD_REPO" || echo "$GH_REPOSITORY")
GITHUB_BRANCH=$([ "$EVENT_NAME" == "pull_request" ] && echo "$HEAD_REF" || echo "$REF_NAME")

TEST_KEYWORDS_TO_USE_UPPER="${MATRIX_LINTER}"
TEST_KEYWORDS_TO_USE="${TEST_KEYWORDS_TO_USE_UPPER,,}"
docker image ls
docker run -e TEST_CASE_RUN=true -e OUTPUT_FORMAT=text -e OUTPUT_FOLDER="${GH_SHA}" -e OUTPUT_DETAIL=detailed -e GITHUB_SHA="${GH_SHA}" -e GITHUB_REPOSITORY="${GITHUB_REPOSITORY}" -e GITHUB_BRANCH="${GITHUB_BRANCH}" -e GITHUB_TOKEN="${GITHUB_TOKEN}" -e TEST_KEYWORDS="${TEST_KEYWORDS_TO_USE}" -e MEGALINTER_VOLUME_ROOT="${GITHUB_WORKSPACE}" -v "/var/run/docker.sock:/var/run/docker.sock:rw" -v "${GITHUB_WORKSPACE}:/tmp/lint" "${DOCKER_IMAGE}"
docker run -e TEST_CASE_RUN=true -e OUTPUT_FORMAT=text -e OUTPUT_FOLDER="${GH_SHA}" -e OUTPUT_DETAIL=detailed -e GITHUB_SHA="${GH_SHA}" -e GITHUB_REPOSITORY="${GITHUB_REPOSITORY}" -e GITHUB_BRANCH="${GITHUB_BRANCH}" -e GITHUB_TOKEN="${GITHUB_TOKEN}" -e SFDX_AUTH_URL="${SFDX_AUTH_URL}" -e TEST_KEYWORDS="${TEST_KEYWORDS_TO_USE}" -e MEGALINTER_VOLUME_ROOT="${GITHUB_WORKSPACE}" -v "/var/run/docker.sock:/var/run/docker.sock:rw" -v "${GITHUB_WORKSPACE}:/tmp/lint" "${DOCKER_IMAGE}"
timeout-minutes: 30

##############################################
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/deploy-DEV.yml
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ jobs:
DOCKER_IMAGE: ${{ needs.build.outputs.image-tag }}
GH_SHA: ${{ github.sha }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Salesforce org auth url used by SALESFORCE_CODE_ANALYZER_APEXGURU.
# Empty on pull requests from forks: the ApexGuru tests then skip themselves
SFDX_AUTH_URL: ${{ secrets.SFDX_AUTH_URL }}
run: |
GITHUB_REPOSITORY=$([ "$EVENT_NAME" == "pull_request" ] && echo "$PR_HEAD_REPO" || echo "$GH_REPOSITORY")
GITHUB_BRANCH=$([ "$EVENT_NAME" == "pull_request" ] && echo "$HEAD_REF" || echo "$REF_NAME")
Expand All @@ -287,7 +290,7 @@ jobs:
fi
docker image ls
# shellcheck disable=SC2086
docker run $CI_ENV -e TEST_CASE_RUN=true -e OUTPUT_FORMAT=text -e OUTPUT_FOLDER="${GH_SHA}" -e OUTPUT_DETAIL=detailed -e GITHUB_SHA="${GH_SHA}" -e GITHUB_REPOSITORY="${GITHUB_REPOSITORY}" -e GITHUB_BRANCH="${GITHUB_BRANCH}" -e GITHUB_TOKEN="${GITHUB_TOKEN}" -e TEST_KEYWORDS="${TEST_KEYWORDS_TO_USE}" -e MEGALINTER_VOLUME_ROOT="${GITHUB_WORKSPACE}" -v "/var/run/docker.sock:/var/run/docker.sock:rw" -v "${GITHUB_WORKSPACE}:/tmp/lint" "${DOCKER_IMAGE}"
docker run $CI_ENV -e TEST_CASE_RUN=true -e OUTPUT_FORMAT=text -e OUTPUT_FOLDER="${GH_SHA}" -e OUTPUT_DETAIL=detailed -e GITHUB_SHA="${GH_SHA}" -e GITHUB_REPOSITORY="${GITHUB_REPOSITORY}" -e GITHUB_BRANCH="${GITHUB_BRANCH}" -e GITHUB_TOKEN="${GITHUB_TOKEN}" -e SFDX_AUTH_URL="${SFDX_AUTH_URL}" -e TEST_KEYWORDS="${TEST_KEYWORDS_TO_USE}" -e MEGALINTER_VOLUME_ROOT="${GITHUB_WORKSPACE}" -v "/var/run/docker.sock:/var/run/docker.sock:rw" -v "${GITHUB_WORKSPACE}:/tmp/lint" "${DOCKER_IMAGE}"
timeout-minutes: 120

- name: Archive production artifacts (test-cases)
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ Note: Can be used with `oxsecurity/megalinter@beta` in your GitHub Action mega-l
- Activated only when a **biome.json** or **biome.jsonc** configuration file is found in the repository
- Supports **APPLY_FIXES** (safe fixes with `--write`) and native **SARIF** output
- `EXCLUDED_DIRECTORIES` are forwarded in project lint mode through a generated configuration extending the workspace one
- **[ApexGuru](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-apexguru.html)**, the AI-driven engine of **Salesforce Code Analyzer**, available as **SALESFORCE_CODE_ANALYZER_APEXGURU**
- Detects **SOQL inefficiencies**, critical anti-patterns and scalability hotspots in your `.cls` and `.trigger` files, with line-level highlights, severity ratings and suggested fixes
- The analysis runs **in a connected Salesforce org**, not locally: store the [auth url](https://developer.salesforce.com/docs/platform/salesforce-cli-reference/guide/cli_reference_org_display.html) of the target org in a CI secret named **`SFDX_AUTH_URL`**, and MegaLinter logs in to that org before the scan
- **Inactive by default**: it activates only when `SFDX_AUTH_URL` is defined, so nothing changes for existing Salesforce projects
- Requires **ApexGuru to be enabled** on the org: it needs Scale Center, and is available for Unlimited Edition production orgs, full copy sandboxes, Signature orgs and Scale Test customers
- Supports native **SARIF** output, like the other Code Analyzer engines
- **[tofu fmt](https://opentofu.org/docs/cli/commands/fmt/)**, the built-in formatter of **OpenTofu** (the MPL-2.0 licensed fork of Terraform), available as **TERRAFORM_TOFU_FMT** ([#8729](https://github.com/oxsecurity/megalinter/issues/8729))
- Analyzes **`.tofu`** files only, the OpenTofu specific extension, so it never doubles up with **TERRAFORM_TERRAFORM_FMT** which keeps `.tf`
- To format your `.tf` files with OpenTofu instead, set `TERRAFORM_TOFU_FMT_FILE_EXTENSIONS: [".tofu", ".tf", ".tfvars"]` and `DISABLE_LINTERS: [TERRAFORM_TERRAFORM_FMT]`
Expand Down Expand Up @@ -139,11 +145,14 @@ Note: Can be used with `oxsecurity/megalinter@beta` in your GitHub Action mega-l
- **Docker pulls monthly chart**: the auto-update workflow now regenerates `docs/assets/images/docker-pulls-monthly.svg` (new pulls per month since October 2020, all images and registries), via the new `.automation/docker_pulls_chart.py` called by `build.py` after the pull counters update
- Historical monthly points are frozen in `.automation/generated/docker-pulls-monthly.json` (built once from the tracked stats plus a Web Archive reconstruction of the collection gaps); the script only appends newly completed months computed from `flavors-stats.json`
- Docker pull counters now also track the **standalone `megalinter-only-*` images**: their download counts are stored in `flavors-stats.json` and included in the README badge total
- New descriptor `activation_rules` type **`variable_is_set`**, activating a linter as soon as a variable holds a value. The existing `variable` type can only compare a variable to a fixed `expected_value`, which can not express "a credential is present" - the condition **SALESFORCE_CODE_ANALYZER_APEXGURU** needs on `SFDX_AUTH_URL`
- Linter tests gated on such a variable **skip themselves** when it is missing, instead of failing: `LinterTestRoot.skip_if_required_variables_missing()` guards the per-lint-mode and SARIF tests, while the version and help tests keep running since they need no credential

- CI
- **Supply-chain hardening of dependency updates**: Renovate (`minimumReleaseAge`) and Dependabot (`cooldown`) now wait until a release is at least **7 days old** before proposing an upgrade, so compromised releases can be caught by the community first. Security fixes are not delayed and still open immediately
- New **Check agent plugins manifests** workflow validating the agent plugin manifests on every change to them or to `skills/`: `.automation/validate_agent_plugins.py` checks the root `plugin.json` against the published Agent Plugins 1.0 schema and keeps the per-vendor manifests consistent with it, then `claude plugin validate ./ --strict` checks the Claude Code marketplace and plugin manifests
- The auto-update workflow patch-bumps the agent plugin version when it regenerates the skills: the plugin follows its own release train, since its fix guides change far more often than MegaLinter is released. `plugin.json` is the single source of truth, mirrored into the per-vendor manifests by `.automation/agent_plugin_manifests.py` (called by `build.py`)
- The test workflows forward the **`SFDX_AUTH_URL`** repository secret to the test container, so the **SALESFORCE_CODE_ANALYZER_APEXGURU** lint tests can reach a connected org. The secret is not exposed on pull requests from forked repositories, where those tests skip themselves

- Linter versions upgrades (N)
- [editorconfig-checker](https://editorconfig-checker.github.io/) from 3.10.0 to **3.11.1** on 2026-08-09
Expand Down
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,11 @@ RUN curl -sSfL https://raw.githubusercontent.com/anchore/syft/refs/tags/v${REPOS
&& sf plugins install code-analyzer@${SALESFORCE_CODE_ANALYZER_VERSION} \
&& (npm cache clean --force || true) \
&& rm -rf /root/.npm/_cacache \
# code-analyzer-apexguru installation
# Next line commented because already managed by another linter
# RUN sf plugins install code-analyzer@${SALESFORCE_CODE_ANALYZER_VERSION} \
# && (npm cache clean --force || true) \
# && rm -rf /root/.npm/_cacache
# code-analyzer-aura installation
# Next line commented because already managed by another linter
# RUN sf plugins install code-analyzer@${SALESFORCE_CODE_ANALYZER_VERSION} \
Expand Down
1 change: 1 addition & 0 deletions docs/standalone-linters.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
| RUBY_RUBOCOP | ghcr.io/oxsecurity/megalinter-only-ruby_rubocop:beta | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/oxsecurity/megalinter-only-ruby_rubocop/beta) |
| RUST_CLIPPY | ghcr.io/oxsecurity/megalinter-only-rust_clippy:beta | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/oxsecurity/megalinter-only-rust_clippy/beta) |
| SALESFORCE_CODE_ANALYZER_APEX | ghcr.io/oxsecurity/megalinter-only-salesforce_code_analyzer_apex:beta | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/oxsecurity/megalinter-only-salesforce_code_analyzer_apex/beta) |
| SALESFORCE_CODE_ANALYZER_APEXGURU | ghcr.io/oxsecurity/megalinter-only-salesforce_code_analyzer_apexguru:beta | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/oxsecurity/megalinter-only-salesforce_code_analyzer_apexguru/beta) |
| SALESFORCE_CODE_ANALYZER_AURA | ghcr.io/oxsecurity/megalinter-only-salesforce_code_analyzer_aura:beta | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/oxsecurity/megalinter-only-salesforce_code_analyzer_aura/beta) |
| SALESFORCE_CODE_ANALYZER_LWC | ghcr.io/oxsecurity/megalinter-only-salesforce_code_analyzer_lwc:beta | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/oxsecurity/megalinter-only-salesforce_code_analyzer_lwc/beta) |
| SALESFORCE_CODE_ANALYZER_FLOW | ghcr.io/oxsecurity/megalinter-only-salesforce_code_analyzer_flow:beta | ![Docker Image Size (tag)](https://img.shields.io/docker/image-size/oxsecurity/megalinter-only-salesforce_code_analyzer_flow/beta) |
Expand Down
5 changes: 5 additions & 0 deletions flavors/salesforce/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,11 @@ RUN curl -sSfL https://raw.githubusercontent.com/anchore/syft/refs/tags/v${REPOS
&& sf plugins install code-analyzer@${SALESFORCE_CODE_ANALYZER_VERSION} \
&& (npm cache clean --force || true) \
&& rm -rf /root/.npm/_cacache
# code-analyzer-apexguru installation
# Next line commented because already managed by another linter
# RUN sf plugins install code-analyzer@${SALESFORCE_CODE_ANALYZER_VERSION} \
# && (npm cache clean --force || true) \
# && rm -rf /root/.npm/_cacache
# code-analyzer-aura installation
# Next line commented because already managed by another linter
# RUN sf plugins install code-analyzer@${SALESFORCE_CODE_ANALYZER_VERSION} \
Expand Down
1 change: 1 addition & 0 deletions flavors/salesforce/flavor.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"REPOSITORY_TRIVY_SBOM",
"REPOSITORY_TRUFFLEHOG",
"SALESFORCE_CODE_ANALYZER_APEX",
"SALESFORCE_CODE_ANALYZER_APEXGURU",
"SALESFORCE_CODE_ANALYZER_AURA",
"SALESFORCE_CODE_ANALYZER_LWC",
"SALESFORCE_CODE_ANALYZER_FLOW",
Expand Down
Loading
Loading