Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion charts/reports-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ helm install reports-server --namespace reports-server --create-namespace report
| affinity | object | `{}` | Affinity |
| service.type | string | `"ClusterIP"` | Service type |
| service.port | int | `443` | Service port |
| config.skipMigration | bool | `false` | Skip database migration on startup |
| config.skipMigration | bool | `false` | Skip database migration on startup. By default, migration is automatically skipped if reports already exist in the database. |
| config.etcd.enabled | bool | `false` | |
| config.etcd.endpoints | string | `nil` | |
| config.etcd.insecure | bool | `true` | |
Expand Down
2 changes: 1 addition & 1 deletion pkg/app/opts/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (o *Options) Flags() (fs flag.NamedFlagSets) {
msfs.BoolVar(&o.StoreReports, "storereports", true, "Whether or not to store and manage Policy Reports.")
msfs.BoolVar(&o.StoreOpenreports, "storeopenreports", true, "Whether or not to store and manage Open Reports.")
msfs.BoolVar(&o.StoreEphemeralReports, "storeephemeralreports", true, "Whether or not to store and manage Ephemeral Reports.")
msfs.BoolVar(&o.SkipMigration, "skipmigration", false, "Skip database migration on startup.")
msfs.BoolVar(&o.SkipMigration, "skipmigration", false, "Skip database migration on startup. By default, migration is automatically skipped if reports already exist in the database.")

o.SecureServing.AddFlags(fs.FlagSet("apiserver secure serving"))
o.Authentication.AddFlags(fs.FlagSet("apiserver authentication"))
Expand Down
72 changes: 64 additions & 8 deletions pkg/server/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,62 @@ import (
"k8s.io/klog/v2"
"sigs.k8s.io/wg-policy-prototypes/policy-report/pkg/api/wgpolicyk8s.io/v1alpha2"
"sigs.k8s.io/wg-policy-prototypes/policy-report/pkg/generated/v1alpha2/clientset/versioned"

"github.com/kyverno/reports-server/pkg/api"
)

func (c *Config) shouldSkipMigration(ctx context.Context) bool {
if c.SkipMigration {
return true
}

if c.APIServices.StoreReports {
cpolrs, err := c.Store.ClusterPolicyReports().List(ctx)
if err == nil && len(cpolrs) > 0 {
for _, r := range cpolrs {
if r.Annotations[api.ServedByReportsServerAnnotation] == api.ServedByReportsServerValue {

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

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

The code accesses r.Annotations without checking if it's nil first. This could cause a nil pointer dereference if a report exists without annotations. The pattern used elsewhere in the codebase (e.g., watch.go lines 38, 74, 110, 146) includes a nil check before accessing the Annotations map. Add a nil check: if r.Annotations != nil && r.Annotations[api.ServedByReportsServerAnnotation] == api.ServedByReportsServerValue

Copilot uses AI. Check for mistakes.
klog.Info("found existing reports in database with reports-server annotation, skipping migration")
return true
}
}
}
Comment on lines +28 to +36

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

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

Errors from database List operations are silently ignored. If the database is temporarily unavailable or there's a connection issue, the function will return false and proceed with migration, potentially causing duplicate data or migration failures. Consider logging the error or returning an error to the caller to allow proper error handling. Other database operations in the migration function return errors (e.g., line 90, 120).

Copilot uses AI. Check for mistakes.

polrs, err := c.Store.PolicyReports().List(ctx, "")
if err == nil && len(polrs) > 0 {
for _, r := range polrs {
if r.Annotations[api.ServedByReportsServerAnnotation] == api.ServedByReportsServerValue {

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

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

The code accesses r.Annotations without checking if it's nil first. This could cause a nil pointer dereference if a report exists without annotations. The pattern used elsewhere in the codebase (e.g., watch.go lines 38, 74, 110, 146) includes a nil check before accessing the Annotations map. Add a nil check: if r.Annotations != nil && r.Annotations[api.ServedByReportsServerAnnotation] == api.ServedByReportsServerValue

Copilot uses AI. Check for mistakes.
klog.Info("found existing reports in database with reports-server annotation, skipping migration")
return true
}
}
}
Comment on lines +38 to +46

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

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

Errors from database List operations are silently ignored. If the database is temporarily unavailable or there's a connection issue, the function will return false and proceed with migration, potentially causing duplicate data or migration failures. Consider logging the error or returning an error to the caller to allow proper error handling. Other database operations in the migration function return errors (e.g., line 90, 120).

Copilot uses AI. Check for mistakes.
}

if c.APIServices.StoreEphemeralReports {
cephrs, err := c.Store.ClusterEphemeralReports().List(ctx)
if err == nil && len(cephrs) > 0 {
for _, r := range cephrs {
if r.Annotations[api.ServedByReportsServerAnnotation] == api.ServedByReportsServerValue {

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

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

The code accesses r.Annotations without checking if it's nil first. This could cause a nil pointer dereference if a report exists without annotations. The pattern used elsewhere in the codebase (e.g., watch.go lines 38, 74, 110, 146) includes a nil check before accessing the Annotations map. Add a nil check: if r.Annotations != nil && r.Annotations[api.ServedByReportsServerAnnotation] == api.ServedByReportsServerValue

Copilot uses AI. Check for mistakes.
klog.Info("found existing reports in database with reports-server annotation, skipping migration")
return true
}
}
}
Comment on lines +50 to +58

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

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

Errors from database List operations are silently ignored. If the database is temporarily unavailable or there's a connection issue, the function will return false and proceed with migration, potentially causing duplicate data or migration failures. Consider logging the error or returning an error to the caller to allow proper error handling. Other database operations in the migration function return errors (e.g., line 153, 183).

Copilot uses AI. Check for mistakes.

ephrs, err := c.Store.EphemeralReports().List(ctx, "")
if err == nil && len(ephrs) > 0 {
for _, r := range ephrs {
if r.Annotations[api.ServedByReportsServerAnnotation] == api.ServedByReportsServerValue {

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

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

The code accesses r.Annotations without checking if it's nil first. This could cause a nil pointer dereference if a report exists without annotations. The pattern used elsewhere in the codebase (e.g., watch.go lines 38, 74, 110, 146) includes a nil check before accessing the Annotations map. Add a nil check: if r.Annotations != nil && r.Annotations[api.ServedByReportsServerAnnotation] == api.ServedByReportsServerValue

Copilot uses AI. Check for mistakes.
klog.Info("found existing reports in database with reports-server annotation, skipping migration")
return true
}
}
}
Comment on lines +60 to +68

Copilot AI Jan 27, 2026

Copy link

Choose a reason for hiding this comment

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

Errors from database List operations are silently ignored. If the database is temporarily unavailable or there's a connection issue, the function will return false and proceed with migration, potentially causing duplicate data or migration failures. Consider logging the error or returning an error to the caller to allow proper error handling. Other database operations in the migration function return errors (e.g., line 153, 183).

Copilot uses AI. Check for mistakes.
}

return false
}

func (c *Config) migration(ctx context.Context) error {
kyvernoClient, err := kyverno.NewForConfig(c.Rest)
if err != nil {
Expand All @@ -28,13 +82,15 @@ func (c *Config) migration(ctx context.Context) error {
}
workerChan := make(chan struct{}, numWorkers)

skipMigration := c.shouldSkipMigration(ctx)

if c.APIServices.StoreReports {
cpolrs, err := policyClient.Wgpolicyk8sV1alpha2().ClusterPolicyReports().List(ctx, metav1.ListOptions{})
if err != nil {
return nil
}

if !c.SkipMigration {
if !skipMigration {
cpolrWg := &sync.WaitGroup{}
cpolrWg.Add(len(cpolrs.Items))
for _, r := range cpolrs.Items {
Expand Down Expand Up @@ -64,7 +120,7 @@ func (c *Config) migration(ctx context.Context) error {
return nil
}

if !c.SkipMigration {
if !skipMigration {
polrWg := &sync.WaitGroup{}
polrWg.Add(len(polrs.Items))
for _, r := range polrs.Items {
Expand Down Expand Up @@ -97,7 +153,7 @@ func (c *Config) migration(ctx context.Context) error {
return nil
}

if !c.SkipMigration {
if !skipMigration {
cephrWg := &sync.WaitGroup{}
cephrWg.Add(len(cephrs.Items))
for _, r := range cephrs.Items {
Expand Down Expand Up @@ -127,7 +183,7 @@ func (c *Config) migration(ctx context.Context) error {
return nil
}

if !c.SkipMigration {
if !skipMigration {
ephrWg := &sync.WaitGroup{}
ephrWg.Add(len(ephrs.Items))
for _, r := range ephrs.Items {
Expand Down Expand Up @@ -169,7 +225,7 @@ func (c *Config) migrateReport(ctx context.Context, kyvernoClient kyverno.Interf
case v1alpha2.ClusterPolicyReport:
err := c.Store.ClusterPolicyReports().Create(ctx, &r)
if err != nil {
klog.Errorf("failed to mirgrate report of kind %s %s: %s", r.GroupVersionKind().String(), r.Name, err)
klog.Errorf("failed to migrate report of kind %s %s: %s", r.GroupVersionKind().String(), r.Name, err)
}
// Update annotation in Kubernetes before deleting so watchers can identify it
_, err = policyClient.Wgpolicyk8sV1alpha2().ClusterPolicyReports().Update(ctx, &r, metav1.UpdateOptions{})
Expand All @@ -182,7 +238,7 @@ func (c *Config) migrateReport(ctx context.Context, kyvernoClient kyverno.Interf
case v1alpha2.PolicyReport:
err := c.Store.PolicyReports().Create(ctx, &r)
if err != nil {
klog.Errorf("failed to mirgrate report of kind %s %s: %s", r.GroupVersionKind().String(), r.Name, err)
klog.Errorf("failed to migrate report of kind %s %s: %s", r.GroupVersionKind().String(), r.Name, err)
}
// Update annotation in Kubernetes before deleting so watchers can identify it
_, err = policyClient.Wgpolicyk8sV1alpha2().PolicyReports(r.Namespace).Update(ctx, &r, metav1.UpdateOptions{})
Expand All @@ -195,7 +251,7 @@ func (c *Config) migrateReport(ctx context.Context, kyvernoClient kyverno.Interf
case v1.ClusterEphemeralReport:
err := c.Store.ClusterEphemeralReports().Create(ctx, &r)
if err != nil {
klog.Errorf("failed to mirgrate report of kind %s %s: %s", r.GroupVersionKind().String(), r.Name, err)
klog.Errorf("failed to migrate report of kind %s %s: %s", r.GroupVersionKind().String(), r.Name, err)
}
// Update annotation in Kubernetes before deleting so watchers can identify it
_, err = kyvernoClient.ReportsV1().ClusterEphemeralReports().Update(ctx, &r, metav1.UpdateOptions{})
Expand All @@ -208,7 +264,7 @@ func (c *Config) migrateReport(ctx context.Context, kyvernoClient kyverno.Interf
case v1.EphemeralReport:
err := c.Store.EphemeralReports().Create(ctx, &r)
if err != nil {
klog.Errorf("failed to mirgrate report of kind %s %s: %s", r.GroupVersionKind().String(), r.Name, err)
klog.Errorf("failed to migrate report of kind %s %s: %s", r.GroupVersionKind().String(), r.Name, err)
}
// Update annotation in Kubernetes before deleting so watchers can identify it
_, err = kyvernoClient.ReportsV1().EphemeralReports(r.Namespace).Update(ctx, &r, metav1.UpdateOptions{})
Expand Down