Skip to content

Commit 0cdc227

Browse files
authored
fix(runtime): expose instance creation time in runtime bindings (#178)
fix(runtime): include instance creation time in runtime bindings
1 parent 6af2b76 commit 0cdc227

File tree

2 files changed

+21
-8
lines changed

2 files changed

+21
-8
lines changed

api/runtime_bindings.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"net/http"
66
"strings"
7+
"time"
78

89
"github.com/labstack/echo/v4"
910
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -25,6 +26,7 @@ type runtimeBindingRuntimePrincipal struct {
2526
type runtimeBindingResponse struct {
2627
InstanceID string `json:"instanceId"`
2728
Namespace string `json:"namespace"`
29+
CreatedAt string `json:"createdAt"`
2830
OwnerPrincipal runtimeBindingOwnerPrincipal `json:"ownerPrincipal"`
2931
RuntimePrincipal runtimeBindingRuntimePrincipal `json:"runtimePrincipal"`
3032
PresetID string `json:"presetId"`
@@ -72,6 +74,10 @@ func buildRuntimeBindingResponse(spritz *spritzv1.Spritz) (runtimeBindingRespons
7274
if namespace == "" {
7375
return runtimeBindingResponse{}, fmt.Errorf("instance namespace is required")
7476
}
77+
if spritz.CreationTimestamp.IsZero() {
78+
return runtimeBindingResponse{}, fmt.Errorf("instance creation timestamp is required")
79+
}
80+
createdAt := spritz.CreationTimestamp.Time.UTC().Format(time.RFC3339Nano)
7581

7682
ownerID := strings.TrimSpace(spritz.Spec.Owner.ID)
7783
if ownerID == "" {
@@ -96,6 +102,7 @@ func buildRuntimeBindingResponse(spritz *spritzv1.Spritz) (runtimeBindingRespons
96102
return runtimeBindingResponse{
97103
InstanceID: instanceID,
98104
Namespace: namespace,
105+
CreatedAt: createdAt,
99106
OwnerPrincipal: runtimeBindingOwnerPrincipal{
100107
ID: ownerID,
101108
Type: "user",

api/runtime_bindings_test.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"net/http/httptest"
66
"strings"
77
"testing"
8+
"time"
89

910
"github.com/labstack/echo/v4"
1011
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -37,8 +38,9 @@ func newRuntimeBindingsTestServer(t *testing.T, objects ...*spritzv1.Spritz) *se
3738
func TestGetRuntimeBindingReturnsCanonicalFacts(t *testing.T) {
3839
spritz := &spritzv1.Spritz{
3940
ObjectMeta: metav1.ObjectMeta{
40-
Name: "zeno-delta-breeze",
41-
Namespace: "spritz-production",
41+
Name: "zeno-delta-breeze",
42+
Namespace: "spritz-production",
43+
CreationTimestamp: metav1.NewTime(time.Date(2026, time.March, 30, 12, 34, 56, 0, time.UTC)),
4244
Annotations: map[string]string{
4345
presetIDAnnotationKey: "zeno",
4446
instanceClassAnnotationKey: "personal-agent",
@@ -73,6 +75,7 @@ func TestGetRuntimeBindingReturnsCanonicalFacts(t *testing.T) {
7375
`"serviceAccountName":"zeno-agent-abcd1234"`,
7476
`"presetId":"zeno"`,
7577
`"instanceClassId":"personal-agent"`,
78+
`"createdAt":"2026-03-30T12:34:56Z"`,
7679
}
7780
for _, fragment := range expectedFragments {
7881
if !strings.Contains(rec.Body.String(), fragment) {
@@ -84,8 +87,9 @@ func TestGetRuntimeBindingReturnsCanonicalFacts(t *testing.T) {
8487
func TestGetRuntimeBindingRejectsMissingServiceAccountName(t *testing.T) {
8588
spritz := &spritzv1.Spritz{
8689
ObjectMeta: metav1.ObjectMeta{
87-
Name: "openclaw-morning-sky",
88-
Namespace: "spritz-production",
90+
Name: "openclaw-morning-sky",
91+
Namespace: "spritz-production",
92+
CreationTimestamp: metav1.NewTime(time.Date(2026, time.March, 30, 12, 34, 56, 0, time.UTC)),
8993
Annotations: map[string]string{
9094
presetIDAnnotationKey: "openclaw",
9195
instanceClassAnnotationKey: "assistant-runtime",
@@ -112,8 +116,9 @@ func TestGetRuntimeBindingRejectsMissingServiceAccountName(t *testing.T) {
112116
func TestGetRuntimeBindingRejectsIncompleteBinding(t *testing.T) {
113117
spritz := &spritzv1.Spritz{
114118
ObjectMeta: metav1.ObjectMeta{
115-
Name: "zeno-delta-breeze",
116-
Namespace: "spritz-production",
119+
Name: "zeno-delta-breeze",
120+
Namespace: "spritz-production",
121+
CreationTimestamp: metav1.NewTime(time.Date(2026, time.March, 30, 12, 34, 56, 0, time.UTC)),
117122
Annotations: map[string]string{
118123
presetIDAnnotationKey: "zeno",
119124
},
@@ -141,8 +146,9 @@ func TestGetRuntimeBindingRejectsIncompleteBinding(t *testing.T) {
141146
func TestGetRuntimeBindingRejectsNamespaceOutsideServerScope(t *testing.T) {
142147
spritz := &spritzv1.Spritz{
143148
ObjectMeta: metav1.ObjectMeta{
144-
Name: "zeno-delta-breeze",
145-
Namespace: "spritz-production",
149+
Name: "zeno-delta-breeze",
150+
Namespace: "spritz-production",
151+
CreationTimestamp: metav1.NewTime(time.Date(2026, time.March, 30, 12, 34, 56, 0, time.UTC)),
146152
Annotations: map[string]string{
147153
presetIDAnnotationKey: "zeno",
148154
instanceClassAnnotationKey: "personal-agent",

0 commit comments

Comments
 (0)