WorkingDirectory icon
Clone icon
Commands icon
Process icon
Docker icon
If icon
Fail icon
Log icon
Switch icon
Return icon
Pause icon
Create icon
Create icon
Webhook icon

Kestra 2.0 Migration Readiness Gate with Approved, Idempotent GitHub Remediation

Check Kestra flows in a GitHub repo for 2.0 readiness with kestra-migrate, then open a verified, approved, duplicate-free migration pull request.

Categories
Infrastructure

Find out whether the Kestra flows in a GitHub repository are ready for Kestra 2.0 and, when the migration can be automated, let a human approve a safe, verified rewrite that is delivered as a pull request.

Kestra 2.0 removes or changes several 1.x constructs. kestra-migrate reports what has to change and can rewrite many flows automatically, but running a rewriting tool on a repository and pushing the result is a risky, manual operation. This blueprint turns it into a gated workflow: read-only scan → classification → human approval → remediation in a fresh clone → verified patch → idempotent GitHub delivery.

How it works

  1. Scan (read-only). clone_a (io.kestra.plugin.git.Clone) checks out the exact commit. verify_a confirms the checkout is that commit, refuses repositories containing symbolic links, and keeps flows_path inside the clone. install_a downloads kestra-migrate 2.6.1 and verifies its SHA-256. scan runs kestra-migrate --check --summary and parses the output with a strict parser: any unexpected line, a missing summary, or totals that do not reconcile make the result TOOL_ERROR instead of a guess.

  2. Classify. The policy Switch routes on the result:

    Classification Meaning What the gate does
    CLEAN every flow is already 2.0-compatible reports NO_REMEDIATION_REQUIRED
    AUTO_MIGRATABLE kestra-migrate can rewrite every flow that needs it asks for approval
    ADVISORY flows deploy on 2.0 but can break at run time reports NOT_ELIGIBLE; a human must fix them
    BLOCKING Kestra 2.0 rejects at least one flow reports NOT_ELIGIBLE; a human must fix them
    TOOL_ERROR the scan output cannot be trusted fails the execution
  3. Approve. For AUTO_MIGRATABLE only, show_proposal logs the repository, commit, path, counts, warnings, the files that would be rewritten and the full proposed diff, then approve (io.kestra.plugin.core.flow.Pause) waits for a decision. decision defaults to REJECT; an unanswered request is cancelled after one day.

  4. Remediate. On APPROVE, remediation_workdir clones the same commit again (the scanned checkout is never modified), re-runs the scan and requires the exact approved result, then runs kestra-migrate -o. remediate rejects the result if any file outside the expected set changed, if files were added, deleted, re-moded or turned into symbolic links, if anything outside flows_path changed, or if a post-migration scan is not CLEAN. The binary patch is re-applied to a pristine copy of the source commit and must reproduce the same tree.

  5. Deliver. delivery_plan derives a remediation key (SHA-256 of repository, commit, path and migrator version), rebuilds the patch as a deterministic commit, and decides CREATE or REUSE for the branch kestra-migration/v2.6.1-<commit12>-<key12>, the issue and the pull request, which carry the hidden marker <!-- kestra-remediation-key: <key> -->. push_branch performs a create-only push. issue_create (io.kestra.plugin.github.issues.Create) and pr_create (io.kestra.plugin.github.pulls.Create) run only when nothing exists yet. A foreign branch or pull request with the same name or key stops the delivery instead of being overwritten.

  6. Verify. delivery_verify reads GitHub back and requires exactly one branch, one issue and one pull request for the key, the branch to be one commit on top of the source commit with exactly the validated files, the pull request to target the default branch, and no credential in anything delivered.

Safety properties

  • Pinned tooling: kestra-migrate 2.6.1 is checksum-verified for amd64 and arm64, the runner image is pinned by digest, and the embedded parser and helper scripts are hash-checked before they run. None of these are inputs.
  • Exact source: only public https://github.com/<owner>/<repo> URLs and full 40-character commit SHAs are accepted; each clone is checked against the requested commit.
  • Untrusted repository: submodules are never cloned, repository git hooks and config are ignored, repositories containing symbolic links are refused, and flows_path is checked against the real path of the clone.
  • Human gate: nothing is written anywhere without an explicit APPROVE.
  • Idempotent delivery: re-running for the same repository, commit and path reuses the existing branch, issue and pull request; it never opens duplicates.
  • Credential hygiene: the token is passed only through environment variables and a temporary askpass helper, and is never put in URLs, arguments, git config, logs or the issue and pull request bodies.

Prerequisites

  • Kestra with the Docker task runner available (the Kestra worker needs access to a Docker daemon), and outbound access to github.com and api.github.com.
  • Plugins: plugin-git, plugin-github and plugin-scripts (included in the default Kestra image).
  • For delivery only: a GitHub fine-grained personal access token for the target repository with Contents: read and write, Issues: read and write and Pull requests: read and write. Scanning public repositories needs no token.

Secrets

  • GITHUB_TOKEN: GitHub token used, after approval only, to push the remediation branch, open the issue and the pull request, and read them back. Not used for CLEAN, ADVISORY, BLOCKING or rejected runs.
  • MIGRATION_GATE_WEBHOOK_KEY: random key that forms the webhook URL. Required only if you use the webhook trigger.

Inputs

Name Type Default Description
repo_url STRING https://github.com/kestra-io/kestra2-flow-migration Public GitHub repository, https://github.com/<owner>/<repo>. No other host, scheme, port, credentials, query or fragment.
commit STRING 41e0fe57268711013841f633bd189cb04d83b198 Full 40-character lowercase commit SHA. Branch names and HEAD are rejected.
flows_path STRING input-flows/additional-test-cases/ion-read.yaml Folder or flow file inside the repository, or . for the whole repository. No absolute paths, .. or leading -.

The defaults scan one example flow of the kestra-migrate repository at a pinned commit. It has a Kestra 2.0 advisory finding (an ION output that becomes binary), so a default run reports ADVISORY / NOT_ELIGIBLE and ends: it never pauses for approval, never uses GITHUB_TOKEN and never writes to GitHub. To remediate, run the flow with your own repository, commit and flows path.

Quick start

  1. Add the GITHUB_TOKEN secret (and MIGRATION_GATE_WEBHOOK_KEY if you use the webhook).
  2. Run the flow with your repository, the commit to check and the folder holding your flows.
  3. Read the readiness and flow_counts outputs. If the result is AUTO_MIGRATABLE, review the proposal in the logs and resume the paused execution with decision: APPROVE and your name, or leave it on REJECT.
  4. After approval, open the pull request linked in the result output.

To check every push automatically, call the webhook from CI, for example from a GitHub Actions step:

curl -fsS -X POST -H 'Content-Type: application/json' \
  -d "{\"repo_url\": \"https://github.com/${GITHUB_REPOSITORY}\", \"commit\": \"${GITHUB_SHA}\", \"flows_path\": \"flows\"}" \
  "https://<your-kestra-host>/api/v1/<tenant>/executions/webhook/company.team/kestra-2-migration-readiness-gate/${MIGRATION_GATE_WEBHOOK_KEY}"

The webhook values go through the same input validators as a manual run: an invalid request is answered with HTTP 422 and no execution is created. flows_path defaults to . when omitted.

Outputs

  • readiness: CLEAN, AUTO_MIGRATABLE, ADVISORY, BLOCKING or TOOL_ERROR.
  • flow_counts: number of flows per classification, plus the total.
  • result: NO_REMEDIATION_REQUIRED, NOT_ELIGIBLE, REJECTED or REMEDIATION_DELIVERED. A delivered result includes the branch and head commit, the issue and pull request numbers and URLs, the patch SHA-256, the changed files, and whether the branch, issue and pull request were created or reused.
  • {{ outputs.scan.outputFiles['scan-report.txt'] }}: the full kestra-migrate report; {{ outputs.remediate.outputFiles['remediation.patch'] }}: the approved patch.

Notes

  • Kestra OSS does not record who resumed a paused execution, so the reviewer name entered at approval is self-declared; the issue and pull request say so.
  • A closed issue or pull request for the same remediation key is reused, not reopened.
  • Pushing the branch, opening the issue and opening the pull request are separate GitHub calls. If one fails, run the flow again: the parts already created are reused.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.