From 70cc2152e8c904f1c7bcf4b10ea895c20150429c Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Mon, 3 Nov 2025 14:08:22 -0800 Subject: [PATCH 01/12] backend changes to support PDC --- pkg/github/client/client.go | 25 +++++++++++++++---------- pkg/github/datasource.go | 5 +++-- pkg/plugin/instance.go | 16 +++++++++++----- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/pkg/github/client/client.go b/pkg/github/client/client.go index 926ede72..d55c590b 100644 --- a/pkg/github/client/client.go +++ b/pkg/github/client/client.go @@ -53,28 +53,27 @@ var runnerPerMinuteRate = map[string]float64{ } // New instantiates a new GitHub API client. -func New(ctx context.Context, settings models.Settings) (*Client, error) { +func New(ctx context.Context, settings models.Settings, opts httpclient.Options) (*Client, error) { if settings.SelectedAuthType == models.AuthTypeGithubApp { - return createAppClient(settings) + return createAppClient(settings, opts) } if settings.SelectedAuthType == models.AuthTypePAT { - return createAccessTokenClient(ctx, settings) + return createAccessTokenClient(ctx, settings, opts) } return nil, backend.DownstreamError(errors.New("access token or app token are required")) } -func createAppClient(settings models.Settings) (*Client, error) { - transport, err := httpclient.GetDefaultTransport() +func createAppClient(settings models.Settings, opts httpclient.Options) (*Client, error) { + httpClient, err := httpclient.New(opts) if err != nil { - return nil, backend.DownstreamError(errors.New("error: http.DefaultTransport is not of type *http.Transport")) + return nil, backend.DownstreamErrorf("error creating http client: %w", err) } - itr, err := ghinstallation.New(transport, settings.AppIdInt64, settings.InstallationIdInt64, []byte(settings.PrivateKey)) + + itr, err := ghinstallation.New(httpClient.Transport, settings.AppIdInt64, settings.InstallationIdInt64, []byte(settings.PrivateKey)) if err != nil { return nil, backend.DownstreamError(errors.New("error creating token source")) } - httpClient := &http.Client{Transport: itr} - if settings.GitHubURL == "" { return &Client{ restClient: googlegithub.NewClient(httpClient), @@ -84,15 +83,21 @@ func createAppClient(settings models.Settings) (*Client, error) { itr.BaseURL = fmt.Sprintf("%s/api/v3", settings.GitHubURL) + httpClient.Transport = itr return useGitHubEnterprise(httpClient, settings) } -func createAccessTokenClient(ctx context.Context, settings models.Settings) (*Client, error) { +func createAccessTokenClient(ctx context.Context, settings models.Settings, opts httpclient.Options) (*Client, error) { src := oauth2.StaticTokenSource( &oauth2.Token{AccessToken: settings.AccessToken}, ) + transport, err := httpclient.GetTransport(opts) + if err != nil { + return nil, backend.DownstreamErrorf("error getting the transport: %w", err) + } httpClient := oauth2.NewClient(ctx, src) + httpClient.Transport = transport if settings.GitHubURL == "" { return &Client{ diff --git a/pkg/github/datasource.go b/pkg/github/datasource.go index bd8a4196..abe2a1d2 100644 --- a/pkg/github/datasource.go +++ b/pkg/github/datasource.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" "github.com/grafana/github-datasource/pkg/dfutil" githubclient "github.com/grafana/github-datasource/pkg/github/client" @@ -244,8 +245,8 @@ func (d *Datasource) QueryData(ctx context.Context, req *backend.QueryDataReques } // NewDatasource creates a new datasource for handling queries -func NewDatasource(ctx context.Context, settings models.Settings) (*Datasource, error) { - client, err := githubclient.New(ctx, settings) +func NewDatasource(ctx context.Context, settings models.Settings, opts httpclient.Options) (*Datasource, error) { + client, err := githubclient.New(ctx, settings, opts) if err != nil { return nil, err } diff --git a/pkg/plugin/instance.go b/pkg/plugin/instance.go index 753defdf..1ae92d0a 100644 --- a/pkg/plugin/instance.go +++ b/pkg/plugin/instance.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" "github.com/grafana/github-datasource/pkg/github" @@ -12,8 +13,8 @@ import ( ) // NewGitHubInstance creates a new GitHubInstance using the settings to determine if things like the Caching Wrapper should be enabled -func NewGitHubInstance(ctx context.Context, settings models.Settings) (instancemgmt.Instance, error) { - gh, err := github.NewDatasource(ctx, settings) +func NewGitHubInstance(ctx context.Context, settings models.Settings, opts httpclient.Options) (instancemgmt.Instance, error) { + gh, err := github.NewDatasource(ctx, settings, opts) if err != nil { return nil, err } @@ -28,15 +29,20 @@ func NewGitHubInstance(ctx context.Context, settings models.Settings) (instancem } // NewDataSourceInstance creates a new instance -func NewDataSourceInstance(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { - datasourceSettings, err := models.LoadSettings(settings) +func NewDataSourceInstance(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { + opts, err := settings.HTTPClientOptions(ctx) if err != nil { return nil, err } + datasourceSettings, err := models.LoadSettings(settings) + if err != nil { + return nil, err + } + datasourceSettings.CachingEnabled = true - instance, err := NewGitHubInstance(context.Background(), datasourceSettings) + instance, err := NewGitHubInstance(context.Background(), datasourceSettings, opts) if err != nil { return instance, fmt.Errorf("instantiating github instance: %w", err) } From d41b38fe6982599666cc4b2f418aa6fa9a9868d8 Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Mon, 3 Nov 2025 14:08:35 -0800 Subject: [PATCH 02/12] frontend changes to support PDC --- src/views/ConfigEditor.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/views/ConfigEditor.tsx b/src/views/ConfigEditor.tsx index a8eda606..b097a251 100644 --- a/src/views/ConfigEditor.tsx +++ b/src/views/ConfigEditor.tsx @@ -1,6 +1,6 @@ import React, { ChangeEvent, useCallback, useEffect, useState } from 'react'; import { css } from '@emotion/css'; -import { Collapse, Field, Input, Label, RadioButtonGroup, SecretInput, SecretTextArea, useStyles2 } from '@grafana/ui'; +import { Collapse, Field, Input, Label, RadioButtonGroup, SecretInput, SecretTextArea, SecureSocksProxySettings, useStyles2 } from '@grafana/ui'; import { ConfigSection, DataSourceDescription } from '@grafana/plugin-ui'; import { Divider } from 'components/Divider'; import { components as selectors } from '../components/selectors'; @@ -12,6 +12,8 @@ import { type SelectableValue, } from '@grafana/data'; import type { GitHubAuthType, GitHubLicenseType, GitHubDataSourceOptions, GitHubSecureJsonData } from 'types/config'; +import { config } from '@grafana/runtime'; +import { gte } from 'semver'; export type ConfigEditorProps = DataSourcePluginOptionsEditorProps; @@ -196,7 +198,11 @@ const ConfigEditor = (props: ConfigEditorProps) => { )} - + { + config.secureSocksDSProxyEnabled && gte(config.buildInfo.version, '10.0.0') && ( + + ) + } From 25309a18d121d9766d0e3dda262954a2a8e841ad Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Mon, 3 Nov 2025 14:08:47 -0800 Subject: [PATCH 03/12] frontend changes to support PDC pt. 2 --- src/types/config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/config.ts b/src/types/config.ts index c76f75dc..46902a1a 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -10,6 +10,7 @@ export type GitHubDataSourceOptions = { selectedAuthType?: GitHubAuthType; appId?: string; installationId?: string; + enableSecureSocksProxy?: boolean } & DataSourceJsonData; export type GitHubSecureJsonDataKeys = From 272e4f928eedbb5d1fb9940e53e80ffeb5bda774 Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Fri, 7 Nov 2025 10:07:07 -0600 Subject: [PATCH 04/12] move transport override earlier for app client and change the way the transport is overridden for access token client --- pkg/github/client/client.go | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/pkg/github/client/client.go b/pkg/github/client/client.go index d55c590b..76d5fbc7 100644 --- a/pkg/github/client/client.go +++ b/pkg/github/client/client.go @@ -13,6 +13,7 @@ import ( googlegithub "github.com/google/go-github/v72/github" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" + "github.com/grafana/grafana-plugin-sdk-go/backend/proxy" "github.com/influxdata/tdigest" "github.com/shurcooL/githubv4" "golang.org/x/oauth2" @@ -74,6 +75,7 @@ func createAppClient(settings models.Settings, opts httpclient.Options) (*Client return nil, backend.DownstreamError(errors.New("error creating token source")) } + httpClient.Transport = itr if settings.GitHubURL == "" { return &Client{ restClient: googlegithub.NewClient(httpClient), @@ -83,7 +85,6 @@ func createAppClient(settings models.Settings, opts httpclient.Options) (*Client itr.BaseURL = fmt.Sprintf("%s/api/v3", settings.GitHubURL) - httpClient.Transport = itr return useGitHubEnterprise(httpClient, settings) } @@ -92,13 +93,21 @@ func createAccessTokenClient(ctx context.Context, settings models.Settings, opts &oauth2.Token{AccessToken: settings.AccessToken}, ) - transport, err := httpclient.GetTransport(opts) - if err != nil { + httpClient := oauth2.NewClient(ctx, src) + + cli := proxy.New(opts.ProxyOptions) + if cli.SecureSocksProxyEnabled() { + // only override the Transport if Secure Proxy is enabled. + transport, err := httpclient.GetTransport(opts) + if err != nil { return nil, backend.DownstreamErrorf("error getting the transport: %w", err) } - httpClient := oauth2.NewClient(ctx, src) - httpClient.Transport = transport + httpClient.Transport = &oauth2.Transport{ + Base: transport, + Source: oauth2.ReuseTokenSource(nil, src), + } + } if settings.GitHubURL == "" { return &Client{ restClient: googlegithub.NewClient(httpClient), From 34575a2215316fbdc878e5b8d35bb5029be4e86a Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Fri, 7 Nov 2025 10:07:57 -0600 Subject: [PATCH 05/12] change check for feature toggle enabled --- src/views/ConfigEditor.tsx | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/views/ConfigEditor.tsx b/src/views/ConfigEditor.tsx index b097a251..a00dafea 100644 --- a/src/views/ConfigEditor.tsx +++ b/src/views/ConfigEditor.tsx @@ -1,10 +1,21 @@ import React, { ChangeEvent, useCallback, useEffect, useState } from 'react'; import { css } from '@emotion/css'; -import { Collapse, Field, Input, Label, RadioButtonGroup, SecretInput, SecretTextArea, SecureSocksProxySettings, useStyles2 } from '@grafana/ui'; +import { + Collapse, + Field, + Input, + Label, + RadioButtonGroup, + SecretInput, + SecretTextArea, + SecureSocksProxySettings, + useStyles2, +} from '@grafana/ui'; import { ConfigSection, DataSourceDescription } from '@grafana/plugin-ui'; import { Divider } from 'components/Divider'; import { components as selectors } from '../components/selectors'; import { + FeatureToggles, onUpdateDatasourceJsonDataOption, onUpdateDatasourceSecureJsonDataOption, type DataSourcePluginOptionsEditorProps, @@ -18,6 +29,7 @@ import { gte } from 'semver'; export type ConfigEditorProps = DataSourcePluginOptionsEditorProps; const ConfigEditor = (props: ConfigEditorProps) => { + console.log('here'); const { options, onOptionsChange } = props; const { jsonData, secureJsonData, secureJsonFields } = options; const secureSettings = secureJsonData || {}; @@ -198,11 +210,9 @@ const ConfigEditor = (props: ConfigEditorProps) => { )} - { - config.secureSocksDSProxyEnabled && gte(config.buildInfo.version, '10.0.0') && ( - - ) - } + {config.featureToggles['secureSocksDSProxyEnabled' as keyof FeatureToggles] && gte(config.buildInfo.version, '10.0.0') && ( + + )} From 1d5a72e36ef1007ed44e3115a3d64611ea91881c Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Fri, 7 Nov 2025 10:09:56 -0600 Subject: [PATCH 06/12] add changeset --- .changeset/lazy-planes-reply.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/lazy-planes-reply.md diff --git a/.changeset/lazy-planes-reply.md b/.changeset/lazy-planes-reply.md new file mode 100644 index 00000000..6fa11b4e --- /dev/null +++ b/.changeset/lazy-planes-reply.md @@ -0,0 +1,5 @@ +--- +'grafana-github-datasource': minor +--- + +Enable PDC for github datasource From ec016af9ed0decb70385370f12f9f8d70e60cdec Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Mon, 10 Nov 2025 07:36:26 -0800 Subject: [PATCH 07/12] Update src/views/ConfigEditor.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Bedi --- src/views/ConfigEditor.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/views/ConfigEditor.tsx b/src/views/ConfigEditor.tsx index a00dafea..e02161be 100644 --- a/src/views/ConfigEditor.tsx +++ b/src/views/ConfigEditor.tsx @@ -29,7 +29,6 @@ import { gte } from 'semver'; export type ConfigEditorProps = DataSourcePluginOptionsEditorProps; const ConfigEditor = (props: ConfigEditorProps) => { - console.log('here'); const { options, onOptionsChange } = props; const { jsonData, secureJsonData, secureJsonFields } = options; const secureSettings = secureJsonData || {}; From 272d4c4c1bb6111fb40feb87e29764d0331611f2 Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Mon, 10 Nov 2025 08:17:20 -0800 Subject: [PATCH 08/12] change wording on release md --- .changeset/lazy-planes-reply.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/lazy-planes-reply.md b/.changeset/lazy-planes-reply.md index 6fa11b4e..64b85379 100644 --- a/.changeset/lazy-planes-reply.md +++ b/.changeset/lazy-planes-reply.md @@ -2,4 +2,4 @@ 'grafana-github-datasource': minor --- -Enable PDC for github datasource +Add support PDC for github datasource From 248fbca92a90952937ce03eca5fcdc70d84606fd Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Mon, 10 Nov 2025 08:27:12 -0800 Subject: [PATCH 09/12] order imports, remove property and change the way we check for feature flag --- src/types/config.ts | 1 - src/views/ConfigEditor.tsx | 24 +++++++++++------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/types/config.ts b/src/types/config.ts index 46902a1a..c76f75dc 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -10,7 +10,6 @@ export type GitHubDataSourceOptions = { selectedAuthType?: GitHubAuthType; appId?: string; installationId?: string; - enableSecureSocksProxy?: boolean } & DataSourceJsonData; export type GitHubSecureJsonDataKeys = diff --git a/src/views/ConfigEditor.tsx b/src/views/ConfigEditor.tsx index e02161be..c52f9fab 100644 --- a/src/views/ConfigEditor.tsx +++ b/src/views/ConfigEditor.tsx @@ -1,5 +1,14 @@ import React, { ChangeEvent, useCallback, useEffect, useState } from 'react'; import { css } from '@emotion/css'; +import { + onUpdateDatasourceJsonDataOption, + onUpdateDatasourceSecureJsonDataOption, + type DataSourcePluginOptionsEditorProps, + type GrafanaTheme2, + type SelectableValue, +} from '@grafana/data'; +import { ConfigSection, DataSourceDescription } from '@grafana/plugin-ui'; +import { config } from '@grafana/runtime'; import { Collapse, Field, @@ -11,20 +20,9 @@ import { SecureSocksProxySettings, useStyles2, } from '@grafana/ui'; -import { ConfigSection, DataSourceDescription } from '@grafana/plugin-ui'; import { Divider } from 'components/Divider'; -import { components as selectors } from '../components/selectors'; -import { - FeatureToggles, - onUpdateDatasourceJsonDataOption, - onUpdateDatasourceSecureJsonDataOption, - type DataSourcePluginOptionsEditorProps, - type GrafanaTheme2, - type SelectableValue, -} from '@grafana/data'; import type { GitHubAuthType, GitHubLicenseType, GitHubDataSourceOptions, GitHubSecureJsonData } from 'types/config'; -import { config } from '@grafana/runtime'; -import { gte } from 'semver'; +import { components as selectors } from '../components/selectors'; export type ConfigEditorProps = DataSourcePluginOptionsEditorProps; @@ -209,7 +207,7 @@ const ConfigEditor = (props: ConfigEditorProps) => { )} - {config.featureToggles['secureSocksDSProxyEnabled' as keyof FeatureToggles] && gte(config.buildInfo.version, '10.0.0') && ( + {config.secureSocksDSProxyEnabled && ( )} From 36a8929b2f071f0fa5f2bc41efc36b7476ffde2f Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Mon, 10 Nov 2025 11:54:41 -0800 Subject: [PATCH 10/12] readd feature toggle check --- src/views/ConfigEditor.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/views/ConfigEditor.tsx b/src/views/ConfigEditor.tsx index c52f9fab..afc56464 100644 --- a/src/views/ConfigEditor.tsx +++ b/src/views/ConfigEditor.tsx @@ -1,6 +1,7 @@ import React, { ChangeEvent, useCallback, useEffect, useState } from 'react'; import { css } from '@emotion/css'; import { + FeatureToggles, onUpdateDatasourceJsonDataOption, onUpdateDatasourceSecureJsonDataOption, type DataSourcePluginOptionsEditorProps, @@ -207,7 +208,7 @@ const ConfigEditor = (props: ConfigEditorProps) => { )} - {config.secureSocksDSProxyEnabled && ( + {config.featureToggles['secureSocksDSProxyEnabled' as keyof FeatureToggles] && ( )} From f6a4b9e47a766b5bbfb3c9b9b98ac118c9f952ec Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Mon, 10 Nov 2025 12:02:14 -0800 Subject: [PATCH 11/12] change to use datasource contextr --- pkg/plugin/instance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/plugin/instance.go b/pkg/plugin/instance.go index 1ae92d0a..1e1f67af 100644 --- a/pkg/plugin/instance.go +++ b/pkg/plugin/instance.go @@ -42,7 +42,7 @@ func NewDataSourceInstance(ctx context.Context, settings backend.DataSourceInsta datasourceSettings.CachingEnabled = true - instance, err := NewGitHubInstance(context.Background(), datasourceSettings, opts) + instance, err := NewGitHubInstance(ctx, datasourceSettings, opts) if err != nil { return instance, fmt.Errorf("instantiating github instance: %w", err) } From e9446bbb75c855560400297aec58a208b143515a Mon Sep 17 00:00:00 2001 From: Jocelyn Collado-Kuri Date: Wed, 12 Nov 2025 08:04:50 -0800 Subject: [PATCH 12/12] Update .changeset/lazy-planes-reply.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Zoltán Bedi --- .changeset/lazy-planes-reply.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/lazy-planes-reply.md b/.changeset/lazy-planes-reply.md index 64b85379..d12bb6c8 100644 --- a/.changeset/lazy-planes-reply.md +++ b/.changeset/lazy-planes-reply.md @@ -2,4 +2,4 @@ 'grafana-github-datasource': minor --- -Add support PDC for github datasource +Add support for PDC