From ffdc971833d65fe54123a3de28477555c3641d5c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 27 Jul 2026 00:28:37 +0000 Subject: [PATCH] Auto-update SDK on 2026-07-27 --- .openapi-generator/FILES | 61 +- README.md | 9 + api/openapi.yaml | 503 ++++++++++- docs/AppTypeEnum.md | 2 + docs/Campaign.md | 43 + docs/CampaignConfiguration.md | 52 ++ .../CampaignGroupAssetVisibilityPolicyEnum.md | 15 + docs/CampaignRevokeOnEnum.md | 15 + docs/CampaignStatusEnum.md | 19 + docs/CampaignsApi.md | 190 ++++ docs/GroupRemoteInfo.md | 1 + docs/GroupRemoteInfoTableauGroup.md | 30 + docs/GroupTypeEnum.md | 2 + docs/GroupsApi.md | 4 +- docs/PaginatedCampaignsList.md | 32 + docs/PropagationStatusEnum.md | 2 + opal_security/__init__.py | 16 + opal_security/api/__init__.py | 1 + opal_security/api/campaigns_api.py | 827 ++++++++++++++++++ opal_security/api/groups_api.py | 12 +- opal_security/models/__init__.py | 7 + opal_security/models/app_type_enum.py | 1 + opal_security/models/campaign.py | 134 +++ .../models/campaign_configuration.py | 150 ++++ ...aign_group_asset_visibility_policy_enum.py | 39 + .../models/campaign_revoke_on_enum.py | 39 + opal_security/models/campaign_status_enum.py | 41 + opal_security/models/group_remote_info.py | 10 +- .../models/group_remote_info_tableau_group.py | 101 +++ opal_security/models/group_type_enum.py | 1 + .../models/paginated_campaigns_list.py | 113 +++ .../models/propagation_status_enum.py | 1 + test/test_campaign.py | 72 ++ test/test_campaign_configuration.py | 88 ++ ...aign_group_asset_visibility_policy_enum.py | 34 + test/test_campaign_revoke_on_enum.py | 34 + test/test_campaign_status_enum.py | 34 + test/test_campaigns_api.py | 45 + test/test_group_remote_info_tableau_group.py | 53 ++ test/test_paginated_campaigns_list.py | 59 ++ 40 files changed, 2843 insertions(+), 49 deletions(-) create mode 100644 docs/Campaign.md create mode 100644 docs/CampaignConfiguration.md create mode 100644 docs/CampaignGroupAssetVisibilityPolicyEnum.md create mode 100644 docs/CampaignRevokeOnEnum.md create mode 100644 docs/CampaignStatusEnum.md create mode 100644 docs/CampaignsApi.md create mode 100644 docs/GroupRemoteInfoTableauGroup.md create mode 100644 docs/PaginatedCampaignsList.md create mode 100644 opal_security/api/campaigns_api.py create mode 100644 opal_security/models/campaign.py create mode 100644 opal_security/models/campaign_configuration.py create mode 100644 opal_security/models/campaign_group_asset_visibility_policy_enum.py create mode 100644 opal_security/models/campaign_revoke_on_enum.py create mode 100644 opal_security/models/campaign_status_enum.py create mode 100644 opal_security/models/group_remote_info_tableau_group.py create mode 100644 opal_security/models/paginated_campaigns_list.py create mode 100644 test/test_campaign.py create mode 100644 test/test_campaign_configuration.py create mode 100644 test/test_campaign_group_asset_visibility_policy_enum.py create mode 100644 test/test_campaign_revoke_on_enum.py create mode 100644 test/test_campaign_status_enum.py create mode 100644 test/test_campaigns_api.py create mode 100644 test/test_group_remote_info_tableau_group.py create mode 100644 test/test_paginated_campaigns_list.py diff --git a/.openapi-generator/FILES b/.openapi-generator/FILES index 1d586f4..beb353d 100644 --- a/.openapi-generator/FILES +++ b/.openapi-generator/FILES @@ -31,6 +31,12 @@ docs/Bundle.md docs/BundleGroup.md docs/BundleResource.md docs/BundlesApi.md +docs/Campaign.md +docs/CampaignConfiguration.md +docs/CampaignGroupAssetVisibilityPolicyEnum.md +docs/CampaignRevokeOnEnum.md +docs/CampaignStatusEnum.md +docs/CampaignsApi.md docs/Condition.md docs/ConfigurationTemplate.md docs/ConfigurationTemplatesApi.md @@ -102,6 +108,7 @@ docs/GroupRemoteInfoPagerdutyOnCallSchedule.md docs/GroupRemoteInfoRootlyOnCallSchedule.md docs/GroupRemoteInfoSlackUserGroup.md docs/GroupRemoteInfoSnowflakeRole.md +docs/GroupRemoteInfoTableauGroup.md docs/GroupRemoteInfoTailscaleGroup.md docs/GroupRemoteInfoTwingateGroup.md docs/GroupRemoteInfoTwingateGroupSynced.md @@ -143,6 +150,7 @@ docs/PaginatedAssignedRequestList.md docs/PaginatedBundleGroupList.md docs/PaginatedBundleList.md docs/PaginatedBundleResourceList.md +docs/PaginatedCampaignsList.md docs/PaginatedConfigurationTemplateList.md docs/PaginatedDelegationsList.md docs/PaginatedEventList.md @@ -330,6 +338,7 @@ opal_security/api/__init__.py opal_security/api/access_rules_api.py opal_security/api/apps_api.py opal_security/api/bundles_api.py +opal_security/api/campaigns_api.py opal_security/api/configuration_templates_api.py opal_security/api/delegations_api.py opal_security/api/event_streams_api.py @@ -379,6 +388,11 @@ opal_security/models/aws_permission_set_metadata_aws_permission_set.py opal_security/models/bundle.py opal_security/models/bundle_group.py opal_security/models/bundle_resource.py +opal_security/models/campaign.py +opal_security/models/campaign_configuration.py +opal_security/models/campaign_group_asset_visibility_policy_enum.py +opal_security/models/campaign_revoke_on_enum.py +opal_security/models/campaign_status_enum.py opal_security/models/condition.py opal_security/models/configuration_template.py opal_security/models/create_bundle_info.py @@ -445,6 +459,7 @@ opal_security/models/group_remote_info_pagerduty_on_call_schedule.py opal_security/models/group_remote_info_rootly_on_call_schedule.py opal_security/models/group_remote_info_slack_user_group.py opal_security/models/group_remote_info_snowflake_role.py +opal_security/models/group_remote_info_tableau_group.py opal_security/models/group_remote_info_tailscale_group.py opal_security/models/group_remote_info_twingate_group.py opal_security/models/group_remote_info_twingate_group_synced.py @@ -479,6 +494,7 @@ opal_security/models/paginated_assigned_request_list.py opal_security/models/paginated_bundle_group_list.py opal_security/models/paginated_bundle_list.py opal_security/models/paginated_bundle_resource_list.py +opal_security/models/paginated_campaigns_list.py opal_security/models/paginated_configuration_template_list.py opal_security/models/paginated_delegations_list.py opal_security/models/paginated_event_list.py @@ -661,41 +677,12 @@ setup.cfg setup.py test-requirements.txt test/__init__.py -test/test_access_entity_filters.py -test/test_access_relationship_filters.py -test/test_create_event_stream_info.py -test/test_entity_item_type_enum.py -test/test_entity_name_filter.py -test/test_entity_tag_filter.py -test/test_event_stream.py -test/test_event_stream_connection.py -test/test_event_stream_connection_type_enum.py -test/test_event_stream_list.py -test/test_event_streams_api.py -test/test_group_remote_info_grafana_team.py -test/test_group_remote_info_hubspot_team.py -test/test_group_remote_info_slack_user_group.py -test/test_group_remote_info_twingate_group_synced.py -test/test_group_remote_info_zendesk_group.py -test/test_group_remote_info_zendesk_organization.py -test/test_opal_node_query.py -test/test_opal_node_query_body.py -test/test_opal_node_query_results.py -test/test_opal_queries_api.py -test/test_opal_query_result_edge.py -test/test_opal_query_result_node.py -test/test_paginated_access_rules_list.py -test/test_resource_remote_info_grafana_dashboard.py -test/test_resource_remote_info_grafana_folder.py -test/test_resource_remote_info_grafana_role.py -test/test_resource_remote_info_hubspot_role.py -test/test_resource_remote_info_zendesk_role.py -test/test_string_match_type.py -test/test_update_event_stream_info.py -test/test_user_attribute_selector.py -test/test_webhook_api_key_credential.py -test/test_webhook_api_key_location_enum.py -test/test_webhook_auth_type_enum.py -test/test_webhook_credentials.py -test/test_webhook_hmac_credential.py +test/test_campaign.py +test/test_campaign_configuration.py +test/test_campaign_group_asset_visibility_policy_enum.py +test/test_campaign_revoke_on_enum.py +test/test_campaign_status_enum.py +test/test_campaigns_api.py +test/test_group_remote_info_tableau_group.py +test/test_paginated_campaigns_list.py tox.ini diff --git a/README.md b/README.md index 81688b4..2152297 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,8 @@ Class | Method | HTTP request | Description *BundlesApi* | [**remove_bundle_resource**](docs/BundlesApi.md#remove_bundle_resource) | **DELETE** /bundles/{bundle_id}/resources/{resource_id} | *BundlesApi* | [**set_bundle_visibility**](docs/BundlesApi.md#set_bundle_visibility) | **PUT** /bundles/{bundle_id}/visibility | *BundlesApi* | [**update_bundle**](docs/BundlesApi.md#update_bundle) | **PUT** /bundles/{bundle_id} | +*CampaignsApi* | [**get_campaign**](docs/CampaignsApi.md#get_campaign) | **GET** /campaigns/{campaign_id} | Get campaign by ID +*CampaignsApi* | [**get_campaigns**](docs/CampaignsApi.md#get_campaigns) | **GET** /campaigns | *ConfigurationTemplatesApi* | [**create_configuration_template**](docs/ConfigurationTemplatesApi.md#create_configuration_template) | **POST** /configuration-templates | *ConfigurationTemplatesApi* | [**delete_configuration_template**](docs/ConfigurationTemplatesApi.md#delete_configuration_template) | **DELETE** /configuration-templates/{configuration_template_id} | *ConfigurationTemplatesApi* | [**get_configuration_templates**](docs/ConfigurationTemplatesApi.md#get_configuration_templates) | **GET** /configuration-templates | @@ -313,6 +315,11 @@ Class | Method | HTTP request | Description - [Bundle](docs/Bundle.md) - [BundleGroup](docs/BundleGroup.md) - [BundleResource](docs/BundleResource.md) + - [Campaign](docs/Campaign.md) + - [CampaignConfiguration](docs/CampaignConfiguration.md) + - [CampaignGroupAssetVisibilityPolicyEnum](docs/CampaignGroupAssetVisibilityPolicyEnum.md) + - [CampaignRevokeOnEnum](docs/CampaignRevokeOnEnum.md) + - [CampaignStatusEnum](docs/CampaignStatusEnum.md) - [Condition](docs/Condition.md) - [ConfigurationTemplate](docs/ConfigurationTemplate.md) - [CreateBundleInfo](docs/CreateBundleInfo.md) @@ -379,6 +386,7 @@ Class | Method | HTTP request | Description - [GroupRemoteInfoRootlyOnCallSchedule](docs/GroupRemoteInfoRootlyOnCallSchedule.md) - [GroupRemoteInfoSlackUserGroup](docs/GroupRemoteInfoSlackUserGroup.md) - [GroupRemoteInfoSnowflakeRole](docs/GroupRemoteInfoSnowflakeRole.md) + - [GroupRemoteInfoTableauGroup](docs/GroupRemoteInfoTableauGroup.md) - [GroupRemoteInfoTailscaleGroup](docs/GroupRemoteInfoTailscaleGroup.md) - [GroupRemoteInfoTwingateGroup](docs/GroupRemoteInfoTwingateGroup.md) - [GroupRemoteInfoTwingateGroupSynced](docs/GroupRemoteInfoTwingateGroupSynced.md) @@ -413,6 +421,7 @@ Class | Method | HTTP request | Description - [PaginatedBundleGroupList](docs/PaginatedBundleGroupList.md) - [PaginatedBundleList](docs/PaginatedBundleList.md) - [PaginatedBundleResourceList](docs/PaginatedBundleResourceList.md) + - [PaginatedCampaignsList](docs/PaginatedCampaignsList.md) - [PaginatedConfigurationTemplateList](docs/PaginatedConfigurationTemplateList.md) - [PaginatedDelegationsList](docs/PaginatedDelegationsList.md) - [PaginatedEventList](docs/PaginatedEventList.md) diff --git a/api/openapi.yaml b/api/openapi.yaml index b1418bc..0bb82e6 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -20,6 +20,8 @@ tags: description: Operations related to apps - name: bundles description: Operations related to bundles + - name: campaigns + description: Operations related to access review campaigns - name: configuration-templates description: Operations related to configuration templates - name: delegations @@ -598,6 +600,166 @@ paths: - BearerAuth: [] tags: - bundles + /campaigns: + get: + description: Returns a list of `Campaign` objects. + operationId: getCampaigns + parameters: + - description: The pagination cursor value. + example: cD0yMDIxLTAxLTA2KzAzJTNBMjQlM0E1My40MzQzMjYlMkIwMCUzQTAw + explode: true + in: query + name: cursor + required: false + schema: + type: string + style: form + - description: Number of results to return per page. Default is 200. + example: 200 + explode: true + in: query + name: page_size + required: false + schema: + type: integer + maximum: 1000 + style: form + - description: Campaign name to filter by. Returns campaigns whose names contain this substring (case-insensitive). + example: Q3 Access Review + explode: true + in: query + name: name + required: false + schema: + type: string + style: form + - description: Filter by campaign status. Status is derived from lifecycle timestamps and review progress. + example: ONGOING + explode: true + in: query + name: status + required: false + schema: + $ref: "#/components/schemas/CampaignStatusEnum" + style: form + - description: Include campaigns created after this timestamp (exclusive). ISO 8601 format. + example: 2026-01-01T00:00:00Z + explode: true + in: query + name: created_at_after + required: false + schema: + type: string + format: date-time + style: form + - description: Include campaigns created before this timestamp (exclusive). ISO 8601 format. + example: 2026-12-31T23:59:59Z + explode: true + in: query + name: created_at_before + required: false + schema: + type: string + format: date-time + style: form + - description: Include campaigns started after this timestamp (exclusive). ISO 8601 format. + example: 2026-01-01T00:00:00Z + explode: true + in: query + name: started_at_after + required: false + schema: + type: string + format: date-time + style: form + - description: Include campaigns started before this timestamp (exclusive). ISO 8601 format. + example: 2026-12-31T23:59:59Z + explode: true + in: query + name: started_at_before + required: false + schema: + type: string + format: date-time + style: form + - description: Include campaigns ended after this timestamp (exclusive). ISO 8601 format. + example: 2026-01-01T00:00:00Z + explode: true + in: query + name: ended_at_after + required: false + schema: + type: string + format: date-time + style: form + - description: Include campaigns ended before this timestamp (exclusive). ISO 8601 format. + example: 2026-12-31T23:59:59Z + explode: true + in: query + name: ended_at_before + required: false + schema: + type: string + format: date-time + style: form + - description: Include campaigns stopped after this timestamp (exclusive). ISO 8601 format. + example: 2026-01-01T00:00:00Z + explode: true + in: query + name: stopped_at_after + required: false + schema: + type: string + format: date-time + style: form + - description: Include campaigns stopped before this timestamp (exclusive). ISO 8601 format. + example: 2026-12-31T23:59:59Z + explode: true + in: query + name: stopped_at_before + required: false + schema: + type: string + format: date-time + style: form + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/PaginatedCampaignsList" + description: A list of campaigns for your organization. + security: + - BearerAuth: [] + tags: + - campaigns + /campaigns/{campaign_id}: + get: + summary: Get campaign by ID + description: Returns a `Campaign` object. + operationId: getCampaign + parameters: + - description: The ID of the campaign. + example: f454d283-ca87-4a8a-bdbb-df212eca5353 + explode: true + in: path + name: campaign_id + required: true + schema: + format: uuid + type: string + style: simple + responses: + "200": + content: + application/json: + schema: + $ref: "#/components/schemas/Campaign" + description: The requested `Campaign`. + security: + - BearerAuth: [] + tags: + - campaigns /configuration-templates: get: description: Returns a list of `ConfigurationTemplate` objects. @@ -1706,7 +1868,13 @@ paths: schema: type: string style: form - - description: Number of results to return per page. Default is 200. + - description: + Number of results to return per page, up to 1000. When set (or when a + cursor is provided), the response contains a single page of results and + a `next` cursor; the default page size is 200. When both page_size and + cursor are omitted, the entire group membership is returned in one + response with no `next` cursor. For large groups, prefer setting + page_size and following `next`. example: 200 explode: true in: query @@ -5692,6 +5860,324 @@ components: type: string type: array type: object + CampaignStatusEnum: + description: The current status of a campaign. + enum: + - DRAFT + - ONGOING + - COMPLETED + - STOPPED + - ENDED + example: ONGOING + type: string + CampaignRevokeOnEnum: + description: When access decisions take effect during a campaign. + enum: + - ACTION + - END + - NONE + example: END + type: string + CampaignGroupAssetVisibilityPolicyEnum: + description: Controls what group assets reviewers can see during the campaign. + enum: + - STRICT + - VIEW_VISIBLE_AND_ASSIGNED + - VIEW_ALL + example: STRICT + type: string + CampaignConfiguration: + description: Configuration for an access review campaign. + example: + configuration_id: 39a4d283-ca87-4a8a-bdbb-df212eca5fdb + created_at: 2026-07-01T00:00:00Z + updated_at: 2026-07-01T00:00:00Z + query: null + reviewer_assignment_policy: MANUALLY + allow_self_review: false + send_reviewer_assignment_notification: true + allow_reviewer_reassignment: false + start_date: null + end_date: 2026-09-30T00:00:00Z + timezone: America/Los_Angeles + revoke_on: END + reminder_schedule: [7, 3, 1] + reminder_include_manager: true + require_reason_on_denial: false + hide_ai_suggestions: false + custom_start_message: null + group_asset_visibility_policy: STRICT + is_template: false + cron_expression: null + next_scheduled_run: null + last_scheduled_run: null + recurring_duration_days: null + properties: + configuration_id: + description: The ID of the campaign configuration. + example: 39a4d283-ca87-4a8a-bdbb-df212eca5fdb + format: uuid + type: string + created_at: + description: The creation time of the configuration. + example: 2026-07-01T00:00:00Z + format: date-time + type: string + updated_at: + description: The last updated time of the configuration. + example: 2026-07-01T00:00:00Z + format: date-time + type: string + query: + description: + Edge-based query defining the scope of access to review. Matches the + stored Opal edge-query JSON shape. + nullable: true + type: object + additionalProperties: true + reviewer_assignment_policy: + $ref: "#/components/schemas/UARReviewerAssignmentPolicyEnum" + allow_self_review: + description: Whether reviewers can review their own access. + example: false + type: boolean + send_reviewer_assignment_notification: + description: Whether to notify reviewers upon assignment. + example: true + type: boolean + allow_reviewer_reassignment: + description: Whether reviewers may reassign their reviews to another user. + example: false + type: boolean + start_date: + description: Scheduled start date of the campaign. + example: 2026-07-02T00:00:00Z + format: date-time + nullable: true + type: string + end_date: + description: Scheduled end date of the campaign. + example: 2026-09-30T00:00:00Z + format: date-time + nullable: true + type: string + timezone: + description: + IANA timezone used to interpret campaign deadlines (e.g. + America/Los_Angeles). + example: America/Los_Angeles + type: string + revoke_on: + $ref: "#/components/schemas/CampaignRevokeOnEnum" + reminder_schedule: + description: Days before end date to send reminder notifications. + example: [7, 3, 1] + items: + type: integer + type: array + reminder_include_manager: + description: Whether to include the reviewer's manager in reminders. + example: true + type: boolean + require_reason_on_denial: + description: + Whether reviewers must provide a reason when denying (revoking) + access. + example: false + type: boolean + hide_ai_suggestions: + description: Whether AI suggestions are hidden from reviewers. + example: false + type: boolean + custom_start_message: + description: + Optional custom message included when notifying reviewers that the + campaign started. + example: Please complete your reviews by Friday. + nullable: true + type: string + group_asset_visibility_policy: + $ref: "#/components/schemas/CampaignGroupAssetVisibilityPolicyEnum" + is_template: + description: + Whether this configuration is a recurring schedule template. + example: false + type: boolean + cron_expression: + description: + Cron expression driving the recurring schedule. Null for one-off + campaigns. + example: 0 9 1 * * + nullable: true + type: string + next_scheduled_run: + description: Next time a draft will be generated from this template. + example: 2026-08-01T16:00:00Z + format: date-time + nullable: true + type: string + last_scheduled_run: + description: Most recent time a draft was generated from this template. + example: 2026-07-01T16:00:00Z + format: date-time + nullable: true + type: string + recurring_duration_days: + description: + Deadline window in days applied to each draft generated from this + template. + example: 14 + nullable: true + type: integer + required: + - configuration_id + - created_at + - updated_at + - reviewer_assignment_policy + - allow_self_review + - send_reviewer_assignment_notification + - allow_reviewer_reassignment + - timezone + - revoke_on + - reminder_include_manager + - require_reason_on_denial + - hide_ai_suggestions + - group_asset_visibility_policy + - is_template + type: object + Campaign: + description: An access review campaign. + example: + campaign_id: f454d283-ca87-4a8a-bdbb-df212eca5353 + name: Q3 Access Review + status: DRAFT + is_template: false + created_at: 2026-07-01T00:00:00Z + updated_at: 2026-07-01T00:00:00Z + created_by_user_id: 32acc112-21ff-4669-91c2-21e27683eaa1 + configuration: null + started_at: null + started_by_user_id: null + stopped_at: null + stopped_by_user_id: null + ended_at: null + ended_by_user_id: null + properties: + campaign_id: + description: The ID of the campaign. + example: f454d283-ca87-4a8a-bdbb-df212eca5353 + format: uuid + type: string + name: + description: The name of the campaign. + example: Q3 Access Review + type: string + status: + $ref: "#/components/schemas/CampaignStatusEnum" + is_template: + description: + Whether this campaign is a recurring schedule template. Templates + spawn draft campaigns on schedule rather than being reviewed directly. + example: false + type: boolean + created_at: + description: The creation time of the campaign. + example: 2026-07-01T00:00:00Z + format: date-time + type: string + updated_at: + description: The last updated time of the campaign. + example: 2026-07-01T00:00:00Z + format: date-time + type: string + created_by_user_id: + description: The ID of the user who created the campaign. + example: 32acc112-21ff-4669-91c2-21e27683eaa1 + format: uuid + type: string + configuration: + description: The campaign's configuration, if set. + allOf: + - $ref: "#/components/schemas/CampaignConfiguration" + nullable: true + started_at: + description: The time the campaign was started, if started. + example: 2026-07-02T00:00:00Z + format: date-time + nullable: true + type: string + started_by_user_id: + description: The ID of the user who started the campaign, if started. + example: 32acc112-21ff-4669-91c2-21e27683eaa1 + format: uuid + nullable: true + type: string + stopped_at: + description: The time the campaign was manually stopped, if stopped. + example: 2026-07-10T00:00:00Z + format: date-time + nullable: true + type: string + stopped_by_user_id: + description: The ID of the user who stopped the campaign, if stopped. + example: 32acc112-21ff-4669-91c2-21e27683eaa1 + format: uuid + nullable: true + type: string + ended_at: + description: The time the campaign reached its scheduled end, if ended. + example: 2026-07-14T00:00:00Z + format: date-time + nullable: true + type: string + ended_by_user_id: + description: The ID of the user who ended the campaign, if ended. + example: 32acc112-21ff-4669-91c2-21e27683eaa1 + format: uuid + nullable: true + type: string + required: + - campaign_id + - name + - status + - is_template + - created_at + - updated_at + - created_by_user_id + type: object + PaginatedCampaignsList: + description: A list of campaigns. + example: + next: cD0yMDIxLTAxLTA2KzAzJTNBMjQlM0E1My40MzQzMjYlMkIwMCUzQTAw + previous: cj1sZXdwd2VycWVtY29zZnNkc2NzUWxNMEUxTXk0ME16UXpNallsTWtJ + results: + - campaign_id: f454d283-ca87-4a8a-bdbb-df212eca5353 + name: Q3 Access Review + status: DRAFT + is_template: false + created_at: 2026-07-01T00:00:00Z + updated_at: 2026-07-01T00:00:00Z + created_by_user_id: 32acc112-21ff-4669-91c2-21e27683eaa1 + properties: + next: + description: + The cursor with which to continue pagination if additional result + pages exist. + example: cD0yMDIxLTAxLTA2KzAzJTNBMjQlM0E1My40MzQzMjYlMkIwMCUzQTAw + nullable: true + type: string + previous: + description: The cursor used to obtain the current result page. + example: cj1sZXdwd2VycWVtY29zZnNkc2NzUWxNMEUxTXk0ME16UXpNallsTWtJ + nullable: true + type: string + results: + items: + $ref: "#/components/schemas/Campaign" + type: array + required: + - results + type: object PaginatedUARsList: description: A list of UARs. example: @@ -6045,6 +6531,7 @@ components: - SALESFORCE - SNOWFLAKE - SLACK + - TABLEAU - TAILSCALE - TELEPORT - TWINGATE @@ -7349,6 +7836,7 @@ components: - ERR_DRY_RUN_MODE_ENABLED - ERR_HR_IDP_PROVIDER_NOT_LINKED - ERR_REMOTE_UNRECOVERABLE_ERROR + - ERR_REMOTE_TICKET_NOT_FOUND example: - SUCCESS type: string @@ -7615,6 +8103,7 @@ components: - ZENDESK_GROUP - ZENDESK_ORGANIZATION - HUBSPOT_TEAM + - TABLEAU_GROUP example: OPAL_GROUP type: string ResourceTypeEnum: @@ -8566,6 +9055,16 @@ components: type: object required: - team_id + tableau_group: + description: Remote info for Tableau group. + properties: + group_id: + description: The ID of the Tableau group. + example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + type: string + type: object + required: + - group_id type: object ResourceRemoteInfo: description: @@ -12955,4 +13454,4 @@ components: securitySchemes: BearerAuth: scheme: bearer - type: http \ No newline at end of file + type: http diff --git a/docs/AppTypeEnum.md b/docs/AppTypeEnum.md index 2bc6e0a..d6ff05d 100644 --- a/docs/AppTypeEnum.md +++ b/docs/AppTypeEnum.md @@ -86,6 +86,8 @@ The type of an app. * `SLACK` (value: `'SLACK'`) +* `TABLEAU` (value: `'TABLEAU'`) + * `TAILSCALE` (value: `'TAILSCALE'`) * `TELEPORT` (value: `'TELEPORT'`) diff --git a/docs/Campaign.md b/docs/Campaign.md new file mode 100644 index 0000000..e59f4f9 --- /dev/null +++ b/docs/Campaign.md @@ -0,0 +1,43 @@ +# Campaign + +An access review campaign. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**campaign_id** | **UUID** | The ID of the campaign. | +**name** | **str** | The name of the campaign. | +**status** | [**CampaignStatusEnum**](CampaignStatusEnum.md) | | +**is_template** | **bool** | Whether this campaign is a recurring schedule template. Templates spawn draft campaigns on schedule rather than being reviewed directly. | +**created_at** | **datetime** | The creation time of the campaign. | +**updated_at** | **datetime** | The last updated time of the campaign. | +**created_by_user_id** | **UUID** | The ID of the user who created the campaign. | +**configuration** | [**CampaignConfiguration**](CampaignConfiguration.md) | The campaign's configuration, if set. | [optional] +**started_at** | **datetime** | The time the campaign was started, if started. | [optional] +**started_by_user_id** | **UUID** | The ID of the user who started the campaign, if started. | [optional] +**stopped_at** | **datetime** | The time the campaign was manually stopped, if stopped. | [optional] +**stopped_by_user_id** | **UUID** | The ID of the user who stopped the campaign, if stopped. | [optional] +**ended_at** | **datetime** | The time the campaign reached its scheduled end, if ended. | [optional] +**ended_by_user_id** | **UUID** | The ID of the user who ended the campaign, if ended. | [optional] + +## Example + +```python +from opal_security.models.campaign import Campaign + +# TODO update the JSON string below +json = "{}" +# create an instance of Campaign from a JSON string +campaign_instance = Campaign.from_json(json) +# print the JSON string representation of the object +print(Campaign.to_json()) + +# convert the object into a dict +campaign_dict = campaign_instance.to_dict() +# create an instance of Campaign from a dict +campaign_from_dict = Campaign.from_dict(campaign_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/CampaignConfiguration.md b/docs/CampaignConfiguration.md new file mode 100644 index 0000000..358e0aa --- /dev/null +++ b/docs/CampaignConfiguration.md @@ -0,0 +1,52 @@ +# CampaignConfiguration + +Configuration for an access review campaign. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**configuration_id** | **UUID** | The ID of the campaign configuration. | +**created_at** | **datetime** | The creation time of the configuration. | +**updated_at** | **datetime** | The last updated time of the configuration. | +**query** | **Dict[str, object]** | Edge-based query defining the scope of access to review. Matches the stored Opal edge-query JSON shape. | [optional] +**reviewer_assignment_policy** | [**UARReviewerAssignmentPolicyEnum**](UARReviewerAssignmentPolicyEnum.md) | | +**allow_self_review** | **bool** | Whether reviewers can review their own access. | +**send_reviewer_assignment_notification** | **bool** | Whether to notify reviewers upon assignment. | +**allow_reviewer_reassignment** | **bool** | Whether reviewers may reassign their reviews to another user. | +**start_date** | **datetime** | Scheduled start date of the campaign. | [optional] +**end_date** | **datetime** | Scheduled end date of the campaign. | [optional] +**timezone** | **str** | IANA timezone used to interpret campaign deadlines (e.g. America/Los_Angeles). | +**revoke_on** | [**CampaignRevokeOnEnum**](CampaignRevokeOnEnum.md) | | +**reminder_schedule** | **List[int]** | Days before end date to send reminder notifications. | [optional] +**reminder_include_manager** | **bool** | Whether to include the reviewer's manager in reminders. | +**require_reason_on_denial** | **bool** | Whether reviewers must provide a reason when denying (revoking) access. | +**hide_ai_suggestions** | **bool** | Whether AI suggestions are hidden from reviewers. | +**custom_start_message** | **str** | Optional custom message included when notifying reviewers that the campaign started. | [optional] +**group_asset_visibility_policy** | [**CampaignGroupAssetVisibilityPolicyEnum**](CampaignGroupAssetVisibilityPolicyEnum.md) | | +**is_template** | **bool** | Whether this configuration is a recurring schedule template. | +**cron_expression** | **str** | Cron expression driving the recurring schedule. Null for one-off campaigns. | [optional] +**next_scheduled_run** | **datetime** | Next time a draft will be generated from this template. | [optional] +**last_scheduled_run** | **datetime** | Most recent time a draft was generated from this template. | [optional] +**recurring_duration_days** | **int** | Deadline window in days applied to each draft generated from this template. | [optional] + +## Example + +```python +from opal_security.models.campaign_configuration import CampaignConfiguration + +# TODO update the JSON string below +json = "{}" +# create an instance of CampaignConfiguration from a JSON string +campaign_configuration_instance = CampaignConfiguration.from_json(json) +# print the JSON string representation of the object +print(CampaignConfiguration.to_json()) + +# convert the object into a dict +campaign_configuration_dict = campaign_configuration_instance.to_dict() +# create an instance of CampaignConfiguration from a dict +campaign_configuration_from_dict = CampaignConfiguration.from_dict(campaign_configuration_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/CampaignGroupAssetVisibilityPolicyEnum.md b/docs/CampaignGroupAssetVisibilityPolicyEnum.md new file mode 100644 index 0000000..d3fdd4c --- /dev/null +++ b/docs/CampaignGroupAssetVisibilityPolicyEnum.md @@ -0,0 +1,15 @@ +# CampaignGroupAssetVisibilityPolicyEnum + +Controls what group assets reviewers can see during the campaign. + +## Enum + +* `STRICT` (value: `'STRICT'`) + +* `VIEW_VISIBLE_AND_ASSIGNED` (value: `'VIEW_VISIBLE_AND_ASSIGNED'`) + +* `VIEW_ALL` (value: `'VIEW_ALL'`) + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/CampaignRevokeOnEnum.md b/docs/CampaignRevokeOnEnum.md new file mode 100644 index 0000000..9e0f7d0 --- /dev/null +++ b/docs/CampaignRevokeOnEnum.md @@ -0,0 +1,15 @@ +# CampaignRevokeOnEnum + +When access decisions take effect during a campaign. + +## Enum + +* `ACTION` (value: `'ACTION'`) + +* `END` (value: `'END'`) + +* `NONE` (value: `'NONE'`) + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/CampaignStatusEnum.md b/docs/CampaignStatusEnum.md new file mode 100644 index 0000000..362f82c --- /dev/null +++ b/docs/CampaignStatusEnum.md @@ -0,0 +1,19 @@ +# CampaignStatusEnum + +The current status of a campaign. + +## Enum + +* `DRAFT` (value: `'DRAFT'`) + +* `ONGOING` (value: `'ONGOING'`) + +* `COMPLETED` (value: `'COMPLETED'`) + +* `STOPPED` (value: `'STOPPED'`) + +* `ENDED` (value: `'ENDED'`) + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/CampaignsApi.md b/docs/CampaignsApi.md new file mode 100644 index 0000000..1d79700 --- /dev/null +++ b/docs/CampaignsApi.md @@ -0,0 +1,190 @@ +# opal_security.CampaignsApi + +All URIs are relative to *https://api.opal.dev/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**get_campaign**](CampaignsApi.md#get_campaign) | **GET** /campaigns/{campaign_id} | Get campaign by ID +[**get_campaigns**](CampaignsApi.md#get_campaigns) | **GET** /campaigns | + + +# **get_campaign** +> Campaign get_campaign(campaign_id) + +Get campaign by ID + +Returns a `Campaign` object. + +### Example + +* Bearer Authentication (BearerAuth): + +```python +import opal_security +from opal_security.models.campaign import Campaign +from opal_security.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to https://api.opal.dev/v1 +# See configuration.py for a list of all supported configuration parameters. +import opal_security as opal + +configuration = opal.Configuration( + host = "https://api.opal.dev/v1" +) + +# The client must configure the authentication and authorization parameters +# in accordance with the API server security policy. +# Examples for each auth method are provided below, use the example that +# satisfies your auth use case. + +# Configure Bearer authorization: BearerAuth +configuration = opal.Configuration( + access_token = os.environ["BEARER_TOKEN"] +) + +# Enter a context with an instance of the API client +with opal_security.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = opal_security.CampaignsApi(api_client) + campaign_id = UUID('f454d283-ca87-4a8a-bdbb-df212eca5353') # UUID | The ID of the campaign. + + try: + # Get campaign by ID + api_response = api_instance.get_campaign(campaign_id) + print("The response of CampaignsApi->get_campaign:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling CampaignsApi->get_campaign: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **campaign_id** | **UUID**| The ID of the campaign. | + +### Return type + +[**Campaign**](Campaign.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | The requested `Campaign`. | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **get_campaigns** +> PaginatedCampaignsList get_campaigns(cursor=cursor, page_size=page_size, name=name, status=status, created_at_after=created_at_after, created_at_before=created_at_before, started_at_after=started_at_after, started_at_before=started_at_before, ended_at_after=ended_at_after, ended_at_before=ended_at_before, stopped_at_after=stopped_at_after, stopped_at_before=stopped_at_before) + +Returns a list of `Campaign` objects. + +### Example + +* Bearer Authentication (BearerAuth): + +```python +import opal_security +from opal_security.models.campaign_status_enum import CampaignStatusEnum +from opal_security.models.paginated_campaigns_list import PaginatedCampaignsList +from opal_security.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to https://api.opal.dev/v1 +# See configuration.py for a list of all supported configuration parameters. +import opal_security as opal + +configuration = opal.Configuration( + host = "https://api.opal.dev/v1" +) + +# The client must configure the authentication and authorization parameters +# in accordance with the API server security policy. +# Examples for each auth method are provided below, use the example that +# satisfies your auth use case. + +# Configure Bearer authorization: BearerAuth +configuration = opal.Configuration( + access_token = os.environ["BEARER_TOKEN"] +) + +# Enter a context with an instance of the API client +with opal_security.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = opal_security.CampaignsApi(api_client) + cursor = 'cD0yMDIxLTAxLTA2KzAzJTNBMjQlM0E1My40MzQzMjYlMkIwMCUzQTAw' # str | The pagination cursor value. (optional) + page_size = 200 # int | Number of results to return per page. Default is 200. (optional) + name = 'Q3 Access Review' # str | Campaign name to filter by. Returns campaigns whose names contain this substring (case-insensitive). (optional) + status = opal_security.CampaignStatusEnum() # CampaignStatusEnum | Filter by campaign status. Status is derived from lifecycle timestamps and review progress. (optional) + created_at_after = '2026-01-01T00:00:00Z' # datetime | Include campaigns created after this timestamp (exclusive). ISO 8601 format. (optional) + created_at_before = '2026-12-31T23:59:59Z' # datetime | Include campaigns created before this timestamp (exclusive). ISO 8601 format. (optional) + started_at_after = '2026-01-01T00:00:00Z' # datetime | Include campaigns started after this timestamp (exclusive). ISO 8601 format. (optional) + started_at_before = '2026-12-31T23:59:59Z' # datetime | Include campaigns started before this timestamp (exclusive). ISO 8601 format. (optional) + ended_at_after = '2026-01-01T00:00:00Z' # datetime | Include campaigns ended after this timestamp (exclusive). ISO 8601 format. (optional) + ended_at_before = '2026-12-31T23:59:59Z' # datetime | Include campaigns ended before this timestamp (exclusive). ISO 8601 format. (optional) + stopped_at_after = '2026-01-01T00:00:00Z' # datetime | Include campaigns stopped after this timestamp (exclusive). ISO 8601 format. (optional) + stopped_at_before = '2026-12-31T23:59:59Z' # datetime | Include campaigns stopped before this timestamp (exclusive). ISO 8601 format. (optional) + + try: + api_response = api_instance.get_campaigns(cursor=cursor, page_size=page_size, name=name, status=status, created_at_after=created_at_after, created_at_before=created_at_before, started_at_after=started_at_after, started_at_before=started_at_before, ended_at_after=ended_at_after, ended_at_before=ended_at_before, stopped_at_after=stopped_at_after, stopped_at_before=stopped_at_before) + print("The response of CampaignsApi->get_campaigns:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling CampaignsApi->get_campaigns: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **cursor** | **str**| The pagination cursor value. | [optional] + **page_size** | **int**| Number of results to return per page. Default is 200. | [optional] + **name** | **str**| Campaign name to filter by. Returns campaigns whose names contain this substring (case-insensitive). | [optional] + **status** | [**CampaignStatusEnum**](.md)| Filter by campaign status. Status is derived from lifecycle timestamps and review progress. | [optional] + **created_at_after** | **datetime**| Include campaigns created after this timestamp (exclusive). ISO 8601 format. | [optional] + **created_at_before** | **datetime**| Include campaigns created before this timestamp (exclusive). ISO 8601 format. | [optional] + **started_at_after** | **datetime**| Include campaigns started after this timestamp (exclusive). ISO 8601 format. | [optional] + **started_at_before** | **datetime**| Include campaigns started before this timestamp (exclusive). ISO 8601 format. | [optional] + **ended_at_after** | **datetime**| Include campaigns ended after this timestamp (exclusive). ISO 8601 format. | [optional] + **ended_at_before** | **datetime**| Include campaigns ended before this timestamp (exclusive). ISO 8601 format. | [optional] + **stopped_at_after** | **datetime**| Include campaigns stopped after this timestamp (exclusive). ISO 8601 format. | [optional] + **stopped_at_before** | **datetime**| Include campaigns stopped before this timestamp (exclusive). ISO 8601 format. | [optional] + +### Return type + +[**PaginatedCampaignsList**](PaginatedCampaignsList.md) + +### Authorization + +[BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | A list of campaigns for your organization. | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/docs/GroupRemoteInfo.md b/docs/GroupRemoteInfo.md index d96154d..461c51f 100644 --- a/docs/GroupRemoteInfo.md +++ b/docs/GroupRemoteInfo.md @@ -35,6 +35,7 @@ Name | Type | Description | Notes **slack_user_group** | [**GroupRemoteInfoSlackUserGroup**](GroupRemoteInfoSlackUserGroup.md) | | [optional] **zendesk_organization** | [**GroupRemoteInfoZendeskOrganization**](GroupRemoteInfoZendeskOrganization.md) | | [optional] **hubspot_team** | [**GroupRemoteInfoHubspotTeam**](GroupRemoteInfoHubspotTeam.md) | | [optional] +**tableau_group** | [**GroupRemoteInfoTableauGroup**](GroupRemoteInfoTableauGroup.md) | | [optional] ## Example diff --git a/docs/GroupRemoteInfoTableauGroup.md b/docs/GroupRemoteInfoTableauGroup.md new file mode 100644 index 0000000..3c70278 --- /dev/null +++ b/docs/GroupRemoteInfoTableauGroup.md @@ -0,0 +1,30 @@ +# GroupRemoteInfoTableauGroup + +Remote info for Tableau group. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**group_id** | **str** | The ID of the Tableau group. | + +## Example + +```python +from opal_security.models.group_remote_info_tableau_group import GroupRemoteInfoTableauGroup + +# TODO update the JSON string below +json = "{}" +# create an instance of GroupRemoteInfoTableauGroup from a JSON string +group_remote_info_tableau_group_instance = GroupRemoteInfoTableauGroup.from_json(json) +# print the JSON string representation of the object +print(GroupRemoteInfoTableauGroup.to_json()) + +# convert the object into a dict +group_remote_info_tableau_group_dict = group_remote_info_tableau_group_instance.to_dict() +# create an instance of GroupRemoteInfoTableauGroup from a dict +group_remote_info_tableau_group_from_dict = GroupRemoteInfoTableauGroup.from_dict(group_remote_info_tableau_group_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/GroupTypeEnum.md b/docs/GroupTypeEnum.md index ca6fdbf..9da03f9 100644 --- a/docs/GroupTypeEnum.md +++ b/docs/GroupTypeEnum.md @@ -68,6 +68,8 @@ The type of the group. * `HUBSPOT_TEAM` (value: `'HUBSPOT_TEAM'`) +* `TABLEAU_GROUP` (value: `'TABLEAU_GROUP'`) + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/docs/GroupsApi.md b/docs/GroupsApi.md index d311da4..0381d3f 100644 --- a/docs/GroupsApi.md +++ b/docs/GroupsApi.md @@ -1257,7 +1257,7 @@ with opal_security.ApiClient(configuration) as api_client: api_instance = opal_security.GroupsApi(api_client) group_id = UUID('4baf8423-db0a-4037-a4cf-f79c60cb67a5') # UUID | The ID of the group. cursor = 'cD0yMDIxLTAxLTA2KzAzJTNBMjQlM0E1My40MzQzMjYlMkIwMCUzQTAw' # str | The pagination cursor value. (optional) - page_size = 200 # int | Number of results to return per page. Default is 200. (optional) + page_size = 200 # int | Number of results to return per page, up to 1000. When set (or when a cursor is provided), the response contains a single page of results and a `next` cursor; the default page size is 200. When both page_size and cursor are omitted, the entire group membership is returned in one response with no `next` cursor. For large groups, prefer setting page_size and following `next`. (optional) try: api_response = api_instance.get_group_users(group_id, cursor=cursor, page_size=page_size) @@ -1276,7 +1276,7 @@ Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **group_id** | **UUID**| The ID of the group. | **cursor** | **str**| The pagination cursor value. | [optional] - **page_size** | **int**| Number of results to return per page. Default is 200. | [optional] + **page_size** | **int**| Number of results to return per page, up to 1000. When set (or when a cursor is provided), the response contains a single page of results and a `next` cursor; the default page size is 200. When both page_size and cursor are omitted, the entire group membership is returned in one response with no `next` cursor. For large groups, prefer setting page_size and following `next`. | [optional] ### Return type diff --git a/docs/PaginatedCampaignsList.md b/docs/PaginatedCampaignsList.md new file mode 100644 index 0000000..97bd506 --- /dev/null +++ b/docs/PaginatedCampaignsList.md @@ -0,0 +1,32 @@ +# PaginatedCampaignsList + +A list of campaigns. + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**next** | **str** | The cursor with which to continue pagination if additional result pages exist. | [optional] +**previous** | **str** | The cursor used to obtain the current result page. | [optional] +**results** | [**List[Campaign]**](Campaign.md) | | + +## Example + +```python +from opal_security.models.paginated_campaigns_list import PaginatedCampaignsList + +# TODO update the JSON string below +json = "{}" +# create an instance of PaginatedCampaignsList from a JSON string +paginated_campaigns_list_instance = PaginatedCampaignsList.from_json(json) +# print the JSON string representation of the object +print(PaginatedCampaignsList.to_json()) + +# convert the object into a dict +paginated_campaigns_list_dict = paginated_campaigns_list_instance.to_dict() +# create an instance of PaginatedCampaignsList from a dict +paginated_campaigns_list_from_dict = PaginatedCampaignsList.from_dict(paginated_campaigns_list_dict) +``` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/PropagationStatusEnum.md b/docs/PropagationStatusEnum.md index ded75f9..74eb900 100644 --- a/docs/PropagationStatusEnum.md +++ b/docs/PropagationStatusEnum.md @@ -46,6 +46,8 @@ The status of whether the user has been synced to the group or resource in the r * `ERR_REMOTE_UNRECOVERABLE_ERROR` (value: `'ERR_REMOTE_UNRECOVERABLE_ERROR'`) +* `ERR_REMOTE_TICKET_NOT_FOUND` (value: `'ERR_REMOTE_TICKET_NOT_FOUND'`) + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/opal_security/__init__.py b/opal_security/__init__.py index bfd68aa..af76bf7 100644 --- a/opal_security/__init__.py +++ b/opal_security/__init__.py @@ -22,6 +22,7 @@ "AccessRulesApi", "AppsApi", "BundlesApi", + "CampaignsApi", "ConfigurationTemplatesApi", "DelegationsApi", "EventStreamsApi", @@ -75,6 +76,11 @@ "Bundle", "BundleGroup", "BundleResource", + "Campaign", + "CampaignConfiguration", + "CampaignGroupAssetVisibilityPolicyEnum", + "CampaignRevokeOnEnum", + "CampaignStatusEnum", "Condition", "ConfigurationTemplate", "CreateBundleInfo", @@ -141,6 +147,7 @@ "GroupRemoteInfoRootlyOnCallSchedule", "GroupRemoteInfoSlackUserGroup", "GroupRemoteInfoSnowflakeRole", + "GroupRemoteInfoTableauGroup", "GroupRemoteInfoTailscaleGroup", "GroupRemoteInfoTwingateGroup", "GroupRemoteInfoTwingateGroupSynced", @@ -175,6 +182,7 @@ "PaginatedBundleGroupList", "PaginatedBundleList", "PaginatedBundleResourceList", + "PaginatedCampaignsList", "PaginatedConfigurationTemplateList", "PaginatedDelegationsList", "PaginatedEventList", @@ -355,6 +363,7 @@ from opal_security.api.access_rules_api import AccessRulesApi as AccessRulesApi from opal_security.api.apps_api import AppsApi as AppsApi from opal_security.api.bundles_api import BundlesApi as BundlesApi +from opal_security.api.campaigns_api import CampaignsApi as CampaignsApi from opal_security.api.configuration_templates_api import ConfigurationTemplatesApi as ConfigurationTemplatesApi from opal_security.api.delegations_api import DelegationsApi as DelegationsApi from opal_security.api.event_streams_api import EventStreamsApi as EventStreamsApi @@ -412,6 +421,11 @@ from opal_security.models.bundle import Bundle as Bundle from opal_security.models.bundle_group import BundleGroup as BundleGroup from opal_security.models.bundle_resource import BundleResource as BundleResource +from opal_security.models.campaign import Campaign as Campaign +from opal_security.models.campaign_configuration import CampaignConfiguration as CampaignConfiguration +from opal_security.models.campaign_group_asset_visibility_policy_enum import CampaignGroupAssetVisibilityPolicyEnum as CampaignGroupAssetVisibilityPolicyEnum +from opal_security.models.campaign_revoke_on_enum import CampaignRevokeOnEnum as CampaignRevokeOnEnum +from opal_security.models.campaign_status_enum import CampaignStatusEnum as CampaignStatusEnum from opal_security.models.condition import Condition as Condition from opal_security.models.configuration_template import ConfigurationTemplate as ConfigurationTemplate from opal_security.models.create_bundle_info import CreateBundleInfo as CreateBundleInfo @@ -478,6 +492,7 @@ from opal_security.models.group_remote_info_rootly_on_call_schedule import GroupRemoteInfoRootlyOnCallSchedule as GroupRemoteInfoRootlyOnCallSchedule from opal_security.models.group_remote_info_slack_user_group import GroupRemoteInfoSlackUserGroup as GroupRemoteInfoSlackUserGroup from opal_security.models.group_remote_info_snowflake_role import GroupRemoteInfoSnowflakeRole as GroupRemoteInfoSnowflakeRole +from opal_security.models.group_remote_info_tableau_group import GroupRemoteInfoTableauGroup as GroupRemoteInfoTableauGroup from opal_security.models.group_remote_info_tailscale_group import GroupRemoteInfoTailscaleGroup as GroupRemoteInfoTailscaleGroup from opal_security.models.group_remote_info_twingate_group import GroupRemoteInfoTwingateGroup as GroupRemoteInfoTwingateGroup from opal_security.models.group_remote_info_twingate_group_synced import GroupRemoteInfoTwingateGroupSynced as GroupRemoteInfoTwingateGroupSynced @@ -512,6 +527,7 @@ from opal_security.models.paginated_bundle_group_list import PaginatedBundleGroupList as PaginatedBundleGroupList from opal_security.models.paginated_bundle_list import PaginatedBundleList as PaginatedBundleList from opal_security.models.paginated_bundle_resource_list import PaginatedBundleResourceList as PaginatedBundleResourceList +from opal_security.models.paginated_campaigns_list import PaginatedCampaignsList as PaginatedCampaignsList from opal_security.models.paginated_configuration_template_list import PaginatedConfigurationTemplateList as PaginatedConfigurationTemplateList from opal_security.models.paginated_delegations_list import PaginatedDelegationsList as PaginatedDelegationsList from opal_security.models.paginated_event_list import PaginatedEventList as PaginatedEventList diff --git a/opal_security/api/__init__.py b/opal_security/api/__init__.py index 27c0e8e..17804a9 100644 --- a/opal_security/api/__init__.py +++ b/opal_security/api/__init__.py @@ -4,6 +4,7 @@ from opal_security.api.access_rules_api import AccessRulesApi from opal_security.api.apps_api import AppsApi from opal_security.api.bundles_api import BundlesApi +from opal_security.api.campaigns_api import CampaignsApi from opal_security.api.configuration_templates_api import ConfigurationTemplatesApi from opal_security.api.delegations_api import DelegationsApi from opal_security.api.event_streams_api import EventStreamsApi diff --git a/opal_security/api/campaigns_api.py b/opal_security/api/campaigns_api.py new file mode 100644 index 0000000..a4cf235 --- /dev/null +++ b/opal_security/api/campaigns_api.py @@ -0,0 +1,827 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + +import warnings +from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt +from typing import Any, Dict, List, Optional, Tuple, Union +from typing_extensions import Annotated + +from datetime import datetime +from pydantic import Field, StrictStr +from typing import Optional +from typing_extensions import Annotated +from uuid import UUID +from opal_security.models.campaign import Campaign +from opal_security.models.campaign_status_enum import CampaignStatusEnum +from opal_security.models.paginated_campaigns_list import PaginatedCampaignsList + +from opal_security.api_client import ApiClient, RequestSerialized +from opal_security.api_response import ApiResponse +from opal_security.rest import RESTResponseType + + +class CampaignsApi: + """NOTE: This class is auto generated by OpenAPI Generator + Ref: https://openapi-generator.tech + + Do not edit the class manually. + """ + + def __init__(self, api_client=None) -> None: + if api_client is None: + api_client = ApiClient.get_default() + self.api_client = api_client + + + @validate_call + def get_campaign( + self, + campaign_id: Annotated[UUID, Field(description="The ID of the campaign.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> Campaign: + """Get campaign by ID + + Returns a `Campaign` object. + + :param campaign_id: The ID of the campaign. (required) + :type campaign_id: UUID + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._get_campaign_serialize( + campaign_id=campaign_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "Campaign", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def get_campaign_with_http_info( + self, + campaign_id: Annotated[UUID, Field(description="The ID of the campaign.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[Campaign]: + """Get campaign by ID + + Returns a `Campaign` object. + + :param campaign_id: The ID of the campaign. (required) + :type campaign_id: UUID + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._get_campaign_serialize( + campaign_id=campaign_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "Campaign", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def get_campaign_without_preload_content( + self, + campaign_id: Annotated[UUID, Field(description="The ID of the campaign.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Get campaign by ID + + Returns a `Campaign` object. + + :param campaign_id: The ID of the campaign. (required) + :type campaign_id: UUID + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._get_campaign_serialize( + campaign_id=campaign_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "Campaign", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _get_campaign_serialize( + self, + campaign_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if campaign_id is not None: + _path_params['campaign_id'] = campaign_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'BearerAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/campaigns/{campaign_id}', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + + + @validate_call + def get_campaigns( + self, + cursor: Annotated[Optional[StrictStr], Field(description="The pagination cursor value.")] = None, + page_size: Annotated[Optional[Annotated[int, Field(le=1000, strict=True)]], Field(description="Number of results to return per page. Default is 200.")] = None, + name: Annotated[Optional[StrictStr], Field(description="Campaign name to filter by. Returns campaigns whose names contain this substring (case-insensitive).")] = None, + status: Annotated[Optional[CampaignStatusEnum], Field(description="Filter by campaign status. Status is derived from lifecycle timestamps and review progress.")] = None, + created_at_after: Annotated[Optional[datetime], Field(description="Include campaigns created after this timestamp (exclusive). ISO 8601 format.")] = None, + created_at_before: Annotated[Optional[datetime], Field(description="Include campaigns created before this timestamp (exclusive). ISO 8601 format.")] = None, + started_at_after: Annotated[Optional[datetime], Field(description="Include campaigns started after this timestamp (exclusive). ISO 8601 format.")] = None, + started_at_before: Annotated[Optional[datetime], Field(description="Include campaigns started before this timestamp (exclusive). ISO 8601 format.")] = None, + ended_at_after: Annotated[Optional[datetime], Field(description="Include campaigns ended after this timestamp (exclusive). ISO 8601 format.")] = None, + ended_at_before: Annotated[Optional[datetime], Field(description="Include campaigns ended before this timestamp (exclusive). ISO 8601 format.")] = None, + stopped_at_after: Annotated[Optional[datetime], Field(description="Include campaigns stopped after this timestamp (exclusive). ISO 8601 format.")] = None, + stopped_at_before: Annotated[Optional[datetime], Field(description="Include campaigns stopped before this timestamp (exclusive). ISO 8601 format.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> PaginatedCampaignsList: + """get_campaigns + + Returns a list of `Campaign` objects. + + :param cursor: The pagination cursor value. + :type cursor: str + :param page_size: Number of results to return per page. Default is 200. + :type page_size: int + :param name: Campaign name to filter by. Returns campaigns whose names contain this substring (case-insensitive). + :type name: str + :param status: Filter by campaign status. Status is derived from lifecycle timestamps and review progress. + :type status: CampaignStatusEnum + :param created_at_after: Include campaigns created after this timestamp (exclusive). ISO 8601 format. + :type created_at_after: datetime + :param created_at_before: Include campaigns created before this timestamp (exclusive). ISO 8601 format. + :type created_at_before: datetime + :param started_at_after: Include campaigns started after this timestamp (exclusive). ISO 8601 format. + :type started_at_after: datetime + :param started_at_before: Include campaigns started before this timestamp (exclusive). ISO 8601 format. + :type started_at_before: datetime + :param ended_at_after: Include campaigns ended after this timestamp (exclusive). ISO 8601 format. + :type ended_at_after: datetime + :param ended_at_before: Include campaigns ended before this timestamp (exclusive). ISO 8601 format. + :type ended_at_before: datetime + :param stopped_at_after: Include campaigns stopped after this timestamp (exclusive). ISO 8601 format. + :type stopped_at_after: datetime + :param stopped_at_before: Include campaigns stopped before this timestamp (exclusive). ISO 8601 format. + :type stopped_at_before: datetime + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._get_campaigns_serialize( + cursor=cursor, + page_size=page_size, + name=name, + status=status, + created_at_after=created_at_after, + created_at_before=created_at_before, + started_at_after=started_at_after, + started_at_before=started_at_before, + ended_at_after=ended_at_after, + ended_at_before=ended_at_before, + stopped_at_after=stopped_at_after, + stopped_at_before=stopped_at_before, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "PaginatedCampaignsList", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def get_campaigns_with_http_info( + self, + cursor: Annotated[Optional[StrictStr], Field(description="The pagination cursor value.")] = None, + page_size: Annotated[Optional[Annotated[int, Field(le=1000, strict=True)]], Field(description="Number of results to return per page. Default is 200.")] = None, + name: Annotated[Optional[StrictStr], Field(description="Campaign name to filter by. Returns campaigns whose names contain this substring (case-insensitive).")] = None, + status: Annotated[Optional[CampaignStatusEnum], Field(description="Filter by campaign status. Status is derived from lifecycle timestamps and review progress.")] = None, + created_at_after: Annotated[Optional[datetime], Field(description="Include campaigns created after this timestamp (exclusive). ISO 8601 format.")] = None, + created_at_before: Annotated[Optional[datetime], Field(description="Include campaigns created before this timestamp (exclusive). ISO 8601 format.")] = None, + started_at_after: Annotated[Optional[datetime], Field(description="Include campaigns started after this timestamp (exclusive). ISO 8601 format.")] = None, + started_at_before: Annotated[Optional[datetime], Field(description="Include campaigns started before this timestamp (exclusive). ISO 8601 format.")] = None, + ended_at_after: Annotated[Optional[datetime], Field(description="Include campaigns ended after this timestamp (exclusive). ISO 8601 format.")] = None, + ended_at_before: Annotated[Optional[datetime], Field(description="Include campaigns ended before this timestamp (exclusive). ISO 8601 format.")] = None, + stopped_at_after: Annotated[Optional[datetime], Field(description="Include campaigns stopped after this timestamp (exclusive). ISO 8601 format.")] = None, + stopped_at_before: Annotated[Optional[datetime], Field(description="Include campaigns stopped before this timestamp (exclusive). ISO 8601 format.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[PaginatedCampaignsList]: + """get_campaigns + + Returns a list of `Campaign` objects. + + :param cursor: The pagination cursor value. + :type cursor: str + :param page_size: Number of results to return per page. Default is 200. + :type page_size: int + :param name: Campaign name to filter by. Returns campaigns whose names contain this substring (case-insensitive). + :type name: str + :param status: Filter by campaign status. Status is derived from lifecycle timestamps and review progress. + :type status: CampaignStatusEnum + :param created_at_after: Include campaigns created after this timestamp (exclusive). ISO 8601 format. + :type created_at_after: datetime + :param created_at_before: Include campaigns created before this timestamp (exclusive). ISO 8601 format. + :type created_at_before: datetime + :param started_at_after: Include campaigns started after this timestamp (exclusive). ISO 8601 format. + :type started_at_after: datetime + :param started_at_before: Include campaigns started before this timestamp (exclusive). ISO 8601 format. + :type started_at_before: datetime + :param ended_at_after: Include campaigns ended after this timestamp (exclusive). ISO 8601 format. + :type ended_at_after: datetime + :param ended_at_before: Include campaigns ended before this timestamp (exclusive). ISO 8601 format. + :type ended_at_before: datetime + :param stopped_at_after: Include campaigns stopped after this timestamp (exclusive). ISO 8601 format. + :type stopped_at_after: datetime + :param stopped_at_before: Include campaigns stopped before this timestamp (exclusive). ISO 8601 format. + :type stopped_at_before: datetime + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._get_campaigns_serialize( + cursor=cursor, + page_size=page_size, + name=name, + status=status, + created_at_after=created_at_after, + created_at_before=created_at_before, + started_at_after=started_at_after, + started_at_before=started_at_before, + ended_at_after=ended_at_after, + ended_at_before=ended_at_before, + stopped_at_after=stopped_at_after, + stopped_at_before=stopped_at_before, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "PaginatedCampaignsList", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def get_campaigns_without_preload_content( + self, + cursor: Annotated[Optional[StrictStr], Field(description="The pagination cursor value.")] = None, + page_size: Annotated[Optional[Annotated[int, Field(le=1000, strict=True)]], Field(description="Number of results to return per page. Default is 200.")] = None, + name: Annotated[Optional[StrictStr], Field(description="Campaign name to filter by. Returns campaigns whose names contain this substring (case-insensitive).")] = None, + status: Annotated[Optional[CampaignStatusEnum], Field(description="Filter by campaign status. Status is derived from lifecycle timestamps and review progress.")] = None, + created_at_after: Annotated[Optional[datetime], Field(description="Include campaigns created after this timestamp (exclusive). ISO 8601 format.")] = None, + created_at_before: Annotated[Optional[datetime], Field(description="Include campaigns created before this timestamp (exclusive). ISO 8601 format.")] = None, + started_at_after: Annotated[Optional[datetime], Field(description="Include campaigns started after this timestamp (exclusive). ISO 8601 format.")] = None, + started_at_before: Annotated[Optional[datetime], Field(description="Include campaigns started before this timestamp (exclusive). ISO 8601 format.")] = None, + ended_at_after: Annotated[Optional[datetime], Field(description="Include campaigns ended after this timestamp (exclusive). ISO 8601 format.")] = None, + ended_at_before: Annotated[Optional[datetime], Field(description="Include campaigns ended before this timestamp (exclusive). ISO 8601 format.")] = None, + stopped_at_after: Annotated[Optional[datetime], Field(description="Include campaigns stopped after this timestamp (exclusive). ISO 8601 format.")] = None, + stopped_at_before: Annotated[Optional[datetime], Field(description="Include campaigns stopped before this timestamp (exclusive). ISO 8601 format.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """get_campaigns + + Returns a list of `Campaign` objects. + + :param cursor: The pagination cursor value. + :type cursor: str + :param page_size: Number of results to return per page. Default is 200. + :type page_size: int + :param name: Campaign name to filter by. Returns campaigns whose names contain this substring (case-insensitive). + :type name: str + :param status: Filter by campaign status. Status is derived from lifecycle timestamps and review progress. + :type status: CampaignStatusEnum + :param created_at_after: Include campaigns created after this timestamp (exclusive). ISO 8601 format. + :type created_at_after: datetime + :param created_at_before: Include campaigns created before this timestamp (exclusive). ISO 8601 format. + :type created_at_before: datetime + :param started_at_after: Include campaigns started after this timestamp (exclusive). ISO 8601 format. + :type started_at_after: datetime + :param started_at_before: Include campaigns started before this timestamp (exclusive). ISO 8601 format. + :type started_at_before: datetime + :param ended_at_after: Include campaigns ended after this timestamp (exclusive). ISO 8601 format. + :type ended_at_after: datetime + :param ended_at_before: Include campaigns ended before this timestamp (exclusive). ISO 8601 format. + :type ended_at_before: datetime + :param stopped_at_after: Include campaigns stopped after this timestamp (exclusive). ISO 8601 format. + :type stopped_at_after: datetime + :param stopped_at_before: Include campaigns stopped before this timestamp (exclusive). ISO 8601 format. + :type stopped_at_before: datetime + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._get_campaigns_serialize( + cursor=cursor, + page_size=page_size, + name=name, + status=status, + created_at_after=created_at_after, + created_at_before=created_at_before, + started_at_after=started_at_after, + started_at_before=started_at_before, + ended_at_after=ended_at_after, + ended_at_before=ended_at_before, + stopped_at_after=stopped_at_after, + stopped_at_before=stopped_at_before, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "PaginatedCampaignsList", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _get_campaigns_serialize( + self, + cursor, + page_size, + name, + status, + created_at_after, + created_at_before, + started_at_after, + started_at_before, + ended_at_after, + ended_at_before, + stopped_at_after, + stopped_at_before, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + if cursor is not None: + + _query_params.append(('cursor', cursor)) + + if page_size is not None: + + _query_params.append(('page_size', page_size)) + + if name is not None: + + _query_params.append(('name', name)) + + if status is not None: + + _query_params.append(('status', status.value)) + + if created_at_after is not None: + if isinstance(created_at_after, datetime): + _query_params.append( + ( + 'created_at_after', + created_at_after.strftime( + self.api_client.configuration.datetime_format + ) + ) + ) + else: + _query_params.append(('created_at_after', created_at_after)) + + if created_at_before is not None: + if isinstance(created_at_before, datetime): + _query_params.append( + ( + 'created_at_before', + created_at_before.strftime( + self.api_client.configuration.datetime_format + ) + ) + ) + else: + _query_params.append(('created_at_before', created_at_before)) + + if started_at_after is not None: + if isinstance(started_at_after, datetime): + _query_params.append( + ( + 'started_at_after', + started_at_after.strftime( + self.api_client.configuration.datetime_format + ) + ) + ) + else: + _query_params.append(('started_at_after', started_at_after)) + + if started_at_before is not None: + if isinstance(started_at_before, datetime): + _query_params.append( + ( + 'started_at_before', + started_at_before.strftime( + self.api_client.configuration.datetime_format + ) + ) + ) + else: + _query_params.append(('started_at_before', started_at_before)) + + if ended_at_after is not None: + if isinstance(ended_at_after, datetime): + _query_params.append( + ( + 'ended_at_after', + ended_at_after.strftime( + self.api_client.configuration.datetime_format + ) + ) + ) + else: + _query_params.append(('ended_at_after', ended_at_after)) + + if ended_at_before is not None: + if isinstance(ended_at_before, datetime): + _query_params.append( + ( + 'ended_at_before', + ended_at_before.strftime( + self.api_client.configuration.datetime_format + ) + ) + ) + else: + _query_params.append(('ended_at_before', ended_at_before)) + + if stopped_at_after is not None: + if isinstance(stopped_at_after, datetime): + _query_params.append( + ( + 'stopped_at_after', + stopped_at_after.strftime( + self.api_client.configuration.datetime_format + ) + ) + ) + else: + _query_params.append(('stopped_at_after', stopped_at_after)) + + if stopped_at_before is not None: + if isinstance(stopped_at_before, datetime): + _query_params.append( + ( + 'stopped_at_before', + stopped_at_before.strftime( + self.api_client.configuration.datetime_format + ) + ) + ) + else: + _query_params.append(('stopped_at_before', stopped_at_before)) + + # process the header parameters + # process the form parameters + # process the body parameter + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + + # authentication setting + _auth_settings: List[str] = [ + 'BearerAuth' + ] + + return self.api_client.param_serialize( + method='GET', + resource_path='/campaigns', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + diff --git a/opal_security/api/groups_api.py b/opal_security/api/groups_api.py index 37436ce..7b91076 100644 --- a/opal_security/api/groups_api.py +++ b/opal_security/api/groups_api.py @@ -4218,7 +4218,7 @@ def get_group_users( self, group_id: Annotated[UUID, Field(description="The ID of the group.")], cursor: Annotated[Optional[StrictStr], Field(description="The pagination cursor value.")] = None, - page_size: Annotated[Optional[Annotated[int, Field(le=1000, strict=True)]], Field(description="Number of results to return per page. Default is 200.")] = None, + page_size: Annotated[Optional[Annotated[int, Field(le=1000, strict=True)]], Field(description="Number of results to return per page, up to 1000. When set (or when a cursor is provided), the response contains a single page of results and a `next` cursor; the default page size is 200. When both page_size and cursor are omitted, the entire group membership is returned in one response with no `next` cursor. For large groups, prefer setting page_size and following `next`.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -4240,7 +4240,7 @@ def get_group_users( :type group_id: UUID :param cursor: The pagination cursor value. :type cursor: str - :param page_size: Number of results to return per page. Default is 200. + :param page_size: Number of results to return per page, up to 1000. When set (or when a cursor is provided), the response contains a single page of results and a `next` cursor; the default page size is 200. When both page_size and cursor are omitted, the entire group membership is returned in one response with no `next` cursor. For large groups, prefer setting page_size and following `next`. :type page_size: int :param _request_timeout: timeout setting for this request. If one number provided, it will be total request @@ -4293,7 +4293,7 @@ def get_group_users_with_http_info( self, group_id: Annotated[UUID, Field(description="The ID of the group.")], cursor: Annotated[Optional[StrictStr], Field(description="The pagination cursor value.")] = None, - page_size: Annotated[Optional[Annotated[int, Field(le=1000, strict=True)]], Field(description="Number of results to return per page. Default is 200.")] = None, + page_size: Annotated[Optional[Annotated[int, Field(le=1000, strict=True)]], Field(description="Number of results to return per page, up to 1000. When set (or when a cursor is provided), the response contains a single page of results and a `next` cursor; the default page size is 200. When both page_size and cursor are omitted, the entire group membership is returned in one response with no `next` cursor. For large groups, prefer setting page_size and following `next`.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -4315,7 +4315,7 @@ def get_group_users_with_http_info( :type group_id: UUID :param cursor: The pagination cursor value. :type cursor: str - :param page_size: Number of results to return per page. Default is 200. + :param page_size: Number of results to return per page, up to 1000. When set (or when a cursor is provided), the response contains a single page of results and a `next` cursor; the default page size is 200. When both page_size and cursor are omitted, the entire group membership is returned in one response with no `next` cursor. For large groups, prefer setting page_size and following `next`. :type page_size: int :param _request_timeout: timeout setting for this request. If one number provided, it will be total request @@ -4368,7 +4368,7 @@ def get_group_users_without_preload_content( self, group_id: Annotated[UUID, Field(description="The ID of the group.")], cursor: Annotated[Optional[StrictStr], Field(description="The pagination cursor value.")] = None, - page_size: Annotated[Optional[Annotated[int, Field(le=1000, strict=True)]], Field(description="Number of results to return per page. Default is 200.")] = None, + page_size: Annotated[Optional[Annotated[int, Field(le=1000, strict=True)]], Field(description="Number of results to return per page, up to 1000. When set (or when a cursor is provided), the response contains a single page of results and a `next` cursor; the default page size is 200. When both page_size and cursor are omitted, the entire group membership is returned in one response with no `next` cursor. For large groups, prefer setting page_size and following `next`.")] = None, _request_timeout: Union[ None, Annotated[StrictFloat, Field(gt=0)], @@ -4390,7 +4390,7 @@ def get_group_users_without_preload_content( :type group_id: UUID :param cursor: The pagination cursor value. :type cursor: str - :param page_size: Number of results to return per page. Default is 200. + :param page_size: Number of results to return per page, up to 1000. When set (or when a cursor is provided), the response contains a single page of results and a `next` cursor; the default page size is 200. When both page_size and cursor are omitted, the entire group membership is returned in one response with no `next` cursor. For large groups, prefer setting page_size and following `next`. :type page_size: int :param _request_timeout: timeout setting for this request. If one number provided, it will be total request diff --git a/opal_security/models/__init__.py b/opal_security/models/__init__.py index e39bbb8..8be83cc 100644 --- a/opal_security/models/__init__.py +++ b/opal_security/models/__init__.py @@ -39,6 +39,11 @@ from opal_security.models.bundle import Bundle from opal_security.models.bundle_group import BundleGroup from opal_security.models.bundle_resource import BundleResource +from opal_security.models.campaign import Campaign +from opal_security.models.campaign_configuration import CampaignConfiguration +from opal_security.models.campaign_group_asset_visibility_policy_enum import CampaignGroupAssetVisibilityPolicyEnum +from opal_security.models.campaign_revoke_on_enum import CampaignRevokeOnEnum +from opal_security.models.campaign_status_enum import CampaignStatusEnum from opal_security.models.condition import Condition from opal_security.models.configuration_template import ConfigurationTemplate from opal_security.models.create_bundle_info import CreateBundleInfo @@ -105,6 +110,7 @@ from opal_security.models.group_remote_info_rootly_on_call_schedule import GroupRemoteInfoRootlyOnCallSchedule from opal_security.models.group_remote_info_slack_user_group import GroupRemoteInfoSlackUserGroup from opal_security.models.group_remote_info_snowflake_role import GroupRemoteInfoSnowflakeRole +from opal_security.models.group_remote_info_tableau_group import GroupRemoteInfoTableauGroup from opal_security.models.group_remote_info_tailscale_group import GroupRemoteInfoTailscaleGroup from opal_security.models.group_remote_info_twingate_group import GroupRemoteInfoTwingateGroup from opal_security.models.group_remote_info_twingate_group_synced import GroupRemoteInfoTwingateGroupSynced @@ -139,6 +145,7 @@ from opal_security.models.paginated_bundle_group_list import PaginatedBundleGroupList from opal_security.models.paginated_bundle_list import PaginatedBundleList from opal_security.models.paginated_bundle_resource_list import PaginatedBundleResourceList +from opal_security.models.paginated_campaigns_list import PaginatedCampaignsList from opal_security.models.paginated_configuration_template_list import PaginatedConfigurationTemplateList from opal_security.models.paginated_delegations_list import PaginatedDelegationsList from opal_security.models.paginated_event_list import PaginatedEventList diff --git a/opal_security/models/app_type_enum.py b/opal_security/models/app_type_enum.py index 7031cd2..7198576 100644 --- a/opal_security/models/app_type_enum.py +++ b/opal_security/models/app_type_enum.py @@ -68,6 +68,7 @@ class AppTypeEnum(str, Enum): SALESFORCE = 'SALESFORCE' SNOWFLAKE = 'SNOWFLAKE' SLACK = 'SLACK' + TABLEAU = 'TABLEAU' TAILSCALE = 'TAILSCALE' TELEPORT = 'TELEPORT' TWINGATE = 'TWINGATE' diff --git a/opal_security/models/campaign.py b/opal_security/models/campaign.py new file mode 100644 index 0000000..6052422 --- /dev/null +++ b/opal_security/models/campaign.py @@ -0,0 +1,134 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from uuid import UUID +from opal_security.models.campaign_configuration import CampaignConfiguration +from opal_security.models.campaign_status_enum import CampaignStatusEnum +from typing import Optional, Set +from typing_extensions import Self + +class Campaign(BaseModel): + """ + An access review campaign. + """ # noqa: E501 + campaign_id: UUID = Field(description="The ID of the campaign.") + name: StrictStr = Field(description="The name of the campaign.") + status: CampaignStatusEnum + is_template: StrictBool = Field(description="Whether this campaign is a recurring schedule template. Templates spawn draft campaigns on schedule rather than being reviewed directly.") + created_at: datetime = Field(description="The creation time of the campaign.") + updated_at: datetime = Field(description="The last updated time of the campaign.") + created_by_user_id: UUID = Field(description="The ID of the user who created the campaign.") + configuration: Optional[CampaignConfiguration] = Field(default=None, description="The campaign's configuration, if set.") + started_at: Optional[datetime] = Field(default=None, description="The time the campaign was started, if started.") + started_by_user_id: Optional[UUID] = Field(default=None, description="The ID of the user who started the campaign, if started.") + stopped_at: Optional[datetime] = Field(default=None, description="The time the campaign was manually stopped, if stopped.") + stopped_by_user_id: Optional[UUID] = Field(default=None, description="The ID of the user who stopped the campaign, if stopped.") + ended_at: Optional[datetime] = Field(default=None, description="The time the campaign reached its scheduled end, if ended.") + ended_by_user_id: Optional[UUID] = Field(default=None, description="The ID of the user who ended the campaign, if ended.") + additional_properties: Dict[str, Any] = {} + __properties: ClassVar[List[str]] = ["campaign_id", "name", "status", "is_template", "created_at", "updated_at", "created_by_user_id", "configuration", "started_at", "started_by_user_id", "stopped_at", "stopped_by_user_id", "ended_at", "ended_by_user_id"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of Campaign from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + * Fields in `self.additional_properties` are added to the output dict. + """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of configuration + if self.configuration: + _dict['configuration'] = self.configuration.to_dict() + # puts key-value pairs in additional_properties in the top level + if self.additional_properties is not None: + for _key, _value in self.additional_properties.items(): + _dict[_key] = _value + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of Campaign from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "campaign_id": obj.get("campaign_id"), + "name": obj.get("name"), + "status": obj.get("status"), + "is_template": obj.get("is_template"), + "created_at": obj.get("created_at"), + "updated_at": obj.get("updated_at"), + "created_by_user_id": obj.get("created_by_user_id"), + "configuration": CampaignConfiguration.from_dict(obj["configuration"]) if obj.get("configuration") is not None else None, + "started_at": obj.get("started_at"), + "started_by_user_id": obj.get("started_by_user_id"), + "stopped_at": obj.get("stopped_at"), + "stopped_by_user_id": obj.get("stopped_by_user_id"), + "ended_at": obj.get("ended_at"), + "ended_by_user_id": obj.get("ended_by_user_id") + }) + # store additional fields in additional_properties + for _key in obj.keys(): + if _key not in cls.__properties: + _obj.additional_properties[_key] = obj.get(_key) + + return _obj + + diff --git a/opal_security/models/campaign_configuration.py b/opal_security/models/campaign_configuration.py new file mode 100644 index 0000000..be990a0 --- /dev/null +++ b/opal_security/models/campaign_configuration.py @@ -0,0 +1,150 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from uuid import UUID +from opal_security.models.campaign_group_asset_visibility_policy_enum import CampaignGroupAssetVisibilityPolicyEnum +from opal_security.models.campaign_revoke_on_enum import CampaignRevokeOnEnum +from opal_security.models.uar_reviewer_assignment_policy_enum import UARReviewerAssignmentPolicyEnum +from typing import Optional, Set +from typing_extensions import Self + +class CampaignConfiguration(BaseModel): + """ + Configuration for an access review campaign. + """ # noqa: E501 + configuration_id: UUID = Field(description="The ID of the campaign configuration.") + created_at: datetime = Field(description="The creation time of the configuration.") + updated_at: datetime = Field(description="The last updated time of the configuration.") + query: Optional[Dict[str, Any]] = Field(default=None, description="Edge-based query defining the scope of access to review. Matches the stored Opal edge-query JSON shape.") + reviewer_assignment_policy: UARReviewerAssignmentPolicyEnum + allow_self_review: StrictBool = Field(description="Whether reviewers can review their own access.") + send_reviewer_assignment_notification: StrictBool = Field(description="Whether to notify reviewers upon assignment.") + allow_reviewer_reassignment: StrictBool = Field(description="Whether reviewers may reassign their reviews to another user.") + start_date: Optional[datetime] = Field(default=None, description="Scheduled start date of the campaign.") + end_date: Optional[datetime] = Field(default=None, description="Scheduled end date of the campaign.") + timezone: StrictStr = Field(description="IANA timezone used to interpret campaign deadlines (e.g. America/Los_Angeles).") + revoke_on: CampaignRevokeOnEnum + reminder_schedule: Optional[List[StrictInt]] = Field(default=None, description="Days before end date to send reminder notifications.") + reminder_include_manager: StrictBool = Field(description="Whether to include the reviewer's manager in reminders.") + require_reason_on_denial: StrictBool = Field(description="Whether reviewers must provide a reason when denying (revoking) access.") + hide_ai_suggestions: StrictBool = Field(description="Whether AI suggestions are hidden from reviewers.") + custom_start_message: Optional[StrictStr] = Field(default=None, description="Optional custom message included when notifying reviewers that the campaign started.") + group_asset_visibility_policy: CampaignGroupAssetVisibilityPolicyEnum + is_template: StrictBool = Field(description="Whether this configuration is a recurring schedule template.") + cron_expression: Optional[StrictStr] = Field(default=None, description="Cron expression driving the recurring schedule. Null for one-off campaigns.") + next_scheduled_run: Optional[datetime] = Field(default=None, description="Next time a draft will be generated from this template.") + last_scheduled_run: Optional[datetime] = Field(default=None, description="Most recent time a draft was generated from this template.") + recurring_duration_days: Optional[StrictInt] = Field(default=None, description="Deadline window in days applied to each draft generated from this template.") + additional_properties: Dict[str, Any] = {} + __properties: ClassVar[List[str]] = ["configuration_id", "created_at", "updated_at", "query", "reviewer_assignment_policy", "allow_self_review", "send_reviewer_assignment_notification", "allow_reviewer_reassignment", "start_date", "end_date", "timezone", "revoke_on", "reminder_schedule", "reminder_include_manager", "require_reason_on_denial", "hide_ai_suggestions", "custom_start_message", "group_asset_visibility_policy", "is_template", "cron_expression", "next_scheduled_run", "last_scheduled_run", "recurring_duration_days"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of CampaignConfiguration from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + * Fields in `self.additional_properties` are added to the output dict. + """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # puts key-value pairs in additional_properties in the top level + if self.additional_properties is not None: + for _key, _value in self.additional_properties.items(): + _dict[_key] = _value + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of CampaignConfiguration from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "configuration_id": obj.get("configuration_id"), + "created_at": obj.get("created_at"), + "updated_at": obj.get("updated_at"), + "query": obj.get("query"), + "reviewer_assignment_policy": obj.get("reviewer_assignment_policy"), + "allow_self_review": obj.get("allow_self_review"), + "send_reviewer_assignment_notification": obj.get("send_reviewer_assignment_notification"), + "allow_reviewer_reassignment": obj.get("allow_reviewer_reassignment"), + "start_date": obj.get("start_date"), + "end_date": obj.get("end_date"), + "timezone": obj.get("timezone"), + "revoke_on": obj.get("revoke_on"), + "reminder_schedule": obj.get("reminder_schedule"), + "reminder_include_manager": obj.get("reminder_include_manager"), + "require_reason_on_denial": obj.get("require_reason_on_denial"), + "hide_ai_suggestions": obj.get("hide_ai_suggestions"), + "custom_start_message": obj.get("custom_start_message"), + "group_asset_visibility_policy": obj.get("group_asset_visibility_policy"), + "is_template": obj.get("is_template"), + "cron_expression": obj.get("cron_expression"), + "next_scheduled_run": obj.get("next_scheduled_run"), + "last_scheduled_run": obj.get("last_scheduled_run"), + "recurring_duration_days": obj.get("recurring_duration_days") + }) + # store additional fields in additional_properties + for _key in obj.keys(): + if _key not in cls.__properties: + _obj.additional_properties[_key] = obj.get(_key) + + return _obj + + diff --git a/opal_security/models/campaign_group_asset_visibility_policy_enum.py b/opal_security/models/campaign_group_asset_visibility_policy_enum.py new file mode 100644 index 0000000..68deed0 --- /dev/null +++ b/opal_security/models/campaign_group_asset_visibility_policy_enum.py @@ -0,0 +1,39 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import json +from enum import Enum +from typing_extensions import Self + + +class CampaignGroupAssetVisibilityPolicyEnum(str, Enum): + """ + Controls what group assets reviewers can see during the campaign. + """ + + """ + allowed enum values + """ + STRICT = 'STRICT' + VIEW_VISIBLE_AND_ASSIGNED = 'VIEW_VISIBLE_AND_ASSIGNED' + VIEW_ALL = 'VIEW_ALL' + + @classmethod + def from_json(cls, json_str: str) -> Self: + """Create an instance of CampaignGroupAssetVisibilityPolicyEnum from a JSON string""" + return cls(json.loads(json_str)) + + diff --git a/opal_security/models/campaign_revoke_on_enum.py b/opal_security/models/campaign_revoke_on_enum.py new file mode 100644 index 0000000..0c9273c --- /dev/null +++ b/opal_security/models/campaign_revoke_on_enum.py @@ -0,0 +1,39 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import json +from enum import Enum +from typing_extensions import Self + + +class CampaignRevokeOnEnum(str, Enum): + """ + When access decisions take effect during a campaign. + """ + + """ + allowed enum values + """ + ACTION = 'ACTION' + END = 'END' + NONE = 'NONE' + + @classmethod + def from_json(cls, json_str: str) -> Self: + """Create an instance of CampaignRevokeOnEnum from a JSON string""" + return cls(json.loads(json_str)) + + diff --git a/opal_security/models/campaign_status_enum.py b/opal_security/models/campaign_status_enum.py new file mode 100644 index 0000000..c3ce7a6 --- /dev/null +++ b/opal_security/models/campaign_status_enum.py @@ -0,0 +1,41 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import json +from enum import Enum +from typing_extensions import Self + + +class CampaignStatusEnum(str, Enum): + """ + The current status of a campaign. + """ + + """ + allowed enum values + """ + DRAFT = 'DRAFT' + ONGOING = 'ONGOING' + COMPLETED = 'COMPLETED' + STOPPED = 'STOPPED' + ENDED = 'ENDED' + + @classmethod + def from_json(cls, json_str: str) -> Self: + """Create an instance of CampaignStatusEnum from a JSON string""" + return cls(json.loads(json_str)) + + diff --git a/opal_security/models/group_remote_info.py b/opal_security/models/group_remote_info.py index 253a55c..f869383 100644 --- a/opal_security/models/group_remote_info.py +++ b/opal_security/models/group_remote_info.py @@ -43,6 +43,7 @@ from opal_security.models.group_remote_info_rootly_on_call_schedule import GroupRemoteInfoRootlyOnCallSchedule from opal_security.models.group_remote_info_slack_user_group import GroupRemoteInfoSlackUserGroup from opal_security.models.group_remote_info_snowflake_role import GroupRemoteInfoSnowflakeRole +from opal_security.models.group_remote_info_tableau_group import GroupRemoteInfoTableauGroup from opal_security.models.group_remote_info_tailscale_group import GroupRemoteInfoTailscaleGroup from opal_security.models.group_remote_info_twingate_group import GroupRemoteInfoTwingateGroup from opal_security.models.group_remote_info_twingate_group_synced import GroupRemoteInfoTwingateGroupSynced @@ -85,8 +86,9 @@ class GroupRemoteInfo(BaseModel): slack_user_group: Optional[GroupRemoteInfoSlackUserGroup] = None zendesk_organization: Optional[GroupRemoteInfoZendeskOrganization] = None hubspot_team: Optional[GroupRemoteInfoHubspotTeam] = None + tableau_group: Optional[GroupRemoteInfoTableauGroup] = None additional_properties: Dict[str, Any] = {} - __properties: ClassVar[List[str]] = ["active_directory_group", "tailscale_group", "twingate_group", "twingate_group_synced", "aws_sso_group", "databricks_account_group", "connector_group", "github_team", "github_enterprise_team", "gitlab_group", "google_group", "ldap_group", "okta_group", "duo_group", "azure_ad_security_group", "azure_ad_microsoft_365_group", "snowflake_role", "okta_group_rule", "workday_user_security_group", "pagerduty_on_call_schedule", "incidentio_on_call_schedule", "rootly_on_call_schedule", "devin_group", "clickhouse_role", "grafana_team", "zendesk_group", "slack_user_group", "zendesk_organization", "hubspot_team"] + __properties: ClassVar[List[str]] = ["active_directory_group", "tailscale_group", "twingate_group", "twingate_group_synced", "aws_sso_group", "databricks_account_group", "connector_group", "github_team", "github_enterprise_team", "gitlab_group", "google_group", "ldap_group", "okta_group", "duo_group", "azure_ad_security_group", "azure_ad_microsoft_365_group", "snowflake_role", "okta_group_rule", "workday_user_security_group", "pagerduty_on_call_schedule", "incidentio_on_call_schedule", "rootly_on_call_schedule", "devin_group", "clickhouse_role", "grafana_team", "zendesk_group", "slack_user_group", "zendesk_organization", "hubspot_team", "tableau_group"] model_config = ConfigDict( populate_by_name=True, @@ -216,6 +218,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of hubspot_team if self.hubspot_team: _dict['hubspot_team'] = self.hubspot_team.to_dict() + # override the default output from pydantic by calling `to_dict()` of tableau_group + if self.tableau_group: + _dict['tableau_group'] = self.tableau_group.to_dict() # puts key-value pairs in additional_properties in the top level if self.additional_properties is not None: for _key, _value in self.additional_properties.items(): @@ -261,7 +266,8 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "zendesk_group": GroupRemoteInfoZendeskGroup.from_dict(obj["zendesk_group"]) if obj.get("zendesk_group") is not None else None, "slack_user_group": GroupRemoteInfoSlackUserGroup.from_dict(obj["slack_user_group"]) if obj.get("slack_user_group") is not None else None, "zendesk_organization": GroupRemoteInfoZendeskOrganization.from_dict(obj["zendesk_organization"]) if obj.get("zendesk_organization") is not None else None, - "hubspot_team": GroupRemoteInfoHubspotTeam.from_dict(obj["hubspot_team"]) if obj.get("hubspot_team") is not None else None + "hubspot_team": GroupRemoteInfoHubspotTeam.from_dict(obj["hubspot_team"]) if obj.get("hubspot_team") is not None else None, + "tableau_group": GroupRemoteInfoTableauGroup.from_dict(obj["tableau_group"]) if obj.get("tableau_group") is not None else None }) # store additional fields in additional_properties for _key in obj.keys(): diff --git a/opal_security/models/group_remote_info_tableau_group.py b/opal_security/models/group_remote_info_tableau_group.py new file mode 100644 index 0000000..cd3dd5f --- /dev/null +++ b/opal_security/models/group_remote_info_tableau_group.py @@ -0,0 +1,101 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set +from typing_extensions import Self + +class GroupRemoteInfoTableauGroup(BaseModel): + """ + Remote info for Tableau group. + """ # noqa: E501 + group_id: StrictStr = Field(description="The ID of the Tableau group.") + additional_properties: Dict[str, Any] = {} + __properties: ClassVar[List[str]] = ["group_id"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of GroupRemoteInfoTableauGroup from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + * Fields in `self.additional_properties` are added to the output dict. + """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # puts key-value pairs in additional_properties in the top level + if self.additional_properties is not None: + for _key, _value in self.additional_properties.items(): + _dict[_key] = _value + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of GroupRemoteInfoTableauGroup from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "group_id": obj.get("group_id") + }) + # store additional fields in additional_properties + for _key in obj.keys(): + if _key not in cls.__properties: + _obj.additional_properties[_key] = obj.get(_key) + + return _obj + + diff --git a/opal_security/models/group_type_enum.py b/opal_security/models/group_type_enum.py index 64a2bc4..ad70286 100644 --- a/opal_security/models/group_type_enum.py +++ b/opal_security/models/group_type_enum.py @@ -59,6 +59,7 @@ class GroupTypeEnum(str, Enum): ZENDESK_GROUP = 'ZENDESK_GROUP' ZENDESK_ORGANIZATION = 'ZENDESK_ORGANIZATION' HUBSPOT_TEAM = 'HUBSPOT_TEAM' + TABLEAU_GROUP = 'TABLEAU_GROUP' @classmethod def from_json(cls, json_str: str) -> Self: diff --git a/opal_security/models/paginated_campaigns_list.py b/opal_security/models/paginated_campaigns_list.py new file mode 100644 index 0000000..6bbb552 --- /dev/null +++ b/opal_security/models/paginated_campaigns_list.py @@ -0,0 +1,113 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from opal_security.models.campaign import Campaign +from typing import Optional, Set +from typing_extensions import Self + +class PaginatedCampaignsList(BaseModel): + """ + A list of campaigns. + """ # noqa: E501 + next: Optional[StrictStr] = Field(default=None, description="The cursor with which to continue pagination if additional result pages exist.") + previous: Optional[StrictStr] = Field(default=None, description="The cursor used to obtain the current result page.") + results: List[Campaign] + additional_properties: Dict[str, Any] = {} + __properties: ClassVar[List[str]] = ["next", "previous", "results"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of PaginatedCampaignsList from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + * Fields in `self.additional_properties` are added to the output dict. + """ + excluded_fields: Set[str] = set([ + "additional_properties", + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of each item in results (list) + _items = [] + if self.results: + for _item_results in self.results: + if _item_results: + _items.append(_item_results.to_dict()) + _dict['results'] = _items + # puts key-value pairs in additional_properties in the top level + if self.additional_properties is not None: + for _key, _value in self.additional_properties.items(): + _dict[_key] = _value + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of PaginatedCampaignsList from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "next": obj.get("next"), + "previous": obj.get("previous"), + "results": [Campaign.from_dict(_item) for _item in obj["results"]] if obj.get("results") is not None else None + }) + # store additional fields in additional_properties + for _key in obj.keys(): + if _key not in cls.__properties: + _obj.additional_properties[_key] = obj.get(_key) + + return _obj + + diff --git a/opal_security/models/propagation_status_enum.py b/opal_security/models/propagation_status_enum.py index 0a98d55..db9bba6 100644 --- a/opal_security/models/propagation_status_enum.py +++ b/opal_security/models/propagation_status_enum.py @@ -48,6 +48,7 @@ class PropagationStatusEnum(str, Enum): ERR_DRY_RUN_MODE_ENABLED = 'ERR_DRY_RUN_MODE_ENABLED' ERR_HR_IDP_PROVIDER_NOT_LINKED = 'ERR_HR_IDP_PROVIDER_NOT_LINKED' ERR_REMOTE_UNRECOVERABLE_ERROR = 'ERR_REMOTE_UNRECOVERABLE_ERROR' + ERR_REMOTE_TICKET_NOT_FOUND = 'ERR_REMOTE_TICKET_NOT_FOUND' @classmethod def from_json(cls, json_str: str) -> Self: diff --git a/test/test_campaign.py b/test/test_campaign.py new file mode 100644 index 0000000..b12413b --- /dev/null +++ b/test/test_campaign.py @@ -0,0 +1,72 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from opal_security.models.campaign import Campaign + +class TestCampaign(unittest.TestCase): + """Campaign unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional) -> Campaign: + """Test Campaign + include_optional is a boolean, when False only required + params are included, when True both required and + optional params are included """ + # uncomment below to create an instance of `Campaign` + """ + model = Campaign() + if include_optional: + return Campaign( + campaign_id = 'f454d283-ca87-4a8a-bdbb-df212eca5353', + name = 'Q3 Access Review', + status = 'ONGOING', + is_template = False, + created_at = '2026-07-01T00:00:00.000+00:00', + updated_at = '2026-07-01T00:00:00.000+00:00', + created_by_user_id = '32acc112-21ff-4669-91c2-21e27683eaa1', + configuration = {"configuration_id":"39a4d283-ca87-4a8a-bdbb-df212eca5fdb","created_at":"2026-07-01T00:00:00.000+00:00","updated_at":"2026-07-01T00:00:00.000+00:00","reviewer_assignment_policy":"MANUALLY","allow_self_review":false,"send_reviewer_assignment_notification":true,"allow_reviewer_reassignment":false,"end_date":"2026-09-30T00:00:00.000+00:00","timezone":"America/Los_Angeles","revoke_on":"END","reminder_schedule":[7,3,1],"reminder_include_manager":true,"require_reason_on_denial":false,"hide_ai_suggestions":false,"group_asset_visibility_policy":"STRICT","is_template":false}, + started_at = '2026-07-02T00:00:00.000+00:00', + started_by_user_id = '32acc112-21ff-4669-91c2-21e27683eaa1', + stopped_at = '2026-07-10T00:00:00.000+00:00', + stopped_by_user_id = '32acc112-21ff-4669-91c2-21e27683eaa1', + ended_at = '2026-07-14T00:00:00.000+00:00', + ended_by_user_id = '32acc112-21ff-4669-91c2-21e27683eaa1' + ) + else: + return Campaign( + campaign_id = 'f454d283-ca87-4a8a-bdbb-df212eca5353', + name = 'Q3 Access Review', + status = 'ONGOING', + is_template = False, + created_at = '2026-07-01T00:00:00.000+00:00', + updated_at = '2026-07-01T00:00:00.000+00:00', + created_by_user_id = '32acc112-21ff-4669-91c2-21e27683eaa1', + ) + """ + + def testCampaign(self): + """Test Campaign""" + # inst_req_only = self.make_instance(include_optional=False) + # inst_req_and_optional = self.make_instance(include_optional=True) + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_campaign_configuration.py b/test/test_campaign_configuration.py new file mode 100644 index 0000000..ff664e5 --- /dev/null +++ b/test/test_campaign_configuration.py @@ -0,0 +1,88 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from opal_security.models.campaign_configuration import CampaignConfiguration + +class TestCampaignConfiguration(unittest.TestCase): + """CampaignConfiguration unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional) -> CampaignConfiguration: + """Test CampaignConfiguration + include_optional is a boolean, when False only required + params are included, when True both required and + optional params are included """ + # uncomment below to create an instance of `CampaignConfiguration` + """ + model = CampaignConfiguration() + if include_optional: + return CampaignConfiguration( + configuration_id = '39a4d283-ca87-4a8a-bdbb-df212eca5fdb', + created_at = '2026-07-01T00:00:00.000+00:00', + updated_at = '2026-07-01T00:00:00.000+00:00', + query = { }, + reviewer_assignment_policy = 'MANUALLY', + allow_self_review = False, + send_reviewer_assignment_notification = True, + allow_reviewer_reassignment = False, + start_date = '2026-07-02T00:00:00.000+00:00', + end_date = '2026-09-30T00:00:00.000+00:00', + timezone = 'America/Los_Angeles', + revoke_on = 'END', + reminder_schedule = [7, 3, 1], + reminder_include_manager = True, + require_reason_on_denial = False, + hide_ai_suggestions = False, + custom_start_message = 'Please complete your reviews by Friday.', + group_asset_visibility_policy = 'STRICT', + is_template = False, + cron_expression = '0 9 1 * *', + next_scheduled_run = '2026-08-01T16:00:00.000+00:00', + last_scheduled_run = '2026-07-01T16:00:00.000+00:00', + recurring_duration_days = 14 + ) + else: + return CampaignConfiguration( + configuration_id = '39a4d283-ca87-4a8a-bdbb-df212eca5fdb', + created_at = '2026-07-01T00:00:00.000+00:00', + updated_at = '2026-07-01T00:00:00.000+00:00', + reviewer_assignment_policy = 'MANUALLY', + allow_self_review = False, + send_reviewer_assignment_notification = True, + allow_reviewer_reassignment = False, + timezone = 'America/Los_Angeles', + revoke_on = 'END', + reminder_include_manager = True, + require_reason_on_denial = False, + hide_ai_suggestions = False, + group_asset_visibility_policy = 'STRICT', + is_template = False, + ) + """ + + def testCampaignConfiguration(self): + """Test CampaignConfiguration""" + # inst_req_only = self.make_instance(include_optional=False) + # inst_req_and_optional = self.make_instance(include_optional=True) + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_campaign_group_asset_visibility_policy_enum.py b/test/test_campaign_group_asset_visibility_policy_enum.py new file mode 100644 index 0000000..e7fe747 --- /dev/null +++ b/test/test_campaign_group_asset_visibility_policy_enum.py @@ -0,0 +1,34 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from opal_security.models.campaign_group_asset_visibility_policy_enum import CampaignGroupAssetVisibilityPolicyEnum + +class TestCampaignGroupAssetVisibilityPolicyEnum(unittest.TestCase): + """CampaignGroupAssetVisibilityPolicyEnum unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def testCampaignGroupAssetVisibilityPolicyEnum(self): + """Test CampaignGroupAssetVisibilityPolicyEnum""" + # inst = CampaignGroupAssetVisibilityPolicyEnum() + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_campaign_revoke_on_enum.py b/test/test_campaign_revoke_on_enum.py new file mode 100644 index 0000000..cdde5a0 --- /dev/null +++ b/test/test_campaign_revoke_on_enum.py @@ -0,0 +1,34 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from opal_security.models.campaign_revoke_on_enum import CampaignRevokeOnEnum + +class TestCampaignRevokeOnEnum(unittest.TestCase): + """CampaignRevokeOnEnum unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def testCampaignRevokeOnEnum(self): + """Test CampaignRevokeOnEnum""" + # inst = CampaignRevokeOnEnum() + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_campaign_status_enum.py b/test/test_campaign_status_enum.py new file mode 100644 index 0000000..d2b1c42 --- /dev/null +++ b/test/test_campaign_status_enum.py @@ -0,0 +1,34 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from opal_security.models.campaign_status_enum import CampaignStatusEnum + +class TestCampaignStatusEnum(unittest.TestCase): + """CampaignStatusEnum unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def testCampaignStatusEnum(self): + """Test CampaignStatusEnum""" + # inst = CampaignStatusEnum() + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_campaigns_api.py b/test/test_campaigns_api.py new file mode 100644 index 0000000..7403dba --- /dev/null +++ b/test/test_campaigns_api.py @@ -0,0 +1,45 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from opal_security.api.campaigns_api import CampaignsApi + + +class TestCampaignsApi(unittest.TestCase): + """CampaignsApi unit test stubs""" + + def setUp(self) -> None: + self.api = CampaignsApi() + + def tearDown(self) -> None: + pass + + def test_get_campaign(self) -> None: + """Test case for get_campaign + + Get campaign by ID + """ + pass + + def test_get_campaigns(self) -> None: + """Test case for get_campaigns + + """ + pass + + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_group_remote_info_tableau_group.py b/test/test_group_remote_info_tableau_group.py new file mode 100644 index 0000000..0e8a204 --- /dev/null +++ b/test/test_group_remote_info_tableau_group.py @@ -0,0 +1,53 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from opal_security.models.group_remote_info_tableau_group import GroupRemoteInfoTableauGroup + +class TestGroupRemoteInfoTableauGroup(unittest.TestCase): + """GroupRemoteInfoTableauGroup unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional) -> GroupRemoteInfoTableauGroup: + """Test GroupRemoteInfoTableauGroup + include_optional is a boolean, when False only required + params are included, when True both required and + optional params are included """ + # uncomment below to create an instance of `GroupRemoteInfoTableauGroup` + """ + model = GroupRemoteInfoTableauGroup() + if include_optional: + return GroupRemoteInfoTableauGroup( + group_id = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890' + ) + else: + return GroupRemoteInfoTableauGroup( + group_id = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', + ) + """ + + def testGroupRemoteInfoTableauGroup(self): + """Test GroupRemoteInfoTableauGroup""" + # inst_req_only = self.make_instance(include_optional=False) + # inst_req_and_optional = self.make_instance(include_optional=True) + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_paginated_campaigns_list.py b/test/test_paginated_campaigns_list.py new file mode 100644 index 0000000..8ef400e --- /dev/null +++ b/test/test_paginated_campaigns_list.py @@ -0,0 +1,59 @@ +# coding: utf-8 + +""" + Opal API + + The Opal API is a RESTful API that allows you to interact with the Opal Security platform programmatically. + + The version of the OpenAPI document: 1.0 + Contact: hello@opal.dev + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from opal_security.models.paginated_campaigns_list import PaginatedCampaignsList + +class TestPaginatedCampaignsList(unittest.TestCase): + """PaginatedCampaignsList unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional) -> PaginatedCampaignsList: + """Test PaginatedCampaignsList + include_optional is a boolean, when False only required + params are included, when True both required and + optional params are included """ + # uncomment below to create an instance of `PaginatedCampaignsList` + """ + model = PaginatedCampaignsList() + if include_optional: + return PaginatedCampaignsList( + next = 'cD0yMDIxLTAxLTA2KzAzJTNBMjQlM0E1My40MzQzMjYlMkIwMCUzQTAw', + previous = 'cj1sZXdwd2VycWVtY29zZnNkc2NzUWxNMEUxTXk0ME16UXpNallsTWtJ', + results = [ + {campaign_id=f454d283-ca87-4a8a-bdbb-df212eca5353, name=Q3 Access Review, status=DRAFT, is_template=false, created_at=2026-07-01T00:00:00.000+00:00, updated_at=2026-07-01T00:00:00.000+00:00, created_by_user_id=32acc112-21ff-4669-91c2-21e27683eaa1} + ] + ) + else: + return PaginatedCampaignsList( + results = [ + {campaign_id=f454d283-ca87-4a8a-bdbb-df212eca5353, name=Q3 Access Review, status=DRAFT, is_template=false, created_at=2026-07-01T00:00:00.000+00:00, updated_at=2026-07-01T00:00:00.000+00:00, created_by_user_id=32acc112-21ff-4669-91c2-21e27683eaa1} + ], + ) + """ + + def testPaginatedCampaignsList(self): + """Test PaginatedCampaignsList""" + # inst_req_only = self.make_instance(include_optional=False) + # inst_req_and_optional = self.make_instance(include_optional=True) + +if __name__ == '__main__': + unittest.main()