Webhook icon
WorkingDirectory icon
Clone icon
Commands icon
Docker icon
Script icon
Process icon
If icon
Create icon
SlackIncomingWebhook icon
Fail icon
Log icon

Scan GitHub Repos for Committed Secrets with gitleaks

Scan every push for committed secrets with gitleaks, open a labeled GitHub issue on findings, alert Slack, and fail the run — orchestrated in Kestra.

Categories
Infrastructureinfrastructure

Secrets committed to git rarely stay secret: keys end up in issue threads, forks, and clone histories even after the file is deleted. This blueprint makes scanning automatic. A webhook fires on push, the repository is checked out into a shared working directory, gitleaks runs inside its official container with --redact so detected values never reach the logs, and a small Python step turns the JSON report into a leak count and the distinct rules that fired. Findings escalate three ways at once — a labeled GitHub issue, a Slack alert, and a failed execution — while a clean scan quietly records itself as proof the check ran.

How it works

  1. The on_push trigger (io.kestra.plugin.core.trigger.Webhook) exposes a keyed URL for your GitHub push hook or CI to POST to.
  2. workspace (io.kestra.plugin.core.flow.WorkingDirectory) opens one shared filesystem for everything that follows, so the scanner sees the clone and the parser sees the report.
  3. clone_repository (io.kestra.plugin.git.Clone) checks out {{ inputs.repository }} at {{ inputs.branch }}, authenticating with GITHUB_TOKEN.
  4. run_secret_scan (io.kestra.plugin.scripts.shell.Commands on the io.kestra.plugin.scripts.runner.docker.Docker runner, image zricethezav/gitleaks:latest) executes gitleaks detect --redact --report-format json --report-path gitleaks-report.json --exit-code 0: findings land in a redacted JSON file and the task stays green so evaluation happens in the next step.
  5. parse_report (io.kestra.plugin.scripts.python.Script on the Process runner) reads the report, and emits leak_count, rules, and rules_summary through Kestra's outputs protocol.
  6. check_findings (io.kestra.plugin.core.flow.If) branches on leak_count. Over zero, create_issue (io.kestra.plugin.github.issues.Create) opens an issue labeled security and secrets with the rule list, alert_slack posts the count and rules, and fail_the_run (io.kestra.plugin.core.execution.Fail) turns the execution red. At zero, log_clean records the all-clear.
  7. The errors block alerts Slack when the scan itself fails, because a broken scanner looks exactly like a clean repository.

What you get

  • Committed secrets found on every push instead of during the next incident.
  • Findings escalated where engineers already work: a labeled GitHub issue plus a Slack ping.
  • Redacted logs — gitleaks never prints the discovered values, only rule IDs and file paths.
  • A scan trail: every execution (clean or not) is a dated record in Kestra's history, with leak_count and rules as outputs.
  • A failed run on findings, so branch protections and downstream automations can enforce it.

Who it's for

  • Development teams that want secret scanning without standing up a SaaS scanner.
  • Security engineers enforcing "no credentials in git" as a checked, alertable gate.
  • Platform teams already running Kestra who want CI-grade checks in their orchestrator.

Why orchestrate this with Kestra

gitleaks is an excellent scanner, but a scanner nobody runs catches nothing. Kestra supplies the loop around it: an event trigger for the scan, a hermetic Docker runner so the tool version lives in the flow, a branch that separates escalation from the all-clear, retries and execution history for every run, and alert routing into GitHub and Slack from one declarative file. A git hook running gitleaks locally gives developers none of that — it only protects the machines of people who remember to install it.

Prerequisites

  • A worker with Docker access (the scan runs in the gitleaks container) and Python 3 on the host for the report parser, or switch parse_report to a Docker task runner.
  • A GitHub repository that allows issue creation with the provided token (classic PAT scope repo, or fine-grained Issues: write plus Contents: read).
  • A Slack incoming webhook for escalation and failure alerts.

Secrets

  • GITHUB_TOKEN: personal access token used both to clone the repository and to open the issue on findings.
  • SECRET_SCAN_WEBHOOK_KEY: key segment guarding the webhook URL — anyone with it can trigger a scan, so treat it as a secret.
  • SLACK_WEBHOOK_URL: Slack incoming webhook URL.

Quick start

  1. Add the three secrets to your Kestra namespace.
  2. Set repository to the owner/repo you want scanned and branch if it is not main.
  3. Point your GitHub webhook (push events) at /api/v1/{tenant}/executions/webhook/{namespace}/github-secret-scan-gitleaks-on-push/{SECRET_SCAN_WEBHOOK_KEY}, or trigger the webhook manually.
  4. Confirm a clean run, then push a test commit containing a fake key (for example a dummy AKIA string) and confirm the issue, the Slack alert, and the failed execution.

How to extend

  • Scan many repositories by overriding the repository input per call, or fan out with a Loop over a repository list.
  • Derive the repository and branch from the push payload instead of inputs with {{ fromJson(trigger.body).repository.full_name }} and {{ trigger.ref }} for multi-repo setups.
  • Replace create_issue with a pull-request comment or a security ticket in Jira/Linear.
  • Add gitleaks dir --no-git variants for repositories shipped as artifacts, or schedule the scan nightly with a Schedule trigger as defense in depth.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.