From a0921de0ea43a08a210a26a9061a5c9ed78283f5 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Mon, 6 Apr 2026 13:38:49 -0400 Subject: [PATCH 1/2] feat: add Gitleaks configuration and CI workflow Adds .gitleaks.toml with custom rules for Ansible-specific credential patterns (OpenShift API keys, Automation Hub tokens, container registry passwords) and allowlists for placeholder values and Jinja2 templates. Adds a GitHub Actions workflow to run Gitleaks on pushes and PRs. Resolves: MFG-376 Co-Authored-By: Claude Opus 4.6 --- .github/workflows/gitleaks.yml | 37 +++++++++++++++++++ .gitleaks.toml | 65 ++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 .github/workflows/gitleaks.yml create mode 100644 .gitleaks.toml diff --git a/.github/workflows/gitleaks.yml b/.github/workflows/gitleaks.yml new file mode 100644 index 0000000..d41d323 --- /dev/null +++ b/.github/workflows/gitleaks.yml @@ -0,0 +1,37 @@ +--- +name: Gitleaks + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + pull_request_target: + types: [opened, synchronize, reopened] + branches: ["main"] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + gitleaks: + runs-on: ubuntu-latest + if: | + (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || + (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository) || + (github.event_name != 'pull_request' && github.event_name != 'pull_request_target') + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + fetch-depth: 0 + + - name: Run Gitleaks + uses: gitleaks/gitleaks-action@v2 + with: + args: --config .gitleaks.toml + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000..bdf4b78 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,65 @@ +# Gitleaks configuration for openshift_virtualization_migration +# https://github.com/gitleaks/gitleaks + +title = "OpenShift Virtualization Migration Gitleaks Configuration" + +[extend] +useDefault = true + +# Allowlist paths and patterns that contain placeholder credentials +# (e.g., "changeme", example domains, template variables) +[allowlist] +description = "Global allowlist for placeholder values and template files" +paths = [ + '''\.gitleaks\.toml$''', +] +regexTarget = "line" +regexes = [ + # Placeholder values used in inventory and defaults + '''changeme''', + # Jinja2 template variables + '''\{\{.*\}\}''', + # Ansible Vault references + '''!vault''', + # Example/documentation values + '''example\.com''', + '''EXAMPLE''', + # YAML comments containing credential variable names + '''^\s*#.*''', +] + +# Custom rules for Ansible-specific credential patterns +[[rules]] +id = "ansible-vault-password-file" +description = "Ansible vault password file" +regex = '''vault[_-]?pass(word)?[_-]?file\s*[:=]\s*['"]?([^\s'"]+)''' +keywords = ["vault"] +[rules.allowlist] +regexes = ['''changeme''', '''\{\{.*\}\}'''] + +[[rules]] +id = "openshift-api-key" +description = "OpenShift API key or token" +regex = '''(?i)(openshift[_-]?(?:api[_-]?key|token|password))\s*[:=]\s*['"]?([^\s'"#}{]+)''' +keywords = ["openshift"] +[rules.allowlist] +regexes = ['''changeme''', '''\{\{.*\}\}''', '''example'''] +paths = ['''defaults/main\.yml$''', '''inventory\.yml$'''] + +[[rules]] +id = "automation-hub-token" +description = "Automation Hub token" +regex = '''(?i)(automation[_-]?hub[_-]?(?:token|password))\s*[:=]\s*['"]?([^\s'"#}{]+)''' +keywords = ["automation_hub", "automation-hub"] +[rules.allowlist] +regexes = ['''changeme''', '''\{\{.*\}\}'''] +paths = ['''defaults/main\.yml$''', '''inventory\.yml$'''] + +[[rules]] +id = "container-registry-password" +description = "Container registry password" +regex = '''(?i)(container[_-]?password|registry[_-]?password)\s*[:=]\s*['"]?([^\s'"#}{]+)''' +keywords = ["container_password", "registry_password"] +[rules.allowlist] +regexes = ['''changeme''', '''\{\{.*\}\}'''] +paths = ['''defaults/main\.yml$''', '''inventory\.yml$'''] From deaa285983810be493bb7a5528d8a631fe083f13 Mon Sep 17 00:00:00 2001 From: sfulmer Date: Tue, 14 Apr 2026 10:06:21 -0400 Subject: [PATCH 2/2] fix: resolve 11 gitleaks false positives on README and YAML files Add allowlists for docsible-generated README.md variable documentation (HTML bold tags), multi-line YAML block scalars (>- / |) where values are Jinja2 templates on the following line, and task files that reference credential variable names without containing actual secrets. Co-Authored-By: Claude Opus 4.6 --- .gitleaks.toml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.gitleaks.toml b/.gitleaks.toml index bdf4b78..972b0b5 100644 --- a/.gitleaks.toml +++ b/.gitleaks.toml @@ -12,6 +12,7 @@ useDefault = true description = "Global allowlist for placeholder values and template files" paths = [ '''\.gitleaks\.toml$''', + '''README\.md$''', ] regexTarget = "line" regexes = [ @@ -26,6 +27,10 @@ regexes = [ '''EXAMPLE''', # YAML comments containing credential variable names '''^\s*#.*''', + # HTML bold tags documenting variable names (docsible-generated) + '''.*''', + # Multi-line YAML block scalars where value is a Jinja2 template on the next line + '''[>|][+-]?\s*$''', ] # Custom rules for Ansible-specific credential patterns @@ -43,8 +48,8 @@ description = "OpenShift API key or token" regex = '''(?i)(openshift[_-]?(?:api[_-]?key|token|password))\s*[:=]\s*['"]?([^\s'"#}{]+)''' keywords = ["openshift"] [rules.allowlist] -regexes = ['''changeme''', '''\{\{.*\}\}''', '''example'''] -paths = ['''defaults/main\.yml$''', '''inventory\.yml$'''] +regexes = ['''changeme''', '''\{\{.*\}\}''', '''example''', '''.*''', '''[>|][+-]?\s*$'''] +paths = ['''defaults/main\.yml$''', '''inventory\.yml$''', '''README\.md$''', '''tasks/main\.yml$'''] [[rules]] id = "automation-hub-token" @@ -61,5 +66,5 @@ description = "Container registry password" regex = '''(?i)(container[_-]?password|registry[_-]?password)\s*[:=]\s*['"]?([^\s'"#}{]+)''' keywords = ["container_password", "registry_password"] [rules.allowlist] -regexes = ['''changeme''', '''\{\{.*\}\}'''] -paths = ['''defaults/main\.yml$''', '''inventory\.yml$'''] +regexes = ['''changeme''', '''\{\{.*\}\}''', '''.*'''] +paths = ['''defaults/main\.yml$''', '''inventory\.yml$''', '''README\.md$''']