diff --git a/.github/config/regal-sigilix.yaml b/.github/config/regal-sigilix.yaml new file mode 100644 index 0000000..7bccfa8 --- /dev/null +++ b/.github/config/regal-sigilix.yaml @@ -0,0 +1,23 @@ +rules: + imports: + use-rego-v1: + level: ignore + implicit-future-keywords: + level: ignore + import-after-rule: + level: ignore + prefer-package-imports: + level: ignore + redundant-alias: + level: ignore + redundant-data-import: + level: ignore +ignore: + files: + - "**/.git/**" + - "**/node_modules/**" + - "**/dist/**" + - "**/build/**" + - "**/coverage/**" + - "**/vendor/**" + - "**/.terraform/**" diff --git a/.github/config/tool-manifest.json b/.github/config/tool-manifest.json index c4f1893..e0ad5a4 100644 --- a/.github/config/tool-manifest.json +++ b/.github/config/tool-manifest.json @@ -105,6 +105,11 @@ "env": "AST_GREP_ENABLED", "output": "ast-grep.sarif" }, + { + "id": "regal", + "env": "REGAL_ENABLED", + "output": "regal.sarif" + }, { "id": "htmlhint", "env": "HTMLHINT_ENABLED", diff --git a/.github/scripts/policy_iac_tools_workflow_test.py b/.github/scripts/policy_iac_tools_workflow_test.py new file mode 100644 index 0000000..faebee5 --- /dev/null +++ b/.github/scripts/policy_iac_tools_workflow_test.py @@ -0,0 +1,101 @@ +import json +import os +import re +import unittest + + +ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +WORKFLOW_PATH = os.path.join(ROOT, ".github", "workflows", "scan.yml") +MANIFEST_PATH = os.path.join(ROOT, ".github", "config", "tool-manifest.json") +REGAL_CONFIG_PATH = os.path.join(ROOT, ".github", "config", "regal-sigilix.yaml") +SCRIPT_DIR = os.path.join(ROOT, ".github", "scripts") + + +class PolicyIacToolsWorkflowTest(unittest.TestCase): + def read_file(self, path): + with open(path, encoding="utf-8") as handle: + return handle.read() + + def workflow_text(self): + return self.read_file(WORKFLOW_PATH) + + def workflow_input_block(self, input_name): + pattern = rf"\n {re.escape(input_name)}:\n(?P(?: .+\n)+)" + match = re.search(pattern, self.workflow_text()) + self.assertIsNotNone(match) + return match.group("block") + + def workflow_step_block(self, step_name): + pattern = rf"(?ms)^ - name: {re.escape(step_name)}\n.+?(?=^ - name: |\Z)" + match = re.search(pattern, self.workflow_text()) + self.assertIsNotNone(match) + return match.group(0) + + def manifest_rows(self): + with open(MANIFEST_PATH, encoding="utf-8") as handle: + return {row["id"]: row for row in json.load(handle)["tools"]} + + def script_text(self, filename): + return self.read_file(os.path.join(SCRIPT_DIR, filename)) + + def test_regal_is_default_on_and_manifested(self): + text = self.workflow_text() + rows = self.manifest_rows() + + self.assertIn(" default: true\n", self.workflow_input_block("regal")) + self.assertIn("REGAL_ENABLED: ${{ inputs.regal }}", text) + self.assertIn('REGAL_VERSION: "0.41.1"', text) + self.assertIn("REGAL_LINUX_X86_64_SHA256:", text) + self.assertEqual(rows["regal"], {"id": "regal", "env": "REGAL_ENABLED", "output": "regal.sarif"}) + + def test_workflow_delegates_policy_iac_tools_to_runner_scripts(self): + expectations = { + "Run zizmor to SARIF": "run_zizmor.sh", + "Run Hadolint to SARIF": "run_hadolint.sh", + "Run Regal to SARIF": "run_regal.sh", + } + + for step_name, script_name in expectations.items(): + block = self.workflow_step_block(step_name) + self.assertIn(f'bash "$RUNNER_DIR/.github/scripts/{script_name}"', block) + + def test_regal_wrapper_uses_high_confidence_sigilix_profile(self): + text = self.script_text("run_regal.sh") + config = self.read_file(REGAL_CONFIG_PATH) + + self.assertIn("REGAL_VERSION", text) + self.assertIn("REGAL_LINUX_X86_64_SHA256", text) + self.assertIn("regal_Linux_x86_64", text) + self.assertIn("sha256sum -c --strict", text) + self.assertIn("Regal installed version mismatch", text) + self.assertIn("discover_rego_files", text) + self.assertIn("No Rego files found", text) + self.assertIn('regal_config="$RUNNER_DIR/.github/config/regal-sigilix.yaml"', text) + self.assertIn("--config-file \"$regal_config\"", text) + for category in ("idiomatic", "style", "performance", "testing", "custom"): + self.assertIn(f"--disable-category {category}", text) + self.assertIn("--format sarif", text) + self.assertIn("--output-file \"$raw\"", text) + self.assertIn("sigilix_sarif_contract.py", text) + self.assertIn("use-rego-v1:", config) + self.assertIn("level: ignore", config) + self.assertIn("node_modules", config) + self.assertIn(".terraform", config) + + def test_zizmor_and_hadolint_wrappers_preserve_sarif_contracts(self): + zizmor = self.script_text("run_zizmor.sh") + hadolint = self.script_text("run_hadolint.sh") + + self.assertIn("ZIZMOR_VERSION", zizmor) + self.assertIn("python3 -m pip install --quiet", zizmor) + self.assertIn("zizmor --format sarif .", zizmor) + self.assertIn("sigilix_sarif_contract.py", zizmor) + self.assertIn("HADOLINT_VERSION", hadolint) + self.assertIn("hadolint-linux-x86_64", hadolint) + self.assertIn("Dockerfile.*", hadolint) + self.assertIn("--no-fail --format sarif", hadolint) + self.assertIn("sigilix_sarif_contract.py", hadolint) + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/scripts/run_hadolint.sh b/.github/scripts/run_hadolint.sh new file mode 100644 index 0000000..62f1fa8 --- /dev/null +++ b/.github/scripts/run_hadolint.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${HADOLINT_VERSION:?}" +: "${RESULT_CAP:?}" +: "${RUNNER_DIR:?}" +: "${RUNNER_TEMP:?}" +: "${SARIF_DIR:?}" +: "${SOURCE_DIR:?}" + +SOURCE_DIR="$(cd "$SOURCE_DIR" && pwd -P)" +RUNNER_DIR="$(cd "$RUNNER_DIR" && pwd -P)" + +raw="$SARIF_DIR/hadolint.raw.sarif" +out="$SARIF_DIR/hadolint.sarif" +files_list="$RUNNER_TEMP/hadolint-files" + +mkdir -p "$SARIF_DIR" "$RUNNER_TEMP" + +emit_empty_sarif() { + printf '{"version":"2.1.0","runs":[]}' > "$raw" +} + +cd "$SOURCE_DIR" +if ! curl -fsSL -o "$RUNNER_TEMP/hadolint" \ + "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-linux-x86_64"; then + echo "::warning::hadolint download failed - manifest will record missing output." +elif ! chmod +x "$RUNNER_TEMP/hadolint"; then + echo "::warning::hadolint chmod failed - manifest will record missing output." +elif ! find . -type f \( -name 'Dockerfile' -o -name 'Dockerfile.*' \) \ + -not -path './.git/*' -not -path './node_modules/*' -print0 > "$files_list"; then + echo "::warning::hadolint file discovery failed - manifest will record missing output." +else + files=() + while IFS= read -r -d '' file; do + files+=("$file") + done < "$files_list" + if [ "${#files[@]}" -eq 0 ]; then + emit_empty_sarif + else + "$RUNNER_TEMP/hadolint" --no-fail --format sarif "${files[@]}" > "$raw" || true + if [ ! -s "$raw" ]; then emit_empty_sarif; fi + fi + python3 "$RUNNER_DIR/.github/scripts/sigilix_sarif_contract.py" \ + hadolint "$raw" "$out" --cap "$RESULT_CAP" --ensure-run \ + || echo "::warning::hadolint SARIF normalization failed - manifest will record missing output." +fi diff --git a/.github/scripts/run_regal.sh b/.github/scripts/run_regal.sh new file mode 100644 index 0000000..b4868ca --- /dev/null +++ b/.github/scripts/run_regal.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${REGAL_LINUX_X86_64_SHA256:?}" +: "${REGAL_VERSION:?}" +: "${RESULT_CAP:?}" +: "${RUNNER_DIR:?}" +: "${RUNNER_TEMP:?}" +: "${SARIF_DIR:?}" +: "${SOURCE_DIR:?}" + +SOURCE_DIR="$(cd "$SOURCE_DIR" && pwd -P)" +RUNNER_DIR="$(cd "$RUNNER_DIR" && pwd -P)" + +raw="$SARIF_DIR/regal.raw.sarif" +out="$SARIF_DIR/regal.sarif" +regal_config="$RUNNER_DIR/.github/config/regal-sigilix.yaml" +regal_bin="$RUNNER_TEMP/regal" +files_list="" + +mkdir -p "$SARIF_DIR" "$RUNNER_TEMP" +files_list="$(mktemp "$RUNNER_TEMP/regal-files.XXXXXX")" + +cleanup_regal() { + rm -f "$files_list" "$regal_bin" +} +trap cleanup_regal EXIT + +emit_empty_sarif() { + printf '{"version":"2.1.0","runs":[]}' > "$raw" +} + +discover_rego_files() { + find -P . \ + \( -type d \( -name '.git' -o -name 'node_modules' -o -name 'dist' -o -name 'build' \ + -o -name 'coverage' -o -name 'vendor' -o -name '.terraform' \) -prune \) -o \ + \( -type f -name '*.rego' -print0 \) +} + +cd "$SOURCE_DIR" +if [ ! -f "$regal_config" ]; then + echo "::warning::Regal Sigilix config missing at $regal_config - emitting empty Regal SARIF run." + emit_empty_sarif +elif ! discover_rego_files > "$files_list"; then + echo "::warning::Regal file discovery failed - emitting empty Regal SARIF run." + emit_empty_sarif +elif ! grep -qz . "$files_list"; then + echo "::notice::No Rego files found - emitting empty Regal SARIF run." + emit_empty_sarif +elif [[ ! "$REGAL_VERSION" =~ ^[0-9]+[.][0-9]+[.][0-9]+$ ]]; then + echo "::warning::Regal version must be a pinned x.y.z version - emitting empty Regal SARIF run." + emit_empty_sarif +elif [[ ! "$REGAL_LINUX_X86_64_SHA256" =~ ^[0-9a-f]{64}$ ]]; then + echo "::warning::Regal checksum must be a pinned SHA256 value - emitting empty Regal SARIF run." + emit_empty_sarif +elif ! curl -fsSL -o "$regal_bin" \ + "https://github.com/open-policy-agent/regal/releases/download/v${REGAL_VERSION}/regal_Linux_x86_64"; then + echo "::warning::Regal download failed - emitting empty Regal SARIF run." + emit_empty_sarif +elif ! printf '%s %s\n' "$REGAL_LINUX_X86_64_SHA256" "$regal_bin" | sha256sum -c --strict -; then + echo "::warning::Regal checksum mismatch - emitting empty Regal SARIF run." + emit_empty_sarif +elif ! chmod +x "$regal_bin"; then + echo "::warning::Regal chmod failed - emitting empty Regal SARIF run." + emit_empty_sarif +elif ! regal_version="$("$regal_bin" version 2>/dev/null)"; then + echo "::warning::Regal version check failed - emitting empty Regal SARIF run." + emit_empty_sarif +elif ! printf '%s\n' "$regal_version" | grep -q "^Version:[[:space:]]*${REGAL_VERSION}$"; then + echo "::warning::Regal installed version mismatch - emitting empty Regal SARIF run." + emit_empty_sarif +else + files=() + while IFS= read -r -d '' file; do + files+=("$file") + done < "$files_list" + "$regal_bin" lint \ + --config-file "$regal_config" \ + --disable-category idiomatic \ + --disable-category style \ + --disable-category performance \ + --disable-category testing \ + --disable-category custom \ + --format sarif \ + --output-file "$raw" \ + -- \ + "${files[@]}" || true + if [ ! -s "$raw" ]; then + echo "::warning::Regal scan produced no SARIF output - emitting empty Regal SARIF run." + emit_empty_sarif + fi +fi + +python3 "$RUNNER_DIR/.github/scripts/sigilix_sarif_contract.py" \ + regal "$raw" "$out" --cap "$RESULT_CAP" --ensure-run diff --git a/.github/scripts/run_zizmor.sh b/.github/scripts/run_zizmor.sh new file mode 100644 index 0000000..99c808a --- /dev/null +++ b/.github/scripts/run_zizmor.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${RESULT_CAP:?}" +: "${RUNNER_DIR:?}" +: "${SARIF_DIR:?}" +: "${SOURCE_DIR:?}" +: "${ZIZMOR_VERSION:?}" + +SOURCE_DIR="$(cd "$SOURCE_DIR" && pwd -P)" +RUNNER_DIR="$(cd "$RUNNER_DIR" && pwd -P)" + +raw="$SARIF_DIR/zizmor.raw.sarif" +out="$SARIF_DIR/zizmor.sarif" + +mkdir -p "$SARIF_DIR" + +emit_empty_sarif() { + printf '{"version":"2.1.0","runs":[]}' > "$raw" +} + +cd "$SOURCE_DIR" +if [ ! -d .github/workflows ]; then + emit_empty_sarif +elif ! python3 -m pip install --quiet "zizmor==${ZIZMOR_VERSION}"; then + echo "::warning::zizmor install failed - manifest will record missing output." +else + zizmor --format sarif . > "$raw" || true + if [ ! -s "$raw" ]; then emit_empty_sarif; fi +fi + +if [ -s "$raw" ]; then + python3 "$RUNNER_DIR/.github/scripts/sigilix_sarif_contract.py" \ + zizmor "$raw" "$out" --cap "$RESULT_CAP" --ensure-run \ + || echo "::warning::zizmor SARIF normalization failed - manifest will record missing output." +fi diff --git a/.github/scripts/sigilix_sarif_contract.py b/.github/scripts/sigilix_sarif_contract.py index c8b5b59..88ac5b2 100644 --- a/.github/scripts/sigilix_sarif_contract.py +++ b/.github/scripts/sigilix_sarif_contract.py @@ -28,6 +28,7 @@ "biome", "oxlint", "ast-grep", + "regal", "htmlhint", "stylelint", "yamllint", @@ -58,6 +59,7 @@ "biome": "Biome", "oxlint": "Oxlint", "ast-grep": "ast-grep", + "regal": "Regal", "htmlhint": "HTMLHint", "stylelint": "Stylelint", "yamllint": "YAMLlint", diff --git a/.github/scripts/sigilix_sarif_test.py b/.github/scripts/sigilix_sarif_test.py index dd3315b..95f01cc 100644 --- a/.github/scripts/sigilix_sarif_test.py +++ b/.github/scripts/sigilix_sarif_test.py @@ -82,6 +82,7 @@ def test_contract_accepts_legacy_and_next_batch_tool_ids(self): ("biome", "Biome"), ("oxlint", "Oxlint"), ("ast-grep", "ast-grep"), + ("regal", "Regal"), ): run = attach_sigilix_metadata({}, tool_id) driver = run["tool"]["driver"] @@ -487,6 +488,10 @@ def test_contract_cli_attaches_metadata_for_new_native_language_tools(self): "htmlhint": "htmlhint.sarif", } +POLICY_TOOL_OUTPUTS = { + "regal": "regal.sarif", +} + LANGUAGE_CONVERTER_TOOL_OUTPUTS = { "flake8": "flake8.sarif", "stylelint": "stylelint.sarif", @@ -516,6 +521,7 @@ def test_contract_cli_attaches_metadata_for_new_native_language_tools(self): **OPT_IN_SECURITY_TOOL_OUTPUTS, **TERRAFORM_TOOL_OUTPUTS, **LANGUAGE_SARIF_TOOL_OUTPUTS, + **POLICY_TOOL_OUTPUTS, **LANGUAGE_CONVERTER_TOOL_OUTPUTS, **CONFIG_TOOL_OUTPUTS, **CI_SECURITY_TOOL_OUTPUTS, @@ -664,6 +670,7 @@ def test_catalog_tool_outputs_are_manifested_and_merged(self): **OPT_IN_SECURITY_TOOL_OUTPUTS, **TERRAFORM_TOOL_OUTPUTS, **LANGUAGE_SARIF_TOOL_OUTPUTS, + **POLICY_TOOL_OUTPUTS, **LANGUAGE_CONVERTER_TOOL_OUTPUTS, **CONFIG_TOOL_OUTPUTS, **CI_SECURITY_TOOL_OUTPUTS, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b06832..68dbdf7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,7 @@ jobs: python3 .github/scripts/docs_config_tools_test.py python3 .github/scripts/oxlint_workflow_test.py python3 .github/scripts/ast_grep_workflow_test.py + python3 .github/scripts/policy_iac_tools_workflow_test.py python3 -m py_compile .github/scripts/*.py lint: diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index c45e42c..0145fbb 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -142,6 +142,11 @@ on: required: false default: true type: boolean + regal: + description: "Run Regal on Rego policy files with Sigilix-controlled bug and import rules." + required: false + default: true + type: boolean htmlhint: description: "Run HTMLHint on HTML files with Sigilix-controlled correctness rules." required: false @@ -226,6 +231,8 @@ jobs: OXLINT_NPM_INTEGRITY: "sha512-ypZkK/aDc5NQV8zIR6s2H2Tl3aNW8FmJ1m9+2qsaYuRenl8vgnHNCGwTHviWJdUQzglOlHFchgopdtGhSy17Rw==" OXLINT_VERSION: "1.69.0" PYLINT_VERSION: "4.0.5" + REGAL_LINUX_X86_64_SHA256: "6769dcd8e88bc5ba5ff4fac500e4a99d55b3eec3d1d0842833d84f6820a2a80f" + REGAL_VERSION: "0.41.1" RESULT_CAP: ${{ inputs.result-cap }} RUFF_VERSION: "0.15.17" SARIF_BYTE_CAP: ${{ inputs.sarif-byte-cap }} @@ -656,54 +663,14 @@ jobs: run: | set -euo pipefail cd "$SOURCE_DIR" - raw="$SARIF_DIR/zizmor.raw.sarif" - out="$SARIF_DIR/zizmor.sarif" - if [ ! -d .github/workflows ]; then - printf '{"version":"2.1.0","runs":[]}' > "$raw" - elif ! python3 -m pip install --quiet "zizmor==${ZIZMOR_VERSION}"; then - echo "::warning::zizmor install failed - manifest will record missing output." - else - zizmor --format sarif . > "$raw" || true - if [ ! -s "$raw" ]; then printf '{"version":"2.1.0","runs":[]}' > "$raw"; fi - fi - if [ -s "$raw" ]; then - python3 "$RUNNER_DIR/.github/scripts/sigilix_sarif_contract.py" \ - zizmor "$raw" "$out" --cap "$RESULT_CAP" --ensure-run \ - || echo "::warning::zizmor SARIF normalization failed - manifest will record missing output." - fi + bash "$RUNNER_DIR/.github/scripts/run_zizmor.sh" - name: Run Hadolint to SARIF if: ${{ inputs.hadolint }} run: | set -euo pipefail cd "$SOURCE_DIR" - raw="$SARIF_DIR/hadolint.raw.sarif" - out="$SARIF_DIR/hadolint.sarif" - if ! curl -fsSL -o "$RUNNER_TEMP/hadolint" \ - "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-linux-x86_64"; then - echo "::warning::hadolint download failed - manifest will record missing output." - else - if ! chmod +x "$RUNNER_TEMP/hadolint"; then - echo "::warning::hadolint chmod failed - manifest will record missing output." - else - files_list="$RUNNER_TEMP/hadolint-files" - if ! find . -type f \( -name 'Dockerfile' -o -name 'Dockerfile.*' \) \ - -not -path './.git/*' -not -path './node_modules/*' -print0 > "$files_list"; then - echo "::warning::hadolint file discovery failed - manifest will record missing output." - else - mapfile -d '' files < "$files_list" - if [ "${#files[@]}" -eq 0 ]; then - printf '{"version":"2.1.0","runs":[]}' > "$raw" - else - "$RUNNER_TEMP/hadolint" --no-fail --format sarif "${files[@]}" > "$raw" || true - if [ ! -s "$raw" ]; then printf '{"version":"2.1.0","runs":[]}' > "$raw"; fi - fi - python3 "$RUNNER_DIR/.github/scripts/sigilix_sarif_contract.py" \ - hadolint "$raw" "$out" --cap "$RESULT_CAP" --ensure-run \ - || echo "::warning::hadolint SARIF normalization failed - manifest will record missing output." - fi - fi - fi + bash "$RUNNER_DIR/.github/scripts/run_hadolint.sh" - name: Run TFLint to SARIF if: ${{ inputs.tflint }} @@ -712,6 +679,13 @@ jobs: cd "$SOURCE_DIR" bash "$RUNNER_DIR/.github/scripts/run_tflint.sh" + - name: Run Regal to SARIF + if: ${{ inputs.regal }} + run: | + set -euo pipefail + cd "$SOURCE_DIR" + bash "$RUNNER_DIR/.github/scripts/run_regal.sh" + - name: Run Biome to SARIF if: ${{ inputs.biome }} run: | @@ -881,6 +855,7 @@ jobs: BIOME_ENABLED: ${{ inputs.biome }} OXLINT_ENABLED: ${{ inputs.oxlint }} AST_GREP_ENABLED: ${{ inputs.ast-grep }} + REGAL_ENABLED: ${{ inputs.regal }} HTMLHINT_ENABLED: ${{ inputs.htmlhint }} STYLELINT_ENABLED: ${{ inputs.stylelint }} YAMLLINT_ENABLED: ${{ inputs.yamllint }} diff --git a/README.md b/README.md index a131ff7..fe72915 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Current staged catalog: | Biome | on | Native SARIF with Sigilix metadata. Default-on Sigilix-controlled correctness linting for JS/TS and JSON; uses runner-owned config, bypasses caller ignore files, and skips common generated-output directories. | | Oxlint | on | Native SARIF with Sigilix metadata. Default-on Sigilix-controlled correctness linting for JavaScript and TypeScript; uses runner-owned config, disables caller Oxlint config and ignore files, skips common generated-output directories, and checks pinned npm package integrity before scanning. | | ast-grep | on | Native SARIF with Sigilix metadata. Default-on Sigilix-owned AST rules for high-confidence JavaScript and TypeScript async array logic bugs; verified npm tarballs are installed without package scripts before scanning. Caller ignore files are bypassed; common generated and vendor directories are still excluded. | +| Regal | on | Native SARIF with Sigilix metadata. Default-on Rego policy linting with runner-owned bug/import rules; style, performance, testing, and migration-preference feedback is disabled. | | HTMLHint | on | Native SARIF with Sigilix metadata for HTML files. Uses runner-owned structural correctness rules, verifies the pinned npm tarball, and skips common generated-output directories. | | Stylelint | on | Converts Stylelint JSON output to SARIF for CSS files. Uses runner-owned correctness rules, verifies the pinned npm tarball, and skips common generated-output directories. | @@ -56,6 +57,7 @@ Current staged catalog: > Set the matching boolean input to `false` in the caller workflow to suppress one of them. > `markdownlint`, `dotenv-linter`, and `checkmake` now default to `true`. Set the matching > boolean input to `false` in the caller workflow to suppress one of them. +> `regal` now defaults to `true`. Set `regal: false` (boolean) in the caller workflow to suppress it. These SIG-107 slices move the runner toward broader third-party tool parity. The Sigilix metadata contract is currently attached to every listed tool. @@ -96,7 +98,7 @@ a moving ref cannot prove which version of the runner ran. Default-on tool booleans: `semgrep`, `eslint`, `ruff`, `actionlint`, `shellcheck`, `yamllint`, `markdownlint`, `dotenv-linter`, `checkmake`, `gitleaks`, `osv-scanner`, `zizmor`, `hadolint`, `biome`, `oxlint`, `ast-grep`, `pylint`, `flake8`, `knip`, `golangci-lint`, `htmlhint`, -`stylelint`, `tflint`, and `tsc`. +`stylelint`, `tflint`, `regal`, and `tsc`. Default-off opt-in tool booleans: `checkov`, `trivy`, and `trufflehog`.