{"id":51120781,"url":"https://github.com/cloudoperators/shoot-grafter","last_synced_at":"2026-06-25T02:01:05.172Z","repository":{"id":332927906,"uuid":"1040076864","full_name":"cloudoperators/shoot-grafter","owner":"cloudoperators","description":"Automatic onboarding of Gardener Shoots to Greenhouse","archived":false,"fork":false,"pushed_at":"2026-06-22T11:56:59.000Z","size":11447,"stargazers_count":1,"open_issues_count":17,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-22T13:25:39.651Z","etag":null,"topics":["gardener","greenhouse","kubebuilder","kubernetes","monitoring","operations"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudoperators.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-18T12:24:32.000Z","updated_at":"2026-06-12T12:31:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cloudoperators/shoot-grafter","commit_stats":null,"previous_names":["cloudoperators/shoot-grafter"],"tags_count":3,"template":false,"template_full_name":"cloudoperators/repository-template","purl":"pkg:github/cloudoperators/shoot-grafter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudoperators%2Fshoot-grafter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudoperators%2Fshoot-grafter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudoperators%2Fshoot-grafter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudoperators%2Fshoot-grafter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudoperators","download_url":"https://codeload.github.com/cloudoperators/shoot-grafter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudoperators%2Fshoot-grafter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34756206,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-25T02:00:05.521Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gardener","greenhouse","kubebuilder","kubernetes","monitoring","operations"],"created_at":"2026-06-25T02:01:03.911Z","updated_at":"2026-06-25T02:01:05.157Z","avatar_url":"https://github.com/cloudoperators.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\nSPDX-FileCopyrightText: 2026 SAP SE or an SAP affiliate company and Greenhouse contributors\n\nSPDX-License-Identifier: Apache-2.0\n--\u003e\n\n[![REUSE status](https://api.reuse.software/badge/github.com/cloudoperators/shoot-grafter)](https://api.reuse.software/info/github.com/cloudoperators/shoot-grafter)\n\n# shoot-grafter\n\n## About this project\n\n**shoot-grafter** is a Kubernetes operator that automates the onboarding of [Gardener](https://gardener.cloud/) Shoots (Kubernetes clusters managed by Gardener) to [Greenhouse](https://github.com/cloudoperators/greenhouse), the cloud operations platform. It bridges the gap between Gardener-managed infrastructure and Greenhouse's centralized cluster management by dynamically discovering and registering Shoots as Greenhouse Clusters.\n\nThe name \"shoot-grafter\" continues Gardener's and Greenhouse's botanical theme: just as a gardener grafts shoots onto rootstock to create robust plants, this operator grafts (connects) Gardener Shoots onto Greenhouse's centralized platform to create fully operational k8s clusters.\n\nThis project is part of the [NeoNephos Foundation](https://neonephos.org/).\n\n## What does shoot-grafter do?\n\nshoot-grafter continuously monitors Garden clusters for Shoots matching specific criteria and automatically:\n\n1. **Discovers Shoots**: Watches for Gardener Shoot resources in specified namespaces based on label selectors and CEL expressions\n2. **Extracts cluster credentials**: Retrieves API server URLs and CA certificates from Shoot resources\n3. **Creates Greenhouse Clusters**: Automatically registers discovered Shoots as Greenhouse Cluster resources\n4. **Propagates labels**: Transfers specified labels from Shoots to Greenhouse Clusters for consistent organization\n5. **Configures OIDC authentication**: Optionally configures OIDC authentication on Shoot clusters to enable Greenhouse authentication\n6. **Configures RBAC**: Optionally sets up role-based access control on Shoot clusters for Greenhouse service accounts\n7. **Maintains synchronization**: Keeps Greenhouse Cluster resources in sync with their corresponding Shoots\n\nshoot-grafter currently only creates clusters matching Shoots but does not automatically clean up clusters when Shoot labels change or Shoots are deleted. Manual cleanup of Greenhouse Cluster resources is required in these scenarios.\n\n## Architecture\n\n```mermaid\ngraph LR\n    subgraph Garden[\"Garden API\"]\n        direction TB\n        subgraph NS1[\" \"]\n            NS1Title[\"Shoots in ns: garden--production\"]\n            Shoot1[\"Shoot-prod-1\u003cbr/\u003e(env=prod)\"]\n            Shoot2[\"Shoot-prod-2\u003cbr/\u003e(env=prod)\"]\n        end\n        subgraph NS2[\" \"]\n            NS2Title[\"Shoots in ns: garden--development\"]\n            Shoot3[\"Shoot-dev-1\u003cbr/\u003e(env=dev)\"]\n            Shoot4[\"Shoot-dev-2\u003cbr/\u003e(env=staging)\"]\n        end\n    end\n    \n    subgraph Greenhouse[\"Greenhouse\"]\n        direction TB\n        \n        subgraph ShootGrafter[\"shoot-grafter\"]\n            CIC[CareInstruction Controller]\n            \n            subgraph CareInstructions[\" \"]\n                CITitle[\"CareInstructions\"]\n                CI1[\"prod-shoots\u003cbr/\u003egardenNamespace: garden--production\u003cbr/\u003eshootSelector.labelSelector: env=prod\"]\n                CI2[\"dev-shoots\u003cbr/\u003egardenNamespace: garden--development\u003cbr/\u003eshootSelector.labelSelector: env=dev\"]\n            end\n            \n            subgraph DynamicControllers[\" \"]\n                DCTitle[\"Dynamically Created Shoot Controllers\"]\n                SC1[shoot-controller-prod-shoots\u003cbr/\u003ewatches: garden--production]\n                SC2[shoot-controller-dev-shoots\u003cbr/\u003ewatches: garden--development]\n            end\n        end\n        \n        subgraph Resources[\"Greenhouse Resources\"]\n            subgraph Secrets[\" \"]\n                SecretsTitle[\"Secrets\"]\n                SecretProd1[shoot-prod-1]\n                SecretProd2[shoot-prod-2]\n                SecretDev1[shoot-dev-1]\n            end\n            subgraph Clusters[\" \"]\n                ClustersTitle[\"Clusters\"]\n                ClusterProd1[shoot-prod-1]\n                ClusterProd2[shoot-prod-2]\n                ClusterDev1[shoot-dev-1]\n            end\n        end\n    end\n    \n    CIC --\u003e|reconciles| CI1\n    CIC --\u003e|reconciles| CI2\n    \n    CI1 --\u003e|creates \u0026 manages| SC1\n    CI2 --\u003e|creates \u0026 manages| SC2\n    \n    SC1 --\u003e|watches| Shoot1\n    SC1 --\u003e|watches| Shoot2\n    SC2 --\u003e|watches| Shoot3\n    SC2 --\u003e|watches| Shoot4\n    \n    SC1 --\u003e|creates| SecretProd1\n    SC1 --\u003e|creates| SecretProd2\n    SC2 --\u003e|creates| SecretDev1\n    \n    ClusterProd1 --\u003e|depends on| SecretProd1\n    ClusterProd2 --\u003e|depends on| SecretProd2\n    ClusterDev1 --\u003e|depends on| SecretDev1\n    \n    style Garden fill:#f5f5f5,stroke:#000,stroke-width:2px,color:#000\n    style Greenhouse fill:#f5f5f5,stroke:#000,stroke-width:2px,color:#000\n    style ShootGrafter fill:#333,stroke:#000,stroke-width:2px,color:#fff\n    style CareInstructions fill:#555,stroke:#000,stroke-width:2px,color:#fff\n    style CIC fill:#444,stroke:#000,stroke-width:2px,color:#fff\n    style DynamicControllers fill:#555,stroke:#000,stroke-width:2px,color:#fff\n    style SC1 fill:#666,stroke:#000,stroke-width:2px,color:#fff\n    style SC2 fill:#666,stroke:#000,stroke-width:2px,color:#fff\n    style Resources fill:#333,stroke:#000,stroke-width:2px,color:#fff\n    style Secrets fill:#444,stroke:#000,stroke-width:2px,color:#fff\n    style Clusters fill:#444,stroke:#000,stroke-width:2px,color:#fff\n    style NS1 fill:#d0d0d0,stroke:#000,stroke-width:2px,color:#000\n    style NS2 fill:#d0d0d0,stroke:#000,stroke-width:2px,color:#000\n    style NS1Title fill:#d0d0d0,stroke:#d0d0d0,color:#000\n    style NS2Title fill:#d0d0d0,stroke:#d0d0d0,color:#000\n    style CITitle fill:#555,stroke:#555,color:#fff\n    style DCTitle fill:#555,stroke:#555,color:#fff\n    style SecretsTitle fill:#444,stroke:#444,color:#fff\n    style ClustersTitle fill:#444,stroke:#444,color:#fff\n    \n    linkStyle default stroke:#000,stroke-width:2px\n```\n\nThe operator consists of two main controllers:\n\n### CareInstruction Controller\n\nThe `CareInstruction` is the primary Custom Resource Definition (CRD) that configures how shoot-grafter operates. Each CareInstruction:\n\n- Defines which Garden cluster to monitor (via kubeconfig secret or Greenhouse Cluster reference)\n- Specifies which namespace to watch for Shoots\n- Declares label selectors and CEL expressions to filter which Shoots to onboard\n- Configures label propagation and additional metadata\n- Manages the lifecycle of dynamically created Shoot controllers\n\n### Shoot Controller\n\nFor each CareInstruction, a dedicated Shoot controller is dynamically created and runs in its own manager. This controller:\n\n- Watches Shoot resources in the specified Garden cluster namespace\n- Extracts cluster connection details (API server URL, CA certificate)\n- Creates or updates corresponding Secret resources with OIDC configuration\n- Generates Greenhouse Cluster resources with appropriate labels\n- Optionally configures OIDC authentication on Shoot clusters for Greenhouse access. Also see respective [Greenhouse docs](https://cloudoperators.github.io/greenhouse/docs/user-guides/cluster/oidc_connectivity/) and [Gardener docs](https://gardener.cloud/docs/guides/administer-shoots/oidc-login/#configure-the-shoot-cluster)\n- Optionally configures RBAC on the Shoot cluster for Greenhouse access\n\n## Custom Resource: CareInstruction\n\nA `CareInstruction` defines the configuration for onboarding Shoots from a specific Garden cluster.\n\n### Example CareInstruction\n\n```yaml\napiVersion: shoot-grafter.cloudoperators.dev/v1alpha1\nkind: CareInstruction\nmetadata:\n  name: production-shoots\n  namespace: greenhouse-org\nspec:\n  # Option 1: Reference a Greenhouse Cluster resource\n  gardenClusterName: garden-prod-cluster\n  \n  # Option 2: Reference a kubeconfig secret directly\n  # gardenClusterKubeConfigSecretName:\n  #   name: garden-kubeconfig\n  #   key: kubeconfig\n  \n  # Namespace in the Garden cluster to watch\n  gardenNamespace: garden-production\n  \n  # Label selector and CEL expression for Shoots to onboard\n  shootSelector:\n    labelSelector:\n      matchLabels:\n        environment: production\n        team: platform\n    expression: 'object.status.lastOperation.state == \"Succeeded\"'\n  \n  # Labels to propagate from Shoot to Greenhouse Cluster\n  propagateLabels:\n    - metadata.greenhouse.sap/region\n    - greenhouse.sap/owned-by\n  \n  # Additional labels to add to all created Clusters\n  additionalLabels:\n    onboarding-source: garden-prod\n  \n  # Reference to AuthenticationConfiguration ConfigMap (optional)\n  authenticationConfigMapName: greenhouse-oidc-config\n\n  # Enable automatic RBAC configuration (default: true)\n  enableRBAC: true\n```\n\n### CareInstruction Spec Fields\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `gardenClusterName` | string | No*| Name of the Greenhouse Cluster resource representing the Garden cluster |\n| `gardenClusterKubeConfigSecretName` | SecretKeyReference | No* | Reference to a secret containing the kubeconfig for the Garden cluster |\n| `gardenNamespace` | string | Yes | Namespace in the Garden cluster where Shoots are located |\n| `shootSelector` | ShootSelector | No | Combines label-based and CEL expression-based filtering (if omitted, all Shoots in namespace are selected) |\n| `shootSelector.labelSelector` | LabelSelector | No | Label selector to filter which Shoots to onboard |\n| `shootSelector.expression` | string | No | CEL expression for filtering shoots by status or other fields (max 1024 chars). The shoot object is available as `object` |\n| `propagateLabels` | []string | No | List of label keys to copy from Shoot to Greenhouse Cluster |\n| `additionalLabels` | map[string]string | No | Additional labels to add to all created Greenhouse Clusters |\n| `authenticationConfigMapName` | string | No | Name of ConfigMap in Greenhouse cluster containing AuthenticationConfiguration [(config.yaml with apiserver.config.k8s.io/v1beta1 content)](https://gardener.cloud/docs/guides/administer-shoots/oidc-login/#configure-the-shoot-cluster)|\n| `enableRBAC` | bool | No | When false, skips automatic RBAC setup on Shoot clusters (default: true‚) |\n\n*Note: Either `gardenClusterName` or `gardenClusterKubeConfigSecretName` must be provided (priority: kubeconfig secret \u003e cluster name)\n\n### CareInstruction Status\n\nThe CareInstruction status provides real-time information about the onboarding process:\n\n```yaml\nstatus:\n  statusConditions:\n    conditions:\n      - type: Ready\n        status: \"True\"\n        reason: Ready\n        message: CareInstruction is ready\n      - type: GardenClusterAccessReady\n        status: \"True\"\n        reason: GardenClusterAccessReady\n      - type: ShootControllerStarted\n        status: \"True\"\n        reason: Started\n      - type: ShootsReconciled\n        status: \"True\"\n        reason: Reconciled\n        message: All shoots and clusters are reconciled\n  clusters:\n    - name: shoot-cluster-1\n      status: Ready\n    - name: shoot-cluster-2\n      status: Ready\n    - name: shoot-cluster-3\n      status: Failed\n      message: couldn't get current server API group list: the server has asked for the client to provide credentials\n  totalShootCount: 4\n  excludedShootCount: 1\n  effectiveShootCount: 3\n  excludedShoots:\n    - name: shoot-cluster-4\n      reason: \"filtered out by CEL expression\"\n  createdClusters: 3\n  failedClusters: 1\n```\n\n**Status Fields**:\n\n- `Ready`: Overall readiness of the CareInstruction (derived from sub-conditions)\n- `GardenClusterAccessReady`: Indicates whether the Garden cluster is accessible\n- `ShootControllerStarted`: Shows if the dynamic Shoot controller has been started\n- `ShootsReconciled`: Reports whether all targeted Shoots have been successfully onboarded\n- `clusters`: Detailed list of all clusters managed by this CareInstruction with their individual status (Ready/Failed) and optional message\n- `totalShootCount`: Total number of Shoots matching the label selector (before CEL filtering)\n- `excludedShootCount`: Number of Shoots excluded by the CEL expression\n- `effectiveShootCount`: Number of Shoots after CEL filtering (`totalShootCount - excludedShootCount`)\n- `excludedShoots`: List of excluded Shoots with names and reasons\n- `createdClusters`: Number of Greenhouse Clusters created by this CareInstruction\n- `failedClusters`: Number of Greenhouse Clusters that are not ready\n\n## Usage Examples\n\n### Example 1: Onboard all Shoots in a namespace\n\n```yaml\napiVersion: shoot-grafter.cloudoperators/v1alpha1\nkind: CareInstruction\nmetadata:\n  name: all-dev-shoots\n  namespace: greenhouse-dev\nspec:\n  gardenClusterName: dev-garden\n  gardenNamespace: garden--dev\n```\n\n### Example 2: Onboard Shoots with specific labels\n\n```yaml\napiVersion: shoot-grafter.cloudoperators/v1alpha1\nkind: CareInstruction\nmetadata:\n  name: production-critical\n  namespace: greenhouse-prod\nspec:\n  gardenClusterName: prod-garden\n  gardenNamespace: garden--production\n  shootSelector:\n    labelSelector:\n      matchLabels:\n        environment: production\n  propagateLabels:\n    - metadata.greenhouse.sap/region\n    - greenhouse.sap/owned-by\n  additionalLabels:\n    monitoring: enabled\n    backup: daily\n```\n\n### Example 3: Using matchExpressions for advanced selection\n\n```yaml\napiVersion: shoot-grafter.cloudoperators/v1alpha1\nkind: CareInstruction\nmetadata:\n  name: multi-env-shoots\n  namespace: greenhouse\nspec:\n  gardenClusterName: my-garden\n  gardenNamespace: garden--myproject\n  shootSelector:\n    labelSelector:\n      matchLabels:\n        shoot.gardener.cloud/status: \"healthy\"\n      matchExpressions:\n        - key: environment\n          operator: In\n          values:\n            - staging\n            - production\n        - key: owned-by\n          operator: Exists\n    expression: 'object.status.lastOperation.state == \"Succeeded\"'\n  propagateLabels:\n    - metadata.greenhouse.sap/region\n    - metadata.greenhouse.sap/environment\n    - greenhouse.sap/owned-by\n  additionalLabels:\n    onboarding-method: shoot-grafter\n```\n\n### Example 4: Configuring OIDC Authentication\n\nThis example shows how to configure OIDC authentication on Shoots to enable Greenhouse authentication:\n\n```yaml\napiVersion: shoot-grafter.cloudoperators/v1alpha1\nkind: CareInstruction\nmetadata:\n  name: oidc-enabled-shoots\n  namespace: greenhouse-prod\nspec:\n  gardenClusterName: prod-garden\n  gardenNamespace: garden--production\n  shootSelector:\n    labelSelector:\n      matchLabels:\n        enabled-oidc: \"true\"\n  authenticationConfigMapRef: greenhouse-oidc-config\n  propagateLabels:\n    - metadata.greenhouse.sap/environment\n```\n\nThe referenced ConfigMap should contain an AuthenticationConfiguration:\n\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: greenhouse-oidc-config\n  namespace: greenhouse-prod\ndata:\n  config.yaml: |\n    apiVersion: apiserver.config.k8s.io/v1beta1\n    kind: AuthenticationConfiguration\n    jwt:\n    - issuer:\n        url: https://oidc.greenhouse.example.com\n        audiences:\n        - greenhouse\n      claimMappings:\n        username:\n          claim: sub\n          prefix: \"greenhouse:\"\n        groups:\n          claim: groups\n          prefix: \"greenhouse:\"\n```\n\n### OIDC Configuration Updates and Shoot Reconciliation\n\nWhen `spec.authenticationConfigMapName` is configured in a CareInstruction, shoot-grafter automatically manages OIDC authentication on Shoots:\n\n1. **Initial Setup**: When a Shoot is first onboarded, shoot-grafter creates an AuthenticationConfiguration ConfigMap in the Garden cluster and updates the Shoot's spec to reference it.\n\n2. **Configuration Updates**: When the Greenhouse AuthenticationConfiguration ConfigMap is updated with new OIDC settings:\n   - shoot-grafter merges the updated configuration with any existing Garden cluster configuration\n   - If the Shoot spec already references the correct ConfigMap (no spec change needed), shoot-grafter automatically triggers a Shoot reconciliation by annotating it with `gardener.cloud/operation: reconcile` to apply the changes immediately without waiting for the Shoot's maintenance window\n   - See the [Gardener documentation on immediate reconciliation](https://gardener.cloud/docs/gardener/shoot-operations/shoot_operations/#immediate-reconciliation) for more details\n\n**Note**: If the Shoot spec needs to be updated (e.g., when the ConfigMap reference changes), the spec update itself triggers reconciliation automatically, so no additional annotation is needed.\n\n## Debugging Shoot Reconciliation\n\nshoot-grafter emits Kubernetes events to help you monitor and debug the Shoot onboarding process. Events are associated with the CareInstruction resource.\n\n### View Events for a CareInstruction\n\nTo see all events related to a specific CareInstruction:\n\n```bash\n# View events in the resource description\nkubectl describe careinstruction \u003ccareinstruction-name\u003e -n \u003cnamespace\u003e\n\n# List all events for a specific CareInstruction\nkubectl get events -n \u003cnamespace\u003e \\\n  --field-selector involvedObject.name=\u003ccareinstruction-name\u003e\n\n# Filter events by reason\nkubectl get events -n \u003cnamespace\u003e \\\n  --field-selector involvedObject.name=\u003ccareinstruction-name\u003e,reason=ShootReconciled\n\n# Watch events in real-time\nkubectl get events -n \u003cnamespace\u003e \\\n  --field-selector involvedObject.name=\u003ccareinstruction-name\u003e \\\n  --watch\n```\n\n### Event Types\n\nshoot-grafter emits the following events during Shoot reconciliation:\n\n#### Normal Events (Successful Operations)\n\n| Event Reason | Description |\n|-------------|-------------|\n| `ShootReconciled` | Successfully completed reconciliation for a Shoot |\n| `SecretCreated` | Created Greenhouse secret with cluster credentials |\n| `SecretUpdated` | Updated existing Greenhouse secret with new credentials |\n| `ShootDeleted` | Shoot was deleted from the Garden cluster |\n| `OIDCConfigured` | Successfully configured OIDC authentication for the Shoot |\n| `RBACCreated` | Created RBAC ClusterRoleBinding for Greenhouse ServiceAccount on the Shoot |\n\n#### Warning Events (Issues Requiring Attention)\n\n| Event Reason | Description | Resolution |\n|-------------|-------------|------------|\n| `APIServerURLMissing` | Shoot doesn't have an external API server URL | Check Shoot status in Garden cluster; ensure Shoot is fully reconciled |\n| `CAConfigMapFetchFailed` | Failed to fetch CA certificate ConfigMap | Verify ConfigMap `\u003cshoot-name\u003e.ca-cluster` exists in Garden namespace |\n| `CADataMissing` | CA certificate data is empty in ConfigMap | Check ConfigMap data contains valid `ca.crt` entry |\n| `SecretOperationFailed` | Failed to create or update Greenhouse secret | Check RBAC permissions and Greenhouse cluster connectivity |\n| `OIDCConfigurationFailed` | Failed to configure OIDC authentication on the Shoot | Verify AuthenticationConfigMap exists and contains valid configuration; check Garden cluster connectivity and permissions |\n| `ShootClientFetchFailed` | Failed to get Shoot cluster client | Verify Shoot is accessible and kubeconfig is valid; check network connectivity to Shoot cluster |\n| `RBACCreationFailed` | Failed to create RBAC ClusterRoleBinding on the Shoot | Check connectivity to Shoot cluster; verify service account has sufficient permissions |\n| `CELFilterError` | CEL expression evaluation failed for a Shoot | Verify the CEL expression syntax in `shootSelector.expression` |\n\n### Event Retention\n\nKubernetes automatically cleans up events after a TTL period (typically 1 hour by default). This TTL can be configured via the `--event-ttl` flag on the kube-apiserver.\n\n## Support, Feedback, Contributing\n\nThis project is open to feature requests/suggestions, bug reports etc. via [GitHub issues](https://github.com/cloudoperators/shoot-grafter/issues). Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our [Contribution Guidelines](CONTRIBUTING.md).\n\n## Security / Disclosure\n\nIf you find any bug that may be a security problem, please follow our instructions at [in our security policy](https://github.com/cloudoperators/shoot-grafter/security/policy) on how to report it. Please do not create GitHub issues for security-related doubts or problems.\n\n## Code of Conduct\n\nWe as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone. By participating in this project, you agree to abide by its [Code of Conduct](https://github.com/SAP/.github/blob/main/CODE_OF_CONDUCT.md) at all times.\n\n## Licensing\n\nCopyright 2025 SAP SE or an SAP affiliate company and shoot-grafter contributors. Please see our [LICENSE](LICENSE) for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available [via the REUSE tool](https://api.reuse.software/info/github.com/cloudoperators/shoot-grafter).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudoperators%2Fshoot-grafter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudoperators%2Fshoot-grafter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudoperators%2Fshoot-grafter/lists"}