diff --git a/pkg/cloudql/client/artifact_vulnerabilities.go b/pkg/cloudql/client/artifact_vulnerabilities.go new file mode 100644 index 000000000..a723e1e8d --- /dev/null +++ b/pkg/cloudql/client/artifact_vulnerabilities.go @@ -0,0 +1,190 @@ +package opengovernance_client + +import ( + "context" + "runtime" + + steampipesdk "github.com/opengovern/og-util/pkg/steampipe" + + es "github.com/opengovern/og-util/pkg/opengovernance-es-sdk" + "github.com/opengovern/opencomply/pkg/cloudql/sdk/config" + "github.com/turbot/steampipe-plugin-sdk/v5/plugin" +) + +const ( + ArtifactVulnerabilitiesIndex = "oci_container_vulnerabilities" +) + +type OciArtifactVulnerabilities struct { + ImageURL string `json:"imageUrl"` + ArtifactDigest string `json:"artifactDigest"` + Vulnerabilities []VulnerabilityMatch `json:"Vulnerabilities"` +} + +type GrypeOutput struct { + Matches []VulnerabilityMatch `json:"matches"` +} + +type VulnerabilityMatch struct { + Vulnerability Vulnerability `json:"vulnerability"` + RelatedVulnerabilities []Vulnerability `json:"relatedVulnerabilities"` + MatchDetail interface{} `json:"matchDetail"` + Artifact interface{} `json:"artifact"` +} + +type Vulnerability struct { + ID string `json:"id"` + DataSource string `json:"dataSource"` + Namespace string `json:"namespace"` + Severity string `json:"severity"` + URLs []string `json:"urls"` + Description string `json:"description"` + CVSs []VulnerabilityCVS `json:"cvss"` + Fix VulnerabilityFix `json:"fix"` + Advisories interface{} `json:"advisories"` +} + +type VulnerabilityCVS struct { + Source string `json:"source"` + Type string `json:"type"` + Version string `json:"version"` + Vector string `json:"vector"` + Metrics map[string]string `json:"metrics"` + VendorMetadata map[string]string `json:"vendorMetadata"` +} + +type VulnerabilityFix struct { + Versions []string `json:"versions"` + State string `json:"state"` +} + +type OciArtifactVulnerabilitiesHit struct { + ID string `json:"_id"` + Score float64 `json:"_score"` + Index string `json:"_index"` + Type string `json:"_type"` + Version int64 `json:"_version,omitempty"` + Source OciArtifactVulnerabilities `json:"_source"` + Sort []any `json:"sort"` +} + +type OciArtifactVulnerabilitiesHits struct { + Total es.SearchTotal `json:"total"` + Hits []OciArtifactVulnerabilitiesHit `json:"hits"` +} + +type OciArtifactVulnerabilitiesSearchResponse struct { + PitID string `json:"pit_id"` + Hits OciArtifactVulnerabilitiesHits `json:"hits"` +} + +type OciArtifactVulnerabilitiesPaginator struct { + paginator *es.BaseESPaginator +} + +func (k Client) NewOciArtifactVulnerabilitiesPaginator(filters []es.BoolFilter, limit *int64) (OciArtifactVulnerabilitiesPaginator, error) { + paginator, err := es.NewPaginator(k.ES.ES(), ArtifactVulnerabilitiesIndex, filters, limit) + if err != nil { + return OciArtifactVulnerabilitiesPaginator{}, err + } + + p := OciArtifactVulnerabilitiesPaginator{ + paginator: paginator, + } + + return p, nil +} + +func (p OciArtifactVulnerabilitiesPaginator) HasNext() bool { + return !p.paginator.Done() +} + +func (p OciArtifactVulnerabilitiesPaginator) Close(ctx context.Context) error { + return p.paginator.Deallocate(ctx) +} + +func (p OciArtifactVulnerabilitiesPaginator) NextPage(ctx context.Context) ([]OciArtifactVulnerabilities, error) { + var response OciArtifactVulnerabilitiesSearchResponse + err := p.paginator.SearchWithLog(ctx, &response, true) + if err != nil { + return nil, err + } + + var values []OciArtifactVulnerabilities + for _, hit := range response.Hits.Hits { + values = append(values, hit.Source) + } + + hits := int64(len(response.Hits.Hits)) + if hits > 0 { + p.paginator.UpdateState(hits, response.Hits.Hits[hits-1].Sort, response.PitID) + } else { + p.paginator.UpdateState(hits, nil, "") + } + + return values, nil +} + +var artifactVulnerabilitiesMapping = map[string]string{ + "image_url": "imageUrl", + "artifact_digest": "artifactDigest", +} + +func ListArtifactVulnerabilities(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (any, error) { + plugin.Logger(ctx).Trace("ListArtifactVulnerabilities", d) + runtime.GC() + // create service + cfg := config.GetConfig(d.Connection) + ke, err := config.NewClientCached(cfg, d.ConnectionCache, ctx) + if err != nil { + plugin.Logger(ctx).Error("ListArtifactVulnerabilities NewClientCached", "error", err) + return nil, err + } + k := Client{ES: ke} + + sc, err := steampipesdk.NewSelfClientCached(ctx, d.ConnectionCache) + if err != nil { + plugin.Logger(ctx).Error("ListArtifactVulnerabilities NewSelfClientCached", "error", err) + return nil, err + } + encodedResourceCollectionFilters, err := sc.GetConfigTableValueOrNil(ctx, steampipesdk.OpenGovernanceConfigKeyResourceCollectionFilters) + if err != nil { + plugin.Logger(ctx).Error("ListLookupResources GetConfigTableValueOrNil for resource_collection_filters", "error", err) + return nil, err + } + clientType, err := sc.GetConfigTableValueOrNil(ctx, steampipesdk.OpenGovernanceConfigKeyClientType) + if err != nil { + plugin.Logger(ctx).Error("ListLookupResources GetConfigTableValueOrNil for client_type", "error", err) + return nil, err + } + + plugin.Logger(ctx).Trace("Columns", d.FetchType) + paginator, err := k.NewOciArtifactVulnerabilitiesPaginator( + es.BuildFilterWithDefaultFieldName(ctx, d.QueryContext, artifactVulnerabilitiesMapping, + nil, encodedResourceCollectionFilters, clientType, true), + d.QueryContext.Limit) + if err != nil { + plugin.Logger(ctx).Error("ListArtifactVulnerabilities NewOciArtifactVulnerabilitiesPaginator", "error", err) + return nil, err + } + + for paginator.HasNext() { + page, err := paginator.NextPage(ctx) + if err != nil { + plugin.Logger(ctx).Error("ListArtifactVulnerabilities NextPage", "error", err) + return nil, err + } + plugin.Logger(ctx).Trace("ListArtifactVulnerabilities", "next page") + + for _, v := range page { + d.StreamListItem(ctx, v) + } + } + + err = paginator.Close(ctx) + if err != nil { + return nil, err + } + + return nil, nil +} diff --git a/pkg/cloudql/client/resource.go b/pkg/cloudql/client/resource.go index 1ee26cca2..668c3e6a2 100644 --- a/pkg/cloudql/client/resource.go +++ b/pkg/cloudql/client/resource.go @@ -110,12 +110,15 @@ func (p ResourcePaginator) NextPage(ctx context.Context) ([]Resource, error) { } var resourceMapping = map[string]string{ - "resource_id": "id", - "resource_arn": "arn", - "connector": "source_type", - "region": "location", - "connection_id": "source_id", - "name": "metadata.Name", + "platform_id": "platform_id", + "resource_id": "resource_id", + "integration_id": "integration_id", + "integration_type": "integration_type", + "resource_type": "resource_type", + "resource_name": "resource_name", + "described_by": "described_by", + "described_at": "described_at", + "name": "metadata.Name", } var resourceTypeMap = map[string]string{ diff --git a/pkg/cloudql/tables/plugin.go b/pkg/cloudql/tables/plugin.go index 2349a4d3a..903b72ba1 100644 --- a/pkg/cloudql/tables/plugin.go +++ b/pkg/cloudql/tables/plugin.go @@ -18,13 +18,14 @@ func Plugin(ctx context.Context) *plugin.Plugin { Schema: config.Schema(), }, TableMap: map[string]*plugin.Table{ - "platform_findings": tablePlatformFindings(ctx), - "platform_resources": tablePlatformResources(ctx), - "platform_lookup": tablePlatformLookup(ctx), - "platform_integrations": tablePlatformConnections(ctx), - "platform_integration_groups": tablePlatformIntegrationGroups(ctx), - "platform_api_benchmark_summary": tablePlatformApiBenchmarkSummary(ctx), - "platform_api_benchmark_controls": tablePlatformApiBenchmarkControls(ctx), + "platform_findings": tablePlatformFindings(ctx), + "platform_resources": tablePlatformResources(ctx), + "platform_lookup": tablePlatformLookup(ctx), + "platform_integrations": tablePlatformConnections(ctx), + "platform_integration_groups": tablePlatformIntegrationGroups(ctx), + "platform_api_benchmark_summary": tablePlatformApiBenchmarkSummary(ctx), + "platform_api_benchmark_controls": tablePlatformApiBenchmarkControls(ctx), + "platform_artifact_vulnerabilities": tablePlatformArtifactVulnerabilities(ctx), }, } diff --git a/pkg/cloudql/tables/table_opengovernance_api_benchmark_controls.go b/pkg/cloudql/tables/table_platform_api_benchmark_controls.go similarity index 100% rename from pkg/cloudql/tables/table_opengovernance_api_benchmark_controls.go rename to pkg/cloudql/tables/table_platform_api_benchmark_controls.go diff --git a/pkg/cloudql/tables/table_opengovernance_api_benchmark_summary.go b/pkg/cloudql/tables/table_platform_api_benchmark_summary.go similarity index 100% rename from pkg/cloudql/tables/table_opengovernance_api_benchmark_summary.go rename to pkg/cloudql/tables/table_platform_api_benchmark_summary.go diff --git a/pkg/cloudql/tables/table_platform_artifact_vulnerabilities.go b/pkg/cloudql/tables/table_platform_artifact_vulnerabilities.go new file mode 100644 index 000000000..728b8a2a7 --- /dev/null +++ b/pkg/cloudql/tables/table_platform_artifact_vulnerabilities.go @@ -0,0 +1,40 @@ +package opengovernance + +import ( + "context" + "github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform" + + og_client "github.com/opengovern/opencomply/pkg/cloudql/client" + "github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto" + "github.com/turbot/steampipe-plugin-sdk/v5/plugin" +) + +func tablePlatformArtifactVulnerabilities(_ context.Context) *plugin.Table { + return &plugin.Table{ + Name: "platform_artifact_vulnerabilities", + Description: "Platform Artifact Vulnerabilities", + Cache: &plugin.TableCacheOptions{ + Enabled: false, + }, + List: &plugin.ListConfig{ + Hydrate: og_client.ListArtifactVulnerabilities, + }, + Columns: []*plugin.Column{ + { + Name: "image_url", + Transform: transform.FromQual("imageUrl"), + Type: proto.ColumnType_STRING, + }, + { + Name: "artifact_digest", + Transform: transform.FromQual("artifactDigest"), + Type: proto.ColumnType_STRING, + }, + { + Name: "vulnerabilities", + Transform: transform.FromQual("Vulnerabilities"), + Type: proto.ColumnType_JSON, + }, + }, + } +} diff --git a/pkg/cloudql/tables/table_opengovernance_findings.go b/pkg/cloudql/tables/table_platform_findings.go similarity index 100% rename from pkg/cloudql/tables/table_opengovernance_findings.go rename to pkg/cloudql/tables/table_platform_findings.go diff --git a/pkg/cloudql/tables/table_opengovernance_integration_groups.go b/pkg/cloudql/tables/table_platform_integration_groups.go similarity index 100% rename from pkg/cloudql/tables/table_opengovernance_integration_groups.go rename to pkg/cloudql/tables/table_platform_integration_groups.go diff --git a/pkg/cloudql/tables/table_opengovernance_integrations.go b/pkg/cloudql/tables/table_platform_integrations.go similarity index 100% rename from pkg/cloudql/tables/table_opengovernance_integrations.go rename to pkg/cloudql/tables/table_platform_integrations.go diff --git a/pkg/cloudql/tables/table_opengovernance_lookup.go b/pkg/cloudql/tables/table_platform_lookup.go similarity index 100% rename from pkg/cloudql/tables/table_opengovernance_lookup.go rename to pkg/cloudql/tables/table_platform_lookup.go diff --git a/pkg/cloudql/tables/table_opengovernance_resources.go b/pkg/cloudql/tables/table_platform_resources.go similarity index 100% rename from pkg/cloudql/tables/table_opengovernance_resources.go rename to pkg/cloudql/tables/table_platform_resources.go