Skip to content
This repository has been archived by the owner on Jul 28, 2023. It is now read-only.

Add table turbot_grant closes #12 #15

Merged
merged 19 commits into from
Jan 24, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions turbot/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func Plugin(ctx context.Context) *plugin.Plugin {
TableMap: map[string]*plugin.Table{
"turbot_control": tableTurbotControl(ctx),
"turbot_control_type": tableTurbotControlType(ctx),
"turbot_grant": tableTurbotGrant(ctx),
"turbot_policy_setting": tableTurbotPolicySetting(ctx),
"turbot_policy_type": tableTurbotPolicyType(ctx),
"turbot_resource": tableTurbotResource(ctx),
Expand Down
218 changes: 218 additions & 0 deletions turbot/table_turbot_grant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package turbot

import (
"context"
"fmt"
"regexp"
"strconv"

"github.com/turbot/steampipe-plugin-sdk/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/plugin"
"github.com/turbot/steampipe-plugin-sdk/plugin/transform"
)

func tableTurbotGrant(ctx context.Context) *plugin.Table {
return &plugin.Table{
Name: "turbot_grant",
Description: "All grants of resources by Turbot.",
List: &plugin.ListConfig{
KeyColumns: []*plugin.KeyColumn{
{Name: "id", Require: plugin.Optional},
},
Hydrate: listGrants,
},
Columns: []*plugin.Column{
// Top columns
{Name: "id", Type: proto.ColumnType_INT, Transform: transform.FromField("Turbot.ID"), Description: "Unique identifier of the grantee."},
{Name: "grantee_status", Type: proto.ColumnType_STRING, Transform: transform.FromField("Identity.Status"), Description: "Status of the grantee."},
bigdatasourav marked this conversation as resolved.
Show resolved Hide resolved
{Name: "grant_status", Type: proto.ColumnType_STRING, Transform: transform.FromField("Status"), Description: "Status of the grant."},
{Name: "display_name", Type: proto.ColumnType_STRING, Transform: transform.FromField("Identity.DisplayName"), Description: "Display name of the grantee."},
bigdatasourav marked this conversation as resolved.
Show resolved Hide resolved
{Name: "email", Type: proto.ColumnType_STRING, Transform: transform.FromField("Identity.Email"), Description: "Email identity for the grantee."},
{Name: "family_name", Type: proto.ColumnType_STRING, Transform: transform.FromField("Identity.FamilyName"), Description: "Family name of the grantee."},
{Name: "given_name", Type: proto.ColumnType_STRING, Transform: transform.FromField("Identity.GivenName"), Description: "Given name of the grantee."},
{Name: "grant_identity_trunk_title", Type: proto.ColumnType_STRING, Transform: transform.FromField("Identity.Trunk.Title"), Description: "Full title (including ancestor trunk) of the grant identity."},
bigdatasourav marked this conversation as resolved.
Show resolved Hide resolved
{Name: "grant_type_trunk_title", Type: proto.ColumnType_STRING, Transform: transform.FromField("Type.Trunk.Title"), Description: "Full title (including ancestor trunk) of the grant type."},
bigdatasourav marked this conversation as resolved.
Show resolved Hide resolved
{Name: "grant_type_uri", Type: proto.ColumnType_STRING, Transform: transform.FromField("Type.URI"), Description: "URI of the grant type."},
bigdatasourav marked this conversation as resolved.
Show resolved Hide resolved
{Name: "last_login_timestamp", Type: proto.ColumnType_TIMESTAMP, Transform: transform.FromField("Identity.LastLoginTimestamp"), Description: "Last login timestamp for the login."},
bigdatasourav marked this conversation as resolved.
Show resolved Hide resolved
{Name: "level_title", Type: proto.ColumnType_STRING, Transform: transform.FromField("Level.Title"), Description: "The title of the level."},
{Name: "level_trunk_title", Type: proto.ColumnType_STRING, Transform: transform.FromField("Level.Trunk.Title"), Description: "Full title (including ancestor trunk) of the level."},
{Name: "level_uri", Type: proto.ColumnType_STRING, Transform: transform.FromField("Level.URI"), Description: "The URI of the level."},
{Name: "profile_id", Type: proto.ColumnType_STRING, Transform: transform.FromField("Identity.ProfileID"), Description: "Profile id of the grantee."},
bigdatasourav marked this conversation as resolved.
Show resolved Hide resolved
{Name: "resource_trunk_title", Type: proto.ColumnType_STRING, Transform: transform.FromField("Resource.Trunk.Title"), Description: "Full title (including ancestor trunk) of the resource."},
{Name: "resource_type_uri", Type: proto.ColumnType_STRING, Transform: transform.FromField("Resource.Type.URI"), Description: "URI of the resource type."},
{Name: "akas", Type: proto.ColumnType_JSON, Transform: transform.FromField("Identity.Akas"), Description: "AKA (also known as) identifiers for the grantee"},
bigdatasourav marked this conversation as resolved.
Show resolved Hide resolved
// Other columns
{Name: "create_timestamp", Type: proto.ColumnType_TIMESTAMP, Transform: transform.FromField("Turbot.CreateTimestamp").NullIfEqual(""), Description: "The create time of grant."},
{Name: "filter", Type: proto.ColumnType_STRING, Transform: transform.FromQual("filter"), Description: "Filter used for this grant list."},
{Name: "timestamp", Type: proto.ColumnType_TIMESTAMP, Transform: transform.FromField("Turbot.Timestamp").NullIfEqual(""), Description: "Timestamp when the grant was last modified (created, updated or deleted)."},
{Name: "update_timestamp", Type: proto.ColumnType_TIMESTAMP, Transform: transform.FromField("Turbot.UpdateTimestamp"), Description: "When the tag grant last updated in Turbot."},
{Name: "version_id", Type: proto.ColumnType_INT, Transform: transform.FromField("Turbot.VersionID").NullIfEqual(""), Description: "Unique identifier for this version of the grantee."},
{Name: "workspace", Type: proto.ColumnType_STRING, Hydrate: plugin.HydrateFunc(getTurbotWorkspace).WithCache(), Transform: transform.FromValue(), Description: "Specifies the workspace URL."},
},
}
}

const (
grants = `
query PermissionsByIdentity($filter: [String!], $paging: String) {
permissionsDetails: permissionsDetailsByIdentity(filter: $filter, paging: $paging) {
items {
permissions {
grants {
resource {
akas
title
trunk {
title
}
type {
uri
trunk {
title
}
}
}
identity {
akas
email: get(path: "email")
status: get(path: "status")
givenName: get(path: "givenName")
profileId: get(path: "profileId")
familyName: get(path: "familyName")
displayName: get(path: "displayName")
lastLoginTimestamp: get(path: "lastLoginTimestamp")
trunk {
title
}
}
type {
category
categoryUri
modUri
trunk {
title
}
uri
}
level {
title
uri
trunk {
title
}
}
turbot {
id
createTimestamp
deleteTimestamp
profileId
timestamp
updateTimestamp
versionId
}
}
activeGrants {
grant {
turbot {
id
}
}
}
}
}
paging {
next
}
}
}
`
)

func listGrants(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) {
conn, err := connect(ctx, d)
if err != nil {
plugin.Logger(ctx).Error("turbot_grants.listGrants", "connection_error", err)
return nil, err
}

filters := []string{}
quals := d.KeyColumnQuals

filter := ""
if quals["filter"] != nil {
filter = quals["filter"].GetStringValue()
filters = append(filters, filter)
}

// Additional filters
if quals["id"] != nil {
filters = append(filters, fmt.Sprintf("id:%s", getQualListValues(ctx, quals, "id", "int64")))
}

// Default to a very large page size. Page sizes earlier in the filter string
// win, so this is only used as a fallback.
pageResults := false
// Add a limit if they haven't given one in the filter field
re := regexp.MustCompile(`(^|\s)limit:[0-9]+($|\s)`)
if !re.MatchString(filter) {
// The caller did not specify a limit, so set a high limit and page all
// results.
pageResults = true
var pageLimit int64 = 5000

// Adjust page limit, if less than default value
limit := d.QueryContext.Limit
if d.QueryContext.Limit != nil {
if *limit < pageLimit {
pageLimit = *limit
}
}
filters = append(filters, fmt.Sprintf("limit:%s", strconv.Itoa(int(pageLimit))))
}

plugin.Logger(ctx).Trace("turbot_grants.listGrants", "quals", quals)
plugin.Logger(ctx).Trace("turbot_grants.listGrants", "filters", filters)

nextToken := ""
for {
result := &PermissionByIdentityResponse{}
err = conn.DoRequest(grants, map[string]interface{}{"filter": filters, "next_token": nextToken}, result)
if err != nil {
plugin.Logger(ctx).Error("turbot_grants.listGrants", "query_error", err)
}
for _, grantDetails := range result.PermissionsDetails.Items {
for _, permission := range grantDetails.Permissions {
for _, grant := range permission.Grants {
grantStatus := getGrantStatus(grant, permission.ActiveGrants)
grant.Status = grantStatus

d.StreamListItem(ctx, grant)
}
}

// Context can be cancelled due to manual cancellation or the limit has been hit
if d.QueryStatus.RowsRemaining(ctx) == 0 {
return nil, nil
}
}
if !pageResults || result.PermissionsDetails.Paging.Next == "" {
break
}
nextToken = result.PermissionsDetails.Paging.Next
}

return nil, nil
}

//// TRANSFORM FUNCTION

func getGrantStatus(grant Grant, activeGrants []ActiveGrant) (status string) {
status = "InActive"
for _, activeGrantDetails := range activeGrants {
if grant.Turbot.ID == activeGrantDetails.Grant.Turbot.ID {
status = "Active"
break
}
}
return status
}
76 changes: 76 additions & 0 deletions turbot/types.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package turbot

import "time"

type ResourcesResponse struct {
Resources struct {
Items []Resource
Expand Down Expand Up @@ -97,6 +99,79 @@ type ControlType struct {
URI string
}

type PermissionByIdentityResponse struct {
PermissionsDetails struct {
Items []GrantDetails
Paging struct {
Next string
}
}
}

type GrantDetails struct {
Permissions []Permission
}

type Permission struct {
Grants []Grant
ActiveGrants []ActiveGrant
}

type ActiveGrant struct {
Grant struct {
Turbot struct {
ID string
}
}
}

type Grant struct {
Resource struct {
Akas []string
Title string
Trunk struct {
Title string
}
Type struct {
URI string
Trunk struct {
Title string
}
}
}
Identity struct {
Akas []string
Email string
Status string
GivenName string
ProfileID string
FamilyName string
DisplayName string
LastLoginTimestamp *time.Time
Trunk struct {
Title string
}
}
Type struct {
CategoriUri string
Category string
ModUri string
Trunk struct {
Title string
}
URI string
}
Level struct {
Title string
URI string
Trunk struct {
Title string
}
}
Turbot TurbotControlMetadata
Status string
}

type PolicyTypesResponse struct {
PolicyTypes struct {
Items []PolicyType
Expand Down Expand Up @@ -207,6 +282,7 @@ type TurbotControlMetadata struct {
ControlTypeID string
ResourceID string
ResourceTypeID string
Status string
}

type PolicySettingsResponse struct {
Expand Down