@@ -77,6 +77,21 @@ type HermesInstanceSpec struct {
7777 // +optional
7878 Scheduling SchedulingSpec `json:"scheduling,omitempty"`
7979
80+ // ShareProcessNamespace enables PID namespace sharing between all containers
81+ // in the pod. When true (the default), the infrastructure (pause) container
82+ // becomes PID 1 and reaps zombie processes, preventing accumulation of defunct
83+ // helper processes (git, plugins, shells) spawned under the agent entrypoint
84+ // when it does not call waitpid().
85+ //
86+ // Security note: enabling this lets every container in the pod see and signal
87+ // every other container's processes. A compromised sidecar could send signals
88+ // to the agent and vice versa. Set to false to keep per-container PID isolation;
89+ // you are then responsible for reaping zombies (e.g. by baking tini or dumb-init
90+ // into the image).
91+ // +kubebuilder:default=true
92+ // +optional
93+ ShareProcessNamespace * bool `json:"shareProcessNamespace,omitempty"`
94+
8095 // InitContainers is a user-supplied list of init containers appended after
8196 // any operator-managed init containers (e.g. runtime-init from Plan 3).
8297 // +optional
@@ -159,15 +174,23 @@ type HermesInstanceSpec struct {
159174}
160175
161176// ImageSpec selects an OCI image.
177+ // +kubebuilder:validation:XValidation:rule="(has(self.tag) && size(self.tag) > 0 && self.tag != 'latest') || (has(self.digest) && size(self.digest) > 0)",message="spec.image: one of tag or digest must be set and the tag must not be the floating ':latest' (pick a specific upstream release tag or pin a digest)"
162178type ImageSpec struct {
163179 // +kubebuilder:default="ghcr.io/paperclipinc/hermes-agent"
164180 // +optional
165181 Repository string `json:"repository,omitempty"`
166182
167- // +kubebuilder:default="latest"
183+ // Tag is the container image tag. Either tag or digest must be set; there is
184+ // no default, because pinning to a mutable tag like :latest can silently pull
185+ // a broken upstream build.
168186 // +optional
169187 Tag string `json:"tag,omitempty"`
170188
189+ // Digest overrides the tag with an image digest (e.g. sha256:abc...). When set
190+ // it takes precedence over the tag for the resolved image reference.
191+ // +optional
192+ Digest string `json:"digest,omitempty"`
193+
171194 // +kubebuilder:default=IfNotPresent
172195 // +kubebuilder:validation:Enum=Always;IfNotPresent;Never
173196 // +optional
@@ -568,6 +591,30 @@ type MetricsSpec struct {
568591 // +kubebuilder:default=false
569592 // +optional
570593 Secure * bool `json:"secure,omitempty"`
594+
595+ // GrafanaDashboard configures auto-provisioned Grafana dashboard ConfigMaps
596+ // (operator overview + per-instance). When enabled, the operator emits
597+ // ConfigMaps labeled grafana_dashboard="1" so the Grafana sidecar provisioner
598+ // picks them up automatically.
599+ // +optional
600+ GrafanaDashboard * GrafanaDashboardSpec `json:"grafanaDashboard,omitempty"`
601+ }
602+
603+ // GrafanaDashboardSpec configures auto-provisioned Grafana dashboard ConfigMaps.
604+ type GrafanaDashboardSpec struct {
605+ // Enabled enables Grafana dashboard ConfigMap creation.
606+ // +kubebuilder:default=false
607+ // +optional
608+ Enabled * bool `json:"enabled,omitempty"`
609+
610+ // Labels to add to the dashboard ConfigMaps (in addition to grafana_dashboard: "1").
611+ // +optional
612+ Labels map [string ]string `json:"labels,omitempty"`
613+
614+ // Folder is the Grafana folder to place the dashboards in.
615+ // +kubebuilder:default="Hermes"
616+ // +optional
617+ Folder string `json:"folder,omitempty"`
571618}
572619
573620// ServiceMonitorSpec controls Prometheus-Operator ServiceMonitor emission.
@@ -1000,18 +1047,19 @@ type MigrationStatus struct {
10001047
10011048// Condition type constants. Centralised so Plan 4-6 and docs/conditions.md stay aligned.
10021049const (
1003- ConditionTypeReady = "Ready"
1004- ConditionTypeStorageReady = "StorageReady"
1005- ConditionTypeConfigReady = "ConfigReady"
1006- ConditionTypeSecretsReady = "SecretsReady"
1007- ConditionTypeNetworkPolicyReady = "NetworkPolicyReady"
1008- ConditionTypeRBACReady = "RBACReady"
1009- ConditionTypeServiceReady = "ServiceReady"
1010- ConditionTypePDBReady = "PDBReady"
1011- ConditionTypeHPAReady = "HPAReady"
1012- ConditionTypeIngressReady = "IngressReady"
1013- ConditionTypeServiceMonitorReady = "ServiceMonitorReady"
1014- ConditionTypePrometheusRuleReady = "PrometheusRuleReady"
1050+ ConditionTypeReady = "Ready"
1051+ ConditionTypeStorageReady = "StorageReady"
1052+ ConditionTypeConfigReady = "ConfigReady"
1053+ ConditionTypeSecretsReady = "SecretsReady"
1054+ ConditionTypeNetworkPolicyReady = "NetworkPolicyReady"
1055+ ConditionTypeRBACReady = "RBACReady"
1056+ ConditionTypeServiceReady = "ServiceReady"
1057+ ConditionTypePDBReady = "PDBReady"
1058+ ConditionTypeHPAReady = "HPAReady"
1059+ ConditionTypeIngressReady = "IngressReady"
1060+ ConditionTypeServiceMonitorReady = "ServiceMonitorReady"
1061+ ConditionTypePrometheusRuleReady = "PrometheusRuleReady"
1062+ ConditionTypeGrafanaDashboardReady = "GrafanaDashboardReady"
10151063
10161064 ConditionBackupReady = "BackupReady"
10171065 ConditionRestoreApplied = "RestoreApplied"
0 commit comments