Skip to content

feat: add flag metadata to FeatureFlag CRD#808

Open
Thuvaraki wants to merge 3 commits intoopen-feature:mainfrom
Thuvaraki:feature/flag-metadata
Open

feat: add flag metadata to FeatureFlag CRD#808
Thuvaraki wants to merge 3 commits intoopen-feature:mainfrom
Thuvaraki:feature/flag-metadata

Conversation

@Thuvaraki
Copy link
Copy Markdown

This PR

  • Adds flag metadata support to the FeatureFlag CRD:
    • Flag-set level: spec.flagSpec.metadata.flagSetId
    • Per-flag level: spec.flagSpec.flags.<name>.metadata.flagSetId
    • x-kubernetes-preserve-unknown-fields: true on both levels so
      flagd metadata inheritance works
  • Regenerates CRD manifests and deepcopy code

Related Issues

Fixes #754

Notes

  • Generated with make generate and make release-manifests
  • Metadata fields are fully optional — existing FeatureFlag resources
    are not affected

How to test

  • Run make release-manifests and inspect config/rendered/release.yaml
    for both metadata blocks under flagSpec
  • Apply the updated CRD to a cluster:
  kubectl apply -f config/rendered/release.yaml
  • Create a FeatureFlag with spec.flagSpec.metadata.flagSetId and per-flag metadata fields and confirm it is accepted

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the FeatureFlag Custom Resource Definition by integrating optional metadata fields. This addition provides greater flexibility for managing feature flags, particularly by supporting flagd's metadata inheritance mechanism. The changes are designed to be fully backward compatible, ensuring that existing FeatureFlag resources remain unaffected.

Highlights

  • FeatureFlag CRD Enhancement: Introduced metadata fields to the FeatureFlag Custom Resource Definition (CRD) at both the flag-set level (spec.flagSpec.metadata.flagSetId) and per-flag level (spec.flagSpec.flags.<name>.metadata.flagSetId).
  • Compatibility with flagd: Enabled x-kubernetes-preserve-unknown-fields: true for these new metadata fields to ensure compatibility with flagd's metadata inheritance model.
  • Code Generation: Regenerated CRD manifests and deepcopy code to reflect the schema changes.
Changelog
  • api/core/v1beta1/featureflag_types.go
    • Added a new FlagMetadata struct to define optional flag metadata, including FlagSetID.
    • Introduced an optional Metadata field of type *FlagMetadata to the FlagSpec struct.
    • Added an optional Metadata field of type *FlagMetadata to the Flag struct.
  • api/core/v1beta1/zz_generated.deepcopy.go
    • Generated DeepCopyInto and DeepCopy methods for the new FlagMetadata struct.
    • Updated the DeepCopyInto method for Flag to include deep copying logic for its new Metadata field.
    • Updated the DeepCopyInto method for FlagSpec to include deep copying logic for its new Metadata field.
  • config/crd/bases/core.openfeature.dev_featureflags.yaml
    • Modified the CRD schema to include an optional metadata object within spec.flagSpec, containing a flagSetId string and x-kubernetes-preserve-unknown-fields: true.
    • Modified the CRD schema to include an optional metadata object within spec.flagSpec.flags.<name>, containing a flagSetId string and x-kubernetes-preserve-unknown-fields: true.
Activity
  • No human activity (comments, reviews, or progress updates) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds metadata support to the FeatureFlag CRD at both the spec and per-flag levels. The changes to the CRD definition and Go types are mostly correct. However, there's a significant issue with how unknown metadata fields are handled. The current implementation will lead to data loss in the operator for any metadata fields other than the explicitly defined flagSetId. Additionally, the auto-generated DeepCopy functions are performing shallow copies, which is a latent bug and a maintainability concern.

Comment on lines +47 to +53
// FlagMetadata captures optional metadata for a flag specification.
// PreserveUnknownFields keeps compatibility with flagd's metadata inheritance model.
// +kubebuilder:pruning:PreserveUnknownFields
type FlagMetadata struct {
// +optional
FlagSetID string `json:"flagSetId,omitempty"`
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The FlagMetadata struct is defined to only contain FlagSetID. While +kubebuilder:pruning:PreserveUnknownFields is used on the CRD, Go's encoding/json unmarshaler will drop any fields not defined in this struct when the operator reads the resource. This contradicts the intent described in the comments to preserve additional metadata keys for flagd inheritance and will lead to data loss.

To correctly preserve unknown fields, consider using json.RawMessage for the Metadata field in FlagSpec and Flag structs. This is consistent with how Evaluators, Variants, and Targeting fields are handled in this file.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed — replaced FlagMetadata struct with json.RawMessage for both FlagSpec.Metadata and Flag.Metadata. This is now consistent with how Evaluators, Variants, and Targeting are handled.

Comment on lines +246 to +250
if in.Metadata != nil {
in, out := &in.Metadata, &out.Metadata
*out = new(FlagMetadata)
**out = **in
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The generated DeepCopyInto logic for Metadata performs a shallow copy of the FlagMetadata struct. This pattern is repeated for FlagSpec.Metadata and in FlagMetadata.DeepCopyInto.

While this is currently safe because FlagMetadata only contains a string, it's a latent bug. If FlagMetadata is ever modified to include types that are not safe to shallow copy (like slices or pointers), this will lead to shared state between copied objects, violating the contract of DeepCopy.

This issue in the generated code is a symptom of the FlagMetadata type definition, which should be revised to properly handle unknown fields.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed — since Metadata is now json.RawMessage (a byte slice), the generated deepcopy correctly uses make and copy instead of a shallow struct copy."

@Thuvaraki
Copy link
Copy Markdown
Author

Thuvaraki commented Mar 17, 2026

Hi @justinabrahms @beeme1mr @toddbaert @oxddr @lukas-reining @odubajDT @thisthat @bacherfl

Could you please review this PR when you get a chance?

This PR adds metadata support to the FeatureFlag CRD flagSpec, addressing issue #754.

Changes included:

  • Flag-set level metadata (spec.flagSpec.metadata.flagSetId)
  • Per-flag level metadata (spec.flagSpec.flags.<n>.metadata.flagSetId)
  • x-kubernetes-preserve-unknown-fields: true on both levels for flagd metadata inheritance compatibility
  • Fully backward compatible — existing FeatureFlag resources are not affected

Related PR:
This pairs with open-feature/flagd#1905 which adds metadata mapping support in the flagd Kubernetes sync provider. Together, these two PRs enable metadata defined in FeatureFlag CRs to be correctly propagated during flag evaluation.

Happy to make any adjustments based on your feedback. Thank you!

Copy link
Copy Markdown
Member

@lukas-reining lukas-reining left a comment

Choose a reason for hiding this comment

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

Thank you @Thuvaraki! This looks good even though it only makes sense with open-feature/flagd#1905
I left two questions.

Comment on lines -17 to -18
newName: open-feature-operator-local
newTag: validate
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why did you change this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for catching this - apologies.
This was a local testing change and not intended for the PR. I’ve reverted it to the original value.

go.mod Outdated
Comment on lines +111 to +112
replace github.com/open-feature/open-feature-operator/apis => ./api

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why did you do this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This was added temporarily for local development. I used the replace directive to point to local API types while regenerating CRDs. It was not intended to be committed. I have removed it from the PR. Both issues were due to local development setup and have now been cleaned up. The PR is updated, please let me know if anything else needs attention.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 72.33%. Comparing base (499661e) to head (d3b3256).
⚠️ Report is 76 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##             main     #808       +/-   ##
===========================================
- Coverage   86.51%   72.33%   -14.19%     
===========================================
  Files          19       30       +11     
  Lines        1587     1923      +336     
===========================================
+ Hits         1373     1391       +18     
- Misses        173      484      +311     
- Partials       41       48        +7     
Files with missing lines Coverage Δ
api/core/v1beta1/featureflag_types.go 92.30% <ø> (ø)

... and 25 files with indirect coverage changes

Flag Coverage Δ
unit-tests 72.33% <ø> (∅)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

THuvaraki added 3 commits March 19, 2026 10:28
Signed-off-by: THuvaraki <Thuvaraki.E@cloudsolutions.com.sa>
Signed-off-by: THuvaraki <Thuvaraki.E@cloudsolutions.com.sa>
Signed-off-by: THuvaraki <Thuvaraki.E@cloudsolutions.com.sa>
@Thuvaraki Thuvaraki force-pushed the feature/flag-metadata branch from 1c35109 to 5ed3246 Compare March 19, 2026 05:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CRD definition is not following the latest flagD specifications

2 participants