From e8f3b9c8f2fc756419e86e2ccc145a2a7fa6b97c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:12:10 -0800 Subject: [PATCH 1/6] chore(deps): bump axios from 1.13.4 to 1.13.5 in /docs/en/samples/pre_post_processing/js/langchain (#2510) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [axios](https://github.com/axios/axios) from 1.13.4 to 1.13.5.
Release notes

Sourced from axios's releases.

v1.13.5

Release 1.13.5

Highlights

Changes

Security

Fixes

Features / Improvements

Documentation

CI / Maintenance

New Contributors

Full Changelog: https://github.com/axios/axios/compare/v1.13.4...v1.13.5

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=axios&package-manager=npm_and_yarn&previous-version=1.13.4&new-version=1.13.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/googleapis/genai-toolbox/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../js/langchain/package-lock.json | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/docs/en/samples/pre_post_processing/js/langchain/package-lock.json b/docs/en/samples/pre_post_processing/js/langchain/package-lock.json index 8eed2a79ea8..27ed1a7601e 100644 --- a/docs/en/samples/pre_post_processing/js/langchain/package-lock.json +++ b/docs/en/samples/pre_post_processing/js/langchain/package-lock.json @@ -217,13 +217,13 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz", - "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==", + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", + "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, @@ -1598,17 +1598,6 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", - "license": "ISC", - "optional": true, - "peer": true, - "peerDependencies": { - "zod": "^3.25 || ^4" - } } } } From 276cf604a2bb41861639ed6881557e38dd97a614 Mon Sep 17 00:00:00 2001 From: Benny Magid <62776247+bennymagid@users.noreply.github.com> Date: Wed, 18 Feb 2026 15:07:40 -0500 Subject: [PATCH 2/6] feat(ui): make tool list panel resizable (#2253) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Add draggable resize handle to tool list panel with min/max width constraints, visual feedback, and localStorage persistence. ## PR Checklist > Thank you for opening a Pull Request! Before submitting your PR, there are a > few things you can do to make sure it goes smoothly: - [ ] Make sure you reviewed [CONTRIBUTING.md](https://github.com/googleapis/genai-toolbox/blob/main/CONTRIBUTING.md) - [ ] Make sure to open an issue as a [bug/issue](https://github.com/googleapis/genai-toolbox/issues/new/choose) before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea - [ ] Ensure the tests and linter pass - [ ] Code coverage does not decrease (if any source code was changed) - [ ] Appropriate docs were updated (if necessary) - [ ] Make sure to add `!` if this involve a breaking change 🛠️ Fixes #1729 --------- Co-authored-by: Wenxin Du <117315983+duwenxin99@users.noreply.github.com> --- internal/server/static/css/style.css | 29 ++++++- internal/server/static/js/resize.js | 116 +++++++++++++++++++++++++++ internal/server/static/tools.html | 10 ++- internal/server/static/toolsets.html | 8 +- 4 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 internal/server/static/js/resize.js diff --git a/internal/server/static/css/style.css b/internal/server/static/css/style.css index 47d8a35974b..b0c1968c1b6 100644 --- a/internal/server/static/css/style.css +++ b/internal/server/static/css/style.css @@ -87,8 +87,29 @@ body { display: flex; flex-direction: column; padding: 15px; - align-items: center; + align-items: stretch; position: relative; + min-width: 200px; + max-width: 50vw; + overflow: visible; + box-sizing: border-box; +} + +.resize-handle { + position: absolute; + right: -2px; + top: 0; + bottom: 0; + width: 4px; + cursor: ew-resize; + background-color: transparent; + z-index: 10; + transition: background-color 0.2s ease; +} + +.resize-handle:hover, +.resize-handle.active { + background-color: var(--toolbox-blue); } .nav-logo { @@ -626,10 +647,13 @@ body { .search-container { display: flex; width: 100%; + min-width: 0; margin-bottom: 15px; + box-sizing: border-box; #toolset-search-input { - flex-grow: 1; + flex: 1; + min-width: 0; padding: 10px 12px; border: 1px solid #ccc; border-radius: 20px 0 0 20px; @@ -637,6 +661,7 @@ body { font-family: inherit; font-size: 0.9em; color: var(--text-primary-gray); + box-sizing: border-box; &:focus { outline: none; diff --git a/internal/server/static/js/resize.js b/internal/server/static/js/resize.js new file mode 100644 index 00000000000..f2ff490fe33 --- /dev/null +++ b/internal/server/static/js/resize.js @@ -0,0 +1,116 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const STORAGE_KEY = 'toolbox-second-nav-width'; +const DEFAULT_WIDTH = 250; +const MIN_WIDTH = 200; +const MAX_WIDTH_PERCENT = 50; + +/** + * Creates and attaches a resize handle to the second navigation panel + */ +export function initializeResize() { + const secondNav = document.querySelector('.second-nav'); + if (!secondNav) { + return; + } + + // Create resize handle + const resizeHandle = document.createElement('div'); + resizeHandle.className = 'resize-handle'; + resizeHandle.setAttribute('aria-label', 'Resize panel'); + secondNav.appendChild(resizeHandle); + + // Load saved width or use default + let initialWidth = DEFAULT_WIDTH; + try { + const savedWidth = localStorage.getItem(STORAGE_KEY); + if (savedWidth) { + const parsed = parseInt(savedWidth, 10); + if (!isNaN(parsed) && parsed >= MIN_WIDTH) { + initialWidth = parsed; + } + } + } catch (e) { + // localStorage may be unavailable in private browsing mode + console.warn('Failed to load saved panel width:', e); + } + setPanelWidth(secondNav, initialWidth); + + // Setup resize functionality + let startX = 0; + let startWidth = 0; + + const onMouseMove = (e) => { + const deltaX = e.clientX - startX; + const newWidth = startWidth + deltaX; + const maxWidth = (window.innerWidth * MAX_WIDTH_PERCENT) / 100; + + const clampedWidth = Math.max(MIN_WIDTH, Math.min(newWidth, maxWidth)); + setPanelWidth(secondNav, clampedWidth); + }; + + const onMouseUp = () => { + document.removeEventListener('mousemove', onMouseMove); + document.removeEventListener('mouseup', onMouseUp); + + resizeHandle.classList.remove('active'); + document.body.style.cursor = ''; + document.body.style.userSelect = ''; + + // Save width to localStorage + try { + localStorage.setItem(STORAGE_KEY, secondNav.offsetWidth.toString()); + } catch (e) { + // localStorage may be unavailable in private browsing mode + console.warn('Failed to save panel width:', e); + } + }; + + resizeHandle.addEventListener('mousedown', (e) => { + startX = e.clientX; + startWidth = secondNav.offsetWidth; + resizeHandle.classList.add('active'); + document.body.style.cursor = 'ew-resize'; + document.body.style.userSelect = 'none'; + e.preventDefault(); + + document.addEventListener('mousemove', onMouseMove); + document.addEventListener('mouseup', onMouseUp); + }); + + // Handle window resize to enforce max width + window.addEventListener('resize', () => { + const currentWidth = secondNav.offsetWidth; + const maxWidth = (window.innerWidth * MAX_WIDTH_PERCENT) / 100; + + if (currentWidth > maxWidth) { + setPanelWidth(secondNav, maxWidth); + try { + localStorage.setItem(STORAGE_KEY, maxWidth.toString()); + } catch (e) { + // localStorage may be unavailable in private browsing mode + console.warn('Failed to save panel width:', e); + } + } + }); +} + +/** + * Sets the width of the panel and updates flex property + */ +function setPanelWidth(panel, width) { + panel.style.flex = `0 0 ${width}px`; +} + diff --git a/internal/server/static/tools.html b/internal/server/static/tools.html index c618c5111b4..f461cc80ad5 100644 --- a/internal/server/static/tools.html +++ b/internal/server/static/tools.html @@ -22,12 +22,16 @@ - diff --git a/internal/server/static/toolsets.html b/internal/server/static/toolsets.html index adcd5fdfde8..84907222603 100644 --- a/internal/server/static/toolsets.html +++ b/internal/server/static/toolsets.html @@ -29,12 +29,16 @@ - From 57b77bca09ce6ee260bd64af9be5fcef593e9acb Mon Sep 17 00:00:00 2001 From: Mark L <73659136+liuxiaopai-ai@users.noreply.github.com> Date: Thu, 19 Feb 2026 04:35:44 +0800 Subject: [PATCH 3/6] feat(sources/postgres): add configurable pgx query execution mode (#2477) Adds optional `queryExecMode` to postgres source config, allowing users to set pgx `DefaultQueryExecMode` for compatibility with external connection poolers (e.g. transaction pooling). Supported values: - cache_statement (default) - cache_describe - describe_exec - exec - simple_protocol Implementation details: - parse DSN with `pgxpool.ParseConfig` - map `queryExecMode` to `pgx.QueryExecMode*` - create pool via `pgxpool.NewWithConfig` - validate config using `oneof` tag - document new field in postgres source docs - add parser/validation tests Tests run: `go test -v ./internal/sources/postgres -count=1 -vet=off` Refs #2385 --------- Co-authored-by: Molt (OpenClaw) Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> Co-authored-by: Yuan Teoh --- docs/en/resources/sources/postgres.md | 1 + internal/sources/postgres/postgres.go | 52 ++++++++++++---- internal/sources/postgres/postgres_test.go | 71 ++++++++++++++++++++++ 3 files changed, 113 insertions(+), 11 deletions(-) diff --git a/docs/en/resources/sources/postgres.md b/docs/en/resources/sources/postgres.md index ed7c77aeee2..c42d8dca644 100644 --- a/docs/en/resources/sources/postgres.md +++ b/docs/en/resources/sources/postgres.md @@ -133,3 +133,4 @@ instead of hardcoding your secrets into the configuration file. | user | string | true | Name of the Postgres user to connect as (e.g. "my-pg-user"). | | password | string | true | Password of the Postgres user (e.g. "my-password"). | | queryParams | map[string]string | false | Raw query to be added to the db connection string. | +| queryExecMode | string | false | pgx query execution mode. Valid values: `cache_statement` (default), `cache_describe`, `describe_exec`, `exec`, `simple_protocol`. Useful with connection poolers that don't support prepared statement caching. | diff --git a/internal/sources/postgres/postgres.go b/internal/sources/postgres/postgres.go index 65d7a17b75d..b2ed44a95d4 100644 --- a/internal/sources/postgres/postgres.go +++ b/internal/sources/postgres/postgres.go @@ -24,6 +24,7 @@ import ( "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/orderedmap" + "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" "go.opentelemetry.io/otel/trace" ) @@ -48,14 +49,15 @@ func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources } type Config struct { - Name string `yaml:"name" validate:"required"` - Type string `yaml:"type" validate:"required"` - Host string `yaml:"host" validate:"required"` - Port string `yaml:"port" validate:"required"` - User string `yaml:"user" validate:"required"` - Password string `yaml:"password" validate:"required"` - Database string `yaml:"database" validate:"required"` - QueryParams map[string]string `yaml:"queryParams"` + Name string `yaml:"name" validate:"required"` + Type string `yaml:"type" validate:"required"` + Host string `yaml:"host" validate:"required"` + Port string `yaml:"port" validate:"required"` + User string `yaml:"user" validate:"required"` + Password string `yaml:"password" validate:"required"` + Database string `yaml:"database" validate:"required"` + QueryParams map[string]string `yaml:"queryParams"` + QueryExecMode string `yaml:"queryExecMode" validate:"omitempty,oneof=cache_statement cache_describe describe_exec exec simple_protocol"` } func (r Config) SourceConfigType() string { @@ -63,7 +65,7 @@ func (r Config) SourceConfigType() string { } func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.Source, error) { - pool, err := initPostgresConnectionPool(ctx, tracer, r.Name, r.Host, r.Port, r.User, r.Password, r.Database, r.QueryParams) + pool, err := initPostgresConnectionPool(ctx, tracer, r.Name, r.Host, r.Port, r.User, r.Password, r.Database, r.QueryParams, r.QueryExecMode) if err != nil { return nil, fmt.Errorf("unable to create pool: %w", err) } @@ -126,7 +128,7 @@ func (s *Source) RunSQL(ctx context.Context, statement string, params []any) (an return out, nil } -func initPostgresConnectionPool(ctx context.Context, tracer trace.Tracer, name, host, port, user, pass, dbname string, queryParams map[string]string) (*pgxpool.Pool, error) { +func initPostgresConnectionPool(ctx context.Context, tracer trace.Tracer, name, host, port, user, pass, dbname string, queryParams map[string]string, queryExecMode string) (*pgxpool.Pool, error) { //nolint:all // Reassigned ctx ctx, span := sources.InitConnectionSpan(ctx, tracer, SourceType, name) defer span.End() @@ -150,7 +152,18 @@ func initPostgresConnectionPool(ctx context.Context, tracer trace.Tracer, name, Path: dbname, RawQuery: ConvertParamMapToRawQuery(queryParams), } - pool, err := pgxpool.New(ctx, url.String()) + config, err := pgxpool.ParseConfig(url.String()) + if err != nil { + return nil, fmt.Errorf("unable to parse connection uri: %w", err) + } + + execMode, err := ParseQueryExecMode(queryExecMode) + if err != nil { + return nil, err + } + config.ConnConfig.DefaultQueryExecMode = execMode + + pool, err := pgxpool.NewWithConfig(ctx, config) if err != nil { return nil, fmt.Errorf("unable to create connection pool: %w", err) } @@ -165,3 +178,20 @@ func ConvertParamMapToRawQuery(queryParams map[string]string) string { } return strings.Join(queryArray, "&") } + +func ParseQueryExecMode(queryExecMode string) (pgx.QueryExecMode, error) { + switch queryExecMode { + case "", "cache_statement": + return pgx.QueryExecModeCacheStatement, nil + case "cache_describe": + return pgx.QueryExecModeCacheDescribe, nil + case "describe_exec": + return pgx.QueryExecModeDescribeExec, nil + case "exec": + return pgx.QueryExecModeExec, nil + case "simple_protocol": + return pgx.QueryExecModeSimpleProtocol, nil + default: + return 0, fmt.Errorf("invalid queryExecMode %q: must be one of %q, %q, %q, %q, or %q", queryExecMode, "cache_statement", "cache_describe", "describe_exec", "exec", "simple_protocol") + } +} diff --git a/internal/sources/postgres/postgres_test.go b/internal/sources/postgres/postgres_test.go index 4bcde0420e5..0441f356a3d 100644 --- a/internal/sources/postgres/postgres_test.go +++ b/internal/sources/postgres/postgres_test.go @@ -25,6 +25,7 @@ import ( "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources/postgres" "github.com/googleapis/genai-toolbox/internal/testutils" + "github.com/jackc/pgx/v5" ) func TestParseFromYamlPostgres(t *testing.T) { @@ -88,6 +89,32 @@ func TestParseFromYamlPostgres(t *testing.T) { }, }, }, + { + desc: "example with query exec mode", + in: ` + kind: sources + name: my-pg-instance + type: postgres + host: my-host + port: my-port + database: my_db + user: my_user + password: my_pass + queryExecMode: simple_protocol + `, + want: map[string]sources.SourceConfig{ + "my-pg-instance": postgres.Config{ + Name: "my-pg-instance", + Type: postgres.SourceType, + Host: "my-host", + Port: "my-port", + Database: "my_db", + User: "my_user", + Password: "my_pass", + QueryExecMode: "simple_protocol", + }, + }, + }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { @@ -137,6 +164,21 @@ func TestFailParseFromYaml(t *testing.T) { `, err: "error unmarshaling sources: unable to parse source \"my-pg-instance\" as \"postgres\": Key: 'Config.Password' Error:Field validation for 'Password' failed on the 'required' tag", }, + { + desc: "invalid query exec mode", + in: ` + kind: sources + name: my-pg-instance + type: postgres + host: my-host + port: my-port + database: my_db + user: my_user + password: my_pass + queryExecMode: invalid_mode + `, + err: "error unmarshaling sources: unable to parse source \"my-pg-instance\" as \"postgres\": [6:16] Key: 'Config.QueryExecMode' Error:Field validation for 'QueryExecMode' failed on the 'oneof' tag\n 3 | name: my-pg-instance\n 4 | password: my_pass\n 5 | port: my-port\n> 6 | queryExecMode: invalid_mode\n ^\n 7 | type: postgres\n 8 | user: my_user", + }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { @@ -193,3 +235,32 @@ func TestConvertParamMapToRawQuery(t *testing.T) { }) } } + +func TestParseQueryExecMode(t *testing.T) { + tcs := []struct { + desc string + in string + want pgx.QueryExecMode + wantErr bool + }{ + {desc: "empty (default)", in: "", want: pgx.QueryExecModeCacheStatement}, + {desc: "cache_statement", in: "cache_statement", want: pgx.QueryExecModeCacheStatement}, + {desc: "cache_describe", in: "cache_describe", want: pgx.QueryExecModeCacheDescribe}, + {desc: "describe_exec", in: "describe_exec", want: pgx.QueryExecModeDescribeExec}, + {desc: "exec", in: "exec", want: pgx.QueryExecModeExec}, + {desc: "simple_protocol", in: "simple_protocol", want: pgx.QueryExecModeSimpleProtocol}, + {desc: "invalid mode", in: "invalid_mode", wantErr: true}, + } + + for _, tc := range tcs { + t.Run(tc.desc, func(t *testing.T) { + got, err := postgres.ParseQueryExecMode(tc.in) + if (err != nil) != tc.wantErr { + t.Fatalf("parseQueryExecMode() error = %v, wantErr %v", err, tc.wantErr) + } + if !tc.wantErr && got != tc.want { + t.Errorf("parseQueryExecMode() = %v, want %v", got, tc.want) + } + }) + } +} From 7a6d0c12e936efb3ba53dee418898b6b9258226e Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Wed, 18 Feb 2026 21:31:15 +0000 Subject: [PATCH 4/6] chore(deps): update peter-evans/create-or-update-comment action to v5 (#2500) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [peter-evans/create-or-update-comment](https://redirect.github.com/peter-evans/create-or-update-comment) | action | major | `v4` → `v5` | --- ### Release Notes
peter-evans/create-or-update-comment (peter-evans/create-or-update-comment) ### [`v5`](https://redirect.github.com/peter-evans/create-or-update-comment/compare/v4...v5) [Compare Source](https://redirect.github.com/peter-evans/create-or-update-comment/compare/v4...v5)
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/googleapis/genai-toolbox). Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> --- .github/workflows/link_checker.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/link_checker.yaml b/.github/workflows/link_checker.yaml index 308d482ca17..b08757dc628 100644 --- a/.github/workflows/link_checker.yaml +++ b/.github/workflows/link_checker.yaml @@ -114,7 +114,7 @@ jobs: - name: Create PR Comment if: env.HAS_CHANGES == 'true' && steps.lychee-check.outcome == 'failure' - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4 + uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5 with: comment-id: ${{ steps.find-comment.outputs.comment-id }} issue-number: ${{ github.event.pull_request.number }} From 3684efd51277869de4a7e934b3cec3f84215a90c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 15:41:29 -0800 Subject: [PATCH 5/6] chore(deps): bump ajv from 8.17.1 to 8.18.0 in /docs/en/getting-started/quickstart/js/genkit (#2487) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [ajv](https://github.com/ajv-validator/ajv) from 8.17.1 to 8.18.0.
Release notes

Sourced from ajv's releases.

v8.18.0

What's Changed

New Contributors

Full Changelog: https://github.com/ajv-validator/ajv/compare/v8.17.1...v8.18.0

Commits
  • 142ce84 8.18.0
  • 720a23f fix(pattern): use configured RegExp engine with $data keyword to mitigate ReD...
  • 82735a1 fix: typos in schema-language.md (#2507)
  • b17ec32 fix: small grammatical error in managing-schemas.md (#2508)
  • 69568d0 fix: #2482 Infinity and NaN serialise to null (#2487)
  • f06766f feat: allow tree-shaking by adding ``"sideEffects": falsetopackage.json` ...
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ajv&package-manager=npm_and_yarn&previous-version=8.17.1&new-version=8.18.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/googleapis/genai-toolbox/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> --- .../getting-started/quickstart/js/genkit/package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/en/getting-started/quickstart/js/genkit/package-lock.json b/docs/en/getting-started/quickstart/js/genkit/package-lock.json index cdb5744245c..436ecf3b6f6 100644 --- a/docs/en/getting-started/quickstart/js/genkit/package-lock.json +++ b/docs/en/getting-started/quickstart/js/genkit/package-lock.json @@ -3231,9 +3231,10 @@ } }, "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", From d6af2907fd2dca5a6751d7d42090dd7ebb8ccd48 Mon Sep 17 00:00:00 2001 From: Yaroslav Date: Thu, 19 Feb 2026 01:11:05 +0100 Subject: [PATCH 6/6] feat(sources/redis): add TLS support for Redis connections (#2432) ## Summary - Add `tlsEnabled` config field to Redis source for enabling TLS on connections - Apply TLS config to both cluster and standalone Redis clients - Add test case for TLS config parsing and update docs This is needed for cloud-managed Redis services like AWS ElastiCache (Redis OSS) that require TLS for secure connections. ## Example config (tools.yaml) ```yaml sources: leadsforge-redis: kind: redis address: - ${REDIS_HOST} clusterEnabled: true tls: enabled: true insecureSkipVerify: true ``` --------- Co-authored-by: Yuan Teoh <45984206+Yuan325@users.noreply.github.com> --- docs/en/resources/sources/redis.md | 31 ++++++++++++++++----------- internal/sources/redis/redis.go | 32 +++++++++++++++++++++------- internal/sources/redis/redis_test.go | 7 ++++++ 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/docs/en/resources/sources/redis.md b/docs/en/resources/sources/redis.md index 51c8cfde00e..62ca36be704 100644 --- a/docs/en/resources/sources/redis.md +++ b/docs/en/resources/sources/redis.md @@ -4,8 +4,8 @@ linkTitle: "Redis" type: docs weight: 1 description: > - Redis is a in-memory data structure store. - + Redis is a in-memory data structure store. + --- ## About @@ -44,6 +44,9 @@ password: ${MY_AUTH_STRING} # Omit this field if you don't have a password. # database: 0 # clusterEnabled: false # useGCPIAM: false +# tls: +# enabled: false +# insecureSkipVerify: false ``` {{< notice tip >}} @@ -61,7 +64,7 @@ Here is an example tools.yaml config with [AUTH][auth] enabled: ```yaml kind: sources name: my-redis-cluster-instance -type: memorystore-redis +type: redis address: - 127.0.0.1:6379 password: ${MY_AUTH_STRING} @@ -78,7 +81,7 @@ using IAM authentication: ```yaml kind: sources name: my-redis-cluster-instance -type: memorystore-redis +type: redis address: - 127.0.0.1:6379 useGCPIAM: true @@ -89,14 +92,16 @@ clusterEnabled: true ## Reference -| **field** | **type** | **required** | **description** | -|----------------|:--------:|:------------:|---------------------------------------------------------------------------------------------------------------------------------| -| type | string | true | Must be "memorystore-redis". | -| address | string | true | Primary endpoint for the Memorystore Redis instance to connect to. | -| username | string | false | If you are using a non-default user, specify the user name here. If you are using Memorystore for Redis, leave this field blank | -| password | string | false | If you have [Redis AUTH][auth] enabled, specify the AUTH string here | -| database | int | false | The Redis database to connect to. Not applicable for cluster enabled instances. The default database is `0`. | -| clusterEnabled | bool | false | Set it to `true` if using a Redis Cluster instance. Defaults to `false`. | -| useGCPIAM | string | false | Set it to `true` if you are using GCP's IAM authentication. Defaults to `false`. | +| **field** | **type** | **required** | **description** | +|------------------------|:--------:|:------------:|-----------------------------------------------------------------------------------------------------------------------------------------------| +| type | string | true | Must be "redis". | +| address | string | true | Primary endpoint for the Memorystore Redis instance to connect to. | +| username | string | false | If you are using a non-default user, specify the user name here. If you are using Memorystore for Redis, leave this field blank | +| password | string | false | If you have [Redis AUTH][auth] enabled, specify the AUTH string here | +| database | int | false | The Redis database to connect to. Not applicable for cluster enabled instances. The default database is `0`. | +| tls.enabled | bool | false | Set it to `true` to enable TLS for the Redis connection. Defaults to `false`. | +| tls.insecureSkipVerify | bool | false | Set it to `true` to skip TLS certificate verification. **Warning:** This is insecure and not recommended for production. Defaults to `false`. | +| clusterEnabled | bool | false | Set it to `true` if using a Redis Cluster instance. Defaults to `false`. | +| useGCPIAM | bool | false | Set it to `true` if you are using GCP's IAM authentication. Defaults to `false`. | [auth]: https://cloud.google.com/memorystore/docs/redis/about-redis-auth diff --git a/internal/sources/redis/redis.go b/internal/sources/redis/redis.go index e2a28c52a7e..2a0b4f81a44 100644 --- a/internal/sources/redis/redis.go +++ b/internal/sources/redis/redis.go @@ -15,6 +15,7 @@ package redis import ( "context" + "crypto/tls" "fmt" "time" @@ -44,14 +45,20 @@ func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources } type Config struct { - Name string `yaml:"name" validate:"required"` - Type string `yaml:"type" validate:"required"` - Address []string `yaml:"address" validate:"required"` - Username string `yaml:"username"` - Password string `yaml:"password"` - Database int `yaml:"database"` - UseGCPIAM bool `yaml:"useGCPIAM"` - ClusterEnabled bool `yaml:"clusterEnabled"` + Name string `yaml:"name" validate:"required"` + Type string `yaml:"type" validate:"required"` + Address []string `yaml:"address" validate:"required"` + Username string `yaml:"username"` + Password string `yaml:"password"` + Database int `yaml:"database"` + UseGCPIAM bool `yaml:"useGCPIAM"` + ClusterEnabled bool `yaml:"clusterEnabled"` + TLS TLSConfig `yaml:"tls"` +} + +type TLSConfig struct { + Enabled bool `yaml:"enabled"` + InsecureSkipVerify bool `yaml:"insecureSkipVerify"` } func (r Config) SourceConfigType() string { @@ -91,6 +98,13 @@ func initRedisClient(ctx context.Context, r Config) (RedisClient, error) { } } + var tlsConfig *tls.Config + if r.TLS.Enabled { + tlsConfig = &tls.Config{ + InsecureSkipVerify: r.TLS.InsecureSkipVerify, + } + } + var client RedisClient var err error if r.ClusterEnabled { @@ -104,6 +118,7 @@ func initRedisClient(ctx context.Context, r Config) (RedisClient, error) { CredentialsProviderContext: authFn, Username: r.Username, Password: r.Password, + TLSConfig: tlsConfig, }) err = clusterClient.ForEachShard(ctx, func(ctx context.Context, shard *redis.Client) error { return shard.Ping(ctx).Err() @@ -125,6 +140,7 @@ func initRedisClient(ctx context.Context, r Config) (RedisClient, error) { CredentialsProviderContext: authFn, Username: r.Username, Password: r.Password, + TLSConfig: tlsConfig, }) _, err = standaloneClient.Ping(ctx).Result() if err != nil { diff --git a/internal/sources/redis/redis_test.go b/internal/sources/redis/redis_test.go index 63e2d01beec..ce44c53afbf 100644 --- a/internal/sources/redis/redis_test.go +++ b/internal/sources/redis/redis_test.go @@ -63,6 +63,9 @@ func TestParseFromYamlRedis(t *testing.T) { database: 1 useGCPIAM: true clusterEnabled: true + tls: + enabled: true + insecureSkipVerify: true `, want: map[string]sources.SourceConfig{ "my-redis-instance": redis.Config{ @@ -73,6 +76,10 @@ func TestParseFromYamlRedis(t *testing.T) { Database: 1, ClusterEnabled: true, UseGCPIAM: true, + TLS: redis.TLSConfig{ + Enabled: true, + InsecureSkipVerify: true, + }, }, }, },