This is page 1 of 97. Use http://codebase.md/controlplaneio-fluxcd/flux-operator?page={x} to view the full context.
# Directory Structure
```
├── .github
│ ├── actions
│ │ └── runner-cleanup
│ │ └── action.yml
│ ├── copilot-instructions.md
│ ├── dependabot.yaml
│ └── workflows
│ ├── actions-test.yaml
│ ├── e2e-olm.yaml
│ ├── preview.yaml
│ ├── push-manifests.yaml
│ ├── release.yaml
│ └── test.yaml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yml
├── actions
│ └── setup
│ ├── action.yaml
│ └── README.md
├── AGENTS.md
├── api
│ └── v1
│ ├── common_types_test.go
│ ├── common_types.go
│ ├── fluxinstance_types.go
│ ├── fluxreport_types.go
│ ├── groupversion_info.go
│ ├── history_types_test.go
│ ├── history_types.go
│ ├── resourceset_types.go
│ ├── resourcesetinputprovider_types.go
│ ├── schedule_types.go
│ └── zz_generated.deepcopy.go
├── cmd
│ ├── cli
│ │ ├── build_instance.go
│ │ ├── build_resourceset_test.go
│ │ ├── build_resourceset.go
│ │ ├── build.go
│ │ ├── client.go
│ │ ├── completion_bash.go
│ │ ├── completion_fish.go
│ │ ├── completion_powershell.go
│ │ ├── completion_zsh.go
│ │ ├── completion.go
│ │ ├── create_secret_basicauth_test.go
│ │ ├── create_secret_basicauth.go
│ │ ├── create_secret_githubapp.go
│ │ ├── create_secret_proxy_test.go
│ │ ├── create_secret_proxy.go
│ │ ├── create_secret_registry_test.go
│ │ ├── create_secret_registry.go
│ │ ├── create_secret_sops_test.go
│ │ ├── create_secret_sops.go
│ │ ├── create_secret_ssh.go
│ │ ├── create_secret_tls.go
│ │ ├── create_secret.go
│ │ ├── create.go
│ │ ├── debug_web_cookie.go
│ │ ├── debug_web.go
│ │ ├── debug.go
│ │ ├── delete_inputprovider_test.go
│ │ ├── delete_inputprovider.go
│ │ ├── delete_instance_test.go
│ │ ├── delete_instance.go
│ │ ├── delete_resourceset_test.go
│ │ ├── delete_resourceset.go
│ │ ├── delete.go
│ │ ├── distro_decrypt_manifests_test.go
│ │ ├── distro_decrypt_manifests.go
│ │ ├── distro_decrypt_token_test.go
│ │ ├── distro_decrypt_token.go
│ │ ├── distro_decrypt.go
│ │ ├── distro_encrypt_manifests_test.go
│ │ ├── distro_encrypt_manifests.go
│ │ ├── distro_encrypt_token_test.go
│ │ ├── distro_encrypt_token.go
│ │ ├── distro_encrypt.go
│ │ ├── distro_keygen_enc_test.go
│ │ ├── distro_keygen_enc.go
│ │ ├── distro_keygen_sig_test.go
│ │ ├── distro_keygen_sig.go
│ │ ├── distro_keygen.go
│ │ ├── distro_revoke_license_key_test.go
│ │ ├── distro_revoke_license_key.go
│ │ ├── distro_revoke.go
│ │ ├── distro_sign_artifacts_test.go
│ │ ├── distro_sign_artifacts.go
│ │ ├── distro_sign_license_key_test.go
│ │ ├── distro_sign_license_key.go
│ │ ├── distro_sign_manifests_test.go
│ │ ├── distro_sign_manifests.go
│ │ ├── distro_sign.go
│ │ ├── distro_verify_artifacts_test.go
│ │ ├── distro_verify_artifacts.go
│ │ ├── distro_verify_license_key_test.go
│ │ ├── distro_verify_license_key.go
│ │ ├── distro_verify_manifests_test.go
│ │ ├── distro_verify_manifests.go
│ │ ├── distro_verify.go
│ │ ├── distro.go
│ │ ├── Dockerfile
│ │ ├── export_report_test.go
│ │ ├── export_report.go
│ │ ├── export_resource_test.go
│ │ ├── export_resource.go
│ │ ├── export.go
│ │ ├── get_inputprovider_test.go
│ │ ├── get_inputprovider.go
│ │ ├── get_instance.go
│ │ ├── get_resources.go
│ │ ├── get_resourceset_test.go
│ │ ├── get_resourceset.go
│ │ ├── get.go
│ │ ├── install.go
│ │ ├── main.go
│ │ ├── README.md
│ │ ├── reconcile_inputprovider.go
│ │ ├── reconcile_instance.go
│ │ ├── reconcile_resource.go
│ │ ├── reconcile_resources.go
│ │ ├── reconcile_resourceset.go
│ │ ├── reconcile.go
│ │ ├── resume_inputprovider.go
│ │ ├── resume_instance.go
│ │ ├── resume_resource.go
│ │ ├── resume_resourceset.go
│ │ ├── resume.go
│ │ ├── stats.go
│ │ ├── suite_test.go
│ │ ├── suspend_inputprovider.go
│ │ ├── suspend_instance.go
│ │ ├── suspend_resource.go
│ │ ├── suspend_resourceset.go
│ │ ├── suspend.go
│ │ ├── testdata
│ │ │ └── build_resourceset
│ │ │ ├── golden-labeled.yaml
│ │ │ ├── golden-named.yaml
│ │ │ ├── golden-permuted.yaml
│ │ │ ├── golden.yaml
│ │ │ ├── inputs.yaml
│ │ │ ├── rset-standalone.yaml
│ │ │ ├── rset-with-rsip-labeled.yaml
│ │ │ ├── rset-with-rsip-named.yaml
│ │ │ ├── rset-with-rsip-permuted.yaml
│ │ │ ├── rset-with-rsip.yaml
│ │ │ ├── rsip-labeled.yaml
│ │ │ ├── rsip-named.yaml
│ │ │ └── rsip.yaml
│ │ ├── trace_test.go
│ │ ├── trace_types.go
│ │ ├── trace.go
│ │ ├── tree_helmrelease.go
│ │ ├── tree_kustomization.go
│ │ ├── tree_resourceset_test.go
│ │ ├── tree_resourceset.go
│ │ ├── tree.go
│ │ ├── uninstall.go
│ │ ├── version_test.go
│ │ ├── version.go
│ │ ├── wait_inputprovider_test.go
│ │ ├── wait_inputprovider.go
│ │ ├── wait_instance_test.go
│ │ ├── wait_instance.go
│ │ ├── wait_resourceset_test.go
│ │ ├── wait_resourceset.go
│ │ └── wait.go
│ ├── mcp
│ │ ├── Dockerfile
│ │ ├── k8s
│ │ │ ├── actions_test.go
│ │ │ ├── actions.go
│ │ │ ├── client_test.go
│ │ │ ├── client.go
│ │ │ ├── config.go
│ │ │ ├── events_test.go
│ │ │ ├── events.go
│ │ │ ├── export_test.go
│ │ │ ├── export.go
│ │ │ ├── helm.go
│ │ │ ├── logs.go
│ │ │ ├── metrics.go
│ │ │ └── suite_test.go
│ │ ├── main.go
│ │ ├── prompter
│ │ │ ├── debug_helmrelease_test.go
│ │ │ ├── debug_helmrelease.go
│ │ │ ├── debug_kustomization_test.go
│ │ │ ├── debug_kustomization.go
│ │ │ ├── index.go
│ │ │ └── manager.go
│ │ ├── README.md
│ │ └── toolbox
│ │ ├── apply_manifest_test.go
│ │ ├── apply_manifest.go
│ │ ├── delete_resource_test.go
│ │ ├── delete_resource.go
│ │ ├── get_apis_test.go
│ │ ├── get_apis.go
│ │ ├── get_contexts_test.go
│ │ ├── get_contexts.go
│ │ ├── get_instance_test.go
│ │ ├── get_instance.go
│ │ ├── get_logs_test.go
│ │ ├── get_logs.go
│ │ ├── get_metrics_test.go
│ │ ├── get_metrics.go
│ │ ├── get_resource_test.go
│ │ ├── get_resource.go
│ │ ├── helpers.go
│ │ ├── indexer
│ │ │ └── main.go
│ │ ├── install_instance_test.go
│ │ ├── install_instance.go
│ │ ├── library
│ │ │ ├── bm25_test.go
│ │ │ ├── bm25.go
│ │ │ ├── index.go
│ │ │ ├── index.gob
│ │ │ ├── library.go
│ │ │ ├── search_test.go
│ │ │ ├── search.go
│ │ │ ├── tokenizer_test.go
│ │ │ └── tokenizer.go
│ │ ├── manager_test.go
│ │ ├── manager.go
│ │ ├── reconcile_helmrelease_test.go
│ │ ├── reconcile_helmrelease.go
│ │ ├── reconcile_kustomization_test.go
│ │ ├── reconcile_kustomization.go
│ │ ├── reconcile_resourceset_test.go
│ │ ├── reconcile_resourceset.go
│ │ ├── reconcile_source_test.go
│ │ ├── reconcile_source.go
│ │ ├── resume_reconciliation_test.go
│ │ ├── resume_reconciliation.go
│ │ ├── scopes_test.go
│ │ ├── scopes.go
│ │ ├── search_flux_docs_test.go
│ │ ├── search_flux_docs.go
│ │ ├── set_context_test.go
│ │ ├── set_context.go
│ │ ├── suspend_reconciliation_test.go
│ │ ├── suspend_reconciliation.go
│ │ └── testdata
│ │ ├── kubeconfig_golden.yaml
│ │ └── kubeconfig.yaml
│ └── operator
│ └── main.go
├── config
│ ├── crd
│ │ ├── bases
│ │ │ ├── fluxcd.controlplane.io_fluxinstances.yaml
│ │ │ ├── fluxcd.controlplane.io_fluxreports.yaml
│ │ │ ├── fluxcd.controlplane.io_resourcesetinputproviders.yaml
│ │ │ └── fluxcd.controlplane.io_resourcesets.yaml
│ │ ├── kustomization.yaml
│ │ └── kustomizeconfig.yaml
│ ├── data
│ │ ├── flux
│ │ │ ├── v2.2.3
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.3.0
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.4.0
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.5.0
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.5.1
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.6.0
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.6.1
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.6.2
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.6.3
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.6.4
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.7.0
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ ├── source-controller.yaml
│ │ │ │ └── source-watcher.yaml
│ │ │ ├── v2.7.1
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ ├── source-controller.yaml
│ │ │ │ └── source-watcher.yaml
│ │ │ ├── v2.7.2
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ ├── source-controller.yaml
│ │ │ │ └── source-watcher.yaml
│ │ │ ├── v2.7.3
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ ├── source-controller.yaml
│ │ │ │ └── source-watcher.yaml
│ │ │ ├── v2.7.4
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ ├── source-controller.yaml
│ │ │ │ └── source-watcher.yaml
│ │ │ └── v2.7.5
│ │ │ ├── helm-controller.yaml
│ │ │ ├── image-automation-controller.yaml
│ │ │ ├── image-reflector-controller.yaml
│ │ │ ├── kustomize-controller.yaml
│ │ │ ├── notification-controller.yaml
│ │ │ ├── policies.yaml
│ │ │ ├── rbac.yaml
│ │ │ ├── source-controller.yaml
│ │ │ └── source-watcher.yaml
│ │ ├── flux-images
│ │ │ ├── v2.2.0
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.2.1
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.2.2
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.2.3
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.3.0
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.4.0
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.5.0
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.5.1
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless-fips.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.6.0
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.6.1
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.6.2
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.6.3
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.6.4
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless-fips.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.7.0
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.7.1
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.7.2
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.7.3
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.7.4
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── v2.7.5
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless-fips.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ └── VERSION
│ │ └── flux-vex
│ │ ├── v2.2.json
│ │ ├── v2.3.json
│ │ ├── v2.4.json
│ │ ├── v2.5.json
│ │ ├── v2.6.json
│ │ └── v2.7.json
│ ├── default
│ │ ├── kustomization.yaml
│ │ ├── namespace.yaml
│ │ └── rbac.yaml
│ ├── manager
│ │ ├── account.yaml
│ │ ├── deployment.yaml
│ │ ├── kustomization.yaml
│ │ └── service.yaml
│ ├── mcp
│ │ ├── deployment.yaml
│ │ ├── kustomization.yaml
│ │ └── service.yaml
│ ├── monitoring
│ │ ├── dashboards
│ │ │ ├── flux-k8s-api-performance.json
│ │ │ └── flux-performance.json
│ │ ├── flux-controllers.yaml
│ │ ├── flux-operator.yaml
│ │ └── kustomization.yaml
│ ├── olm
│ │ ├── build
│ │ │ └── Dockerfile
│ │ ├── bundle
│ │ │ ├── manifests
│ │ │ │ ├── flux-operator.clusterserviceversion.yaml
│ │ │ │ ├── flux-operator.service.yaml
│ │ │ │ ├── fluxinstances.fluxcd.controlplane.io.crd.yaml
│ │ │ │ ├── fluxreports.fluxcd.controlplane.io.crd.yaml
│ │ │ │ ├── resourcesetinputproviders.fluxcd.controlplane.io.crd.yaml
│ │ │ │ └── resourcesets.fluxcd.controlplane.io.crd.yaml
│ │ │ ├── metadata
│ │ │ │ └── annotations.yaml
│ │ │ └── tests
│ │ │ └── scorecard
│ │ │ └── config.yaml
│ │ ├── ci.yaml
│ │ └── test
│ │ ├── bundle.Dockerfile
│ │ ├── olm.yaml
│ │ └── opm.Dockerfile
│ ├── rbac
│ │ ├── fluxinstance_editor_role.yaml
│ │ ├── fluxinstance_viewer_role.yaml
│ │ ├── fluxreport_editor_role.yaml
│ │ ├── fluxreport_viewer_role.yaml
│ │ ├── kustomization.yaml
│ │ ├── leader_election_role_binding.yaml
│ │ ├── leader_election_role.yaml
│ │ ├── resourceset_editor_role.yaml
│ │ ├── resourceset_viewer_role.yaml
│ │ ├── role_binding.yaml
│ │ ├── role.yaml
│ │ └── service_account.yaml
│ ├── samples
│ │ ├── fluxcd_v1_fluxinstance.yaml
│ │ ├── fluxcd_v1_fluxreport.yaml
│ │ ├── fluxcd_v1_resourceset.yaml
│ │ ├── fluxcd_v1_resourcesetinputprovider.yaml
│ │ └── kustomization.yaml
│ └── terraform
│ ├── main.tf
│ ├── outputs.tf
│ ├── providers.tf
│ ├── README.md
│ ├── values
│ │ └── components.yaml
│ ├── variables.tf
│ └── versions.tf
├── CONTRIBUTING.md
├── Dockerfile
├── docs
│ ├── api
│ │ └── v1
│ │ ├── fluxinstance.md
│ │ ├── fluxreport.md
│ │ ├── resourceset.md
│ │ └── resourcesetinputprovider.md
│ ├── dev
│ │ └── README.md
│ ├── guides
│ │ ├── instance
│ │ │ ├── instance-controllers.md
│ │ │ ├── instance-customization.md
│ │ │ ├── instance-monitoring.md
│ │ │ ├── instance-sharding.md
│ │ │ └── instance-sync.md
│ │ ├── operator
│ │ │ ├── operator-install.md
│ │ │ └── operator-migration.md
│ │ └── resourcesets
│ │ ├── rset-app-definition.md
│ │ ├── rset-github-pull-requests.md
│ │ ├── rset-gitlab-environments.md
│ │ ├── rset-gitlab-merge-requests.md
│ │ ├── rset-image-automation.md
│ │ ├── rset-introduction.md
│ │ └── rset-time-based-delivery.md
│ ├── lkm
│ │ └── README.md
│ ├── logo
│ │ ├── flux-operator-banner.png
│ │ ├── flux-operator-banner.svg
│ │ ├── flux-operator-icon.png
│ │ ├── flux-operator-icon.svg
│ │ ├── flux-operator-logo.png
│ │ └── flux-operator-logo.svg
│ ├── mcp
│ │ ├── instructions.md
│ │ ├── mcp-config.md
│ │ ├── mcp-install.md
│ │ ├── mcp-prompting.md
│ │ ├── prompts.md
│ │ └── tools.md
│ └── web
│ ├── web-config-api.md
│ ├── web-ingress.md
│ ├── web-sso-dex.md
│ ├── web-sso-keycloak.md
│ ├── web-sso-openshift.md
│ ├── web-standalone.md
│ └── web-user-management.md
├── go.mod
├── go.sum
├── hack
│ ├── boilerplate.go.txt
│ ├── build-dist-manifests.sh
│ ├── build-olm-images.sh
│ ├── build-olm-manifests.sh
│ ├── install-operator-sdk.sh
│ ├── prep-release.sh
│ ├── vendor-flux-manifests.sh
│ └── web-ui-load-test.sh
├── internal
│ ├── builder
│ │ ├── build_test.go
│ │ ├── build.go
│ │ ├── components.go
│ │ ├── digest.go
│ │ ├── images_test.go
│ │ ├── images.go
│ │ ├── options.go
│ │ ├── preflight_test.go
│ │ ├── preflight.go
│ │ ├── profiles.go
│ │ ├── pull.go
│ │ ├── resourceset_test.go
│ │ ├── resourceset.go
│ │ ├── result.go
│ │ ├── semver_test.go
│ │ ├── semver.go
│ │ ├── templates.go
│ │ ├── testdata
│ │ │ ├── flux
│ │ │ │ ├── v2.2.0
│ │ │ │ │ └── .gitkeep
│ │ │ │ ├── v2.2.1
│ │ │ │ │ └── .gitkeep
│ │ │ │ └── v2.3.0
│ │ │ │ └── .gitkeep
│ │ │ ├── flux-images
│ │ │ │ └── v2.3.0
│ │ │ │ ├── enterprise-alpine.yaml
│ │ │ │ ├── enterprise-distroless.yaml
│ │ │ │ └── upstream-alpine.yaml
│ │ │ ├── resourceset
│ │ │ │ ├── dedup.golden.yaml
│ │ │ │ ├── dedup.yaml
│ │ │ │ ├── empty.yaml
│ │ │ │ ├── exclude.golden.yaml
│ │ │ │ ├── exclude.yaml
│ │ │ │ ├── invalid-output.yaml
│ │ │ │ ├── missing-inputs.yaml
│ │ │ │ ├── multi-doc-template.golden.yaml
│ │ │ │ ├── multi-doc-template.yaml
│ │ │ │ ├── nestedinputs.golden.yaml
│ │ │ │ ├── nestedinputs.yaml
│ │ │ │ ├── noinputs.golden.yaml
│ │ │ │ ├── noinputs.yaml
│ │ │ │ ├── slugify.golden.yaml
│ │ │ │ └── slugify.yaml
│ │ │ ├── v2.3.0
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.3.0-golden
│ │ │ │ ├── default.kustomization.yaml
│ │ │ │ ├── patches.kustomization.yaml
│ │ │ │ ├── profiles.kustomization.yaml
│ │ │ │ ├── sharding.kustomization.yaml
│ │ │ │ ├── storage.kustomization.yaml
│ │ │ │ └── sync.kustomization.yaml
│ │ │ ├── v2.6.0
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ └── source-controller.yaml
│ │ │ ├── v2.6.0-golden
│ │ │ │ ├── shard1.kustomization.yaml
│ │ │ │ ├── shard2.kustomization.yaml
│ │ │ │ ├── sharding.kustomization.yaml
│ │ │ │ ├── size.large.kustomization.yaml
│ │ │ │ ├── size.medium.kustomization.yaml
│ │ │ │ └── size.small.kustomization.yaml
│ │ │ ├── v2.7.0
│ │ │ │ ├── helm-controller.yaml
│ │ │ │ ├── image-automation-controller.yaml
│ │ │ │ ├── image-reflector-controller.yaml
│ │ │ │ ├── kustomize-controller.yaml
│ │ │ │ ├── notification-controller.yaml
│ │ │ │ ├── policies.yaml
│ │ │ │ ├── rbac.yaml
│ │ │ │ ├── source-controller.yaml
│ │ │ │ └── source-watcher.yaml
│ │ │ └── v2.7.0-golden
│ │ │ └── source-watcher.kustomization.yaml
│ │ └── workload_identity.go
│ ├── controller
│ │ ├── common.go
│ │ ├── entitlement_controller_test.go
│ │ ├── entitlement_controller.go
│ │ ├── fluxinstance_artifact_controller_test.go
│ │ ├── fluxinstance_artifact_controller.go
│ │ ├── fluxinstance_artifact_manager_test.go
│ │ ├── fluxinstance_artifact_manager.go
│ │ ├── fluxinstance_controller_test.go
│ │ ├── fluxinstance_controller.go
│ │ ├── fluxinstance_manager.go
│ │ ├── fluxinstance_migrator.go
│ │ ├── fluxinstance_uninstaller.go
│ │ ├── fluxreport_controller_test.go
│ │ ├── fluxreport_controller.go
│ │ ├── resourceset_controller_test.go
│ │ ├── resourceset_controller.go
│ │ ├── resourceset_manager_test.go
│ │ ├── resourceset_manager.go
│ │ ├── resourcesetinputprovider_controller_git_test.go
│ │ ├── resourcesetinputprovider_controller_oci_test.go
│ │ ├── resourcesetinputprovider_controller_test.go
│ │ ├── resourcesetinputprovider_controller.go
│ │ ├── resourcesetinputprovider_manager.go
│ │ ├── suite_test.go
│ │ └── testdata
│ │ └── rsa-private-key.pem
│ ├── entitlement
│ │ ├── aws.go
│ │ ├── client_test.go
│ │ ├── client.go
│ │ ├── default_test.go
│ │ └── default.go
│ ├── filtering
│ │ ├── filters_test.go
│ │ └── filters.go
│ ├── gitprovider
│ │ ├── azuredevops_test.go
│ │ ├── azuredevops.go
│ │ ├── github_test.go
│ │ ├── github.go
│ │ ├── gitlab_test.go
│ │ ├── gitlab.go
│ │ ├── interface.go
│ │ ├── options.go
│ │ ├── result_test.go
│ │ └── result.go
│ ├── inputs
│ │ ├── combine_test.go
│ │ ├── combine.go
│ │ ├── flattener.go
│ │ ├── id.go
│ │ ├── json_test.go
│ │ ├── json.go
│ │ ├── keys_test.go
│ │ ├── keys.go
│ │ ├── permuter_test.go
│ │ ├── permuter.go
│ │ └── provider.go
│ ├── install
│ │ ├── autoupdate.go
│ │ ├── client.go
│ │ ├── credentials.go
│ │ ├── deploy.go
│ │ ├── download.go
│ │ ├── events.go
│ │ ├── installer.go
│ │ ├── options.go
│ │ └── uninstall.go
│ ├── inventory
│ │ ├── inventory_test.go
│ │ ├── inventory.go
│ │ ├── reader_test.go
│ │ ├── reader.go
│ │ └── testdata
│ │ ├── inventory1.yaml
│ │ └── inventory2.yaml
│ ├── lkm
│ │ ├── artifacts_attestation_test.go
│ │ ├── artifacts_attestation.go
│ │ ├── attestation_test.go
│ │ ├── attestation.go
│ │ ├── doc.go
│ │ ├── errors.go
│ │ ├── fetch_test.go
│ │ ├── fetch.go
│ │ ├── jwe_test.go
│ │ ├── jwe.go
│ │ ├── jwt_test.go
│ │ ├── jwt.go
│ │ ├── keygen_test.go
│ │ ├── keygen.go
│ │ ├── keyset_test.go
│ │ ├── keyset.go
│ │ ├── license_test.go
│ │ ├── license.go
│ │ ├── licensekey.go
│ │ ├── manifests_attestation_test.go
│ │ ├── manifests_attestation.go
│ │ ├── revocation_test.go
│ │ └── revocation.go
│ ├── notifier
│ │ └── notifier.go
│ ├── reporter
│ │ ├── cluster.go
│ │ ├── components.go
│ │ ├── crds.go
│ │ ├── distribution.go
│ │ ├── metrics_test.go
│ │ ├── metrics.go
│ │ ├── reconcilers.go
│ │ ├── reporter.go
│ │ └── sync.go
│ ├── schedule
│ │ ├── scheduler_test.go
│ │ └── scheduler.go
│ ├── tests
│ │ ├── fluxinstance
│ │ │ ├── health_check_test.go
│ │ │ └── suite_test.go
│ │ └── resourceset
│ │ ├── health_check_test.go
│ │ └── suite_test.go
│ ├── testutils
│ │ ├── log.go
│ │ └── time.go
│ └── web
│ ├── action_test.go
│ ├── action.go
│ ├── auth
│ │ ├── claims_test.go
│ │ ├── claims.go
│ │ ├── cookies_test.go
│ │ ├── cookies.go
│ │ ├── errors_test.go
│ │ ├── errors.go
│ │ ├── middlewares_test.go
│ │ ├── middlewares.go
│ │ ├── oauth2_test.go
│ │ ├── oauth2.go
│ │ └── oidc.go
│ ├── config
│ │ ├── authentication_types_test.go
│ │ ├── authentication_types.go
│ │ ├── config_types_test.go
│ │ ├── config_types.go
│ │ ├── groupversion_info.go
│ │ ├── loader_test.go
│ │ ├── loader.go
│ │ ├── user_actions_types_test.go
│ │ ├── user_actions_types.go
│ │ └── watcher.go
│ ├── events_test.go
│ ├── events.go
│ ├── favorites_test.go
│ ├── favorites.go
│ ├── fs.go
│ ├── handler.go
│ ├── inventory.go
│ ├── kubeclient
│ │ ├── client_test.go
│ │ ├── client.go
│ │ └── suite_test.go
│ ├── middlewares_test.go
│ ├── middlewares.go
│ ├── report_test.go
│ ├── report.go
│ ├── resource_test.go
│ ├── resource.go
│ ├── resources_test.go
│ ├── resources.go
│ ├── search_test.go
│ ├── search.go
│ ├── server_test.go
│ ├── server.go
│ ├── source.go
│ ├── suite_test.go
│ ├── user
│ │ ├── user_test.go
│ │ └── user.go
│ ├── workload_test.go
│ ├── workload.go
│ ├── workloads_test.go
│ └── workloads.go
├── LICENSE
├── Makefile
├── PROJECT
├── README.md
├── SECURITY.md
├── test
│ ├── e2e
│ │ ├── e2e_suite_test.go
│ │ ├── e2e_test.go
│ │ ├── instance_test.go
│ │ └── utils.go
│ └── olm
│ ├── e2e_suite_test.go
│ ├── e2e_test.go
│ ├── instance_test.go
│ └── scorecard_test.go
└── web
├── .gitignore
├── embed.go
├── eslint.config.js
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ ├── favicon.svg
│ └── fonts
│ └── inter.woff2
├── README.md
├── src
│ ├── app.jsx
│ ├── app.test.jsx
│ ├── components
│ │ ├── auth
│ │ │ ├── LoginPage.jsx
│ │ │ └── LoginPage.test.jsx
│ │ ├── dashboards
│ │ │ ├── cluster
│ │ │ │ ├── ClusterPage.jsx
│ │ │ │ ├── ClusterPage.test.jsx
│ │ │ │ ├── ControllersPanel.jsx
│ │ │ │ ├── ControllersPanel.test.jsx
│ │ │ │ ├── InfoPanel.jsx
│ │ │ │ ├── InfoPanel.test.jsx
│ │ │ │ ├── OverallStatusPanel.jsx
│ │ │ │ ├── OverallStatusPanel.test.jsx
│ │ │ │ ├── ReconcilersPanel.jsx
│ │ │ │ ├── ReconcilersPanel.test.jsx
│ │ │ │ ├── SyncPanel.jsx
│ │ │ │ └── SyncPanel.test.jsx
│ │ │ ├── common
│ │ │ │ ├── panel.jsx
│ │ │ │ ├── panel.test.jsx
│ │ │ │ ├── yaml.jsx
│ │ │ │ └── yaml.test.jsx
│ │ │ └── resource
│ │ │ ├── ActionBar.jsx
│ │ │ ├── ActionBar.test.jsx
│ │ │ ├── ArtifactPanel.jsx
│ │ │ ├── ArtifactPanel.test.jsx
│ │ │ ├── ExportedInputsPanel.jsx
│ │ │ ├── ExportedInputsPanel.test.jsx
│ │ │ ├── GraphTabContent.jsx
│ │ │ ├── GraphTabContent.test.jsx
│ │ │ ├── HistoryTimeline.jsx
│ │ │ ├── HistoryTimeline.test.jsx
│ │ │ ├── InputsPanel.jsx
│ │ │ ├── InputsPanel.test.jsx
│ │ │ ├── InventoryPanel.jsx
│ │ │ ├── InventoryPanel.test.jsx
│ │ │ ├── ReconcilerPanel.jsx
│ │ │ ├── ReconcilerPanel.test.jsx
│ │ │ ├── ResourcePage.jsx
│ │ │ ├── ResourcePage.test.jsx
│ │ │ ├── SourcePanel.jsx
│ │ │ ├── SourcePanel.test.jsx
│ │ │ ├── WorkloadsTabContent.jsx
│ │ │ └── WorkloadsTabContent.test.jsx
│ │ ├── favorites
│ │ │ ├── FavoriteCard.jsx
│ │ │ ├── FavoriteCard.test.jsx
│ │ │ ├── FavoritesHeader.jsx
│ │ │ ├── FavoritesHeader.test.jsx
│ │ │ ├── FavoritesPage.jsx
│ │ │ ├── FavoritesPage.test.jsx
│ │ │ ├── FavoritesSearch.jsx
│ │ │ └── FavoritesSearch.test.jsx
│ │ ├── layout
│ │ │ ├── ConnectionStatus.jsx
│ │ │ ├── ConnectionStatus.test.jsx
│ │ │ ├── Footer.jsx
│ │ │ ├── Footer.test.jsx
│ │ │ ├── Header.jsx
│ │ │ ├── Header.test.jsx
│ │ │ ├── Icons.jsx
│ │ │ ├── NotFoundPage.jsx
│ │ │ ├── NotFoundPage.test.jsx
│ │ │ ├── ThemeToggle.jsx
│ │ │ ├── ThemeToggle.test.jsx
│ │ │ ├── UserMenu.jsx
│ │ │ └── UserMenu.test.jsx
│ │ └── search
│ │ ├── EventList.jsx
│ │ ├── EventList.test.jsx
│ │ ├── FilterForm.jsx
│ │ ├── FilterForm.test.jsx
│ │ ├── QuickSearch.jsx
│ │ ├── QuickSearch.test.jsx
│ │ ├── ResourceDetailsView.jsx
│ │ ├── ResourceDetailsView.test.jsx
│ │ ├── ResourceList.jsx
│ │ ├── ResourceList.test.jsx
│ │ ├── StatusChart.jsx
│ │ └── StatusChart.test.jsx
│ ├── index.css
│ ├── main.jsx
│ ├── mock
│ │ ├── action.js
│ │ ├── events.js
│ │ ├── events.test.js
│ │ ├── report.js
│ │ ├── resource.js
│ │ ├── resources.js
│ │ ├── resources.test.js
│ │ ├── workload.js
│ │ └── workload.test.js
│ └── utils
│ ├── constants.js
│ ├── cookies.js
│ ├── cookies.test.js
│ ├── favorites.js
│ ├── favorites.test.js
│ ├── fetch.js
│ ├── fetch.test.js
│ ├── hash.js
│ ├── hash.test.js
│ ├── meta.js
│ ├── meta.test.js
│ ├── navHistory.js
│ ├── navHistory.test.js
│ ├── routing.js
│ ├── routing.test.js
│ ├── scroll.js
│ ├── scroll.test.js
│ ├── status.js
│ ├── status.test.js
│ ├── theme.js
│ ├── theme.test.js
│ ├── time.js
│ ├── time.test.js
│ ├── version.js
│ └── version.test.js
├── tailwind.config.js
├── vite.config.js
└── vitest.setup.js
```
# Files
--------------------------------------------------------------------------------
/internal/builder/testdata/flux/v2.2.0/.gitkeep:
--------------------------------------------------------------------------------
```
```
--------------------------------------------------------------------------------
/internal/builder/testdata/flux/v2.2.1/.gitkeep:
--------------------------------------------------------------------------------
```
```
--------------------------------------------------------------------------------
/internal/builder/testdata/flux/v2.3.0/.gitkeep:
--------------------------------------------------------------------------------
```
```
--------------------------------------------------------------------------------
/web/.gitignore:
--------------------------------------------------------------------------------
```
node_modules
dist
coverage
.DS_Store
*.log
.vite
```
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
bin/
disto/
# Terraform
**/.terraform
*.tfstate
*.tfstate.*
.terraform.lock.hcl
.terraformrc
/internal/builder/testdata/output/
/cmd/cli/testdata/distro/
# Status Page config.
web-config.yaml
```
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
```yaml
version: "2"
run:
allow-parallel-runners: true
linters:
default: none
enable:
- copyloopvar
- dupl
- errcheck
- ginkgolinter
- goconst
- gocyclo
- govet
- ineffassign
- lll
- misspell
- nakedret
- prealloc
- revive
- staticcheck
- unconvert
- unparam
- unused
settings:
gocyclo:
min-complexity: 35
revive:
rules:
- name: comment-spacings
- name: import-shadowing
- name: use-any
- name: unreachable-code
- name: struct-tag
arguments:
- "json,inline"
- name: file-header
arguments:
- "SPDX-License-Identifier: AGPL-3.0"
staticcheck:
checks:
- all
# Incorrect or missing package comment.
# https://staticcheck.dev/docs/checks/#ST1000
- -ST1000
# Dot imports are discouraged.
# https://staticcheck.dev/docs/checks/#ST1001
- -ST1001
# Use consistent method receiver names.
# https://staticcheck.dev/docs/checks/#ST1016
- -ST1016
# Omit embedded fields from selector expression.
# https://staticcheck.dev/docs/checks/#QF1008
- -QF1008
exclusions:
generated: lax
rules:
- linters:
- errcheck
source: "^\\s*defer\\s+"
- linters:
- staticcheck
source: "r\\.Requeue"
- linters:
- lll
path: api/*
- linters:
- dupl
- lll
- goconst
path: cmd/*
- linters:
- dupl
- lll
path: internal/*
- linters:
- dupl
- lll
path: test/*
- linters:
- goconst
path: ".*_test\\.go$"
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
```
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
```yaml
version: 2
# xref: https://goreleaser.com/errors/multiple-tokens/
force_token: github
# xref: https://goreleaser.com/customization/project/
project_name: flux-operator
# xref: https://goreleaser.com/customization/hooks/
before:
hooks:
- go mod download
# xref: https://goreleaser.com/customization/env/
env:
- CGO_ENABLED=0
# xref: https://goreleaser.com/customization/build/
builds:
- <<: &cmd_defaults
binary: flux-operator
main: ./cmd/cli
ldflags:
- -s -w -X main.VERSION={{ .Version }}
id: cli
goos:
- linux
- darwin
goarch:
- amd64
- arm64
- <<: *cmd_defaults
id: cli-windows
goos:
- windows
goarch:
- amd64
- arm64
- <<: &mcp_defaults
binary: flux-operator-mcp
main: ./cmd/mcp
ldflags:
- -s -w -X main.VERSION={{ .Version }}
id: mcp
goos:
- linux
- darwin
goarch:
- amd64
- arm64
- <<: *mcp_defaults
id: mcp-windows
goos:
- windows
goarch:
- amd64
- arm64
# xref: https://goreleaser.com/customization/archive/
archives:
- name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
id: unix-cli
ids:
- cli
formats: ['tar.gz']
files:
- LICENSE
- name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
id: unix-mcp
ids:
- mcp
formats: ['tar.gz']
files:
- LICENSE
- name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
id: windows-cli
ids:
- cli-windows
formats: ['zip']
files:
- LICENSE
- name_template: "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
id: windows-mcp
ids:
- mcp-windows
formats: ['zip']
files:
- LICENSE
# xref: https://goreleaser.com/customization/checksum/
checksum:
extra_files:
- glob: ./bin/release/install.yaml
- glob: ./bin/release/crd-schemas.tar.gz
# xref: https://goreleaser.com/customization/source/
source:
enabled: true
name_template: '{{ .ProjectName }}_{{ .Version }}_source_code'
# xref: https://goreleaser.com/customization/sbom/
sboms:
- id: source
artifacts: source
documents:
- "{{ .ProjectName }}_{{ .Version }}_sbom.spdx.json"
# xref: https://goreleaser.com/customization/changelog/
changelog:
use: github-native
# xref: https://goreleaser.com/customization/release/
release:
extra_files:
- glob: ./bin/release/install.yaml
- glob: ./bin/release/crd-schemas.tar.gz
```
--------------------------------------------------------------------------------
/actions/setup/README.md:
--------------------------------------------------------------------------------
```markdown
# Setup Flux Operator CLI GitHub Action
This GitHub Action can be used to install the Flux Operator CLI on GitHub runners for usage in workflows.
All GitHub runners are supported, including Ubuntu, Windows, and macOS.
## Usage
Example workflow for printing the latest version:
```yaml
name: Check the latest version
on:
workflow_dispatch:
jobs:
check-latest-flux-operator-version:
runs-on: ubuntu-latest
steps:
- name: Setup Flux Operator CLI
uses: controlplaneio-fluxcd/flux-operator/actions/setup@main
with:
version: latest
- name: Print Flux Operator Version
run: flux-operator version --client
```
## Action Inputs
| Name | Description | Default |
|--------------------|----------------------------------|---------------------------|
| `version` | Flux Operator version | The latest stable release |
| `bindir` | Alternative location for the CLI | `$RUNNER_TOOL_CACHE` |
## Action Outputs
| Name | Description |
|--------------------|--------------------------------------------------------------|
| `version` | The Flux Operator CLI version that was effectively installed |
```
--------------------------------------------------------------------------------
/config/terraform/README.md:
--------------------------------------------------------------------------------
```markdown
# Install Flux with Terraform
This example demonstrates how to deploy Flux on a Kubernetes cluster using Terraform
and the `flux-operator` and `flux-instance` Helm charts.
## Usage
Create a Kubernetes cluster using KinD:
```shell
kind create cluster --name flux
```
Install the Flux Operator and deploy the Flux instance on the cluster
set as the default context in the `~/.kube/config` file:
```shell
terraform apply \
-var flux_version="2.x" \
-var flux_registry="ghcr.io/fluxcd" \
-var git_token="${GITHUB_TOKEN}" \
-var git_url="https://github.com/fluxcd/flux2-kustomize-helm-example.git" \
-var git_ref="refs/heads/main" \
-var git_path="clusters/production"
```
Note that the `GITHUB_TOKEN` env var must be set to a GitHub personal access token.
The `git_token` variable is used to create a Kubernetes secret in the `flux-system` namespace for
Flux to authenticate with the Git repository over HTTPS.
If the repository is public, the token variable can be omitted.
Alternatively, you can use a GitHub App to authenticate with a GitHub repository:
```shell
export GITHUB_APP_PEM=`cat path/to/app.private-key.pem`
terraform apply \
-var flux_version="2.x" \
-var flux_registry="ghcr.io/fluxcd" \
-var github_app_id="1" \
-var github_app_installation_id="2" \
-var github_app_pem="$GITHUB_APP_PEM" \
-var git_url="https://github.com/org/repo.git" \
-var git_ref="refs/heads/main" \
-var git_path="clusters/production"
```
Verify the Flux components are running:
```shell
kubectl -n flux-system get pods
```
Verify the Flux instance is syncing the cluster state from the Git repository:
```shell
kubectl -n flux-system get fluxreport/flux -o yaml
```
The output should show the sync status:
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: FluxReport
metadata:
name: flux
namespace: flux-system
spec:
# Distribution status omitted for brevity
sync:
id: kustomization/flux-system
path: clusters/production
ready: true
source: https://github.com/fluxcd/flux2-kustomize-helm-example.git
status: 'Applied revision: refs/heads/main@sha1:21486401be9bcdc37e6ebda48a3b68f8350777c9'
```
```
--------------------------------------------------------------------------------
/cmd/mcp/README.md:
--------------------------------------------------------------------------------
```markdown
# Flux MCP Server
The Flux MCP Server connects AI assistants directly to your Kubernetes clusters running Flux Operator,
enabling GitOps analysis and troubleshooting through natural language.
Using AI assistants with the Flux MCP Server, you can:
- Debug GitOps pipelines end-to-end from Flux resources to application logs
- Get intelligent root cause analysis for failed deployments
- Compare Flux configurations and Kubernetes resources between clusters
- Visualize Flux dependencies with diagrams generated from the cluster state
- Instruct Flux to perform operations using conversational prompts
## Quickstart
Install the Flux MCP Server using Homebrew:
```shell
brew install controlplaneio-fluxcd/tap/flux-operator-mcp
```
For other installation options, refer to the [installation guide](https://fluxcd.control-plane.io/mcp/install/).
Add the following configuration to your AI assistant's MCP settings:
```json
{
"flux-operator-mcp":{
"command":"flux-operator-mcp",
"args":[
"serve",
"--read-only=false"
],
"env":{
"KUBECONFIG":"/path/to/.kube/config"
}
}
}
```
Replace `/path/to/.kube/config` with the absolute path to your kubeconfig file,
you can find it with: `echo $HOME/.kube/config`.
Copy the AI rules from
[instructions.md](https://raw.githubusercontent.com/controlplaneio-fluxcd/distribution/refs/heads/main/docs/mcp/instructions.md)
and place them into the appropriate file for your assistant.
Restart the AI assistant app and test the MCP Server with the following prompts:
- "Which cluster contexts are available in my kubeconfig?"
- "What version of Flux is running in my current cluster?"
For more information on how to use the MCP Server with Claude, Cursor, GitHub Copilot,
and other assistants, please refer to the [documentation website](https://fluxcd.control-plane.io/mcp/).
## Documentation
- [Flux MCP Server Overview](https://fluxcd.control-plane.io/mcp/)
- [Installation Guide](https://fluxcd.control-plane.io/mcp/install/)
- [Transport Modes and Security Configurations](https://fluxcd.control-plane.io/mcp/config/)
- [Effective Prompting Guide](https://fluxcd.control-plane.io/mcp/prompt-engineering/)
- [MCP Tools Reference](https://fluxcd.control-plane.io/mcp/tools/)
- [MCP Prompts Reference](https://fluxcd.control-plane.io/mcp/prompts/)
## Contributing
We welcome contributions to the Flux MCP Server project via GitHub pull requests.
Please see the [CONTRIBUTING](https://github.com/controlplaneio-fluxcd/flux-operator/blob/main/CONTRIBUTING.md)
guide for details on how to set up your development environment and start contributing to the project.
## License
The MCP Server is open-source and part of the [Flux Operator](https://github.com/controlplaneio-fluxcd/flux-operator)
project licensed under the [AGPL-3.0 license](https://github.com/controlplaneio-fluxcd/flux-operator/blob/main/LICENSE).
```
--------------------------------------------------------------------------------
/web/README.md:
--------------------------------------------------------------------------------
```markdown
# Flux Status Page
**Mission control dashboard for Kubernetes app delivery powered by Flux CD**
The **Flux Status Page** is a lightweight, mobile-friendly web interface providing real-time
visibility into your GitOps pipelines. Embedded directly within the **Flux Operator**,
it requires no additional installation steps.
Designed for DevOps engineers and platform teams, the Status Page offers direct insight
into your Kubernetes clusters. It allows you to track app deployments, monitor
controller readiness, and troubleshoot issues instantly, without needing to access the CLI.
Built with security in mind, the interface is strictly read-only, ensuring it never
interferes with Flux controllers or compromises cluster security.
Together with the **Flux MCP Server**, it provides a comprehensive solution for
on-call monitoring and Agentic AI incident response in production environments.
## Features
- **Operational Insight:** View the real-time status and readiness of all workloads managed by Flux.
- **Monitor Reconciliation:** Track the sync state of GitOps pipelines across your cluster and infrastructure.
- **Pinpoint Issues:** Quickly identify and troubleshoot failures within your app delivery pipelines.
- **Navigate Efficiently:** Use advanced search and filtering to find specific resources instantly.
- **Deep Dive:** Access dedicated dashboards for ResourceSets, HelmReleases, Kustomizations and Flux sources.
- **Favorites:** Mark important resources as favorites for quick access and at-a-glance status monitoring.
- **Mobile-Optimized:** Stay informed with a fully responsive interface designed for on-the-go checks.
- **Adaptive Theming:** Toggle between dark and light modes to suit your environment and preference.
## Accessing the Status Page
The Flux Status Page is exposed on port `9080` by the `flux-operator` Kubernetes service.
To access the Status Page, you can port-forward the service to your local machine:
```bash
kubectl -n flux-system port-forward svc/flux-operator 9080:9080
```
To expose the Status Page externally, you can create an Ingress or Gateway HTTPRoute resource
pointing to the `flux-operator` service on port `9080`.
> [!IMPORTANT]
> Ensure you secure access to the Flux Status Page appropriately!
> While the UI is read-only and doesn't show sensitive data from Kubernetes secrets,
> it does expose details about your cluster's infrastructure and app deployments.
## Contributing
We welcome contributions to the Flux Status Page project via GitHub pull requests.
Please see the [CONTRIBUTING](https://github.com/controlplaneio-fluxcd/flux-operator/blob/main/CONTRIBUTING.md)
guide for details on how to set up your development environment and start contributing to the project.
## License
The Flux Status Page is open-source and part of the [Flux Operator](https://github.com/controlplaneio-fluxcd/flux-operator)
project licensed under the [AGPL-3.0 license](https://github.com/controlplaneio-fluxcd/flux-operator/blob/main/LICENSE).
```
--------------------------------------------------------------------------------
/docs/lkm/README.md:
--------------------------------------------------------------------------------
```markdown
# Flux Operator License Key Management (LKM)
Flux Operator LKM provides cryptographic license key management and attestation functionality
for the Flux distribution. LKM is built on industry-standard cryptographic primitives:
- **Ed25519 digital signatures** compliant with FIPS 186-5 for license signing
- **ECDH-ES key agreement** for secure key exchange
- **SHA-256 hashing** for data integrity verification
- **JSON Web Key (JWK)** format for interoperable key management
- **JSON Web Token (JWT)** format following RFC 7519 for standardized claims
- **JSON Web Encryption (JWE)** for secure data transmission
- **UUID v6** for unique, chronologically sortable identifiers
## Core Capabilities
LKM serves both the Flux Operator command-line interface and the Kubernetes controller,
enabling comprehensive license management and artifact attestation across the Flux ecosystem.
### License Management
- EdDSA-based license signing and verification using Ed25519 keys
- JWT-based license keys with standard header and payload structure
- Time-based license expiration with customizable validity periods
- Capability-based access control for fine-grained feature management
- License key revocation and ledger management
### Attestation Services
- OCI artifacts and container image attestation with SHA-256 digest verification
- Manifest attestation using directory hash checksums
- Cryptographic signing and verification of attestation claims
- Support for offline verification workflows
### Secure Secrets Exchange
- ECC (Elliptic Curve) public/private key pair generation
- JWK formatting for public key distribution
- JWE compact format encryption using ECDH-ES key agreement
- JWE token decryption using recipient's private ECC key
## Flux Operator CLI Distro Operations
Build the CLI binary from source code:
```shell
make cli-build
```
Create the directory structure for the distro operations:
```shell
mkdir -p \
bin/distro/keys \
bin/distro/licenses \
bin/distro/attestations \
bin/distro/secrets
```
### Bootstrap the JSON Web Key Sets
Generate encryption and signing keys:
```shell
bin/flux-operator-cli distro keygen enc fluxcd.control-plane.io \
--output-dir=bin/distro/keys
bin/flux-operator-cli distro keygen sig https://fluxcd.control-plane.io \
--output-dir=bin/distro/keys
```
Export the JWKS to env variables:
```shell
export FLUX_DISTRO_ENC_PRIVATE_JWKS=$(cat bin/distro/keys/*enc-private.jwks)
export FLUX_DISTRO_ENC_PUBLIC_JWKS=$(cat bin/distro/keys/*enc-public.jwks)
export FLUX_DISTRO_SIG_PRIVATE_JWKS=$(cat bin/distro/keys/*sig-private.jwks)
export FLUX_DISTRO_SIG_PUBLIC_JWKS=$(cat bin/distro/keys/*sig-public.jwks)
```
### Working with licenses
Create a license:
```shell
bin/flux-operator-cli distro sign license-key \
--customer="ControlPlane Group Limited" \
--duration=365 \
--capabilities="feature1,feature2" \
--output=bin/distro/licenses/cp-license.jwt
```
Verify a license:
```shell
bin/flux-operator-cli distro verify license-key \
bin/distro/licenses/cp-license.jwt
```
Revoke a license:
```shell
bin/flux-operator-cli distro revoke license-key \
bin/distro/licenses/cp-license.jwt \
--output=bin/distro/licenses/revocations.json
```
Verify a license against the revocation set:
```shell
bin/flux-operator-cli distro verify license-key \
bin/distro/licenses/cp-license.jwt \
--revoked-set=bin/distro/licenses/revocations.json
```
### Working with attestations
Create an attestation for artifacts:
```shell
bin/flux-operator-cli distro sign artifacts \
--attestation=bin/distro/attestations/flux-v2.6.4.jwt \
--url=ghcr.io/fluxcd/source-controller:v1.6.2 \
--url=ghcr.io/fluxcd/kustomize-controller:v1.6.1 \
--url=ghcr.io/fluxcd/notification-controller:v1.6.0 \
--url=ghcr.io/fluxcd/helm-controller:v1.3.0 \
--url=ghcr.io/fluxcd/image-reflector-controller:v0.35.2 \
--url=ghcr.io/fluxcd/image-automation-controller:v0.41.2
```
Verify the attestation of artifacts:
```shell
bin/flux-operator-cli distro verify artifacts \
--attestation=bin/distro/attestations/flux-v2.6.4.jwt \
--url=ghcr.io/fluxcd/source-controller:v1.6.2 \
--url=ghcr.io/fluxcd/kustomize-controller:v1.6.1 \
--url=ghcr.io/fluxcd/notification-controller:v1.6.0 \
--url=ghcr.io/fluxcd/helm-controller:v1.3.0 \
--url=ghcr.io/fluxcd/image-reflector-controller:v0.35.2 \
--url=ghcr.io/fluxcd/image-automation-controller:v0.41.2
```
Create an attestation for manifests:
```shell
bin/flux-operator-cli distro sign manifests api/ \
--attestation=bin/distro/attestations/api-source.jwt
```
Verify the attestation of manifests:
```shell
bin/flux-operator-cli distro verify manifests api/ \
--attestation=bin/distro/attestations/api-source.jwt
```
### Working with secrets
Encrypt a token:
```shell
bin/flux-operator-cli distro encrypt token \
--input=bin/distro/licenses/cp-license.jwt \
--output=bin/distro/secrets/cp-license.jwe
```
Decrypt a token:
```shell
bin/flux-operator-cli distro decrypt token \
--input=bin/distro/secrets/cp-license.jwe \
--output=bin/distro/secrets/cp-license.jwt
```
Encrypt manifests:
```shell
bin/flux-operator-cli distro encrypt manifests api/ \
--output=bin/distro/secrets/api-source.jwe
```
Decrypt manifests:
```shell
bin/flux-operator-cli distro decrypt manifests \
bin/distro/secrets/api-source.jwe \
--output-dir=bin/distro/secrets/api-source/
```
### Clean up
Unset the environment variables:
```shell
unset FLUX_DISTRO_ENC_PRIVATE_JWKS
unset FLUX_DISTRO_ENC_PUBLIC_JWKS
unset FLUX_DISTRO_SIG_PRIVATE_JWKS
unset FLUX_DISTRO_SIG_PUBLIC_JWKS
```
Remove the distro directory
```shell
rm -rf bin/distro
```
```
--------------------------------------------------------------------------------
/docs/dev/README.md:
--------------------------------------------------------------------------------
```markdown
# Flux Operator Dev Documentation
## Release Procedure
### Flux Operator
1. Switch to the `main` branch and pull the latest commit of the [`controlplaneio-fluxcd/flux-operator` repository](https://github.com/controlplaneio-fluxcd/flux-operator).
2. Run `make prep-release` that increments the minor version and opens a PR with the changes. (Or set a version with `NEXT_VERSION=v1.2.3 make prep-release`.)
3. Merge the PR and pull the latest commit from the `main` branch locally.
4. Run `make release` that creates a new tag for the release and pushes it to the remote repository.
5. Wait for the `release` GitHub Workflow to finish.
### Helm Chart
1. Run the `update` GitHub Workflow in the [`controlplaneio-fluxcd/charts` repository](https://github.com/controlplaneio-fluxcd/charts/actions/workflows/update.yaml).
2. Merge the PR opened by the `update` GitHub Workflow.
3. Wait for the `test` workflow to pass on the `main` branch.
4. Tag the `main` branch with the new next semver from [`controlplaneio-fluxcd/charts` repository](https://github.com/controlplaneio-fluxcd/charts/tags), e.g. `git tag -s -m "v0.2.0" "v0.2.0"`.
5. Wait for the `release` GitHub Workflow to finish.
6. After the Helm chart is published, the new version will be available at [artifacthub.io/packages/helm/flux-operator/flux-operator](https://artifacthub.io/packages/helm/flux-operator/flux-operator).
### OperatorHub Bundle
1. Validate the new version by running the `e2e-olm` GitHub Workflow in the [`controlplaneio-fluxcd/flux-operator` repository](https://github.com/controlplaneio-fluxcd/flux-operator/actions/workflows/e2e-olm.yaml).
2. Generate the OLM manifests locally by running `make build-olm-manifests`.
3. Fork the [OperatorHub.io repository](https://github.com/k8s-operatorhub/community-operators) and clone it locally.
4. Create a new branch from `main`, e.g. `flux-operator-1.0.0`.
5. Copy the OLM manifests from the `flux-operator/bin/olm/1.0.0` dir to the `community-operators/operators/flux-operator/1.0.0`.
6. Commit the changes with the title `operator flux-operator (1.0.0)` and push the branch to the fork.
7. Open a PR in the upstream repository and wait for the CI to pass.
8. After the PR is merged, the new version will be available at [operatorhub.io/operator/flux-operator](https://operatorhub.io/operator/flux-operator).
### RedHat OpenShift Bundle
1. Generate the OLM manifests for the UBI version locally by running `make build-olm-manifests-ubi`.
2. Fork the [redhat-openshift-ecosystem/community-operators-prod repository](https://github.com/redhat-openshift-ecosystem/community-operators-prod) and clone it locally.
3. Create a new branch from `main`, e.g. `flux-operator-1.0.0`.
4. Copy the OLM manifests from the `flux-operator/bin/olm/1.0.0` dir to the `community-operators-prod/operators/flux-operator/1.0.0`.
5. Commit the changes with the title `operator flux-operator (1.0.0)` and push the branch to the fork.
6. Open a PR in the upstream repository and wait for the CI to pass.
7. After the PR is merged, the new version will be available in the OpenShift Container Platform catalog.
### Homebrew Tap
1. Trigger the `release` GitHub Workflow in the [`controlplaneio-fluxcd/homebrew-tap` repository](https://github.com/controlplaneio-fluxcd/homebrew-tap/blob/main/.github/workflows/release.yml).
2. Merge the PR opened by the `release` workflow.
3. Verify the new version is available by running `brew upgrade flux-operator flux-operator-mcp` on your local machine.
### Documentation Website
1. Trigger the `vendor-operator-docs` GitHub Workflow in the [`controlplaneio-fluxcd/distribution` repository](https://github.com/controlplaneio-fluxcd/distribution/blob/main/.github/workflows/vendor-operator-docs.yaml).
2. Merge the PR opened by the `vendor-operator-docs` workflow.
3. Trigger the `docs` GitHub Workflow in the [`controlplaneio-fluxcd/distribution` repository](https://github.com/controlplaneio-fluxcd/distribution/blob/main/.github/workflows/docs.yaml).
4. Wait for the `docs` workflow to finish and verify the changes on the [Flux Operator documentation site](https://fluxcd.control-plane.io/operator/).
## Manifests Release Procedure
### Manifests Update for a New Flux Version
1. Create a new branch from `main`, e.g. `flux-v2.x.x` in the [`controlplaneio-fluxcd/flux-operator` repository](https://github.com/controlplaneio-fluxcd/flux-operator).
2. Generate the manifests for the latest Flux version by running `make vendor-flux`.
3. Build the manifests with images digests by running `make build-manifests`.
4. Write an end-to-end test for the upgrade if the new Flux version is a minor release.
5. Run `make mcp-build-search-index` to rebuild the docs index if the new Flux version is a minor release.
6. Commit changes and open a PR.
7. After the PR is merged, publish the OCI artifact with the manifests by running the [`push-manifests` GitHub Workflow](https://github.com/controlplaneio-fluxcd/flux-operator/actions/workflows/push-manifests.yml).
### Manifests Update for Enterprise CVE Fixes
1. Create a new branch from `main`, e.g. `enterprise-cve-fixes` in the [`controlplaneio-fluxcd/flux-operator` repository](https://github.com/controlplaneio-fluxcd/flux-operator).
2. Rebuild the Flux manifests with the latest image patches by running `make vendor-flux`.
3. Commit changes and open a PR.
4. After the PR is merged, publish the OCI artifact with the manifests by running the [`push-manifests` GitHub Workflow](https://github.com/controlplaneio-fluxcd/flux-operator/actions/workflows/push-manifests.yml).
## Local Development
### Prerequisites
- [Go](https://golang.org/doc/install) 1.25+
- [Docker](https://docs.docker.com/get-docker/)
- [Kind](https://kind.sigs.k8s.io/docs/user/quick-start/)
- [Kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
### Building
After code changes, run the following command:
```sh
make all
```
### Unit Testing
Unit tests can be run with:
```sh
make test
```
### End-to-End Testing
First, create a cluster named `kind`:
```sh
kind create cluster
```
End-to-end tests can be run with:
```sh
make test-e2e
```
### Manual Testing
Build and run the operator in a Kind cluster:
```sh
IMG=flux-operator:test1 make docker-build load-image deploy
```
Make sure to increment the `test1` tag for each new build.
Apply the instance from the `config/samples` dir:
```sh
kubectl -n flux-system apply -f config/samples/fluxcd_v1_fluxinstance.yaml
```
Check the logs:
```sh
kubectl -n flux-system logs deployment/flux-operator --follow
```
To test the Flux Operator CLI, build it with:
```sh
make cli-build
```
Then run the CLI with:
```sh
./bin/flux-operator-cli get instance flux -n flux-system
```
To clean up the resources, run:
```sh
kubectl -n flux-system delete fluxinstance/flux
make undeploy
```
### Upgrading the Go Version
To upgrade Go to the latest minor version, follow these steps:
1. Bump the `go` minor version in the `go.mod` file.
2. Bump `GOLANGCI_LINT_VERSION` to match the new Go version.
3. Run `make` to validate that the build and tests pass with the new Go version.
4. Bump the `golang` image tag in all `Dockerfile`s.
5. Bump the `go-version` in all GitHub workflows.
6. Bump the Go version in [prerequisites](#prerequisites) section of this document.
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
# flux-operator
[](https://github.com/controlplaneio-fluxcd/flux-operator/releases)
[](https://artifacthub.io/packages/helm/flux-operator/flux-operator)
[](https://operatorhub.io/operator/flux-operator)
[](https://github.com/controlplaneio-fluxcd/flux-operator/actions/workflows/test.yaml)
[](https://github.com/controlplaneio-fluxcd/flux-operator/blob/main/LICENSE)
[](https://fluxcd.control-plane.io/distribution/security/)
The Flux Operator is a Kubernetes CRD controller that manages
the lifecycle of CNCF [Flux CD](https://fluxcd.io) and the [ControlPlane enterprise distribution](https://github.com/controlplaneio-fluxcd/distribution).
The operator extends Flux with self-service capabilities, deployment windows,
and preview environments for GitHub, GitLab and Azure DevOps pull requests testing.
---
<p align="center">
<a href="https://fluxoperator.dev">
<img src="https://raw.githubusercontent.com/controlplaneio-fluxcd/flux-operator/refs/heads/main/docs/logo/flux-operator-banner.png" width="100%">
</a>
</p>
---
**Autopilot for Flux CD** - The operator offers an alternative to the Flux Bootstrap procedure, it
removes the operational burden of managing Flux across fleets of clusters by fully automating the
installation, configuration, and upgrade of the Flux controllers based on a declarative API.
**Advanced Configuration** - The operator simplifies the configuration of Flux multi-tenancy lockdown,
sharding, horizontal and vertical scaling, persistent storage, and allows fine-tuning the Flux
controllers with Kustomize patches. The operator streamlines the transition from Git as the delivery
mechanism for the cluster desired state to OCI artifacts and S3-compatible storage.
**Deep Insights** - The operator provides deep insights into the delivery pipelines managed by Flux,
including detailed reports and Prometheus metrics about the Flux controllers
readiness status, reconcilers statistics, and cluster state synchronization.
The [Flux Web UI](https://fluxoperator.dev/web-ui/) offers a real-time view of the GitOps pipelines,
allowing you to monitor deployments, track reconciliation status, and troubleshoot issues.
**Self-Service Environments** - The operator [ResourceSet API](https://fluxoperator.dev/docs/resourcesets/introduction/)
enables platform teams to define their own application standard as a group of Flux and Kubernetes resources
that can be templated, parameterized and deployed as a single unit on self-service environments.
The ResourceSet API integrates with Git pull requests to create ephemeral environments
for testing and validation.
**AI-Assisted GitOps** - The [Flux MCP Server](https://fluxoperator.dev/mcp-server/) connects
AI assistants to Kubernetes clusters running the operator, enabling seamless interaction
through natural language. It serves as a bridge between AI tools and GitOps pipelines,
allowing you to analyze deployment across environments, troubleshoot issues,
and perform operations using conversational prompts.
**Enterprise Support** - The operator is a key component of the ControlPlane
[Enterprise offering](https://fluxcd.control-plane.io/pricing/), and is designed to automate the
rollout of new Flux versions, CVE patches and hotfixes to production environments in a secure and reliable way.
The operator is end-to-end tested along with the ControlPlane Flux distribution on
Red Hat OpenShift, Amazon EKS, Azure AKS and Google GKE.
## Quickstart Guide
### Install the Flux Operator
Install the Flux Operator in the `flux-system` namespace, for example using Helm:
```shell
helm install flux-operator oci://ghcr.io/controlplaneio-fluxcd/charts/flux-operator \
--namespace flux-system
```
> [!NOTE]
> The Flux Operator can be installed using Helm, Terraform, OperatorHub, kubectl and other methods.
> For more information, refer to the
> [installation guide](https://fluxoperator.dev/docs/guides/install/).
### Install the Flux Controllers
Create a [FluxInstance](https://fluxoperator.dev/docs/crd/fluxinstance/) resource
named `flux` in the `flux-system` namespace to install the latest Flux stable version:
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: FluxInstance
metadata:
name: flux
namespace: flux-system
annotations:
fluxcd.controlplane.io/reconcileEvery: "1h"
fluxcd.controlplane.io/reconcileArtifactEvery: "10m"
fluxcd.controlplane.io/reconcileTimeout: "5m"
spec:
distribution:
version: "2.x"
registry: "ghcr.io/fluxcd"
artifact: "oci://ghcr.io/controlplaneio-fluxcd/flux-operator-manifests"
components:
- source-controller
- kustomize-controller
- helm-controller
- notification-controller
- image-reflector-controller
- image-automation-controller
cluster:
type: kubernetes
size: medium
multitenant: false
networkPolicy: true
domain: "cluster.local"
kustomize:
patches:
- target:
kind: Deployment
patch: |
- op: replace
path: /spec/template/spec/nodeSelector
value:
kubernetes.io/os: linux
- op: add
path: /spec/template/spec/tolerations
value:
- key: "CriticalAddonsOnly"
operator: "Exists"
```
> [!NOTE]
> The Flux instance can be customized in various ways.
> For more information, refer to the
> [configuration guide](https://fluxoperator.dev/docs/instance/controllers/).
### Sync from a Git Repository
To sync the cluster state from a Git repository, add the following configuration to the `FluxInstance`:
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: FluxInstance
metadata:
name: flux
namespace: flux-system
spec:
sync:
kind: GitRepository
url: "https://github.com/my-org/my-fleet.git"
ref: "refs/heads/main"
path: "clusters/my-cluster"
pullSecret: "flux-system"
# distribution omitted for brevity
```
If the source repository is private, the Kubernetes secret must be created in the `flux-system` namespace
and should contain the credentials to clone the repository:
```shell
flux create secret git flux-system \
--url=https://github.com/my-org/my-fleet.git \
--username=git \
--password=$GITHUB_TOKEN
```
> [!NOTE]
> For more information on how to configure syncing from Git repositories,
> container registries and S3-compatible storage, refer to the
> [cluster sync guide](https://fluxoperator.dev/docs/instance/sync/).
### Monitor the Flux Installation
To monitor the Flux deployment status, check the
[FluxReport](https://fluxoperator.dev/docs/crd/fluxreport/)
resource in the `flux-system` namespace:
```shell
kubectl get fluxreport/flux -n flux-system -o yaml
```
The report is update at regular intervals and contains information about the deployment
readiness status, the distribution details, reconcilers statistics, Flux CRDs versions,
the cluster sync status and more.
### Access the Flux Web UI
To access the [Flux Web UI](https://fluxoperator.dev/web-ui/),
you can port-forward the operator service:
```shell
kubectl -n flux-system port-forward svc/flux-operator 9080:9080
```
Note that the Flux Web UI can be configured with [Ingress](https://fluxoperator.dev/docs/web-ui/ingress/)
and [Single Sign-On](https://fluxoperator.dev/docs/web-ui/user-management/) for secure external access.
## ResourceSet APIs
The Flux Operator [ResourceSet APIs](https://fluxoperator.dev/docs/resourcesets/introduction/)
offer a high-level abstraction for defining and managing Flux resources and related Kubernetes
objects as a single unit.
The ResourceSet API is designed to reduce the complexity of GitOps workflows and to
enable self-service for developers and platform teams.
Guides:
- [Using ResourceSets for Application Definitions](https://fluxoperator.dev/docs/resourcesets/app-definition/)
- [Using ResourceSets for Time-Based Delivery](https://fluxoperator.dev/docs/resourcesets/time-based-delivery/)
- [Ephemeral Environments for GitHub Pull Requests](https://fluxoperator.dev/docs/resourcesets/github-pull-requests/)
- [Ephemeral Environments for GitLab Merge Requests](https://fluxoperator.dev/docs/resourcesets/gitlab-merge-requests/)
## Documentation
- Installation
- [Flux Operator installation](https://fluxoperator.dev/docs/guides/install/)
- [Migration of bootstrapped clusters](https://fluxoperator.dev/docs/guides/migration/)
- [Flux Operator CLI](https://fluxoperator.dev/docs/guides/cli/)
- Flux Configuration
- [Flux controllers configuration](https://fluxoperator.dev/docs/instance/controllers/)
- [Flux instance customization](https://fluxoperator.dev/docs/instance/customization/)
- [Cluster sync configuration](https://fluxoperator.dev/docs/instance/sync/)
- [Flux controllers sharding](https://fluxoperator.dev/docs/instance/sharding/)
- [Flux monitoring and reporting](https://fluxoperator.dev/docs/instance/monitoring/)
- CRD references
- [FluxInstance API reference](https://fluxoperator.dev/docs/crd/fluxinstance/)
- [FluxReport API reference](https://fluxoperator.dev/docs/crd/fluxreport/)
- [ResourceSet API reference](https://fluxoperator.dev/docs/crd/resourceset/)
- [ResourceSetInputProvider API reference](https://fluxoperator.dev/docs/crd/resourcesetinputprovider/)
## Contributing
We welcome contributions to the Flux Operator project via GitHub pull requests.
Please see the [CONTRIBUTING](https://github.com/controlplaneio-fluxcd/flux-operator/blob/main/CONTRIBUTING.md)
guide for details on how to set up your development environment and start contributing to the project.
## License
The Flux Operator is an open-source project licensed under the
[AGPL-3.0 license](https://github.com/controlplaneio-fluxcd/flux-operator/blob/main/LICENSE).
The project is developed by CNCF Flux core maintainers part of the [ControlPlane](https://control-plane.io) team.
```
--------------------------------------------------------------------------------
/cmd/cli/README.md:
--------------------------------------------------------------------------------
```markdown
---
title: Flux Operator CLI
description: Flux Operator command line tool installation and usage guide
---
# Flux Operator CLI
The Flux Operator CLI is a command line tool that allows you to manage the Flux Operator resources
in your Kubernetes clusters. It provides a convenient way to interact with the operator
and perform various operations.
## Installation
The Flux Operator CLI is available as a binary executable for Linux, macOS, and Windows. The binaries
can be downloaded from GitHub [releases page](https://github.com/controlplaneio-fluxcd/flux-operator/releases).
If you are using macOS or Linux, you can install the CLI using Homebrew:
```shell
brew install controlplaneio-fluxcd/tap/flux-operator
```
To configure your shell to load `flux-operator` Bash completions add to your profile:
```shell
echo "source <(flux-operator completion bash)" >> ~/.bash_profile
```
Zsh, Fish, and PowerShell are also supported with their own sub-commands.
### Container Image
The Flux Operator CLI is also available as a container image, which can be used in CI pipelines
or Kubernetes Jobs. The image contains the `flux-operator` CLI binary and the `kubectl` binary.
The multi-arch image (Linux AMD64/ARM64) is hosted on GitHub Container Registry at
`ghcr.io/controlplaneio-fluxcd/flux-operator-cli`.
```shell
version=$(gh release view --repo controlplaneio-fluxcd/flux-operator --json tagName -q '.tagName')
docker run --rm -it --entrypoint=flux-operator ghcr.io/controlplaneio-fluxcd/flux-operator-cli:$version help
docker run --rm -it --entrypoint=kubectl ghcr.io/controlplaneio-fluxcd/flux-operator-cli:$version help
```
## Commands
The Flux Operator CLI provides commands to manage the Flux Operator resources.
Except for the `build` commands, all others require access to the Kubernetes cluster
and the Flux Operator to be installed.
The CLI connects to the cluster using the `~.kube/config` file, similar to `kubectl`.
All commands display help information and example usage when run with the `-h` or `--help` flag.
### Build Commands
The `flux-operator build` commands are used to build and validate the Flux Operator resources.
These commands do not require access to a Kubernetes cluster and can be run in any environment.
The following commands are available:
- `flux-operator build instance`: Generates the Flux Kubernetes manifests from a FluxInstance definition.
- `-f, --file`: Path to the FluxInstance YAML manifest (required).
- `flux-operator build rset`: Generates the Kubernetes manifests from a ResourceSet definition.
- `-f, --file`: Path to the ResourceSet YAML manifest (required).
- `--inputs-from`: Path to the ResourceSet inputs YAML manifest.
- `--inputs-from-provider`: Path to the ResourceSetInputProvider static type YAML manifest.
### Get Commands
The `flux-operator get` commands are used to retrieve information about the Flux Operator resources in the cluster.
The following commands are available:
- `flux-operator get instance`: Retrieves the FluxInstance resource in the cluster.
- `flux-operator get rset`: Retrieves the ResourceSet resources in the cluster.
- `flux-operator get rsip`: Retrieves the ResourceSetInputProvider resources in the cluster.
Arguments:
- `-n, --namespace`: Specifies the namespace to filter the resources.
- `-A, --all-namespaces`: Retrieves resources from all namespaces.
### Get All Command
This command can be used to retrieve information about all Flux resources in the cluster,
it supports filtering by resource kind, namespace and ready status.
- `flux-operator get all`: Retrieves all Flux resources and their status.
Arguments:
- `--kind`: Specifies the kind of resources to filter (e.g. Kustomization, HelmRelease, etc.).
- `--ready-status`: Filters resources by their ready status (True, False, Unknown or Suspended).
- `-o, --output`: Specifies the output format (table, json, yaml). Default is table.
- `-n, --namespace`: Specifies the namespace to filter the resources.
- `-A, --all-namespaces`: Retrieves resources from all namespaces.
### Export Commands
The `flux-operator export` commands are used to export the Flux Operator resources in YAML or JSON format.
The exported resources can be used for backup, migration, or inspection purposes.
The following commands are available:
- `flux-operator export report`: Exports the FluxReport resource containing the distribution status and version information.
- `flux-operator export resource <kind>/<name>`: Exports a Flux resource from the specified namespace.
Arguments:
- `-n, --namespace`: Specifies the namespace scope of the command.
- `-o, --output`: Specifies the output format (yaml, json). Default is yaml.
### Reconcile Commands
The `flux-operator reconcile` commands are used to trigger the reconciliation of the Flux Operator resources.
The following commands are available:
- `flux-operator reconcile instance <name>`: Reconciles the FluxInstance resource in the cluster.
- `flux-operator reconcile rset <name>`: Reconciles the ResourceSet resource in the cluster.
- `flux-operator reconcile rsip <name>`: Reconciles the ResourceSetInputProvider resource in the cluster.
- `flux-operator reconcile resource <kind>/<name>`: Reconciles a Flux resource in the specified namespace.
- `flux-operator reconcile all`: Reconciles all Flux resources in the cluster (supports filtering by ready status).
Arguments:
- `-n, --namespace`: Specifies the namespace scope of the command.
- `--wait`: Waits for the reconciliation to complete before returning.
### Suspend/Resume Commands
The `flux-operator suspend` and `flux-operator resume` commands are used
to suspend or resume the reconciliation of the Flux Operator resources.
The following commands are available:
- `flux-operator suspend instance <name>`: Suspends the reconciliation of the FluxInstance resource in the cluster.
- `flux-operator resume instance <name>`: Resumes the reconciliation of the FluxInstance resource in the cluster.
- `flux-operator suspend rset <name>`: Suspends the reconciliation of the ResourceSet resource in the cluster.
- `flux-operator resume rset <name>`: Resumes the reconciliation of the ResourceSet resource in the cluster.
- `flux-operator suspend rsip <name>`: Suspends the reconciliation of the ResourceSetInputProvider resource in the cluster.
- `flux-operator resume rsip <name>`: Resumes the reconciliation of the ResourceSetInputProvider resource in the cluster.
- `flux-operator suspend resource <kind>/<name>`: Suspends the reconciliation of the Flux resource in the cluster.
- `flux-operator resume resource <kind>/<name>`: Resumes the reconciliation of the Flux resource in the cluster.
Arguments:
- `-n, --namespace`: Specifies the namespace scope of the command.
- `--wait`: On resume, waits for the reconciliation to complete before returning.
### Delete Commands
The `flux-operator delete` commands are used to delete the Flux Operator resources from the cluster.
The following commands are available:
- `flux-operator delete instance <name>`: Deletes the FluxInstance resource from the cluster.
- `flux-operator delete rset <name>`: Deletes the ResourceSet resource from the cluster.
- `flux-operator delete rsip <name>`: Deletes the ResourceSetInputProvider resource from the cluster.
Arguments:
- `-n, --namespace`: Specifies the namespace scope of the command.
- `--wait`: Waits for the resource to be deleted before returning (enabled by default).
- `--with-suspend`: Suspends the resource before deleting it (leaving the managed resources in-place).
### Statistics Command
This command is used to retrieve statistics about the Flux resources
including their reconciliation status and the amount of cumulative storage used for each source type.
- `flux-operator stats`: Displays statistics about the Flux resources in the cluster.
### Trace Command
This command is used to trace Kubernetes objects throughout the GitOps delivery pipeline
to identify which Flux reconciler manages them and from which source they originate.
- `flux-operator trace <kind>/<name>`: Trace a Kubernetes object to its Flux reconciler and source.
Arguments:
- `-n, --namespace`: Specifies the namespace scope of the command.
### Tree Commands
The `flux-operator tree` commands are used to visualize the Flux-managed Kubernetes objects in a tree format
by recursively traversing the Flux resources such as ResourceSets, Kustomizations and HelmReleases.
The following commands are available:
- `flux-operator tree rset <name>`: Print a tree view of the ResourceSet managed objects.
- `flux-operator tree ks <name>`: Print a tree view of the Flux Kustomization managed objects.
- `flux-operator tree hr <name>`: Print a tree view of the Flux HelmRelease managed objects.
Arguments:
- `-n, --namespace`: Specifies the namespace scope of the command.
### Wait Commands
The `flux-operator wait` commands are used to wait for Flux Operator resources to become ready.
These commands will poll the resource status until it reaches a ready state or times out.
If the resource is not created or its status is not ready within the specified timeout,
the command will return an error.
The following commands are available:
- `flux-operator wait instance <name>`: Wait for a FluxInstance to become ready.
- `flux-operator wait rset <name>`: Wait for a ResourceSet to become ready.
- `flux-operator wait rsip <name>`: Wait for a ResourceSetInputProvider to become ready.
Arguments:
- `-n, --namespace`: Specifies the namespace scope of the command.
- `--timeout`: The length of time to wait before giving up (default 1m).
### Create Secret Commands
The `flux-operator create secret` commands are used to create Kubernetes secrets specific to Flux.
These commands can be used to create or update secrets directly in the cluster, or to export them in YAML format.
The following commands are available:
- `flux-operator create secret basic-auth`: Create a Kubernetes Secret containing basic auth credentials.
- `--username`: Set the username for basic authentication (required).
- `--password`: Set the password for basic authentication (required if --password-stdin is not used).
- `--password-stdin`: Read the password from stdin.
- `flux-operator create secret githubapp`: Create a Kubernetes Secret containing GitHub App credentials.
- `--app-id`: GitHub App ID (required).
- `--app-installation-id`: GitHub App Installation ID (required).
- `--app-private-key-file`: Path to GitHub App private key file (required).
- `--app-base-url`: GitHub base URL for GitHub Enterprise Server (optional).
- `flux-operator create secret proxy`: Create a Kubernetes Secret containing HTTP/S proxy credentials.
- `--address`: Set the proxy address (required).
- `--username`: Set the username for proxy authentication (optional).
- `--password`: Set the password for proxy authentication (optional).
- `--password-stdin`: Read the password from stdin.
- `flux-operator create secret registry`: Create a Kubernetes Secret containing registry credentials.
- `--server`: Set the registry server (required).
- `--username`: Set the username for registry authentication (required).
- `--password`: Set the password for registry authentication (required if --password-stdin is not used).
- `--password-stdin`: Read the password from stdin.
- `flux-operator create secret sops`: Create a Kubernetes Secret containing SOPS decryption keys.
- `--age-key-file`: Path to Age private key file (can be used multiple times).
- `--gpg-key-file`: Path to GPG private key file (can be used multiple times).
- `--age-key-stdin`: Read Age private key from stdin.
- `--gpg-key-stdin`: Read GPG private key from stdin.
- `flux-operator create secret ssh`: Create a Kubernetes Secret containing SSH credentials.
- `--private-key-file`: Path to SSH private key file (required).
- `--public-key-file`: Path to SSH public key file (optional).
- `--knownhosts-file`: Path to SSH known_hosts file (required).
- `--password`: Password for encrypted SSH private key (optional).
- `--password-stdin`: Read the password from stdin.
- `flux-operator create secret tls`: Create a Kubernetes Secret containing TLS certs.
- `--tls-crt-file`: Path to TLS client certificate file.
- `--tls-key-file`: Path to TLS client private key file.
- `--ca-crt-file`: Path to CA certificate file (optional).
Arguments:
- `-n, --namespace`: Specifies the namespace to create the secret in.
- `--annotation`: Set annotations on the resource (can specify multiple annotations with commas: annotation1=value1,annotation2=value2).
- `--label`: Set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2).
- `--immutable`: Set the immutable flag on the Secret.
- `--export`: Export secret in YAML format to stdout instead of creating it in the cluster.
### Version Command
This command is used to display the version of the CLI, of the Flux Operator
and of the Flux distribution running in the cluster.
- `flux-operator version`: Displays the version information for the CLI and the Flux Operator.
- `--client`: If true, shows the client version only (no server required).
### Install Command
The `flux-operator install` command provides a quick way to bootstrap a Kubernetes cluster with the Flux Operator and a Flux instance.
This command performs the following steps:
1. Downloads the Flux Operator distribution artifact from `oci://ghcr.io/controlplaneio-fluxcd/flux-operator-manifests`.
2. Installs the Flux Operator in the `flux-system` namespace and waits for it to become ready.
3. Installs the Flux instance in the `flux-system` namespace according to the provided configuration.
4. Configures the pull secret for the instance sync source if credentials are provided.
5. Configures Flux to bootstrap the cluster from a Git repository or OCI repository if a sync URL is provided.
6. Configures automatic updates of the Flux Operator from the distribution artifact.
This command is intended for development and testing purposes. On production environments,
it is recommended to follow the [installation guide](https://fluxcd.control-plane.io/operator/install/).
- `flux-operator install`: Installs the Flux Operator and a Flux instance in the cluster.
- `--instance-file, -f`: Path to FluxInstance YAML file (local file, OCI or HTTPS URL).
- `--instance-distribution-version`: Flux distribution version.
- `--instance-distribution-registry`: Container registry to pull Flux images from.
- `--instance-distribution-artifact`: OCI artifact containing the Flux distribution manifests.
- `--instance-components`: List of Flux components to install.
- `--instance-components-extra`: Additional Flux components to install on top of the default set.
- `--instance-cluster-type`: Cluster type (kubernetes, openshift, aws, azure, gcp).
- `--instance-cluster-size`: Cluster size profile for vertical scaling (small, medium, large).
- `--instance-cluster-domain`: Cluster domain used for generating the FQDN of services.
- `--instance-cluster-multitenant`: Enable multitenant lockdown for Flux controllers.
- `--instance-cluster-network-policy`: Restrict network access to the current namespace.
- `--instance-sync-url`: URL of the source for cluster sync (Git repository URL or OCI repository address).
- `--instance-sync-ref`: Source reference for cluster sync (Git ref name or OCI tag).
- `--instance-sync-path`: Path to the manifests directory in the source.
- `--instance-sync-creds`: Credentials for the source in the format `username:token`.
- `--auto-update`: Enable automatic updates of the Flux Operator from the distribution artifact.
### Uninstall Command
The `flux-operator uninstall` command safely removes the Flux Operator and Flux instance from the cluster.
This command performs the following steps:
1. Deletes the cluster role bindings of Flux Operator and Flux controllers.
2. Deletes the deployments of Flux Operator and Flux controllers.
3. Removes finalizers from Flux Operator and Flux custom resources.
4. Deletes the CustomResourceDefinitions of Flux Operator and Flux.
5. Deletes the namespace where Flux Operator is installed (unless `--keep-namespace` is specified).
- `flux-operator -n flux-system uninstall`: Uninstalls the Flux Operator and Flux instance from the cluster.
- `--keep-namespace`: Keep the namespace after uninstalling Flux Operator and Flux instance.
Note that the `uninstall` command will not delete any Kubernetes objects or Helm releases
that were reconciled on the cluster by Flux. It is safe to run this command and re-install
Flux Operator later to resume managing the existing resources.
```
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
```markdown
# Security Policy
This document defines security reporting, handling and disclosure for the Flux Operator project.
## Report a Vulnerability
You can privately disclose a vulnerability through GitHub's
[private vulnerability reporting](https://github.com/controlplaneio-fluxcd/flux-operator/security) mechanism.
You will be able to choose if you want public acknowledgement of your effort and how you would like to be credited.
## Disclosures
Vulnerability disclosures are made public on GitHub's
[security advisories](https://github.com/controlplaneio-fluxcd/flux-operator/security/advisories) page.
Disclosures will contain an overview, details about the vulnerability,
a fix that will typically be an update, and optionally a workaround if one is available.
Disclosures will be made public in a timely manner after a release is published that fixes the vulnerability.
```
--------------------------------------------------------------------------------
/AGENTS.md:
--------------------------------------------------------------------------------
```markdown
# AGENTS instructions
For detailed information on source code structure and development guidelines,
refer to the project's [CONTRIBUTING.md](CONTRIBUTING.md) file.
## Project Overview
This project is a Kubernetes operator for managing the lifecycle of Flux CD.
It provides a declarative API for installing, configuring, and upgrading the Flux distribution.
The operator extends Flux with self-service capabilities, deployment windows, and preview environments.
The project is structured as a Go module with the following components:
* **Flux Operator Kubernetes Controller**: The main component of the project. It is built using the Kubernetes controller-runtime managing the following CRDs:
- **FluxInstance CRD**: Manages the Flux controllers installation and configuration
- **FluxReport CRD**: Reflects the state of a Flux installation
- **ResourceSet CRD**: Manages groups of Kubernetes and Flux resources based on input matrices
- **ResourceSetInputProvider CRD**: Fetches input values from external services (GitHub, GitLab, Azure DevOps, Container Registries)
* **Flux Operator CLI**: A command-line interface for interacting with the Flux Operator. It is built using the Cobra library.
* **Flux Operator MCP Server**: A server that connects AI assistants to Kubernetes clusters running the operator. It is built using the mcp-go library.
* **Flux Status Page**: A web UI for displaying the status of the Flux GitOps pipelines. It is built using Preact, Vite, and Tailwind CSS.
## Directory Structure
```bash
├── api/ # Go API definitions for Kubernetes CRDs
├── cmd/ # Main entrypoint for the binaries
│ ├── cli/ # Flux Operator CLI
│ ├── mcp/ # Flux Operator MCP Server
│ └── operator/ # Flux Operator Kubernetes Controller
├── config/ # Kubernetes manifests for deploying the operator
├── docs/ # Kubernetes APIs and MCP tools documentation
├── hack/ # Scripts for development, building, and releases
├── internal/ # Internal Go packages
│ ├── controller/ # Controller reconciliation logic
│ └── web/ # Backend for the Flux Status Page
├── test/ # End-to-end tests with Kubernetes Kind
└── web/ # Preact frontend for the Flux Status Page
```
## Rules of Engagement for AI Agents
- Do not deviate from the established patterns in the codebase
- If files are modified between reads, assume the change is intentional
- Never run `git tag` and never push tags
- Follow the Go code style used in the project
- Add proper doc comments for new functions and types
- After modifying a function or type, update its doc comment
- Add comments for complex logic but don't comment obvious code
- Read existing tests before writing new ones
- Run individual tests when debugging
- Replace `interface{}` with `any` type alias
- Use `go doc` to read func signatures in external packages
## Development Commands for AI Agents
- Run `make generate` after modifying types in the `api` dir
- Run `make fmt lint` after completing a task and fix lint errors
- Run `make test` to execute all Go tests
- Run `make cli-test` for Flux Operator CLI specific tests
- Run `make mcp-test` for Flux Operator MCP server specific tests
- Run `make web-test` for Flux Status Page frontend tests
```
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
```markdown
# Contributing
Flux Operator is [AGPL-3.0 licensed](https://github.com/controlplaneio-fluxcd/flux-operator/blob/main/LICENSE)
and accepts contributions via GitHub pull requests. This document outlines
some of the conventions on how to make it easier to get your contribution accepted.
We gratefully welcome improvements to code and documentation!
## Certificate of Origin
By contributing to this project, you agree to the Developer Certificate of
Origin ([DCO](https://developercertificate.org/)). This document was created by the Linux Kernel community and is a
simple statement that you, as a contributor, have the legal right to make the contribution.
> You must sign-off your commits with your name and email address using `git commit -s`.
## Project Overview
The project is structured as a [Go module](https://go.dev/doc/modules/developing) with the following components:
- [Flux Operator Kubernetes Controller](#flux-operator-kubernetes-controller)
- [Flux Operator CLI](#flux-operator-cli)
- [Flux Operator MCP Server](#flux-operator-mcp-server)
- [Flux Status Web UI](#flux-status-web-ui)
The documentation is structured as follows:
- [API documentation](#api-documentation-flux-operator-repository)
- [User Guides](#website-distribution-repository)
## Source Code Structure
### Flux Operator Kubernetes Controller
The Flux Operator is built using the Kubernetes [controller-runtime](https://github.com/kubernetes-sigs/controller-runtime)
framework and the [Flux runtime SDK](https://pkg.go.dev/github.com/fluxcd/pkg/runtime).
The test framework is based on controller-runtime's [envtest](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest)
and [Gomega](https://pkg.go.dev/github.com/onsi/gomega).
Packages:
- [api](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/api/) - contains the API definitions for the Flux Operator Kubernetes CRDs
- [cmd/operator](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/cmd/operator/) - contains the entrypoint of the Kubernetes controller
- [internal/controller](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/internal/controller/) - contains the reconcilers for `FluxInstance`, `FluxReport`, `ResourceSet`, and `ResourceSetInputProvider` resources
- [internal/builder](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/internal/builder/) - contains utilities for building and templating Flux manifests
- [internal/entitlement](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/internal/entitlement/) - contains metering and entitlement validation logic
- [internal/gitprovider](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/internal/gitprovider/) - contains integrations for GitHub, GitLab, and Azure DevOps
- [internal/inventory](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/internal/inventory/) - contains inventory management for tracking applied resources
- [internal/reporter](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/internal/reporter/) - contains cluster reporting and metrics collection utilities
- [internal/schedule](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/internal/schedule/) - contains scheduling utilities for automated operations
To test and build the operator binary, run:
```shell
make test build
```
The build command writes the binary at `bin/flux-operator` relative to the repository root.
To run the controller locally, first create a Kubernetes cluster using `kind`:
```shell
kind create cluster
```
To run the integration tests against the kind cluster, run:
```shell
make test-e2e
```
For more information on how to run the controller locally and perform manual testing, refer to the
[development](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/docs/dev#local-development) guide.
### Flux Operator CLI
The Flux Operator command-line interface (CLI) is built using the [Cobra](https://github.com/spf13/cobra) library.
Packages:
- [cmd/cli](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/cmd/cli/) - contains the commands for the Flux Operator CLI
To test and build the CLI binary, run:
```shell
make cli-test cli-build
```
The build command writes the binary at `bin/flux-operator-cli` relative to the repository root.
To run the CLI locally, use the binary built in the previous step:
```shell
./bin/flux-operator-cli --help
```
The CLI commands documentation is maintained in the
[cmd/cli/README.md](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/cmd/cli/README.md) file.
### Flux Operator MCP Server
The Flux Operator MCP Server is built using the [mcp-go](https://github.com/mark3labs/mcp-go) library.
Packages:
- [cmd/mcp/k8s](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/cmd/mcp/k8s/) - contains the Kubernetes client
- [cmd/mcp/prompter](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/cmd/mcp/prompter/) - contains the MCP prompts
- [cmd/mcp/toolbox](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/cmd/mcp/toolbox/) - contains the MCP tools
- [cmd/mcp/main.go](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/cmd/mcp/main.go) - contains the server entrypoint
To test and build the MCP Server binary, run:
```shell
make mcp-test mcp-build
```
The build command writes the binary at `bin/flux-operator-mcp` relative to the repository root.
To run the MCP Server using stdio, add the following configuration to your AI assistant's settings:
```json
{
"mcpServers": {
"flux-operator-mcp": {
"command": "/path/to/bin/flux-operator-mcp",
"args": ["serve"],
"env": {
"KUBECONFIG": "/path/to/.kube/config"
}
}
}
}
```
Replace `/path/to/bin/flux-operator-mcp` with the absolute path to the binary
and `/path/to/.kube/config` with the absolute path to your kubeconfig file.
After rebuilding the MCP Server binary, you need to restart the AI assistant app to test the new build.
To run the MCP Server using SSE, use the following command:
```shell
export KUBECONFIG=$HOME/.kube/config
./bin/flux-operator-mcp serve --transport sse --port 8080
```
To connect to the server from VS Code, use the following configuration:
```json
{
"mcp": {
"servers": {
"flux-operator-mcp": {
"type": "sse",
"url": "http://localhost:8080/sse"
}
}
}
}
```
After rebuilding the MCP Server binary, you need to restart the server to test the new build.
### Flux Status Page
The Flux Status Web UI is a single-page application (SPA) built using [Preact](https://preactjs.com/),
[Tailwind CSS](https://tailwindcss.com/), and [Vite](https://vite.dev/).
The test framework is based on [Vitest](https://vitest.dev/) with [jsdom](https://github.com/jsdom/jsdom)
for DOM simulation and [@testing-library/preact](https://testing-library.com/docs/preact-testing-library/intro/)
for component testing.
Packages:
- [web/src](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/web/src/) - contains the Preact components and utilities
- [web/src/components](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/web/src/components/) - contains the UI components
- [web/src/utils](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/web/src/utils/) - contains utility functions for theming, time formatting, etc.
- [web/src/mock](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/web/src/mock/) - contains mock data for development
- [web/dist](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/web/dist/) - build output embedded in the Go binary via `web/embed.go`
- [internal/web](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/internal/web/) - contains the Go HTTP server, API routes, and embedded frontend serving
To test and build the web UI, run:
```shell
make web-test web-build
```
The build command writes the production assets to the `web/dist/` directory, which is embedded
into the Go binary and served by the status web server.
To run the web UI locally with mock data:
```shell
make web-dev-mock
```
This starts a Vite dev server with hot module replacement at `http://localhost:5173`.
To run the web UI with a live backend connected to Kubernetes:
```shell
# Terminal 1: Start the status web server
make web-run
# Terminal 2: Start the Vite dev server
make web-dev
```
The Vite dev server will proxy API requests to the Go backend running on port 35000.
To run the web server as cluster-admin (for testing user actions that require elevated permissions),
first create a `web-config.yaml` file with the following content:
```yaml
apiVersion: web.fluxcd.controlplane.io/v1
kind: Config
spec:
baseURL: http://localhost:9080
authentication:
type: Anonymous
anonymous:
username: cluster-admin
groups:
- system:masters
```
Then run the web server with the config:
```shell
make web-run WEB_RUN_ARGS=--web-config=web-config.yaml
```
## Project Documentation Structure
The project documentation is written in Markdown.
To contribute to the documentation, you can edit the Markdown files in the following locations:
### API documentation (flux-operator repository)
- [docs/api](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/docs/api/v1) - contains the API documentation for the Flux Operator Kubernetes CRDs
- [docs/mcp](https://github.com/controlplaneio-fluxcd/flux-operator/tree/main/docs/mcp) - contains the documentation for the MCP Server tools and prompts
### Website (distribution repository)
- [docs/operator](https://github.com/controlplaneio-fluxcd/distribution/tree/main/docs/operator) - contains the user guides for the Flux Operator
- [docs/mcp](https://github.com/controlplaneio-fluxcd/distribution/tree/main/docs/mcp) - contains the user guides for the MCP Server
The documentation website is built using [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/).
## Acceptance policy
These things will make a PR more likely to be accepted:
- a well-described requirement
- tests for new code
- tests for old code!
- new code and tests follow the conventions in old code and tests
- a good commit message (see below)
- all code must abide [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments)
- names should abide [What's in a name](https://talks.golang.org/2014/names.slide#1)
- code must build on Linux, macOS and Windows via plain `go build`
- code should have appropriate test coverage, and tests should be written
to work with `go test`
Before opening a PR, please check that your code passes the following:
```shell
make all
```
In general, we will merge a PR once one maintainer has endorsed it.
For significant changes, more people may become involved, and you might
get asked to resubmit the PR or divide the changes into more than one PR.
### Format of the Commit Message
For this project, we prefer the following rules for good commit messages:
- Limit the subject to 50 characters and write as the continuation
of the sentence "If applied, this commit will ..."
- Explain what and why in the body, if more than a trivial change;
wrap it at 72 characters.
The [following article](https://chris.beams.io/posts/git-commit/#seven-rules)
has some more helpful advice on documenting your work.
```
--------------------------------------------------------------------------------
/config/olm/bundle/manifests/fluxinstances.fluxcd.controlplane.io.crd.yaml:
--------------------------------------------------------------------------------
```yaml
```
--------------------------------------------------------------------------------
/config/olm/bundle/manifests/fluxreports.fluxcd.controlplane.io.crd.yaml:
--------------------------------------------------------------------------------
```yaml
```
--------------------------------------------------------------------------------
/config/olm/bundle/manifests/resourcesetinputproviders.fluxcd.controlplane.io.crd.yaml:
--------------------------------------------------------------------------------
```yaml
```
--------------------------------------------------------------------------------
/config/olm/bundle/manifests/resourcesets.fluxcd.controlplane.io.crd.yaml:
--------------------------------------------------------------------------------
```yaml
```
--------------------------------------------------------------------------------
/hack/boilerplate.go.txt:
--------------------------------------------------------------------------------
```
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
```
--------------------------------------------------------------------------------
/web/postcss.config.js:
--------------------------------------------------------------------------------
```javascript
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
```
--------------------------------------------------------------------------------
/internal/builder/testdata/resourceset/nestedinputs.golden.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: v1
data:
k1: v1
k2: v2
kind: ConfigMap
metadata:
name: configmap1
---
```
--------------------------------------------------------------------------------
/config/default/namespace.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: v1
kind: Namespace
metadata:
labels:
app.kubernetes.io/name: flux-operator
name: flux-system
```
--------------------------------------------------------------------------------
/cmd/mcp/toolbox/testdata/kubeconfig_golden.yaml:
--------------------------------------------------------------------------------
```yaml
- cluster: kind-dev
context: kind-dev
current: true
- cluster: kind-staging
context: kind-staging
current: false
```
--------------------------------------------------------------------------------
/config/manager/account.yaml:
--------------------------------------------------------------------------------
```yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/name: flux-operator
name: flux-operator
```
--------------------------------------------------------------------------------
/config/default/kustomization.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: flux-system
resources:
- namespace.yaml
- rbac.yaml
- ../crd
- ../manager
```
--------------------------------------------------------------------------------
/config/samples/fluxcd_v1_fluxreport.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: FluxReport
metadata:
name: flux
spec:
distribution:
entitlement: "unknown"
status: "unknown"
```
--------------------------------------------------------------------------------
/internal/inventory/testdata/inventory1.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: test
---
apiVersion: v1
kind: ConfigMap
metadata:
name: test1
namespace: test
data:
key: value1
```
--------------------------------------------------------------------------------
/internal/builder/testdata/resourceset/empty.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
name: app1
namespace: apps
spec:
commonMetadata:
labels:
app.kubernetes.io/name: podinfo
```
--------------------------------------------------------------------------------
/.github/dependabot.yaml:
--------------------------------------------------------------------------------
```yaml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
groups:
actions:
patterns:
- "*"
schedule:
interval: "daily"
```
--------------------------------------------------------------------------------
/cmd/cli/testdata/build_resourceset/inputs.yaml:
--------------------------------------------------------------------------------
```yaml
- tenantName: team1
id: 340788154
applications:
- name: app1
envs:
- name: staging
version: v1.0.1
- name: production
version: v1.0.0
```
--------------------------------------------------------------------------------
/config/samples/kustomization.yaml:
--------------------------------------------------------------------------------
```yaml
## Append samples of your project ##
resources:
- fluxcd_v1_fluxinstance.yaml
- fluxcd_v1_fluxreport.yaml
- fluxcd_v1_resourceset.yaml
# +kubebuilder:scaffold:manifestskustomizesamples
```
--------------------------------------------------------------------------------
/config/rbac/service_account.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/name: flux-operator
app.kubernetes.io/managed-by: kustomize
name: controller-manager
namespace: system
```
--------------------------------------------------------------------------------
/config/olm/ci.yaml:
--------------------------------------------------------------------------------
```yaml
---
# Use `replaces-mode` or `semver-mode`. Once you switch to `semver-mode`, there is no easy way back.
updateGraph: semver-mode
addReviewers: true
reviewers:
- stefanprodan
- matheuscscp
```
--------------------------------------------------------------------------------
/web/src/main.jsx:
--------------------------------------------------------------------------------
```javascript
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
import { render } from 'preact'
import { App } from './app'
import './index.css'
render(<App />, document.getElementById('app'))
```
--------------------------------------------------------------------------------
/web/embed.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package web
import "embed"
//go:embed dist/*
var web embed.FS
// GetFS returns the embedded SPA filesystem.
func GetFS() embed.FS {
return web
}
```
--------------------------------------------------------------------------------
/config/manager/kustomization.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- account.yaml
- deployment.yaml
- service.yaml
images:
- name: flux-operator
newName: ghcr.io/controlplaneio-fluxcd/flux-operator
newTag: v0.38.1
```
--------------------------------------------------------------------------------
/internal/inventory/testdata/inventory2.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: test
---
apiVersion: v1
kind: ConfigMap
metadata:
name: test1
namespace: test
data:
key: value1
---
apiVersion: v1
kind: ConfigMap
metadata:
name: test2
namespace: test
data:
key: value2
```
--------------------------------------------------------------------------------
/config/mcp/kustomization.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: flux-system
resources:
- deployment.yaml
- service.yaml
images:
- name: flux-operator-mcp
newName: ghcr.io/controlplaneio-fluxcd/flux-operator-mcp
newTag: v0.38.1
```
--------------------------------------------------------------------------------
/internal/inputs/id.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package inputs
import (
"fmt"
"hash/adler32"
)
// ID returns a short, opaque ID for input sets.
func ID(s string) string {
return fmt.Sprintf("%v", adler32.Checksum([]byte(s)))
}
```
--------------------------------------------------------------------------------
/cmd/cli/debug.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var debugCmd = &cobra.Command{
Use: "debug",
Short: "Debug Flux Operator features",
}
func init() {
rootCmd.AddCommand(debugCmd)
}
```
--------------------------------------------------------------------------------
/cmd/cli/build.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var buildCmd = &cobra.Command{
Use: "build",
Short: "Build Flux Operator resources",
}
func init() {
rootCmd.AddCommand(buildCmd)
}
```
--------------------------------------------------------------------------------
/cmd/cli/create.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var createCmd = &cobra.Command{
Use: "create",
Short: "Create Kubernetes resources",
}
func init() {
rootCmd.AddCommand(createCmd)
}
```
--------------------------------------------------------------------------------
/cmd/cli/delete.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var deleteCmd = &cobra.Command{
Use: "delete",
Short: "Delete Flux Operator resources",
}
func init() {
rootCmd.AddCommand(deleteCmd)
}
```
--------------------------------------------------------------------------------
/cmd/cli/export.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var exportCmd = &cobra.Command{
Use: "export",
Short: "Export Flux Operator resources",
}
func init() {
rootCmd.AddCommand(exportCmd)
}
```
--------------------------------------------------------------------------------
/config/mcp/service.yaml:
--------------------------------------------------------------------------------
```yaml
---
apiVersion: v1
kind: Service
metadata:
name: flux-operator-mcp
labels:
app.kubernetes.io/name: flux-operator-mcp
spec:
ports:
- name: http
port: 9090
protocol: TCP
targetPort: http
selector:
app.kubernetes.io/name: flux-operator-mcp
```
--------------------------------------------------------------------------------
/cmd/cli/debug_web.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var debugWebCmd = &cobra.Command{
Use: "web",
Short: "Debug Flux Operator Web UI features",
}
func init() {
debugCmd.AddCommand(debugWebCmd)
}
```
--------------------------------------------------------------------------------
/cmd/cli/wait.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var waitCmd = &cobra.Command{
Use: "wait",
Short: "Wait for Flux Operator resources to become ready",
}
func init() {
rootCmd.AddCommand(waitCmd)
}
```
--------------------------------------------------------------------------------
/cmd/cli/resume.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var resumeCmd = &cobra.Command{
Use: "resume",
Short: "Resume Flux Operator resources reconciliation",
}
func init() {
rootCmd.AddCommand(resumeCmd)
}
```
--------------------------------------------------------------------------------
/cmd/cli/suspend.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var suspendCmd = &cobra.Command{
Use: "suspend",
Short: "Suspend Flux Operator resources reconciliation",
}
func init() {
rootCmd.AddCommand(suspendCmd)
}
```
--------------------------------------------------------------------------------
/config/crd/kustomization.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- bases/fluxcd.controlplane.io_fluxinstances.yaml
- bases/fluxcd.controlplane.io_fluxreports.yaml
- bases/fluxcd.controlplane.io_resourcesets.yaml
- bases/fluxcd.controlplane.io_resourcesetinputproviders.yaml
```
--------------------------------------------------------------------------------
/cmd/cli/distro_revoke.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var distroRevokeCmd = &cobra.Command{
Use: "revoke",
Short: "Maintain a ledger of revoked license keys",
}
func init() {
distroCmd.AddCommand(distroRevokeCmd)
}
```
--------------------------------------------------------------------------------
/cmd/cli/reconcile.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var reconcileCmd = &cobra.Command{
Use: "reconcile",
Short: "Trigger Flux Operator resources reconciliation",
}
func init() {
rootCmd.AddCommand(reconcileCmd)
}
```
--------------------------------------------------------------------------------
/internal/builder/testdata/resourceset/nestedinputs.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
name: app1
namespace: apps
spec:
inputs:
- foo:
bar:
k1: v1
k2: v2
resources:
- apiVersion: v1
kind: ConfigMap
metadata:
name: configmap1
data: << inputs.foo.bar | toYaml | nindent 2 >>
```
--------------------------------------------------------------------------------
/cmd/cli/distro_keygen.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var distroKeygenCmd = &cobra.Command{
Use: "keygen",
Short: "Generate asymmetric key pairs for encryption and signing",
}
func init() {
distroCmd.AddCommand(distroKeygenCmd)
}
```
--------------------------------------------------------------------------------
/cmd/cli/distro_sign.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var distroSignCmd = &cobra.Command{
Use: "sign",
Short: "Issue signed license keys and attestations of artifacts and manifests",
}
func init() {
distroCmd.AddCommand(distroSignCmd)
}
```
--------------------------------------------------------------------------------
/cmd/cli/distro_verify.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var distroVerifyCmd = &cobra.Command{
Use: "verify",
Short: "Verify license keys and attestations of artifacts and manifests",
}
func init() {
distroCmd.AddCommand(distroVerifyCmd)
}
```
--------------------------------------------------------------------------------
/web/src/mock/action.js:
--------------------------------------------------------------------------------
```javascript
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
// Mock action response for POST /api/v1/action
export const mockAction = (body) => {
return {
success: true,
message: `${body.action.charAt(0).toUpperCase() + body.action.slice(1)} triggered for ${body.namespace}/${body.name}`
}
}
```
--------------------------------------------------------------------------------
/cmd/cli/distro_decrypt.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var distroDecryptCmd = &cobra.Command{
Use: "decrypt",
Short: "Decrypt sensitive information using JWE with asymmetric key pairs",
}
func init() {
distroCmd.AddCommand(distroDecryptCmd)
}
```
--------------------------------------------------------------------------------
/cmd/cli/distro_encrypt.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"github.com/spf13/cobra"
)
var distroEncryptCmd = &cobra.Command{
Use: "encrypt",
Short: "Encrypt sensitive information using JWE with asymmetric key pairs",
}
func init() {
distroCmd.AddCommand(distroEncryptCmd)
}
```
--------------------------------------------------------------------------------
/internal/web/config/groupversion_info.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package config
import (
"k8s.io/apimachinery/pkg/runtime/schema"
)
var (
// GroupVersion is group and version of the Flux Status Page configuration API.
GroupVersion = schema.GroupVersion{Group: "web.fluxcd.controlplane.io", Version: "v1"}
)
```
--------------------------------------------------------------------------------
/config/manager/service.yaml:
--------------------------------------------------------------------------------
```yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: flux-operator
name: flux-operator
spec:
ports:
- name: http-web
port: 9080
protocol: TCP
targetPort: 9080
- name: http
port: 8080
protocol: TCP
targetPort: 8080
selector:
app.kubernetes.io/name: flux-operator
```
--------------------------------------------------------------------------------
/config/olm/bundle/manifests/flux-operator.service.yaml:
--------------------------------------------------------------------------------
```yaml
---
apiVersion: v1
kind: Service
metadata:
name: flux-operator
labels:
app.kubernetes.io/name: flux-operator
spec:
ports:
- name: http-web
port: 9080
protocol: TCP
targetPort: 9080
- name: http
port: 8080
protocol: TCP
targetPort: 8080
selector:
app.kubernetes.io/name: flux-operator
```
--------------------------------------------------------------------------------
/cmd/mcp/prompter/index.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package prompter
// PromptSet returns a slice of predefined Prompt objects
// with their associated names, descriptions, and handlers.
func (m *Manager) PromptSet() []SystemPrompt {
return []SystemPrompt{
m.NewDebugKustomizationPrompt(),
m.NewDebugHelmReleasePrompt(),
}
}
```
--------------------------------------------------------------------------------
/internal/builder/result.go:
--------------------------------------------------------------------------------
```go
// Copyright 2024 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package builder
import "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
// Result holds the build result.
type Result struct {
Version string
Digest string
Revision string
Objects []*unstructured.Unstructured
ComponentImages []ComponentImage
}
```
--------------------------------------------------------------------------------
/internal/gitprovider/options.go:
--------------------------------------------------------------------------------
```go
// Copyright 2024 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package gitprovider
import (
"crypto/tls"
"github.com/controlplaneio-fluxcd/flux-operator/internal/filtering"
)
// Options holds the configuration for the Git SaaS provider.
type Options struct {
URL string
TLSConfig *tls.Config
Token string
Filters filtering.Filters
}
```
--------------------------------------------------------------------------------
/config/rbac/role_binding.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/name: flux-operator
app.kubernetes.io/managed-by: kustomize
name: manager-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: manager-role
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system
```
--------------------------------------------------------------------------------
/config/monitoring/flux-operator.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: flux-operator
labels:
app.kubernetes.io/component: metrics
app.kubernetes.io/part-of: flux
spec:
namespaceSelector:
matchNames:
- flux-system
selector:
matchLabels:
app.kubernetes.io/name: flux-operator
endpoints:
- targetPort: 8080
path: /metrics
```
--------------------------------------------------------------------------------
/config/rbac/leader_election_role_binding.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/name: flux-operator
app.kubernetes.io/managed-by: kustomize
name: leader-election-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: leader-election-role
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system
```
--------------------------------------------------------------------------------
/test/e2e/e2e_suite_test.go:
--------------------------------------------------------------------------------
```go
// Copyright 2024 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package e2e
import (
"fmt"
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
// Run e2e tests using the Ginkgo runner.
func TestE2E(t *testing.T) {
RegisterFailHandler(Fail)
fmt.Fprintf(GinkgoWriter, "Starting flux-operator suite\n") //nolint:errcheck
RunSpecs(t, "e2e suite")
}
```
--------------------------------------------------------------------------------
/internal/builder/testdata/resourceset/noinputs.golden.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
name: app1
namespace: apps
spec:
interval: 10m
ref:
semver: '*'
url: oci://ghcr.io/org/charts/app1
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: app1
namespace: apps
spec:
chartRef:
kind: OCIRepository
name: app1
interval: 1h
releaseName: app1
---
```
--------------------------------------------------------------------------------
/test/olm/e2e_suite_test.go:
--------------------------------------------------------------------------------
```go
// Copyright 2024 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package e2eolm
import (
"fmt"
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
// Run e2e tests using the Ginkgo runner.
func TestE2E(t *testing.T) {
RegisterFailHandler(Fail)
fmt.Fprintf(GinkgoWriter, "Starting flux-operator olm e2e suite\n") //nolint:errcheck
RunSpecs(t, "olm e2e suite")
}
```
--------------------------------------------------------------------------------
/config/data/flux-vex/v2.4.json:
--------------------------------------------------------------------------------
```json
{
"@context": "https://openvex.dev/ns/v0.2.0",
"@id": "https://openvex.dev/docs/public/vex-f843e58a33079b9f9344d4b4e72a3dcc0ee7ad51825e087b96692dccaf21f2d8",
"author": "[email protected]",
"role": "Enterprise Flux Maintainers",
"timestamp": "2024-09-30T17:26:04.422544+03:00",
"last_updated": "2024-09-30T17:26:04.422544+03:00",
"version": 2,
"statements": [
]
}
```
--------------------------------------------------------------------------------
/cmd/cli/testdata/build_resourceset/rsip.yaml:
--------------------------------------------------------------------------------
```yaml
---
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
name: team1-apps
namespace: test
labels:
fluxcd.controlplane.io/role: provisioning
spec:
type: Static
defaultValues:
tenantName: team1
applications:
- name: app1
envs:
- name: staging
version: v1.0.1
- name: production
version: v1.0.0
```
--------------------------------------------------------------------------------
/internal/testutils/time.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package testutils
import (
"testing"
"time"
. "github.com/onsi/gomega"
)
// ParseTime parses a time string in RFC3339 format and returns a time.Time object.
func ParseTime(t *testing.T, s string) time.Time {
t.Helper()
g := NewWithT(t)
tm, err := time.Parse(time.RFC3339, s)
g.Expect(err).NotTo(HaveOccurred())
return tm
}
```
--------------------------------------------------------------------------------
/config/monitoring/flux-controllers.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: flux-controllers
labels:
app.kubernetes.io/component: metrics
app.kubernetes.io/part-of: flux
spec:
namespaceSelector:
matchNames:
- flux-system
selector:
matchExpressions:
- key: app.kubernetes.io/part-of
operator: In
values:
- flux
podMetricsEndpoints:
- port: http-prom
```
--------------------------------------------------------------------------------
/config/monitoring/kustomization.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- flux-controllers.yaml
- flux-operator.yaml
configMapGenerator:
- name: flux-grafana-dashboards
files:
- dashboards/flux-k8s-api-performance.json
- dashboards/flux-performance.json
options:
labels:
grafana_dashboard: "1"
app.kubernetes.io/component: monitoring
app.kubernetes.io/part-of: flux
```
--------------------------------------------------------------------------------
/internal/inputs/json_test.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package inputs_test
import (
"testing"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"github.com/controlplaneio-fluxcd/flux-operator/internal/inputs"
)
func mustJSON(t *testing.T, s string) *apiextensionsv1.JSON {
id, err := inputs.JSON(s)
if err != nil {
t.Fatalf("failed to compute JSON: %v", err)
}
return id
}
```
--------------------------------------------------------------------------------
/web/tailwind.config.js:
--------------------------------------------------------------------------------
```javascript
/** @type {import('tailwindcss').Config} */
export default {
darkMode: 'class',
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
fontFamily: {
sans: ['inter', 'system-ui', 'sans-serif'],
},
colors: {
'flux-blue': '#0066CC',
'success': '#10B981',
'warning': '#F59E0B',
'danger': '#EF4444',
},
},
},
plugins: [],
}
```
--------------------------------------------------------------------------------
/internal/inputs/json.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package inputs
import (
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/util/json"
)
// JSON returns the Kubernetes API JSON representation of any value.
func JSON(v any) (*apiextensionsv1.JSON, error) {
b, err := json.Marshal(v)
if err != nil {
return nil, err
}
return &apiextensionsv1.JSON{Raw: b}, nil
}
```
--------------------------------------------------------------------------------
/config/rbac/fluxreport_viewer_role.yaml:
--------------------------------------------------------------------------------
```yaml
# permissions for end users to view fluxreports.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: flux-operator
app.kubernetes.io/managed-by: kustomize
name: fluxreport-viewer-role
rules:
- apiGroups:
- fluxcd.controlplane.io
resources:
- fluxreports
verbs:
- get
- list
- watch
- apiGroups:
- fluxcd.controlplane.io
resources:
- fluxreports/status
verbs:
- get
```
--------------------------------------------------------------------------------
/config/rbac/resourceset_viewer_role.yaml:
--------------------------------------------------------------------------------
```yaml
# permissions for end users to view fluxinstances.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: flux-operator
app.kubernetes.io/managed-by: kustomize
name: resourceset-viewer-role
rules:
- apiGroups:
- fluxcd.controlplane.io
resources:
- resourcesets
verbs:
- get
- list
- watch
- apiGroups:
- fluxcd.controlplane.io
resources:
- resourcesets/status
verbs:
- get
```
--------------------------------------------------------------------------------
/config/rbac/fluxinstance_viewer_role.yaml:
--------------------------------------------------------------------------------
```yaml
# permissions for end users to view fluxinstances.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: flux-operator
app.kubernetes.io/managed-by: kustomize
name: fluxinstance-viewer-role
rules:
- apiGroups:
- fluxcd.controlplane.io
resources:
- fluxinstances
verbs:
- get
- list
- watch
- apiGroups:
- fluxcd.controlplane.io
resources:
- fluxinstances/status
verbs:
- get
```
--------------------------------------------------------------------------------
/cmd/cli/testdata/build_resourceset/rsip-named.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
name: app1-tenant1
namespace: apps
spec:
type: Static
defaultValues:
tenant: "tenant1"
app:
version: "7.8.x"
replicas: 1
---
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
name: app1-tenant2
namespace: apps
spec:
type: Static
defaultValues:
tenant: "tenant2"
app:
version: "5.9.x"
replicas: 2
```
--------------------------------------------------------------------------------
/internal/builder/testdata/resourceset/missing-inputs.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
name: app1
namespace: apps
spec:
inputs:
- tenant: team1
semver: "1.x"
- tenant: team2
resources:
- apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
name: app1-<< inputs.tenant >>
namespace: apps
spec:
interval: 10m
url: oci://ghcr.io/org/charts/app1
ref:
semver: << inputs.semver >>
```
--------------------------------------------------------------------------------
/config/rbac/fluxreport_editor_role.yaml:
--------------------------------------------------------------------------------
```yaml
# permissions for end users to edit fluxreports.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: flux-operator
app.kubernetes.io/managed-by: kustomize
name: fluxreport-editor-role
rules:
- apiGroups:
- fluxcd.controlplane.io
resources:
- fluxreports
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- fluxcd.controlplane.io
resources:
- fluxreports/status
verbs:
- get
```
--------------------------------------------------------------------------------
/config/rbac/resourceset_editor_role.yaml:
--------------------------------------------------------------------------------
```yaml
# permissions for end users to edit fluxinstances.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: flux-operator
app.kubernetes.io/managed-by: kustomize
name: resourceset-editor-role
rules:
- apiGroups:
- fluxcd.controlplane.io
resources:
- resourcesets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- fluxcd.controlplane.io
resources:
- resourcesets/status
verbs:
- get
```
--------------------------------------------------------------------------------
/config/rbac/fluxinstance_editor_role.yaml:
--------------------------------------------------------------------------------
```yaml
# permissions for end users to edit fluxinstances.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: flux-operator
app.kubernetes.io/managed-by: kustomize
name: fluxinstance-editor-role
rules:
- apiGroups:
- fluxcd.controlplane.io
resources:
- fluxinstances
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- fluxcd.controlplane.io
resources:
- fluxinstances/status
verbs:
- get
```
--------------------------------------------------------------------------------
/config/crd/kustomizeconfig.yaml:
--------------------------------------------------------------------------------
```yaml
# This file is for teaching kustomize how to substitute name and namespace reference in CRD
nameReference:
- kind: Service
version: v1
fieldSpecs:
- kind: CustomResourceDefinition
version: v1
group: apiextensions.k8s.io
path: spec/conversion/webhook/clientConfig/service/name
namespace:
- kind: CustomResourceDefinition
version: v1
group: apiextensions.k8s.io
path: spec/conversion/webhook/clientConfig/service/namespace
create: false
varReference:
- path: metadata/annotations
```
--------------------------------------------------------------------------------
/config/olm/test/opm.Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
FROM alpine:3.20
ARG DOCKER_VERSION=26.1.3
ARG OPM_VERSION=4.15.16
# x86_64 or aarch64
ARG ARCH=x86_64
WORKDIR /opt
RUN wget https://download.docker.com/linux/static/stable/${ARCH}/docker-${DOCKER_VERSION}.tgz
RUN tar xf docker-${DOCKER_VERSION}.tgz
RUN wget https://mirror.openshift.com/pub/openshift-v4/${ARCH}/clients/ocp/${OPM_VERSION}/opm-linux-${OPM_VERSION}.tar.gz
RUN tar xf opm-linux-${OPM_VERSION}.tar.gz
FROM ubuntu:24.04
WORKDIR /opt
COPY --from=0 /opt/docker/docker /usr/bin/
COPY --from=0 /opt/opm /opt/
ENTRYPOINT ["/opt/opm"]
```
--------------------------------------------------------------------------------
/config/samples/fluxcd_v1_resourcesetinputprovider.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
name: demo
namespace: default
annotations:
fluxcd.controlplane.io/reconcile: "enabled"
fluxcd.controlplane.io/reconcileEvery: "10m"
fluxcd.controlplane.io/reconcileTimeout: "1m"
spec:
type: GitHubPullRequest
url: "https://github.com/fluxcd-testing/pr-testing"
filter:
limit: 10
includeBranch: "^stefanprodan-patch-.*$"
labels:
- "enhancement"
skip:
labels:
- "deploy/flux-preview-pause"
- "!test-build-push/passed"
```
--------------------------------------------------------------------------------
/cmd/cli/testdata/build_resourceset/rsip-labeled.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
name: app1-tenant1
namespace: apps
labels:
some: label
anotherLabel: value1
spec:
type: Static
defaultValues:
tenant: "tenant1"
app:
version: "6.7.x"
replicas: 2
---
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
name: app1-tenant2
namespace: apps
labels:
some: label
anotherLabel: value2
spec:
type: Static
defaultValues:
tenant: "tenant2"
app:
version: "6.6.x"
replicas: 3
```
--------------------------------------------------------------------------------
/cmd/mcp/k8s/suite_test.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package k8s
import (
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
fluxcdv1 "github.com/controlplaneio-fluxcd/flux-operator/api/v1"
)
func NewTestScheme() *runtime.Scheme {
s := runtime.NewScheme()
utilruntime.Must(corev1.AddToScheme(s))
utilruntime.Must(apiextensionsv1.AddToScheme(s))
utilruntime.Must(fluxcdv1.AddToScheme(s))
return s
}
```
--------------------------------------------------------------------------------
/.github/workflows/actions-test.yaml:
--------------------------------------------------------------------------------
```yaml
name: actions
on:
pull_request:
paths:
- 'action/**'
- '.github/workflows/actions-test.yaml'
push:
branches:
- 'main'
paths:
- 'actions/**'
- '.github/workflows/actions-test.yaml'
permissions:
contents: read # for actions/checkout to fetch code
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup CLI
uses: ./actions/setup
- name: Run CLI
run: flux-operator version --client
```
--------------------------------------------------------------------------------
/config/rbac/leader_election_role.yaml:
--------------------------------------------------------------------------------
```yaml
# permissions to do leader election.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/name: flux-operator
app.kubernetes.io/managed-by: kustomize
name: leader-election-role
rules:
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
```
--------------------------------------------------------------------------------
/config/terraform/values/components.yaml:
--------------------------------------------------------------------------------
```yaml
instance:
components:
- source-controller
- kustomize-controller
- helm-controller
- notification-controller
- image-reflector-controller
- image-automation-controller
kustomize:
patches:
- target:
kind: Deployment
patch: |
- op: replace
path: /spec/template/spec/nodeSelector
value:
kubernetes.io/os: linux
- op: add
path: /spec/template/spec/tolerations
value:
- key: "CriticalAddonsOnly"
operator: "Exists"
```
--------------------------------------------------------------------------------
/internal/builder/testdata/resourceset/noinputs.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
name: app1
namespace: apps
spec:
resources:
- apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
name: app1
namespace: apps
spec:
interval: 10m
url: oci://ghcr.io/org/charts/app1
ref:
semver: '*'
- apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: app1
namespace: apps
spec:
interval: 1h
releaseName: app1
chartRef:
kind: OCIRepository
name: app1
```
--------------------------------------------------------------------------------
/.github/actions/runner-cleanup/action.yml:
--------------------------------------------------------------------------------
```yaml
name: Runner Cleanup
description: A GitHub Action for removing bloat from Ubuntu GitHub Actions runner.
author: Stefan Prodan
branding:
color: blue
icon: command
runs:
using: composite
steps:
- name: "Disk Usage Before Cleanup"
shell: bash
run: |
df -h
- name: "Remove .NET, Android and Haskell"
shell: bash
run: |
sudo rm -rf /usr/share/dotnet || true
sudo rm -rf /usr/local/lib/android || true
sudo rm -rf /opt/ghc || true
sudo rm -rf /usr/local/.ghcup || true
- name: "Disk Usage After Cleanup"
shell: bash
run: |
df -h
```
--------------------------------------------------------------------------------
/test/olm/scorecard_test.go:
--------------------------------------------------------------------------------
```go
// Copyright 2024 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package e2eolm
import (
"os/exec"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
utils "github.com/controlplaneio-fluxcd/flux-operator/test/e2e"
)
var _ = Describe("Scorecard", Ordered, func() {
Context("test", func() {
It("should run successfully", func() {
By("run scorecard tests")
cmd := exec.Command(operatorsdkBin, "scorecard",
img, "-c", bundlePath+"/"+version+"/tests/scorecard/config.yaml",
"-w", "5m", "-o", "json")
_, err := utils.Run(cmd, "/test/olm")
ExpectWithOffset(2, err).NotTo(HaveOccurred())
})
})
})
```
--------------------------------------------------------------------------------
/internal/builder/testdata/resourceset/dedup.golden.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
name: app1
namespace: apps
spec:
interval: 10m
ref:
semver: '*'
url: oci://ghcr.io/org/charts/app1
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: app1-team1
namespace: apps
spec:
chartRef:
kind: OCIRepository
name: app1
interval: 1h
releaseName: app1-team1
values:
replicas: 2
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: app1-team2
namespace: apps
spec:
chartRef:
kind: OCIRepository
name: app1
interval: 1h
releaseName: app1-team2
values:
replicas: 3
---
```
--------------------------------------------------------------------------------
/internal/web/auth/errors.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package auth
import (
"errors"
)
var (
errUserError = errors.New("user error")
errInternalError = errors.New("internal error")
)
// sanitizeErrorMessage returns a user-friendly error message. It
// avoids exposing internal error details that could aid attackers.
func sanitizeErrorMessage(err error) string {
switch {
case errors.Is(err, errInternalError), errors.Is(err, errInvalidOAuth2Scopes):
return "An internal error occurred. Please try again. Contact your administrator if the problem persists."
default:
return "Authentication failed. Please try again."
}
}
```
--------------------------------------------------------------------------------
/cmd/cli/completion_bash.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"os"
"github.com/spf13/cobra"
)
var completionBashCmd = &cobra.Command{
Use: "bash",
Short: "Generates bash completion scripts",
Example: `To load completion run
. <(flux-operator completion bash)
To configure your bash shell to load completions for each session add to your bashrc
# ~/.bashrc or ~/.profile
command -v flux-operator >/dev/null && . <(flux-operator completion bash)`,
Run: func(cmd *cobra.Command, args []string) {
rootCmd.GenBashCompletion(os.Stdout) //nolint:errcheck
},
}
func init() {
completionCmd.AddCommand(completionBashCmd)
}
```
--------------------------------------------------------------------------------
/config/data/flux/v2.2.3/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.3.0/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.4.0/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.5.0/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.5.1/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.6.0/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.6.1/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.6.2/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.6.3/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.6.4/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.7.0/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.7.1/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.7.2/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.7.3/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.7.4/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/config/data/flux/v2.7.5/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/internal/builder/testdata/v2.3.0/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/internal/builder/testdata/v2.6.0/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/internal/builder/testdata/v2.7.0/policies.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress
spec:
egress:
- {}
ingress:
- from:
- podSelector: {}
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-scraping
spec:
ingress:
- from:
- namespaceSelector: {}
ports:
- port: 8080
protocol: TCP
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-webhooks
spec:
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: notification-controller
policyTypes:
- Ingress
```
--------------------------------------------------------------------------------
/cmd/cli/completion_fish.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"os"
"github.com/spf13/cobra"
)
var completionFishCmd = &cobra.Command{
Use: "fish",
Short: "Generates fish completion scripts",
Example: `To configure your fish shell to load completions for each session write this script to your completions dir:
flux-operator completion fish > ~/.config/fish/completions/flux-operator.fish
See http://fishshell.com/docs/current/index.html#completion-own for more details`,
Run: func(cmd *cobra.Command, args []string) {
rootCmd.GenFishCompletion(os.Stdout, true) //nolint:errcheck
},
}
func init() {
completionCmd.AddCommand(completionFishCmd)
}
```
--------------------------------------------------------------------------------
/internal/builder/digest.go:
--------------------------------------------------------------------------------
```go
// Copyright 2024 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package builder
import (
"context"
"fmt"
"strings"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/crane"
)
// GetArtifactDigest looks up an artifact from an OCI repository and returns the digest of the artifact.
func GetArtifactDigest(ctx context.Context, ociURL string, keyChain authn.Keychain) (string, error) {
digest, err := crane.Digest(strings.TrimPrefix(ociURL, "oci://"), crane.WithContext(ctx), crane.WithAuthFromKeychain(keyChain))
if err != nil {
return "", fmt.Errorf("fetching digest for artifact %s failed: %w", ociURL, err)
}
return digest, nil
}
```
--------------------------------------------------------------------------------
/cmd/mcp/toolbox/testdata/kubeconfig.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority-data: cGFzc3dvcmQ=
server: https://127.0.0.1:57975
name: kind-dev
- cluster:
certificate-authority-data: dGVzdDI=
server: https://127.0.0.1:57974
name: kind-staging
contexts:
- context:
cluster: kind-dev
user: kind-dev
name: kind-dev
- context:
cluster: kind-staging
user: kind-staging
name: kind-staging
current-context: kind-dev
preferences: {}
users:
- name: kind-dev
user:
client-certificate-data: cGFzc3dvcmQ=
client-key-data: test
- name: kind-staging
user:
client-certificate-data: dGVzdDI=
client-key-data: test
```
--------------------------------------------------------------------------------
/internal/inputs/flattener.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package inputs
// Flattener is a strategy that flattens the inputs from multiple providers
// into a single list by concatenating them.
type Flattener struct {
combined Combined
}
// NewFlattener returns a new initialized *Flattener.
func NewFlattener() *Flattener {
return &Flattener{}
}
// AddProvider adds the inputs from a provider to the flattener.
func (f *Flattener) AddProvider(name string, inputs []map[string]any) error {
f.combined = append(f.combined, ToCombined(inputs)...)
return nil
}
// Combine returns the combined inputs as a single flattened list.
func (f *Flattener) Combine() Combined {
return f.combined
}
```
--------------------------------------------------------------------------------
/config/rbac/role.yaml:
--------------------------------------------------------------------------------
```yaml
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: manager-role
rules:
- apiGroups:
- fluxcd.controlplane.io
resources:
- fluxinstances
- fluxreports
- resourcesetinputproviders
- resourcesets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- fluxcd.controlplane.io
resources:
- fluxinstances/finalizers
- fluxreports/finalizers
- resourcesetinputproviders/finalizers
- resourcesets/finalizers
verbs:
- update
- apiGroups:
- fluxcd.controlplane.io
resources:
- fluxinstances/status
- fluxreports/status
- resourcesetinputproviders/status
- resourcesets/status
verbs:
- get
- patch
- update
```
--------------------------------------------------------------------------------
/internal/entitlement/client_test.go:
--------------------------------------------------------------------------------
```go
// Copyright 2024 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package entitlement
import (
"testing"
. "github.com/onsi/gomega"
)
func TestNewClient_DefaultVendor(t *testing.T) {
g := NewWithT(t)
// Unset the environment variable
t.Setenv(MarketplaceTypeEnvKey, "")
client, err := NewClient()
g.Expect(err).ToNot(HaveOccurred())
g.Expect(client).ToNot(BeNil())
g.Expect(client.GetVendor()).To(Equal(DefaultVendor))
}
func TestNewClient_UnsupportedVendor(t *testing.T) {
g := NewWithT(t)
// Set the environment variable to an unsupported value
t.Setenv(MarketplaceTypeEnvKey, "unsupported")
client, err := NewClient()
g.Expect(err).To(HaveOccurred())
g.Expect(client).To(BeNil())
}
```
--------------------------------------------------------------------------------
/api/v1/groupversion_info.go:
--------------------------------------------------------------------------------
```go
// Copyright 2024 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
// Package v1 contains API Schema definitions for the fluxcd v1 API group
// +kubebuilder:object:generate=true
// +groupName=fluxcd.controlplane.io
package v1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)
var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "fluxcd.controlplane.io", Version: "v1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
```
--------------------------------------------------------------------------------
/internal/gitprovider/interface.go:
--------------------------------------------------------------------------------
```go
// Copyright 2024 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package gitprovider
import (
"context"
)
// Interface that all Git SaaS providers must implement.
type Interface interface {
// ListTags returns a list of tags that match the filters.
ListTags(ctx context.Context, opts Options) ([]Result, error)
// ListBranches returns a list of branches that match the filters.
ListBranches(ctx context.Context, opts Options) ([]Result, error)
// ListRequests returns a list of pull/merge requests that match the filters.
ListRequests(ctx context.Context, opts Options) ([]Result, error)
// ListEnvironments returns a list of environments that match the filters.
ListEnvironments(ctx context.Context, opts Options) ([]Result, error)
}
```
--------------------------------------------------------------------------------
/cmd/mcp/prompter/manager.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package prompter
import (
"github.com/modelcontextprotocol/go-sdk/mcp"
)
type SystemPrompt struct {
Prompt *mcp.Prompt
Handler mcp.PromptHandler
}
// Manager represents an entity responsible for managing and
// registering prompts and their handlers in a server.
type Manager struct{}
// NewManager creates and returns a new instance of Manager
// for managing and registering prompts and their handlers.
func NewManager() *Manager {
return &Manager{}
}
// RegisterPrompts registers all prompts in the Manager's PromptSet with the provided server.
func (m *Manager) RegisterPrompts(server *mcp.Server) {
for _, p := range m.PromptSet() {
server.AddPrompt(p.Prompt, p.Handler)
}
}
```
--------------------------------------------------------------------------------
/internal/testutils/log.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package testutils
import (
"testing"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/yaml"
fluxcdv1 "github.com/controlplaneio-fluxcd/flux-operator/api/v1"
)
// LogObjectStatus logs the status fields of a FluxObject in YAML format.
func LogObjectStatus(t *testing.T, obj fluxcdv1.FluxObject) {
u, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
status, _, _ := unstructured.NestedFieldCopy(u, "status")
sts, _ := yaml.Marshal(status)
t.Log(obj.GetName(), "status:\n", string(sts))
}
// LogObject logs the entire FluxObject in YAML format.
func LogObject(t *testing.T, obj fluxcdv1.FluxObject) {
sts, _ := yaml.Marshal(obj)
t.Log("object:\n", string(sts))
}
```
--------------------------------------------------------------------------------
/internal/builder/testdata/resourceset/dedup.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
name: app1
namespace: apps
spec:
inputs:
- tenant: team1
replicas: "2"
- tenant: team2
replicas: "3"
resources:
- apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
name: app1
namespace: apps
spec:
interval: 10m
url: oci://ghcr.io/org/charts/app1
ref:
semver: '*'
- apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: app1-<< inputs.tenant >>
namespace: apps
spec:
interval: 1h
releaseName: app1-<< inputs.tenant >>
chartRef:
kind: OCIRepository
name: app1
values:
replicas: << inputs.replicas | int >>
```
--------------------------------------------------------------------------------
/config/olm/test/olm.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: flux-system
---
apiVersion: operators.coreos.com/v1alpha1
kind: CatalogSource
metadata:
name: custom
namespace: flux-system
spec:
description: custom
displayName: custom
image: ghcr.io/controlplaneio-fluxcd/openshift-flux-operator-index:v${FLUX_OPERATOR_VERSION}
publisher: custom
sourceType: grpc
updateStrategy:
registryPoll:
interval: 30m
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: flux-subscription
namespace: flux-system
spec:
channel: stable
name: flux-operator
source: custom
sourceNamespace: flux-system
startingCSV: flux-operator.v${FLUX_OPERATOR_VERSION}
---
apiVersion: operators.coreos.com/v1alpha2
kind: OperatorGroup
metadata:
name: flux-system-group
namespace: flux-system
```
--------------------------------------------------------------------------------
/internal/builder/testdata/resourceset/invalid-output.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
name: app1
namespace: apps
spec:
inputs:
- tenant: team1
semver: ">=1.0.0-rc.0"
- tenant: team2
semver: ">=1.0.0-rc.0"
resources:
- apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
name: app1-<< inputs.tenant >>
namespace: apps
spec:
interval: 10m
url: oci://ghcr.io/org/charts/app1
ref:
semver: << inputs.semver >>
- apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: app1-<< inputs.tenant >>
namespace: apps
spec:
interval: 1h
releaseName: app1-<< inputs.tenant >>
chartRef:
kind: OCIRepository
name: app1-<< inputs.tenant >>
```
--------------------------------------------------------------------------------
/cmd/cli/get.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"io"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
)
var getCmd = &cobra.Command{
Use: "get",
Short: "List Flux Operator resources",
}
func init() {
rootCmd.AddCommand(getCmd)
}
func printTable(writer io.Writer, header []string, rows [][]string) {
table := tablewriter.NewWriter(writer)
table.SetHeader(header)
table.SetAutoWrapText(false)
table.SetAutoFormatHeaders(true)
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetCenterSeparator("")
table.SetColumnSeparator("")
table.SetRowSeparator("")
table.SetHeaderLine(false)
table.SetBorder(false)
table.SetTablePadding("\t")
table.SetNoWhiteSpace(true)
table.AppendBulk(rows)
table.Render()
}
```
--------------------------------------------------------------------------------
/web/vite.config.js:
--------------------------------------------------------------------------------
```javascript
import { defineConfig } from 'vite'
import preact from '@preact/preset-vite'
export default defineConfig(() => {
const useMockData = process.env.VITE_USE_MOCK_DATA === 'true'
return {
plugins: [preact()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './vitest.setup.js',
env: {
MODE: 'test',
VITE_USE_MOCK_DATA: 'false'
}
},
build: {
outDir: 'dist',
emptyOutDir: true,
assetsDir: 'assets',
rollupOptions: {
output: {
manualChunks: undefined,
},
},
},
// API proxy for development server (disabled when using mock data)
server: useMockData ? {} : {
proxy: {
'/api': {
target: 'http://localhost:9080',
changeOrigin: true,
},
},
},
}
})
```
--------------------------------------------------------------------------------
/cmd/cli/testdata/build_resourceset/rset-with-rsip-named.yaml:
--------------------------------------------------------------------------------
```yaml
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
name: app1
namespace: apps
spec:
inputsFrom:
- name: app1-tenant1
- name: app1-tenant2
resources:
- apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
name: app1-<< inputs.tenant >>
namespace: apps
spec:
interval: 10m
url: oci://my.registry/org/charts/app1
ref:
semver: << inputs.app.version | quote >>
- apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: app1-<< inputs.tenant >>
namespace: apps
spec:
interval: 1h
releaseName: app1-<< inputs.tenant >>
chartRef:
kind: OCIRepository
name: app1-<< inputs.tenant >>
values:
replicaCount: << inputs.app.replicas | int >>
```
--------------------------------------------------------------------------------
/config/rbac/kustomization.yaml:
--------------------------------------------------------------------------------
```yaml
resources:
# All RBAC will be applied under this service account in
# the deployment namespace. You may comment out this resource
# if your manager will use a service account that exists at
# runtime. Be sure to update RoleBinding and ClusterRoleBinding
# subjects if changing service account names.
- service_account.yaml
- role.yaml
- role_binding.yaml
- leader_election_role.yaml
- leader_election_role_binding.yaml
# For each CRD, "Editor" and "Viewer" roles are scaffolded by
# default, aiding admins in cluster management. Those roles are
# not used by the Project itself. You can comment the following lines
# if you do not want those helpers be installed with your Project.
- fluxreport_editor_role.yaml
- fluxreport_viewer_role.yaml
- fluxinstance_editor_role.yaml
- fluxinstance_viewer_role.yaml
- resourceset_editor_role.yaml
- resourceset_viewer_role.yaml
```
--------------------------------------------------------------------------------
/cmd/cli/completion_powershell.go:
--------------------------------------------------------------------------------
```go
// Copyright 2025 Stefan Prodan.
// SPDX-License-Identifier: AGPL-3.0
package main
import (
"os"
"github.com/spf13/cobra"
)
var completionPowerShellCmd = &cobra.Command{
Use: "powershell",
Short: "Generates powershell completion scripts",
Example: `To load completion run
. <(flux-operator completion powershell)
To configure your powershell shell to load completions for each session add to your powershell profile
Windows:
cd "$env:USERPROFILE\Documents\WindowsPowerShell\Modules"
flux-operator completion >> flux-operator-completion.ps1
Linux:
cd "${XDG_CONFIG_HOME:-"$HOME/.config/"}/powershell/modules"
flux-operator completion >> flux-operator-completions.ps1`,
Run: func(cmd *cobra.Command, args []string) {
rootCmd.GenPowerShellCompletion(os.Stdout) //nolint:errcheck
},
}
func init() {
completionCmd.AddCommand(completionPowerShellCmd)
}
```
--------------------------------------------------------------------------------
/config/olm/bundle/metadata/annotations.yaml:
--------------------------------------------------------------------------------
```yaml
annotations:
# Core bundle annotations.
operators.operatorframework.io.bundle.channels.v1: stable
operators.operatorframework.io.bundle.channel.default.v1: stable
operators.operatorframework.io.bundle.manifests.v1: manifests/
operators.operatorframework.io.bundle.mediatype.v1: registry+v1
operators.operatorframework.io.bundle.metadata.v1: metadata/
operators.operatorframework.io.bundle.package.v1: flux-operator
operators.operatorframework.io.metrics.builder: operator-sdk-v1.41.0
operators.operatorframework.io.metrics.mediatype.v1: metrics+v1
operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v4
# Annotations for testing.
operators.operatorframework.io.test.mediatype.v1: scorecard+v1
operators.operatorframework.io.test.config.v1: tests/scorecard/
# OpenShift specific annotations
com.redhat.openshift.versions: "v4.12-v4.19"
```
--------------------------------------------------------------------------------
/web/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "flux-status-page",
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint src --ext .jsx",
"lint:fix": "eslint src --ext .jsx --fix",
"test": "vitest --run"
},
"dependencies": {
"@preact/signals": "^2.5.1",
"js-yaml": "^4.1.1",
"preact": "^10.28.2",
"preact-iso": "^2.11.1",
"prismjs": "^1.30.0"
},
"devDependencies": {
"@eslint/js": "^9.39.0",
"@preact/preset-vite": "^2.10.2",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/preact": "^3.2.4",
"@testing-library/user-event": "^14.6.1",
"@vitest/coverage-v8": "^4.0.16",
"autoprefixer": "^10.4.23",
"eslint": "^9.39.2",
"jsdom": "^27.4.0",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.19",
"vite": "^7.3.1",
"vitest": "^4.0.9"
}
}
```
--------------------------------------------------------------------------------
/cmd/mcp/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
# Build the Flux MCP server binary using Docker's Debian image.
FROM --platform=${BUILDPLATFORM} golang:1.25 AS builder
ARG TARGETOS
ARG TARGETARCH
ARG VERSION
WORKDIR /workspace
# Copy the Go Modules manifests.
COPY go.mod go.mod
COPY go.sum go.sum
# Cache the Go Modules
RUN go mod download
# Copy the Go sources.
COPY cmd/mcp/ cmd/mcp/
COPY api/ api/
COPY internal/ internal/
# Build the server binary.
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} \
go build -ldflags="-s -w -X main.VERSION=${VERSION}" -a -o flux-operator-mcp ./cmd/mcp/
# Run the server binary using Google's Distroless image.
FROM gcr.io/distroless/static:nonroot
WORKDIR /
# Copy the license.
COPY LICENSE /licenses/LICENSE
# Copy the server binary.
COPY --from=builder /workspace/flux-operator-mcp .
# Run the server under a non-root user.
USER 65532:65532
ENTRYPOINT ["/flux-operator-mcp"]
```
--------------------------------------------------------------------------------
/config/data/flux-images/v2.3.0/upstream-alpine.yaml:
--------------------------------------------------------------------------------
```yaml
images:
- name: ghcr.io/fluxcd/source-controller
newTag: v1.3.0
digest: sha256:161da425b16b64dda4b3cec2ba0f8d7442973aba29bb446db3b340626181a0bc
- name: ghcr.io/fluxcd/kustomize-controller
newTag: v1.3.0
digest: sha256:48a032574dd45c39750ba0f1488e6f1ae36756a38f40976a6b7a588d83acefc1
- name: ghcr.io/fluxcd/helm-controller
newTag: v1.0.1
digest: sha256:a67a037faa850220ff94d8090253732079589ad9ff10b6ddf294f3b7cd0f3424
- name: ghcr.io/fluxcd/notification-controller
newTag: v1.3.0
digest: sha256:c0fab940c7e578ea519097d36c040238b0cc039ce366fdb753947428bbf0c3d6
- name: ghcr.io/fluxcd/image-reflector-controller
newTag: v0.32.0
digest: sha256:aed795c7a8b85bca93f6d199d5a14bbefaf925ad5aa5316b32a716cfa4070d0b
- name: ghcr.io/fluxcd/image-automation-controller
newTag: v0.38.0
digest: sha256:ab5097213194f3cd9f0e68d8a937d94c4fc7e821f6544453211e94815b282aa2
```
--------------------------------------------------------------------------------
/config/data/flux-images/v2.4.0/upstream-alpine.yaml:
--------------------------------------------------------------------------------
```yaml
images:
- name: ghcr.io/fluxcd/source-controller
newTag: v1.4.1
digest: sha256:3c5f0f022f990ffc0daf00e5b199548fc0fa6e7119e972318f0267081a332963
- name: ghcr.io/fluxcd/kustomize-controller
newTag: v1.4.0
digest: sha256:e3b0cf847e9cdf47b19af0fbcfe22786b80b598e0caeea8b6d2a5f9c26a48a24
- name: ghcr.io/fluxcd/helm-controller
newTag: v1.1.0
digest: sha256:4c75ca6c24ceb1f1bd7e935d9287a93e4f925c512f206763ec5a47de3ef3ff48
- name: ghcr.io/fluxcd/notification-controller
newTag: v1.4.0
digest: sha256:425309a159b15e07f7d97622effc79bc432a37ed55289dd465d37fa217a92a7d
- name: ghcr.io/fluxcd/image-reflector-controller
newTag: v0.33.0
digest: sha256:c6864684f96cfbb3a91c816084032bb019b302af8b63b0e06b12b4018a9a8242
- name: ghcr.io/fluxcd/image-automation-controller
newTag: v0.39.0
digest: sha256:5b6c2e97055cfe69fe8996f48b53db039c136210dbc98c5631864a9e573d0e20
```
--------------------------------------------------------------------------------
/config/data/flux-images/v2.5.0/upstream-alpine.yaml:
--------------------------------------------------------------------------------
```yaml
images:
- name: ghcr.io/fluxcd/source-controller
newTag: v1.5.0
digest: sha256:00cd9316a3790f3e212132f38c849f87d6e6eeca6272ec9557387be3cec054be
- name: ghcr.io/fluxcd/kustomize-controller
newTag: v1.5.0
digest: sha256:590deed942202f1e4097b9996a4d2892995605af94f730635169c7f15f9e79e3
- name: ghcr.io/fluxcd/helm-controller
newTag: v1.2.0
digest: sha256:62eaa9c9a9296a22684f9a77befa4f7fbf850fc314da47b3d6c28ad2e34ba965
- name: ghcr.io/fluxcd/notification-controller
newTag: v1.5.0
digest: sha256:9fe4b5fb312eace22e43969975938deca08d64282c9a1e2783afe91be3da2869
- name: ghcr.io/fluxcd/image-reflector-controller
newTag: v0.34.0
digest: sha256:d002d16ab3bd4b370b23d989525182c19a068d5c1d63764acb14e43709d1949b
- name: ghcr.io/fluxcd/image-automation-controller
newTag: v0.40.0
digest: sha256:8c9de4b247271d6b02293f0cbc901e79b14b57b7ef0d8989dfdf3ec6151df8d5
```
--------------------------------------------------------------------------------
/config/data/flux-images/v2.5.1/upstream-alpine.yaml:
--------------------------------------------------------------------------------
```yaml
images:
- name: ghcr.io/fluxcd/source-controller
newTag: v1.5.0
digest: sha256:00cd9316a3790f3e212132f38c849f87d6e6eeca6272ec9557387be3cec054be
- name: ghcr.io/fluxcd/kustomize-controller
newTag: v1.5.1
digest: sha256:b89935f9428764c389c5192fdb8f6c53b66e365fa09ac8cec597e82273e9f518
- name: ghcr.io/fluxcd/helm-controller
newTag: v1.2.0
digest: sha256:62eaa9c9a9296a22684f9a77befa4f7fbf850fc314da47b3d6c28ad2e34ba965
- name: ghcr.io/fluxcd/notification-controller
newTag: v1.5.0
digest: sha256:9fe4b5fb312eace22e43969975938deca08d64282c9a1e2783afe91be3da2869
- name: ghcr.io/fluxcd/image-reflector-controller
newTag: v0.34.0
digest: sha256:d002d16ab3bd4b370b23d989525182c19a068d5c1d63764acb14e43709d1949b
- name: ghcr.io/fluxcd/image-automation-controller
newTag: v0.40.0
digest: sha256:8c9de4b247271d6b02293f0cbc901e79b14b57b7ef0d8989dfdf3ec6151df8d5
```
--------------------------------------------------------------------------------
/config/data/flux-images/v2.6.0/upstream-alpine.yaml:
--------------------------------------------------------------------------------
```yaml
images:
- name: ghcr.io/fluxcd/source-controller
newTag: v1.6.0
digest: sha256:44ea51a40e4da2c0f19427df3219f29b86c8fce38539d227f6ffc2bdc944036f
- name: ghcr.io/fluxcd/kustomize-controller
newTag: v1.6.0
digest: sha256:d8c5445003196791441354f2d549e96cc6e69bb9ef6c5a7e440918dab0503776
- name: ghcr.io/fluxcd/helm-controller
newTag: v1.3.0
digest: sha256:db55d9d9f9b5106acd8c21da6916b8e285fcfc5572f214361ececd1a8571a4f0
- name: ghcr.io/fluxcd/notification-controller
newTag: v1.6.0
digest: sha256:80174ff676407af7a6feff67b0c2f100de9f7f89df4c26fc871e4d4c4006544d
- name: ghcr.io/fluxcd/image-reflector-controller
newTag: v0.35.0
digest: sha256:dcfb9bfd6dea79f608788dc1e9821f297cf62c053bb51b482fcaf5b674a3198a
- name: ghcr.io/fluxcd/image-automation-controller
newTag: v0.41.0
digest: sha256:868010070f063758282bf0c64cf17c6150b51d6eee49d40647706ccbd93c109d
```
--------------------------------------------------------------------------------
/config/data/flux-images/v2.6.1/upstream-alpine.yaml:
--------------------------------------------------------------------------------
```yaml
images:
- name: ghcr.io/fluxcd/source-controller
newTag: v1.6.0
digest: sha256:44ea51a40e4da2c0f19427df3219f29b86c8fce38539d227f6ffc2bdc944036f
- name: ghcr.io/fluxcd/kustomize-controller
newTag: v1.6.0
digest: sha256:d8c5445003196791441354f2d549e96cc6e69bb9ef6c5a7e440918dab0503776
- name: ghcr.io/fluxcd/helm-controller
newTag: v1.3.0
digest: sha256:db55d9d9f9b5106acd8c21da6916b8e285fcfc5572f214361ececd1a8571a4f0
- name: ghcr.io/fluxcd/notification-controller
newTag: v1.6.0
digest: sha256:80174ff676407af7a6feff67b0c2f100de9f7f89df4c26fc871e4d4c4006544d
- name: ghcr.io/fluxcd/image-reflector-controller
newTag: v0.35.1
digest: sha256:65e68ed78cac29a9f42b83098ec8fa1e40a6ef554f89303da1520cff68ec5a05
- name: ghcr.io/fluxcd/image-automation-controller
newTag: v0.41.0
digest: sha256:868010070f063758282bf0c64cf17c6150b51d6eee49d40647706ccbd93c109d
```