From a45a11980e480fcabdcbb501413c7f31149094cd Mon Sep 17 00:00:00 2001 From: Erez Rokah Date: Thu, 8 Oct 2026 15:55:05 +0300 Subject: [PATCH 1/5] feat: Support local, gRPC and Docker sources in `upgrade check` (#23497) This PR makes `cloudquery upgrade check` run sources from the `local`, `grpc` and `docker` registries as configured and compare them with the `--to` version from the CloudQuery Hub, with an optional `--to-path` flag to set the Hub path when it cannot be inferred from the plugin name. --- cli/cmd/testdata/upgrade-check/datadog.json | 12 +- .../upgrade-check/gcp-selected-tables.json | 12 +- .../testdata/upgrade-check/okta-append.json | 12 +- .../okta-overwrite-delete-stale.json | 12 +- cli/cmd/upgrade_check.go | 163 ++++++++++-- cli/cmd/upgrade_check_json.go | 22 +- cli/cmd/upgrade_check_json_test.go | 20 +- cli/cmd/upgrade_check_report.go | 5 +- cli/cmd/upgrade_check_report_test.go | 23 ++ cli/cmd/upgrade_check_test.go | 243 +++++++++++++++++- .../reference/cloudquery_upgrade_check.md | 4 + 11 files changed, 487 insertions(+), 41 deletions(-) diff --git a/cli/cmd/testdata/upgrade-check/datadog.json b/cli/cmd/testdata/upgrade-check/datadog.json index 7a1f893c08..229680c14e 100644 --- a/cli/cmd/testdata/upgrade-check/datadog.json +++ b/cli/cmd/testdata/upgrade-check/datadog.json @@ -4,7 +4,17 @@ "source": { "name": "datadog", "from_version": "v5.19.10", - "to_version": "v6.0.0" + "to_version": "v6.0.0", + "from": { + "registry": "cloudquery", + "path": "cloudquery/datadog", + "version": "v5.19.10" + }, + "to": { + "registry": "cloudquery", + "path": "cloudquery/datadog", + "version": "v6.0.0" + } }, "destination": { "name": "postgresql", diff --git a/cli/cmd/testdata/upgrade-check/gcp-selected-tables.json b/cli/cmd/testdata/upgrade-check/gcp-selected-tables.json index 37aa89dfe5..5f6511d634 100644 --- a/cli/cmd/testdata/upgrade-check/gcp-selected-tables.json +++ b/cli/cmd/testdata/upgrade-check/gcp-selected-tables.json @@ -4,7 +4,17 @@ "source": { "name": "gcp", "from_version": "v22.1.2", - "to_version": "v23.0.0" + "to_version": "v23.0.0", + "from": { + "registry": "cloudquery", + "path": "cloudquery/gcp", + "version": "v22.1.2" + }, + "to": { + "registry": "cloudquery", + "path": "cloudquery/gcp", + "version": "v23.0.0" + } }, "destination": { "name": "postgresql", diff --git a/cli/cmd/testdata/upgrade-check/okta-append.json b/cli/cmd/testdata/upgrade-check/okta-append.json index ea0c2ce869..00139dbe79 100644 --- a/cli/cmd/testdata/upgrade-check/okta-append.json +++ b/cli/cmd/testdata/upgrade-check/okta-append.json @@ -4,7 +4,17 @@ "source": { "name": "okta", "from_version": "v6.8.2", - "to_version": "v7.0.0" + "to_version": "v7.0.0", + "from": { + "registry": "cloudquery", + "path": "cloudquery/okta", + "version": "v6.8.2" + }, + "to": { + "registry": "cloudquery", + "path": "cloudquery/okta", + "version": "v7.0.0" + } }, "destination": { "name": "postgresql", diff --git a/cli/cmd/testdata/upgrade-check/okta-overwrite-delete-stale.json b/cli/cmd/testdata/upgrade-check/okta-overwrite-delete-stale.json index 59cdf999f9..2dbb41c8b3 100644 --- a/cli/cmd/testdata/upgrade-check/okta-overwrite-delete-stale.json +++ b/cli/cmd/testdata/upgrade-check/okta-overwrite-delete-stale.json @@ -4,7 +4,17 @@ "source": { "name": "okta", "from_version": "v6.8.2", - "to_version": "v7.0.0" + "to_version": "v7.0.0", + "from": { + "registry": "cloudquery", + "path": "cloudquery/okta", + "version": "v6.8.2" + }, + "to": { + "registry": "cloudquery", + "path": "cloudquery/okta", + "version": "v7.0.0" + } }, "destination": { "name": "postgresql", diff --git a/cli/cmd/upgrade_check.go b/cli/cmd/upgrade_check.go index e331f2ffd6..35d7e5ca73 100644 --- a/cli/cmd/upgrade_check.go +++ b/cli/cmd/upgrade_check.go @@ -33,6 +33,9 @@ Exit codes: With several destinations, the highest of 0, 3 and 4 is used. The report is always printed first.` upgradeCheckExample = `# Check how upgrading the datadog source to v6.0.0 affects the destinations in config.yml cloudquery upgrade check ./config.yml --source datadog --to v6.0.0 + +# Compare a source that runs from a local binary, gRPC server or Docker image with cloudquery/semgrep v3.1.0 from the CloudQuery Hub +cloudquery upgrade check ./config.yml --source semgrep --to v3.1.0 --to-path cloudquery/semgrep ` destinationNoProtocolV3Reason = "destination does not support plugin protocol v3" destinationNoAssessmentReason = "destination version does not support assessment" @@ -61,6 +64,7 @@ func newCmdUpgradeCheck() *cobra.Command { } cmd.Flags().String("source", "", "Name of the source to upgrade, as set in the configuration") cmd.Flags().String("to", "", "Source plugin version to upgrade to") + cmd.Flags().String("to-path", "", "CloudQuery Hub path of the source plugin to upgrade to, as /. Only for sources from the local, grpc or docker registry. Default: cloudquery/") _ = cmd.MarkFlagRequired("source") _ = cmd.MarkFlagRequired("to") cmd.Flags().String("output", upgradeOutputText, "Output format. One of: text, json") @@ -83,6 +87,10 @@ func upgradeCheck(cmd *cobra.Command, args []string) error { if err != nil { return err } + toPath, err := cmd.Flags().GetString("to-path") + if err != nil { + return err + } output, err := cmd.Flags().GetString("output") if err != nil { return err @@ -131,7 +139,7 @@ func upgradeCheck(cmd *cobra.Command, args []string) error { opts = append(opts, managedplugin.WithNoSentry()) } - from, to, err := loadUpgradeSourceTables(ctx, *sourceSpec, toVersion, opts...) + from, to, err := loadUpgradeSourceTables(ctx, *sourceSpec, upgradeTarget{Version: toVersion, Path: toPath}, managedplugin.NewClient, opts...) if err != nil { return err } @@ -161,6 +169,8 @@ func upgradeReports(ctx context.Context, sourceSpec specs.Source, destinationSpe SourceName: sourceSpec.Name, FromVersion: from.Version, ToVersion: to.Version, + FromOrigin: from.Origin, + ToOrigin: to.Origin, SourceGaps: upgradeSourceGaps(sourceSpec.Name, from, to), } if from.UnknownReason != "" || to.UnknownReason != "" { @@ -216,7 +226,7 @@ func loadUpgradeCheckSpecs(ctx context.Context, args []string, sourceName string return upgradeCheckSpecs{}, fmt.Errorf("source %q not found in %s", sourceName, strings.Join(args, ", ")) } - loaded.downloadToken, loaded.teamName, err = cqplatform.DownloadAuth(ctx, log.Logger, []*specs.Source{loaded.source}, specReader.Destinations, specReader.Transformers) + loaded.downloadToken, loaded.teamName, err = cqplatform.DownloadAuth(ctx, log.Logger, upgradeAuthSources(*loaded.source), specReader.Destinations, specReader.Transformers) if err != nil { return upgradeCheckSpecs{}, err } @@ -245,13 +255,25 @@ func loadUpgradeCheckSpecs(ctx context.Context, args []string, sourceName string return loaded, nil } -func upgradeSourceGaps(sourceName string, versions ...upgradeSourceTables) []string { +func upgradeAuthSources(sourceSpec specs.Source) []*specs.Source { + sources := []*specs.Source{&sourceSpec} + if !upgradeVersionSelectsBinary(sourceSpec.Registry) { + sources = append(sources, &specs.Source{Metadata: specs.Metadata{Name: sourceSpec.Name, Registry: specs.RegistryCloudQuery}}) + } + return sources +} + +func upgradeSourceGaps(sourceName string, from, to upgradeSourceTables) []string { + fromLabel, toLabel := upgradeSourceLabels(from.Origin, from.Version, to.Origin, to.Version) var gaps []string - for _, version := range versions { - if version.UnknownReason != "" { - gaps = append(gaps, fmt.Sprintf("%s %s: tables could not be listed: %s", sourceName, version.Version, version.UnknownReason)) - } else if version.Connected { - gaps = append(gaps, fmt.Sprintf("%s %s: tables were listed with a connection (metadata only, no rows read)", sourceName, version.Version)) + for _, side := range []struct { + label string + tables upgradeSourceTables + }{{fromLabel, from}, {toLabel, to}} { + if side.tables.UnknownReason != "" { + gaps = append(gaps, fmt.Sprintf("%s %s: tables could not be listed: %s", sourceName, side.label, side.tables.UnknownReason)) + } else if side.tables.Connected { + gaps = append(gaps, fmt.Sprintf("%s %s: tables were listed with a connection (metadata only, no rows read)", sourceName, side.label)) } } return gaps @@ -273,50 +295,147 @@ func terminatePlugin(client *managedplugin.Client) { } } +type upgradeSourceOrigin struct { + Registry specs.Registry + Path string +} + +func (o upgradeSourceOrigin) label(version string) string { + if upgradeVersionSelectsBinary(o.Registry) { + return o.Path + "@" + version + } + return fmt.Sprintf("(%s: %s, %s)", o.Registry, o.Path, version) +} + +func upgradeSourceLabels(from upgradeSourceOrigin, fromVersion string, to upgradeSourceOrigin, toVersion string) (fromLabel, toLabel string) { + if from == to { + return fromVersion, toVersion + } + return from.label(fromVersion), to.label(toVersion) +} + type upgradeSourceTables struct { + Origin upgradeSourceOrigin Version string + PluginName string Tables schema.Tables Connected bool UnknownReason string } -func loadUpgradeSourceTables(ctx context.Context, sourceSpec specs.Source, toVersion string, opts ...managedplugin.Option) (from, to upgradeSourceTables, err error) { - if sourceSpec.Registry != specs.RegistryCloudQuery && sourceSpec.Registry != specs.RegistryGitHub { - return from, to, fmt.Errorf("upgrade check supports only sources from the cloudquery or github registry, source %s uses the %s registry", sourceSpec.Name, sourceSpec.Registry) +type upgradeTarget struct { + Version string + Path string +} + +type newPluginClientFunc func(ctx context.Context, typ managedplugin.PluginType, config managedplugin.Config, opts ...managedplugin.Option) (*managedplugin.Client, error) + +const upgradeUnknownVersion = "unknown" + +func upgradeVersionSelectsBinary(registry specs.Registry) bool { + return registry == specs.RegistryCloudQuery || registry == specs.RegistryGitHub +} + +func loadUpgradeSourceTables(ctx context.Context, sourceSpec specs.Source, target upgradeTarget, newClient newPluginClientFunc, opts ...managedplugin.Option) (from, to upgradeSourceTables, err error) { + if err := validateUpgradeTarget(sourceSpec, target); err != nil { + return from, to, err } if err := registerOnce(); err != nil { return from, to, err } - from, err = loadSourceVersionTables(ctx, sourceSpec, sourceSpec.Version, opts...) + fromOrigin := upgradeSourceOrigin{Registry: sourceSpec.Registry, Path: sourceSpec.Path} + from, err = loadSourceTables(ctx, newClient, sourceSpec, fromOrigin, managedPluginConfig(sourceSpec.Metadata), opts...) if err != nil { return from, to, err } - to, err = loadSourceVersionTables(ctx, sourceSpec, toVersion, opts...) + toOrigin, toConfig, err := upgradeTargetConfig(sourceSpec, target, from.PluginName) + if err != nil { + return from, to, err + } + to, err = loadSourceTables(ctx, newClient, sourceSpec, toOrigin, toConfig, opts...) + if err != nil && !upgradeVersionSelectsBinary(sourceSpec.Registry) && target.Path == "" { + return from, to, fmt.Errorf("%w. The CloudQuery Hub path %s was inferred from the name the source reports. Use --to-path / to set a different path", err, toConfig.Path) + } return from, to, err } -func loadSourceVersionTables(ctx context.Context, sourceSpec specs.Source, version string, opts ...managedplugin.Option) (upgradeSourceTables, error) { +func validateUpgradeTarget(sourceSpec specs.Source, target upgradeTarget) error { + if target.Path == "" { + return nil + } + if upgradeVersionSelectsBinary(sourceSpec.Registry) { + return fmt.Errorf("--to-path is supported only for sources from the local, grpc or docker registry, source %s uses the %s registry", sourceSpec.Name, sourceSpec.Registry) + } + team, name, ok := strings.Cut(target.Path, "/") + if !ok || team == "" || name == "" || strings.Contains(name, "/") { + return fmt.Errorf("invalid --to-path %q. Use /, for example cloudquery/aws", target.Path) + } + return nil +} + +func upgradeTargetConfig(sourceSpec specs.Source, target upgradeTarget, pluginName string) (upgradeSourceOrigin, managedplugin.Config, error) { config := managedPluginConfig(sourceSpec.Metadata) - config.Version = version - client, err := managedplugin.NewClient(ctx, managedplugin.PluginSource, config, opts...) + config.Version = target.Version + if upgradeVersionSelectsBinary(sourceSpec.Registry) { + return upgradeSourceOrigin{Registry: sourceSpec.Registry, Path: config.Path}, config, nil + } + config.Registry = managedplugin.RegistryCloudQuery + config.DockerAuth = "" + config.Path = target.Path + if config.Path == "" { + if pluginName == "" { + return upgradeSourceOrigin{}, managedplugin.Config{}, fmt.Errorf("could not infer the CloudQuery Hub path to upgrade source %s to, because the source from the %s registry did not report its name. Use --to-path / to set the path, for example --to-path cloudquery/aws", sourceSpec.Name, sourceSpec.Registry) + } + config.Path = "cloudquery/" + pluginName + } + return upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: config.Path}, config, nil +} + +func loadSourceTables(ctx context.Context, newClient newPluginClientFunc, sourceSpec specs.Source, origin upgradeSourceOrigin, config managedplugin.Config, opts ...managedplugin.Option) (upgradeSourceTables, error) { + version := config.Version + if !upgradeVersionSelectsBinary(origin.Registry) { + version = upgradeUnknownVersion + } + client, err := newClient(ctx, managedplugin.PluginSource, config, opts...) if err != nil { - return upgradeSourceTables{}, fmt.Errorf("failed to start source %s@%s: %w", sourceSpec.Name, version, err) + return upgradeSourceTables{}, fmt.Errorf("failed to start source %s %s: %w", sourceSpec.Name, origin.label(version), err) } defer terminatePlugin(client) versions, err := client.Versions(ctx) if err != nil { - return upgradeSourceTables{}, fmt.Errorf("failed to get protocol versions for %s@%s: %w", sourceSpec.Name, version, err) + return upgradeSourceTables{}, fmt.Errorf("failed to get protocol versions for %s %s: %w", sourceSpec.Name, origin.label(version), err) } if findMaxCommonVersion(versions, []int{3}) != 3 { - return upgradeSourceTables{Version: version, UnknownReason: "source does not support plugin protocol v3"}, nil + return upgradeSourceTables{Origin: origin, Version: version, UnknownReason: "source does not support plugin protocol v3"}, nil } - result := listSourceTables(ctx, pluginPb.NewPluginClient(client.Conn), sourceSpec.Spec) + pluginClient := pluginPb.NewPluginClient(client.Conn) + pluginName, reportedVersion := reportedPluginIdentity(ctx, pluginClient) + if !upgradeVersionSelectsBinary(origin.Registry) && reportedVersion != "" { + version = reportedVersion + } + result := listSourceTables(ctx, pluginClient, sourceSpec.Spec) + result.Origin = origin result.Version = version + result.PluginName = pluginName return result, nil } +func reportedPluginIdentity(ctx context.Context, client pluginPb.PluginClient) (name, version string) { + if resp, err := client.GetName(ctx, &pluginPb.GetName_Request{}); err == nil { + name = resp.Name + } else { + log.Debug().Err(err).Msg("failed to get source plugin name") + } + if resp, err := client.GetVersion(ctx, &pluginPb.GetVersion_Request{}); err == nil { + version = resp.Version + } else { + log.Debug().Err(err).Msg("failed to get source plugin version") + } + return name, version +} + func listSourceTables(ctx context.Context, client pluginPb.PluginClient, spec map[string]any) upgradeSourceTables { tables, err := initAndGetAllTables(ctx, client, spec, true) if err != nil { @@ -364,7 +483,7 @@ type upgradeTableSchemas struct { func selectUpgradeTables(sourceSpec specs.Source, from, to schema.Tables) (upgradeTableSelection, error) { selectedFrom, err := selectSourceTables(sourceSpec, from) if err != nil { - return upgradeTableSelection{}, fmt.Errorf("failed to select tables from source version %s: %w", sourceSpec.Version, err) + return upgradeTableSelection{}, fmt.Errorf("failed to select tables from current source version: %w", err) } selectedTo, err := selectSourceTables(sourceSpec, to) if err != nil { @@ -427,7 +546,7 @@ func transformUpgradeTables(ctx context.Context, sourceSpec specs.Source, destin for i, pair := range pairs { from, err := transform(pair.From) if err != nil { - return nil, fmt.Errorf("failed to transform table %s from source version %s for destination %s: %w", pair.Name, sourceSpec.Version, destinationSpec.Name, err) + return nil, fmt.Errorf("failed to transform table %s from current source version for destination %s: %w", pair.Name, destinationSpec.Name, err) } to, err := transform(pair.To) if err != nil { diff --git a/cli/cmd/upgrade_check_json.go b/cli/cmd/upgrade_check_json.go index b285ddc903..d650d3324c 100644 --- a/cli/cmd/upgrade_check_json.go +++ b/cli/cmd/upgrade_check_json.go @@ -25,9 +25,17 @@ type upgradeReportJSON struct { } type upgradeSourceJSON struct { - Name string `json:"name"` - FromVersion string `json:"from_version"` - ToVersion string `json:"to_version"` + Name string `json:"name"` + FromVersion string `json:"from_version"` + ToVersion string `json:"to_version"` + From upgradeSourceSideJSON `json:"from"` + To upgradeSourceSideJSON `json:"to"` +} + +type upgradeSourceSideJSON struct { + Registry string `json:"registry"` + Path string `json:"path"` + Version string `json:"version"` } type upgradeDestinationJSON struct { @@ -77,7 +85,13 @@ func upgradeReportToJSON(r upgradeReport) upgradeReportJSON { verdict, _ := upgradeVerdict(r, impacts, comparisons, migrateMode) action, _ := upgradeAction(r, impacts, comparisons, migrateMode) out := upgradeReportJSON{ - Source: upgradeSourceJSON{Name: r.SourceName, FromVersion: r.FromVersion, ToVersion: r.ToVersion}, + Source: upgradeSourceJSON{ + Name: r.SourceName, + FromVersion: r.FromVersion, + ToVersion: r.ToVersion, + From: upgradeSourceSideJSON{Registry: r.FromOrigin.Registry.String(), Path: r.FromOrigin.Path, Version: r.FromVersion}, + To: upgradeSourceSideJSON{Registry: r.ToOrigin.Registry.String(), Path: r.ToOrigin.Path, Version: r.ToVersion}, + }, Verdict: verdict, Tables: append([]upgradeTableImpact{}, impacts...), RemovedTables: append([]string{}, r.RemovedTables...), diff --git a/cli/cmd/upgrade_check_json_test.go b/cli/cmd/upgrade_check_json_test.go index 6cf2fe102f..b125d04543 100644 --- a/cli/cmd/upgrade_check_json_test.go +++ b/cli/cmd/upgrade_check_json_test.go @@ -134,6 +134,8 @@ func textAction(report string) (string, bool) { func TestRenderUpgradeReportsJSON(t *testing.T) { report := upgradeReport{ SourceName: "okta", FromVersion: "v6.8.2", ToVersion: "v7.0.0", + FromOrigin: upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: "cloudquery/okta"}, + ToOrigin: upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: "cloudquery/okta"}, Destination: postgresqlDestinationSpec(specs.WriteModeAppend, specs.MigrateModeSafe), RemovedTables: []string{"okta_removed"}, Findings: []*pluginPb.AssessTables_TableFinding{ @@ -160,7 +162,11 @@ func TestRenderUpgradeReportsJSON(t *testing.T) { require.NoError(t, renderUpgradeReportsJSON(&out, []upgradeReport{report})) require.JSONEq(t, `{"reports": [{ - "source": {"name": "okta", "from_version": "v6.8.2", "to_version": "v7.0.0"}, + "source": { + "name": "okta", "from_version": "v6.8.2", "to_version": "v7.0.0", + "from": {"registry": "cloudquery", "path": "cloudquery/okta", "version": "v6.8.2"}, + "to": {"registry": "cloudquery", "path": "cloudquery/okta", "version": "v7.0.0"} + }, "destination": {"name": "postgresql", "registry": "cloudquery", "path": "cloudquery/postgresql", "version": "v8.14.0", "write_mode": "append", "pk_mode": "default", "migrate_mode": "safe"}, "verdict": "SELECTED TABLES REMOVED", "summary": "1 changed table, 1 removed table", @@ -188,10 +194,18 @@ func TestRenderUpgradeReportsJSON(t *testing.T) { func TestRenderUpgradeReportsJSONWithoutDestination(t *testing.T) { var out bytes.Buffer - require.NoError(t, renderUpgradeReportsJSON(&out, []upgradeReport{{SourceName: "s3", FromVersion: "v1.0.0", ToVersion: "v2.0.0", SourceUnknown: true}})) + require.NoError(t, renderUpgradeReportsJSON(&out, []upgradeReport{{ + SourceName: "s3", FromVersion: "unknown", ToVersion: "v2.0.0", SourceUnknown: true, + FromOrigin: upgradeSourceOrigin{Registry: specs.RegistryLocal, Path: "/opt/plugins/s3"}, + ToOrigin: upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: "cloudquery/s3"}, + }})) require.JSONEq(t, `{"reports": [{ - "source": {"name": "s3", "from_version": "v1.0.0", "to_version": "v2.0.0"}, + "source": { + "name": "s3", "from_version": "unknown", "to_version": "v2.0.0", + "from": {"registry": "local", "path": "/opt/plugins/s3", "version": "unknown"}, + "to": {"registry": "cloudquery", "path": "cloudquery/s3", "version": "v2.0.0"} + }, "destination": null, "verdict": "UNKNOWN", "tables": [], diff --git a/cli/cmd/upgrade_check_report.go b/cli/cmd/upgrade_check_report.go index 4725d28973..3def52e573 100644 --- a/cli/cmd/upgrade_check_report.go +++ b/cli/cmd/upgrade_check_report.go @@ -26,6 +26,8 @@ type upgradeReport struct { SourceName string FromVersion string ToVersion string + FromOrigin upgradeSourceOrigin + ToOrigin upgradeSourceOrigin SourceUnknown bool SourceGaps []string RemovedTables []string @@ -97,7 +99,8 @@ func renderUpgradeReport(w io.Writer, r upgradeReport) error { } var b strings.Builder - header := fmt.Sprintf("%s %s → %s", r.SourceName, r.FromVersion, r.ToVersion) + fromLabel, toLabel := upgradeSourceLabels(r.FromOrigin, r.FromVersion, r.ToOrigin, r.ToVersion) + header := fmt.Sprintf("%s %s → %s", r.SourceName, fromLabel, toLabel) if r.Destination == nil { b.WriteString(bold.Sprint(header) + "\n") } else { diff --git a/cli/cmd/upgrade_check_report_test.go b/cli/cmd/upgrade_check_report_test.go index f11efa4ba8..5d32f382df 100644 --- a/cli/cmd/upgrade_check_report_test.go +++ b/cli/cmd/upgrade_check_report_test.go @@ -447,6 +447,29 @@ Coverage gaps Action: review the source changelog for what this check could not assess. This check only previews the changes. It does not migrate, write, delete or upload anything. +`, + }, + { + name: "source from a local binary compared with the hub", + report: upgradeReport{ + SourceName: "semgrep", FromVersion: "v3.0.0", ToVersion: "v3.1.0", SourceUnknown: true, + FromOrigin: upgradeSourceOrigin{Registry: specs.RegistryLocal, Path: "/opt/plugins/semgrep"}, + ToOrigin: upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: "cloudquery/semgrep"}, + SourceGaps: upgradeSourceGaps("semgrep", + upgradeSourceTables{Origin: upgradeSourceOrigin{Registry: specs.RegistryLocal, Path: "/opt/plugins/semgrep"}, Version: "v3.0.0", UnknownReason: "source returned no tables with or without a connection"}, + upgradeSourceTables{Origin: upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: "cloudquery/semgrep"}, Version: "v3.1.0", Connected: true}, + ), + }, + want: `semgrep (local: /opt/plugins/semgrep, v3.0.0) → cloudquery/semgrep@v3.1.0 +UNKNOWN + +Coverage gaps + semgrep (local: /opt/plugins/semgrep, v3.0.0): tables could not be listed: source returned no tables with or without a connection + semgrep cloudquery/semgrep@v3.1.0: tables were listed with a connection (metadata only, no rows read) + +Action: review the source changelog for what this check could not assess. +This check only previews the changes. It does not migrate, write, delete or upload anything. + `, }, } diff --git a/cli/cmd/upgrade_check_test.go b/cli/cmd/upgrade_check_test.go index 7d6d6edc14..b9ca1bb28b 100644 --- a/cli/cmd/upgrade_check_test.go +++ b/cli/cmd/upgrade_check_test.go @@ -7,6 +7,7 @@ import ( "encoding/json" "errors" "flag" + "net" "net/http" "net/http/httptest" "os" @@ -20,6 +21,7 @@ import ( "github.com/cloudquery/cloudquery/cli/v6/internal/auth" "github.com/cloudquery/cloudquery/cli/v6/internal/specs/v0" "github.com/cloudquery/plugin-pb-go/managedplugin" + discoveryPb "github.com/cloudquery/plugin-pb-go/pb/discovery/v1" pluginPb "github.com/cloudquery/plugin-pb-go/pb/plugin/v3" "github.com/cloudquery/plugin-sdk/v4/schema" "github.com/rs/zerolog/log" @@ -173,7 +175,7 @@ func TestLoadUpgradeSourceTables(t *testing.T) { teamName, err := auth.GetTeamForToken(ctx, authToken) require.NoError(t, err) - from, to, err := loadUpgradeSourceTables(ctx, sourceSpec, "v4.7.0", + from, to, err := loadUpgradeSourceTables(ctx, sourceSpec, upgradeTarget{Version: "v4.7.0"}, managedplugin.NewClient, managedplugin.WithLogger(log.Logger), managedplugin.WithAuthToken(authToken.Value), managedplugin.WithTeamName(teamName), @@ -188,20 +190,247 @@ func TestLoadUpgradeSourceTables(t *testing.T) { } require.Equal(t, "v4.5.1", from.Version) require.Equal(t, "v4.7.0", to.Version) + require.Equal(t, upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: "cloudquery/test"}, from.Origin) + require.Equal(t, from.Origin, to.Origin) } -func TestLoadUpgradeSourceTablesRejectsFixedPathRegistries(t *testing.T) { - for _, registry := range []specs.Registry{specs.RegistryLocal, specs.RegistryGRPC, specs.RegistryDocker} { - t.Run(registry.String(), func(t *testing.T) { - sourceSpec := specs.Source{Metadata: specs.Metadata{Name: "test", Path: "/plugins/test", Version: "v1.0.0", Registry: registry}} +type fakeSourceServer struct { + pluginPb.UnimplementedPluginServer + discoveryPb.UnimplementedDiscoveryServer + name string + version string + tables schema.Tables +} + +func (*fakeSourceServer) GetVersions(context.Context, *discoveryPb.GetVersions_Request) (*discoveryPb.GetVersions_Response, error) { + return &discoveryPb.GetVersions_Response{Versions: []int32{3}}, nil +} + +func (f *fakeSourceServer) GetName(context.Context, *pluginPb.GetName_Request) (*pluginPb.GetName_Response, error) { + if f.name == "" { + return nil, status.Error(codes.Unimplemented, "no name") + } + return &pluginPb.GetName_Response{Name: f.name}, nil +} + +func (f *fakeSourceServer) GetVersion(context.Context, *pluginPb.GetVersion_Request) (*pluginPb.GetVersion_Response, error) { + if f.version == "" { + return nil, status.Error(codes.Unimplemented, "no version") + } + return &pluginPb.GetVersion_Response{Version: f.version}, nil +} + +func (*fakeSourceServer) Init(context.Context, *pluginPb.Init_Request) (*pluginPb.Init_Response, error) { + return &pluginPb.Init_Response{}, nil +} + +func (f *fakeSourceServer) GetTables(context.Context, *pluginPb.GetTables_Request) (*pluginPb.GetTables_Response, error) { + b, err := pluginPb.SchemasToBytes(f.tables.ToArrowSchemas()) + if err != nil { + return nil, err + } + return &pluginPb.GetTables_Response{Tables: b}, nil +} + +func startFakeSourceServer(t *testing.T, source *fakeSourceServer) string { + t.Helper() + listener, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + server := grpc.NewServer() + pluginPb.RegisterPluginServer(server, source) + discoveryPb.RegisterDiscoveryServer(server, source) + go func() { _ = server.Serve(listener) }() + t.Cleanup(server.Stop) + return listener.Addr().String() +} + +type recordingPluginStarter struct { + fromAddress string + toAddress string + toVersion string + toErr error + configs []managedplugin.Config +} + +func (r *recordingPluginStarter) newClient(ctx context.Context, typ managedplugin.PluginType, config managedplugin.Config, opts ...managedplugin.Option) (*managedplugin.Client, error) { + r.configs = append(r.configs, config) + address := r.fromAddress + if config.Version == r.toVersion { + if r.toErr != nil { + return nil, r.toErr + } + address = r.toAddress + } + return managedplugin.NewClient(ctx, typ, managedplugin.Config{Name: config.Name, Registry: managedplugin.RegistryGrpc, Path: address}, opts...) +} + +func TestLoadUpgradeSourceTablesRegistryDispatch(t *testing.T) { + fromAddress := startFakeSourceServer(t, &fakeSourceServer{name: "semgrep", version: "v3.0.0", tables: schema.Tables{testTable("semgrep_old")}}) + toAddress := startFakeSourceServer(t, &fakeSourceServer{name: "semgrep", version: "v3.1.0", tables: schema.Tables{testTable("semgrep_new")}}) + + cases := []struct { + name string + metadata specs.Metadata + toPath string + wantFromConfig managedplugin.Config + wantToConfig managedplugin.Config + wantFrom upgradeSourceOrigin + wantTo upgradeSourceOrigin + wantFromVer string + }{ + { + name: "cloudquery registry starts the same path at both versions", + metadata: specs.Metadata{Name: "semgrep", Registry: specs.RegistryCloudQuery, Path: "cloudquery/semgrep", Version: "v3.0.0"}, + wantFromConfig: managedplugin.Config{Name: "semgrep", Registry: managedplugin.RegistryCloudQuery, Path: "cloudquery/semgrep", Version: "v3.0.0"}, + wantToConfig: managedplugin.Config{Name: "semgrep", Registry: managedplugin.RegistryCloudQuery, Path: "cloudquery/semgrep", Version: "v3.1.0"}, + wantFrom: upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: "cloudquery/semgrep"}, + wantTo: upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: "cloudquery/semgrep"}, + wantFromVer: "v3.0.0", + }, + { + name: "github registry starts the same path at both versions", + metadata: specs.Metadata{Name: "semgrep", Registry: specs.RegistryGitHub, Path: "cloudquery/semgrep", Version: "v3.0.0"}, + wantFromConfig: managedplugin.Config{Name: "semgrep", Registry: managedplugin.RegistryGithub, Path: "cloudquery/semgrep", Version: "v3.0.0"}, + wantToConfig: managedplugin.Config{Name: "semgrep", Registry: managedplugin.RegistryGithub, Path: "cloudquery/semgrep", Version: "v3.1.0"}, + wantFrom: upgradeSourceOrigin{Registry: specs.RegistryGitHub, Path: "cloudquery/semgrep"}, + wantTo: upgradeSourceOrigin{Registry: specs.RegistryGitHub, Path: "cloudquery/semgrep"}, + wantFromVer: "v3.0.0", + }, + { + name: "local registry starts the configured binary and the inferred hub plugin", + metadata: specs.Metadata{Name: "semgrep-prod", Registry: specs.RegistryLocal, Path: "/opt/plugins/semgrep"}, + wantFromConfig: managedplugin.Config{Name: "semgrep-prod", Registry: managedplugin.RegistryLocal, Path: "/opt/plugins/semgrep"}, + wantToConfig: managedplugin.Config{Name: "semgrep-prod", Registry: managedplugin.RegistryCloudQuery, Path: "cloudquery/semgrep", Version: "v3.1.0"}, + wantFrom: upgradeSourceOrigin{Registry: specs.RegistryLocal, Path: "/opt/plugins/semgrep"}, + wantTo: upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: "cloudquery/semgrep"}, + wantFromVer: "v3.0.0", + }, + { + name: "grpc registry connects to the configured server and the inferred hub plugin", + metadata: specs.Metadata{Name: "semgrep", Registry: specs.RegistryGRPC, Path: "localhost:7777"}, + wantFromConfig: managedplugin.Config{Name: "semgrep", Registry: managedplugin.RegistryGrpc, Path: "localhost:7777"}, + wantToConfig: managedplugin.Config{Name: "semgrep", Registry: managedplugin.RegistryCloudQuery, Path: "cloudquery/semgrep", Version: "v3.1.0"}, + wantFrom: upgradeSourceOrigin{Registry: specs.RegistryGRPC, Path: "localhost:7777"}, + wantTo: upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: "cloudquery/semgrep"}, + wantFromVer: "v3.0.0", + }, + { + name: "docker registry starts the configured image and the hub plugin from --to-path", + metadata: specs.Metadata{Name: "semgrep", Registry: specs.RegistryDocker, Path: "ghcr.io/acme/semgrep:v3.0.0", DockerRegistryAuthToken: "secret"}, + toPath: "acme/semgrep-fork", + wantFromConfig: managedplugin.Config{Name: "semgrep", Registry: managedplugin.RegistryDocker, Path: "ghcr.io/acme/semgrep:v3.0.0", DockerAuth: "secret"}, + wantToConfig: managedplugin.Config{Name: "semgrep", Registry: managedplugin.RegistryCloudQuery, Path: "acme/semgrep-fork", Version: "v3.1.0"}, + wantFrom: upgradeSourceOrigin{Registry: specs.RegistryDocker, Path: "ghcr.io/acme/semgrep:v3.0.0"}, + wantTo: upgradeSourceOrigin{Registry: specs.RegistryCloudQuery, Path: "acme/semgrep-fork"}, + wantFromVer: "v3.0.0", + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + starter := &recordingPluginStarter{fromAddress: fromAddress, toAddress: toAddress, toVersion: "v3.1.0"} + sourceSpec := specs.Source{Metadata: tc.metadata, Spec: map[string]any{}} + + from, to, err := loadUpgradeSourceTables(t.Context(), sourceSpec, upgradeTarget{Version: "v3.1.0", Path: tc.toPath}, starter.newClient, managedplugin.WithLogger(log.Logger)) + + require.NoError(t, err) + require.Equal(t, []managedplugin.Config{tc.wantFromConfig, tc.wantToConfig}, starter.configs) + require.Equal(t, tc.wantFrom, from.Origin) + require.Equal(t, tc.wantTo, to.Origin) + require.Equal(t, tc.wantFromVer, from.Version) + require.Equal(t, "v3.1.0", to.Version) + require.Equal(t, []string{"semgrep_old"}, tableNames(from.Tables)) + require.Equal(t, []string{"semgrep_new"}, tableNames(to.Tables)) + }) + } +} + +func TestLoadUpgradeSourceTablesUnknownReportedVersion(t *testing.T) { + starter := &recordingPluginStarter{ + fromAddress: startFakeSourceServer(t, &fakeSourceServer{name: "semgrep", tables: schema.Tables{testTable("semgrep_old")}}), + toAddress: startFakeSourceServer(t, &fakeSourceServer{name: "semgrep", tables: schema.Tables{testTable("semgrep_new")}}), + toVersion: "v3.1.0", + } + sourceSpec := specs.Source{Metadata: specs.Metadata{Name: "semgrep", Registry: specs.RegistryLocal, Path: "/opt/plugins/semgrep"}} + + from, _, err := loadUpgradeSourceTables(t.Context(), sourceSpec, upgradeTarget{Version: "v3.1.0"}, starter.newClient, managedplugin.WithLogger(log.Logger)) + + require.NoError(t, err) + require.Equal(t, upgradeUnknownVersion, from.Version) +} + +func TestLoadUpgradeSourceTablesErrors(t *testing.T) { + namedAddress := startFakeSourceServer(t, &fakeSourceServer{name: "semgrep", tables: schema.Tables{testTable("semgrep_old")}}) + unnamedAddress := startFakeSourceServer(t, &fakeSourceServer{tables: schema.Tables{testTable("semgrep_old")}}) + local := specs.Metadata{Name: "semgrep", Registry: specs.RegistryLocal, Path: "/opt/plugins/semgrep"} + + cases := []struct { + name string + metadata specs.Metadata + toPath string + fromAddress string + toErr error + wantErr string + wantStarts int + }{ + { + name: "to-path with the cloudquery registry", + metadata: specs.Metadata{Name: "semgrep", Registry: specs.RegistryCloudQuery, Path: "cloudquery/semgrep", Version: "v3.0.0"}, + toPath: "cloudquery/semgrep", + wantErr: "--to-path is supported only for sources from the local, grpc or docker registry, source semgrep uses the cloudquery registry", + }, + { + name: "to-path without a team", + metadata: local, + toPath: "semgrep", + wantErr: `invalid --to-path "semgrep". Use /, for example cloudquery/aws`, + }, + { + name: "to-path with too many parts", + metadata: local, + toPath: "cloudquery/semgrep/v3", + wantErr: `invalid --to-path "cloudquery/semgrep/v3"`, + }, + { + name: "source does not report its name", + metadata: local, + fromAddress: unnamedAddress, + wantErr: "could not infer the CloudQuery Hub path to upgrade source semgrep to, because the source from the local registry did not report its name. Use --to-path / to set the path", + wantStarts: 1, + }, + { + name: "inferred hub path cannot be started", + metadata: local, + fromAddress: namedAddress, + toErr: errors.New("plugin not found"), + wantErr: "failed to start source semgrep cloudquery/semgrep@v3.1.0: plugin not found. The CloudQuery Hub path cloudquery/semgrep was inferred from the name the source reports. Use --to-path / to set a different path", + wantStarts: 2, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + starter := &recordingPluginStarter{fromAddress: tc.fromAddress, toVersion: "v3.1.0", toErr: tc.toErr} - _, _, err := loadUpgradeSourceTables(context.Background(), sourceSpec, "v2.0.0") + _, _, err := loadUpgradeSourceTables(t.Context(), specs.Source{Metadata: tc.metadata}, upgradeTarget{Version: "v3.1.0", Path: tc.toPath}, starter.newClient, managedplugin.WithLogger(log.Logger)) - require.ErrorContains(t, err, "upgrade check supports only sources from the cloudquery or github registry") + require.ErrorContains(t, err, tc.wantErr) + require.Len(t, starter.configs, tc.wantStarts) }) } } +func TestUpgradeAuthSources(t *testing.T) { + for _, registry := range []specs.Registry{specs.RegistryCloudQuery, specs.RegistryGitHub} { + sourceSpec := specs.Source{Metadata: specs.Metadata{Name: "semgrep", Registry: registry}} + require.Equal(t, []*specs.Source{&sourceSpec}, upgradeAuthSources(sourceSpec)) + } + for _, registry := range []specs.Registry{specs.RegistryLocal, specs.RegistryGRPC, specs.RegistryDocker} { + sourceSpec := specs.Source{Metadata: specs.Metadata{Name: "semgrep", Registry: registry}} + sources := upgradeAuthSources(sourceSpec) + require.Len(t, sources, 2) + require.Equal(t, specs.RegistryCloudQuery, sources[1].Registry) + } +} + func tableNames(tables schema.Tables) []string { if len(tables) == 0 { return nil diff --git a/cli/docs/reference/cloudquery_upgrade_check.md b/cli/docs/reference/cloudquery_upgrade_check.md index 56b490e2b6..cda27c94b3 100644 --- a/cli/docs/reference/cloudquery_upgrade_check.md +++ b/cli/docs/reference/cloudquery_upgrade_check.md @@ -27,6 +27,9 @@ cloudquery upgrade check [files or directories] [flags] # Check how upgrading the datadog source to v6.0.0 affects the destinations in config.yml cloudquery upgrade check ./config.yml --source datadog --to v6.0.0 +# Compare a source that runs from a local binary, gRPC server or Docker image with cloudquery/semgrep v3.1.0 from the CloudQuery Hub +cloudquery upgrade check ./config.yml --source semgrep --to v3.1.0 --to-path cloudquery/semgrep + ``` ## Options @@ -37,6 +40,7 @@ cloudquery upgrade check ./config.yml --source datadog --to v6.0.0 --output string Output format. One of: text, json (default "text") --source string Name of the source to upgrade, as set in the configuration --to string Source plugin version to upgrade to + --to-path string CloudQuery Hub path of the source plugin to upgrade to, as /. Only for sources from the local, grpc or docker registry. Default: cloudquery/ ``` ## Options inherited from parent commands From f31986406f2e8d04b6cdc5cba9827ba75dba901e Mon Sep 17 00:00:00 2001 From: "cloudquery-ci[bot]" <271027272+cloudquery-ci[bot]@users.noreply.github.com> Date: Thu, 8 Oct 2026 14:20:45 +0000 Subject: [PATCH 2/5] fix(deps): Update module github.com/cloudquery/plugin-pb-go to v1.28.1 (#23500) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [github.com/cloudquery/plugin-pb-go](https://redirect.github.com/cloudquery/plugin-pb-go) | `v1.28.0` → `v1.28.1` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fcloudquery%2fplugin-pb-go/v1.28.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fcloudquery%2fplugin-pb-go/v1.28.0/v1.28.1?slim=true) | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/22356) for more information. --- ### Release Notes
cloudquery/plugin-pb-go (github.com/cloudquery/plugin-pb-go) ### [`v1.28.1`](https://redirect.github.com/cloudquery/plugin-pb-go/releases/tag/v1.28.1) [Compare Source](https://redirect.github.com/cloudquery/plugin-pb-go/compare/v1.28.0...v1.28.1) ##### Bug Fixes - Fall back to architecture specific path for missing local plugin path ([#​708](https://redirect.github.com/cloudquery/plugin-pb-go/issues/708)) ([acc11fd](https://redirect.github.com/cloudquery/plugin-pb-go/commit/acc11fd43916d9826785f646de3ffdd9c02fbd6c))
--- ### Configuration 📅 **Schedule**: (UTC) - 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 has been generated by [Mend Renovate](https://redirect.github.com/renovatebot/renovate). --- scaffold/sourcetpl/templates/source/go.mod.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scaffold/sourcetpl/templates/source/go.mod.tpl b/scaffold/sourcetpl/templates/source/go.mod.tpl index 9f5cae4d47..6dbff18413 100644 --- a/scaffold/sourcetpl/templates/source/go.mod.tpl +++ b/scaffold/sourcetpl/templates/source/go.mod.tpl @@ -4,7 +4,7 @@ go 1.27.1 require ( github.com/apache/arrow-go/v18 v18.8.0 - github.com/cloudquery/plugin-pb-go v1.28.0 + github.com/cloudquery/plugin-pb-go v1.28.1 github.com/cloudquery/plugin-sdk/v4 v4.98.0 github.com/rs/zerolog v1.35.1 ) From d36fa8efb20d88828b0d45f80c62ed0b4ab761fa Mon Sep 17 00:00:00 2001 From: "cloudquery-ci[bot]" <271027272+cloudquery-ci[bot]@users.noreply.github.com> Date: Thu, 8 Oct 2026 14:24:06 +0000 Subject: [PATCH 3/5] fix(deps): Update module github.com/cloudquery/cloudquery/cli/v6 to v6.45.1 (#23501) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [github.com/cloudquery/cloudquery/cli/v6](https://redirect.github.com/cloudquery/cloudquery) | `v6.44.0` → `v6.45.1` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fcloudquery%2fcloudquery%2fcli%2fv6/v6.45.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fcloudquery%2fcloudquery%2fcli%2fv6/v6.44.0/v6.45.1?slim=true) | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/22356) for more information. --- ### Release Notes
cloudquery/cloudquery (github.com/cloudquery/cloudquery/cli/v6) ### [`v6.45.1`](https://redirect.github.com/cloudquery/cloudquery/releases/tag/cli-v6.45.1) [Compare Source](https://redirect.github.com/cloudquery/cloudquery/compare/v6.45.0...v6.45.1) ##### Bug Fixes - Fall back to architecture specific path for missing local plugin path ([#​23495](https://redirect.github.com/cloudquery/cloudquery/issues/23495)) ([5b261c6](https://redirect.github.com/cloudquery/cloudquery/commit/5b261c63c3e5bef1380106684acde72544491792)) ### [`v6.45.0`](https://redirect.github.com/cloudquery/cloudquery/compare/v6.44.0...v6.45.0) [Compare Source](https://redirect.github.com/cloudquery/cloudquery/compare/v6.44.0...v6.45.0)
--- ### Configuration 📅 **Schedule**: (UTC) - 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 has been generated by [Mend Renovate](https://redirect.github.com/renovatebot/renovate). --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 4c157a8b8b..0c889d019f 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/cloudquery/cloudquery/v6 go 1.27.1 -require github.com/cloudquery/cloudquery/cli/v6 v6.44.0 +require github.com/cloudquery/cloudquery/cli/v6 v6.45.1 require ( github.com/Masterminds/semver v1.5.0 // indirect @@ -20,7 +20,7 @@ require ( github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/cloudquery/cloudquery-api-go v1.14.13 // indirect - github.com/cloudquery/plugin-pb-go v1.27.24 // indirect + github.com/cloudquery/plugin-pb-go v1.28.1 // indirect github.com/cloudquery/plugin-sdk/v4 v4.98.0 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect diff --git a/go.sum b/go.sum index 2e77a742b3..5fc4a08dfd 100644 --- a/go.sum +++ b/go.sum @@ -46,12 +46,12 @@ github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJ github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/cloudquery/cloudquery-api-go v1.14.13 h1:+lu1mLKqVSwrc02eqf9vfqGj9c0RowtJowx3VCBueoY= github.com/cloudquery/cloudquery-api-go v1.14.13/go.mod h1:u4uzOBEss9hJZco/tULIZuObqiBD748kejlxZ2AqOxs= -github.com/cloudquery/cloudquery/cli/v6 v6.44.0 h1:8qumBGMifBQsB57lJBt9n1ZZ2BR5BXnxomKe/ePMEo8= -github.com/cloudquery/cloudquery/cli/v6 v6.44.0/go.mod h1:n5+gJyPTHZ47TEcY0sJZyd/2Y9U9tVxY5hSEFQ4aR1o= +github.com/cloudquery/cloudquery/cli/v6 v6.45.1 h1:p9TLEvhaukTuTmXoNRtrkTUs9ibaKM3bhZuf4bDXiV0= +github.com/cloudquery/cloudquery/cli/v6 v6.45.1/go.mod h1:5TEMx3/IFte40ulEkecjl+jCYAsRY5ugCEnKuLip+TA= github.com/cloudquery/codegen v0.4.1 h1:c9D18N925tUvnDeGHIl3JWKj37TyII9daHufkf8hU+Y= github.com/cloudquery/codegen v0.4.1/go.mod h1:QWIOD6R1aCa+YM+th+9Qt9lZw+ztdJR9JDEMLWyazwM= -github.com/cloudquery/plugin-pb-go v1.27.24 h1:WWi1Phq4yp/ONMBHb9JgTZPI1wRKGqwMP36e2OJpC2Y= -github.com/cloudquery/plugin-pb-go v1.27.24/go.mod h1:06VOdOlk5Y64CahAxQnmGy6l7PXJYm3SAwNxpEWPwn4= +github.com/cloudquery/plugin-pb-go v1.28.1 h1:ybmzSjSsptntiUeh1PCOuxYqpdtHRgYC3CaFDLtNNic= +github.com/cloudquery/plugin-pb-go v1.28.1/go.mod h1:06VOdOlk5Y64CahAxQnmGy6l7PXJYm3SAwNxpEWPwn4= github.com/cloudquery/plugin-sdk/v4 v4.98.0 h1:mghjLE1ubwVbch56WHgeu6Riec5wkFqGsgo4fDP52OY= github.com/cloudquery/plugin-sdk/v4 v4.98.0/go.mod h1:hjRfyspLbB6djHN8h+ieWP2lw4gfoHjZtorhkf0xC3Y= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= From 8d6964a9d399b7cd88f43dc15a00f53a58bcff8a Mon Sep 17 00:00:00 2001 From: "cloudquery-ci[bot]" <271027272+cloudquery-ci[bot]@users.noreply.github.com> Date: Fri, 9 Oct 2026 05:35:59 +0000 Subject: [PATCH 4/5] chore(deps): Update dependency cli to v6.45.1 (#23498) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Update | Change | |---|---|---| | [cli](https://redirect.github.com/cloudquery/cloudquery) | patch | `v6.45.0` → `v6.45.1` | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/22356) for more information. --- ### Release Notes
cloudquery/cloudquery (cli) ### [`v6.45.1`](https://redirect.github.com/cloudquery/cloudquery/releases/tag/cli-v6.45.1) [Compare Source](https://redirect.github.com/cloudquery/cloudquery/compare/cli-v6.45.0...cli-v6.45.1) ##### Bug Fixes - Fall back to architecture specific path for missing local plugin path ([#​23495](https://redirect.github.com/cloudquery/cloudquery/issues/23495)) ([5b261c6](https://redirect.github.com/cloudquery/cloudquery/commit/5b261c63c3e5bef1380106684acde72544491792))
--- ### Configuration 📅 **Schedule**: (UTC) - 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 has been generated by [Mend Renovate](https://redirect.github.com/renovatebot/renovate). --- .github/workflows/manual_commands_triggers.yml | 2 +- .github/workflows/publish_plugin_to_hub.yml | 10 +++++----- .github/workflows/publish_plugin_to_hub_duckdb.yml | 2 +- .github/workflows/publish_plugin_to_hub_fips.yml | 2 +- .github/workflows/publish_plugin_to_hub_snowflake.yml | 2 +- .github/workflows/publish_plugin_to_hub_sqlite.yml | 2 +- .github/workflows/publish_ui_dir.yml | 2 +- .github/workflows/source_hackernews.yml | 2 +- .github/workflows/source_test.yml | 2 +- .github/workflows/source_xkcd.yml | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/manual_commands_triggers.yml b/.github/workflows/manual_commands_triggers.yml index 5a6075fd27..26b733700a 100644 --- a/.github/workflows/manual_commands_triggers.yml +++ b/.github/workflows/manual_commands_triggers.yml @@ -42,7 +42,7 @@ jobs: - name: Setup CloudQuery uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: Set up Go 1.x id: setup-go diff --git a/.github/workflows/publish_plugin_to_hub.yml b/.github/workflows/publish_plugin_to_hub.yml index 0fae320f34..1e2451c8d5 100644 --- a/.github/workflows/publish_plugin_to_hub.yml +++ b/.github/workflows/publish_plugin_to_hub.yml @@ -131,7 +131,7 @@ jobs: if: needs.prepare.outputs.ui_dir_arg != '' uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: Build working-directory: ${{ needs.prepare.outputs.plugin_dir }} @@ -256,7 +256,7 @@ jobs: - name: Setup CloudQuery uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: Publish plugin to hub working-directory: ${{ needs.prepare.outputs.plugin_dir }} @@ -358,7 +358,7 @@ jobs: - name: Setup CloudQuery uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: Publish plugin to hub working-directory: ${{ needs.prepare.outputs.plugin_dir }} @@ -457,7 +457,7 @@ jobs: - name: Setup CloudQuery uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: Publish plugin to hub working-directory: ${{ needs.prepare.outputs.plugin_dir }} @@ -561,7 +561,7 @@ jobs: - name: Setup CloudQuery uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: Publish plugin to hub working-directory: ${{ needs.prepare.outputs.plugin_dir }} diff --git a/.github/workflows/publish_plugin_to_hub_duckdb.yml b/.github/workflows/publish_plugin_to_hub_duckdb.yml index 1ecc0b7654..e134d7d839 100644 --- a/.github/workflows/publish_plugin_to_hub_duckdb.yml +++ b/.github/workflows/publish_plugin_to_hub_duckdb.yml @@ -161,7 +161,7 @@ jobs: - name: Setup CloudQuery uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: Publish plugin to hub working-directory: ${{ needs.prepare.outputs.plugin_dir }} diff --git a/.github/workflows/publish_plugin_to_hub_fips.yml b/.github/workflows/publish_plugin_to_hub_fips.yml index 978e743edc..b5e43b6e71 100644 --- a/.github/workflows/publish_plugin_to_hub_fips.yml +++ b/.github/workflows/publish_plugin_to_hub_fips.yml @@ -121,7 +121,7 @@ jobs: - name: Setup CloudQuery uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: Publish plugin to hub working-directory: ${{ needs.prepare.outputs.plugin_dir }} diff --git a/.github/workflows/publish_plugin_to_hub_snowflake.yml b/.github/workflows/publish_plugin_to_hub_snowflake.yml index a4459a1424..f662b0f99a 100644 --- a/.github/workflows/publish_plugin_to_hub_snowflake.yml +++ b/.github/workflows/publish_plugin_to_hub_snowflake.yml @@ -163,7 +163,7 @@ jobs: - name: Setup CloudQuery uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: Publish plugin to hub working-directory: ${{ needs.prepare.outputs.plugin_dir }} diff --git a/.github/workflows/publish_plugin_to_hub_sqlite.yml b/.github/workflows/publish_plugin_to_hub_sqlite.yml index f5e00fd2e4..c1ca595c8c 100644 --- a/.github/workflows/publish_plugin_to_hub_sqlite.yml +++ b/.github/workflows/publish_plugin_to_hub_sqlite.yml @@ -161,7 +161,7 @@ jobs: - name: Setup CloudQuery uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: Publish plugin to hub working-directory: ${{ needs.prepare.outputs.plugin_dir }} diff --git a/.github/workflows/publish_ui_dir.yml b/.github/workflows/publish_ui_dir.yml index 6560833862..10c4a81933 100644 --- a/.github/workflows/publish_ui_dir.yml +++ b/.github/workflows/publish_ui_dir.yml @@ -102,7 +102,7 @@ jobs: - name: Setup CloudQuery uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: Build UI for ${{ matrix.plugin.dir }} working-directory: ${{ matrix.plugin.ui }} diff --git a/.github/workflows/source_hackernews.yml b/.github/workflows/source_hackernews.yml index 223310cdcc..c5adadf2ce 100644 --- a/.github/workflows/source_hackernews.yml +++ b/.github/workflows/source_hackernews.yml @@ -55,7 +55,7 @@ jobs: if: github.event_name == 'pull_request' uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: gen if: github.event_name == 'pull_request' run: make gen diff --git a/.github/workflows/source_test.yml b/.github/workflows/source_test.yml index d21c9ebe80..5354f421a0 100644 --- a/.github/workflows/source_test.yml +++ b/.github/workflows/source_test.yml @@ -55,7 +55,7 @@ jobs: if: github.event_name == 'pull_request' uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: gen if: github.event_name == 'pull_request' run: make gen diff --git a/.github/workflows/source_xkcd.yml b/.github/workflows/source_xkcd.yml index ef077d46c7..f9db5f62d7 100644 --- a/.github/workflows/source_xkcd.yml +++ b/.github/workflows/source_xkcd.yml @@ -55,7 +55,7 @@ jobs: if: github.event_name == 'pull_request' uses: cloudquery/setup-cloudquery@757b19eb8496cf9e89a78de54f2c677253f54f6b # v5.0.3 with: - version: v6.45.0 + version: v6.45.1 - name: gen if: github.event_name == 'pull_request' run: make gen From 1889351e93c7d6e06744e73f8f5aab54243d4cf8 Mon Sep 17 00:00:00 2001 From: "cloudquery-ci[bot]" <271027272+cloudquery-ci[bot]@users.noreply.github.com> Date: Fri, 9 Oct 2026 05:52:41 +0000 Subject: [PATCH 5/5] chore(main): Release cli v6.46.0 (#23499) :robot: I have created a release *beep* *boop* --- ## [6.46.0](https://github.com/cloudquery/cloudquery/compare/cli-v6.45.1...cli-v6.46.0) (2026-10-09) ### Features * Support local, gRPC and Docker sources in `upgrade check` ([#23497](https://github.com/cloudquery/cloudquery/issues/23497)) ([a45a119](https://github.com/cloudquery/cloudquery/commit/a45a11980e480fcabdcbb501413c7f31149094cd)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 2 +- cli/CHANGELOG.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 81c08d8a9e..0b9b4ea66d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,5 +1,5 @@ { - "cli": "6.45.1", + "cli": "6.46.0", "cli+FILLER": "0.0.0", "plugins/source/aws": "22.19.2", "plugins/source/aws+FILLER": "0.0.0", diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index ce75de3888..0547457845 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to CloudQuery will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [6.46.0](https://github.com/cloudquery/cloudquery/compare/cli-v6.45.1...cli-v6.46.0) (2026-10-09) + + +### Features + +* Support local, gRPC and Docker sources in `upgrade check` ([#23497](https://github.com/cloudquery/cloudquery/issues/23497)) ([a45a119](https://github.com/cloudquery/cloudquery/commit/a45a11980e480fcabdcbb501413c7f31149094cd)) + ## [6.45.1](https://github.com/cloudquery/cloudquery/compare/cli-v6.45.0...cli-v6.45.1) (2026-10-08)