Skip to content
Merged
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
31 changes: 22 additions & 9 deletions cmd/relayfile-cli/control_plane.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,19 @@ type listWebhookSubscriptionsResponse struct {
WorkspaceID string `json:"workspaceId,omitempty"`
}

type webhookSubscriptionHealth struct {
LastDeliveryAt *string `json:"lastDeliveryAt"`
LastSuccessAt *string `json:"lastSuccessAt"`
LastError *string `json:"lastError"`
ConsecutiveFailures *int `json:"consecutiveFailures,omitempty"`
}

type webhookSubscriptionSummary struct {
SubscriptionID string `json:"subscriptionId"`
URL string `json:"url"`
PathGlobs []string `json:"pathGlobs"`
SubscriptionID string `json:"subscriptionId"`
URL string `json:"url"`
PathGlobs []string `json:"pathGlobs"`
GithubPrIdentityAuthorized *bool `json:"githubPrIdentityAuthorized,omitempty"`
Health *webhookSubscriptionHealth `json:"health,omitempty"`
}

func runControlPlane(args []string, stdout io.Writer) error {
Expand Down Expand Up @@ -514,9 +523,11 @@ func handleControlPlaneWebhookSubscription(w http.ResponseWriter, r *http.Reques
return
}
var upstream []struct {
ID string `json:"id"`
URL string `json:"url"`
PathGlobs []string `json:"pathGlobs"`
ID string `json:"id"`
URL string `json:"url"`
PathGlobs []string `json:"pathGlobs"`
GithubPrIdentityAuthorized *bool `json:"githubPrIdentityAuthorized"`
Health *webhookSubscriptionHealth `json:"health"`
}
if err := commandClient.client.getJSON(
r.Context(),
Expand All @@ -529,9 +540,11 @@ func handleControlPlaneWebhookSubscription(w http.ResponseWriter, r *http.Reques
subscriptions := make([]webhookSubscriptionSummary, 0, len(upstream))
for _, item := range upstream {
subscriptions = append(subscriptions, webhookSubscriptionSummary{
SubscriptionID: item.ID,
URL: item.URL,
PathGlobs: item.PathGlobs,
SubscriptionID: item.ID,
URL: item.URL,
PathGlobs: item.PathGlobs,
GithubPrIdentityAuthorized: item.GithubPrIdentityAuthorized,
Health: item.Health,
})
}
writeControlPlaneJSON(w, http.StatusOK, listWebhookSubscriptionsResponse{
Expand Down
37 changes: 37 additions & 0 deletions cmd/relayfile-cli/control_plane_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,11 @@ func TestControlPlaneCloudIntegrationConformance(t *testing.T) {
listedSubscriptions.Subscriptions[0].PathGlobs[0] != "/github/repos/acme/widgets/issues/**" {
t.Fatalf("unexpected webhook subscription list: %#v", listedSubscriptions)
}
if listedSubscriptions.Subscriptions[0].Health == nil ||
listedSubscriptions.Subscriptions[0].Health.ConsecutiveFailures == nil ||
*listedSubscriptions.Subscriptions[0].Health.ConsecutiveFailures != 0 {
t.Fatalf("expected webhook subscription health to pass through: %#v", listedSubscriptions.Subscriptions[0].Health)
}

var deleted map[string]bool
status = controlPlaneJSON(t, client, http.MethodDelete, baseURL+"/v1/integrations/webhook-subscriptions", deleteWebhookSubscriptionRequest{
Expand Down Expand Up @@ -421,6 +426,38 @@ func TestControlPlaneCloudIntegrationConformance(t *testing.T) {
}
}

func TestWebhookSubscriptionHealthOmitsAbsentConsecutiveFailures(t *testing.T) {
var omitted webhookSubscriptionHealth
if err := json.Unmarshal([]byte(`{"lastDeliveryAt":null,"lastSuccessAt":null,"lastError":null}`), &omitted); err != nil {
t.Fatalf("unmarshal omitted consecutiveFailures: %v", err)
}
if omitted.ConsecutiveFailures != nil {
t.Fatalf("expected omitted consecutiveFailures to stay nil, got %#v", omitted.ConsecutiveFailures)
}
raw, err := json.Marshal(omitted)
if err != nil {
t.Fatalf("marshal omitted consecutiveFailures: %v", err)
}
if strings.Contains(string(raw), "consecutiveFailures") {
t.Fatalf("omitempty should drop absent consecutiveFailures: %s", raw)
}

var present webhookSubscriptionHealth
if err := json.Unmarshal([]byte(`{"consecutiveFailures":0}`), &present); err != nil {
t.Fatalf("unmarshal zero consecutiveFailures: %v", err)
}
if present.ConsecutiveFailures == nil || *present.ConsecutiveFailures != 0 {
t.Fatalf("expected confirmed zero consecutiveFailures, got %#v", present.ConsecutiveFailures)
}
raw, err = json.Marshal(present)
if err != nil {
t.Fatalf("marshal zero consecutiveFailures: %v", err)
}
if !strings.Contains(string(raw), `"consecutiveFailures":0`) {
t.Fatalf("confirmed zero consecutiveFailures should serialize as 0: %s", raw)
}
}

func TestControlPlaneProviderStatusUsesCloudTokenFromEnvironment(t *testing.T) {
t.Setenv("HOME", t.TempDir())
clearRelayfileEnv(t)
Expand Down
19 changes: 19 additions & 0 deletions openapi/relayfile-control-plane-v1.openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,25 @@ components:
type: array
items:
type: string
githubPrIdentityAuthorized:
type: boolean
description: Whether `/pulls/<n>/**` identity expansion (title slugs, reviews, comments, checks via resource_ref) is enabled for this subscription.
health:
type: object
properties:
lastDeliveryAt:
type: string
format: date-time
nullable: true
lastSuccessAt:
type: string
format: date-time
nullable: true
lastError:
type: string
nullable: true
consecutiveFailures:
type: integer
ErrorEnvelope:
type: object
required: [error]
Expand Down
14 changes: 14 additions & 0 deletions packages/client/src/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,13 @@ describe('RelayfileControlPlaneClient integration webhook subscriptions', () =>
subscriptionId: 'whsub_123',
url: 'https://cast.test/v1/integrations/relayfile/inbound/ws/ch',
pathGlobs: ['/github/repos/acme/widgets/issues/**'],
githubPrIdentityAuthorized: true,
health: {
lastDeliveryAt: '2026-09-21T00:00:00.000Z',
lastSuccessAt: '2026-09-21T00:00:00.000Z',
lastError: null,
consecutiveFailures: 0,
},
},
],
});
Expand All @@ -622,6 +629,13 @@ describe('RelayfileControlPlaneClient integration webhook subscriptions', () =>
subscriptionId: 'whsub_123',
url: 'https://cast.test/v1/integrations/relayfile/inbound/ws/ch',
pathGlobs: ['/github/repos/acme/widgets/issues/**'],
githubPrIdentityAuthorized: true,
health: {
lastDeliveryAt: '2026-09-21T00:00:00.000Z',
lastSuccessAt: '2026-09-21T00:00:00.000Z',
lastError: null,
consecutiveFailures: 0,
},
},
],
});
Expand Down
10 changes: 10 additions & 0 deletions packages/client/src/generated/control-plane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,16 @@ export interface components {
/** Format: uri */
url: string;
pathGlobs: string[];
/** @description Whether `/pulls/<n>/**` identity expansion (title slugs, reviews, comments, checks via resource_ref) is enabled for this subscription. */
githubPrIdentityAuthorized?: boolean;
health?: {
/** Format: date-time */
lastDeliveryAt?: string | null;
/** Format: date-time */
lastSuccessAt?: string | null;
lastError?: string | null;
consecutiveFailures?: number;
};
};
ErrorEnvelope: {
error: {
Expand Down
Loading