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/.github/workflows/slack-pr-notifications.yml b/.github/workflows/slack-pr-notifications.yml
new file mode 100644
index 0000000..8015e74
--- /dev/null
+++ b/.github/workflows/slack-pr-notifications.yml
@@ -0,0 +1,63 @@
+name: Slack PR Notifications
+
+on:
+ pull_request:
+ types: [opened, closed, reopened]
+ branches: ["main"]
+ pull_request_review:
+ types: [submitted]
+
+jobs:
+ notify:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Set notification details
+ id: details
+ run: |
+ if [[ "${{ github.event_name }}" == "pull_request_review" ]]; then
+ STATE="${{ github.event.review.state }}"
+ TITLE="PR Review: ${STATE} - ${{ github.event.pull_request.title }}"
+ COLOR=$([[ "$STATE" == "approved" ]] && echo "good" || echo "warning")
+ BODY="${{ github.event.review.user.login }} ${STATE} the PR"
+ else
+ ACTION="${{ github.event.action }}"
+ TITLE="PR ${ACTION^}: ${{ github.event.pull_request.title }}"
+ if [[ "$ACTION" == "closed" && "${{ github.event.pull_request.merged }}" == "true" ]]; then
+ TITLE="PR Merged: ${{ github.event.pull_request.title }}"
+ COLOR="good"
+ elif [[ "$ACTION" == "opened" ]]; then
+ COLOR="#1a73e8"
+ elif [[ "$ACTION" == "reopened" ]]; then
+ COLOR="warning"
+ else
+ COLOR="danger"
+ fi
+ BODY="${{ github.event.pull_request.user.login }} ${ACTION} the PR"
+ fi
+
+ echo "title=${TITLE}" >> $GITHUB_OUTPUT
+ echo "color=${COLOR}" >> $GITHUB_OUTPUT
+ echo "body=${BODY}" >> $GITHUB_OUTPUT
+
+ - name: Send Slack notification
+ uses: slackapi/slack-github-action@v2.1.0
+ with:
+ webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
+ webhook-type: incoming-webhook
+ payload: |
+ {
+ "attachments": [
+ {
+ "color": "${{ steps.details.outputs.color }}",
+ "blocks": [
+ {
+ "type": "section",
+ "text": {
+ "type": "mrkdwn",
+ "text": "*${{ steps.details.outputs.title }}*\n${{ steps.details.outputs.body }}\n*Repo:* `${{ github.repository }}`\n*Branch:* `${{ github.event.pull_request.head.ref }}` -> `${{ github.event.pull_request.base.ref }}`\n<${{ github.event.pull_request.html_url }}|View Pull Request>"
+ }
+ }
+ ]
+ }
+ ]
+ }
diff --git a/.gitleaks.toml b/.gitleaks.toml
new file mode 100644
index 0000000..972b0b5
--- /dev/null
+++ b/.gitleaks.toml
@@ -0,0 +1,70 @@
+# 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$''',
+ '''README\.md$''',
+]
+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*#.*''',
+ # 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
+[[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''', '''.*''', '''[>|][+-]?\s*$''']
+paths = ['''defaults/main\.yml$''', '''inventory\.yml$''', '''README\.md$''', '''tasks/main\.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$''', '''README\.md$''']