New to Kestra?
Use blueprints to kickstart your first workflows.
Export CycloneDX SBOMs from Aikido, compare against a stored baseline in Kestra KV, and fail the release only on newly introduced blocked licences.
Licence scanning usually fails for a boring reason: turn it on, get four hundred violations that predate everyone in the room, and switch it off again. This blueprint makes the check adoptable by comparing against a baseline instead of against zero. It exports the CycloneDX SBOM from Aikido, diffs the component set against the last approved release, and blocks only when a newly introduced dependency carries a blocked licence. Pre-existing violations are still reported, so the debt stays visible, but they do not stop today's release. The baseline advances only on a clean run, which means a blocked release can never quietly become the new normal.
export_sbom task (io.kestra.plugin.aikido.repositories.ExportSbom) pulls the CycloneDX SBOM with scope: EXCLUDE_DEV_DEPS, so the gate reflects what ships rather than what the test suite pulls in. includeVex: true carries exploitability context alongside the components.supply_chain_issues task (io.kestra.plugin.aikido.issues.Export) pulls the open findings Aikido already raised for the same repository, including malware and licence issues, so the gate has scanner context and not just licence strings.read_baseline task (io.kestra.plugin.core.kv.Get) loads the previously approved component set with errorOnMissing: false, so the very first run treats everything as pre-existing instead of blocking the world.assess task (io.kestra.plugin.scripts.python.Script) does the diff in plain Python with no third-party dependencies. It splits findings into new_violations and pre_existing_violations and writes a verdict.json output file.gate task (io.kestra.plugin.core.flow.If) branches on that verdict. The blocking path posts a structured Slack notice and then calls io.kestra.plugin.core.execution.Fail, so a release pipeline waiting on this execution stops too.io.kestra.plugin.core.kv.Set and logs how much debt was carried forward.blocked, new_violations) that a parent release flow can branch on.The hard part of a licence gate is not parsing an SBOM, it is the state. You need last release's component set, a decision about what counts as new, a place to keep that memory, and a way to stop the pipeline without leaving the baseline corrupted. Kestra supplies the durable KV store for the baseline, the branch that only advances it on success, typed flow outputs a parent pipeline can read, and an execution record showing exactly which components entered the artifact on which release. In a CI script this becomes a cache file nobody trusts and a gate everyone bypasses.
repositories:read and issues:read scopes.io.kestra.plugin.aikido.repositories.List.taskRunner to the process runner if Python is installed on the host.AIKIDO_CLIENT_ID, AIKIDO_CLIENT_SECRET: OAuth2 credentials for the Aikido public API.SLACK_WEBHOOK: incoming webhook used for block notices and gate failures.io.kestra.plugin.aikido.repositories.List once to find the numeric id of the repository you want to gate.blocked_licenses to your own policy. The shipped list covers the common copyleft and source-available cases.release_tag, and branch on the blocked output.io.kestra.plugin.aikido.repositories.List and then a Subflow per repository.Pause task on the blocking branch so a licence exception can be granted in-flow and recorded against a named approver.io.kestra.plugin.jira.issues.Create and store the component name in the summary.format to SBOM_SPDX when your downstream tooling expects SPDX rather than CycloneDX.io.kestra.plugin.aws.s3.Upload so you can reconstruct the exact dependency set of any past release.