Compare commits

..

201 Commits
v2.6.0 ... main

Author SHA1 Message Date
Matheus Pimenta 94e9af6b2a
Merge pull request #5656 from jaxels10/main
fix: #5654 by checking if both --chart and --chart-ref are set
4 days ago
Jesper Axelsen 3fb05a604f fix: #5654 by check if both --chart and --chart-ref are set
Signed-off-by: Jesper Axelsen <jesperbaxelsen@gmail.com>
4 days ago
Matheus Pimenta 9b76ba19a8
Merge pull request #5648 from fluxcd/update-components
Update toolkit components
3 weeks ago
fluxcdbot 1e7dd5dfd8 Update toolkit components
- helm-controller to v1.4.5
  https://github.com/fluxcd/helm-controller/blob/v1.4.5/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
3 weeks ago
Stefan Prodan d6dec730d8
Merge pull request #5597 from anshuishere/skip-tenant-ns-create
Allow option to skip tenant namespace creation
3 weeks ago
Anshuman Singh 0ba28f3f91
Allow option to skip tenant namespace creation
Add --skip-namespace flag to the 'create tenant' command to skip automatic
namespace creation when the namespace already exists.

Signed-off-by: Anshuman Singh <anshumanchauhan9@gmail.com>
3 weeks ago
Matheus Pimenta 55936e9366
Merge pull request #5639 from fluxcd/update-components
Update toolkit components
4 weeks ago
fluxcdbot 6ecad4783f Update toolkit components
- helm-controller to v1.4.4
  https://github.com/fluxcd/helm-controller/blob/v1.4.4/CHANGELOG.md
- kustomize-controller to v1.7.3
  https://github.com/fluxcd/kustomize-controller/blob/v1.7.3/CHANGELOG.md
- source-controller to v1.7.4
  https://github.com/fluxcd/source-controller/blob/v1.7.4/CHANGELOG.md
- notification-controller to v1.7.5
  https://github.com/fluxcd/notification-controller/blob/v1.7.5/CHANGELOG.md
- image-reflector-controller to v1.0.4
  https://github.com/fluxcd/image-reflector-controller/blob/v1.0.4/CHANGELOG.md
- image-automation-controller to v1.0.4
  https://github.com/fluxcd/image-automation-controller/blob/v1.0.4/CHANGELOG.md
- source-watcher to v2.0.3
  https://github.com/fluxcd/source-watcher/blob/v2.0.3/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
4 weeks ago
Matheus Pimenta 5759d08473
Merge pull request #5625 from hown3d/report-diff-skip
diff: report if object is skipped
4 weeks ago
Lukas Hoehl 5048de80f0
diff: report if object is skipped
Signed-off-by: Lukas Hoehl <lukas.hoehl@stackit.cloud>
4 weeks ago
Matheus Pimenta 97a437d059
Merge pull request #5633 from fluxcd/upgrade-deps
Upgrade k8s to 1.34.2, c-r to 0.22.4 and helm to 3.19.2
4 weeks ago
Matheus Pimenta cfb28ffdc0
Upgrade k8s to 1.34.2, c-r to 0.22.4 and helm to 3.19.2
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
4 weeks ago
Matheus Pimenta ae9ef62f39
Merge pull request #5630 from fluxcd/fix-5629
Fix panic on reconcile with source of ExternalArtifact kind
4 weeks ago
Matheus Pimenta 69feb7214a
Fix panic on reconcile with source of ExternalArtifact kind
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
4 weeks ago
Matheus Pimenta e95da82f5a
Merge pull request #5627 from fluxcd/fix-5626
Add source.extensions.fluxcd.io group to aggregated RBAC roles
1 month ago
Matheus Pimenta 7c5f9befb4
Add source.extensions.fluxcd.io group to aggregated RBAC roles
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
1 month ago
Stefan Prodan 26a8d0c1c7
Merge pull request #5614 from fluxcd/conform-source-watcher
ci: Include source-watcher in the e2e test suite
1 month ago
Stefan Prodan 833815c71d
ci: Include source-watcher in the e2e test suite
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
1 month ago
Matheus Pimenta 31287b9b27
Merge pull request #5602 from jaxels10/main
fix: return accepted values for flags when calling Values.Type()
2 months ago
Jesper Axelsen 28f5b553a2
fix: return supported values for flags when calling Values.Type()
Signed-off-by: Jesper Axelsen <jesperbaxelsen@gmail.com>
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2 months ago
Matheus Pimenta b33f173670
Merge pull request #5603 from fluxcd/update-components
Update toolkit components
2 months ago
Matheus Pimenta d8c6ee167c
Fix bootstrap e2e test for image policy
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2 months ago
fluxcdbot e288cb2771 Update toolkit components
- helm-controller to v1.4.3
  https://github.com/fluxcd/helm-controller/blob/v1.4.3/CHANGELOG.md
- kustomize-controller to v1.7.2
  https://github.com/fluxcd/kustomize-controller/blob/v1.7.2/CHANGELOG.md
- source-controller to v1.7.3
  https://github.com/fluxcd/source-controller/blob/v1.7.3/CHANGELOG.md
- notification-controller to v1.7.4
  https://github.com/fluxcd/notification-controller/blob/v1.7.4/CHANGELOG.md
- image-reflector-controller to v1.0.3
  https://github.com/fluxcd/image-reflector-controller/blob/v1.0.3/CHANGELOG.md
- image-automation-controller to v1.0.3
  https://github.com/fluxcd/image-automation-controller/blob/v1.0.3/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2 months ago
Stefan Prodan 5f2a6ebc2b
Merge pull request #5583 from dgunzy/add-export-source-external
[RFC-0012] Add command `flux export source external`
2 months ago
Daniel Guns cdc37c304a
Adding export source external
Signed-off-by: Daniel Guns <danbguns@gmail.com>
2 months ago
Matheus Pimenta 60e4d99b57
Merge pull request #5594 from fluxcd/pin-cosign-v2.6.1
Pin cosign to v2.6.1
2 months ago
Matheus Pimenta 8229ffb674
Pin cosign to v2.6.1
xref: https://github.com/fluxcd/source-controller/issues/1923
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2 months ago
Stefan Prodan 9b944da896
Merge pull request #5589 from akshatsinha0/fix/check-prompt-write-error
fix: handle error when writing password prompt to stdout
2 months ago
Akshat Sinha 5b37a6b04b fix(cli): handle error when writing password prompt and correct spelling (i) Add error handling for fmt.Fprint when writing password prompt to stdout (ii) Fixed : initalization to initialization in the commented region
Signed-off-by: Akshat Sinha <akshatsinhasramhardy@gmail.com>
2 months ago
Stefan Prodan 9f18062d43
Merge pull request #5555 from dgunzy/add-get-source-external-artifact
[RFC-0012] Add command `flux get source external`
2 months ago
Daniel Guns 1055f28524 Adding get source external-artifact
Signed-off-by: Daniel Guns <danbguns@gmail.com>
2 months ago
Matheus Pimenta 7b0021c1a8
Merge pull request #5581 from fluxcd/restore-github-pat-for-backports
Restore GitHub PAT for backports
2 months ago
Matheus Pimenta ba997449aa
Restore GitHub PAT for backports
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2 months ago
Matheus Pimenta ca2f0205c4
Merge pull request #5578 from fluxcd/update-components
Update toolkit components
2 months ago
fluxcdbot 058525fe37 Update toolkit components
- helm-controller to v1.4.2
  https://github.com/fluxcd/helm-controller/blob/v1.4.2/CHANGELOG.md
- kustomize-controller to v1.7.1
  https://github.com/fluxcd/kustomize-controller/blob/v1.7.1/CHANGELOG.md
- source-controller to v1.7.2
  https://github.com/fluxcd/source-controller/blob/v1.7.2/CHANGELOG.md
- notification-controller to v1.7.3
  https://github.com/fluxcd/notification-controller/blob/v1.7.3/CHANGELOG.md
- image-reflector-controller to v1.0.2
  https://github.com/fluxcd/image-reflector-controller/blob/v1.0.2/CHANGELOG.md
- image-automation-controller to v1.0.2
  https://github.com/fluxcd/image-automation-controller/blob/v1.0.2/CHANGELOG.md
- source-watcher to v2.0.2
  https://github.com/fluxcd/source-watcher/blob/v2.0.2/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2 months ago
Stefan Prodan 686ee31f8a
Merge pull request #5576 from fluxcd/k8s-1.34.1
Update dependencies to Kubernetes v1.34.1 and Go 1.25.2
2 months ago
Stefan Prodan 767f235f94
Update dependencies to Kubernetes v1.34.1 and Go 1.25.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2 months ago
Stefan Prodan d5a2c66746
Merge pull request #5574 from fluxcd/fix-manifestgen
Fix manifest generation for `--storage-adv-addr` and `--events-addr` flags
2 months ago
Stefan Prodan f2ff083b8e
Use `RUNTIME_NAMESPACE` when setting `--events-addr`
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2 months ago
Stefan Prodan 8c45f25f33
Fix `--storage-adv-addr` for source-watcher
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2 months ago
Stefan Prodan f85cbfa9c8
Merge pull request #5570 from fluxcd/remove-aur-pkgs
Disable AUR publishing
2 months ago
Stefan Prodan 71a3dad213
Disable AUR publishing
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2 months ago
Matheus Pimenta 72e0535958
Merge pull request #5568 from fluxcd/update-components
Update toolkit components
2 months ago
fluxcdbot 4f2d1c3a2a Update toolkit components
- helm-controller to v1.4.1
  https://github.com/fluxcd/helm-controller/blob/v1.4.1/CHANGELOG.md
- source-controller to v1.7.1
  https://github.com/fluxcd/source-controller/blob/v1.7.1/CHANGELOG.md
- notification-controller to v1.7.2
  https://github.com/fluxcd/notification-controller/blob/v1.7.2/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
2 months ago
Stefan Prodan 8e99cf7c93
Merge pull request #5566 from ramasai1/refactor-variable-sub
refactor: convert `Kustomization` resource into unstructured map only once during variable substitution
2 months ago
Ramasai Venkatsitarambhaskar Tadepalli 2bb7f38603
refactor: convert `Kustomization` resource into unstructured map only once during variable substitution
Signed-off-by: Ramasai Venkatsitarambhaskar Tadepalli <ramasai.tadepalli@mongodb.com>
2 months ago
Matheus Pimenta 0fe4449870
Merge pull request #5563 from fluxcd/fix-migrate-f
Fix `flux migrate -f` not considering kind comments
2 months ago
Matheus Pimenta 7c5fb2297c
Fix flux migrate -f not considering kind comments
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2 months ago
Stefan Prodan f4a811fbd3
Merge pull request #5562 from fluxcd/source-watcher-links
Add source-watcher to docs
2 months ago
Stefan Prodan bb3726bb87
Add source-watcher to docs
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2 months ago
Matheus Pimenta 333c8fe704
Merge pull request #5560 from fluxcd/fix-migrate-files
Fix `flux migrate -f` command to work with comments
2 months ago
Matheus Pimenta 83213ce83f
Fix migrate -f command to work with comments
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2 months ago
Stefan Prodan 69718599ac
Merge pull request #5558 from fluxcd/improve-flux-migrate
Improve `flux migrate` for live cluster migrations
2 months ago
Stefan Prodan 0255957dd7
Improve `flux migrate` for live cluster migrations
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2 months ago
Stefan Prodan 69b4b85cd9
Merge pull request #5554 from fluxcd/migrate-dir
Extend `flux migrate` to work with local files
2 months ago
Matheus Pimenta a9b5be7ff4
Extend flux migrate to work with local files
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2 months ago
Matheus Pimenta 1b46056e7d
Merge pull request #5551 from fluxcd/fix-5549
Fix `flux push artifact` not working with `--provider`
2 months ago
Matheus Pimenta 039d79b3c2
Fix flux push artifact not working with --provider
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2 months ago
Stefan Prodan 66b8aca399
Merge pull request #5548 from fluxcd/dependabot/github_actions/ci-b5b9679c22
build(deps): bump the ci group across 1 directory with 3 updates
2 months ago
dependabot[bot] 41c413e178
build(deps): bump the ci group across 1 directory with 3 updates
Bumps the ci group with 3 updates in the / directory: [docker/login-action](https://github.com/docker/login-action), [ossf/scorecard-action](https://github.com/ossf/scorecard-action) and [github/codeql-action](https://github.com/github/codeql-action).


Updates `docker/login-action` from 3.5.0 to 3.6.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](184bdaa072...5e57cd1181)

Updates `ossf/scorecard-action` from 2.4.2 to 2.4.3
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](05b42c6244...4eaacf0543)

Updates `github/codeql-action` from 3.30.3 to 3.30.5
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](192325c861...3599b3baa1)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: github/codeql-action
  dependency-version: 3.30.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
...

Signed-off-by: dependabot[bot] <support@github.com>
2 months ago
Matheus Pimenta d5f8720c4d
Merge pull request #5550 from fluxcd/update-labels
Add backport label for Flux 2.7
2 months ago
Matheus Pimenta e6eb9d79e3
Add backport label for Flux 2.7
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
2 months ago
Stefan Prodan b90d1738a9
Merge pull request #5547 from fluxcd/ci-fix-release-flux-manifests
ci: Set `GITHUB_TOKEN` in the `release-flux-manifests` workflow
3 months ago
Stefan Prodan f9e66dee9e
ci: Set `GITHUB_TOKEN` in the `release-flux-manifests` workflow
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Matheus Pimenta f251e8e8a9
Merge pull request #5509 from RussellAult/action-without-api
`fluxcd/flux2/action`: Determine latest version without using GitHub API
3 months ago
RussellAult 44f0d50dbf
`fluxcd/flux2/action`: Determine latest version without using GitHub API
Signed-off-by: RussellAult <RussellAult@users.noreply.github.com>
Co-authored-by: Matheus Pimenta <matheuscscp@gmail.com>
3 months ago
Matheus Pimenta 4664d49e29
Merge pull request #5542 from fluxcd/update-components
Update image-automation-controller to v1.0.1
3 months ago
fluxcdbot 2997645ea3 Update toolkit components
- image-automation-controller to v1.0.1
  https://github.com/fluxcd/image-automation-controller/blob/v1.0.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
3 months ago
Matheus Pimenta 3247a46654
Merge pull request #5541 from fluxcd/debug-ks-history
Add `--show-history` flag to `debug kustomization`
3 months ago
Matheus Pimenta b5ecb9bc56
Add --show-history flag to debug kustomization
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
3 months ago
Stefan Prodan 550260638d
Merge pull request #5540 from fluxcd/update-components
Update source-watcher to v2.0.1
3 months ago
fluxcdbot b52d76d6e6 Update toolkit components
- source-watcher to v2.0.1
  https://github.com/fluxcd/source-watcher/blob/v2.0.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
3 months ago
Matheus Pimenta 95b2d855cb
Merge pull request #5539 from fluxcd/no-cron-for-update
ci: remove cron schedule from update
3 months ago
Matheus Pimenta 52e0c9815b
ci: remove cron schedule from update
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
3 months ago
Stefan Prodan 154069893b
Merge pull request #5537 from fluxcd/update-components
Update toolkit components
3 months ago
Stefan Prodan 6185366b8a
Migrate create commands to `DependencyReference` type
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
fluxcdbot f7665f4b47 Update toolkit components
- helm-controller to v1.4.0
  https://github.com/fluxcd/helm-controller/blob/v1.4.0/CHANGELOG.md
- kustomize-controller to v1.7.0
  https://github.com/fluxcd/kustomize-controller/blob/v1.7.0/CHANGELOG.md
- notification-controller to v1.7.1
  https://github.com/fluxcd/notification-controller/blob/v1.7.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
3 months ago
Stefan Prodan b20eb0ca22
Merge pull request #5534 from prasad89/issue#5526
Add support for custom storage namespace in HelmRelease creation
3 months ago
prasad89 8000a41015 Add support for custom storage namespace in HelmRelease creation
Signed-off-by: prasad89 <vdbhaleraovb@gmail.com>
3 months ago
Stefan Prodan 4601a304dd
Merge pull request #5535 from fluxcd/dependabot/github_actions/ci-57db20d2cc
build(deps): bump the ci group with 6 updates
3 months ago
dependabot[bot] 2fc09963e8
build(deps): bump the ci group with 6 updates
Bumps the ci group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [fluxcd/gha-workflows](https://github.com/fluxcd/gha-workflows) | `0.3.0` | `0.4.0` |
| [actions/setup-go](https://github.com/actions/setup-go) | `5.5.0` | `6.0.0` |
| [fluxcd/pkg](https://github.com/fluxcd/pkg) | `1.20.0` | `1.22.0` |
| [github/codeql-action](https://github.com/github/codeql-action) | `3.29.11` | `3.30.3` |
| [anchore/sbom-action](https://github.com/anchore/sbom-action) | `0.20.5` | `0.20.6` |
| [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) | `3.9.2` | `3.10.0` |


Updates `fluxcd/gha-workflows` from 0.3.0 to 0.4.0
- [Release notes](https://github.com/fluxcd/gha-workflows/releases)
- [Commits](https://github.com/fluxcd/gha-workflows/compare/v0.3.0...v0.4.0)

Updates `actions/setup-go` from 5.5.0 to 6.0.0
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](d35c59abb0...4469467582)

Updates `fluxcd/pkg` from 1.20.0 to 1.22.0
- [Commits](7f090e9313...bf02f0a2d6)

Updates `github/codeql-action` from 3.29.11 to 3.30.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](3c3833e0f8...192325c861)

Updates `anchore/sbom-action` from 0.20.5 to 0.20.6
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](da167eac91...f8bdd1d8ac)

Updates `sigstore/cosign-installer` from 3.9.2 to 3.10.0
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](d58896d6a1...d7543c93d8)

---
updated-dependencies:
- dependency-name: fluxcd/gha-workflows
  dependency-version: 0.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: actions/setup-go
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: ci
- dependency-name: fluxcd/pkg
  dependency-version: 1.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: github/codeql-action
  dependency-version: 3.30.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
...

Signed-off-by: dependabot[bot] <support@github.com>
3 months ago
Stefan Prodan a2b4edc2f3
Merge pull request #5533 from fluxcd/conform-k8s-1.34.1
Set Kubernetes 1.32 as min supported version
3 months ago
Stefan Prodan 55bb3fe643
Set Kubernetes 1.32 as min supported version
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 7060770258
Merge pull request #5532 from fluxcd/trace-external-artifact
Add support for `ExternalArtifact` to `flux trace`
3 months ago
Stefan Prodan c3eadad983
Add support for `ExternalArtifact` to `flux trace`
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan e56dfcacf2
Merge pull request #5531 from fluxcd/uninstall-artifact-generator
Remove `ArtifactGenerators` during uninstall
3 months ago
Stefan Prodan 56e73ae03c
Remove `ArtifactGenerators` during uninstall
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 7a2f77ffe0
Merge pull request #5529 from fluxcd/fluxcd/gha-workflows
ci: Refactor CI with `fluxcd/gha-workflows`
3 months ago
Stefan Prodan c1b2c7cae8
ci: Refactor CI with `fluxcd/gha-workflows`
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 79186a0055
Merge pull request #5528 from fluxcd/diff-force
Handle `force: enabled` annotation in `flux diff ks` command
3 months ago
Stefan Prodan e7f1faea01
Handle `force: enabled` annotation in `flux diff ks` command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Matheus Pimenta 74edb12bd1
Merge pull request #5492 from lukas8219/5411-reconcile-suspend-resume-img-policy
Implement `flux [reconcile|suspend|resume] image policy` commands
3 months ago
lukas8219 48d509d838
Implement flux [reconcile|suspend|resume] image policy commands
Signed-off-by: lukas8219 <lucas.c4d@gmail.com>
3 months ago
Matheus Pimenta 948ed45f10
Merge pull request #5525 from fluxcd/update-components
Update image-reflector-controller to v1.0.1
3 months ago
fluxcdbot 6f47ae0f2f Update toolkit components
- image-reflector-controller to v1.0.1
  https://github.com/fluxcd/image-reflector-controller/blob/v1.0.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
3 months ago
Matheus Pimenta a1f366933b
Merge pull request #5522 from fluxcd/update-components
Update image-automation-controller to v1.0.0
3 months ago
fluxcdbot 99b51ad525
Update toolkit components
- image-automation-controller to v1.0.0
  https://github.com/fluxcd/image-automation-controller/blob/v1.0.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
3 months ago
Stefan Prodan b6e0e8fd63
Merge pull request #5521 from fluxcd/update-source-watcher
ci: Add source-watcher to the update workflow
3 months ago
Stefan Prodan 9056ec029c
ci: Add source-watcher to the update workflow
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 9caea521ea
Merge pull request #5520 from fluxcd/artifact-generator
Add read-only commands for `ArtifactGenerator` kind
3 months ago
Stefan Prodan a317f7c445
Add support for `events --for ArtifactGenerator/<name>`
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 698a68424f
Add `tree artifact generator` command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 5556a5cc9a
Add `get artifact generator` command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan c416671ec4
Add `export artifact generator` command
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan f719d2bf76
Use stdout when exporting objects
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 46aa068fda
Merge pull request #5519 from fluxcd/source-watcher
Add the source-watcher controller to the Flux distribution
3 months ago
Stefan Prodan 3542d61afd
Add source-watcher to the `install` and `bootstrap` commands
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 0a87ed5a42
Add source-watcher to manifests
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Matheus Pimenta e4dcc4bd5f
Merge pull request #5518 from fluxcd/update-components
Update source-controller to v1.7.0
3 months ago
fluxcdbot b4bc0d4932
Update toolkit components
- source-controller to v1.7.0
  https://github.com/fluxcd/source-controller/blob/v1.7.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
3 months ago
Stefan Prodan 6cc446af00
Merge pull request #5517 from fluxcd/update-components
Update image-reflector-controller to v1.0.0
3 months ago
Matheus Pimenta 8db628cc90
Update image-reflector-controller to v1 in integration tests
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
3 months ago
Matheus Pimenta e765897df7
Update image-reflector-controller API imports to v1
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
3 months ago
fluxcdbot 210b2aa458 Update toolkit components
- image-reflector-controller to v1.0.0
  https://github.com/fluxcd/image-reflector-controller/blob/v1.0.0/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
3 months ago
Matheus Pimenta a8e0ea495d
Merge pull request #5508 from fluxcd/azure-e2e
ci: Align azure e2e tests secret names with fluxcd/pkg
3 months ago
Matheus Pimenta 8fb1ccebfa
ci: Align azure e2e tests secret names with fluxcd/pkg
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
3 months ago
Matheus Pimenta 664423230d
Merge pull request #5507 from fluxcd/skip-rc-upd
Skip release candidates on updates
3 months ago
Matheus Pimenta 0c8cfcdc85
Skip release candidates on updates
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
3 months ago
Matheus Pimenta 89d4467a50
Merge pull request #5505 from hawkaii/history
Add `--show-history` flag to `debug  helmrelease`
3 months ago
Parthib Mukherjee bef6f36755 Add --show-history flag to debug helmrelease
Signed-off-by: Parthib Mukherjee <parthibmukherjee@gmail.com>
3 months ago
Stefan Prodan 6125991b78
Merge pull request #5292 from fluxcd/rfc-external-artifact
[RFC-0012] External Artifact API
3 months ago
Stefan Prodan 64bfa02db4
Add Artifact access restrictions to recommendations
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 1e662e5ed9
Assign 0012 to RFC
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan df57392f48
Add Feature Gate
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 19cd02e548
Add SDK for packaging and exposing artifacts
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 8bc7822fe5
Add security considerations and recommendations
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan e97da26435
Add design details to `ExternalArtifact` RFC
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 1a89fa419e
RFC External Artifact API
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
3 months ago
Stefan Prodan 7c0e70b9cc
Merge pull request #5321 from adri1197/rfcs-opentelemetry
[RFC-0011] OpenTelemetry Tracing
3 months ago
Adrian Fernandez De La Torre ed9ee95dbe [RFC-0011] - OpenTelemetry Tracing
Signed-off-by: Adrian Fernandez De La Torre <adri1197@gmail.com>
3 months ago
Matheus Pimenta 63a38ab228
Merge pull request #5414 from mohiuddin-khan-shiam/main
fix(events): respect `--all-namespaces` flag
3 months ago
S. M. Mohiuddin Khan Shiam c2a883e25a
fix(events): respect `--all-namespaces` flag
The `flux events` command always applied a namespace filter, even when `--all-namespaces` was set.
This produced incomplete results and confused users expecting cluster-wide events.

Changes made:
* Build `clientListOpts` dynamically.
* Omit `client.InNamespace(...)` when `eventArgs.allNamespaces` is true, ensuring no namespace constraint.

Impact:
`flux events --all-namespaces` now returns events from every namespace, restoring expected functionality without affecting other options.

Signed-off-by: S. M. Mohiuddin Khan Shiam <147746955+mohiuddin-khan-shiam@users.noreply.github.com>
3 months ago
Stefan Prodan 24ae50cfd5
Merge pull request #5501 from fluxcd/auto-gomaxprocs
Allow the Go runtime to dynamically set `GOMAXPROCS`
3 months ago
Stefan Prodan 0573138e38
Allow the Go runtime to dynamically set `GOMAXPROCS`
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
4 months ago
Stefan Prodan 2f14313646
Merge pull request #5500 from fluxcd/dependabot/github_actions/ci-fe119e88f8
build(deps): bump the ci group across 1 directory with 10 updates
4 months ago
dependabot[bot] e135336aae
build(deps): bump the ci group across 1 directory with 10 updates
Bumps the ci group with 10 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `4.2.2` | `5.0.0` |
| [korthout/backport-action](https://github.com/korthout/backport-action) | `3.2.1` | `3.3.0` |
| [fluxcd/pkg](https://github.com/fluxcd/pkg) | `1.19.0` | `1.20.0` |
| [google-github-actions/auth](https://github.com/google-github-actions/auth) | `2.1.10` | `3.0.0` |
| [google-github-actions/setup-gcloud](https://github.com/google-github-actions/setup-gcloud) | `2.1.4` | `3.0.1` |
| [docker/login-action](https://github.com/docker/login-action) | `3.4.0` | `3.5.0` |
| [github/codeql-action](https://github.com/github/codeql-action) | `3.29.2` | `3.29.11` |
| [anchore/sbom-action](https://github.com/anchore/sbom-action) | `0.20.2` | `0.20.5` |
| [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) | `3.9.1` | `3.9.2` |
| [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) | `6.3.0` | `6.4.0` |



Updates `actions/checkout` from 4.2.2 to 5.0.0
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](11bd71901b...08c6903cd8)

Updates `korthout/backport-action` from 3.2.1 to 3.3.0
- [Release notes](https://github.com/korthout/backport-action/releases)
- [Commits](0193454f0c...ca4972adce)

Updates `fluxcd/pkg` from 1.19.0 to 1.20.0
- [Commits](9e79277372...7f090e9313)

Updates `google-github-actions/auth` from 2.1.10 to 3.0.0
- [Release notes](https://github.com/google-github-actions/auth/releases)
- [Changelog](https://github.com/google-github-actions/auth/blob/main/CHANGELOG.md)
- [Commits](ba79af0395...7c6bc770da)

Updates `google-github-actions/setup-gcloud` from 2.1.4 to 3.0.1
- [Release notes](https://github.com/google-github-actions/setup-gcloud/releases)
- [Changelog](https://github.com/google-github-actions/setup-gcloud/blob/main/CHANGELOG.md)
- [Commits](77e7a554d4...aa5489c893)

Updates `docker/login-action` from 3.4.0 to 3.5.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](74a5d14239...184bdaa072)

Updates `github/codeql-action` from 3.29.2 to 3.29.11
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](181d5eefc2...3c3833e0f8)

Updates `anchore/sbom-action` from 0.20.2 to 0.20.5
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](cee1b8e05a...da167eac91)

Updates `sigstore/cosign-installer` from 3.9.1 to 3.9.2
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](398d4b0eee...d58896d6a1)

Updates `goreleaser/goreleaser-action` from 6.3.0 to 6.4.0
- [Release notes](https://github.com/goreleaser/goreleaser-action/releases)
- [Commits](9c156ee8a1...e435ccd777)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: ci
- dependency-name: korthout/backport-action
  dependency-version: 3.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: fluxcd/pkg
  dependency-version: 1.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: google-github-actions/auth
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: ci
- dependency-name: google-github-actions/setup-gcloud
  dependency-version: 3.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: ci
- dependency-name: docker/login-action
  dependency-version: 3.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: github/codeql-action
  dependency-version: 3.29.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.9.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: goreleaser/goreleaser-action
  dependency-version: 6.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
...

Signed-off-by: dependabot[bot] <support@github.com>
4 months ago
Stefan Prodan 64eeda58e6
Merge pull request #5499 from fluxcd/k8s-1.34
Update to Kubernetes v1.34.0 and Go 1.25.0
4 months ago
Stefan Prodan acdf523c54
Build with Go 1.25
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
4 months ago
Stefan Prodan e2abf8e358
Update `flux-cli` image to Alpine 3.22 and kubectl 1.34
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
4 months ago
Stefan Prodan d340f80d75
Update dependencies to Kubernetes v1.34.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
4 months ago
Stefan Prodan 76d36cb429
Merge pull request #5497 from fluxcd/conform-k8s-1.34
Run conformance tests for Kubernetes 1.34.0
4 months ago
Stefan Prodan a7fadcd344
Run conformance tests for Kubernetes 1.34.0
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
4 months ago
Stefan Prodan f19f8611f4
Merge pull request #5480 from fluxcd/rfc-0007-history
[RFC-0007] Implementation history update
4 months ago
Stefan Prodan 8cccb90f90
[RFC-0007] Implementation history update
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
4 months ago
Stefan Prodan 1408bb8294
Merge pull request #5473 from fluxcd/cmd-migrate
Implement `flux migrate` command
4 months ago
Stefan Prodan 45837d2d1b
Implement `flux migrate` command
The migrate command must be run before a Flux minor version upgrade.
The command migrates the Flux custom resources stored in Kubernetes etcd to their latest API version, ensuring the Flux components can continue to function correctly after the upgrade.

Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
4 months ago
Matheus Pimenta ccb9d12927
Merge pull request #5462 from cappyzawa/feat/runtime-secrets-migration
Migrate sourcesecret package to runtime/secrets APIs
5 months ago
cappyzawa 8b95a09319
Migrate sourcesecret package to runtime/secrets APIs
The sourcesecret package now uses pkg/runtime/secrets factory
functions instead of the previous monolithic approach. This
provides standardized secret generation with consistent
validation and error handling across all authentication types.

Signed-off-by: cappyzawa <cappyzawa@gmail.com>
5 months ago
Stefan Prodan 8176d88801
Merge pull request #5440 from pinkavaj/pi-labels
manifests: Add `app.kubernetes.io/part-of: flux` label to controller pods
5 months ago
Jiří Pinkava 2f850743fa Add labels to Pod templates
Ensure also pods contain the relevant labels inherited from pared
Deployment object, this makes it easier to select and filter the pods
using the labels eg. when scraping for metrics.

Signed-off-by: Jiří Pinkava <j-pi@seznam.cz>
5 months ago
Stefan Prodan 4e53b6cb8d
Merge pull request #5460 from fluxcd/ci-token-update
ci: Use GITHUB_TOKEN for API calls in update workflow
5 months ago
Stefan Prodan 0bb2e3929f
ci: Use GITHUB_TOKEN for API calls in update workflow
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
5 months ago
Matheus Pimenta 82b38dfa68
Merge pull request #5455 from fluxcd/upgrade-deps
Upgrade fluxcd/pkg dependencies
5 months ago
Matheus Pimenta b3b404ed30
Upgrade fluxcd/pkg dependencies
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
5 months ago
Stefan Prodan 45990633e6
Merge pull request #5435 from fluxcd/dependabot/github_actions/ci-641206964f
build(deps): bump the ci group across 1 directory with 7 updates
5 months ago
dependabot[bot] 97937c55bf
build(deps): bump the ci group across 1 directory with 7 updates
Bumps the ci group with 7 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [korthout/backport-action](https://github.com/korthout/backport-action) | `3.2.0` | `3.2.1` |
| [fluxcd/pkg](https://github.com/fluxcd/pkg) | `1.17.0` | `1.18.0` |
| [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `3.10.0` | `3.11.1` |
| [ossf/scorecard-action](https://github.com/ossf/scorecard-action) | `2.4.1` | `2.4.2` |
| [github/codeql-action](https://github.com/github/codeql-action) | `3.28.17` | `3.29.2` |
| [anchore/sbom-action](https://github.com/anchore/sbom-action) | `0.19.0` | `0.20.1` |
| [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) | `3.8.2` | `3.9.1` |



Updates `korthout/backport-action` from 3.2.0 to 3.2.1
- [Release notes](https://github.com/korthout/backport-action/releases)
- [Commits](436145e922...0193454f0c)

Updates `fluxcd/pkg` from 1.17.0 to 1.18.0
- [Commits](7e9c75bbb6...3d6f759b76)

Updates `docker/setup-buildx-action` from 3.10.0 to 3.11.1
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](b5ca514318...e468171a9d)

Updates `ossf/scorecard-action` from 2.4.1 to 2.4.2
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](f49aabe0b5...05b42c6244)

Updates `github/codeql-action` from 3.28.17 to 3.29.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](60168efe1c...181d5eefc2)

Updates `anchore/sbom-action` from 0.19.0 to 0.20.1
- [Release notes](https://github.com/anchore/sbom-action/releases)
- [Changelog](https://github.com/anchore/sbom-action/blob/main/RELEASE.md)
- [Commits](9f73021414...9246b90769)

Updates `sigstore/cosign-installer` from 3.8.2 to 3.9.1
- [Release notes](https://github.com/sigstore/cosign-installer/releases)
- [Commits](3454372f43...398d4b0eee)

---
updated-dependencies:
- dependency-name: korthout/backport-action
  dependency-version: 3.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: fluxcd/pkg
  dependency-version: 1.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: docker/setup-buildx-action
  dependency-version: 3.11.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: ci
- dependency-name: github/codeql-action
  dependency-version: 3.29.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: anchore/sbom-action
  dependency-version: 0.20.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
- dependency-name: sigstore/cosign-installer
  dependency-version: 3.9.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: ci
...

Signed-off-by: dependabot[bot] <support@github.com>
5 months ago
Stefan Prodan f79c44ee0a
Merge pull request #5453 from fluxcd/k8s-1.33.2
Update dependencies to Kubernetes 1.33.2
5 months ago
Stefan Prodan 16eb212609
Update dependencies to Kubernetes 1.33.2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
5 months ago
Stefan Prodan 5da5186b3b
Merge pull request #5451 from dgunzy/bump-kustomize-1.18.1
Fix `flux diff kustomization` ignore patterns
5 months ago
Daniel Guns 158618e632 Bump pkg/kustomize 1.18.1
Fixes #4921

Signed-off-by: Daniel Guns <danbguns@gmail.com>
5 months ago
Matheus Pimenta 81bd619abd
Merge pull request #5452 from fluxcd/rfc-0010-kubeconfig
[RFC-0010] Add workload identity support for remote generic clusters
5 months ago
Matheus Pimenta d2aa9fb996
[RFC-0010] Add workload identity support for remote generic clusters
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
5 months ago
Stefan Prodan 315dad8682
Merge pull request #5449 from fluxcd/fix-push-insecure
Fix `flux push artifact` for insecure registries
5 months ago
Stefan Prodan 600ec37524
Fix `flux push artifact` for insecure registries
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
5 months ago
Matheus Pimenta 1af7e08f07
Merge pull request #5443 from fluxcd/update-components
Update toolkit components
5 months ago
fluxcdbot 61a19cac84 Update toolkit components
- kustomize-controller to v1.6.1
  https://github.com/fluxcd/kustomize-controller/blob/v1.6.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
5 months ago
Matheus Pimenta fa8ef5b9d1
Merge pull request #5434 from fluxcd/rfc-0010-kubeconfig
[RFC-0010] Add workload identity support for remote clusters
5 months ago
Matheus Pimenta eb5904fb9d
[RFC-0010] Add workload identity support for remote clusters
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
6 months ago
Matheus Pimenta fda72a014c
Merge pull request #5431 from dgunzy/bump-ssa-v0.49.0
Bump pkg/ssa to v0.49.0 for CABundle validation fix
6 months ago
Daniel Guns f4d6934a6f
Bump pkg/ssa to v0.49.0 for CABundle validation fix
Includes fix for #800: Remove CABundle from CRDs if cert is invalid

Signed-off-by: Daniel Guns <danbguns@gmail.com>
6 months ago
Stefan Prodan 545b338004
Merge pull request #5426 from fluxcd/update-components
Update toolkit components
6 months ago
Matheus Pimenta a8425f50bd
Fix: Prioritize sha2-512 and sha2-256 for ssh-rsa host keys
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
6 months ago
fluxcdbot 24bf751d4d Update toolkit components
- source-controller to v1.6.2
  https://github.com/fluxcd/source-controller/blob/v1.6.2/CHANGELOG.md
- image-automation-controller to v0.41.2
  https://github.com/fluxcd/image-automation-controller/blob/v0.41.2/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
6 months ago
Matheus Pimenta cf157ad8a3
Merge pull request #5421 from dgunzy/promote-image-commands-stable
Promote image CLI commands to stable
6 months ago
Daniel Guns 5a4bc9410b
Promote image CLI commands to stable
Remove experimental status from flux image commands in preparation
for GA release of image automation APIs.

Partial fix for #5411

Signed-off-by: Daniel Guns <danbguns@gmail.com>
6 months ago
Matheus Pimenta de594183bd
Merge pull request #5418 from cappyzawa/cleanup-auth-error-handling
refactor: cleanup GetArtifactRegistryCredentials error handling
6 months ago
cappyzawa 4c343893c5
refactor: cleanup GetArtifactRegistryCredentials error handling
Update fluxcd/pkg/auth to v0.18.0 and simplify error handling for
GetArtifactRegistryCredentials() following the improvements made in
the library.

Similar to fluxcd/image-reflector-controller#786, this removes
unnecessary nil checks as the function now returns errors directly
for unsupported providers.

- Replace authentication code in push_artifact.go with loginWithProvider()
- Remove unnecessary authenticator nil check in oci.go
- Remove unused imports (errors, auth packages)

Signed-off-by: cappyzawa <cappyzawa@gmail.com>
6 months ago
Matheus Pimenta 8ae0aaa46c
Merge pull request #5409 from fluxcd/update-components
Update toolkit components
6 months ago
fluxcdbot 6b3a1134bd Update toolkit components
- source-controller to v1.6.1
  https://github.com/fluxcd/source-controller/blob/v1.6.1/CHANGELOG.md
- image-reflector-controller to v0.35.2
  https://github.com/fluxcd/image-reflector-controller/blob/v0.35.2/CHANGELOG.md
- image-automation-controller to v0.41.1
  https://github.com/fluxcd/image-automation-controller/blob/v0.41.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
6 months ago
Stefan Prodan 40a9b495b2
Merge pull request #5402 from reiSh6phoo9o/feat/configurable_serviceaccountname
Make service-account name configurable in `flux create tenant`
6 months ago
Stefan Bickel 1d34e5355b Make golden tests pass
Signed-off-by: Stefan Bickel <stefan.bickel@cornelsen.de>
6 months ago
Stefan Bickel 00d0e1af25 Add tests and golden files for create tenant
Signed-off-by: Stefan Bickel <stefan.bickel@cornelsen.de>
6 months ago
Stefan Bickel 9f29702f54 Add cli arg --with-service-account
Signed-off-by: Stefan Bickel <stefan.bickel@cornelsen.de>
6 months ago
Stefan Prodan 7626cd0c86
Merge pull request #5407 from cappyzawa/refactor-deprecated-ssa-func
refactor: Use `normalize.UnstructuredList` instead of `ssa.SetNativeKindsDefaults`
6 months ago
cappyzawa 5291902fd7
Use normalize.UnstructuredList instead of ssa.SetNativeKindsDefaults
Signed-off-by: cappyzawa <cappyzawa@gmail.com>
6 months ago
Matheus Pimenta 1757d964c0
Merge pull request #5404 from fluxcd/fix-host-keys
Fix `knownhosts key mismatch` regression bug
6 months ago
Matheus Pimenta 999f61c02e
Upgrade dependencies
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
6 months ago
Matheus Pimenta 5eb43e4566
Merge pull request #5390 from fluxcd/azure-cli-auth
fix: Allow Azure CLI calls in `flux push artifact --provider azure` on DevOps runners
6 months ago
Matheus Pimenta ec3804cc6f
Introduce support for shelling out to Azure binaries in authentication
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
6 months ago
Matheus Pimenta 4c3aed9faf
Merge pull request #5389 from ba-work/add-sparse-checkout
Add sparse checkout to cli
6 months ago
Brock Alberry 06e3047a2f add sparse checkout to cli
Signed-off-by: Brock Alberry <brock.alberry@cse-cst.gc.ca>
6 months ago
Matheus Pimenta 99e6791f4b
Merge pull request #5347 from fluxcd/remove-manifests
Remove credentials sync manifests
6 months ago
Matheus Pimenta 9cad95dda5
Remove credentials sync manifests
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
6 months ago
Matheus Pimenta 76c584e751
Merge pull request #5388 from JIbald/typo
correct small typo
6 months ago
Johannes Ibald cd4244ae65 correct small typo
Signed-off-by: Johannes Ibald <johannes.ibald@etes.de>
6 months ago
Stefan Prodan 1d6137d39d
Merge pull request #5383 from fluxcd/test-image-automation-digest
Add digest pinning to image automation testing
7 months ago
Stefan Prodan be8acc0cfb
Add digest pinning to image automation testing
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
7 months ago
Stefan Prodan 2f5f40d593
Merge pull request #5381 from fluxcd/update-components
Update image-reflector-controller to v0.35.1
7 months ago
fluxcdbot 4172a8a7f9 Update toolkit components
- image-reflector-controller to v0.35.1
  https://github.com/fluxcd/image-reflector-controller/blob/v0.35.1/CHANGELOG.md

Signed-off-by: GitHub <noreply@github.com>
7 months ago
Stefan Prodan 4addf8a528
Merge pull request #5379 from fluxcd/backport-2.6-label
Add backport label for `v2.6.x`
7 months ago
Stefan Prodan 1df7697811
Add backport label for v2.6/x
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
7 months ago

@ -44,12 +44,12 @@
description: Feature request proposals in the RFC format
color: '#D621C3'
aliases: ['area/RFC']
- name: backport:release/v2.3.x
description: To be backported to release/v2.3.x
color: '#ffd700'
- name: backport:release/v2.4.x
description: To be backported to release/v2.4.x
color: '#ffd700'
- name: backport:release/v2.5.x
description: To be backported to release/v2.5.x
color: '#ffd700'
- name: backport:release/v2.6.x
description: To be backported to release/v2.6.x
color: '#ffd700'
- name: backport:release/v2.7.x
description: To be backported to release/v2.7.x
color: '#ffd700'

@ -24,6 +24,6 @@ jobs:
name: action on ${{ matrix.version }}
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup flux
uses: ./action

@ -1,34 +1,13 @@
name: backport
on:
pull_request_target:
types: [closed, labeled]
permissions:
contents: read
permissions: read-all
jobs:
pull-request:
runs-on: ubuntu-latest
backport:
permissions:
contents: write
pull-requests: write
if: github.event.pull_request.state == 'closed' && github.event.pull_request.merged && (github.event_name != 'labeled' || startsWith('backport:', github.event.label.name))
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Create backport PRs
uses: korthout/backport-action@436145e922f9561fc5ea157ff406f21af2d6b363 # v3.2.0
# xref: https://github.com/korthout/backport-action#inputs
with:
# Use token to allow workflows to be triggered for the created PR
github_token: ${{ secrets.BOT_GITHUB_TOKEN }}
# Match labels with a pattern `backport:<target-branch>`
label_pattern: '^backport:([^ ]+)$'
# A bit shorter pull-request title than the default
pull_title: '[${target_branch}] ${pull_title}'
# Simpler PR description than default
pull_description: |-
Automated backport to `${target_branch}`, triggered by a label in #${pull_number}.
contents: write # for reading and creating branches.
pull-requests: write # for creating pull requests against release branches.
uses: fluxcd/gha-workflows/.github/workflows/backport.yaml@v0.4.0
secrets:
github-token: ${{ secrets.BOT_GITHUB_TOKEN }}

@ -9,7 +9,7 @@ permissions:
contents: read
env:
GO_VERSION: 1.24.x
GO_VERSION: 1.25.x
jobs:
conform-kubernetes:
@ -19,13 +19,13 @@ jobs:
matrix:
# Keep this list up-to-date with https://endoflife.date/kubernetes
# Build images with https://github.com/fluxcd/flux-benchmark/actions/workflows/build-kind.yaml
KUBERNETES_VERSION: [1.31.5, 1.32.1, 1.33.0]
KUBERNETES_VERSION: [1.32.1, 1.33.0, 1.34.1]
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: |
@ -42,7 +42,7 @@ jobs:
- name: Setup Kubernetes
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
version: v0.27.0
version: v0.30.0
cluster_name: ${{ steps.prep.outputs.CLUSTER }}
node_image: ghcr.io/fluxcd/kindest/node:v${{ matrix.KUBERNETES_VERSION }}-arm64
- name: Run e2e tests
@ -76,13 +76,13 @@ jobs:
matrix:
# Keep this list up-to-date with https://endoflife.date/kubernetes
# Available versions can be found with "replicated cluster versions"
K3S_VERSION: [ 1.31.8, 1.32.4, 1.33.0 ]
K3S_VERSION: [ 1.32.9, 1.33.5, 1.34.1 ]
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: |
@ -97,7 +97,7 @@ jobs:
KUBECONFIG_PATH="$(git rev-parse --show-toplevel)/bin/kubeconfig.yaml"
echo "kubeconfig-path=${KUBECONFIG_PATH}" >> $GITHUB_OUTPUT
- name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@7e9c75bbb6a47b08c194edefa11d1c436e5bdd9e # main
uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Build
run: make build-dev
- name: Create repository
@ -120,8 +120,7 @@ jobs:
run: TEST_KUBECONFIG=${{ steps.prep.outputs.kubeconfig-path }} make e2e
- name: Run flux bootstrap
run: |
./bin/flux bootstrap git --manifests ./manifests/install/ \
--components-extra=image-reflector-controller,image-automation-controller \
./bin/flux bootstrap git --manifests ./manifests/test/ \
--url=https://github.com/fluxcd-testing/${{ steps.prep.outputs.cluster }} \
--branch=main \
--path=clusters/k3s \
@ -169,13 +168,13 @@ jobs:
strategy:
matrix:
# Keep this list up-to-date with https://endoflife.date/red-hat-openshift
OPENSHIFT_VERSION: [ 4.18.0-okd ]
OPENSHIFT_VERSION: [ 4.19.0-okd, 4.20.0-okd ]
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: |
@ -190,7 +189,7 @@ jobs:
KUBECONFIG_PATH="$(git rev-parse --show-toplevel)/bin/kubeconfig.yaml"
echo "kubeconfig-path=${KUBECONFIG_PATH}" >> $GITHUB_OUTPUT
- name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@7e9c75bbb6a47b08c194edefa11d1c436e5bdd9e # main
uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Build
run: make build-dev
- name: Create repository
@ -212,7 +211,6 @@ jobs:
- name: Run flux bootstrap
run: |
./bin/flux bootstrap git --manifests ./manifests/openshift/ \
--components-extra=image-reflector-controller,image-automation-controller \
--url=https://github.com/fluxcd-testing/${{ steps.prep.outputs.cluster }} \
--branch=main \
--path=clusters/openshift \

@ -22,19 +22,18 @@ permissions:
jobs:
e2e-aks:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./tests/integration
# This job is currently disabled. Remove the false check when Azure subscription is enabled.
if: false && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]'
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]'
steps:
- name: CheckoutD
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: 1.24.x
go-version: 1.25.x
cache-dependency-path: tests/integration/go.sum
- name: Setup Terraform
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
@ -51,7 +50,7 @@ jobs:
- name: Authenticate to Azure
uses: Azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v1.4.6
with:
creds: '{"clientId":"${{ secrets.AZ_ARM_CLIENT_ID }}","clientSecret":"${{ secrets.AZ_ARM_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZ_ARM_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZ_ARM_TENANT_ID }}"}'
creds: '{"clientId":"${{ secrets.ARM_CLIENT_ID }}","clientSecret":"${{ secrets.ARM_CLIENT_SECRET }}","subscriptionId":"${{ secrets.ARM_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.ARM_TENANT_ID }}"}'
- name: Set dynamic variables in .env
run: |
cat > .env <<EOF
@ -61,33 +60,35 @@ jobs:
run: cat .env
- name: Run Azure e2e tests
env:
ARM_CLIENT_ID: ${{ secrets.AZ_ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.AZ_ARM_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZ_ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.AZ_ARM_TENANT_ID }}
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
TF_VAR_azuredevops_org: ${{ secrets.TF_VAR_azuredevops_org }}
TF_VAR_azuredevops_pat: ${{ secrets.TF_VAR_azuredevops_pat }}
TF_VAR_location: ${{ vars.TF_VAR_azure_location }}
GITREPO_SSH_CONTENTS: ${{ secrets.AZURE_GITREPO_SSH_CONTENTS }}
GITREPO_SSH_PUB_CONTENTS: ${{ secrets.AZURE_GITREPO_SSH_PUB_CONTENTS }}
TF_VAR_azure_location: ${{ vars.TF_VAR_azure_location }}
GITREPO_SSH_CONTENTS: ${{ secrets.GIT_SSH_IDENTITY }}
GITREPO_SSH_PUB_CONTENTS: ${{ secrets.GIT_SSH_IDENTITY_PUB }}
run: |
source .env
mkdir -p ./build/ssh
touch ./build/ssh/key
echo $GITREPO_SSH_CONTENTS | base64 -d > build/ssh/key
cat <<EOF > build/ssh/key
$GITREPO_SSH_CONTENTS
EOF
export GITREPO_SSH_PATH=build/ssh/key
touch ./build/ssh/key.pub
echo $GITREPO_SSH_PUB_CONTENTS | base64 -d > ./build/ssh/key.pub
cat <<EOF > build/ssh/key.pub
$GITREPO_SSH_PUB_CONTENTS
EOF
export GITREPO_SSH_PUB_PATH=build/ssh/key.pub
make test-azure
- name: Ensure resource cleanup
if: ${{ always() }}
env:
ARM_CLIENT_ID: ${{ secrets.AZ_ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.AZ_ARM_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZ_ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.AZ_ARM_TENANT_ID }}
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
TF_VAR_azuredevops_org: ${{ secrets.TF_VAR_azuredevops_org }}
TF_VAR_azuredevops_pat: ${{ secrets.TF_VAR_azuredevops_pat }}
TF_VAR_location: ${{ vars.TF_VAR_azure_location }}
TF_VAR_azure_location: ${{ vars.TF_VAR_azure_location }}
run: source .env && make destroy-azure

@ -17,27 +17,27 @@ jobs:
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]'
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: 1.24.x
go-version: 1.25.x
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Setup Kubernetes
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
version: v0.24.0
version: v0.30.0
cluster_name: kind
# The versions below should target the newest Kubernetes version
# Keep this up-to-date with https://endoflife.date/kubernetes
node_image: ghcr.io/fluxcd/kindest/node:v1.33.0-amd64
node_image: ghcr.io/fluxcd/kindest/node:v1.32.1-amd64
kubectl_version: v1.32.0
- name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@7e9c75bbb6a47b08c194edefa11d1c436e5bdd9e # main
uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Setup yq
uses: fluxcd/pkg/actions/yq@7e9c75bbb6a47b08c194edefa11d1c436e5bdd9e # main
uses: fluxcd/pkg/actions/yq@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Build
run: make build-dev
- name: Set outputs
@ -51,7 +51,7 @@ jobs:
echo "test_repo_name=$TEST_REPO_NAME" >> $GITHUB_OUTPUT
- name: bootstrap init
run: |
./bin/flux bootstrap github --manifests ./manifests/install/ \
./bin/flux bootstrap github --manifests ./manifests/test/ \
--owner=fluxcd-testing \
--image-pull-secret=ghcr-auth \
--registry-creds=fluxcd:$GITHUB_TOKEN \
@ -66,7 +66,7 @@ jobs:
kubectl -n flux-system get secret ghcr-auth | grep dockerconfigjson
- name: bootstrap no-op
run: |
./bin/flux bootstrap github --manifests ./manifests/install/ \
./bin/flux bootstrap github --manifests ./manifests/test/ \
--owner=fluxcd-testing \
--image-pull-secret=ghcr-auth \
--repository=${{ steps.vars.outputs.test_repo_name }} \
@ -78,7 +78,7 @@ jobs:
- name: bootstrap customize
run: |
make setup-bootstrap-patch
./bin/flux bootstrap github --manifests ./manifests/install/ \
./bin/flux bootstrap github --manifests ./manifests/test/ \
--owner=fluxcd-testing \
--repository=${{ steps.vars.outputs.test_repo_name }} \
--branch=main \
@ -98,15 +98,18 @@ jobs:
- name: test image automation
run: |
make setup-image-automation
./bin/flux bootstrap github --manifests ./manifests/install/ \
./bin/flux bootstrap github --manifests ./manifests/test/ \
--owner=fluxcd-testing \
--repository=${{ steps.vars.outputs.test_repo_name }} \
--branch=main \
--path=test-cluster \
--read-write-key
./bin/flux reconcile image repository podinfo
./bin/flux reconcile image policy podinfo
./bin/flux reconcile image update flux-system
./bin/flux get images all
./bin/flux -n flux-system events --for ImageUpdateAutomation/flux-system
kubectl -n flux-system get -o yaml ImageUpdateAutomation flux-system
kubectl -n flux-system get -o yaml ImageUpdateAutomation flux-system | \
yq '.status.lastPushCommit | length > 1' | grep 'true'
env:

@ -22,18 +22,18 @@ permissions:
jobs:
e2e-gcp:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./tests/integration
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]'
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: 1.24.x
go-version: 1.25.x
cache-dependency-path: tests/integration/go.sum
- name: Setup Terraform
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
@ -48,19 +48,19 @@ jobs:
env:
SOPS_VER: 3.7.1
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@ba79af03959ebeac9769e648f473a284504d9193 # v2.1.10
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
id: 'auth'
with:
credentials_json: '${{ secrets.FLUX2_E2E_GOOGLE_CREDENTIALS }}'
token_format: 'access_token'
- name: Setup gcloud
uses: google-github-actions/setup-gcloud@77e7a554d41e2ee56fc945c52dfd3f33d12def9a # v2.1.4
uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1
- name: Setup QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Log into us-central1-docker.pkg.dev
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: us-central1-docker.pkg.dev
username: oauth2accesstoken

@ -23,30 +23,30 @@ jobs:
- 5000:5000
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: 1.24.x
go-version: 1.25.x
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Setup Kubernetes
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
version: v0.24.0
version: v0.30.0
cluster_name: kind
wait: 5s
config: .github/kind/config.yaml # disable KIND-net
# The versions below should target the oldest supported Kubernetes version
# Keep this up-to-date with https://endoflife.date/kubernetes
node_image: ghcr.io/fluxcd/kindest/node:v1.31.5-amd64
node_image: ghcr.io/fluxcd/kindest/node:v1.32.1-amd64
kubectl_version: v1.32.0
- name: Setup Calico for network policy
run: |
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/calico.yaml
- name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@7e9c75bbb6a47b08c194edefa11d1c436e5bdd9e # main
uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Run tests
run: make test
- name: Run e2e tests
@ -65,7 +65,7 @@ jobs:
./bin/flux check --pre
- name: flux install --manifests
run: |
./bin/flux install --manifests ./manifests/install/
./bin/flux install --manifests ./manifests/test/
- name: flux create secret
run: |
./bin/flux create secret git git-ssh-test \
@ -238,6 +238,9 @@ jobs:
- name: flux check
run: |
./bin/flux check
- name: flux migrate
run: |
./bin/flux migrate
- name: flux version
run: |
./bin/flux version

@ -19,9 +19,9 @@ jobs:
actions: read
contents: read
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Run analysis
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
@ -34,6 +34,6 @@ jobs:
path: results.sarif
retention-days: 5
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5
with:
sarif_file: results.sarif

@ -20,33 +20,35 @@ jobs:
packages: write # needed for ghcr access
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Unshallow
run: git fetch --prune --unshallow
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: 1.24.x
go-version: 1.25.x
cache: false
- name: Setup QEMU
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Setup Docker Buildx
id: buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Setup Syft
uses: anchore/sbom-action/download-syft@9f7302141466aa6482940f15371237e9d9f4c34a # v0.19.0
uses: anchore/sbom-action/download-syft@f8bdd1d8ac5e901a77a92f111440fdb1b593736b # v0.20.6
- name: Setup Cosign
uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2
uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
with:
cosign-release: v2.6.1 # TODO: remove after Flux 2.8 with support for cosign v3
- name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@7e9c75bbb6a47b08c194edefa11d1c436e5bdd9e # main
uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Login to GitHub Container Registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: fluxcdbot
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: fluxcdbot
password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
@ -59,7 +61,7 @@ jobs:
run: |
kustomize build manifests/crds > all-crds.yaml
- name: Generate OpenAPI JSON schemas from CRDs
uses: fluxcd/pkg/actions/crdjsonschema@7e9c75bbb6a47b08c194edefa11d1c436e5bdd9e # main
uses: fluxcd/pkg/actions/crdjsonschema@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
with:
crd: all-crds.yaml
output: schemas
@ -68,7 +70,7 @@ jobs:
tar -czvf ./output/crd-schemas.tar.gz -C schemas .
- name: Run GoReleaser
id: run-goreleaser
uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
with:
version: latest
args: release --skip=validate
@ -99,24 +101,26 @@ jobs:
id-token: write
packages: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Kustomize
uses: fluxcd/pkg/actions/kustomize@7e9c75bbb6a47b08c194edefa11d1c436e5bdd9e # main
uses: fluxcd/pkg/actions/kustomize@bf02f0a2d612cc07e0892166369fa8f63246aabb # main
- name: Setup Flux CLI
uses: ./action/
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Prepare
id: prep
run: |
VERSION=$(flux version --client | awk '{ print $NF }')
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Login to GHCR
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: fluxcdbot
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to DockerHub
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: fluxcdbot
password: ${{ secrets.DOCKER_FLUXCD_PASSWORD }}
@ -144,7 +148,9 @@ jobs:
--path="./flux-system" \
--source=${{ github.repositoryUrl }} \
--revision="${{ github.ref_name }}@sha1:${{ github.sha }}"
- uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2
- uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
with:
cosign-release: v2.6.1 # TODO: remove after Flux 2.8 with support for cosign v3
- name: Sign manifests
env:
COSIGN_EXPERIMENTAL: 1

@ -1,5 +1,4 @@
name: scan
on:
workflow_dispatch:
push:
@ -8,46 +7,13 @@ on:
branches: [ 'main', 'release/**' ]
schedule:
- cron: '18 10 * * 3'
permissions:
contents: read
permissions: read-all
jobs:
scan-fossa:
runs-on: ubuntu-latest
if: github.actor != 'dependabot[bot]'
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Run FOSSA scan and upload build data
uses: fossa-contrib/fossa-action@3d2ef181b1820d6dcd1972f86a767d18167fa19b # v3.0.1
with:
# FOSSA Push-Only API Token
fossa-api-key: 5ee8bf422db1471e0bcf2bcb289185de
github-token: ${{ github.token }}
scan-codeql:
runs-on: ubuntu-latest
analyze:
permissions:
security-events: write
if: github.actor != 'dependabot[bot]'
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version-file: 'go.mod'
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Initialize CodeQL
uses: github/codeql-action/init@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
with:
languages: go
# xref: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# xref: https://codeql.github.com/codeql-query-help/go/
queries: security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
contents: read # for reading the repository code.
security-events: write # for uploading the CodeQL analysis results.
uses: fluxcd/gha-workflows/.github/workflows/code-scan.yaml@v0.4.0
secrets:
github-token: ${{ secrets.GITHUB_TOKEN }}
fossa-token: ${{ secrets.FOSSA_TOKEN }}

@ -6,23 +6,12 @@ on:
- main
paths:
- .github/labels.yaml
permissions:
contents: read
permissions: read-all
jobs:
labels:
name: Run sync
runs-on: ubuntu-latest
sync-labels:
permissions:
issues: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: EndBug/label-sync@52074158190acb45f3077f9099fea818aa43f97a # v2.3.3
with:
# Configuration file
config-file: |
https://raw.githubusercontent.com/fluxcd/community/main/.github/standard-labels.yaml
.github/labels.yaml
# Strictly declarative
delete-other-labels: true
contents: read # for reading the labels file.
issues: write # for creating and updating labels.
uses: fluxcd/gha-workflows/.github/workflows/labels-sync.yaml@v0.4.0
secrets:
github-token: ${{ secrets.GITHUB_TOKEN }}

@ -2,8 +2,6 @@ name: update
on:
workflow_dispatch:
schedule:
- cron: "0 * * * *"
push:
branches: [main]
@ -18,24 +16,37 @@ jobs:
pull-requests: write
steps:
- name: Check out code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: 1.24.x
go-version: 1.25.x
cache-dependency-path: |
**/go.sum
**/go.mod
- name: Update component versions
id: update
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_BODY=$(mktemp)
bump_version() {
local LATEST_VERSION=$(curl -s https://api.github.com/repos/fluxcd/$1/releases | jq -r 'sort_by(.published_at) | .[-1] | .tag_name')
local LATEST_VERSION=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/fluxcd/$1/releases | jq -r 'sort_by(.published_at) | .[-1] | .tag_name')
if [[ "$LATEST_VERSION" == *"-rc"* ]]; then
echo "Skipping release candidate version for $1: $LATEST_VERSION"
return
fi
local CTRL_VERSION=$(sed -n "s/.*$1\/releases\/download\/\(.*\)\/.*/\1/p;n" manifests/bases/$1/kustomization.yaml)
local CRD_VERSION=$(sed -n "s/.*$1\/releases\/download\/\(.*\)\/.*/\1/p" manifests/crds/kustomization.yaml)
local MOD_VERSION=$(go list -m -f '{{ .Version }}' "github.com/fluxcd/$1/api")
local API_PKG="github.com/fluxcd/$1/api"
if [[ "$1" == "source-watcher" ]]; then
API_PKG="github.com/fluxcd/$1/api/v2"
fi
local MOD_VERSION=$(go list -m -f '{{ .Version }}' "$API_PKG")
local changed=false
@ -50,7 +61,7 @@ jobs:
fi
if [[ "${MOD_VERSION}" != "${LATEST_VERSION}" ]]; then
go mod edit -require="github.com/fluxcd/$1/api@${LATEST_VERSION}"
go mod edit -require="$API_PKG@${LATEST_VERSION}"
make tidy
changed=true
fi
@ -69,6 +80,7 @@ jobs:
bump_version notification-controller
bump_version image-reflector-controller
bump_version image-automation-controller
bump_version source-watcher
# diff change
git diff

@ -88,22 +88,6 @@ brews:
generate_completions_from_executable(bin/"flux", "completion")
test: |
system "#{bin}/flux --version"
publishers:
- name: aur-pkg-bin
env:
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
cmd: |
.github/aur/flux-bin/publish.sh {{ .Version }}
- name: aur-pkg-scm
env:
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
cmd: |
.github/aur/flux-scm/publish.sh {{ .Version }}
- name: aur-pkg-go
env:
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
cmd: |
.github/aur/flux-go/publish.sh {{ .Version }}
dockers:
- image_templates:
- 'fluxcd/flux-cli:{{ .Tag }}-amd64'

@ -49,7 +49,8 @@ you might want to take a look at the [introductory talk and demo](https://www.yo
This project is composed of:
- [flux2](https://github.com/fluxcd/flux2): The Flux CLI
- [source-manager](https://github.com/fluxcd/source-controller): Kubernetes operator for managing sources (Git and Helm repositories, S3-compatible Buckets)
- [source-controller](https://github.com/fluxcd/source-controller): Kubernetes operator for managing sources (Git, OCI and Helm repositories, S3-compatible Buckets)
- [source-watcher](https://github.com/fluxcd/source-watcher): Kubernetes operator for advanced source composition and decomposition patterns
- [kustomize-controller](https://github.com/fluxcd/kustomize-controller): Kubernetes operator for building GitOps pipelines with Kustomize
- [helm-controller](https://github.com/fluxcd/helm-controller): Kubernetes operator for building GitOps pipelines with Helm
- [notification-controller](https://github.com/fluxcd/notification-controller): Kubernetes operator for handling inbound and outbound events
@ -67,10 +68,9 @@ for source changes.
Prerequisites:
* go >= 1.24
* go >= 1.25
* kubectl >= 1.30
* kustomize >= 5.0
* coreutils (on Mac OS)
Install the [controller-runtime/envtest](https://github.com/kubernetes-sigs/controller-runtime/tree/master/tools/setup-envtest) binaries with:

@ -1,16 +1,16 @@
FROM alpine:3.21 AS builder
FROM alpine:3.22 AS builder
RUN apk add --no-cache ca-certificates curl
ARG ARCH=linux/amd64
ARG KUBECTL_VER=1.33.0
ARG KUBECTL_VER=1.34.1
RUN curl -sL https://dl.k8s.io/release/v${KUBECTL_VER}/bin/${ARCH}/kubectl \
-o /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl
RUN kubectl version --client=true
FROM alpine:3.21 AS flux-cli
FROM alpine:3.22 AS flux-cli
RUN apk add --no-cache ca-certificates

@ -17,8 +17,8 @@ rwildcard=$(foreach d,$(wildcard $(addsuffix *,$(1))),$(call rwildcard,$(d)/,$(2
all: test build
tidy:
go mod tidy -compat=1.24
cd tests/integration && go mod tidy -compat=1.24
go mod tidy -compat=1.25
cd tests/integration && go mod tidy -compat=1.25
fmt:
go fmt ./...

@ -52,12 +52,14 @@ guides](https://fluxcd.io/flux/gitops-toolkit/source-watcher/).
### Components
- [Source Controller](https://fluxcd.io/flux/components/source/)
- [Source Controllers](https://fluxcd.io/flux/components/source/)
- [GitRepository CRD](https://fluxcd.io/flux/components/source/gitrepositories/)
- [OCIRepository CRD](https://fluxcd.io/flux/components/source/ocirepositories/)
- [HelmRepository CRD](https://fluxcd.io/flux/components/source/helmrepositories/)
- [HelmChart CRD](https://fluxcd.io/flux/components/source/helmcharts/)
- [Bucket CRD](https://fluxcd.io/flux/components/source/buckets/)
- [ExternalArtifact CRD](https://fluxcd.io/flux/components/source/externalartifacts/)
- [ArtifactGenerator CRD](https://fluxcd.io/flux/components/source/artifactgenerators/)
- [Kustomize Controller](https://fluxcd.io/flux/components/kustomize/)
- [Kustomization CRD](https://fluxcd.io/flux/components/kustomize/kustomizations/)
- [Helm Controller](https://fluxcd.io/flux/components/helm/)

@ -16,23 +16,24 @@ inputs:
description: "Alternative location for the Flux binary, defaults to path relative to $RUNNER_TOOL_CACHE."
required: false
token:
description: "Token used to authentication against the GitHub.com API. Defaults to the token from the GitHub context of the workflow."
description: "Token used to authenticate against the GitHub.com API."
required: false
runs:
using: composite
steps:
- name: "Download the binary to the runner's cache dir"
shell: bash
env:
VERSION: "${{ inputs.version }}"
FLUX_TOOL_DIR: "${{ inputs.bindir }}"
TOKEN: "${{ inputs.token }}"
run: |
VERSION=${{ inputs.version }}
TOKEN=${{ inputs.token }}
if [[ -z "$TOKEN" ]]; then
TOKEN=${{ github.token }}
fi
if [[ -z "$VERSION" ]] || [[ "$VERSION" = "latest" ]]; then
if [[ "${TOKEN}" != '' ]]; then
VERSION=$(curl -fsSL -H "Authorization: token ${TOKEN}" https://api.github.com/repos/fluxcd/flux2/releases/latest | grep tag_name | cut -d '"' -f 4)
else
VERSION=$(curl -w "%{url_effective}\n" -IsSL https://github.com/fluxcd/flux2/releases/latest -o /dev/null | sed 's$^.*/$$')
fi
fi
if [[ -z "$VERSION" ]]; then
echo "Unable to determine Flux CLI version"
@ -59,7 +60,6 @@ runs:
FLUX_EXEC_FILE="${FLUX_EXEC_FILE}.exe"
fi
FLUX_TOOL_DIR=${{ inputs.bindir }}
if [[ -z "$FLUX_TOOL_DIR" ]]; then
FLUX_TOOL_DIR="${RUNNER_TOOL_CACHE}/flux2/${VERSION}/${OS}/${ARCH}"
fi

@ -0,0 +1,57 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"sigs.k8s.io/controller-runtime/pkg/client"
swapi "github.com/fluxcd/source-watcher/api/v2/v1beta1"
)
// swapi.ArtifactGenerator
var artifactGeneratorType = apiType{
kind: swapi.ArtifactGeneratorKind,
humanKind: "artifactgenerator",
groupVersion: swapi.GroupVersion,
}
type artifactGeneratorAdapter struct {
*swapi.ArtifactGenerator
}
func (h artifactGeneratorAdapter) asClientObject() client.Object {
return h.ArtifactGenerator
}
func (h artifactGeneratorAdapter) deepCopyClientObject() client.Object {
return h.ArtifactGenerator.DeepCopy()
}
// swapi.ArtifactGeneratorList
type artifactGeneratorListAdapter struct {
*swapi.ArtifactGeneratorList
}
func (h artifactGeneratorListAdapter) asClientList() client.ObjectList {
return h.ArtifactGeneratorList
}
func (h artifactGeneratorListAdapter) len() int {
return len(h.ArtifactGeneratorList.Items)
}

@ -97,7 +97,7 @@ func init() {
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.defaultComponents, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values")
bootstrapCmd.PersistentFlags().StringSliceVar(&bootstrapArgs.extraComponents, "components-extra", nil,
"list of components in addition to those supplied or defaulted, accepts values such as 'image-reflector-controller,image-automation-controller'")
"list of components in addition to those supplied or defaulted, accepts values such as 'image-reflector-controller,image-automation-controller,source-watcher'")
bootstrapCmd.PersistentFlags().StringVar(&bootstrapArgs.registry, "registry", "ghcr.io/fluxcd",
"container registry where the Flux controller images are published")

@ -42,7 +42,7 @@ import (
var bootstrapGitLabCmd = &cobra.Command{
Use: "gitlab",
Short: "Deploy Flux on a cluster connected to a GitLab repository",
Long: `The bootstrap gitlab command creates the GitLab repository if it doesn't exists and
Long: `The bootstrap gitlab command creates the GitLab repository if it doesn't exist and
commits the Flux manifests to the specified branch.
Then it configures the target cluster to synchronize with that repository.
If the Flux components are present on the cluster,

@ -60,7 +60,7 @@ type checkFlags struct {
}
var kubernetesConstraints = []string{
">=1.31.0-0",
">=1.32.0-0",
}
var checkArgs checkFlags

@ -94,6 +94,13 @@ var createHelmReleaseCmd = &cobra.Command{
--source=HelmRepository/podinfo \
--chart=podinfo
# Create a HelmRelease with custom storage namespace for hub-and-spoke model
flux create hr podinfo \
--target-namespace=production \
--storage-namespace=fluxcd-system \
--source=HelmRepository/podinfo \
--chart=podinfo
# Create a HelmRelease using a source from a different namespace
flux create hr podinfo \
--namespace=default \
@ -127,6 +134,7 @@ type helmReleaseFlags struct {
chartVersion string
chartRef string
targetNamespace string
storageNamespace string
createNamespace bool
valuesFiles []string
valuesFrom []string
@ -150,6 +158,7 @@ func init() {
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.chartVersion, "chart-version", "", "Helm chart version, accepts a semver range (ignored for charts from GitRepository sources)")
createHelmReleaseCmd.Flags().StringSliceVar(&helmReleaseArgs.dependsOn, "depends-on", nil, "HelmReleases that must be ready before this release can be installed, supported formats '<name>' and '<namespace>/<name>'")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.targetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.storageNamespace, "storage-namespace", "", "namespace to store the Helm release, defaults to the target namespace")
createHelmReleaseCmd.Flags().BoolVar(&helmReleaseArgs.createNamespace, "create-target-namespace", false, "create the target namespace if it does not exist")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.saName, "service-account", "", "the name of the service account to impersonate when reconciling this HelmRelease")
createHelmReleaseCmd.Flags().StringVar(&helmReleaseArgs.reconcileStrategy, "reconcile-strategy", "ChartVersion", "the reconcile strategy for helm chart created by the helm release(accepted values: Revision and ChartRevision)")
@ -165,10 +174,18 @@ func init() {
func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
name := args[0]
if helmReleaseArgs.storageNamespace == "" && helmReleaseArgs.targetNamespace != "" {
helmReleaseArgs.storageNamespace = helmReleaseArgs.targetNamespace
}
if helmReleaseArgs.chart == "" && helmReleaseArgs.chartRef == "" {
return fmt.Errorf("chart or chart-ref is required")
}
if helmReleaseArgs.chart != "" && helmReleaseArgs.chartRef != "" {
return fmt.Errorf("cannot use --chart in combination with --chart-ref")
}
sourceLabels, err := parseLabels()
if err != nil {
return err
@ -191,15 +208,27 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
},
Spec: helmv2.HelmReleaseSpec{
ReleaseName: helmReleaseArgs.name,
DependsOn: utils.MakeDependsOn(helmReleaseArgs.dependsOn),
Interval: metav1.Duration{
Duration: createArgs.interval,
},
TargetNamespace: helmReleaseArgs.targetNamespace,
StorageNamespace: helmReleaseArgs.storageNamespace,
Suspend: false,
},
}
if len(helmReleaseArgs.dependsOn) > 0 {
ls := utils.MakeDependsOn(helmReleaseArgs.dependsOn)
hrDependsOn := make([]helmv2.DependencyReference, 0, len(ls))
for _, d := range ls {
hrDependsOn = append(hrDependsOn, helmv2.DependencyReference{
Name: d.Name,
Namespace: d.Namespace,
})
}
helmRelease.Spec.DependsOn = hrDependsOn
}
switch {
case helmReleaseArgs.chart != "":
helmRelease.Spec.Chart = &helmv2.HelmChartTemplate{
@ -234,7 +263,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
if helmReleaseArgs.kubeConfigSecretRef != "" {
helmRelease.Spec.KubeConfig = &meta.KubeConfigReference{
SecretRef: meta.SecretKeyReference{
SecretRef: &meta.SecretKeyReference{
Name: helmReleaseArgs.kubeConfigSecretRef,
},
}

@ -42,6 +42,11 @@ func TestCreateHelmRelease(t *testing.T) {
args: "create helmrelease podinfo --export",
assert: assertError("chart or chart-ref is required"),
},
{
name: "chart and chartRef used in combination",
args: "create helmrelease podinfo --chart podinfo --chart-ref foobar/podinfo --export",
assert: assertError("cannot use --chart in combination with --chart-ref"),
},
{
name: "unknown source kind",
args: "create helmrelease podinfo --source foobar/podinfo --chart podinfo --export",

@ -29,18 +29,18 @@ import (
"github.com/fluxcd/pkg/apis/meta"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var createImagePolicyCmd = &cobra.Command{
Use: "policy [name]",
Short: "Create or update an ImagePolicy object",
Long: withPreviewNote(`The create image policy command generates an ImagePolicy resource.
Long: `The create image policy command generates an ImagePolicy resource.
An ImagePolicy object calculates a "latest image" given an image
repository and a policy, e.g., semver.
The image that sorts highest according to the policy is recorded in
the status of the object.`),
the status of the object.`,
Example: ` # Create an ImagePolicy to select the latest stable release
flux create image policy podinfo \
--image-ref=podinfo \
@ -81,12 +81,6 @@ func init() {
createImageCmd.AddCommand(createImagePolicyCmd)
}
// getObservedGeneration is implemented here, since it's not
// (presently) needed elsewhere.
func (obj imagePolicyAdapter) getObservedGeneration() int64 {
return obj.ImagePolicy.Status.ObservedGeneration
}
func createImagePolicyRun(cmd *cobra.Command, args []string) error {
objectName := args[0]

@ -26,14 +26,14 @@ import (
"github.com/fluxcd/pkg/apis/meta"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var createImageRepositoryCmd = &cobra.Command{
Use: "repository [name]",
Short: "Create or update an ImageRepository object",
Long: withPreviewNote(`The create image repository command generates an ImageRepository resource.
An ImageRepository object specifies an image repository to scan.`),
Long: `The create image repository command generates an ImageRepository resource.
An ImageRepository object specifies an image repository to scan.`,
Example: ` # Create an ImageRepository object to scan the alpine image repository:
flux create image repository alpine-repo --image alpine --interval 20m

@ -22,16 +22,16 @@ import (
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
)
var createImageUpdateCmd = &cobra.Command{
Use: "update [name]",
Short: "Create or update an ImageUpdateAutomation object",
Long: withPreviewNote(`The create image update command generates an ImageUpdateAutomation resource.
Long: `The create image update command generates an ImageUpdateAutomation resource.
An ImageUpdateAutomation object specifies an automated update to images
mentioned in YAMLs in a git repository.`),
mentioned in YAMLs in a git repository.`,
Example: ` # Configure image updates for the main repository created by flux bootstrap
flux create image update flux-system \
--git-repo-ref=flux-system \

@ -153,7 +153,6 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
Labels: kslabels,
},
Spec: kustomizev1.KustomizationSpec{
DependsOn: utils.MakeDependsOn(kustomizationArgs.dependsOn),
Interval: metav1.Duration{
Duration: createArgs.interval,
},
@ -169,9 +168,21 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
},
}
if len(kustomizationArgs.dependsOn) > 0 {
ls := utils.MakeDependsOn(kustomizationArgs.dependsOn)
ksDependsOn := make([]kustomizev1.DependencyReference, 0, len(ls))
for _, d := range ls {
ksDependsOn = append(ksDependsOn, kustomizev1.DependencyReference{
Name: d.Name,
Namespace: d.Namespace,
})
}
kustomization.Spec.DependsOn = ksDependsOn
}
if kustomizationArgs.kubeConfigSecretRef != "" {
kustomization.Spec.KubeConfig = &meta.KubeConfigReference{
SecretRef: meta.SecretKeyReference{
SecretRef: &meta.SecretKeyReference{
Name: kustomizationArgs.kubeConfigSecretRef,
},
}

@ -172,7 +172,7 @@ func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)
}
secret, err := sourcesecret.Generate(opts)
secret, err := sourcesecret.GenerateGit(opts)
if err != nil {
return err
}

@ -99,7 +99,7 @@ func createSecretGitHubAppCmdRun(cmd *cobra.Command, args []string) error {
opts.GitHubAppBaseURL = secretGitHubAppArgs.baseURL
}
secret, err := sourcesecret.Generate(opts)
secret, err := sourcesecret.GenerateGitHubApp(opts)
if err != nil {
return err
}

@ -83,10 +83,12 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
}
var certFile, keyFile []byte
if secretHelmArgs.tlsCrtFile != "" && secretHelmArgs.tlsKeyFile != "" {
if secretHelmArgs.tlsCrtFile != "" {
if certFile, err = os.ReadFile(secretHelmArgs.tlsCrtFile); err != nil {
return fmt.Errorf("failed to read cert file: %w", err)
}
}
if secretHelmArgs.tlsKeyFile != "" {
if keyFile, err = os.ReadFile(secretHelmArgs.tlsKeyFile); err != nil {
return fmt.Errorf("failed to read key file: %w", err)
}
@ -102,7 +104,7 @@ func createSecretHelmCmdRun(cmd *cobra.Command, args []string) error {
TLSCrt: certFile,
TLSKey: keyFile,
}
secret, err := sourcesecret.Generate(opts)
secret, err := sourcesecret.GenerateHelm(opts)
if err != nil {
return err
}

@ -132,7 +132,7 @@ func createSecretNotationCmdRun(cmd *cobra.Command, args []string) error {
VerificationCrts: caCerts,
TrustPolicy: policy,
}
secret, err := sourcesecret.Generate(opts)
secret, err := sourcesecret.GenerateNotation(opts)
if err != nil {
return err
}

@ -92,7 +92,7 @@ func createSecretOCICmdRun(cmd *cobra.Command, args []string) error {
Username: secretOCIArgs.username,
}
secret, err := sourcesecret.Generate(opts)
secret, err := sourcesecret.GenerateOCI(opts)
if err != nil {
return err
}

@ -83,7 +83,7 @@ func createSecretProxyCmdRun(cmd *cobra.Command, args []string) error {
Username: secretProxyArgs.username,
Password: secretProxyArgs.password,
}
secret, err := sourcesecret.Generate(opts)
secret, err := sourcesecret.GenerateProxy(opts)
if err != nil {
return err
}

@ -84,16 +84,18 @@ func createSecretTLSCmdRun(cmd *cobra.Command, args []string) error {
}
}
if secretTLSArgs.tlsCrtFile != "" && secretTLSArgs.tlsKeyFile != "" {
if secretTLSArgs.tlsCrtFile != "" {
if opts.TLSCrt, err = os.ReadFile(secretTLSArgs.tlsCrtFile); err != nil {
return fmt.Errorf("failed to read cert file: %w", err)
}
}
if secretTLSArgs.tlsKeyFile != "" {
if opts.TLSKey, err = os.ReadFile(secretTLSArgs.tlsKeyFile); err != nil {
return fmt.Errorf("failed to read key file: %w", err)
}
}
secret, err := sourcesecret.Generate(opts)
secret, err := sourcesecret.GenerateTLS(opts)
if err != nil {
return err
}

@ -19,7 +19,6 @@ package main
import (
"context"
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
@ -114,12 +113,6 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
return err
}
tmpDir, err := os.MkdirTemp("", name)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
var ignorePaths *string
if len(sourceBucketArgs.ignorePaths) > 0 {
ignorePathsStr := strings.Join(sourceBucketArgs.ignorePaths, "\n")

@ -63,6 +63,7 @@ type sourceGitFlags struct {
recurseSubmodules bool
silent bool
ignorePaths []string
sparseCheckoutPaths []string
}
var createSourceGitCmd = &cobra.Command{
@ -154,6 +155,7 @@ func init() {
"when enabled, configures the GitRepository source to initialize and include Git submodules in the artifact it produces")
createSourceGitCmd.Flags().BoolVarP(&sourceGitArgs.silent, "silent", "s", false, "assumes the deploy key is already setup, skips confirmation")
createSourceGitCmd.Flags().StringSliceVar(&sourceGitArgs.ignorePaths, "ignore-paths", nil, "set paths to ignore in git resource (can specify multiple paths with commas: path1,path2)")
createSourceGitCmd.Flags().StringSliceVar(&sourceGitArgs.sparseCheckoutPaths, "sparse-checkout-paths", nil, "set paths to sparse checkout in git resource (can specify multiple paths with commas: path1,path2)")
createSourceCmd.AddCommand(createSourceGitCmd)
}
@ -189,12 +191,6 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("specifying a CA file is not supported for Git over SSH")
}
tmpDir, err := os.MkdirTemp("", name)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
sourceLabels, err := parseLabels()
if err != nil {
return err
@ -220,6 +216,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
RecurseSubmodules: sourceGitArgs.recurseSubmodules,
Reference: &sourcev1.GitRepositoryRef{},
Ignore: ignorePaths,
SparseCheckout: sourceGitArgs.sparseCheckoutPaths,
},
}
@ -302,7 +299,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
secretOpts.Username = sourceGitArgs.username
secretOpts.Password = sourceGitArgs.password
}
secret, err := sourcesecret.Generate(secretOpts)
secret, err := sourcesecret.GenerateGit(secretOpts)
if err != nil {
return err
}

@ -87,7 +87,7 @@ func (r *reconciler) conditionFunc() (bool, error) {
}
func TestCreateSourceGitExport(t *testing.T) {
var command = "create source git podinfo --url=https://github.com/stefanprodan/podinfo --branch=master --ignore-paths .cosign,non-existent-dir/ -n default --interval 1m --export --timeout=" + testTimeout.String()
var command = "create source git podinfo --url=https://github.com/stefanprodan/podinfo --branch=master --sparse-checkout-paths .cosign,non-existent-dir/ --ignore-paths .cosign,non-existent-dir/ -n default --interval 1m --export --timeout=" + testTimeout.String()
cases := []struct {
name string
@ -101,7 +101,7 @@ func TestCreateSourceGitExport(t *testing.T) {
},
{
name: "no args",
args: "create secret git",
args: "create source git --url=https://github.com/stefanprodan/podinfo",
assert: assertError("name is required"),
},
{
@ -204,12 +204,13 @@ func TestCreateSourceGit(t *testing.T) {
ObservedGeneration: repo.GetGeneration(),
}
apimeta.SetStatusCondition(&repo.Status.Conditions, newCondition)
repo.Status.Artifact = &sourcev1.Artifact{
repo.Status.Artifact = &meta.Artifact{
Path: "some-path",
Revision: "v1",
LastUpdateTime: metav1.Time{
Time: time.Now(),
},
Digest: "sha256:1234567890abcdef",
}
repo.Status.ObservedGeneration = repo.GetGeneration()
},

@ -114,12 +114,6 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
return err
}
tmpDir, err := os.MkdirTemp("", name)
if err != nil {
return err
}
defer os.RemoveAll(tmpDir)
if _, err := url.Parse(sourceHelmArgs.url); err != nil {
return fmt.Errorf("url parse failed: %w", err)
}
@ -202,7 +196,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
TLSKey: keyFile,
ManifestFile: sourcesecret.MakeDefaultOptions().ManifestFile,
}
secret, err := sourcesecret.Generate(secretOpts)
secret, err := sourcesecret.GenerateHelm(secretOpts)
if err != nil {
return err
}

@ -21,7 +21,6 @@ import (
"context"
"fmt"
"github.com/fluxcd/flux2/v2/internal/utils"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
@ -32,6 +31,8 @@ import (
"k8s.io/apimachinery/pkg/util/validation"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/v2/internal/utils"
)
var createTenantCmd = &cobra.Command{
@ -59,6 +60,8 @@ const (
type tenantFlags struct {
namespaces []string
clusterRole string
account string
skipNamespace bool
}
var tenantArgs tenantFlags
@ -66,6 +69,8 @@ var tenantArgs tenantFlags
func init() {
createTenantCmd.Flags().StringSliceVar(&tenantArgs.namespaces, "with-namespace", nil, "namespace belonging to this tenant")
createTenantCmd.Flags().StringVar(&tenantArgs.clusterRole, "cluster-role", "cluster-admin", "cluster role of the tenant role binding")
createTenantCmd.Flags().StringVar(&tenantArgs.account, "with-service-account", "", "service account belonging to this tenant")
createTenantCmd.Flags().BoolVar(&tenantArgs.skipNamespace, "skip-namespace", false, "skip namespace creation (namespace must exist already)")
createCmd.AddCommand(createTenantCmd)
}
@ -107,9 +112,17 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
}
namespaces = append(namespaces, namespace)
accountName := tenant
if tenantArgs.account != "" {
accountName = tenantArgs.account
}
if err := validation.IsQualifiedName(accountName); len(err) > 0 {
return fmt.Errorf("invalid service-account name '%s': %v", accountName, err)
}
account := corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: tenant,
Name: accountName,
Namespace: ns,
Labels: objLabels,
},
@ -131,7 +144,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
},
{
Kind: "ServiceAccount",
Name: tenant,
Name: accountName,
Namespace: ns,
},
},
@ -146,7 +159,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
if createArgs.export {
for i := range tenantArgs.namespaces {
if err := exportTenant(namespaces[i], accounts[i], roleBindings[i]); err != nil {
if err := exportTenant(namespaces[i], accounts[i], roleBindings[i], tenantArgs.skipNamespace); err != nil {
return err
}
}
@ -162,10 +175,12 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
}
for i := range tenantArgs.namespaces {
if !tenantArgs.skipNamespace {
logger.Actionf("applying namespace %s", namespaces[i].Name)
if err := upsertNamespace(ctx, kubeClient, namespaces[i]); err != nil {
return err
}
}
logger.Actionf("applying service account %s", accounts[i].Name)
if err := upsertServiceAccount(ctx, kubeClient, accounts[i]); err != nil {
@ -273,19 +288,24 @@ func upsertRoleBinding(ctx context.Context, kubeClient client.Client, roleBindin
return nil
}
func exportTenant(namespace corev1.Namespace, account corev1.ServiceAccount, roleBinding rbacv1.RoleBinding) error {
func exportTenant(namespace corev1.Namespace, account corev1.ServiceAccount, roleBinding rbacv1.RoleBinding, skipNamespace bool) error {
var data []byte
var err error
if !skipNamespace {
namespace.TypeMeta = metav1.TypeMeta{
APIVersion: "v1",
Kind: "Namespace",
}
data, err := yaml.Marshal(namespace)
data, err = yaml.Marshal(namespace)
if err != nil {
return err
}
fmt.Println("---")
data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1)
fmt.Println(resourceToString(data))
printlnStdout("---")
printlnStdout(resourceToString(data))
}
account.TypeMeta = metav1.TypeMeta{
APIVersion: "v1",
@ -295,10 +315,10 @@ func exportTenant(namespace corev1.Namespace, account corev1.ServiceAccount, rol
if err != nil {
return err
}
fmt.Println("---")
data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1)
fmt.Println(resourceToString(data))
printlnStdout("---")
printlnStdout(resourceToString(data))
roleBinding.TypeMeta = metav1.TypeMeta{
APIVersion: "rbac.authorization.k8s.io/v1",
@ -309,8 +329,8 @@ func exportTenant(namespace corev1.Namespace, account corev1.ServiceAccount, rol
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
printlnStdout("---")
printlnStdout(resourceToString(data))
return nil
}

@ -0,0 +1,73 @@
//go:build e2e
// +build e2e
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"testing"
)
func TestCreateTenant(t *testing.T) {
tests := []struct {
name string
args string
assert assertFunc
}{
{
name: "no args",
args: "create tenant",
assert: assertError("name is required"),
},
{
name: "no namespace",
args: "create tenant dev-team --cluster-role=cluster-admin",
assert: assertError("with-namespace is required"),
},
{
name: "basic tenant",
args: "create tenant dev-team --with-namespace=apps --cluster-role=cluster-admin --export",
assert: assertGoldenFile("./testdata/create_tenant/tenant-basic.yaml"),
},
{
name: "tenant with custom serviceaccount",
args: "create tenant dev-team --with-namespace=apps --cluster-role=cluster-admin --with-service-account=flux-tenant --export",
assert: assertGoldenFile("./testdata/create_tenant/tenant-with-service-account.yaml"),
},
{
name: "tenant with custom cluster role",
args: "create tenant dev-team --with-namespace=apps --cluster-role=custom-role --export",
assert: assertGoldenFile("./testdata/create_tenant/tenant-with-cluster-role.yaml"),
},
{
name: "tenant with skip namespace",
args: "create tenant dev-team --with-namespace=apps --cluster-role=cluster-admin --skip-namespace --export",
assert: assertGoldenFile("./testdata/create_tenant/tenant-with-skip-namespace.yaml"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := cmdTestCase{
args: tt.args,
assert: tt.assert,
}
cmd.runTestCmd(t)
})
}
}

@ -40,7 +40,10 @@ WARNING: This command will print sensitive information if Kubernetes Secrets are
flux debug hr podinfo --show-status
# Export the final values of a Helm release composed from referred ConfigMaps and Secrets
flux debug hr podinfo --show-values > values.yaml`,
flux debug hr podinfo --show-values > values.yaml
# Print the reconciliation history of a Helm release
flux debug hr podinfo --show-history`,
RunE: debugHelmReleaseCmdRun,
Args: cobra.ExactArgs(1),
ValidArgsFunction: resourceNamesCompletionFunc(helmv2.GroupVersion.WithKind(helmv2.HelmReleaseKind)),
@ -49,6 +52,7 @@ WARNING: This command will print sensitive information if Kubernetes Secrets are
type debugHelmReleaseFlags struct {
showStatus bool
showValues bool
showHistory bool
}
var debugHelmReleaseArgs debugHelmReleaseFlags
@ -56,15 +60,25 @@ var debugHelmReleaseArgs debugHelmReleaseFlags
func init() {
debugHelmReleaseCmd.Flags().BoolVar(&debugHelmReleaseArgs.showStatus, "show-status", false, "print the status of the Helm release")
debugHelmReleaseCmd.Flags().BoolVar(&debugHelmReleaseArgs.showValues, "show-values", false, "print the final values of the Helm release")
debugHelmReleaseCmd.Flags().BoolVar(&debugHelmReleaseArgs.showHistory, "show-history", false, "print the reconciliation history of the Helm release")
debugCmd.AddCommand(debugHelmReleaseCmd)
}
func debugHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
name := args[0]
if (!debugHelmReleaseArgs.showStatus && !debugHelmReleaseArgs.showValues) ||
(debugHelmReleaseArgs.showStatus && debugHelmReleaseArgs.showValues) {
return fmt.Errorf("either --show-status or --show-values must be set")
flagsSet := 0
if debugHelmReleaseArgs.showStatus {
flagsSet++
}
if debugHelmReleaseArgs.showValues {
flagsSet++
}
if debugHelmReleaseArgs.showHistory {
flagsSet++
}
if flagsSet != 1 {
return fmt.Errorf("exactly one of --show-status, --show-values, or --show-history must be set")
}
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
@ -109,5 +123,20 @@ func debugHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
rootCmd.Print(string(values))
}
if debugHelmReleaseArgs.showHistory {
if len(hr.Status.History) == 0 {
hr.Status.History = helmv2.Snapshots{}
}
history, err := yaml.Marshal(hr.Status.History)
if err != nil {
return err
}
rootCmd.Println("# History documentation: https://fluxcd.io/flux/components/helm/helmreleases/#history")
rootCmd.Print(string(history))
return nil
}
return nil
}

@ -56,6 +56,18 @@ func TestDebugHelmRelease(t *testing.T) {
"testdata/debug_helmrelease/values-from.golden.yaml",
tmpl,
},
{
"debug history",
"debug helmrelease test-with-history --show-history --show-status=false",
"testdata/debug_helmrelease/history.golden.yaml",
tmpl,
},
{
"debug history empty",
"debug helmrelease test-values-inline --show-history --show-status=false",
"testdata/debug_helmrelease/history-empty.golden.yaml",
tmpl,
},
}
for _, tt := range cases {

@ -24,6 +24,7 @@ import (
"strings"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/kustomize"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -44,7 +45,10 @@ WARNING: This command will print sensitive information if Kubernetes Secrets are
flux debug ks podinfo --show-status
# Export the final variables used for post-build substitutions composed from referred ConfigMaps and Secrets
flux debug ks podinfo --show-vars > vars.env`,
flux debug ks podinfo --show-vars > vars.env
# Print the reconciliation history of a Flux Kustomization
flux debug ks podinfo --show-history`,
RunE: debugKustomizationCmdRun,
Args: cobra.ExactArgs(1),
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
@ -53,6 +57,7 @@ WARNING: This command will print sensitive information if Kubernetes Secrets are
type debugKustomizationFlags struct {
showStatus bool
showVars bool
showHistory bool
}
var debugKustomizationArgs debugKustomizationFlags
@ -60,15 +65,25 @@ var debugKustomizationArgs debugKustomizationFlags
func init() {
debugKustomizationCmd.Flags().BoolVar(&debugKustomizationArgs.showStatus, "show-status", false, "print the status of the Flux Kustomization")
debugKustomizationCmd.Flags().BoolVar(&debugKustomizationArgs.showVars, "show-vars", false, "print the final vars of the Flux Kustomization in dot env format")
debugKustomizationCmd.Flags().BoolVar(&debugKustomizationArgs.showHistory, "show-history", false, "print the reconciliation history of the Flux Kustomization")
debugCmd.AddCommand(debugKustomizationCmd)
}
func debugKustomizationCmdRun(cmd *cobra.Command, args []string) error {
name := args[0]
if (!debugKustomizationArgs.showStatus && !debugKustomizationArgs.showVars) ||
(debugKustomizationArgs.showStatus && debugKustomizationArgs.showVars) {
return fmt.Errorf("either --show-status or --show-vars must be set")
flagsSet := 0
if debugKustomizationArgs.showStatus {
flagsSet++
}
if debugKustomizationArgs.showVars {
flagsSet++
}
if debugKustomizationArgs.showHistory {
flagsSet++
}
if flagsSet != 1 {
return fmt.Errorf("exactly one of --show-status, --show-vars, or --show-history must be set")
}
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
@ -130,5 +145,20 @@ func debugKustomizationCmdRun(cmd *cobra.Command, args []string) error {
}
}
if debugKustomizationArgs.showHistory {
if len(ks.Status.History) == 0 {
ks.Status.History = meta.History{}
}
history, err := yaml.Marshal(ks.Status.History)
if err != nil {
return err
}
rootCmd.Println("# History documentation: https://fluxcd.io/flux/components/kustomize/kustomizations/#history")
rootCmd.Print(string(history))
return nil
}
return nil
}

@ -55,6 +55,17 @@ func TestDebugKustomization(t *testing.T) {
"debug ks test-from --show-vars --show-status=false",
"testdata/debug_kustomization/vars-from.golden.env",
tmpl,
}, {
"debug history",
"debug ks test-with-history --show-history --show-status=false",
"testdata/debug_kustomization/history.golden.yaml",
tmpl,
},
{
"debug history empty",
"debug ks test --show-history --show-status=false",
"testdata/debug_kustomization/history-empty.golden.yaml",
tmpl,
},
}

@ -19,13 +19,13 @@ package main
import (
"github.com/spf13/cobra"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var deleteImagePolicyCmd = &cobra.Command{
Use: "policy [name]",
Short: "Delete an ImagePolicy object",
Long: withPreviewNote(`The delete image policy command deletes the given ImagePolicy from the cluster.`),
Long: `The delete image policy command deletes the given ImagePolicy from the cluster.`,
Example: ` # Delete an image policy
flux delete image policy alpine3.x`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)),

@ -19,13 +19,13 @@ package main
import (
"github.com/spf13/cobra"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var deleteImageRepositoryCmd = &cobra.Command{
Use: "repository [name]",
Short: "Delete an ImageRepository object",
Long: withPreviewNote("The delete image repository command deletes the given ImageRepository from the cluster."),
Long: "The delete image repository command deletes the given ImageRepository from the cluster.",
Example: ` # Delete an image repository
flux delete image repository alpine`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImageRepositoryKind)),

@ -19,13 +19,13 @@ package main
import (
"github.com/spf13/cobra"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1"
)
var deleteImageUpdateCmd = &cobra.Command{
Use: "update [name]",
Short: "Delete an ImageUpdateAutomation object",
Long: withPreviewNote(`The delete image update command deletes the given ImageUpdateAutomation from the cluster.`),
Long: `The delete image update command deletes the given ImageUpdateAutomation from the cluster.`,
Example: ` # Delete an image update automation
flux delete image update latest-images`,
ValidArgsFunction: resourceNamesCompletionFunc(autov1.GroupVersion.WithKind(autov1.ImageUpdateAutomationKind)),

@ -93,7 +93,7 @@ func diffArtifactCmdRun(cmd *cobra.Command, args []string) error {
if diffArtifactArgs.provider.String() != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials")
opt, err := loginWithProvider(ctx, url, diffArtifactArgs.provider.String())
opt, _, err := loginWithProvider(ctx, url, diffArtifactArgs.provider.String())
if err != nil {
return fmt.Errorf("error during login with provider: %w", err)
}

@ -27,6 +27,7 @@ import (
"github.com/fluxcd/flux2/v2/internal/build"
"github.com/fluxcd/pkg/ssa"
"github.com/fluxcd/pkg/ssa/normalize"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@ -151,7 +152,7 @@ func createObjectFromFile(objectFile string, templateValues map[string]string, t
t.Fatalf("Error decoding yaml file '%s': %v", objectFile, err)
}
if err := ssa.SetNativeKindsDefaults(clientObjects); err != nil {
if err := normalize.UnstructuredList(clientObjects); err != nil {
t.Fatalf("Error setting native kinds defaults for '%s': %v", objectFile, err)
}

@ -20,7 +20,6 @@ package main
import (
"context"
"fmt"
"os"
"sort"
"strings"
"time"
@ -40,12 +39,13 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
helmv2 "github.com/fluxcd/helm-controller/api/v2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
swapi "github.com/fluxcd/source-watcher/api/v2/v1beta1"
"github.com/fluxcd/flux2/v2/internal/utils"
"github.com/fluxcd/flux2/v2/pkg/printers"
@ -112,7 +112,12 @@ func eventsCmdRun(cmd *cobra.Command, args []string) error {
}
var diffRefNs bool
clientListOpts := []client.ListOption{client.InNamespace(*kubeconfigArgs.Namespace)}
// Build the base list options. When --all-namespaces is set we must NOT constrain the
// query to a single namespace, otherwise we silently return a partial result set.
clientListOpts := []client.ListOption{}
if !eventArgs.allNamespaces {
clientListOpts = append(clientListOpts, client.InNamespace(*kubeconfigArgs.Namespace))
}
var refListOpts [][]client.ListOption
if eventArgs.forSelector != "" {
kind, name := getKindNameFromSelector(eventArgs.forSelector)
@ -246,7 +251,7 @@ func eventsCmdWatchRun(ctx context.Context, kubeclient client.WithWatch, listOpt
hdr = getHeaders(showNs)
firstIteration = false
}
return printers.TablePrinter(hdr).Print(os.Stdout, [][]string{rows})
return printers.TablePrinter(hdr).Print(rootCmd.OutOrStdout(), [][]string{rows})
}
for _, refOpts := range refListOpts {
@ -450,6 +455,7 @@ var fluxKindMap = refMap{
sourcev1.HelmRepositoryKind: {gvk: sourcev1.GroupVersion.WithKind(sourcev1.HelmRepositoryKind)},
autov1.ImageUpdateAutomationKind: {gvk: autov1.GroupVersion.WithKind(autov1.ImageUpdateAutomationKind)},
imagev1.ImageRepositoryKind: {gvk: imagev1.GroupVersion.WithKind(imagev1.ImageRepositoryKind)},
swapi.ArtifactGeneratorKind: {gvk: swapi.GroupVersion.WithKind(swapi.ArtifactGeneratorKind)},
}
func ignoreEvent(e corev1.Event) bool {

@ -140,7 +140,7 @@ spec:
address: https://hooks.slack.com/services/mock
type: slack
---
apiVersion: image.toolkit.fluxcd.io/v1beta2
apiVersion: image.toolkit.fluxcd.io/v1
kind: ImagePolicy
metadata:
name: podinfo

@ -109,13 +109,13 @@ func (export exportCommand) run(cmd *cobra.Command, args []string) error {
return nil
}
func printExport(export interface{}) error {
func printExport(export any) error {
data, err := yaml.Marshal(export)
if err != nil {
return err
}
rootCmd.Println("---")
rootCmd.Println(resourceToString(data))
printlnStdout("---")
printlnStdout(resourceToString(data))
return nil
}

@ -0,0 +1,31 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
)
var exportArtifactCmd = &cobra.Command{
Use: "artifact",
Short: "Export artifact objects",
Long: `The export artifact sub-commands export artifacts objects in YAML format.`,
}
func init() {
exportCmd.AddCommand(exportArtifactCmd)
}

@ -0,0 +1,72 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
swapi "github.com/fluxcd/source-watcher/api/v2/v1beta1"
)
var exportArtifactGeneratorCmd = &cobra.Command{
Use: "generator [name]",
Short: "Export ArtifactGenerator resources in YAML format",
Long: "The export artifact generator command exports one or all ArtifactGenerator resources in YAML format.",
Example: ` # Export all ArtifactGenerator resources
flux export artifact generator --all > artifact-generators.yaml
# Export a specific generator
flux export artifact generator my-generator > my-generator.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(swapi.GroupVersion.WithKind(swapi.ArtifactGeneratorKind)),
RunE: exportCommand{
object: artifactGeneratorAdapter{&swapi.ArtifactGenerator{}},
list: artifactGeneratorListAdapter{&swapi.ArtifactGeneratorList{}},
}.run,
}
func init() {
exportArtifactCmd.AddCommand(exportArtifactGeneratorCmd)
}
// Export returns an ArtifactGenerator value which has
// extraneous information stripped out.
func exportArtifactGenerator(item *swapi.ArtifactGenerator) interface{} {
gvk := swapi.GroupVersion.WithKind(swapi.ArtifactGeneratorKind)
export := swapi.ArtifactGenerator{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: item.Name,
Namespace: item.Namespace,
Labels: item.Labels,
Annotations: item.Annotations,
},
Spec: item.Spec,
}
return export
}
func (ex artifactGeneratorAdapter) export() interface{} {
return exportArtifactGenerator(ex.ArtifactGenerator)
}
func (ex artifactGeneratorListAdapter) exportItem(i int) interface{} {
return exportArtifactGenerator(&ex.ArtifactGeneratorList.Items[i])
}

@ -20,13 +20,13 @@ import (
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var exportImagePolicyCmd = &cobra.Command{
Use: "policy [name]",
Short: "Export ImagePolicy resources in YAML format",
Long: withPreviewNote("The export image policy command exports one or all ImagePolicy resources in YAML format."),
Long: "The export image policy command exports one or all ImagePolicy resources in YAML format.",
Example: ` # Export all ImagePolicy resources
flux export image policy --all > image-policies.yaml

@ -20,13 +20,13 @@ import (
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var exportImageRepositoryCmd = &cobra.Command{
Use: "repository [name]",
Short: "Export ImageRepository resources in YAML format",
Long: withPreviewNote("The export image repository command exports one or all ImageRepository resources in YAML format."),
Long: "The export image repository command exports one or all ImageRepository resources in YAML format.",
Example: ` # Export all ImageRepository resources
flux export image repository --all > image-repositories.yaml

@ -20,13 +20,13 @@ import (
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1"
)
var exportImageUpdateCmd = &cobra.Command{
Use: "update [name]",
Short: "Export ImageUpdateAutomation resources in YAML format",
Long: withPreviewNote("The export image update command exports one or all ImageUpdateAutomation resources in YAML format."),
Long: "The export image update command exports one or all ImageUpdateAutomation resources in YAML format.",
Example: ` # Export all ImageUpdateAutomation resources
flux export image update --all > updates.yaml

@ -0,0 +1,84 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
)
var exportSourceExternalCmd = &cobra.Command{
Use: "external [name]",
Short: "Export ExternalArtifact sources in YAML format",
Long: "The export source external command exports one or all ExternalArtifact sources in YAML format.",
Example: ` # Export all ExternalArtifact sources
flux export source external --all > sources.yaml
# Export a specific ExternalArtifact
flux export source external my-artifact > source.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(sourcev1.GroupVersion.WithKind(sourcev1.ExternalArtifactKind)),
RunE: exportWithSecretCommand{
list: externalArtifactListAdapter{&sourcev1.ExternalArtifactList{}},
object: externalArtifactAdapter{&sourcev1.ExternalArtifact{}},
}.run,
}
func init() {
exportSourceCmd.AddCommand(exportSourceExternalCmd)
}
func exportExternalArtifact(source *sourcev1.ExternalArtifact) any {
gvk := sourcev1.GroupVersion.WithKind(sourcev1.ExternalArtifactKind)
export := sourcev1.ExternalArtifact{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: source.Name,
Namespace: source.Namespace,
Labels: source.Labels,
Annotations: source.Annotations,
},
Spec: source.Spec,
}
return export
}
func getExternalArtifactSecret(source *sourcev1.ExternalArtifact) *types.NamespacedName {
// ExternalArtifact does not have a secretRef in its spec, this satisfies the interface
return nil
}
func (ex externalArtifactAdapter) secret() *types.NamespacedName {
return getExternalArtifactSecret(ex.ExternalArtifact)
}
func (ex externalArtifactListAdapter) secretItem(i int) *types.NamespacedName {
return getExternalArtifactSecret(&ex.ExternalArtifactList.Items[i])
}
func (ex externalArtifactAdapter) export() any {
return exportExternalArtifact(ex.ExternalArtifact)
}
func (ex externalArtifactListAdapter) exportItem(i int) any {
return exportExternalArtifact(&ex.ExternalArtifactList.Items[i])
}

@ -110,6 +110,12 @@ func TestExport(t *testing.T) {
"testdata/export/bucket.yaml",
tmpl,
},
{
"source external",
"export source external flux-system",
"testdata/export/external-artifact.yaml",
tmpl,
},
}
for _, tt := range cases {

@ -0,0 +1,32 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
)
var getArtifactCmd = &cobra.Command{
Use: "artifacts",
Aliases: []string{"artifact"},
Short: "Get artifact object status",
Long: `The get artifact sub-commands print the status of artifact objects.`,
}
func init() {
getCmd.AddCommand(getArtifactCmd)
}

@ -0,0 +1,93 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"strconv"
"github.com/spf13/cobra"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"k8s.io/apimachinery/pkg/runtime"
swapi "github.com/fluxcd/source-watcher/api/v2/v1beta1"
)
var getArtifactGeneratorCmd = &cobra.Command{
Use: "generators",
Aliases: []string{"generator"},
Short: "Get artifact generator statuses",
Long: `The get artifact generator command prints the statuses of the resources.`,
Example: ` # List all ArtifactGenerators and their status
flux get artifact generators`,
ValidArgsFunction: resourceNamesCompletionFunc(swapi.GroupVersion.WithKind(swapi.ArtifactGeneratorKind)),
RunE: func(cmd *cobra.Command, args []string) error {
get := getCommand{
apiType: receiverType,
list: artifactGeneratorListAdapter{&swapi.ArtifactGeneratorList{}},
funcMap: make(typeMap),
}
err := get.funcMap.registerCommand(get.apiType.kind, func(obj runtime.Object) (summarisable, error) {
o, ok := obj.(*swapi.ArtifactGenerator)
if !ok {
return nil, fmt.Errorf("impossible to cast type %#v generator", obj)
}
sink := artifactGeneratorListAdapter{&swapi.ArtifactGeneratorList{
Items: []swapi.ArtifactGenerator{
*o,
}}}
return sink, nil
})
if err != nil {
return err
}
if err := get.run(cmd, args); err != nil {
return err
}
return nil
},
}
func init() {
getArtifactCmd.AddCommand(getArtifactGeneratorCmd)
}
func (s artifactGeneratorListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind),
cases.Title(language.English).String(strconv.FormatBool(item.IsDisabled())), status, msg)
}
func (s artifactGeneratorListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Suspended", "Ready", "Message"}
if includeNamespace {
return append(namespaceHeader, headers...)
}
return headers
}
func (s artifactGeneratorListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
item := s.Items[i]
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
}

@ -19,14 +19,14 @@ package main
import (
"github.com/spf13/cobra"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var getImageAllCmd = &cobra.Command{
Use: "all",
Short: "Get all image statuses",
Long: withPreviewNote("The get image sub-commands print the statuses of all image objects."),
Long: "The get image sub-commands print the statuses of all image objects.",
Example: ` # List all image objects in a namespace
flux get images all --namespace=flux-system

@ -22,13 +22,13 @@ import (
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var getImagePolicyCmd = &cobra.Command{
Use: "policy",
Short: "Get ImagePolicy status",
Long: withPreviewNote("The get image policy command prints the status of ImagePolicy objects."),
Long: "The get image policy command prints the status of ImagePolicy objects.",
Example: ` # List all image policies and their status
flux get image policy
@ -74,11 +74,16 @@ func init() {
func (s imagePolicyListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := s.Items[i]
status, msg := statusAndMessage(item.Status.Conditions)
return append(nameColumns(&item, includeNamespace, includeKind), item.Status.LatestImage, status, msg)
var image, tag string
if ref := item.Status.LatestRef; ref != nil {
image = ref.Name
tag = ref.Tag
}
return append(nameColumns(&item, includeNamespace, includeKind), image, tag, status, msg)
}
func (s imagePolicyListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Latest image", "Ready", "Message"}
headers := []string{"Name", "Image", "Tag", "Ready", "Message"}
if includeNamespace {
return append(namespaceHeader, headers...)
}

@ -26,13 +26,13 @@ import (
"golang.org/x/text/language"
"k8s.io/apimachinery/pkg/runtime"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var getImageRepositoryCmd = &cobra.Command{
Use: "repository",
Short: "Get ImageRepository status",
Long: withPreviewNote("The get image repository command prints the status of ImageRepository objects."),
Long: "The get image repository command prints the status of ImageRepository objects.",
Example: ` # List all image repositories and their status
flux get image repository

@ -26,13 +26,13 @@ import (
"golang.org/x/text/language"
"k8s.io/apimachinery/pkg/runtime"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1"
)
var getImageUpdateCmd = &cobra.Command{
Use: "update",
Short: "Get ImageUpdateAutomation status",
Long: withPreviewNote("The get image update command prints the status of ImageUpdateAutomation objects."),
Long: "The get image update command prints the status of ImageUpdateAutomation objects.",
Example: ` # List all image update automation object and their status
flux get image update

@ -59,6 +59,10 @@ var getSourceAllCmd = &cobra.Command{
apiType: helmChartType,
list: &helmChartListAdapter{&sourcev1.HelmChartList{}},
},
{
apiType: externalArtifactType,
list: &externalArtifactListAdapter{&sourcev1.ExternalArtifactList{}},
},
}
for _, c := range allSourceCmd {

@ -0,0 +1,108 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
"github.com/fluxcd/flux2/v2/internal/utils"
)
var getSourceExternalCmd = &cobra.Command{
Use: "external",
Short: "Get ExternalArtifact source statuses",
Long: `The get sources external command prints the status of the ExternalArtifact sources.`,
Example: ` # List all ExternalArtifacts and their status
flux get sources external
# List ExternalArtifacts from all namespaces
flux get sources external --all-namespaces`,
ValidArgsFunction: resourceNamesCompletionFunc(sourcev1.GroupVersion.WithKind(sourcev1.ExternalArtifactKind)),
RunE: func(cmd *cobra.Command, args []string) error {
get := getCommand{
apiType: externalArtifactType,
list: &externalArtifactListAdapter{&sourcev1.ExternalArtifactList{}},
funcMap: make(typeMap),
}
err := get.funcMap.registerCommand(get.apiType.kind, func(obj runtime.Object) (summarisable, error) {
o, ok := obj.(*sourcev1.ExternalArtifact)
if !ok {
return nil, fmt.Errorf("impossible to cast type %#v to ExternalArtifact", obj)
}
sink := &externalArtifactListAdapter{&sourcev1.ExternalArtifactList{
Items: []sourcev1.ExternalArtifact{
*o,
}}}
return sink, nil
})
if err != nil {
return err
}
if err := get.run(cmd, args); err != nil {
return err
}
return nil
},
}
func init() {
getSourceCmd.AddCommand(getSourceExternalCmd)
}
func (a *externalArtifactListAdapter) summariseItem(i int, includeNamespace bool, includeKind bool) []string {
item := a.Items[i]
var revision string
if item.Status.Artifact != nil {
revision = item.Status.Artifact.Revision
}
status, msg := statusAndMessage(item.Status.Conditions)
revision = utils.TruncateHex(revision)
msg = utils.TruncateHex(msg)
var source string
if item.Spec.SourceRef != nil {
source = fmt.Sprintf("%s/%s/%s",
item.Spec.SourceRef.Kind,
item.Spec.SourceRef.Namespace,
item.Spec.SourceRef.Name)
}
return append(nameColumns(&item, includeNamespace, includeKind),
revision, source, status, msg)
}
func (a externalArtifactListAdapter) headers(includeNamespace bool) []string {
headers := []string{"Name", "Revision", "Source", "Ready", "Message"}
if includeNamespace {
headers = append([]string{"Namespace"}, headers...)
}
return headers
}
func (a externalArtifactListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
item := a.Items[i]
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
}

@ -17,10 +17,12 @@ limitations under the License.
package main
import (
"fmt"
"sigs.k8s.io/controller-runtime/pkg/client"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
// These are general-purpose adapters for attaching methods to, for
@ -77,6 +79,34 @@ func (a imagePolicyAdapter) asClientObject() client.Object {
return a.ImagePolicy
}
func (a imagePolicyAdapter) deepCopyClientObject() client.Object {
return a.ImagePolicy.DeepCopy()
}
func (a imagePolicyAdapter) isStatic() bool {
return false
}
func (a imagePolicyAdapter) lastHandledReconcileRequest() string {
return a.Status.GetLastHandledReconcileRequest()
}
func (a imagePolicyAdapter) isSuspended() bool {
return a.Spec.Suspend
}
func (a imagePolicyAdapter) setSuspended() {
a.Spec.Suspend = true
}
func (a imagePolicyAdapter) successMessage() string {
return fmt.Sprintf("selected ref %s", a.Status.LatestRef.String())
}
func (a imagePolicyAdapter) setUnsuspended() {
a.Spec.Suspend = false
}
// imagev1.ImagePolicyList
type imagePolicyListAdapter struct {
@ -91,6 +121,18 @@ func (a imagePolicyListAdapter) len() int {
return len(a.ImagePolicyList.Items)
}
func (a imagePolicyListAdapter) resumeItem(i int) resumable {
return &imagePolicyAdapter{&a.ImagePolicyList.Items[i]}
}
func (obj imagePolicyAdapter) getObservedGeneration() int64 {
return obj.ImagePolicy.Status.ObservedGeneration
}
func (a imagePolicyListAdapter) item(i int) suspendable {
return &imagePolicyAdapter{&a.ImagePolicyList.Items[i]}
}
// autov1.ImageUpdateAutomation
var imageUpdateAutomationType = apiType{

@ -53,6 +53,18 @@ func TestImageScanning(t *testing.T) {
"get image policy podinfo-regex",
"testdata/image/get_image_policy_regex.golden",
},
{
"suspend image policy podinfo-semver",
"testdata/image/suspend_image_policy.golden",
},
{
"resume image policy podinfo-semver",
"testdata/image/resume_image_policy.golden",
},
{
"reconcile image policy podinfo-semver",
"testdata/image/reconcile_image_policy.golden",
},
}
for _, tc := range cases {

@ -83,7 +83,7 @@ type installFlags struct {
force bool
}
var installArgs = NewInstallFlags()
var installArgs = newInstallFlags()
func init() {
installCmd.Flags().BoolVar(&installArgs.export, "export", false,
@ -93,7 +93,7 @@ func init() {
installCmd.Flags().StringSliceVar(&installArgs.defaultComponents, "components", rootArgs.defaults.Components,
"list of components, accepts comma-separated values")
installCmd.Flags().StringSliceVar(&installArgs.extraComponents, "components-extra", nil,
"list of components in addition to those supplied or defaulted, accepts values such as 'image-reflector-controller,image-automation-controller'")
"list of components in addition to those supplied or defaulted, accepts values such as 'image-reflector-controller,image-automation-controller,source-watcher'")
installCmd.Flags().StringVar(&installArgs.manifestsPath, "manifests", "", "path to the manifest directory")
installCmd.Flags().StringVar(&installArgs.registry, "registry", rootArgs.defaults.Registry,
"container registry where the toolkit images are published")
@ -115,9 +115,14 @@ func init() {
rootCmd.AddCommand(installCmd)
}
func NewInstallFlags() installFlags {
func newInstallFlags() installFlags {
return installFlags{
logLevel: flags.LogLevel(rootArgs.defaults.LogLevel),
defaultComponents: rootArgs.defaults.Components,
registry: rootArgs.defaults.Registry,
watchAllNamespaces: rootArgs.defaults.WatchAllNamespaces,
networkPolicy: rootArgs.defaults.NetworkPolicy,
clusterDomain: rootArgs.defaults.ClusterDomain,
}
}
@ -195,10 +200,13 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
}
if installArgs.export {
fmt.Print(manifest.Content)
return nil
_, err = rootCmd.OutOrStdout().Write([]byte(manifest.Content))
return err
} else if rootArgs.verbose {
fmt.Print(manifest.Content)
_, err = rootCmd.OutOrStdout().Write([]byte(manifest.Content))
if err != nil {
return err
}
}
logger.Successf("manifests build completed")
@ -238,7 +246,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("install failed: %w", err)
}
fmt.Fprintln(os.Stderr, applyOutput)
rootCmd.Println(applyOutput)
if opts.ImagePullSecret != "" && opts.RegistryCredential != "" {
logger.Actionf("generating image pull secret %s", opts.ImagePullSecret)
@ -250,7 +258,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
Username: credentials[0],
Password: credentials[1],
}
imagePullSecret, err := sourcesecret.Generate(secretOpts)
imagePullSecret, err := sourcesecret.GenerateOCI(secretOpts)
if err != nil {
return fmt.Errorf("install failed: %w", err)
}

@ -1,5 +1,5 @@
/*
Copyright 2022 The Flux authors
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -16,7 +16,17 @@ limitations under the License.
package main
import "testing"
import (
"strings"
"testing"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
ssautil "github.com/fluxcd/pkg/ssa/utils"
"github.com/fluxcd/flux2/v2/pkg/manifestgen/install"
)
func TestInstall(t *testing.T) {
// The pointer to kubeconfigArgs.Namespace is shared across
@ -59,3 +69,43 @@ func TestInstall(t *testing.T) {
})
}
}
func TestInstall_ComponentsExtra(t *testing.T) {
g := NewWithT(t)
command := "install --export --components-extra=" +
strings.Join(install.MakeDefaultOptions().ComponentsExtra, ",")
output, err := executeCommand(command)
g.Expect(err).NotTo(HaveOccurred())
manifests, err := ssautil.ReadObjects(strings.NewReader(output))
g.Expect(err).NotTo(HaveOccurred())
foundImageAutomation := false
foundImageReflector := false
foundSourceWatcher := false
foundExternalArtifact := false
for _, obj := range manifests {
if obj.GetKind() == "Deployment" && obj.GetName() == "image-automation-controller" {
foundImageAutomation = true
}
if obj.GetKind() == "Deployment" && obj.GetName() == "image-reflector-controller" {
foundImageReflector = true
}
if obj.GetKind() == "Deployment" && obj.GetName() == "source-watcher" {
foundSourceWatcher = true
}
if obj.GetKind() == "Deployment" &&
(obj.GetName() == "kustomize-controller" || obj.GetName() == "helm-controller") {
containers, _, _ := unstructured.NestedSlice(obj.Object, "spec", "template", "spec", "containers")
g.Expect(containers).ToNot(BeEmpty())
args, _, _ := unstructured.NestedSlice(containers[0].(map[string]any), "args")
g.Expect(args).To(ContainElement("--feature-gates=ExternalArtifact=true"))
foundExternalArtifact = true
}
}
g.Expect(foundImageAutomation).To(BeTrue(), "image-automation-controller deployment not found")
g.Expect(foundImageReflector).To(BeTrue(), "image-reflector-controller deployment not found")
g.Expect(foundSourceWatcher).To(BeTrue(), "source-watcher deployment not found")
g.Expect(foundExternalArtifact).To(BeTrue(), "ExternalArtifact feature gate not found")
}

@ -52,7 +52,7 @@ var listArtifactsCmd = &cobra.Command{
Long: `The list command fetches the tags and their metadata from a remote OCI repository.
The command can read the credentials from '~/.docker/config.json' but they can also be passed with --creds. It can also login to a supported provider with the --provider flag.`,
Example: ` # List the artifacts stored in an OCI repository
flux list artifact oci://ghcr.io/org/config/app
flux list artifacts oci://ghcr.io/org/config/app
`,
RunE: listArtifactsCmdRun,
}
@ -85,7 +85,7 @@ func listArtifactsCmdRun(cmd *cobra.Command, args []string) error {
if listArtifactArgs.provider.String() != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials")
ociOpt, err := loginWithProvider(ctx, url, listArtifactArgs.provider.String())
ociOpt, _, err := loginWithProvider(ctx, url, listArtifactArgs.provider.String())
if err != nil {
return fmt.Errorf("error during login with provider: %w", err)
}

@ -180,7 +180,7 @@ func main() {
// This is required because controller-runtime expects its consumers to
// set a logger through log.SetLogger within 30 seconds of the program's
// initalization. If not set, the entire debug stack is printed as an
// initialization. If not set, the entire debug stack is printed as an
// error, see: https://github.com/kubernetes-sigs/controller-runtime/blob/ed8be90/pkg/log/log.go#L59
// Since we have our own logging and don't care about controller-runtime's
// logger, we configure it's logger to do nothing.
@ -225,7 +225,9 @@ func configureDefaultNamespace() {
func readPasswordFromStdin(prompt string) (string, error) {
var out string
var err error
fmt.Fprint(os.Stdout, prompt)
if _, err := fmt.Fprint(os.Stdout, prompt); err != nil {
return "", fmt.Errorf("failed to write prompt: %w", err)
}
stdinFD := int(os.Stdin.Fd())
if term.IsTerminal(stdinFD) {
var inBytes []byte
@ -247,3 +249,8 @@ While we try our best to not introduce breaking changes, they may occur when
we adapt to new features and/or find better ways to facilitate what it does.`
return fmt.Sprintf("%s\n\n%s", strings.TrimSpace(desc), previewNote)
}
// printlnStdout prints the given text to stdout with a newline.
func printlnStdout(txt string) {
_, _ = rootCmd.OutOrStdout().Write([]byte(txt + "\n"))
}

@ -447,6 +447,7 @@ func resetCmdArgs() {
imagePolicyArgs = imagePolicyFlags{}
imageRepoArgs = imageRepoFlags{}
imageUpdateArgs = imageUpdateFlags{}
installArgs = newInstallFlags()
kustomizationArgs = NewKustomizationFlags()
receiverArgs = receiverFlags{}
resumeArgs = ResumeFlags{}

@ -0,0 +1,691 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"context"
"encoding/json"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"github.com/fluxcd/pkg/ssa"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
helmv2 "github.com/fluxcd/helm-controller/api/v2"
imageautov1 "github.com/fluxcd/image-automation-controller/api/v1"
imageautov1b2 "github.com/fluxcd/image-automation-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
imagev1b2 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
swv1b1 "github.com/fluxcd/source-watcher/api/v2/v1beta1"
"github.com/fluxcd/flux2/v2/internal/utils"
)
// APIVersions holds the mapping of GroupKinds to their respective
// latest API versions for a specific Flux version.
type APIVersions struct {
FluxVersion string
LatestVersions map[schema.GroupKind]string
}
// TODO: Update this mapping when new Flux minor versions are released!
// latestAPIVersions contains the latest API versions for each GroupKind
// for each supported Flux version. We maintain the latest two minor versions.
var latestAPIVersions = []APIVersions{
{
FluxVersion: "2.7",
LatestVersions: map[schema.GroupKind]string{
// source-controller
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.BucketKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.GitRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.OCIRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.HelmRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.HelmChartKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.ExternalArtifactKind}: sourcev1.GroupVersion.Version,
// kustomize-controller
{Group: kustomizev1.GroupVersion.Group, Kind: kustomizev1.KustomizationKind}: kustomizev1.GroupVersion.Version,
// helm-controller
{Group: helmv2.GroupVersion.Group, Kind: helmv2.HelmReleaseKind}: helmv2.GroupVersion.Version,
// notification-controller
{Group: notificationv1.GroupVersion.Group, Kind: notificationv1.ReceiverKind}: notificationv1.GroupVersion.Version,
{Group: notificationv1b3.GroupVersion.Group, Kind: notificationv1b3.AlertKind}: notificationv1b3.GroupVersion.Version,
{Group: notificationv1b3.GroupVersion.Group, Kind: notificationv1b3.ProviderKind}: notificationv1b3.GroupVersion.Version,
// image-reflector-controller
{Group: imagev1.GroupVersion.Group, Kind: imagev1.ImageRepositoryKind}: imagev1.GroupVersion.Version,
{Group: imagev1.GroupVersion.Group, Kind: imagev1.ImagePolicyKind}: imagev1.GroupVersion.Version,
// image-automation-controller
{Group: imageautov1.GroupVersion.Group, Kind: imageautov1.ImageUpdateAutomationKind}: imageautov1.GroupVersion.Version,
// source-watcher
{Group: swv1b1.GroupVersion.Group, Kind: swv1b1.ArtifactGeneratorKind}: swv1b1.GroupVersion.Version,
},
},
{
FluxVersion: "2.6",
LatestVersions: map[schema.GroupKind]string{
// source-controller
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.BucketKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.GitRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.OCIRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.HelmRepositoryKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.HelmChartKind}: sourcev1.GroupVersion.Version,
{Group: sourcev1.GroupVersion.Group, Kind: sourcev1.ExternalArtifactKind}: sourcev1.GroupVersion.Version,
// kustomize-controller
{Group: kustomizev1.GroupVersion.Group, Kind: kustomizev1.KustomizationKind}: kustomizev1.GroupVersion.Version,
// helm-controller
{Group: helmv2.GroupVersion.Group, Kind: helmv2.HelmReleaseKind}: helmv2.GroupVersion.Version,
// notification-controller
{Group: notificationv1.GroupVersion.Group, Kind: notificationv1.ReceiverKind}: notificationv1.GroupVersion.Version,
{Group: notificationv1b3.GroupVersion.Group, Kind: notificationv1b3.AlertKind}: notificationv1b3.GroupVersion.Version,
{Group: notificationv1b3.GroupVersion.Group, Kind: notificationv1b3.ProviderKind}: notificationv1b3.GroupVersion.Version,
// image-reflector-controller
{Group: imagev1b2.GroupVersion.Group, Kind: imagev1b2.ImageRepositoryKind}: imagev1b2.GroupVersion.Version,
{Group: imagev1b2.GroupVersion.Group, Kind: imagev1b2.ImagePolicyKind}: imagev1b2.GroupVersion.Version,
// image-automation-controller
{Group: imageautov1b2.GroupVersion.Group, Kind: imageautov1b2.ImageUpdateAutomationKind}: imageautov1b2.GroupVersion.Version,
},
},
}
var migrateCmd = &cobra.Command{
Use: "migrate",
Args: cobra.NoArgs,
Short: "Migrate the Flux custom resources to their latest API version",
Long: `The migrate command must be run before a Flux minor version upgrade.
The command has two modes of operation:
- Cluster mode (default): migrates all the Flux custom resources stored in Kubernetes etcd to their latest API version.
- File system mode (-f): migrates the Flux custom resources defined in the manifests located in the specified path.
`,
Example: ` # Migrate all the Flux custom resources in the cluster.
# This uses the current kubeconfig context and requires cluster-admin permissions.
flux migrate
# Migrate all the Flux custom resources in a Git repository
# checked out in the current working directory.
flux migrate -f .
# Migrate all Flux custom resources defined in YAML and Helm YAML template files.
flux migrate -f . --extensions=.yml,.yaml,.tpl
# Migrate the Flux custom resources to the latest API versions of Flux 2.6.
flux migrate -f . --version=2.6
# Migrate the Flux custom resources defined in a multi-document YAML manifest file.
flux migrate -f path/to/manifest.yaml
# Simulate the migration without making any changes.
flux migrate -f . --dry-run
# Run the migration skipping confirmation prompts.
flux migrate -f . --yes
`,
RunE: runMigrateCmd,
}
var migrateFlags struct {
yes bool
dryRun bool
path string
version string
extensions []string
}
func init() {
rootCmd.AddCommand(migrateCmd)
migrateCmd.Flags().StringVarP(&migrateFlags.path, "path", "f", "",
"the path to the directory containing the manifests to migrate")
migrateCmd.Flags().StringSliceVarP(&migrateFlags.extensions, "extensions", "e", []string{".yaml", ".yml"},
"the file extensions to consider when migrating manifests, only applicable with --path")
migrateCmd.Flags().StringVarP(&migrateFlags.version, "version", "v", "",
"the target Flux minor version to migrate manifests to, only applicable with --path (defaults to the version of the CLI)")
migrateCmd.Flags().BoolVarP(&migrateFlags.yes, "yes", "y", false,
"skip confirmation prompts when migrating manifests, only applicable with --path")
migrateCmd.Flags().BoolVar(&migrateFlags.dryRun, "dry-run", false,
"simulate the migration of manifests without making any changes, only applicable with --path")
}
func runMigrateCmd(*cobra.Command, []string) error {
if migrateFlags.path == "" {
return migrateCluster()
}
return migrateFileSystem()
}
func migrateCluster() error {
logger.Actionf("starting migration of custom resources")
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
cfg, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions)
if err != nil {
return fmt.Errorf("the Kubernetes client initialization failed: %w", err)
}
kubeClient, err := client.New(cfg, client.Options{Scheme: utils.NewScheme()})
if err != nil {
return err
}
migrator := NewClusterMigrator(kubeClient, client.MatchingLabels{
"app.kubernetes.io/part-of": "flux",
})
if err := migrator.Run(ctx); err != nil {
return err
}
logger.Successf("custom resources migrated successfully")
return nil
}
func migrateFileSystem() error {
pathRoot, err := os.OpenRoot(".")
if err != nil {
return fmt.Errorf("failed to open filesystem at the current working directory: %w", err)
}
defer pathRoot.Close()
fileSystem := &osFS{pathRoot.FS()}
yes := migrateFlags.yes
dryRun := migrateFlags.dryRun
path := migrateFlags.path
extensions := migrateFlags.extensions
var latestVersions map[schema.GroupKind]string
// Determine latest API versions based on the Flux version.
if migrateFlags.version == "" {
latestVersions = latestAPIVersions[0].LatestVersions
} else {
supportedVersions := make([]string, 0, len(latestAPIVersions))
for _, v := range latestAPIVersions {
if v.FluxVersion == migrateFlags.version {
latestVersions = v.LatestVersions
break
}
supportedVersions = append(supportedVersions, v.FluxVersion)
}
if latestVersions == nil {
return fmt.Errorf("version %s is not supported, supported versions are: %s",
migrateFlags.version, strings.Join(supportedVersions, ", "))
}
}
return NewFileSystemMigrator(fileSystem, yes, dryRun, path, extensions, latestVersions).Run()
}
// ClusterMigrator migrates all the CRs in the cluster for the CRDs matching the label selector.
type ClusterMigrator struct {
labelSelector client.MatchingLabels
kubeClient client.Client
}
// NewClusterMigrator creates a new ClusterMigrator instance with the specified label selector.
func NewClusterMigrator(kubeClient client.Client, labelSelector client.MatchingLabels) *ClusterMigrator {
return &ClusterMigrator{
labelSelector: labelSelector,
kubeClient: kubeClient,
}
}
func (c *ClusterMigrator) Run(ctx context.Context) error {
crdList := &apiextensionsv1.CustomResourceDefinitionList{}
if err := c.kubeClient.List(ctx, crdList, c.labelSelector); err != nil {
return fmt.Errorf("failed to list CRDs: %w", err)
}
for _, crd := range crdList.Items {
if err := c.migrateCRD(ctx, crd.Name); err != nil {
return err
}
}
return nil
}
func (c *ClusterMigrator) migrateCRD(ctx context.Context, name string) error {
crd := &apiextensionsv1.CustomResourceDefinition{}
if err := c.kubeClient.Get(ctx, client.ObjectKey{Name: name}, crd); err != nil {
return fmt.Errorf("failed to get CRD %s: %w", name, err)
}
// get the latest storage version for the CRD
storageVersion := c.getStorageVersion(crd)
if storageVersion == "" {
return fmt.Errorf("no storage version found for CRD %s", name)
}
// migrate all the resources for the CRD
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
return c.migrateCR(ctx, crd, storageVersion)
})
if err != nil {
return fmt.Errorf("failed to migrate resources for CRD %s: %w", name, err)
}
// set the CRD status to contain only the latest storage version
if len(crd.Status.StoredVersions) > 1 || crd.Status.StoredVersions[0] != storageVersion {
crd.Status.StoredVersions = []string{storageVersion}
if err := c.kubeClient.Status().Update(ctx, crd); err != nil {
return fmt.Errorf("failed to update CRD %s status: %w", crd.Name, err)
}
logger.Successf("%s migrated to storage version %s", crd.Name, storageVersion)
}
return nil
}
// migrateCR migrates all CRs for the given CRD to the specified version by patching them.
func (c *ClusterMigrator) migrateCR(ctx context.Context, crd *apiextensionsv1.CustomResourceDefinition, version string) error {
list := &unstructured.UnstructuredList{}
apiVersion := crd.Spec.Group + "/" + version
listKind := crd.Spec.Names.ListKind
list.SetAPIVersion(apiVersion)
list.SetKind(listKind)
err := c.kubeClient.List(ctx, list, client.InNamespace(""))
if err != nil {
return fmt.Errorf("failed to list resources for CRD %s: %w", crd.Name, err)
}
if len(list.Items) == 0 {
return nil
}
for _, item := range list.Items {
patches, err := ssa.PatchMigrateToVersion(&item, apiVersion)
if err != nil {
return fmt.Errorf("failed to create migration patch for %s/%s/%s: %w",
item.GetKind(), item.GetNamespace(), item.GetName(), err)
}
if len(patches) == 0 {
// patch the resource with an empty patch to update the version
if err := c.kubeClient.Patch(
ctx,
&item,
client.RawPatch(client.Merge.Type(), []byte("{}")),
); err != nil && !apierrors.IsNotFound(err) {
return fmt.Errorf(" %s/%s/%s failed to migrate: %w",
item.GetKind(), item.GetNamespace(), item.GetName(), err)
}
} else {
// patch the resource to migrate the managed fields to the latest apiVersion
rawPatch, err := json.Marshal(patches)
if err != nil {
return fmt.Errorf("failed to marshal migration patch for %s/%s/%s: %w",
item.GetKind(), item.GetNamespace(), item.GetName(), err)
}
if err := c.kubeClient.Patch(
ctx,
&item,
client.RawPatch(types.JSONPatchType, rawPatch),
); err != nil && !apierrors.IsNotFound(err) {
return fmt.Errorf(" %s/%s/%s failed to migrate managed fields: %w",
item.GetKind(), item.GetNamespace(), item.GetName(), err)
}
}
logger.Successf("%s/%s/%s migrated to version %s",
item.GetKind(), item.GetNamespace(), item.GetName(), version)
}
return nil
}
// getStorageVersion retrieves the storage version of a CustomResourceDefinition.
func (c *ClusterMigrator) getStorageVersion(crd *apiextensionsv1.CustomResourceDefinition) string {
var version string
for _, v := range crd.Spec.Versions {
if v.Storage {
version = v.Name
break
}
}
return version
}
// WritableFS extends fs.FS with a WriteFile method.
type WritableFS interface {
fs.FS
WriteFile(name string, data []byte, perm os.FileMode) error
}
// osFS is a WritableFS implementation that uses the file system of the OS.
type osFS struct {
fs.FS
}
func (o *osFS) WriteFile(name string, data []byte, perm os.FileMode) error {
return os.WriteFile(name, data, perm)
}
// FileSystemMigrator migrates all the CRs found in the manifests located in the specified path.
type FileSystemMigrator struct {
fileSystem WritableFS
yes bool
dryRun bool
path string
extensions []string
latestVersions map[schema.GroupKind]string
}
// FileAPIUpgrades represents the API upgrades detected in a specific manifest file.
type FileAPIUpgrades struct {
File string
Upgrades []APIUpgrade
}
// APIUpgrade represents an upgrade of a specific API version in a manifest file.
type APIUpgrade struct {
Line int
Kind string
OldVersion string
NewVersion string
}
// NewFileSystemMigrator creates a new FileSystemMigrator instance with the specified flags.
func NewFileSystemMigrator(fileSystem WritableFS, yes, dryRun bool, path string,
extensions []string, latestVersions map[schema.GroupKind]string) *FileSystemMigrator {
return &FileSystemMigrator{
fileSystem: fileSystem,
yes: yes,
dryRun: dryRun,
path: filepath.Clean(path), // convert dir/ to dir to avoid error when walking
extensions: extensions,
latestVersions: latestVersions,
}
}
func (f *FileSystemMigrator) Run() error {
logger.Actionf("starting migration of custom resources")
// List and filter files.
files, err := f.listFiles()
if err != nil {
return err
}
// Detect upgrades.
upgrades, err := f.detectUpgrades(files)
if err != nil {
return err
}
if len(upgrades) == 0 {
logger.Successf("no custom resources found that require migration")
return nil
}
if f.dryRun {
logger.Successf("dry-run mode enabled, no changes will be made")
return nil
}
// Confirm upgrades.
if !f.yes {
prompt := promptui.Prompt{
Label: "Are you sure you want to proceed with the above upgrades", // Already prints "? [y/N]"
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return err
}
}
// Migrate files.
for _, fileUpgrades := range upgrades {
if err := f.migrateFile(&fileUpgrades); err != nil {
return err
}
logger.Successf("file %s migrated successfully", fileUpgrades.File)
}
logger.Successf("custom resources migrated successfully")
return nil
}
func (f *FileSystemMigrator) listFiles() ([]string, error) {
fileInfo, err := fs.Stat(f.fileSystem, f.path)
if err != nil {
return nil, fmt.Errorf("failed to stat path %s: %w", f.path, err)
}
if fileInfo.IsDir() {
return f.listDirectoryFiles()
}
if err := f.validateSingleFile(); err != nil {
return nil, err
}
return []string{f.path}, nil
}
func (f *FileSystemMigrator) listDirectoryFiles() ([]string, error) {
var files []string
err := fs.WalkDir(f.fileSystem, f.path, func(path string, dirEntry fs.DirEntry, err error) error {
if err != nil {
return err
}
if !f.matchesExtensions(path) {
return nil
}
fileInfo, err := dirEntry.Info()
if err != nil {
return err
}
if fileInfo.Mode().IsRegular() {
files = append(files, path)
} else if !fileInfo.IsDir() {
logger.Warningf("skipping irregular file %s", path)
}
return nil
})
if err != nil {
return nil, fmt.Errorf("failed to walk directory %s: %w", f.path, err)
}
return files, nil
}
func (f *FileSystemMigrator) validateSingleFile() error {
if !f.matchesExtensions(f.path) {
return fmt.Errorf("file %s does not match the specified extensions: %v",
f.path, strings.Join(f.extensions, ", "))
}
// Check if it's irregular by walking the parent directory.
var irregular bool
err := fs.WalkDir(f.fileSystem, filepath.Dir(f.path), func(path string, dirEntry fs.DirEntry, err error) error {
if err != nil {
return err
}
if path != f.path {
return nil
}
fileInfo, err := dirEntry.Info()
if err != nil {
return err
}
if !fileInfo.Mode().IsRegular() {
irregular = true
}
return nil
})
if err != nil {
return fmt.Errorf("failed to validate file %s: %w", f.path, err)
}
if irregular {
return fmt.Errorf("file %s is irregular", f.path)
}
return nil
}
func (f *FileSystemMigrator) matchesExtensions(file string) bool {
for _, ext := range f.extensions {
if strings.HasSuffix(file, ext) {
return true
}
}
return false
}
func (f *FileSystemMigrator) detectUpgrades(files []string) ([]FileAPIUpgrades, error) {
var upgrades []FileAPIUpgrades
for _, file := range files {
fileUpgrades, err := f.detectFileUpgrades(file)
if err != nil {
return nil, err
}
if len(fileUpgrades) == 0 {
continue
}
fu := FileAPIUpgrades{
File: file,
Upgrades: fileUpgrades,
}
upgrades = append(upgrades, fu)
f.printDetectedUpgrades(&fu)
}
return upgrades, nil
}
func (f *FileSystemMigrator) detectFileUpgrades(file string) ([]APIUpgrade, error) {
b, err := fs.ReadFile(f.fileSystem, file)
if err != nil {
return nil, fmt.Errorf("failed to read file %s: %w", file, err)
}
lines := strings.Split(string(b), "\n")
var fileUpgrades []APIUpgrade
for line, apiVersionLine := range lines {
// Parse apiVersion.
const apiVersionPrefix = "apiVersion: "
idx := strings.Index(apiVersionLine, apiVersionPrefix)
if idx == -1 {
continue
}
apiVersionValuePrefix := strings.TrimSpace(apiVersionLine[idx+len(apiVersionPrefix):])
apiVersion := strings.Split(apiVersionValuePrefix, " ")[0]
gv, err := schema.ParseGroupVersion(apiVersion)
if err != nil {
logger.Warningf("%s:%d: %v", file, line+1, err)
continue
}
// Parse kind.
if line+1 >= len(lines) {
continue
}
kindLine := lines[line+1]
const kindPrefix = "kind: "
idx = strings.Index(kindLine, kindPrefix)
if idx == -1 {
continue
}
kindValuePrefix := strings.TrimSpace(kindLine[idx+len(kindPrefix):])
kind := strings.Split(kindValuePrefix, " ")[0]
// Build GroupKind.
gk := schema.GroupKind{
Group: gv.Group,
Kind: kind,
}
// Check if there's a newer version for the GroupKind.
latestVersion, ok := f.latestVersions[gk]
if !ok || latestVersion == gv.Version {
continue
}
// Record the upgrade.
fileUpgrades = append(fileUpgrades, APIUpgrade{
Line: line,
Kind: kind,
OldVersion: gv.Version,
NewVersion: latestVersion,
})
}
return fileUpgrades, nil
}
func (f *FileSystemMigrator) printDetectedUpgrades(fileUpgrades *FileAPIUpgrades) {
for _, upgrade := range fileUpgrades.Upgrades {
logger.Generatef("%s:%d: %s %s -> %s",
fileUpgrades.File,
upgrade.Line+1,
upgrade.Kind,
upgrade.OldVersion,
upgrade.NewVersion)
}
}
func (f *FileSystemMigrator) migrateFile(fileUpgrades *FileAPIUpgrades) error {
// Read file and map lines.
b, err := fs.ReadFile(f.fileSystem, fileUpgrades.File)
if err != nil {
return fmt.Errorf("failed to read file %s: %w", fileUpgrades.File, err)
}
lines := strings.Split(string(b), "\n")
// Apply upgrades to lines.
for _, upgrade := range fileUpgrades.Upgrades {
line := lines[upgrade.Line]
line = strings.Replace(line, upgrade.OldVersion, upgrade.NewVersion, 1)
lines[upgrade.Line] = line
}
// Read file info to preserve permissions.
fileInfo, err := fs.Stat(f.fileSystem, fileUpgrades.File)
if err != nil {
return fmt.Errorf("failed to stat file %s: %w", fileUpgrades.File, err)
}
// Write file with preserved permissions.
b = []byte(strings.Join(lines, "\n"))
if err := f.fileSystem.WriteFile(fileUpgrades.File, b, fileInfo.Mode()); err != nil {
return fmt.Errorf("failed to write file %s: %w", fileUpgrades.File, err)
}
return nil
}

@ -0,0 +1,161 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"bytes"
"io/fs"
"os"
"testing"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type writeToMemoryFS struct {
fs.FS
writtenFiles map[string][]byte
}
func (m *writeToMemoryFS) WriteFile(name string, data []byte, perm os.FileMode) error {
m.writtenFiles[name] = data
return nil
}
type writtenFile struct {
file string
goldenFile string
}
func TestFileSystemMigrator(t *testing.T) {
for _, tt := range []struct {
name string
path string
outputGolden string
writtenFiles []writtenFile
err string
}{
{
name: "errors out for single file that is a symlink",
path: "testdata/migrate/file-system/single-file-link.yaml",
err: "file testdata/migrate/file-system/single-file-link.yaml is irregular",
},
{
name: "errors out for single file with wrong extension",
path: "testdata/migrate/file-system/single-file-wrong-ext.json",
err: "file testdata/migrate/file-system/single-file-wrong-ext.json does not match the specified extensions: .yaml, .yml",
},
{
name: "migrate single file",
path: "testdata/migrate/file-system/single-file.yaml",
outputGolden: "testdata/migrate/file-system/single-file.yaml.output.golden",
writtenFiles: []writtenFile{
{
file: "testdata/migrate/file-system/single-file.yaml",
goldenFile: "testdata/migrate/file-system/single-file.yaml.golden",
},
},
},
{
name: "migrate files in directory",
path: "testdata/migrate/file-system/dir",
outputGolden: "testdata/migrate/file-system/dir.output.golden",
writtenFiles: []writtenFile{
{
file: "testdata/migrate/file-system/dir/some-dir/another-file.yaml",
goldenFile: "testdata/migrate/file-system/dir.golden/some-dir/another-file.yaml",
},
{
file: "testdata/migrate/file-system/dir/some-dir/another-file.yml",
goldenFile: "testdata/migrate/file-system/dir.golden/some-dir/another-file.yml",
},
{
file: "testdata/migrate/file-system/dir/some-file.yaml",
goldenFile: "testdata/migrate/file-system/dir.golden/some-file.yaml",
},
{
file: "testdata/migrate/file-system/dir/some-file.yml",
goldenFile: "testdata/migrate/file-system/dir.golden/some-file.yml",
},
},
},
} {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
// Store logger, replace with test logger, and restore at the end of the test.
var testLogger bytes.Buffer
oldLogger := logger
logger = stderrLogger{&testLogger}
t.Cleanup(func() { logger = oldLogger })
// Open current working directory as root and build write-to-memory filesystem.
pathRoot, err := os.OpenRoot(".")
g.Expect(err).ToNot(HaveOccurred())
t.Cleanup(func() { pathRoot.Close() })
fileSystem := &writeToMemoryFS{
FS: pathRoot.FS(),
writtenFiles: make(map[string][]byte),
}
// Prepare other inputs.
const yes = true
const dryRun = false
extensions := []string{".yaml", ".yml"}
latestVersions := map[schema.GroupKind]string{
{Group: "image.toolkit.fluxcd.io", Kind: "ImageRepository"}: "v1",
{Group: "image.toolkit.fluxcd.io", Kind: "ImagePolicy"}: "v1",
{Group: "image.toolkit.fluxcd.io", Kind: "ImageUpdateAutomation"}: "v1",
}
// Run migration.
err = NewFileSystemMigrator(fileSystem, yes, dryRun, tt.path, extensions, latestVersions).Run()
if tt.err != "" {
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(Equal(tt.err))
return
}
g.Expect(err).ToNot(HaveOccurred())
// Assert logger output.
b, err := os.ReadFile(tt.outputGolden)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(string(b)).To(Equal(testLogger.String()),
"logger output does not match golden file %s", tt.outputGolden)
// Assert which files were written.
writtenFiles := make([]string, 0, len(fileSystem.writtenFiles))
for name := range fileSystem.writtenFiles {
writtenFiles = append(writtenFiles, name)
}
expectedWrittenFiles := make([]string, 0, len(tt.writtenFiles))
for _, wf := range tt.writtenFiles {
expectedWrittenFiles = append(expectedWrittenFiles, wf.file)
}
g.Expect(writtenFiles).To(ConsistOf(expectedWrittenFiles))
// Assert contents of written files.
for _, wf := range tt.writtenFiles {
b, err := os.ReadFile(wf.goldenFile)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(string(fileSystem.writtenFiles[wf.file])).To(Equal(string(b)),
"file %s does not match golden file %s", wf.file, wf.goldenFile)
}
})
}
}

@ -18,22 +18,25 @@ package main
import (
"context"
"errors"
"fmt"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/crane"
"github.com/fluxcd/pkg/auth"
"github.com/fluxcd/pkg/auth/azure"
authutils "github.com/fluxcd/pkg/auth/utils"
)
// loginWithProvider gets a crane authentication option for the given provider and URL.
func loginWithProvider(ctx context.Context, url, provider string) (crane.Option, error) {
authenticator, err := authutils.GetArtifactRegistryCredentials(ctx, provider, url)
if err != nil {
return nil, fmt.Errorf("could not login to provider %s with url %s: %w", provider, url, err)
func loginWithProvider(ctx context.Context, url, provider string) (crane.Option, authn.Authenticator, error) {
var opts []auth.Option
if provider == azure.ProviderName {
opts = append(opts, auth.WithAllowShellOut())
}
if authenticator == nil {
return nil, errors.New("unsupported provider")
authenticator, err := authutils.GetArtifactRegistryCredentials(ctx, provider, url, opts...)
if err != nil {
return nil, nil, fmt.Errorf("could not login to provider %s with url %s: %w", provider, url, err)
}
return crane.WithAuth(authenticator), nil
return crane.WithAuth(authenticator), authenticator, nil
}

@ -94,7 +94,7 @@ func pullArtifactCmdRun(cmd *cobra.Command, args []string) error {
if pullArtifactArgs.provider.String() != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials")
opt, err := loginWithProvider(ctx, url, pullArtifactArgs.provider.String())
opt, _, err := loginWithProvider(ctx, url, pullArtifactArgs.provider.String())
if err != nil {
return fmt.Errorf("error during login with provider: %w", err)
}

@ -19,7 +19,6 @@ package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"strings"
@ -34,7 +33,6 @@ import (
"github.com/spf13/cobra"
"sigs.k8s.io/yaml"
authutils "github.com/fluxcd/pkg/auth/utils"
"github.com/fluxcd/pkg/oci"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
@ -225,16 +223,14 @@ func pushArtifactCmdRun(cmd *cobra.Command, args []string) error {
opts = append(opts, crane.WithAuth(authenticator))
}
if pushArtifactArgs.provider.String() != sourcev1.GenericOCIProvider {
if provider := pushArtifactArgs.provider.String(); provider != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials")
authenticator, err = authutils.GetArtifactRegistryCredentials(ctx, pushArtifactArgs.provider.String(), url)
var opt crane.Option
opt, authenticator, err = loginWithProvider(ctx, url, provider)
if err != nil {
return fmt.Errorf("error during login with provider: %w", err)
}
if authenticator == nil {
return errors.New("unsupported provider")
}
opts = append(opts, crane.WithAuth(authenticator))
opts = append(opts, opt)
}
if rootArgs.timeout != 0 {
@ -255,7 +251,13 @@ func pushArtifactCmdRun(cmd *cobra.Command, args []string) error {
return err
}
}
transportOpts, err := oci.WithRetryTransport(ctx, ref, authenticator, backoff, []string{ref.Context().Scope(transport.PushScope)})
transportOpts, err := oci.WithRetryTransport(ctx,
ref,
authenticator,
backoff,
[]string{ref.Context().Scope(transport.PushScope)},
pushArtifactArgs.insecure,
)
if err != nil {
return fmt.Errorf("error setting up transport: %w", err)
}

@ -20,7 +20,6 @@ import (
"fmt"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
helmv2 "github.com/fluxcd/helm-controller/api/v2"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
@ -67,7 +66,7 @@ func (obj helmReleaseAdapter) reconcileSource() bool {
return rhrArgs.syncHrWithSource
}
func (obj helmReleaseAdapter) getSource() (reconcileSource, types.NamespacedName) {
func (obj helmReleaseAdapter) getSource() (reconcileSource, sourceReference) {
var (
name string
ns string
@ -78,21 +77,26 @@ func (obj helmReleaseAdapter) getSource() (reconcileSource, types.NamespacedName
if ns == "" {
ns = obj.Namespace
}
namespacedName := types.NamespacedName{
Name: name,
Namespace: ns,
srcRef := sourceReference{
kind: obj.Spec.ChartRef.Kind,
name: name,
namespace: ns,
}
if obj.Spec.ChartRef.Kind == sourcev1.HelmChartKind {
switch obj.Spec.ChartRef.Kind {
case sourcev1.HelmChartKind:
return reconcileWithSourceCommand{
apiType: helmChartType,
object: helmChartAdapter{&sourcev1.HelmChart{}},
force: true,
}, namespacedName
}
}, srcRef
case sourcev1.OCIRepositoryKind:
return reconcileCommand{
apiType: ociRepositoryType,
object: ociRepositoryAdapter{&sourcev1.OCIRepository{}},
}, namespacedName
}, srcRef
default:
return nil, srcRef
}
default:
// default case assumes the HelmRelease is using a HelmChartTemplate
ns = obj.Spec.Chart.Spec.SourceRef.Namespace
@ -104,9 +108,10 @@ func (obj helmReleaseAdapter) getSource() (reconcileSource, types.NamespacedName
apiType: helmChartType,
object: helmChartAdapter{&sourcev1.HelmChart{}},
force: true,
}, types.NamespacedName{
Name: name,
Namespace: ns,
}, sourceReference{
kind: sourcev1.HelmChartKind,
name: name,
namespace: ns,
}
}
}

@ -0,0 +1,40 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
"github.com/spf13/cobra"
)
var reconcileImagePolicyCmd = &cobra.Command{
Use: "policy [name]",
Short: "Reconcile an ImagePolicy",
Long: `The reconcile image policy command triggers a reconciliation of an ImagePolicy resource and waits for it to finish.`,
Example: `
# Trigger a reconciliation for an existing image policy called 'alpine'
flux reconcile image policy alpine`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)),
RunE: reconcileCommand{
apiType: imagePolicyType,
object: imagePolicyAdapter{&imagev1.ImagePolicy{}},
}.run,
}
func init() {
reconcileImageCmd.AddCommand(reconcileImagePolicyCmd)
}

@ -21,7 +21,7 @@ import (
"github.com/spf13/cobra"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var reconcileImageRepositoryCmd = &cobra.Command{

@ -22,7 +22,7 @@ import (
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1"
meta "github.com/fluxcd/pkg/apis/meta"
)

@ -18,7 +18,6 @@ package main
import (
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
@ -62,8 +61,8 @@ func (obj kustomizationAdapter) reconcileSource() bool {
return rksArgs.syncKsWithSource
}
func (obj kustomizationAdapter) getSource() (reconcileSource, types.NamespacedName) {
var cmd reconcileCommand
func (obj kustomizationAdapter) getSource() (reconcileSource, sourceReference) {
var cmd reconcileSource
switch obj.Spec.SourceRef.Kind {
case sourcev1.OCIRepositoryKind:
cmd = reconcileCommand{
@ -82,9 +81,10 @@ func (obj kustomizationAdapter) getSource() (reconcileSource, types.NamespacedNa
}
}
return cmd, types.NamespacedName{
Name: obj.Spec.SourceRef.Name,
Namespace: obj.Spec.SourceRef.Namespace,
return cmd, sourceReference{
kind: obj.Spec.SourceRef.Kind,
name: obj.Spec.SourceRef.Name,
namespace: obj.Spec.SourceRef.Namespace,
}
}

@ -18,7 +18,6 @@ package main
import (
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
)
@ -58,8 +57,8 @@ func (obj helmChartAdapter) reconcileSource() bool {
return rhcArgs.syncHrWithSource
}
func (obj helmChartAdapter) getSource() (reconcileSource, types.NamespacedName) {
var cmd reconcileCommand
func (obj helmChartAdapter) getSource() (reconcileSource, sourceReference) {
var cmd reconcileSource
switch obj.Spec.SourceRef.Kind {
case sourcev1.HelmRepositoryKind:
cmd = reconcileCommand{
@ -78,9 +77,10 @@ func (obj helmChartAdapter) getSource() (reconcileSource, types.NamespacedName)
}
}
return cmd, types.NamespacedName{
Name: obj.Spec.SourceRef.Name,
Namespace: obj.Namespace,
return cmd, sourceReference{
kind: obj.Spec.SourceRef.Kind,
name: obj.Spec.SourceRef.Name,
namespace: obj.Namespace,
}
}

@ -15,11 +15,17 @@ import (
"github.com/fluxcd/flux2/v2/internal/utils"
)
type sourceReference struct {
kind string
name string
namespace string
}
type reconcileWithSource interface {
adapter
reconcilable
reconcileSource() bool
getSource() (reconcileSource, types.NamespacedName)
getSource() (reconcileSource, sourceReference)
}
type reconcileSource interface {
@ -61,14 +67,17 @@ func (reconcile reconcileWithSourceCommand) run(cmd *cobra.Command, args []strin
}
if reconcile.object.reconcileSource() || reconcile.force {
reconcileCmd, nsName := reconcile.object.getSource()
reconcileCmd, srcRef := reconcile.object.getSource()
if reconcileCmd == nil {
return fmt.Errorf("cannot reconcile source of kind %s", srcRef.kind)
}
nsCopy := *kubeconfigArgs.Namespace
if nsName.Namespace != "" {
*kubeconfigArgs.Namespace = nsName.Namespace
if srcRef.namespace != "" {
*kubeconfigArgs.Namespace = srcRef.namespace
}
err := reconcileCmd.run(nil, []string{nsName.Name})
if err != nil {
if err := reconcileCmd.run(nil, []string{srcRef.name}); err != nil {
return err
}
*kubeconfigArgs.Namespace = nsCopy

@ -0,0 +1,40 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
"github.com/spf13/cobra"
)
var resumeImagePolicyCmd = &cobra.Command{
Use: "policy [name]",
Short: "Resume an ImagePolicy",
Long: `The resume image policy command resumes a suspended ImagePolicy resource.`,
Example: `
# Resume a suspended image policy called 'alpine'
flux resume image policy alpine`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)),
RunE: resumeCommand{
apiType: imagePolicyType,
list: imagePolicyListAdapter{&imagev1.ImagePolicyList{}},
}.run,
}
func init() {
resumeImageCmd.AddCommand(resumeImagePolicyCmd)
}

@ -19,7 +19,7 @@ package main
import (
"github.com/spf13/cobra"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var resumeImageRepositoryCmd = &cobra.Command{

@ -19,7 +19,7 @@ package main
import (
"github.com/spf13/cobra"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1"
)
var resumeImageUpdateCmd = &cobra.Command{

@ -195,3 +195,37 @@ func (a helmRepositoryListAdapter) asClientList() client.ObjectList {
func (a helmRepositoryListAdapter) len() int {
return len(a.HelmRepositoryList.Items)
}
// sourcev1.ExternalArtifact
var externalArtifactType = apiType{
kind: sourcev1.ExternalArtifactKind,
humanKind: "source external-artifact",
groupVersion: sourcev1.GroupVersion,
}
type externalArtifactAdapter struct {
*sourcev1.ExternalArtifact
}
func (a externalArtifactAdapter) asClientObject() client.Object {
return a.ExternalArtifact
}
func (a externalArtifactAdapter) deepCopyClientObject() client.Object {
return a.ExternalArtifact.DeepCopy()
}
// sourcev1.ExternalArtifactList
type externalArtifactListAdapter struct {
*sourcev1.ExternalArtifactList
}
func (a externalArtifactListAdapter) asClientList() client.ObjectList {
return a.ExternalArtifactList
}
func (a externalArtifactListAdapter) len() int {
return len(a.ExternalArtifactList.Items)
}

@ -28,8 +28,8 @@ import (
"github.com/fluxcd/cli-utils/pkg/kstatus/status"
helmv2 "github.com/fluxcd/helm-controller/api/v2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
notificationv1 "github.com/fluxcd/notification-controller/api/v1"
notificationv1b3 "github.com/fluxcd/notification-controller/api/v1beta3"

@ -0,0 +1,37 @@
/*
Copyright 2025 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
"github.com/spf13/cobra"
)
var suspendImagePolicyCmd = &cobra.Command{
Use: "policy [name]",
Short: "Suspend an ImagePolicy",
Long: `The suspend image policy command suspends the reconciliation of an ImagePolicy resource.`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)),
RunE: suspendCommand{
apiType: imagePolicyType,
list: imagePolicyListAdapter{&imagev1.ImagePolicyList{}},
}.run,
}
func init() {
suspendImageCmd.AddCommand(suspendImagePolicyCmd)
}

@ -19,7 +19,7 @@ package main
import (
"github.com/spf13/cobra"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1"
)
var suspendImageRepositoryCmd = &cobra.Command{

@ -19,7 +19,7 @@ package main
import (
"github.com/spf13/cobra"
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
autov1 "github.com/fluxcd/image-automation-controller/api/v1"
)
var suspendImageUpdateCmd = &cobra.Command{

@ -82,7 +82,7 @@ func tagArtifactCmdRun(cmd *cobra.Command, args []string) error {
if tagArtifactArgs.provider.String() != sourcev1.GenericOCIProvider {
logger.Actionf("logging in to registry with provider credentials")
opt, err := loginWithProvider(ctx, url, tagArtifactArgs.provider.String())
opt, _, err := loginWithProvider(ctx, url, tagArtifactArgs.provider.String())
if err != nil {
return fmt.Errorf("error during login with provider: %w", err)
}

@ -1,3 +1,3 @@
► checking prerequisites
✔ Kubernetes {{ .serverVersion }} >=1.31.0-0
✔ Kubernetes {{ .serverVersion }} >=1.32.0-0
✔ prerequisites checks passed

@ -36,4 +36,5 @@ stringData:
lbD102oXw9lUefVI0McyQIN9J58ewDC79AG7gU/fTSt6F75OeFLOJmoedQo33Y+s
bUytJtOhHbLRNxwgalhjBUNWICrDktqJmumNOEOOPBqVz7RGwUg=
-----END RSA PRIVATE KEY-----
type: Opaque

@ -35,4 +35,5 @@ stringData:
lbD102oXw9lUefVI0McyQIN9J58ewDC79AG7gU/fTSt6F75OeFLOJmoedQo33Y+s
bUytJtOhHbLRNxwgalhjBUNWICrDktqJmumNOEOOPBqVz7RGwUg=
-----END RSA PRIVATE KEY-----
type: Opaque

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save