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$''']