Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

APP-5079 : Manage Policies #83

Merged
merged 6 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions atlan/assets/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ type AssetFields struct {
VIEWER_GROUPS *KeywordField
CONNECTOR_NAME *KeywordTextField
CONNECTION_NAME *KeywordTextField
CONNECTION_QUALIFIED_NAME *KeywordTextField
}

type CatalogFields struct {
Expand Down Expand Up @@ -366,6 +367,7 @@ func NewSearchTable() *AtlasTableFields {
VIEWER_USERS: NewKeywordField("viewerUsers", "viewerUsers"),
VIEWER_GROUPS: NewKeywordField("viewerGroups", "viewerGroups"),
CONNECTOR_NAME: NewKeywordTextField("connectorName", "connectorName", "connectorName.text"),
CONNECTION_QUALIFIED_NAME: NewKeywordTextField("connectionQualifiedName", "connectionQualifiedName", "connectionQualifiedName.text"),
},
INPUT_TO_PROCESSES: NewRelationField("inputToProcesses"),
OUTPUT_FROM_AIRFLOW_TASKS: NewRelationField("outputFromAirflowTasks"),
Expand Down Expand Up @@ -432,6 +434,7 @@ func NewSearchColumn() *ColumnFields {
VIEWER_USERS: NewKeywordField("viewerUsers", "viewerUsers"),
VIEWER_GROUPS: NewKeywordField("viewerGroups", "viewerGroups"),
CONNECTOR_NAME: NewKeywordTextField("connectorName", "connectorName", "connectorName.text"),
CONNECTION_QUALIFIED_NAME: NewKeywordTextField("connectionQualifiedName", "connectionQualifiedName", "connectionQualifiedName.text"),
},
INPUT_TO_PROCESSES: NewRelationField("inputToProcesses"),
OUTPUT_FROM_AIRFLOW_TASKS: NewRelationField("outputFromAirflowTasks"),
Expand Down Expand Up @@ -561,6 +564,7 @@ func NewSearchConnection() *ConnectionFields {
VIEWER_USERS: NewKeywordField("viewerUsers", "viewerUsers"),
VIEWER_GROUPS: NewKeywordField("viewerGroups", "viewerGroups"),
CONNECTOR_NAME: NewKeywordTextField("connectorName", "connectorName", "connectorName.text"),
CONNECTION_QUALIFIED_NAME: NewKeywordTextField("connectionQualifiedName", "connectionQualifiedName", "connectionQualifiedName.text"),
},
CATEGORY: NewKeywordField("category", "category"),
SUB_CATEGORY: NewKeywordField("subCategory", "subCategory"),
Expand Down Expand Up @@ -628,6 +632,7 @@ func NewSearchGlossary() *AtlasGlossaryFields {
VIEWER_USERS: NewKeywordField("viewerUsers", "viewerUsers"),
VIEWER_GROUPS: NewKeywordField("viewerGroups", "viewerGroups"),
CONNECTOR_NAME: NewKeywordTextField("connectorName", "connectorName", "connectorName.text"),
CONNECTION_QUALIFIED_NAME: NewKeywordTextField("connectionQualifiedName", "connectionQualifiedName", "connectionQualifiedName.text"),
},
}
}
Expand Down Expand Up @@ -669,6 +674,7 @@ func NewSearchMaterialisedView() *MaterialisedViewFields {
VIEWER_USERS: NewKeywordField("viewerUsers", "viewerUsers"),
VIEWER_GROUPS: NewKeywordField("viewerGroups", "viewerGroups"),
CONNECTOR_NAME: NewKeywordTextField("connectorName", "connectorName", "connectorName.text"),
CONNECTION_QUALIFIED_NAME: NewKeywordTextField("connectionQualifiedName", "connectionQualifiedName", "connectionQualifiedName.text"),
},
INPUT_TO_PROCESSES: NewRelationField("inputToProcesses"),
OUTPUT_FROM_AIRFLOW_TASKS: NewRelationField("outputFromAirflowTasks"),
Expand Down Expand Up @@ -749,6 +755,7 @@ func NewSearchView() *ViewFields {
VIEWER_USERS: NewKeywordField("viewerUsers", "viewerUsers"),
VIEWER_GROUPS: NewKeywordField("viewerGroups", "viewerGroups"),
CONNECTOR_NAME: NewKeywordTextField("connectorName", "connectorName", "connectorName.text"),
CONNECTION_QUALIFIED_NAME: NewKeywordTextField("connectionQualifiedName", "connectionQualifiedName", "connectionQualifiedName.text"),
},
INPUT_TO_PROCESSES: NewRelationField("inputToProcesses"),
OUTPUT_FROM_AIRFLOW_TASKS: NewRelationField("outputFromAirflowTasks"),
Expand Down Expand Up @@ -835,6 +842,7 @@ func NewAccessControlFields() *AccessControlFields {
VIEWER_USERS: NewKeywordField("viewerUsers", "viewerUsers"),
VIEWER_GROUPS: NewKeywordField("viewerGroups", "viewerGroups"),
CONNECTOR_NAME: NewKeywordTextField("connectorName", "connectorName", "connectorName.text"),
CONNECTION_QUALIFIED_NAME: NewKeywordTextField("connectionQualifiedName", "connectionQualifiedName", "connectionQualifiedName.text"),
},
}
}
Expand Down Expand Up @@ -886,6 +894,7 @@ func NewPersonaFields() *PersonaFields {
VIEWER_USERS: NewKeywordField("viewerUsers", "viewerUsers"),
VIEWER_GROUPS: NewKeywordField("viewerGroups", "viewerGroups"),
CONNECTOR_NAME: NewKeywordTextField("connectorName", "connectorName", "connectorName.text"),
CONNECTION_QUALIFIED_NAME: NewKeywordTextField("connectionQualifiedName", "connectionQualifiedName", "connectionQualifiedName.text"),
},
},
PERSONA_GROUPS: NewKeywordField("personaGroups", "personaGroups"),
Expand Down Expand Up @@ -930,6 +939,7 @@ func NewAuthPolicyFields() *AuthPolicyFields {
VIEWER_USERS: NewKeywordField("viewerUsers", "viewerUsers"),
VIEWER_GROUPS: NewKeywordField("viewerGroups", "viewerGroups"),
CONNECTOR_NAME: NewKeywordTextField("connectorName", "connectorName", "connectorName.text"),
CONNECTION_QUALIFIED_NAME: NewKeywordTextField("connectionQualifiedName", "connectionQualifiedName", "connectionQualifiedName.text"),
},
POLICY_TYPE: NewKeywordField("policyType", "policyType"),
POLICY_SERVICE_NAME: NewKeywordField("policyServiceName", "policyServiceName"),
Expand Down
10 changes: 10 additions & 0 deletions atlan/assets/atlan_fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@ func NewKeywordField(atlanFieldName, keywordFieldName string) *KeywordField {
}
}

// StartsWith Returns a query that will match all assets whose field has a value that starts with
// the provided value. Note that this can also be a case-insensitive match.
func (kf *KeywordField) StartsWith(value string, caseInsensitive *bool) model.Query {
return &model.PrefixQuery{
Field: kf.KeywordFieldName,
Value: value,
CaseInsensitive: caseInsensitive,
}
}

func (kf *KeywordField) GetKeywordFieldName() string {
return kf.KeywordFieldName
}
Expand Down
106 changes: 68 additions & 38 deletions atlan/assets/auth_policy_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,53 +21,77 @@ func (a *AuthPolicy) Updater(name string, qualifiedName string) error {
return nil
}

// UnmarshalJSON unmarshal a AuthPolicy from JSON.
func (a *AuthPolicy) UnmarshalJSON(data []byte) error {
// Define a temporary structure with the expected JSON structure.
var temp struct {
ReferredEntities map[string]interface{} `json:"referredEntities"`
Entity struct {
TypeName string `json:"typeName"`
AttributesJSON json.RawMessage `json:"attributes"`
Guid string `json:"guid"`
IsIncomplete bool `json:"isIncomplete"`
Status atlan.AtlanStatus `json:"status"`
CreatedBy string `json:"createdBy"`
UpdatedBy string `json:"updatedBy"`
CreateTime int64 `json:"createTime"`
UpdateTime int64 `json:"updateTime"`
Version int `json:"version"`
RelationshipAttributes struct {
SchemaRegistrySubjects []structs.SchemaRegistrySubject `json:"schemaRegistrySubjects"`
McMonitors []structs.MCMonitor `json:"mcMonitors"`
Terms []structs.AtlasGlossaryTerm `json:"terms"`
OutputPortDataProducts []string `json:"outputPortDataProducts"`
AtlasGlossary []structs.AtlasGlossary `json:"AtlasGlossary"`
AccessControl []structs.AccessControl `json:"AccessControl"`
Policies []structs.AuthPolicy `json:"policies"`
} `json:"relationshipAttributes"`
}
}

// Unmarshal the JSON data into the temporary structure.
if err := json.Unmarshal(data, &temp); err != nil {
attributes := struct {
// Base attributes
QualifiedName *string `json:"qualifiedName,omitempty"`
Name *string `json:"name,omitempty"`

// AuthPolicy specific attributes
PolicyType *atlan.AuthPolicyType `json:"policyType,omitempty"`
PolicyServiceName *string `json:"policyServiceName,omitempty"`
PolicyCategory *string `json:"policyCategory,omitempty"`
PolicySubCategory *string `json:"policySubCategory,omitempty"`
PolicyUsers *[]string `json:"policyUsers,omitempty"`
PolicyGroups *[]string `json:"policyGroups,omitempty"`
PolicyRoles *[]string `json:"policyRoles,omitempty"`
PolicyActions *[]string `json:"policyActions,omitempty"`
PolicyResources *[]string `json:"policyResources,omitempty"`
PolicyResourceCategory *string `json:"policyResourceCategory,omitempty"`
PolicyPriority *int `json:"policyPriority,omitempty"`
IsPolicyEnabled *bool `json:"isPolicyEnabled,omitempty"`
PolicyMaskType *string `json:"policyMaskType,omitempty"`
PolicyValiditySchedule *[]atlan.AuthPolicyValiditySchedule `json:"policyValiditySchedule,omitempty"`
PolicyResourceSignature *string `json:"policyResourceSignature,omitempty"`
PolicyDelegateAdmin *bool `json:"policyDelegateAdmin,omitempty"`
PolicyConditions *[]atlan.AuthPolicyCondition `json:"policyConditions,omitempty"`
AccessControl *structs.AccessControl `json:"accessControl,omitempty"` // Relationship
}{}

// Unmarshal Base attributes
base, err := UnmarshalBaseEntity(data, &attributes)
if err != nil {
return err
}

// Unmarshal the attributes JSON into the entity.
if err := json.Unmarshal(temp.Entity.AttributesJSON, &a); err != nil {
return err
}

// Set the GUID and TypeName.
a.Guid = &temp.Entity.Guid
a.TypeName = &temp.Entity.TypeName
// Map base entity fields.
a.Guid = &base.Entity.Guid
a.TypeName = &base.Entity.TypeName
a.IsIncomplete = &base.Entity.IsIncomplete
a.Status = &base.Entity.Status
a.CreatedBy = &base.Entity.CreatedBy
a.UpdatedBy = &base.Entity.UpdatedBy
a.CreateTime = &base.Entity.CreateTime
a.UpdateTime = &base.Entity.UpdateTime

// Map AuthPolicy specific attributes to AuthPolicy fields.
a.UniqueAttributes.QualifiedName = attributes.QualifiedName
a.Name = attributes.Name
a.PolicyType = attributes.PolicyType
a.PolicyServiceName = attributes.PolicyServiceName
a.PolicyCategory = attributes.PolicyCategory
a.PolicySubCategory = attributes.PolicySubCategory
a.PolicyUsers = attributes.PolicyUsers
a.PolicyGroups = attributes.PolicyGroups
a.PolicyRoles = attributes.PolicyRoles
a.PolicyActions = attributes.PolicyActions
a.PolicyResources = attributes.PolicyResources
a.PolicyResourceCategory = attributes.PolicyResourceCategory
a.PolicyPriority = attributes.PolicyPriority
a.IsPolicyEnabled = attributes.IsPolicyEnabled
a.PolicyMaskType = attributes.PolicyMaskType
a.PolicyValiditySchedule = attributes.PolicyValiditySchedule
a.PolicyResourceSignature = attributes.PolicyResourceSignature
a.PolicyDelegateAdmin = attributes.PolicyDelegateAdmin
a.PolicyConditions = attributes.PolicyConditions
a.AccessControl = attributes.AccessControl

return nil
}

// MarshalJSON Marshals the AuthPolicy asset into a JSON object.
func (a *AuthPolicy) MarshalJSON() ([]byte, error) {
// Marshal the AccessControl asset into a JSON object.

// Construct the custom JSON structure
customJSON := map[string]interface{}{
"typeName": "AuthPolicy",
Expand Down Expand Up @@ -144,6 +168,12 @@ func (a *AuthPolicy) MarshalJSON() ([]byte, error) {
accessControl["typeName"] = *a.AccessControl.TypeName
}

if a.AccessControl.UniqueAttributes.QualifiedName != nil && *a.AccessControl.UniqueAttributes.QualifiedName != "" {
accessControl["uniqueAttributes"] = map[string]interface{}{
"qualifiedName": *a.AccessControl.UniqueAttributes.QualifiedName,
}
}

attributes["accessControl"] = accessControl
}

Expand Down
36 changes: 36 additions & 0 deletions atlan/assets/purpose_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,18 @@ func (p *Purpose) UnmarshalJSON(data []byte) error {

// Purpose-specific attributes
PurposeAtlanTags *[]structs.AtlanTagName `json:"purposeAtlanTags,omitempty"`

// Access Control-specific Attributes
IsAccessControlEnabled *bool `json:"isAccessControlEnabled,omitempty"`
DenyCustomMetadataGuids *[]string `json:"denyCustomMetadataGuids,omitempty"`
DenyAssetTabs *[]string `json:"denyAssetTabs,omitempty"`
DenyAssetFilters *[]string `json:"denyAssetFilters,omitempty"`
ChannelLink *string `json:"channelLink,omitempty"`
DenyAssetTypes *[]string `json:"denyAssetTypes,omitempty"`
DenyNavigationPages *[]string `json:"denyNavigationPages,omitempty"`
DefaultNavigation *string `json:"defaultNavigation,omitempty"`
DisplayPreferences *[]string `json:"displayPreferences,omitempty"`
Policies *[]AuthPolicy `json:"policies,omitempty"`
}{}
base, err := UnmarshalBaseEntity(data, &attributes)
if err != nil {
Expand All @@ -264,6 +276,30 @@ func (p *Purpose) UnmarshalJSON(data []byte) error {
PurposeAtlanTags: attributes.PurposeAtlanTags,
}

// Map Access Control Attributes
p.IsAccessControlEnabled = attributes.IsAccessControlEnabled
p.DenyCustomMetadataGuids = attributes.DenyCustomMetadataGuids
p.DenyAssetTabs = attributes.DenyAssetTabs
p.DenyAssetFilters = attributes.DenyAssetFilters
p.ChannelLink = attributes.ChannelLink
p.DenyAssetTypes = attributes.DenyAssetTypes
p.DenyNavigationPages = attributes.DenyNavigationPages
p.DefaultNavigation = attributes.DefaultNavigation
p.DisplayPreferences = attributes.DisplayPreferences

// Unmarshal RelationshipAttributes for Policies
if base.Entity.RelationshipAttributes != nil {
relationshipAttributes := struct {
Policies []structs.AuthPolicy `json:"policies,omitempty"`
}{}

if err := json.Unmarshal(base.Entity.RelationshipAttributes, &relationshipAttributes); err != nil {
return err
}
// Map the Policies field
p.Policies = &relationshipAttributes.Policies
}

return nil
}

Expand Down
67 changes: 61 additions & 6 deletions atlan/model/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,30 @@ func (sa *SearchAssets) MarshalJSON() ([]byte, error) {
customJSON["guid"] = *sa.Guid
}

if sa.Status != nil {
customJSON["status"] = *sa.Status
}

if sa.CreatedBy != nil {
customJSON["createdBy"] = *sa.CreatedBy
}

if sa.CreateTime != nil {
customJSON["createTime"] = *sa.CreateTime
}

if sa.UpdateTime != nil {
customJSON["updateTime"] = *sa.UpdateTime
}

if sa.UpdatedBy != nil {
customJSON["updatedBy"] = *sa.UpdatedBy
}

if sa.DisplayText != nil && *sa.DisplayText != "" {
customJSON["DisplayText"] = *sa.DisplayText
}

if sa.Asset.DisplayName != nil && *sa.Asset.DisplayName != "" {
attributes["DisplayText"] = *sa.Asset.DisplayName
}
Expand Down Expand Up @@ -832,6 +856,27 @@ func (sa *SearchAssets) MarshalJSON() ([]byte, error) {
attributes["roleId"] = *sa.RoleId
}

// Handle nested AccessControl field
accessControl := map[string]interface{}{}

if sa.AccessControl.Guid != nil && *sa.AccessControl.Guid != "" {
accessControl["guid"] = *sa.AccessControl.Guid
}

if sa.AccessControl.TypeName != nil && *sa.AccessControl.TypeName != "" {
accessControl["typeName"] = *sa.AccessControl.TypeName
}

if sa.AccessControl.UniqueAttributes.QualifiedName != nil && *sa.AccessControl.UniqueAttributes.QualifiedName != "" {
accessControl["uniqueAttributes"] = map[string]interface{}{
"qualifiedName": sa.AccessControl.UniqueAttributes.QualifiedName,
}
}

if len(accessControl) > 0 {
attributes["accessControl"] = accessControl
}

// Marshal the custom JSON
return json.MarshalIndent(customJSON, "", " ")
}
Expand All @@ -843,14 +888,15 @@ func (sa *SearchAssets) UnmarshalJSON(data []byte) error {
structs.Table
structs.Column
structs.AuthPolicy
structs.AccessControl
structs.Persona
structs.Purpose
QualifiedName *string `json:"qualifiedName,omitempty"`
Name *string `json:"name,omitempty"`
SearchAttributes *SearchAttributes `json:"attributes,omitempty"`
SearchMeanings []Meanings `json:"meanings,omitempty"`
NotNull *bool `json:"notNull,omitempty"`
structs.AccessControl
QualifiedName *string `json:"qualifiedName,omitempty"`
Name *string `json:"name,omitempty"`
SearchAttributes *SearchAttributes `json:"attributes,omitempty"`
SearchMeanings []Meanings `json:"meanings,omitempty"`
NotNull *bool `json:"notNull,omitempty"`

rawSearchAttributes map[string]interface{}
}

Expand All @@ -877,6 +923,8 @@ func (sa *SearchAssets) UnmarshalJSON(data []byte) error {
sa.Column = aux.Column
sa.NotNull = aux.NotNull
sa.SearchMeanings = meaningsData.SearchMeanings
sa.AuthPolicy = aux.AuthPolicy
sa.AccessControl = aux.AccessControl

// Check if any search attributes are present
if aux.SearchAttributes != nil {
Expand Down Expand Up @@ -990,6 +1038,13 @@ func (sa *SearchAssets) UnmarshalJSON(data []byte) error {
sa.PersonaUsers = aux.SearchAttributes.PersonaUsers
sa.RoleId = aux.SearchAttributes.RoleId

if aux.SearchAttributes.AccessControl != nil {
// Attributes under AccessControl struct
sa.AccessControl.TypeName = aux.SearchAttributes.AccessControl.TypeName
sa.AccessControl.Guid = aux.SearchAttributes.AccessControl.Guid
sa.AccessControl.UniqueAttributes.QualifiedName = aux.SearchAttributes.AccessControl.UniqueAttributes.QualifiedName
}

// Populate `rawSearchAttributes` (necessary for setting `SearchAssets.CustomMetadataSets`)
// First, unmarshal the data into a `rawSearchAsset` map
var rawSearchAsset map[string]interface{}
Expand Down
3 changes: 3 additions & 0 deletions atlan/model/structs/access_control.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ type AccessControl struct {
DefaultNavigation *string `json:"defaultNavigation,omitempty"`
DisplayPreferences *[]string `json:"displayPreferences,omitempty"`
Policies *[]AuthPolicy `json:"policies,omitempty"` // Relationship
UniqueAttributes struct {
QualifiedName *string `json:"qualifiedName,omitempty"`
} `json:"uniqueAttributes,omitempty"`
}

// AuthPolicy represents a policy with various attributes.
Expand Down
Loading
Loading