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
78 changes: 78 additions & 0 deletions api/v1alpha1/modelvalidation_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ limitations under the License.
package v1alpha1

import (
"crypto/sha256"
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -69,15 +72,54 @@ type ModelValidationSpec struct {
Config ValidationConfig `json:"config"`
}

// PodTrackingInfo contains information about a tracked pod
type PodTrackingInfo struct {
// Name is the name of the pod
Name string `json:"name"`
// UID is the unique identifier of the pod
UID string `json:"uid"`
// InjectedAt is when the pod was injected
InjectedAt metav1.Time `json:"injectedAt"`
}

// ModelValidationStatus defines the observed state of ModelValidation
type ModelValidationStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
Conditions []metav1.Condition `json:"conditions,omitempty"`

// InjectedPodCount is the number of pods that have been injected with validation
InjectedPodCount int32 `json:"injectedPodCount"`

// UninjectedPodCount is the number of pods that have the label but were not injected
UninjectedPodCount int32 `json:"uninjectedPodCount"`

// OrphanedPodCount is the number of injected pods that reference this CR but are inconsistent
OrphanedPodCount int32 `json:"orphanedPodCount"`

// AuthMethod indicates which authentication method is being used
AuthMethod string `json:"authMethod,omitempty"`

// InjectedPods contains detailed information about injected pods
InjectedPods []PodTrackingInfo `json:"injectedPods,omitempty"`

// UninjectedPods contains detailed information about pods that should have been injected but weren't
UninjectedPods []PodTrackingInfo `json:"uninjectedPods,omitempty"`

// OrphanedPods contains detailed information about pods that are injected but inconsistent
OrphanedPods []PodTrackingInfo `json:"orphanedPods,omitempty"`

// LastUpdated is the timestamp of the last status update
LastUpdated metav1.Time `json:"lastUpdated,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Auth Method",type=string,JSONPath=`.status.authMethod`
// +kubebuilder:printcolumn:name="Injected Pods",type=integer,JSONPath=`.status.injectedPodCount`
// +kubebuilder:printcolumn:name="Uninjected Pods",type=integer,JSONPath=`.status.uninjectedPodCount`
// +kubebuilder:printcolumn:name="Orphaned Pods",type=integer,JSONPath=`.status.orphanedPodCount`
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"

// ModelValidation is the Schema for the modelvalidations API
type ModelValidation struct {
Expand All @@ -97,6 +139,42 @@ type ModelValidationList struct {
Items []ModelValidation `json:"items"`
}

// GetAuthMethod returns the authentication method being used
func (mv *ModelValidation) GetAuthMethod() string {
if mv.Spec.Config.SigstoreConfig != nil {
return "sigstore"
} else if mv.Spec.Config.PkiConfig != nil {
return "pki"
} else if mv.Spec.Config.PrivateKeyConfig != nil {
return "private-key"
}
return "unknown"
}

// GetConfigHash returns a hash of the validation configuration for drift detection
func (mv *ModelValidation) GetConfigHash() string {
return mv.Spec.Config.GetConfigHash()
}

// GetConfigHash returns a hash of the validation configuration for drift detection
func (vc *ValidationConfig) GetConfigHash() string {
hasher := sha256.New()

if vc.SigstoreConfig != nil {
hasher.Write([]byte("sigstore"))
hasher.Write([]byte(vc.SigstoreConfig.CertificateIdentity))
hasher.Write([]byte(vc.SigstoreConfig.CertificateOidcIssuer))
} else if vc.PkiConfig != nil {
hasher.Write([]byte("pki"))
hasher.Write([]byte(vc.PkiConfig.CertificateAuthority))
} else if vc.PrivateKeyConfig != nil {
hasher.Write([]byte("privatekey"))
hasher.Write([]byte(vc.PrivateKeyConfig.KeyPath))
}

return fmt.Sprintf("%x", hasher.Sum(nil))[:16] // Use first 16 chars for brevity
}

func init() {
SchemeBuilder.Register(&ModelValidation{}, &ModelValidationList{})
}
38 changes: 38 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 65 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ import (
"flag"
"os"
"path/filepath"
"time"

"github.com/sigstore/model-validation-operator/internal/constants"
"github.com/sigstore/model-validation-operator/internal/controller"
"github.com/sigstore/model-validation-operator/internal/tracker"
"github.com/sigstore/model-validation-operator/internal/utils"
"github.com/sigstore/model-validation-operator/internal/webhooks"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
Expand All @@ -47,6 +50,16 @@ import (
// +kubebuilder:scaffold:imports
)

const (
// Default configuration values for the status tracker
defaultDebounceDuration = 500 * time.Millisecond
defaultRetryBaseDelay = 100 * time.Millisecond
defaultRetryMaxDelay = 16 * time.Second
defaultRateLimitQPS = 10.0
defaultRateLimitBurst = 100
defaultStatusUpdateTimeout = 30 * time.Second
)

var (
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
Expand All @@ -69,6 +82,14 @@ func main() {
var secureMetrics bool
var enableHTTP2 bool
var tlsOpts []func(*tls.Config)

// Status tracker configuration
var debounceDuration time.Duration
var retryBaseDelay time.Duration
var retryMaxDelay time.Duration
var rateLimitQPS float64
var rateLimitBurst int
var statusUpdateTimeout time.Duration
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
Expand All @@ -91,6 +112,20 @@ func main() {
"MODEL_TRANSPARENCY_CLI_IMAGE",
constants.ModelTransparencyCliImage,
"Model transparency CLI image to be used.")

// Status tracker configuration flags
flag.DurationVar(&debounceDuration, "debounce-duration", defaultDebounceDuration,
"Time to wait for more changes before updating status")
flag.DurationVar(&retryBaseDelay, "retry-base-delay", defaultRetryBaseDelay,
"Base delay for exponential backoff retries")
flag.DurationVar(&retryMaxDelay, "retry-max-delay", defaultRetryMaxDelay,
"Maximum delay for exponential backoff retries")
flag.Float64Var(&rateLimitQPS, "rate-limit-qps", defaultRateLimitQPS,
"Overall rate limit for status updates (queries per second)")
flag.IntVar(&rateLimitBurst, "rate-limit-burst", defaultRateLimitBurst,
"Burst capacity for overall rate limit")
flag.DurationVar(&statusUpdateTimeout, "status-update-timeout", defaultStatusUpdateTimeout,
"Timeout for status update operations")
opts := zap.Options{
Development: true,
}
Expand Down Expand Up @@ -246,6 +281,36 @@ func main() {
Handler: interceptor,
})

statusTracker := tracker.NewStatusTracker(mgr.GetClient(), tracker.StatusTrackerConfig{
DebounceDuration: debounceDuration,
RetryBaseDelay: retryBaseDelay,
RetryMaxDelay: retryMaxDelay,
RateLimitQPS: rateLimitQPS,
RateLimitBurst: rateLimitBurst,
StatusUpdateTimeout: statusUpdateTimeout,
})
defer statusTracker.Stop()

podReconciler := &controller.PodReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Tracker: statusTracker,
}
if err := podReconciler.SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create pod controller")
os.Exit(1)
}

mvReconciler := &controller.ModelValidationReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Tracker: statusTracker,
}
if err := mvReconciler.SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create ModelValidation controller")
os.Exit(1)
}

setupLog.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running manager")
Expand Down
114 changes: 113 additions & 1 deletion config/crd/bases/ml.sigstore.dev_modelvalidations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,23 @@ spec:
singular: modelvalidation
scope: Namespaced
versions:
- name: v1alpha1
- additionalPrinterColumns:
- jsonPath: .status.authMethod
name: Auth Method
type: string
- jsonPath: .status.injectedPodCount
name: Injected Pods
type: integer
- jsonPath: .status.uninjectedPodCount
name: Uninjected Pods
type: integer
- jsonPath: .status.orphanedPodCount
name: Orphaned Pods
type: integer
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1alpha1
schema:
openAPIV3Schema:
description: ModelValidation is the Schema for the modelvalidations API
Expand Down Expand Up @@ -89,6 +105,10 @@ spec:
status:
description: ModelValidationStatus defines the observed state of ModelValidation
properties:
authMethod:
description: AuthMethod indicates which authentication method is being
used
type: string
conditions:
description: |-
INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
Expand Down Expand Up @@ -148,6 +168,98 @@ spec:
- type
type: object
type: array
injectedPodCount:
description: InjectedPodCount is the number of pods that have been
injected with validation
format: int32
type: integer
injectedPods:
description: InjectedPods contains detailed information about injected
pods
items:
description: PodTrackingInfo contains information about a tracked
pod
properties:
injectedAt:
description: InjectedAt is when the pod was injected
format: date-time
type: string
name:
description: Name is the name of the pod
type: string
uid:
description: UID is the unique identifier of the pod
type: string
required:
- injectedAt
- name
- uid
type: object
type: array
lastUpdated:
description: LastUpdated is the timestamp of the last status update
format: date-time
type: string
orphanedPodCount:
description: OrphanedPodCount is the number of injected pods that
reference this CR but are inconsistent
format: int32
type: integer
orphanedPods:
description: OrphanedPods contains detailed information about pods
that are injected but inconsistent
items:
description: PodTrackingInfo contains information about a tracked
pod
properties:
injectedAt:
description: InjectedAt is when the pod was injected
format: date-time
type: string
name:
description: Name is the name of the pod
type: string
uid:
description: UID is the unique identifier of the pod
type: string
required:
- injectedAt
- name
- uid
type: object
type: array
uninjectedPodCount:
description: UninjectedPodCount is the number of pods that have the
label but were not injected
format: int32
type: integer
uninjectedPods:
description: UninjectedPods contains detailed information about pods
that should have been injected but weren't
items:
description: PodTrackingInfo contains information about a tracked
pod
properties:
injectedAt:
description: InjectedAt is when the pod was injected
format: date-time
type: string
name:
description: Name is the name of the pod
type: string
uid:
description: UID is the unique identifier of the pod
type: string
required:
- injectedAt
- name
- uid
type: object
type: array
required:
- injectedPodCount
- orphanedPodCount
- uninjectedPodCount
type: object
type: object
served: true
Expand Down
Loading