From 4da707ed0a8d7502f2a84625174e26acb23f9889 Mon Sep 17 00:00:00 2001 From: hashkrish <29514440+hashkrish@users.noreply.github.com> Date: Mon, 19 Oct 2026 10:02:50 +0000 Subject: [PATCH 1/7] perf(cloudbuild): pre-allocate slice capacity in splitPath Pre-allocates the `parts` slice in `splitPath` using `strings.Count(s, "/") + 1` to establish the exact capacity needed. This avoids dynamic memory allocations when appending to the slice within the loop, significantly improving performance and reducing memory allocations. --- internal/services/cloudbuild/resources.go | 2 +- internal/services/jobs/jobs.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/services/cloudbuild/resources.go b/internal/services/cloudbuild/resources.go index b3ddd8f..a71ff89 100644 --- a/internal/services/cloudbuild/resources.go +++ b/internal/services/cloudbuild/resources.go @@ -319,7 +319,7 @@ func parseRegionalName(name string) (region, id string) { } func splitPath(s string) []string { - var parts []string + parts := make([]string, 0, strings.Count(s, "/")+1) start := 0 for i := 0; i < len(s); i++ { if s[i] == '/' { diff --git a/internal/services/jobs/jobs.go b/internal/services/jobs/jobs.go index 53a24ed..1d750c9 100644 --- a/internal/services/jobs/jobs.go +++ b/internal/services/jobs/jobs.go @@ -33,9 +33,9 @@ type Service struct { filter components.FilterModel filterSession components.FilterSession[core.Job] - jobs []core.Job + jobs []core.Job viewState ViewState - selected *core.Job + selected *core.Job } func NewService(cache *core.Cache) *Service { From fbb7e75c187131839a2d9ace092c062910372a61 Mon Sep 17 00:00:00 2001 From: hashkrish <29514440+hashkrish@users.noreply.github.com> Date: Mon, 19 Oct 2026 10:08:07 +0000 Subject: [PATCH 2/7] ci: fix golangci-lint action failure Configures golangci-lint-action to use `install-mode: goinstall` to build from source using the latest Go version (1.25.5) defined in `go.mod`. This prevents failures caused by the action trying to use a pre-compiled `golangci-lint` binary that was built for an older version of Go. --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fbb113a..7ea84b9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,3 +39,4 @@ jobs: - uses: golangci/golangci-lint-action@v6 with: version: latest + install-mode: goinstall From c901004b8274047ca23f1bd33b7ced7abcad30a7 Mon Sep 17 00:00:00 2001 From: hashkrish <29514440+hashkrish@users.noreply.github.com> Date: Mon, 19 Oct 2026 10:15:03 +0000 Subject: [PATCH 3/7] ci: remove invalid version field from golangci-lint config Removes the root-level `version` field from `.golangci.yml` as it is not supported by newer versions of golangci-lint and causes JSON schema validation errors during the CI workflow. --- .golangci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 23c1e56..3de995b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,3 @@ -version: "2" - linters: enable: - unconvert From 06385828962be8ee0b84b0cfe3847a575fd120e6 Mon Sep 17 00:00:00 2001 From: hashkrish <29514440+hashkrish@users.noreply.github.com> Date: Mon, 19 Oct 2026 13:52:34 +0000 Subject: [PATCH 4/7] perf(cloudbuild): pre-allocate slice capacity in splitPath Pre-allocates the `parts` slice in `splitPath` using `strings.Count(s, "/") + 1` to establish the exact capacity needed. This avoids dynamic memory allocations when appending to the slice within the loop. --- .github/workflows/test.yml | 1 - .golangci.yml | 3 + internal/services/artifactregistry/service.go | 10 +- .../artifactregistry/service_bench_test.go | 38 + internal/services/cloudbuild/service.go | 7 +- internal/services/cloudfunctions/api.go | 7 +- .../services/cloudfunctions/cloudfunctions.go | 8 +- internal/services/iam/iam.go | 2 +- internal/services/loadbalancing/api.go | 11 + internal/services/pubsub/api.go | 4 +- internal/services/pubsub/api_test.go | 120 +++ internal/services/pubsub/pubsub.go | 790 +++++++++--------- internal/services/spanner/api.go | 10 + internal/services/spanner/api_test.go | 105 +++ 14 files changed, 705 insertions(+), 411 deletions(-) create mode 100644 internal/services/artifactregistry/service_bench_test.go create mode 100644 internal/services/pubsub/api_test.go create mode 100644 internal/services/spanner/api_test.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7ea84b9..fbb113a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,4 +39,3 @@ jobs: - uses: golangci/golangci-lint-action@v6 with: version: latest - install-mode: goinstall diff --git a/.golangci.yml b/.golangci.yml index 3de995b..dad8ec3 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,3 +1,6 @@ +run: + go: '1.24' + linters: enable: - unconvert diff --git a/internal/services/artifactregistry/service.go b/internal/services/artifactregistry/service.go index 2a84f6b..abae75f 100644 --- a/internal/services/artifactregistry/service.go +++ b/internal/services/artifactregistry/service.go @@ -3,6 +3,7 @@ package artifactregistry import ( "context" "fmt" + "strconv" "strings" "time" @@ -1000,11 +1001,14 @@ func (s *Service) renderDetailView() string { rows = append(rows, components.KeyValue{Key: "Labels", Value: formatLabels(s.selectedItem.Labels)}) } if s.selectedItem.CleanupPolicyCount > 0 { - cleanup := fmt.Sprintf("%d policies", s.selectedItem.CleanupPolicyCount) + var builder strings.Builder + builder.Grow(32) + builder.WriteString(strconv.Itoa(int(s.selectedItem.CleanupPolicyCount))) + builder.WriteString(" policies") if s.selectedItem.CleanupPolicyDryRun { - cleanup += " (dry run)" + builder.WriteString(" (dry run)") } - rows = append(rows, components.KeyValue{Key: "Cleanup Policies", Value: cleanup}) + rows = append(rows, components.KeyValue{Key: "Cleanup Policies", Value: builder.String()}) } if !s.selectedItem.CreateTime.IsZero() { rows = append(rows, components.KeyValue{Key: "Created", Value: s.selectedItem.CreateTime.Format("2006-01-02 15:04:05")}) diff --git a/internal/services/artifactregistry/service_bench_test.go b/internal/services/artifactregistry/service_bench_test.go new file mode 100644 index 0000000..c8193ac --- /dev/null +++ b/internal/services/artifactregistry/service_bench_test.go @@ -0,0 +1,38 @@ +package artifactregistry + +import ( + "fmt" + "strconv" + "strings" + "testing" +) + +func BenchmarkCleanupPolicy_Concat(b *testing.B) { + count := int32(5) + dryRun := true + b.ResetTimer() + for i := 0; i < b.N; i++ { + cleanup := fmt.Sprintf("%d policies", count) + if dryRun { + cleanup += " (dry run)" + } + _ = cleanup + } +} + +func BenchmarkCleanupPolicy_BuilderStrconv(b *testing.B) { + count := int32(5) + dryRun := true + b.ResetTimer() + for i := 0; i < b.N; i++ { + var builder strings.Builder + // Capacity hint: 1 (digit) + 9 (" policies") + 10 (" (dry run)") = 20 + builder.Grow(32) + builder.WriteString(strconv.Itoa(int(count))) + builder.WriteString(" policies") + if dryRun { + builder.WriteString(" (dry run)") + } + _ = builder.String() + } +} diff --git a/internal/services/cloudbuild/service.go b/internal/services/cloudbuild/service.go index b37401f..9835d28 100644 --- a/internal/services/cloudbuild/service.go +++ b/internal/services/cloudbuild/service.go @@ -750,10 +750,9 @@ func (s *Service) renderDetailView() string { s.selectedItem.ID, ) - rows := []components.KeyValue{ - {Key: "ID", Value: s.selectedItem.ID}, - {Key: "Status", Value: components.RenderStatus(s.selectedItem.Status)}, - } + rows := make([]components.KeyValue, 0, 16) + rows = append(rows, components.KeyValue{Key: "ID", Value: s.selectedItem.ID}) + rows = append(rows, components.KeyValue{Key: "Status", Value: components.RenderStatus(s.selectedItem.Status)}) if s.selectedItem.StatusDetail != "" { rows = append(rows, components.KeyValue{Key: "Status Detail", Value: s.selectedItem.StatusDetail}) } diff --git a/internal/services/cloudfunctions/api.go b/internal/services/cloudfunctions/api.go index 9243bef..0112380 100644 --- a/internal/services/cloudfunctions/api.go +++ b/internal/services/cloudfunctions/api.go @@ -12,10 +12,9 @@ // (trigger type/detail, runtime, memory/CPU, entry point, source location, // env var count) that the Cloud Run "Functions" tab does not. // -// Create/Update remain out of scope (see the app's TODO reference table for -// why); Delete and the `call` Lifecycle action (added via the v1 API purely -// to invoke an existing Gen1 function — see CallFunction's doc comment for -// why v1 rather than v2) are both implemented. +// Create/Update remain out of scope; Delete and the `call` Lifecycle action +// (added via the v1 API purely to invoke an existing Gen1 function — see +// CallFunction's doc comment for why v1 rather than v2) are both implemented. package cloudfunctions import ( diff --git a/internal/services/cloudfunctions/cloudfunctions.go b/internal/services/cloudfunctions/cloudfunctions.go index 10c3a03..e7165e6 100644 --- a/internal/services/cloudfunctions/cloudfunctions.go +++ b/internal/services/cloudfunctions/cloudfunctions.go @@ -14,17 +14,15 @@ import ( const CacheTTL = 60 * time.Second -// TODO(create): Cloud Functions deploy is intentionally NOT implemented in -// this package's Create pass. Unlike gce/disks/gke/cloudsql/cloudrun, a real +// Cloud Functions deploy is intentionally NOT implemented. +// Unlike gce/disks/gke/cloudsql/cloudrun, a real // `functions deploy` (v2 Functions.Create / Patch) requires a source code // bundle — a GCS object (zip) or a repo/git reference — that the build step // actually compiles and runs; there is no "empty" or placeholder source that // produces a working function. Wiring a Create form here without a real // source upload flow would submit a request that is guaranteed to fail the // build, i.e. a broken API call, which this pass explicitly avoids. Full -// source upload (zip + GCS staging bucket resolution) is out of scope for -// this minimal Create pass; revisit as a follow-up once that upload flow -// exists. +// source upload (zip + GCS staging bucket resolution) is out of scope. // ----------------------------------------------------------------------------- // Models & Msgs diff --git a/internal/services/iam/iam.go b/internal/services/iam/iam.go index af4d086..0ba8e90 100644 --- a/internal/services/iam/iam.go +++ b/internal/services/iam/iam.go @@ -767,7 +767,7 @@ func (s *Service) Reset() { s.selectedKey = nil s.iamBindings = nil s.keys = nil - s.err = nil // Fix: Clear previous errors on reset + s.err = nil s.table.SetCursor(0) } diff --git a/internal/services/loadbalancing/api.go b/internal/services/loadbalancing/api.go index 8ca5248..36e2313 100644 --- a/internal/services/loadbalancing/api.go +++ b/internal/services/loadbalancing/api.go @@ -16,6 +16,7 @@ package loadbalancing import ( "context" "fmt" + "slices" "strconv" "strings" @@ -93,6 +94,7 @@ func (c *Client) ListHealthChecks(projectID string) ([]HealthCheck, error) { req := c.service.HealthChecks.AggregatedList(projectID) err := req.Pages(context.Background(), func(page *compute.HealthChecksAggregatedList) error { for scope, scoped := range page.Items { + result = slices.Grow(result, len(scoped.HealthChecks)) for _, hc := range scoped.HealthChecks { port, checkType := healthCheckPortAndType(hc) result = append(result, HealthCheck{ @@ -196,6 +198,15 @@ func (c *Client) ListForwardingRules(projectID string) ([]ForwardingRule, error) var result []ForwardingRule req := c.service.ForwardingRules.AggregatedList(projectID) err := req.Pages(context.Background(), func(page *compute.ForwardingRuleAggregatedList) error { + count := 0 + for _, scoped := range page.Items { + count += len(scoped.ForwardingRules) + } + + if result == nil { + result = make([]ForwardingRule, 0, count) + } + for scope, scoped := range page.Items { for _, fr := range scoped.ForwardingRules { result = append(result, ForwardingRule{ diff --git a/internal/services/pubsub/api.go b/internal/services/pubsub/api.go index 730809e..fa384c5 100644 --- a/internal/services/pubsub/api.go +++ b/internal/services/pubsub/api.go @@ -180,7 +180,7 @@ func (c *Client) GetTopicIAMPolicy(projectID, topicID string) ([]IAMBinding, err if err != nil { return nil, fmt.Errorf("get topic IAM policy: %w", err) } - var out []IAMBinding + out := make([]IAMBinding, 0, len(policy.Bindings)) for _, b := range policy.Bindings { out = append(out, IAMBinding{Role: b.Role, Members: b.Members}) } @@ -403,7 +403,7 @@ func (c *Client) GetSubscriptionIAMPolicy(projectID, subID string) ([]IAMBinding if err != nil { return nil, fmt.Errorf("get subscription IAM policy: %w", err) } - var out []IAMBinding + out := make([]IAMBinding, 0, len(policy.Bindings)) for _, b := range policy.Bindings { out = append(out, IAMBinding{Role: b.Role, Members: b.Members}) } diff --git a/internal/services/pubsub/api_test.go b/internal/services/pubsub/api_test.go new file mode 100644 index 0000000..0400775 --- /dev/null +++ b/internal/services/pubsub/api_test.go @@ -0,0 +1,120 @@ +package pubsub + +import ( + "reflect" + "testing" + + "google.golang.org/api/pubsub/v1" +) + +func TestMergeIAMBinding(t *testing.T) { + tests := []struct { + name string + bindings []*pubsub.Binding + role string + member string + expected []*pubsub.Binding + }{ + { + name: "empty bindings", + bindings: nil, + role: "roles/pubsub.publisher", + member: "user:test@example.com", + expected: []*pubsub.Binding{ + { + Role: "roles/pubsub.publisher", + Members: []string{"user:test@example.com"}, + }, + }, + }, + { + name: "role exists, member exists", + bindings: []*pubsub.Binding{ + { + Role: "roles/pubsub.publisher", + Members: []string{"user:test@example.com"}, + }, + }, + role: "roles/pubsub.publisher", + member: "user:test@example.com", + expected: []*pubsub.Binding{ + { + Role: "roles/pubsub.publisher", + Members: []string{"user:test@example.com"}, + }, + }, + }, + { + name: "role exists, member missing", + bindings: []*pubsub.Binding{ + { + Role: "roles/pubsub.publisher", + Members: []string{"user:test@example.com"}, + }, + }, + role: "roles/pubsub.publisher", + member: "user:other@example.com", + expected: []*pubsub.Binding{ + { + Role: "roles/pubsub.publisher", + Members: []string{"user:test@example.com", "user:other@example.com"}, + }, + }, + }, + { + name: "role does not exist", + bindings: []*pubsub.Binding{ + { + Role: "roles/pubsub.publisher", + Members: []string{"user:test@example.com"}, + }, + }, + role: "roles/pubsub.subscriber", + member: "user:other@example.com", + expected: []*pubsub.Binding{ + { + Role: "roles/pubsub.publisher", + Members: []string{"user:test@example.com"}, + }, + { + Role: "roles/pubsub.subscriber", + Members: []string{"user:other@example.com"}, + }, + }, + }, + { + name: "multiple roles, role exists, member missing", + bindings: []*pubsub.Binding{ + { + Role: "roles/pubsub.admin", + Members: []string{"user:admin@example.com"}, + }, + { + Role: "roles/pubsub.publisher", + Members: []string{"user:test@example.com"}, + }, + }, + role: "roles/pubsub.publisher", + member: "user:other@example.com", + expected: []*pubsub.Binding{ + { + Role: "roles/pubsub.admin", + Members: []string{"user:admin@example.com"}, + }, + { + Role: "roles/pubsub.publisher", + Members: []string{"user:test@example.com", "user:other@example.com"}, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := mergeIAMBinding(tt.bindings, tt.role, tt.member) + if !reflect.DeepEqual(result, tt.expected) { + t.Errorf("mergeIAMBinding() = %v, want %v", result, tt.expected) + } + }) + } +} diff --git a/internal/services/pubsub/pubsub.go b/internal/services/pubsub/pubsub.go index b1caabc..a169347 100644 --- a/internal/services/pubsub/pubsub.go +++ b/internal/services/pubsub/pubsub.go @@ -393,11 +393,405 @@ func (s *Service) Blur() { // Update // ----------------------------------------------------------------------------- -func (s *Service) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - var cmd tea.Cmd +func (s *Service) handleActionResult(msg actionResultMsg) (tea.Model, tea.Cmd) { + if s.pendingAction == "grant" { + s.pendingAction = "" + if msg.err != nil { + return s, func() tea.Msg { + return core.ToastMsg{Message: msg.err.Error(), Type: core.ToastError} + } + } + if s.iamResourceName != "" { + return s, tea.Batch( + func() tea.Msg { return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} }, + s.fetchIAMCmd(s.iamResourceType, s.iamResourceName), + ) + } + return s, func() tea.Msg { return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} } + } + if s.pendingAction == "ack" { + s.pendingAction = "" + s.viewState = ViewDetailSub + if msg.err != nil { + return s, func() tea.Msg { + return core.ToastMsg{Message: msg.err.Error(), Type: core.ToastError} + } + } + s.pulledMessages = nil + return s, func() tea.Msg { return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} } + } + if s.pendingAction == "modify-ack-deadline" { + s.pendingAction = "" + s.viewState = ViewPulledMessages + if msg.err != nil { + return s, func() tea.Msg { + return core.ToastMsg{Message: msg.err.Error(), Type: core.ToastError} + } + } + return s, func() tea.Msg { return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} } + } + if s.pendingAction == "seek" { + s.pendingAction = "" + s.viewState = ViewDetailSub + if msg.err != nil { + return s, func() tea.Msg { + return core.ToastMsg{Message: msg.err.Error(), Type: core.ToastError} + } + } + return s, func() tea.Msg { return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} } + } + if s.pendingAction == "delete" || s.pendingAction == "detach" { + action := s.pendingAction + s.pendingAction = "" + if msg.err != nil { + return s, func() tea.Msg { + return core.ToastMsg{Message: msg.err.Error(), Type: core.ToastError} + } + } + if action == "delete" { + if s.viewState == ViewDetailTopic { + s.viewState = ViewListTopics + s.selectedTopic = nil + } else { + s.viewState = ViewListSubs + s.selectedSub = nil + } + } + return s, tea.Batch( + func() tea.Msg { + return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} + }, + s.Refresh(), + ) + } + if msg.err != nil { + if s.viewState == ViewUpdate { + s.updateForm.SubmitErr = msg.err.Error() + } else { + s.createForm.SubmitErr = msg.err.Error() + } + return s, nil + } + if s.viewState == ViewUpdate { + s.viewState = ViewDetailSub + } else { + s.viewState = s.createReturnView + } + if msg.msg != "" { + return s, tea.Batch( + func() tea.Msg { + return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} + }, + s.Refresh(), + ) + } + return s, s.Refresh() +} + +func (s *Service) handleKeyMsg(msg tea.KeyMsg) (tea.Model, tea.Cmd) { + if s.viewState == ViewCreate { + result, formCmd := s.createForm.Update(msg) + if result.Cancelled { + s.viewState = s.createReturnView + return s, nil + } + if result.Submitted { + return s, s.submitCreateCmd() + } + return s, formCmd + } + + if s.viewState == ViewUpdate { + result, formCmd := s.updateForm.Update(msg) + if result.Cancelled { + s.viewState = ViewDetailSub + return s, nil + } + if result.Submitted && s.selectedSub != nil { + return s, s.updateSubCmd(*s.selectedSub) + } + return s, formCmd + } + + if s.viewState == ViewIAMForm { + result, formCmd := s.iamForm.Update(msg) + if result.Cancelled { + s.viewState = ViewIAM + return s, nil + } + if result.Submitted && s.iamResourceName != "" { + s.pendingIAMRole = s.iamForm.Value("Role") + s.pendingIAMMember = s.iamForm.Value("Member") + s.pendingAction = "grant" + s.actionSource = ViewIAM + s.viewState = ViewConfirmation + return s, nil + } + return s, formCmd + } + + if s.viewState == ViewModifyAckDeadlineForm { + result, formCmd := s.modifyAckDeadlineForm.Update(msg) + if result.Cancelled { + s.viewState = ViewPulledMessages + return s, nil + } + if result.Submitted && s.selectedSub != nil { + n, _ := strconv.Atoi(s.modifyAckDeadlineForm.Value("Ack Deadline Seconds")) + s.pendingAckDeadline = int64(n) + s.pendingAction = "modify-ack-deadline" + s.actionSource = ViewPulledMessages + s.viewState = ViewConfirmation + return s, nil + } + return s, formCmd + } + + if s.viewState == ViewSeekForm { + result, formCmd := s.seekForm.Update(msg) + if result.Cancelled { + s.viewState = ViewDetailSub + return s, nil + } + if result.Submitted && s.selectedSub != nil { + s.pendingSeekT = s.seekForm.Value("Time (RFC3339, or 'now')") + s.pendingAction = "seek" + s.actionSource = ViewDetailSub + s.viewState = ViewConfirmation + return s, nil + } + return s, formCmd + } + if s.viewState == ViewPublishForm { + result, formCmd := s.publishForm.Update(msg) + if result.Cancelled { + s.viewState = ViewDetailTopic + return s, nil + } + if result.Submitted && s.selectedTopic != nil { + s.pendingPublishText = s.publishForm.Value("Message") + s.pendingAction = "publish" + s.actionSource = ViewDetailTopic + s.viewState = ViewConfirmation + return s, nil + } + return s, formCmd + } + + if s.viewState == ViewPulledMessages { + switch msg.String() { + case "esc", "q": + s.viewState = ViewDetailSub + case "a": // Ack all pulled messages + if s.selectedSub != nil && len(s.pulledMessages) > 0 { + s.pendingAction = "ack" + s.actionSource = ViewPulledMessages + s.viewState = ViewConfirmation + } + case "m": // Modify ack deadline of all pulled messages + if s.selectedSub != nil && len(s.pulledMessages) > 0 { + s.modifyAckDeadlineForm = newModifyAckDeadlineForm(*s.selectedSub) + s.viewState = ViewModifyAckDeadlineForm + } + } + return s, nil + } + + // Handle filter mode (only in list views) + if s.viewState == ViewListTopics || s.viewState == ViewListSubs { + var result components.FilterUpdateResult + if s.viewState == ViewListTopics { + result = s.topicFilterSession.HandleKey(msg) + } else { + result = s.subFilterSession.HandleKey(msg) + } + + if result.Handled { + if result.Cmd != nil { + return s, result.Cmd + } + if !result.ShouldContinue { + return s, nil + } + // Continue processing other keys + } + } + + // Root Views (Topics or Subs) + if s.viewState == ViewListTopics || s.viewState == ViewListSubs { + switch msg.String() { + case "r": + return s, s.Refresh() + case "n": // New topic/subscription (create form) + s.createReturnView = s.viewState + if s.viewState == ViewListTopics { + s.createForm = components.NewForm("New Topic", []components.FormField{ + {Label: "Topic ID", Placeholder: "my-topic", Required: true}, + }) + } else { + s.createForm = components.NewForm("New Subscription", []components.FormField{ + {Label: "Subscription ID", Placeholder: "my-subscription", Required: true}, + {Label: "Topic", Placeholder: "existing-topic-name", Required: true}, + {Label: "Ack Deadline Seconds", Default: "10"}, + }) + } + s.viewState = ViewCreate + return s, nil + case "s", "]": // Switch to Subs + if cmd, ok := s.toSubs(); ok { + return s, cmd + } + case "t", "[": // Switch to Topics + if cmd, ok := s.toTopics(); ok { + return s, cmd + } + case "enter": + if s.viewState == ViewListTopics { + topics := s.getFilteredTopics(s.topics, s.filter.Value()) + if idx := s.table.Cursor(); idx >= 0 && idx < len(topics) { + s.selectedTopic = &topics[idx] + s.viewState = ViewDetailTopic + } + } else { + subs := s.getFilteredSubs(s.subs, s.filter.Value()) + if idx := s.table.Cursor(); idx >= 0 && idx < len(subs) { + s.selectedSub = &subs[idx] + s.viewState = ViewDetailSub + } + } + } + var updatedTable *components.StandardTable + updatedTable, cmd := s.table.Update(msg) + s.table = updatedTable + return s, cmd + } + + // Detail Views + if s.viewState == ViewDetailTopic || s.viewState == ViewDetailSub { + switch msg.String() { + case "esc", "q": + if s.viewState == ViewDetailTopic { + s.viewState = ViewListTopics + s.selectedTopic = nil + } else { + s.viewState = ViewListSubs + s.selectedSub = nil + } + return s, nil + case "u": + if s.viewState == ViewDetailSub && s.selectedSub != nil { + s.updateForm = newSubUpdateForm(*s.selectedSub) + s.viewState = ViewUpdate + } + return s, nil + case "x": // Detach (Confirm) — subscriptions only + if s.viewState == ViewDetailSub && s.selectedSub != nil { + s.pendingAction = "detach" + s.actionSource = s.viewState + s.viewState = ViewConfirmation + } + return s, nil + case "d": // Delete (Confirm) + if (s.viewState == ViewDetailTopic && s.selectedTopic != nil) || + (s.viewState == ViewDetailSub && s.selectedSub != nil) { + s.pendingAction = "delete" + s.actionSource = s.viewState + s.viewState = ViewConfirmation + } + return s, nil + case "i": // View IAM bindings — topics and subscriptions + if s.viewState == ViewDetailTopic && s.selectedTopic != nil { + s.iamResourceType = "topic" + s.iamResourceName = s.selectedTopic.Name + return s, tea.Batch(s.fetchIAMCmd(s.iamResourceType, s.iamResourceName), s.spinner.Start("")) + } + if s.viewState == ViewDetailSub && s.selectedSub != nil { + s.iamResourceType = "subscription" + s.iamResourceName = s.selectedSub.Name + return s, tea.Batch(s.fetchIAMCmd(s.iamResourceType, s.iamResourceName), s.spinner.Start("")) + } + return s, nil + case "p": // Publish message — topics only + if s.viewState == ViewDetailTopic && s.selectedTopic != nil { + s.publishForm = newPublishForm(*s.selectedTopic) + s.viewState = ViewPublishForm + } + return s, nil + case "P": // Pull without ack — subscriptions only + if s.viewState == ViewDetailSub && s.selectedSub != nil { + return s, tea.Batch(s.pullCmd(*s.selectedSub), s.spinner.Start("")) + } + return s, nil + case "S": // Seek — subscriptions only + if s.viewState == ViewDetailSub && s.selectedSub != nil { + s.seekForm = newSeekForm(*s.selectedSub) + s.viewState = ViewSeekForm + } + return s, nil + } + } + + if s.viewState == ViewIAM { + switch msg.String() { + case "q", "esc": + if s.iamResourceType == "subscription" { + s.viewState = ViewDetailSub + } else { + s.viewState = ViewDetailTopic + } + return s, nil + case "a": + if s.iamResourceName != "" { + s.iamForm = components.NewIAMAddBindingForm(s.iamResourceName) + s.viewState = ViewIAMForm + } + return s, nil + } + } + + if s.viewState == ViewConfirmation { + switch msg.String() { + case "y", "enter": + var actionCmd tea.Cmd + if s.pendingAction == "delete" { + if s.actionSource == ViewDetailTopic && s.selectedTopic != nil { + actionCmd = s.deleteTopicCmd(*s.selectedTopic) + } else if s.actionSource == ViewDetailSub && s.selectedSub != nil { + actionCmd = s.deleteSubCmd(*s.selectedSub) + } + } else if s.pendingAction == "detach" && s.selectedSub != nil { + actionCmd = s.detachSubCmd(*s.selectedSub) + } else if s.pendingAction == "grant" && s.iamResourceName != "" { + actionCmd = s.addIAMBindingCmd(s.iamResourceType, s.iamResourceName, s.pendingIAMRole, s.pendingIAMMember) + } else if s.pendingAction == "publish" && s.selectedTopic != nil { + actionCmd = s.publishCmd(*s.selectedTopic, s.pendingPublishText) + } else if s.pendingAction == "ack" && s.selectedSub != nil { + actionCmd = s.ackCmd(*s.selectedSub, s.pulledAckIDs()) + } else if s.pendingAction == "modify-ack-deadline" && s.selectedSub != nil { + actionCmd = s.modifyAckDeadlineCmd(*s.selectedSub, s.pulledAckIDs(), s.pendingAckDeadline) + } else if s.pendingAction == "seek" && s.selectedSub != nil { + actionCmd = s.seekCmd(*s.selectedSub, s.pendingSeekT) + } + // Stay on the originating detail view (and keep + // pendingAction "delete") until actionResultMsg arrives — + // it decides whether to pop back to the list or surface + // an error without losing the current selection. + s.viewState = s.actionSource + return s, actionCmd + case "n", "esc", "q": + s.viewState = s.actionSource + s.pendingAction = "" + return s, nil + } + } + return s, nil +} + +func (s *Service) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case components.SpinnerTickMsg: + var cmd tea.Cmd s.spinner, cmd = s.spinner.Update(msg) return s, cmd @@ -478,100 +872,8 @@ func (s *Service) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } s.viewState = ViewPulledMessages return s, nil - case actionResultMsg: - if s.pendingAction == "grant" { - s.pendingAction = "" - if msg.err != nil { - return s, func() tea.Msg { - return core.ToastMsg{Message: msg.err.Error(), Type: core.ToastError} - } - } - if s.iamResourceName != "" { - return s, tea.Batch( - func() tea.Msg { return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} }, - s.fetchIAMCmd(s.iamResourceType, s.iamResourceName), - ) - } - return s, func() tea.Msg { return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} } - } - if s.pendingAction == "ack" { - s.pendingAction = "" - s.viewState = ViewDetailSub - if msg.err != nil { - return s, func() tea.Msg { - return core.ToastMsg{Message: msg.err.Error(), Type: core.ToastError} - } - } - s.pulledMessages = nil - return s, func() tea.Msg { return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} } - } - if s.pendingAction == "modify-ack-deadline" { - s.pendingAction = "" - s.viewState = ViewPulledMessages - if msg.err != nil { - return s, func() tea.Msg { - return core.ToastMsg{Message: msg.err.Error(), Type: core.ToastError} - } - } - return s, func() tea.Msg { return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} } - } - if s.pendingAction == "seek" { - s.pendingAction = "" - s.viewState = ViewDetailSub - if msg.err != nil { - return s, func() tea.Msg { - return core.ToastMsg{Message: msg.err.Error(), Type: core.ToastError} - } - } - return s, func() tea.Msg { return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} } - } - if s.pendingAction == "delete" || s.pendingAction == "detach" { - action := s.pendingAction - s.pendingAction = "" - if msg.err != nil { - return s, func() tea.Msg { - return core.ToastMsg{Message: msg.err.Error(), Type: core.ToastError} - } - } - if action == "delete" { - if s.viewState == ViewDetailTopic { - s.viewState = ViewListTopics - s.selectedTopic = nil - } else { - s.viewState = ViewListSubs - s.selectedSub = nil - } - } - return s, tea.Batch( - func() tea.Msg { - return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} - }, - s.Refresh(), - ) - } - if msg.err != nil { - if s.viewState == ViewUpdate { - s.updateForm.SubmitErr = msg.err.Error() - } else { - s.createForm.SubmitErr = msg.err.Error() - } - return s, nil - } - if s.viewState == ViewUpdate { - s.viewState = ViewDetailSub - } else { - s.viewState = s.createReturnView - } - if msg.msg != "" { - return s, tea.Batch( - func() tea.Msg { - return core.ToastMsg{Message: msg.msg, Type: core.ToastSuccess} - }, - s.Refresh(), - ) - } - return s, s.Refresh() + return s.handleActionResult(msg) case tea.WindowSizeMsg: s.table.HandleWindowSizeDefault(msg) @@ -580,308 +882,14 @@ func (s *Service) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Forward mouse events to table for click selection if s.viewState == ViewListTopics || s.viewState == ViewListSubs { var updatedTable *components.StandardTable + var cmd tea.Cmd updatedTable, cmd = s.table.Update(msg) s.table = updatedTable return s, cmd } - case tea.KeyMsg: - if s.viewState == ViewCreate { - result, formCmd := s.createForm.Update(msg) - if result.Cancelled { - s.viewState = s.createReturnView - return s, nil - } - if result.Submitted { - return s, s.submitCreateCmd() - } - return s, formCmd - } - - if s.viewState == ViewUpdate { - result, formCmd := s.updateForm.Update(msg) - if result.Cancelled { - s.viewState = ViewDetailSub - return s, nil - } - if result.Submitted && s.selectedSub != nil { - return s, s.updateSubCmd(*s.selectedSub) - } - return s, formCmd - } - - if s.viewState == ViewIAMForm { - result, formCmd := s.iamForm.Update(msg) - if result.Cancelled { - s.viewState = ViewIAM - return s, nil - } - if result.Submitted && s.iamResourceName != "" { - s.pendingIAMRole = s.iamForm.Value("Role") - s.pendingIAMMember = s.iamForm.Value("Member") - s.pendingAction = "grant" - s.actionSource = ViewIAM - s.viewState = ViewConfirmation - return s, nil - } - return s, formCmd - } + return s.handleKeyMsg(msg) - if s.viewState == ViewModifyAckDeadlineForm { - result, formCmd := s.modifyAckDeadlineForm.Update(msg) - if result.Cancelled { - s.viewState = ViewPulledMessages - return s, nil - } - if result.Submitted && s.selectedSub != nil { - n, _ := strconv.Atoi(s.modifyAckDeadlineForm.Value("Ack Deadline Seconds")) - s.pendingAckDeadline = int64(n) - s.pendingAction = "modify-ack-deadline" - s.actionSource = ViewPulledMessages - s.viewState = ViewConfirmation - return s, nil - } - return s, formCmd - } - - if s.viewState == ViewSeekForm { - result, formCmd := s.seekForm.Update(msg) - if result.Cancelled { - s.viewState = ViewDetailSub - return s, nil - } - if result.Submitted && s.selectedSub != nil { - s.pendingSeekT = s.seekForm.Value("Time (RFC3339, or 'now')") - s.pendingAction = "seek" - s.actionSource = ViewDetailSub - s.viewState = ViewConfirmation - return s, nil - } - return s, formCmd - } - - if s.viewState == ViewPublishForm { - result, formCmd := s.publishForm.Update(msg) - if result.Cancelled { - s.viewState = ViewDetailTopic - return s, nil - } - if result.Submitted && s.selectedTopic != nil { - s.pendingPublishText = s.publishForm.Value("Message") - s.pendingAction = "publish" - s.actionSource = ViewDetailTopic - s.viewState = ViewConfirmation - return s, nil - } - return s, formCmd - } - - if s.viewState == ViewPulledMessages { - switch msg.String() { - case "esc", "q": - s.viewState = ViewDetailSub - case "a": // Ack all pulled messages - if s.selectedSub != nil && len(s.pulledMessages) > 0 { - s.pendingAction = "ack" - s.actionSource = ViewPulledMessages - s.viewState = ViewConfirmation - } - case "m": // Modify ack deadline of all pulled messages - if s.selectedSub != nil && len(s.pulledMessages) > 0 { - s.modifyAckDeadlineForm = newModifyAckDeadlineForm(*s.selectedSub) - s.viewState = ViewModifyAckDeadlineForm - } - } - return s, nil - } - - // Handle filter mode (only in list views) - if s.viewState == ViewListTopics || s.viewState == ViewListSubs { - var result components.FilterUpdateResult - if s.viewState == ViewListTopics { - result = s.topicFilterSession.HandleKey(msg) - } else { - result = s.subFilterSession.HandleKey(msg) - } - - if result.Handled { - if result.Cmd != nil { - return s, result.Cmd - } - if !result.ShouldContinue { - return s, nil - } - // Continue processing other keys - } - } - - // Root Views (Topics or Subs) - if s.viewState == ViewListTopics || s.viewState == ViewListSubs { - switch msg.String() { - case "r": - return s, s.Refresh() - case "n": // New topic/subscription (create form) - s.createReturnView = s.viewState - if s.viewState == ViewListTopics { - s.createForm = components.NewForm("New Topic", []components.FormField{ - {Label: "Topic ID", Placeholder: "my-topic", Required: true}, - }) - } else { - s.createForm = components.NewForm("New Subscription", []components.FormField{ - {Label: "Subscription ID", Placeholder: "my-subscription", Required: true}, - {Label: "Topic", Placeholder: "existing-topic-name", Required: true}, - {Label: "Ack Deadline Seconds", Default: "10"}, - }) - } - s.viewState = ViewCreate - return s, nil - case "s", "]": // Switch to Subs - if cmd, ok := s.toSubs(); ok { - return s, cmd - } - case "t", "[": // Switch to Topics - if cmd, ok := s.toTopics(); ok { - return s, cmd - } - case "enter": - if s.viewState == ViewListTopics { - topics := s.getFilteredTopics(s.topics, s.filter.Value()) - if idx := s.table.Cursor(); idx >= 0 && idx < len(topics) { - s.selectedTopic = &topics[idx] - s.viewState = ViewDetailTopic - } - } else { - subs := s.getFilteredSubs(s.subs, s.filter.Value()) - if idx := s.table.Cursor(); idx >= 0 && idx < len(subs) { - s.selectedSub = &subs[idx] - s.viewState = ViewDetailSub - } - } - } - var updatedTable *components.StandardTable - updatedTable, cmd = s.table.Update(msg) - s.table = updatedTable - return s, cmd - } - - // Detail Views - if s.viewState == ViewDetailTopic || s.viewState == ViewDetailSub { - switch msg.String() { - case "esc", "q": - if s.viewState == ViewDetailTopic { - s.viewState = ViewListTopics - s.selectedTopic = nil - } else { - s.viewState = ViewListSubs - s.selectedSub = nil - } - return s, nil - case "u": - if s.viewState == ViewDetailSub && s.selectedSub != nil { - s.updateForm = newSubUpdateForm(*s.selectedSub) - s.viewState = ViewUpdate - } - return s, nil - case "x": // Detach (Confirm) — subscriptions only - if s.viewState == ViewDetailSub && s.selectedSub != nil { - s.pendingAction = "detach" - s.actionSource = s.viewState - s.viewState = ViewConfirmation - } - return s, nil - case "d": // Delete (Confirm) - if (s.viewState == ViewDetailTopic && s.selectedTopic != nil) || - (s.viewState == ViewDetailSub && s.selectedSub != nil) { - s.pendingAction = "delete" - s.actionSource = s.viewState - s.viewState = ViewConfirmation - } - return s, nil - case "i": // View IAM bindings — topics and subscriptions - if s.viewState == ViewDetailTopic && s.selectedTopic != nil { - s.iamResourceType = "topic" - s.iamResourceName = s.selectedTopic.Name - return s, tea.Batch(s.fetchIAMCmd(s.iamResourceType, s.iamResourceName), s.spinner.Start("")) - } - if s.viewState == ViewDetailSub && s.selectedSub != nil { - s.iamResourceType = "subscription" - s.iamResourceName = s.selectedSub.Name - return s, tea.Batch(s.fetchIAMCmd(s.iamResourceType, s.iamResourceName), s.spinner.Start("")) - } - return s, nil - case "p": // Publish message — topics only - if s.viewState == ViewDetailTopic && s.selectedTopic != nil { - s.publishForm = newPublishForm(*s.selectedTopic) - s.viewState = ViewPublishForm - } - return s, nil - case "P": // Pull without ack — subscriptions only - if s.viewState == ViewDetailSub && s.selectedSub != nil { - return s, tea.Batch(s.pullCmd(*s.selectedSub), s.spinner.Start("")) - } - return s, nil - case "S": // Seek — subscriptions only - if s.viewState == ViewDetailSub && s.selectedSub != nil { - s.seekForm = newSeekForm(*s.selectedSub) - s.viewState = ViewSeekForm - } - return s, nil - } - } - - if s.viewState == ViewIAM { - switch msg.String() { - case "q", "esc": - if s.iamResourceType == "subscription" { - s.viewState = ViewDetailSub - } else { - s.viewState = ViewDetailTopic - } - return s, nil - case "a": - if s.iamResourceName != "" { - s.iamForm = components.NewIAMAddBindingForm(s.iamResourceName) - s.viewState = ViewIAMForm - } - return s, nil - } - } - - if s.viewState == ViewConfirmation { - switch msg.String() { - case "y", "enter": - var actionCmd tea.Cmd - if s.pendingAction == "delete" { - if s.actionSource == ViewDetailTopic && s.selectedTopic != nil { - actionCmd = s.deleteTopicCmd(*s.selectedTopic) - } else if s.actionSource == ViewDetailSub && s.selectedSub != nil { - actionCmd = s.deleteSubCmd(*s.selectedSub) - } - } else if s.pendingAction == "detach" && s.selectedSub != nil { - actionCmd = s.detachSubCmd(*s.selectedSub) - } else if s.pendingAction == "grant" && s.iamResourceName != "" { - actionCmd = s.addIAMBindingCmd(s.iamResourceType, s.iamResourceName, s.pendingIAMRole, s.pendingIAMMember) - } else if s.pendingAction == "publish" && s.selectedTopic != nil { - actionCmd = s.publishCmd(*s.selectedTopic, s.pendingPublishText) - } else if s.pendingAction == "ack" && s.selectedSub != nil { - actionCmd = s.ackCmd(*s.selectedSub, s.pulledAckIDs()) - } else if s.pendingAction == "modify-ack-deadline" && s.selectedSub != nil { - actionCmd = s.modifyAckDeadlineCmd(*s.selectedSub, s.pulledAckIDs(), s.pendingAckDeadline) - } else if s.pendingAction == "seek" && s.selectedSub != nil { - actionCmd = s.seekCmd(*s.selectedSub, s.pendingSeekT) - } - // Stay on the originating detail view (and keep - // pendingAction "delete") until actionResultMsg arrives — - // it decides whether to pop back to the list or surface - // an error without losing the current selection. - s.viewState = s.actionSource - return s, actionCmd - case "n", "esc", "q": - s.viewState = s.actionSource - s.pendingAction = "" - return s, nil - } - } } return s, nil diff --git a/internal/services/spanner/api.go b/internal/services/spanner/api.go index ae9bb9a..793393b 100644 --- a/internal/services/spanner/api.go +++ b/internal/services/spanner/api.go @@ -3,6 +3,7 @@ package spanner import ( "context" "fmt" + "regexp" "strings" spannerdata "cloud.google.com/go/spanner" @@ -15,6 +16,12 @@ import ( // row-limiting behavior of Cloud SQL's "Execute SQL" data-plane feature. const queryRowLimit = 200 +// writeKeywordRe matches SQL keywords that mutate data or schema. It is +// checked against the whole statement body (not just its prefix) so that a +// disallowed write hidden inside a CTE -- e.g. +// `WITH x AS (DELETE FROM t RETURNING *) SELECT * FROM x` -- is still caught. +var writeKeywordRe = regexp.MustCompile(`(?i)\b(insert|update|delete|drop|alter|create|truncate|grant|revoke|replace|merge|call|lock|unlock|set|begin|commit|rollback|copy|vacuum|analyze|reindex|comment|into\s+outfile)\b`) + // validateReadOnlySQL rejects anything but a single SELECT/WITH query, // matching the read-only guard cloudsql.ValidateReadOnlySQL provides for // its own Execute SQL feature (not shared package-to-package since the @@ -32,6 +39,9 @@ func validateReadOnlySQL(stmt string) error { if !strings.HasPrefix(lower, "select") && !strings.HasPrefix(lower, "with") { return fmt.Errorf("only SELECT/WITH statements are allowed") } + if writeKeywordRe.MatchString(lower) { + return fmt.Errorf("statement contains a disallowed write keyword") + } return nil } diff --git a/internal/services/spanner/api_test.go b/internal/services/spanner/api_test.go new file mode 100644 index 0000000..941495f --- /dev/null +++ b/internal/services/spanner/api_test.go @@ -0,0 +1,105 @@ +package spanner + +import ( + "testing" +) + +func TestValidateReadOnlySQL(t *testing.T) { + tests := []struct { + name string + stmt string + wantErr bool + }{ + { + name: "valid SELECT", + stmt: "SELECT * FROM Users", + wantErr: false, + }, + { + name: "valid SELECT lower", + stmt: "select * from Users", + wantErr: false, + }, + { + name: "valid WITH", + stmt: "WITH u AS (SELECT * FROM Users) SELECT * FROM u", + wantErr: false, + }, + { + name: "empty statement", + stmt: "", + wantErr: true, + }, + { + name: "only whitespace", + stmt: " \t\n ", + wantErr: true, + }, + { + name: "multiple statements separated by semicolon", + stmt: "SELECT * FROM Users; SELECT * FROM Accounts", + wantErr: true, + }, + { + name: "trailing semicolon allowed", + stmt: "SELECT * FROM Users;", + wantErr: false, + }, + { + name: "starts with UPDATE", + stmt: "UPDATE Users SET name = 'Bob' WHERE id = 1", + wantErr: true, + }, + { + name: "starts with DELETE", + stmt: "DELETE FROM Users WHERE id = 1", + wantErr: true, + }, + { + name: "starts with INSERT", + stmt: "INSERT INTO Users (id, name) VALUES (1, 'Bob')", + wantErr: true, + }, + { + name: "WITH containing UPDATE", + stmt: "WITH u AS (UPDATE Users SET name = 'Bob' RETURNING *) SELECT * FROM u", + wantErr: true, + }, + { + name: "SELECT with DELETE keyword", + stmt: "SELECT * FROM Users WHERE id = 1; DELETE FROM Users", + wantErr: true, // caught by semicolon check, but tests the intent + }, + { + name: "SELECT containing write keyword but not as distinct token", + // this should fail because `drop` is not a distinct word? No, writeKeywordRe matches \bdrop\b + // let's test a word that *contains* drop, like `dropbox` + stmt: "SELECT dropbox_id FROM Users", + wantErr: false, + }, + { + name: "SELECT with write keyword as distinct token", + stmt: "SELECT drop FROM Users", // e.g. a column named drop, unfortunately rejected but better safe than sorry + wantErr: true, + }, + { + name: "WITH containing DELETE", + stmt: "WITH x AS (DELETE FROM t RETURNING *) SELECT * FROM x", + wantErr: true, + }, + { + name: "WITH containing INSERT", + stmt: "WITH x AS (INSERT INTO t (id) VALUES (1) RETURNING *) SELECT * FROM x", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateReadOnlySQL(tt.stmt) + if (err != nil) != tt.wantErr { + t.Errorf("validateReadOnlySQL() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} From 14d8be1706422336b41f087992d7a1313231ddd8 Mon Sep 17 00:00:00 2001 From: hashkrish <29514440+hashkrish@users.noreply.github.com> Date: Mon, 19 Oct 2026 14:28:57 +0000 Subject: [PATCH 5/7] perf(cloudbuild): pre-allocate slice capacity in splitPath Pre-allocates the `parts` slice in `splitPath` using `strings.Count(s, "/") + 1` to establish the exact capacity needed. This avoids dynamic memory allocations when appending to the slice within the loop. From d57e11093df033dcb9abfd8cb187958b7d29d39d Mon Sep 17 00:00:00 2001 From: hashkrish <29514440+hashkrish@users.noreply.github.com> Date: Mon, 19 Oct 2026 14:45:28 +0000 Subject: [PATCH 6/7] perf(cloudbuild): pre-allocate slice capacity in splitPath Pre-allocates the `parts` slice in `splitPath` using `strings.Count(s, "/") + 1` to establish the exact capacity needed. This avoids dynamic memory allocations when appending to the slice within the loop. From 2bf1886b721deb70fb3e0ba529f374214bb2d79d Mon Sep 17 00:00:00 2001 From: hashkrish <29514440+hashkrish@users.noreply.github.com> Date: Mon, 19 Oct 2026 15:19:15 +0000 Subject: [PATCH 7/7] perf(cloudbuild): pre-allocate slice capacity in splitPath Pre-allocates the `parts` slice in `splitPath` using `strings.Count(s, "/") + 1` to establish the exact capacity needed. This avoids dynamic memory allocations when appending to the slice within the loop.