Repository navigation
b1_06_tekton_bundle_tracking_
In the previous chapter, we saw how ec-cli acts like a skilled librarian, finding and fetching container images and related artifacts (Image & OCI Artifact Handling). This is crucial for checking your application's components.
But applications aren't just built from container images; they are often built by automated pipelines. In the Kubernetes world, Tekton is a popular tool for creating these pipelines. Tekton pipelines are made up of Tasks (reusable steps) and Pipelines (sequences of Tasks). These Tasks and Pipelines can be packaged together into Tekton Bundles, which are stored in container registries just like container images!
How do we make sure our build pipelines are using the right, approved, and up-to-date versions of these Tekton Tasks?
Imagine your organization uses a standard Tekton Task for building container images, let's call it quay.io/my-org/build-task:v1. You want to ensure all your CI/CD pipelines use only approved versions of this task. Maybe v1 is okay for now, but you plan to release v2 next month with important security fixes. How do you:
- Keep a record of which versions (
v1,v2) are considered "trusted"? - Know when it's time to encourage teams to update from
v1tov2? - Allow
ec-clipolicies to check if a pipeline run actually used a trusted task version?
This is where Tekton Bundle Tracking comes in. It acts like a subscription manager for your Tekton Tasks and Pipelines.
Think of it this way: You subscribe to a magazine. The publisher keeps a list of active subscribers and knows when your subscription is about to expire, prompting you to renew. Similarly, Tekton Bundle Tracking keeps a list of "trusted" Tekton bundle versions (by their unique digest) and sets an "effective date" to encourage updates.
The core idea is to generate a data file (usually YAML) that lists the specific Tekton bundles (identified by their unique digest, like a fingerprint) that your organization trusts.
Here's the basic flow:
-
You tell
ec-cliwhich bundles to track: You use theec track bundlecommand, pointing it to the Tekton bundles you want to manage (e.g.,quay.io/my-org/build-task:v1). -
ec-clifinds the exact version: Just like with container images (Chapter 5),ec-cliresolves the tag (:v1) to its unique digest (sha256:...). -
ec-cliupdates a tracking file: It adds an entry to a YAML file (let's call ittrusted_tasks.yml). This entry includes:- The bundle's repository and tag/digest.
- The specific digest (
ref) that is trusted. - An
effective_ondate (e.g., 30 days from now). This date signifies when this version becomes the standard, encouraging updates to older versions before this date.
-
Policies use this file: Later, when
ec-clivalidates a pipeline run, policies (Chapter 2) can consult thistrusted_tasks.ymlfile. They check if the specific Tekton Task digest used in the pipeline run is listed in the file and if itseffective_ondate has passed (or is the most recent one).
This process ensures that you have a clear, manageable record of trusted Tekton resources and a mechanism to drive updates.
The main way to interact with this feature is through the ec track bundle command (which also has an alias ec track tekton-task).
Example 1: Tracking a new bundle
Let's say you want to start tracking quay.io/my-org/build-task:v1.
# Tell ec-cli to track this Tekton bundle
ec track bundle --bundle quay.io/my-org/build-task:v1Explanation:
-
ec track bundle: The command to manage Tekton bundle tracking. -
--bundle quay.io/my-org/build-task:v1: Specifies the Tekton bundle image reference to add to the tracking list.
ec-cli will:
- Connect to
quay.io. - Find the digest for the
:v1tag (e.g.,sha256:abc...def). - Calculate an
effective_ondate (e.g., 30 days from today). - Print the tracking data to your console (standard output).
The output might look something like this (simplified):
# Output printed to console
trusted_tasks:
oci://quay.io/my-org/build-task:v1: # The bundle reference being tracked
- effective_on: "2024-09-15T00:00:00Z" # Date when this entry becomes effective
ref: sha256:abcdef1234567890abcdef... # The trusted digest for v1Explanation of Output:
-
trusted_tasks: The main section listing tracked bundles. -
oci://quay.io/my-org/build-task:v1: The key identifying the bundle group (using theoci://prefix). -
- effective_on: The date this specific digest (ref) is considered the standard. Policies might warn about older versions before this date. -
ref: The unique, immutable digest of the bundle version that is trusted.
Example 2: Updating an existing tracking file
Usually, you'll want to save this data to a file and update it over time.
# Create an initial file
ec track bundle --bundle quay.io/my-org/build-task:v1 --output trusted_tasks.yml
# Later, track a new version (v2) and add it to the existing file
ec track bundle --bundle quay.io/my-org/build-task:v2 --input trusted_tasks.yml --output trusted_tasks.ymlExplanation:
-
--output trusted_tasks.yml: Saves the output to a file namedtrusted_tasks.yml. -
--input trusted_tasks.yml: Reads the existing tracking data fromtrusted_tasks.ymlbefore adding new entries.
After adding v2 (let's say its digest is sha256:123...456), the trusted_tasks.yml file might look like this:
# trusted_tasks.yml after adding v2
trusted_tasks:
oci://quay.io/my-org/build-task:v1:
- effective_on: "2024-09-15T00:00:00Z" # v1 effective date
ref: sha256:abcdef1234567890abcdef...
oci://quay.io/my-org/build-task:v2:
- effective_on: "2024-10-15T00:00:00Z" # v2 effective date (e.g., 30 days after adding)
ref: sha256:1234567890abcdef123456...Other Useful Flags:
-
--prune(default:true): Automatically removes older entries that are no longer considered relevant (e.g., if a newer version is already effective). -
--freshen: If you track a bundle using a tag (like:latest), this flag tellsec-clito re-check the registry for the current digest associated with that tag and add a new entry if it has changed. This helps keep track of rolling tags. -
--git git+https://...: You can also track Tekton Task files directly from Git repositories. -
--replace: Updates the--inputfile directly instead of requiring--output. -
--in-effect-days N: Sets the number of days in the future for theeffective_ondate (default is 30).
How does ec track bundle build this list?
sequenceDiagram
participant User
participant EC_CLI as ec track bundle
participant Parser as Argument Parser
participant OCI_Handler as OCI/Git Handler
participant TrackerLogic as Tracker Logic
participant OutputHandler as Output Handler
User->>EC_CLI: Runs `ec track bundle --bundle <ref> [--input file] [--output file]`
EC_CLI->>Parser: Parse flags (--bundle, --input, --output etc.)
Parser-->>EC_CLI: Parsed arguments
Note over EC_CLI: Has list of bundles to track & input/output paths
EC_CLI->>OutputHandler: Read data from --input file (if provided)
OutputHandler-->>EC_CLI: Existing tracking data (or empty)
EC_CLI->>OCI_Handler: For each --bundle <ref>, resolve digest (e.g., sha256:abc...)
Note over OCI_Handler: Uses logic similar to Chapter 5
OCI_Handler-->>EC_CLI: Resolved digest for <ref>
EC_CLI->>TrackerLogic: Add/Update record (bundle ref, digest, effective_on) in tracking data
TrackerLogic->>TrackerLogic: Apply pruning/freshening logic if needed
TrackerLogic-->>EC_CLI: Updated tracking data
EC_CLI->>OutputHandler: Write updated data to --output file (or stdout)
OutputHandler-->>User: Shows output / Saves file
Code Snippets:
-
Command Setup (
cmd/track/track_bundle.go) This file sets up theec track bundlecommand, defines its flags (--bundle,--input,--output,--prune,--freshen, etc.), and calls the core tracking logic.// Simplified view from cmd/track/track_bundle.go func trackBundleCmd(track trackBundleFn /*...*/) *cobra.Command { params := struct { // Structure to hold flag values bundles []string input string prune bool // ... other flags }{ prune: true /* default */ } cmd := &cobra.Command{ Use: "bundle", Short: "Record tracking information about Tekton bundles", RunE: func(cmd *cobra.Command, args []string) (err error) { // ... Read input data from params.input (file or OCI) ... var data []byte if params.input != "" { /* read data */ } // *** Call the core tracking function *** out, err := track(cmd.Context(), params.bundles, data, params.prune, params.freshen, /*...*/) if err != nil { return err } // ... Write output data 'out' based on params.output ... return nil }, } // Define flags using cmd.Flags()... cmd.Flags().StringSliceVarP(¶ms.bundles, "bundle", "b", /*...*/) cmd.Flags().StringVarP(¶ms.input, "input", "i", /*...*/) // ... other flags defined ... return cmd }
Explanation: This sets up the command-line interface. It defines the flags users can provide and then, in
RunE, reads any input, calls the maintrackfunction (passing the flag values), and handles writing the output. -
Core Tracking Logic (
internal/tracker/tracker.go) This is where the main work happens: reading existing data, resolving bundles, adding records, and applying filtering.// Represents one entry in the tracking list for a specific digest type taskRecord struct { Ref string `json:"ref"` // The trusted digest (sha256:...) EffectiveOn time.Time `json:"effective_on"` // When it becomes effective // ... other fields like ExpiresOn ... Tag string `json:"-"` // Transient info, not saved in YAML Repository string `json:"-"` // Transient info } // Holds the entire tracking data, mapping bundle group to records type Tracker struct { TrustedTasks map[string][]taskRecord `json:"trusted_tasks,omitempty"` } // Main function called by the command func Track(ctx context.Context, urls []string, input []byte, prune bool, freshen bool, /*...*/) ([]byte, error) { // Load existing data from 'input' bytes t, err := newTracker(input) if err != nil { return nil, err } // Process image URLs (e.g., quay.io/...) if err := t.trackImageReferences(ctx, imageUrls, freshen, /*...*/); err != nil { // ... handle error ... } // Process git URLs (e.g., git+https://...) if err := t.trackGitReferences(ctx, gitUrls, freshen, /*...*/); err != nil { // ... handle error ... } // Apply filtering/pruning rules t.filterBundles(prune) // Set expiration dates based on effective dates t.setExpiration() // Convert the final Tracker struct back to YAML bytes return t.Output() }
Explanation: The
Trackfunction orchestrates the process. It parses the input YAML into aTrackerstruct. It calls helper functions (trackImageReferences,trackGitReferences) which resolve the bundle URLs to digests (using code similar to Chapter 5) and addtaskRecordentries. It then filters these records (filterBundles) and finally converts the updatedTrackerstruct back into YAML for output. -
Checking Bundle Contents (
internal/tracker/bundle_info.go)ec-clineeds to check if a bundle actually contains a Tekton Task before tracking it.// Simplified concept: Checks if a bundle manifest lists a layer as a "task" func containsTask(ctx context.Context, ref image.ImageReference) (bool, error) { // Get image manifest using OCI client (like in Chapter 5) img, err := /* ... get image from registry ... */ if err != nil { return false, err } manifest, err := img.Manifest() if err != nil { return false, err } // Check annotations on layers in the manifest for _, layer := range manifest.Layers { // Tekton bundles use annotations to mark layer types if kind, ok := layer.Annotations["dev.tekton.image.kind"]; ok { if kind == "task" { // Found a layer marked as a Tekton Task! return true, nil } } } return false, nil // No task layer found }
Explanation: This function examines the bundle's manifest file (metadata stored in the registry). It looks for specific annotations that Tekton uses to identify layers containing Tasks. If it finds one, it confirms the bundle is suitable for tracking.
The trusted_tasks.yml file generated by ec track bundle becomes a crucial piece of data for your policies (Chapter 2). When ec-cli validates a system (like a Kubernetes cluster where pipelines run), Rego policies executed by the Validation Engine (Evaluator) can:
- Identify which Tekton Task (by its digest) was used in a specific pipeline run.
- Load the
trusted_tasks.ymldata. - Check if the digest used in the pipeline run is present in the
trusted_taskslist. - Potentially check the
effective_ondate to enforce updates.
This allows you to create rules like: "Pipeline runs must only use Tekton Task digests that are listed as trusted and currently effective."
You've learned about Tekton Bundle Tracking, ec-cli's feature for managing the trustworthiness and lifecycle of your Tekton Tasks and Pipelines. It acts like a subscription manager, creating a data file (trusted_tasks.yml) that lists approved bundle digests and their effective dates using the ec track bundle command. This helps you ensure your CI/CD pipelines use verified components and encourages timely updates. This generated data file is then used by policies during validation.
We've now covered how ec-cli defines inputs, sources policies, evaluates rules, verifies signatures, handles artifacts, and tracks Tekton bundles. The final piece of the puzzle is understanding how ec-cli presents the results of all these checks back to you.
Let's move on to the final chapter: Output Reporting.
Generated by AI Codebase Knowledge Builder