Skip to content

Enable pipeline steps to inject environment into the parent pipeline#1827

Open
maxgio92 wants to merge 5 commits intochainguard-dev:mainfrom
maxgio92:feat/pipelines-environment-inject
Open

Enable pipeline steps to inject environment into the parent pipeline#1827
maxgio92 wants to merge 5 commits intochainguard-dev:mainfrom
maxgio92:feat/pipelines-environment-inject

Conversation

@maxgio92
Copy link
Copy Markdown
Member

@maxgio92 maxgio92 commented Feb 28, 2025

This commit enable pipelines to inject environment variables the same way they're able to inject package dependencies into the build or test configuration. This will allow to remove responsibility of satisfying environment dependencies from the consumer. When setting needs.environment all the other pipeline runs in the same build or config will inherit that additional environment.

Cases like go/covdata pipeline will benefit from this feature being able to inject the GOCOVERDIR environment variable that the go runtime will use to generate coverage data during the whole test runtime, and the go tool covdata to generate reports from.

Melange Pull Request Template

Fixes #1823

Functional Changes

  • This change can build all of Wolfi without errors (describe results in notes)

Notes:

SCA Changes

  • Examining several representative APKs show no regression / the desired effect (details in notes)

Notes:

Linter

  • The new check is clean across Wolfi
  • The new check is opt-in or a warning

Notes:

@maxgio92 maxgio92 force-pushed the feat/pipelines-environment-inject branch 3 times, most recently from cfc5b2f to d819b25 Compare February 28, 2025 19:18
Comment thread pkg/config/config.go
// A list of packages needed by this pipeline
Packages []string
// A list of environment variables to inject to the build or test config.
Environment map[string]string
Copy link
Copy Markdown
Member Author

@maxgio92 maxgio92 Feb 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really convinced by this API as needs.environment can be confusing considering that environment exists as well.

Specifically, the former applies to the whole config hence built/test time, while the latter to just the specific pipeline.

@maxgio92
Copy link
Copy Markdown
Member Author

maxgio92 commented Feb 28, 2025

An example of use case would be the following:

diff --git a/pkg/build/pipelines/go/covdata.yaml b/pkg/build/pipelines/go/covdata.yaml
index b90b539..737856e 100644
--- a/pkg/build/pipelines/go/covdata.yaml
+++ b/pkg/build/pipelines/go/covdata.yaml
@@ -5,6 +5,8 @@ needs:
   packages:
     - ${{inputs.package}}
     - busybox
+  environment:
+    GOCOVERDIR: /home/build

 inputs:
   package:
# crane.yaml
...
subpackages:
  - name: ${{package.name}}-cover
    pipeline:
      - uses: go/build
        with:
          packages: ./cmd/crane
          extra-args: -cover
          ldflags: -buildid= -X github.com/google/go-containerregistry/cmd/crane/cmd.Version=${{package.version}} -X github.com/google/go-containerregistry/pkg/v1/remote/transport.Version=${{package.version}}
          output: crane
    test:
      environment:
        contents:
          packages:
            - jq
        # The following can be removed thanks to go/covdata needs.environment['GOCOVERDIR']=/home/build
        #environment:
        #  GOCOVERDIR: /home/build
      pipeline:
        - name: Verify Crane installation
          runs: |
            crane version || exit 1
            crane --help
        - name: Fetch and verify manifest
          runs: |
            crane manifest chainguard/static | jq '.schemaVersion' | grep '2' || exit 1
        - name: List tags for a public image
          runs: |
            crane ls chainguard/static | grep -E 'latest|v[0-9]+.[0-9]+.[0-9]+' || exit 1
        - name: Validate image existence
          runs: |
            crane digest chainguard/static:latest && echo "Image exists" || exit 1
        - name: Pull and save an image locally
          runs: |
            crane pull chainguard/static:latest static_latest.tar || exit 1
            [ -f static_latest.tar ] || exit 1
        - uses: go/covdata

we briefly discussed this use case @joshrwolf

@maxgio92 maxgio92 marked this pull request as ready for review March 7, 2025 17:31
Copy link
Copy Markdown
Contributor

@imjasonh imjasonh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add an example to examples/ to demonstrate this working? That will act both as a test, and as runnable documentation of its behavior.

@maxgio92
Copy link
Copy Markdown
Member Author

Yes, sure @imjasonh! I'll do it.

Comment thread docs/BUILD-PROCESS.md Outdated
Comment thread pkg/build/compile_test.go
@maxgio92
Copy link
Copy Markdown
Member Author

maxgio92 commented Mar 12, 2025

Can you add an example to examples/ to demonstrate this working? That will act both as a test, and as runnable documentation of its behavior.

@imjasonh an example which can be used at test as well has been added to examples/needs-environment.yaml.
Thanks for highlighting it. I fixed a bug thanks to it which was affecting non built-in pipelines.

@maxgio92 maxgio92 force-pushed the feat/pipelines-environment-inject branch 2 times, most recently from 2f2a751 to ec2bc4d Compare March 12, 2025 22:18
@maxgio92 maxgio92 requested review from hectorj2f and imjasonh March 19, 2025 11:04
Copy link
Copy Markdown
Member

@hectorj2f hectorj2f left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Comment on lines +83 to +87
- name: Inject an environment transparently to the parent pipeline.
needs:
environment:
FOO: "bar"
BAZ: "baz"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems weird, if I'm understanding correctly. A later step in the pipeline can set env vars for a previous step? What should happen if two steps overwrite each other, who wins?

I'd have expected this to need to come before the steps that use it, and then the rules of precedence are easier to understand (latest wins)

(I'm really glad this example exists, to make it clear how this is working!)

Copy link
Copy Markdown
Member Author

@maxgio92 maxgio92 Mar 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the point @imjasonh. I'm too not 100% convinced by the UX.

W.r.t. the priority, the pipeline-level environment wins over needs.environment, so for instance:

  pipeline:
    - name: Expect an environment transparently.
      environment:
        FOO: "baz"
      runs: |
        set -u
        echo "FOO: ${FOO}"
    - name: Inject an environment to the parent pipeline.
      needs:
        environment:
          FOO: "bar"

will end up with $FOO evaluated to baz.

The way it works is that it feeds the pipeline's environment.environment, so it's enabled for either for all steps or nothing, with a priority lower than the step specific environment.

From usability point of view is not 100% intuitive, at the same time it solves some use cases. I think it's a trade-off. Whether it's worth it or not, I'm fine both ways :-)

@maxgio92 maxgio92 changed the title feat(pkg/build): enable pipelines to inject environment feat(pkg/build): enable pipeline steps to inject environment into the pipeline Mar 21, 2025
@maxgio92 maxgio92 changed the title feat(pkg/build): enable pipeline steps to inject environment into the pipeline feat(pkg/build): enable pipeline steps to inject environment into the parent pipeline Mar 21, 2025
@maxgio92 maxgio92 changed the title feat(pkg/build): enable pipeline steps to inject environment into the parent pipeline Enable pipeline steps to inject environment into the parent pipeline Mar 21, 2025
This commit enable pipelines to inject environment variables the same
way they're able to inject package dependencies into the build or
test configuration. This will allow to remove responsibility to
satisfy environment dependencies from the consumer.
When setting needs.environment all the other pipeline runs in the
same build or config will inherit that additional environment.

Cases like go/covdata pipeline will benefit from this being able to
inject the GOCOVERDIR that the go runtime will use to generate coverage
data and the go tool covdata to generate reports from.

Signed-off-by: Massimiliano Giovagnoli <massimiliano.giovagnoli@chainguard.dev>
Signed-off-by: Massimiliano Giovagnoli <massimiliano.giovagnoli@chainguard.dev>
Signed-off-by: Massimiliano Giovagnoli <massimiliano.giovagnoli@chainguard.dev>
The example can be used as test to ensure:
- the environment is injected correctly to build and test parent
pipelines
- in case of existing environment variables the pipeline-level environment
field wins over needs.environment.

Signed-off-by: Massimiliano Giovagnoli <massimiliano.giovagnoli@chainguard.dev>
@maxgio92 maxgio92 force-pushed the feat/pipelines-environment-inject branch from ec2bc4d to b015f62 Compare April 16, 2025 08:46
Signed-off-by: Massimiliano Giovagnoli <massimiliano.giovagnoli@chainguard.dev>
@kranurag7
Copy link
Copy Markdown
Member

👋🏻 Hello, if we merge this then it'll enable me/us to write pipelines which will allow us to define environment in the pipeline itself. I wanted to this patch inside test/kwok/cluster pipeline.

@maxgio92
Copy link
Copy Markdown
Member Author

maxgio92 commented Apr 16, 2025

I guess @kranurag7 is to export KUBERNETES_SERVICE_HOST + KUBERNETES_SERVICE_PORT environment variable to available to subsequent step's shell session. This feature should avoid exporting them for each step dependent on the kwok step

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: allow pipelines to modify environment.environment

4 participants