feat(runners): implement Tekton Pipeline runner with native metadata discovery#2767
feat(runners): implement Tekton Pipeline runner with native metadata discovery#2767waveywaves wants to merge 1 commit intochainloop-dev:mainfrom
Conversation
cbcf765 to
229b0c9
Compare
|
@cubic-dev-ai review |
@migmartri I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
1 issue found across 3 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="pkg/attestation/crafter/runners/tektonpipeline_test.go">
<violation number="1" location="pkg/attestation/crafter/runners/tektonpipeline_test.go:111">
P3: Unused `tmpDir` in test: `t.TempDir()` is called and immediately suppressed with `_ = tmpDir`. The test only exercises `taskRunNameFromHostname()` via a struct literal — no temp directory is needed. Remove both lines to avoid unnecessary filesystem allocations.</violation>
</file>
Since this is your first cubic review, here's how it works:
- cubic automatically reviews your code and comments on bugs and improvements
- Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
- Add one-off context when rerunning by tagging
@cubic-dev-aiwith guidance or docs links (includingllms.txt) - Ask questions if you need clarification on any suggestion
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
Thanks @waveywaves for the PR! Could you please provide an example of a completed chainloop attestation that has been processed on Tekton? |
javirln
left a comment
There was a problem hiding this comment.
That's basically why I would to see this: #2767 (comment) 👀
| // All metadata is discovered from K8s API labels and filesystem. | ||
| // Return HOSTNAME as the only env var we consume (for traceability in attestation). | ||
| return []*EnvVarDefinition{ | ||
| {"HOSTNAME", true}, |
There was a problem hiding this comment.
Although the environment variables could not be auto resolved automatically, I think it would be good to have TEKTON_TASKRUN_NAME, TEKTON_PIPELINE_NAME, TEKTON_PIPELINERUN_NAME, TEKTON_TASK_NAME, TEKTON_PIPELINE_TASK_NAME, and TEKTON_NAMESPACE as we do with the rest of the runners.
In the Dagger client for example, we "promote" the underlying environment variables because of the encapsulation of Dagger
There was a problem hiding this comment.
I have added support for promoting env vars like it's done for dagger and have 2 required and 5 optional env vars as inline tasks and pipeline names might not necessarily be present.
There was a problem hiding this comment.
3 issues found across 4 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="test/e2e/tekton-runner/main.go">
<violation number="1" location="test/e2e/tekton-runner/main.go:137">
P2: The `Environment` check always reports PASS regardless of the returned value. Unlike every other check in this e2e test, there's no conditional validation — if `r.Environment()` returns `Unknown` (e.g., due to a detection bug), the test silently passes. Add validation for the expected environment value.</violation>
</file>
<file name="pkg/attestation/crafter/runners/tektonpipeline.go">
<violation number="1" location="pkg/attestation/crafter/runners/tektonpipeline.go:63">
P2: Storing `context.Context` in a struct is a Go anti-pattern, and here `r.ctx` is only used during construction (in `discoverLabelsFromKubeAPI`, called from `NewTektonPipeline`). After the constructor returns, the field is never read again — it's dead state. Pass `ctx` as a parameter to `discoverLabelsFromKubeAPI(ctx)` and remove the struct field.
(Based on your team's feedback about removing unused code, methods, and variables.) [FEEDBACK_USED]</violation>
<violation number="2" location="pkg/attestation/crafter/runners/tektonpipeline.go:247">
P1: `TEKTON_TASKRUN_NAME` is marked as required, but its value comes exclusively from Tier 2 K8s API discovery (`r.labels["tekton.dev/taskRun"]`). If the K8s API call fails (RBAC denied, missing SA token), this label will be empty and `ResolveEnvVars` will return an error — blocking attestation. This contradicts the PR's "graceful degradation" design goal. Consider either making it optional (with `optionalVar`) or falling back to the `taskRunNameFromHostname()` derivation that `RunURI` already uses.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
@waveywaves could you make sure you
|
javirln
left a comment
There was a problem hiding this comment.
I'm sorry to block the PR but I have high concerns about the blockade of the attestation when one environment variable couldn't be resolved due to RBAC restrictions.
Also please, could you please share a result of a Chainloop attestation, I would like to see the populated runner environment variables.
Thanks!
| optionalVar("HOSTNAME", os.Getenv("HOSTNAME")) | ||
|
|
||
| // Required: always available in any TaskRun (needs RBAC for pod get) | ||
| requireVar("TEKTON_TASKRUN_NAME", r.labels["tekton.dev/taskRun"]) |
There was a problem hiding this comment.
Please pay attention to what https://github.com/chainloop-dev/chainloop/pull/2767/changes#r2864820538 is saying. If we get blocked by RBAC the attestation will be blocked.
The taskRunNameFromHostname() method already exists as a fallback and is used in RunURI(). The fix is to also use it here:
taskRunName := r.labels["tekton.dev/taskRun"]
if taskRunName == "" {
taskRunName = r.taskRunNameFromHostname()
}
requireVar("TEKTON_TASKRUN_NAME", taskRunName)
There was a problem hiding this comment.
I have added a fallback as you have mentioned.
| } | ||
|
|
||
| r := &TektonPipeline{ | ||
| ctx: ctx, |
There was a problem hiding this comment.
Why do we need the context as part of the struct?
There was a problem hiding this comment.
Updated to pass the context from the top.
|
@javirln I appreciate the collaboration to make the best of this feature and to ship it in a way that works well. Thanks for reviewing. Please don't apologize for reviewing the PR. Shall reply soon. |
2c6dec3 to
a2d6a8b
Compare
|
Here is a completed Chainloop attestation processed on a real Tekton Pipeline running on a kind cluster. Runner detection and initialization: Pushing signed attestation: Verification results (9/9 pass): The runner auto-discovers all metadata from the K8s API pod labels and ServiceAccount namespace file, zero env var wiring needed in the Pipeline YAML. Full asciinema recording of the E2E flow: https://asciinema.org/a/795546 |
|
Done, the commit is now squashed and signed off. |
migmartri
left a comment
There was a problem hiding this comment.
Very nice! Thanks for posting the tests
once we merge it we'll update the docs, feel free to suggest any changes we should add in that section :)
Thanks!
https://docs.chainloop.dev/concepts/contracts#tekton_pipeline
a2d6a8b to
5389af4
Compare
|
Thanks @migmartri! Here are the suggested updates for the Tekton runner docs: The TEKTON_PIPELINE runner now auto-discovers all metadata natively. The docs section should be updated to reflect: Runner context variables (auto-captured):
Key points:
The "work in progress" note can be removed — all runner context is now automatically gathered. |
Add documentation for the Tekton Pipeline runner context variables that are auto-discovered natively from K8s API pod labels and ServiceAccount namespace file. Ref: chainloop-dev/chainloop#2767 Signed-off-by: Vibhav Bobade <vibhav.bobde@gmail.com> Co-Authored-By: Claude <noreply@anthropic.com>
|
@migmartri Thanks! I noticed the docs repo (chainloop-dev/docs) is archived so I couldn't open a PR there. I've posted the suggested runner context variable table above — happy to open a docs PR wherever the docs live now if you point me to the right place. |
Yeah it's private, I have a PR ready to be merged with the update
|
|
@migmartri CI is green now |
I still see the commit signature issue |
|
@javirln All feedback has been addressed — context refactored to function param, env var promotion with required/optional split, RBAC fallback added, and attestation example posted above. Could you re-review when you get a chance? CI is all green. |
…discovery Add a new TektonPipeline runner that discovers Tekton metadata natively using a two-tier approach: - Tier 1: HOSTNAME env var and ServiceAccount namespace file (always available) - Tier 2: K8s API pod labels for rich tekton.dev/* metadata (best-effort) The runner promotes 7 env vars (2 required, 5 optional) following the Dagger runner pattern. TEKTON_TASK_NAME is optional since inline taskSpec pipelines lack the tekton.dev/task label. TEKTON_TASKRUN_NAME falls back to hostname derivation when K8s API labels are unavailable. context.Context is passed as a function parameter to discoverLabelsFromKubeAPI() rather than stored in the struct, following Go best practices. Includes comprehensive unit tests, e2e test binary with Environment validation, and tekton:// URI scheme for RunURI. Signed-off-by: Vibhav Bobade <vibhav.bobde@gmail.com> Co-Authored-By: Claude <noreply@anthropic.com>
5389af4 to
2f00e03
Compare
|
@migmartri I did not sign correctly earlier looks like, it should be good now. |
|
cc @migmartri CI is properly green now :D |



Summary
TektonPipelinerunner with two-tier native metadata discovery: Tier 1 reads HOSTNAME env var and ServiceAccount namespace file (always available in K8s pods); Tier 2 makes a best-effort K8s API call to discovertekton.dev/*pod labels for rich pipeline contextSupportedRunnerinterface methods:RunURI(Tekton Dashboard URL withtekton-pipeline://fallback),Report(writes to/tekton/results/attestation-reportwith 3500-byte truncation),Environment(detects GKE/EKS/AKS as Managed vs self-hosted),ListEnvVars, andResolveEnvVars(synthesizes discovered metadata as key-value entries)runner.goto pass logger toNewTektonPipelineDesign decisions
$(context.*)variables as env varsWithHTTPClient,WithSATokenPath,WithNamespacePath,WithCACertPath,WithResultsDirallow test injection without polluting the production APITesting