From a90cdb66efcbf0b2458a0b9820977ed0ac15e6d3 Mon Sep 17 00:00:00 2001 From: Matt Jenkinson <75292329+mattdjenkinson@users.noreply.github.com> Date: Mon, 23 Mar 2026 13:34:33 +0000 Subject: [PATCH 1/4] feat: add location, client and last active fields to session endpoint --- docs/api/identity.md | 4 ++ internal/apiserver/identity/sessions/rest.go | 38 +++++++++-- pkg/apis/identity/v1alpha1/types.go | 39 +++++++++-- .../v1alpha1/zz_generated.deepcopy.go | 4 ++ .../identity/v1alpha1/zz_generated.openapi.go | 65 ++++++++++++++----- 5 files changed, 124 insertions(+), 26 deletions(-) diff --git a/docs/api/identity.md b/docs/api/identity.md index edc68e08..5a5a2040 100644 --- a/docs/api/identity.md +++ b/docs/api/identity.md @@ -68,3 +68,7 @@ This resource provides information about user authentication sessions, including | `fingerprintID` | string | A fingerprint identifier for the session (optional). | | `createdAt` | metav1.Time | The timestamp when the session was created. | | `expiresAt` | *metav1.Time | The timestamp when the session expires (optional). | +| `location` | string | Human-readable location for the client (e.g. city and country), if the provider supplies it (optional). | +| `browser` | string | Detected browser or app name (e.g. Safari, Chrome) (optional). | +| `os` | string | Detected operating system (e.g. macOS, Windows) (optional). | +| `lastActiveAt` | *metav1.Time | Last session activity time from the provider (optional). | diff --git a/internal/apiserver/identity/sessions/rest.go b/internal/apiserver/identity/sessions/rest.go index ce1dc8c4..1dac63d7 100644 --- a/internal/apiserver/identity/sessions/rest.go +++ b/internal/apiserver/identity/sessions/rest.go @@ -98,13 +98,29 @@ func (r *REST) Delete(ctx context.Context, name string, _ rest.ValidateObjectFun func (r *REST) Destroy() {} // Satisfy rest.TableConvertor with a no-op conversion (returning nil uses default table printer) +func sessionClientLabel(browser, os string) string { + switch { + case browser == "" && os == "": + return "" + case browser == "": + return os + case os == "": + return browser + default: + return browser + " / " + os + } +} + func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { table := &metav1.Table{ ColumnDefinitions: []metav1.TableColumnDefinition{ - {Name: "Name", Type: "string"}, - {Name: "Provider", Type: "string"}, - {Name: "UserUID", Type: "string"}, - {Name: "Age", Type: "date"}, + {Name: "Name", Type: "string", Format: "name", Description: "Metadata name of the session.", Priority: 0}, + {Name: "Provider", Type: "string", Description: "Authentication provider.", Priority: 0}, + {Name: "Age", Type: "date", Description: "Creation timestamp.", Priority: 0}, + {Name: "Location", Type: "string", Description: "Approximate client location, if known.", Priority: 1}, + {Name: "Client", Type: "string", Description: "Browser and OS, if known.", Priority: 1}, + {Name: "Last active", Type: "string", Description: "Last activity time (RFC3339), if known.", Priority: 1}, + {Name: "UserUID", Type: "string", Description: "Owning user UID.", Priority: 1}, }, } @@ -115,8 +131,20 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO // metav1.Table wants a date in the cell; pass the timestamp age = s.CreationTimestamp } + lastActive := "" + if s.Status.LastActiveAt != nil { + lastActive = s.Status.LastActiveAt.Time.Format(time.RFC3339) + } table.Rows = append(table.Rows, metav1.TableRow{ - Cells: []interface{}{s.Name, s.Status.Provider, s.Status.UserUID, age.Time.Format(time.RFC3339)}, + Cells: []interface{}{ + s.Name, + s.Status.Provider, + age.Time.Format(time.RFC3339), + s.Status.Location, + sessionClientLabel(s.Status.Browser, s.Status.OS), + lastActive, + s.Status.UserUID, + }, Object: runtime.RawExtension{Object: s}, }) } diff --git a/pkg/apis/identity/v1alpha1/types.go b/pkg/apis/identity/v1alpha1/types.go index 912d3935..eddcb3cc 100644 --- a/pkg/apis/identity/v1alpha1/types.go +++ b/pkg/apis/identity/v1alpha1/types.go @@ -12,13 +12,40 @@ type Session struct { Status SessionStatus `json:"status,omitempty"` } +// SessionStatus contains session metadata exposed for display and management. +// All fields except those required for identity are optional and populated by the authentication provider. type SessionStatus struct { - UserUID string `json:"userUID"` - Provider string `json:"provider"` - IP string `json:"ip,omitempty"` - FingerprintID string `json:"fingerprintID,omitempty"` - CreatedAt metav1.Time `json:"createdAt"` - ExpiresAt *metav1.Time `json:"expiresAt,omitempty"` + // UserUID is the unique identifier of the user who owns this session. + UserUID string `json:"userUID"` + + // Provider is the authentication provider for this session (e.g. "zitadel"). + Provider string `json:"provider"` + + // IP is the client IP address associated with the session, if known. + IP string `json:"ip,omitempty"` + + // FingerprintID is an optional device or client fingerprint from the provider. + FingerprintID string `json:"fingerprintID,omitempty"` + + // CreatedAt is when the session was created. + CreatedAt metav1.Time `json:"createdAt"` + + // ExpiresAt is when the session expires, if applicable. + ExpiresAt *metav1.Time `json:"expiresAt,omitempty"` + + // Location is a human-readable geographic label for the client (e.g. "Bristol, United Kingdom"), + // typically derived from GeoIP by the provider. + Location string `json:"location,omitempty"` + + // Browser is the detected client browser or app name (e.g. "Safari", "Chrome"). + Browser string `json:"browser,omitempty"` + + // OS is the detected operating system (e.g. "macOS", "Windows"). + OS string `json:"os,omitempty"` + + // LastActiveAt is the last time the session had activity according to the provider + // (e.g. last refresh or change). Distinct from CreatedAt and ExpiresAt. + LastActiveAt *metav1.Time `json:"lastActiveAt,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go index 73588aed..b65b3aae 100644 --- a/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go @@ -74,6 +74,10 @@ func (in *SessionStatus) DeepCopyInto(out *SessionStatus) { in, out := &in.ExpiresAt, &out.ExpiresAt *out = (*in).DeepCopy() } + if in.LastActiveAt != nil { + in, out := &in.LastActiveAt, &out.LastActiveAt + *out = (*in).DeepCopy() + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SessionStatus. diff --git a/pkg/apis/identity/v1alpha1/zz_generated.openapi.go b/pkg/apis/identity/v1alpha1/zz_generated.openapi.go index 253a22d2..89cb06fd 100644 --- a/pkg/apis/identity/v1alpha1/zz_generated.openapi.go +++ b/pkg/apis/identity/v1alpha1/zz_generated.openapi.go @@ -27,7 +27,8 @@ func schema_pkg_apis_identity_v1alpha1_Session(ref common.ReferenceCallback) com return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "Session represents an active user authentication session. Status is read-only and populated by the identity provider (e.g. Zitadel).", + Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { SchemaProps: spec.SchemaProps{ @@ -115,43 +116,77 @@ func schema_pkg_apis_identity_v1alpha1_SessionStatus(ref common.ReferenceCallbac return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "SessionStatus contains session metadata exposed for display and management. All fields except those required for identity are optional and populated by the authentication provider.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ "userUID": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "UserUID is the unique identifier of the user who owns this session.", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "provider": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Provider is the authentication provider for this session (e.g. \"zitadel\").", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "ip": { SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", + Description: "IP is the client IP address associated with the session, if known.", + Type: []string{"string"}, + Format: "", }, }, "fingerprintID": { SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", + Description: "FingerprintID is an optional device or client fingerprint from the provider.", + Type: []string{"string"}, + Format: "", }, }, "createdAt": { SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + Description: "CreatedAt is when the session was created.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, "expiresAt": { SchemaProps: spec.SchemaProps{ - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + Description: "ExpiresAt is when the session expires, if applicable.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "location": { + SchemaProps: spec.SchemaProps{ + Description: "Location is a human-readable geographic label for the client (e.g. \"Bristol, United Kingdom\"), typically derived from GeoIP by the provider.", + Type: []string{"string"}, + Format: "", + }, + }, + "browser": { + SchemaProps: spec.SchemaProps{ + Description: "Browser is the detected client browser or app name (e.g. \"Safari\", \"Chrome\").", + Type: []string{"string"}, + Format: "", + }, + }, + "os": { + SchemaProps: spec.SchemaProps{ + Description: "OS is the detected operating system (e.g. \"macOS\", \"Windows\").", + Type: []string{"string"}, + Format: "", + }, + }, + "lastActiveAt": { + SchemaProps: spec.SchemaProps{ + Description: "LastActiveAt is the last time the session had activity according to the provider (e.g. last refresh or change). Distinct from CreatedAt and ExpiresAt.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, }, From 66b9a71c16303524bb1632904a0c51aba5452906 Mon Sep 17 00:00:00 2001 From: Matt Jenkinson <75292329+mattdjenkinson@users.noreply.github.com> Date: Mon, 23 Mar 2026 18:01:07 +0000 Subject: [PATCH 2/4] remove expiresAt and lastActive field --- docs/api/identity.md | 2 -- internal/apiserver/identity/sessions/rest.go | 6 ------ pkg/apis/identity/v1alpha1/types.go | 7 ------- .../identity/v1alpha1/zz_generated.deepcopy.go | 8 -------- .../identity/v1alpha1/zz_generated.openapi.go | 15 +-------------- 5 files changed, 1 insertion(+), 37 deletions(-) diff --git a/docs/api/identity.md b/docs/api/identity.md index 5a5a2040..0f631027 100644 --- a/docs/api/identity.md +++ b/docs/api/identity.md @@ -67,8 +67,6 @@ This resource provides information about user authentication sessions, including | `ip` | string | The IP address from which the session was created (optional). | | `fingerprintID` | string | A fingerprint identifier for the session (optional). | | `createdAt` | metav1.Time | The timestamp when the session was created. | -| `expiresAt` | *metav1.Time | The timestamp when the session expires (optional). | | `location` | string | Human-readable location for the client (e.g. city and country), if the provider supplies it (optional). | | `browser` | string | Detected browser or app name (e.g. Safari, Chrome) (optional). | | `os` | string | Detected operating system (e.g. macOS, Windows) (optional). | -| `lastActiveAt` | *metav1.Time | Last session activity time from the provider (optional). | diff --git a/internal/apiserver/identity/sessions/rest.go b/internal/apiserver/identity/sessions/rest.go index 1dac63d7..b55621c8 100644 --- a/internal/apiserver/identity/sessions/rest.go +++ b/internal/apiserver/identity/sessions/rest.go @@ -119,7 +119,6 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO {Name: "Age", Type: "date", Description: "Creation timestamp.", Priority: 0}, {Name: "Location", Type: "string", Description: "Approximate client location, if known.", Priority: 1}, {Name: "Client", Type: "string", Description: "Browser and OS, if known.", Priority: 1}, - {Name: "Last active", Type: "string", Description: "Last activity time (RFC3339), if known.", Priority: 1}, {Name: "UserUID", Type: "string", Description: "Owning user UID.", Priority: 1}, }, } @@ -131,10 +130,6 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO // metav1.Table wants a date in the cell; pass the timestamp age = s.CreationTimestamp } - lastActive := "" - if s.Status.LastActiveAt != nil { - lastActive = s.Status.LastActiveAt.Time.Format(time.RFC3339) - } table.Rows = append(table.Rows, metav1.TableRow{ Cells: []interface{}{ s.Name, @@ -142,7 +137,6 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO age.Time.Format(time.RFC3339), s.Status.Location, sessionClientLabel(s.Status.Browser, s.Status.OS), - lastActive, s.Status.UserUID, }, Object: runtime.RawExtension{Object: s}, diff --git a/pkg/apis/identity/v1alpha1/types.go b/pkg/apis/identity/v1alpha1/types.go index eddcb3cc..0912b410 100644 --- a/pkg/apis/identity/v1alpha1/types.go +++ b/pkg/apis/identity/v1alpha1/types.go @@ -30,9 +30,6 @@ type SessionStatus struct { // CreatedAt is when the session was created. CreatedAt metav1.Time `json:"createdAt"` - // ExpiresAt is when the session expires, if applicable. - ExpiresAt *metav1.Time `json:"expiresAt,omitempty"` - // Location is a human-readable geographic label for the client (e.g. "Bristol, United Kingdom"), // typically derived from GeoIP by the provider. Location string `json:"location,omitempty"` @@ -42,10 +39,6 @@ type SessionStatus struct { // OS is the detected operating system (e.g. "macOS", "Windows"). OS string `json:"os,omitempty"` - - // LastActiveAt is the last time the session had activity according to the provider - // (e.g. last refresh or change). Distinct from CreatedAt and ExpiresAt. - LastActiveAt *metav1.Time `json:"lastActiveAt,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go index b65b3aae..0d6de5dc 100644 --- a/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go @@ -70,14 +70,6 @@ func (in *SessionList) DeepCopyObject() runtime.Object { func (in *SessionStatus) DeepCopyInto(out *SessionStatus) { *out = *in in.CreatedAt.DeepCopyInto(&out.CreatedAt) - if in.ExpiresAt != nil { - in, out := &in.ExpiresAt, &out.ExpiresAt - *out = (*in).DeepCopy() - } - if in.LastActiveAt != nil { - in, out := &in.LastActiveAt, &out.LastActiveAt - *out = (*in).DeepCopy() - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SessionStatus. diff --git a/pkg/apis/identity/v1alpha1/zz_generated.openapi.go b/pkg/apis/identity/v1alpha1/zz_generated.openapi.go index 89cb06fd..0ba6c5f1 100644 --- a/pkg/apis/identity/v1alpha1/zz_generated.openapi.go +++ b/pkg/apis/identity/v1alpha1/zz_generated.openapi.go @@ -27,8 +27,7 @@ func schema_pkg_apis_identity_v1alpha1_Session(ref common.ReferenceCallback) com return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Session represents an active user authentication session. Status is read-only and populated by the identity provider (e.g. Zitadel).", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { SchemaProps: spec.SchemaProps{ @@ -156,12 +155,6 @@ func schema_pkg_apis_identity_v1alpha1_SessionStatus(ref common.ReferenceCallbac Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, - "expiresAt": { - SchemaProps: spec.SchemaProps{ - Description: "ExpiresAt is when the session expires, if applicable.", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), - }, - }, "location": { SchemaProps: spec.SchemaProps{ Description: "Location is a human-readable geographic label for the client (e.g. \"Bristol, United Kingdom\"), typically derived from GeoIP by the provider.", @@ -183,12 +176,6 @@ func schema_pkg_apis_identity_v1alpha1_SessionStatus(ref common.ReferenceCallbac Format: "", }, }, - "lastActiveAt": { - SchemaProps: spec.SchemaProps{ - Description: "LastActiveAt is the last time the session had activity according to the provider (e.g. last refresh or change). Distinct from CreatedAt and ExpiresAt.", - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), - }, - }, }, Required: []string{"userUID", "provider", "createdAt"}, }, From 8df69ab52512fa09801ba414b06d2a7fe34bdae5 Mon Sep 17 00:00:00 2001 From: Matt Jenkinson <75292329+mattdjenkinson@users.noreply.github.com> Date: Tue, 24 Mar 2026 10:13:24 +0000 Subject: [PATCH 3/4] add an updated at field --- docs/api/identity.md | 1 + internal/apiserver/identity/sessions/rest.go | 6 ++++++ pkg/apis/identity/v1alpha1/types.go | 3 +++ pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go | 4 ++++ pkg/apis/identity/v1alpha1/zz_generated.openapi.go | 6 ++++++ 5 files changed, 20 insertions(+) diff --git a/docs/api/identity.md b/docs/api/identity.md index 0f631027..c056c003 100644 --- a/docs/api/identity.md +++ b/docs/api/identity.md @@ -67,6 +67,7 @@ This resource provides information about user authentication sessions, including | `ip` | string | The IP address from which the session was created (optional). | | `fingerprintID` | string | A fingerprint identifier for the session (optional). | | `createdAt` | metav1.Time | The timestamp when the session was created. | +| `lastUpdatedAt` | *metav1.Time | Last time the authentication provider updated this session (optional). | | `location` | string | Human-readable location for the client (e.g. city and country), if the provider supplies it (optional). | | `browser` | string | Detected browser or app name (e.g. Safari, Chrome) (optional). | | `os` | string | Detected operating system (e.g. macOS, Windows) (optional). | diff --git a/internal/apiserver/identity/sessions/rest.go b/internal/apiserver/identity/sessions/rest.go index b55621c8..21b8f1ea 100644 --- a/internal/apiserver/identity/sessions/rest.go +++ b/internal/apiserver/identity/sessions/rest.go @@ -119,6 +119,7 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO {Name: "Age", Type: "date", Description: "Creation timestamp.", Priority: 0}, {Name: "Location", Type: "string", Description: "Approximate client location, if known.", Priority: 1}, {Name: "Client", Type: "string", Description: "Browser and OS, if known.", Priority: 1}, + {Name: "Last updated", Type: "string", Description: "Provider last update time (RFC3339), if known.", Priority: 1}, {Name: "UserUID", Type: "string", Description: "Owning user UID.", Priority: 1}, }, } @@ -130,6 +131,10 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO // metav1.Table wants a date in the cell; pass the timestamp age = s.CreationTimestamp } + lastUpdated := "" + if s.Status.LastUpdatedAt != nil { + lastUpdated = s.Status.LastUpdatedAt.Time.Format(time.RFC3339) + } table.Rows = append(table.Rows, metav1.TableRow{ Cells: []interface{}{ s.Name, @@ -137,6 +142,7 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO age.Time.Format(time.RFC3339), s.Status.Location, sessionClientLabel(s.Status.Browser, s.Status.OS), + lastUpdated, s.Status.UserUID, }, Object: runtime.RawExtension{Object: s}, diff --git a/pkg/apis/identity/v1alpha1/types.go b/pkg/apis/identity/v1alpha1/types.go index 0912b410..1857d332 100644 --- a/pkg/apis/identity/v1alpha1/types.go +++ b/pkg/apis/identity/v1alpha1/types.go @@ -30,6 +30,9 @@ type SessionStatus struct { // CreatedAt is when the session was created. CreatedAt metav1.Time `json:"createdAt"` + // LastUpdatedAt is the last time the provider updated this session (e.g. Zitadel change_date). + LastUpdatedAt *metav1.Time `json:"lastUpdatedAt,omitempty"` + // Location is a human-readable geographic label for the client (e.g. "Bristol, United Kingdom"), // typically derived from GeoIP by the provider. Location string `json:"location,omitempty"` diff --git a/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go index 0d6de5dc..0bf61d2e 100644 --- a/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/identity/v1alpha1/zz_generated.deepcopy.go @@ -70,6 +70,10 @@ func (in *SessionList) DeepCopyObject() runtime.Object { func (in *SessionStatus) DeepCopyInto(out *SessionStatus) { *out = *in in.CreatedAt.DeepCopyInto(&out.CreatedAt) + if in.LastUpdatedAt != nil { + in, out := &in.LastUpdatedAt, &out.LastUpdatedAt + *out = (*in).DeepCopy() + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SessionStatus. diff --git a/pkg/apis/identity/v1alpha1/zz_generated.openapi.go b/pkg/apis/identity/v1alpha1/zz_generated.openapi.go index 0ba6c5f1..af150e28 100644 --- a/pkg/apis/identity/v1alpha1/zz_generated.openapi.go +++ b/pkg/apis/identity/v1alpha1/zz_generated.openapi.go @@ -155,6 +155,12 @@ func schema_pkg_apis_identity_v1alpha1_SessionStatus(ref common.ReferenceCallbac Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, + "lastUpdatedAt": { + SchemaProps: spec.SchemaProps{ + Description: "LastUpdatedAt is the last time the provider updated this session (e.g. Zitadel change_date).", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, "location": { SchemaProps: spec.SchemaProps{ Description: "Location is a human-readable geographic label for the client (e.g. \"Bristol, United Kingdom\"), typically derived from GeoIP by the provider.", From a69d6cb3f07cb27b287edd157da034be638ccc1f Mon Sep 17 00:00:00 2001 From: Matt Jenkinson <75292329+mattdjenkinson@users.noreply.github.com> Date: Wed, 25 Mar 2026 16:57:31 +0000 Subject: [PATCH 4/4] remove location and add userAgent --- docs/api/identity.md | 4 +--- internal/apiserver/identity/sessions/rest.go | 22 ++++++------------- pkg/apis/identity/v1alpha1/types.go | 11 ++-------- .../identity/v1alpha1/zz_generated.openapi.go | 18 ++------------- 4 files changed, 12 insertions(+), 43 deletions(-) diff --git a/docs/api/identity.md b/docs/api/identity.md index c056c003..efaa841f 100644 --- a/docs/api/identity.md +++ b/docs/api/identity.md @@ -68,6 +68,4 @@ This resource provides information about user authentication sessions, including | `fingerprintID` | string | A fingerprint identifier for the session (optional). | | `createdAt` | metav1.Time | The timestamp when the session was created. | | `lastUpdatedAt` | *metav1.Time | Last time the authentication provider updated this session (optional). | -| `location` | string | Human-readable location for the client (e.g. city and country), if the provider supplies it (optional). | -| `browser` | string | Detected browser or app name (e.g. Safari, Chrome) (optional). | -| `os` | string | Detected operating system (e.g. macOS, Windows) (optional). | +| `userAgent` | string | Client User-Agent string for this session, if the provider supplies it (optional). | diff --git a/internal/apiserver/identity/sessions/rest.go b/internal/apiserver/identity/sessions/rest.go index 21b8f1ea..30482c89 100644 --- a/internal/apiserver/identity/sessions/rest.go +++ b/internal/apiserver/identity/sessions/rest.go @@ -2,6 +2,7 @@ package sessions import ( "context" + "strings" "time" identityv1alpha1 "go.miloapis.com/milo/pkg/apis/identity/v1alpha1" @@ -97,18 +98,11 @@ func (r *REST) Delete(ctx context.Context, name string, _ rest.ValidateObjectFun func (r *REST) Destroy() {} -// Satisfy rest.TableConvertor with a no-op conversion (returning nil uses default table printer) -func sessionClientLabel(browser, os string) string { - switch { - case browser == "" && os == "": - return "" - case browser == "": - return os - case os == "": - return browser - default: - return browser + " / " + os +func truncateForTable(s string, max int) string { + if max <= 0 || len(s) <= max { + return s } + return strings.TrimSpace(s[:max]) + "…" } func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { @@ -117,8 +111,7 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO {Name: "Name", Type: "string", Format: "name", Description: "Metadata name of the session.", Priority: 0}, {Name: "Provider", Type: "string", Description: "Authentication provider.", Priority: 0}, {Name: "Age", Type: "date", Description: "Creation timestamp.", Priority: 0}, - {Name: "Location", Type: "string", Description: "Approximate client location, if known.", Priority: 1}, - {Name: "Client", Type: "string", Description: "Browser and OS, if known.", Priority: 1}, + {Name: "User agent", Type: "string", Description: "Client User-Agent (truncated in table view).", Priority: 1}, {Name: "Last updated", Type: "string", Description: "Provider last update time (RFC3339), if known.", Priority: 1}, {Name: "UserUID", Type: "string", Description: "Owning user UID.", Priority: 1}, }, @@ -140,8 +133,7 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO s.Name, s.Status.Provider, age.Time.Format(time.RFC3339), - s.Status.Location, - sessionClientLabel(s.Status.Browser, s.Status.OS), + truncateForTable(s.Status.UserAgent, 80), lastUpdated, s.Status.UserUID, }, diff --git a/pkg/apis/identity/v1alpha1/types.go b/pkg/apis/identity/v1alpha1/types.go index 1857d332..829a1bdb 100644 --- a/pkg/apis/identity/v1alpha1/types.go +++ b/pkg/apis/identity/v1alpha1/types.go @@ -33,15 +33,8 @@ type SessionStatus struct { // LastUpdatedAt is the last time the provider updated this session (e.g. Zitadel change_date). LastUpdatedAt *metav1.Time `json:"lastUpdatedAt,omitempty"` - // Location is a human-readable geographic label for the client (e.g. "Bristol, United Kingdom"), - // typically derived from GeoIP by the provider. - Location string `json:"location,omitempty"` - - // Browser is the detected client browser or app name (e.g. "Safari", "Chrome"). - Browser string `json:"browser,omitempty"` - - // OS is the detected operating system (e.g. "macOS", "Windows"). - OS string `json:"os,omitempty"` + // UserAgent is the client User-Agent string for this session, if the provider supplies it. + UserAgent string `json:"userAgent,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/identity/v1alpha1/zz_generated.openapi.go b/pkg/apis/identity/v1alpha1/zz_generated.openapi.go index af150e28..621e351f 100644 --- a/pkg/apis/identity/v1alpha1/zz_generated.openapi.go +++ b/pkg/apis/identity/v1alpha1/zz_generated.openapi.go @@ -161,23 +161,9 @@ func schema_pkg_apis_identity_v1alpha1_SessionStatus(ref common.ReferenceCallbac Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, - "location": { + "userAgent": { SchemaProps: spec.SchemaProps{ - Description: "Location is a human-readable geographic label for the client (e.g. \"Bristol, United Kingdom\"), typically derived from GeoIP by the provider.", - Type: []string{"string"}, - Format: "", - }, - }, - "browser": { - SchemaProps: spec.SchemaProps{ - Description: "Browser is the detected client browser or app name (e.g. \"Safari\", \"Chrome\").", - Type: []string{"string"}, - Format: "", - }, - }, - "os": { - SchemaProps: spec.SchemaProps{ - Description: "OS is the detected operating system (e.g. \"macOS\", \"Windows\").", + Description: "UserAgent is the client User-Agent string for this session, if the provider supplies it.", Type: []string{"string"}, Format: "", },