Skip to content

feat: support custom chart ref for InstallCrossplane (file/OCI/repo)#134

Open
maximilianbraun wants to merge 2 commits into
mainfrom
feat/install-crossplane-from-chart
Open

feat: support custom chart ref for InstallCrossplane (file/OCI/repo)#134
maximilianbraun wants to merge 2 commits into
mainfrom
feat/install-crossplane-from-chart

Conversation

@maximilianbraun

Copy link
Copy Markdown
Collaborator

Adds CrossplaneSetup.ChartRef and CrossplaneSetup.ChartRepoURL plus matching xpenvfuncs helpers and entry points (InstallCrossplaneFromChart, InstallCrossplaneFromRepo). Lets consumers bypass the hardcoded helm repo add https://charts.crossplane.io/stable flow when the upstream CDN is unreliable, when running air-gapped, or when installing from an OCI registry.

What changes

  • setup.CrossplaneSetup gains:
    • ChartRef string — passed straight to helm install. Accepts a file path, OCI URL (oci://...), or repo/name. When non-empty, helm repo add / helm repo update are skipped.
    • ChartRepoURL string — overrides the default https://charts.crossplane.io/stable URL passed to helm repo add. Ignored when ChartRef is set.
  • xpenvfuncs exposes:
    • InstallCrossplaneFromChart(clusterName, chartRef, opts...)
    • InstallCrossplaneFromRepo(clusterName, chartRepoURL, opts...)
    • ChartRef(string) CrossplaneOpt helper (thin wrapper around helm.WithChart)
  • InstallCrossplane(clusterName, opts...) signature unchanged. Default behaviour preserved when both fields are empty.
  • CrossplaneOpt = helm.Option alias unchanged.

Backwards compatibility

No existing field renamed, no public signature changed. All existing tests pass without modification.

Motivation

SAP/crossplane-provider-btp e2e matrix collapses on transient 403 Forbidden from charts.crossplane.io/stable. Switching the consumer to OCI install (oci://xpkg.crossplane.io/crossplane/crossplane) removes the per-test helm repo add network call.

Tests

Unit tests cover:

  • default (legacy) flow unchanged when both fields empty (TestBuildCrossplaneHelmInstallOpts)
  • ChartRepoURL override threads through (TestResolveCrossplaneChartRepoURL)
  • ChartRef skips helm repo add and is forwarded as helm.WithChart (file path + OCI URL cases)
  • entry-point smoke tests (TestInstallCrossplaneEntryPoints)

Adds CrossplaneSetup.ChartRef (and the ChartRef CrossplaneOpt) that
replaces the hardcoded `helm repo add https://charts.crossplane.io/stable`
flow with a direct chart reference passed to `helm install`. Accepts:
  - file path:  /path/to/crossplane-1.20.1.tgz
  - OCI URL:    oci://xpkg.crossplane.io/crossplane/crossplane
  - repo/name:  e2e_crossplane-stable/crossplane (legacy default,
                still used when ChartRef is empty)

Companion CrossplaneSetup.ChartRepoURL overrides the default repo URL
when the legacy `helm repo add` flow is preferred.

Existing InstallCrossplane(clusterName, opts...) signature unchanged;
default behaviour preserved when both fields are empty. Backwards
compatible.

Motivation: SAP/crossplane-provider-btp e2e matrix collapses on transient
403 from charts.crossplane.io/stable. Switching to OCI install
(oci://xpkg.crossplane.io/crossplane/crossplane) removes the per-test
`helm repo add` network call.

Signed-off-by: Maximilian Braun (SAP) <maximilian.braun@sap.com>
maximilianbraun added a commit to SAP/crossplane-provider-btp that referenced this pull request Jun 15, 2026
Replaces xp-testing's bundled `helm repo add https://charts.crossplane.io/stable`
flow with a chart-from-tarball install. The build job pulls the Crossplane
chart once per workflow run (cached via actions/cache, retried with backoff),
uploads it as a workflow artifact, and matrix `e2e-test` jobs download it
and install via `helm install crossplane /path/to/crossplane-X.Y.Z.tgz`.

Single CDN entry point per workflow run instead of per-matrix-leg. Cache
means follow-up runs at the same version skip the pull entirely.

The charts.crossplane.io CDN throws intermittent 403 Forbidden errors that
collapse entire matrix shards (see docs/development/flakiness-analysis.md
Pattern A). With this change, only the build job touches the CDN — and
only on cache miss.

Implementation: a new `InstallCrossplaneFromChart(clusterName, chartRef,
version)` helper in `test/test_utils.go` accepts any chart reference
`helm.WithChart` understands (file path, OCI URL, repo/name). The e2e
harness reads `CROSSPLANE_CHART_PATH` from the environment, which the
workflow sets after downloading the chart artifact.

xp-testing v1.9.2 stays pinned. crossplane-contrib/xp-testing#134 (which
would let us drop the inline `setup.ClusterSetup.Configure` replication)
is blocked on a k8s dep skew with this repo's crossplane-runtime/v2.

Earlier commit on this branch tried `oci://xpkg.crossplane.io/...` but
Crossplane's chart is not OCI-distributed.
maximilianbraun added a commit to SAP/crossplane-provider-btp that referenced this pull request Jun 15, 2026
…ll install

The earlier InstallCrossplaneFromChart helper installed Crossplane via
`helm install --set packageCache.pvc=package-cache`, but never created
the PV/PVC backing it or the host-path directory the PV references.
Without that backing, the BTP provider's xpkg loaded by xp-testing's
InstallCrossplaneProvider had nowhere to land in the cluster, and the
provider failed its Healthy gate with:

    failed to get pre-cached package with pull policy Never

This commit inline-replicates xp-testing v1.9.2's unexported
setupCrossplanePackageCache helper:

  1. `docker exec <cluster>-control-plane mkdir -m 777 -p /cache/xpkg`
  2. Apply PV (hostPath: /cache/xpkg) + PVC (crossplane-system).

Composed into InstallCrossplaneFromChart between the namespace creation
and the helm install. Mirrors xpenvfuncs.InstallCrossplane verbatim —
once the upstream helper becomes exportable (xp-testing follow-up to
crossplane-contrib/xp-testing#134), this inline copy can be removed.

The hostPath is /cache/xpkg (matching xp-testing v1.9.2 xpenvfuncs.go:326)
because xp-testing's InstallCrossplaneProvider docker-cps the xpkg into
/cache/xpkg/<friendlyName>.gz on the control-plane node, and the Crossplane
helm chart mounts the package-cache PVC at /cache in the pod — so the
files surface at /cache/<friendlyName>.gz where Crossplane looks.
sdischer-sap added a commit to SAP/crossplane-provider-btp that referenced this pull request Jun 17, 2026
* feat(test/e2e): install Crossplane from cached chart tarball

Replaces xp-testing's bundled `helm repo add https://charts.crossplane.io/stable`
flow with a chart-from-tarball install. The build job pulls the Crossplane
chart once per workflow run (cached via actions/cache, retried with backoff),
uploads it as a workflow artifact, and matrix `e2e-test` jobs download it
and install via `helm install crossplane /path/to/crossplane-X.Y.Z.tgz`.

Single CDN entry point per workflow run instead of per-matrix-leg. Cache
means follow-up runs at the same version skip the pull entirely.

The charts.crossplane.io CDN throws intermittent 403 Forbidden errors that
collapse entire matrix shards (see docs/development/flakiness-analysis.md
Pattern A). With this change, only the build job touches the CDN — and
only on cache miss.

Implementation: a new `InstallCrossplaneFromChart(clusterName, chartRef,
version)` helper in `test/test_utils.go` accepts any chart reference
`helm.WithChart` understands (file path, OCI URL, repo/name). The e2e
harness reads `CROSSPLANE_CHART_PATH` from the environment, which the
workflow sets after downloading the chart artifact.

xp-testing v1.9.2 stays pinned. crossplane-contrib/xp-testing#134 (which
would let us drop the inline `setup.ClusterSetup.Configure` replication)
is blocked on a k8s dep skew with this repo's crossplane-runtime/v2.

Earlier commit on this branch tried `oci://xpkg.crossplane.io/...` but
Crossplane's chart is not OCI-distributed.

* ci(e2e): pin Crossplane chart SHA256 to harden against artifact poisoning

Adds a SHA256 integrity check after `helm pull` in the build job. The
pulled chart tarball is uploaded as a workflow artifact and `helm
install`'d by every matrix leg — a malicious PR that rewrites the pull
step (workflow_dispatch / pull_request_target both check out PR head)
could otherwise replace the chart.

The expected SHA256 is sourced from upstream charts.crossplane.io's
index.yaml `digest:` field for crossplane-2.1.3.tgz. Update the
constant on every Crossplane version bump.

Addresses GitHub Advanced Security CodeQL alert #64 on PR #720.

* ci(renovate): auto-update Crossplane chart version + SHA256 in lockstep

Adds a Renovate customManager that watches the Crossplane chart on
charts.crossplane.io/stable and bumps both CROSSPLANE_CHART_VERSION
and CROSSPLANE_CHART_SHA256 in e2e_test.yaml together when a new
chart version is published. The verify step in the build job catches
any version/digest mismatch the bot might produce.

The upgrade-test fixture (test/upgrade/main_test.go) deliberately stays
manually pinned at v1.20.1 — it exercises a specific Crossplane
v1->v2 upgrade scenario and auto-bumps would break the test premise.

Companion to commit 6374294 (SHA256 verification).

* fix(test/e2e): graceful fallback when CROSSPLANE_CHART_PATH unset + add workflow_dispatch

Two related fixes for PR pull_request_target asymmetry:

1. main_test.go: when CROSSPLANE_CHART_PATH is unset, fall back to
   xp-testing's bundled helm-repo install (xpenvfuncs.InstallCrossplane).
   pull_request_target uses workflows from the BASE branch — so this PR's
   chart-export step doesn't run on its own CI, and the unconditional
   GetOrPanic crashed every matrix leg.

2. e2e_test.yaml: add `workflow_dispatch:` trigger alongside `workflow_call`.
   workflow_dispatch uses the workflow file from the dispatched ref, so a
   maintainer can `gh workflow run e2e_test.yaml --ref feat/oci-crossplane-install`
   to validate the full chart-tarball + cache + SHA-verify flow against
   THIS PR's workflow, not main's.

Once this lands on main, both paths are exercised by every PR.

* refactor(ci): split chart pull into dedicated fetch-chart job

Extracts the Crossplane chart pull/cache/verify/upload steps from the
`build` job into a new `fetch-chart` job that runs in parallel with
`build`. Both feed the `e2e-test` matrix.

Why:
- Failure attribution: a CDN 403 from charts.crossplane.io now fails
  `fetch-chart` cleanly, leaving `build` and its diagnostics untouched.
- Wall-clock: chart pull (~10s on cache hit, up to ~3min on retry) and
  provider build (~3-4min) run in parallel instead of sequentially.
- Restart granularity: re-running just `fetch-chart` after a CDN blip
  preserves build artifacts.
- Setup cost: `fetch-chart` skips Go install + submodule checkout
  (chart pull only needs helm + curl). Faster spin-up.

The `e2e-tests` aggregator now also gates on `fetch-chart` so a
chart-pull failure (which cascades to the matrix as `skipped`, not
`failure`) cannot pass the required status check.

No behavior change otherwise. Cache, retry, SHA verification, and
artifact upload semantics are preserved exactly.

* fix(test/e2e): set up Crossplane package cache PV/PVC for chart-tarball install

The earlier InstallCrossplaneFromChart helper installed Crossplane via
`helm install --set packageCache.pvc=package-cache`, but never created
the PV/PVC backing it or the host-path directory the PV references.
Without that backing, the BTP provider's xpkg loaded by xp-testing's
InstallCrossplaneProvider had nowhere to land in the cluster, and the
provider failed its Healthy gate with:

    failed to get pre-cached package with pull policy Never

This commit inline-replicates xp-testing v1.9.2's unexported
setupCrossplanePackageCache helper:

  1. `docker exec <cluster>-control-plane mkdir -m 777 -p /cache/xpkg`
  2. Apply PV (hostPath: /cache/xpkg) + PVC (crossplane-system).

Composed into InstallCrossplaneFromChart between the namespace creation
and the helm install. Mirrors xpenvfuncs.InstallCrossplane verbatim —
once the upstream helper becomes exportable (xp-testing follow-up to
crossplane-contrib/xp-testing#134), this inline copy can be removed.

The hostPath is /cache/xpkg (matching xp-testing v1.9.2 xpenvfuncs.go:326)
because xp-testing's InstallCrossplaneProvider docker-cps the xpkg into
/cache/xpkg/<friendlyName>.gz on the control-plane node, and the Crossplane
helm chart mounts the package-cache PVC at /cache in the pod — so the
files surface at /cache/<friendlyName>.gz where Crossplane looks.

---------

Co-authored-by: sdischer-sap <stephan.discher@sap.com>

@christophrj christophrj left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM 👍 thanks @maximilianbraun

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.

2 participants