From ffa83a758794dfe55261f2fe670bdd1ab03ae5e4 Mon Sep 17 00:00:00 2001 From: Erik Schultink Date: Wed, 10 Sep 2025 11:41:55 -0700 Subject: [PATCH 1/6] support passing in custom api connectors for gcp, aws --- infra/examples-dev/aws/main.tf | 1 + infra/examples-dev/aws/variables.tf | 33 +++++++++++++++++++++++++++++ infra/examples-dev/gcp/main.tf | 1 + infra/examples-dev/gcp/variables.tf | 33 +++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/infra/examples-dev/aws/main.tf b/infra/examples-dev/aws/main.tf index b831624b7d..01f76daa69 100644 --- a/infra/examples-dev/aws/main.tf +++ b/infra/examples-dev/aws/main.tf @@ -51,6 +51,7 @@ locals { module.worklytics_connectors.enabled_api_connectors, module.worklytics_connectors_google_workspace.enabled_api_connectors, local.msft_api_connectors_with_auth, + var.custom_api_connectors, {} ) diff --git a/infra/examples-dev/aws/variables.tf b/infra/examples-dev/aws/variables.tf index 372abbdf88..9cf87cd5cb 100644 --- a/infra/examples-dev/aws/variables.tf +++ b/infra/examples-dev/aws/variables.tf @@ -237,6 +237,39 @@ variable "bulk_sanitized_expiration_days" { default = 1805 # 5 years; intent is 'forever', but some upperbound in case bucket is forgotten } +variable "custom_api_connectors" { + type = map(object({ + source_kind = string + source_auth_strategy = string + target_host = string + oauth_scopes_needed = optional(list(string), []) + environment_variables = optional(map(string), {}) + enable_async_processing = optional(bool, false) + example_api_calls = optional(list(string), []) + example_api_requests = optional(list(object({ + method = optional(string, "GET") + path = string + content_type = optional(string, "application/json") + body = optional(string, null) + })), []) + example_api_calls_user_to_impersonate = optional(string) + secured_variables = optional(list(object({ + name = string + value = optional(string) + writable = optional(bool, false) + lockable = optional(bool, false) + sensitive = optional(bool, true) + description = optional(string) + value_managed_by_tf = optional(bool, true) + })), + []) + settings_to_provide = optional(map(string), {}) + })) + + description = "map of API connectors to provision" + default = {} +} + variable "custom_api_connector_rules" { type = map(string) description = "map of connector id --> YAML file with custom rules" diff --git a/infra/examples-dev/gcp/main.tf b/infra/examples-dev/gcp/main.tf index 901e78965f..b0e3a4aa29 100644 --- a/infra/examples-dev/gcp/main.tf +++ b/infra/examples-dev/gcp/main.tf @@ -57,6 +57,7 @@ locals { module.worklytics_connectors.enabled_api_connectors, module.worklytics_connectors_google_workspace.enabled_api_connectors, local.msft_api_connectors_with_auth, + var.custom_api_connectors, {} ) diff --git a/infra/examples-dev/gcp/variables.tf b/infra/examples-dev/gcp/variables.tf index 3e39ca5ed2..9558621af7 100644 --- a/infra/examples-dev/gcp/variables.tf +++ b/infra/examples-dev/gcp/variables.tf @@ -246,6 +246,39 @@ variable "bulk_sanitized_expiration_days" { default = 1805 # 5 years; intent is 'forever', but some upperbound in case bucket is forgotten } +variable "custom_api_connectors" { + type = map(object({ + source_kind = string + source_auth_strategy = string + target_host = string + oauth_scopes_needed = optional(list(string), []) + environment_variables = optional(map(string), {}) + enable_async_processing = optional(bool, false) + example_api_calls = optional(list(string), []) + example_api_requests = optional(list(object({ + method = optional(string, "GET") + path = string + content_type = optional(string, "application/json") + body = optional(string, null) + })), []) + example_api_calls_user_to_impersonate = optional(string) + secured_variables = optional(list(object({ + name = string + value = optional(string) + writable = optional(bool, false) + lockable = optional(bool, false) + sensitive = optional(bool, true) + value_managed_by_tf = optional(bool, true) + description = optional(string) + })), + []) + settings_to_provide = optional(map(string), {}) + })) + + description = "map of custom API connectors to provision" + default = {} +} + variable "custom_api_connector_rules" { type = map(string) description = "map of connector id --> YAML file with custom rules" From 618eb680eea5f6044309d98bff12d1d5477044fc Mon Sep 17 00:00:00 2001 From: Erik Schultink Date: Wed, 10 Sep 2025 11:50:29 -0700 Subject: [PATCH 2/6] rules_file passed in as part of api_connector_spec --- infra/modules/aws-host/main.tf | 6 ++++-- infra/modules/aws-host/variables.tf | 1 + infra/modules/gcp-host/main.tf | 6 ++++-- infra/modules/gcp-host/variables.tf | 1 + 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/infra/modules/aws-host/main.tf b/infra/modules/aws-host/main.tf index b6a2a53f6f..26c4ff48ce 100644 --- a/infra/modules/aws-host/main.tf +++ b/infra/modules/aws-host/main.tf @@ -28,6 +28,8 @@ locals { has_enabled_webhook_collectors = length(keys(var.webhook_collectors)) > 0 enable_webhook_testing = var.provision_testing_infra && local.has_enabled_webhook_collectors + + api_connector_rules_files = merge(var.custom_api_connector_rules, { for k, v in var.api_connectors : k => v if v.rules_file != null }) } module "psoxy" { @@ -218,7 +220,7 @@ module "api_connector" { { PSEUDONYMIZE_APP_IDS = tostring(var.pseudonymize_app_ids) EMAIL_CANONICALIZATION = var.email_canonicalization - CUSTOM_RULES_SHA = try(var.custom_api_connector_rules[each.key], null) != null ? filesha1(var.custom_api_connector_rules[each.key]) : null + CUSTOM_RULES_SHA = try(local.api_connector_rules_files[each.key], null) != null ? filesha1(local.api_connector_rules_files[each.key]) : null IS_DEVELOPMENT_MODE = contains(var.non_production_connectors, each.key) } ) @@ -229,7 +231,7 @@ module "api_connector" { module "custom_api_connector_rules" { source = "../../modules/aws-ssm-rules" - for_each = var.custom_api_connector_rules + for_each = local.api_connector_rules_files prefix = "${local.instance_ssm_prefix}${replace(upper(each.key), "-", "_")}_" file_path = each.value diff --git a/infra/modules/aws-host/variables.tf b/infra/modules/aws-host/variables.tf index 66003e45e2..e2762a671e 100644 --- a/infra/modules/aws-host/variables.tf +++ b/infra/modules/aws-host/variables.tf @@ -197,6 +197,7 @@ variable "api_connectors" { })), []) settings_to_provide = optional(map(string), {}) + rules_file = optional(string, null) })) description = "map of API connectors to provision" diff --git a/infra/modules/gcp-host/main.tf b/infra/modules/gcp-host/main.tf index 556586bc9d..46371265af 100644 --- a/infra/modules/gcp-host/main.tf +++ b/infra/modules/gcp-host/main.tf @@ -13,6 +13,8 @@ locals { config_parameter_prefix = var.config_parameter_prefix == "" ? local.default_config_parameter_prefix : var.config_parameter_prefix environment_id_prefix = "${var.environment_name}${length(var.environment_name) > 0 ? "-" : ""}" environment_id_display_name_qualifier = length(var.environment_name) > 0 ? " ${var.environment_name} " : "" + + api_connector_rules_files = merge(var.custom_api_connector_rules, { for k, v in var.api_connectors : k => v if v.rules_file != null }) } module "psoxy" { @@ -196,7 +198,7 @@ module "api_connector" { BUNDLE_FILENAME = module.psoxy.filename IS_DEVELOPMENT_MODE = contains(var.non_production_connectors, each.key) PSEUDONYMIZE_APP_IDS = tostring(var.pseudonymize_app_ids) - CUSTOM_RULES_SHA = try(var.custom_api_connector_rules[each.key], null) != null ? filesha1(var.custom_api_connector_rules[each.key]) : null + CUSTOM_RULES_SHA = try(local.api_connector_rules_files[each.key], null) != null ? filesha1(local.api_connector_rules_files[each.key]) : null EMAIL_CANONICALIZATION = var.email_canonicalization } ) @@ -209,7 +211,7 @@ module "api_connector" { } module "custom_api_connector_rules" { - for_each = var.custom_api_connector_rules + for_each = local.api_connector_rules_files source = "../../modules/gcp-sm-rules" diff --git a/infra/modules/gcp-host/variables.tf b/infra/modules/gcp-host/variables.tf index 17ba536775..d903540c94 100644 --- a/infra/modules/gcp-host/variables.tf +++ b/infra/modules/gcp-host/variables.tf @@ -199,6 +199,7 @@ variable "api_connectors" { })), []) settings_to_provide = optional(map(string), {}) + rules_file = optional(string, null) })) description = "map of API connectors to provision" From 94130ae17a9bb480f47f4795a8014244610990ac Mon Sep 17 00:00:00 2001 From: Erik Schultink Date: Wed, 10 Sep 2025 15:04:07 -0700 Subject: [PATCH 3/6] rules_file param in more places --- infra/examples-dev/aws/variables.tf | 1 + infra/examples-dev/gcp/variables.tf | 1 + infra/modules/aws-host/variables.tf | 2 +- infra/modules/gcp-host/variables.tf | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/infra/examples-dev/aws/variables.tf b/infra/examples-dev/aws/variables.tf index 9cf87cd5cb..cda9926d23 100644 --- a/infra/examples-dev/aws/variables.tf +++ b/infra/examples-dev/aws/variables.tf @@ -264,6 +264,7 @@ variable "custom_api_connectors" { })), []) settings_to_provide = optional(map(string), {}) + rules_file = optional(string, null) })) description = "map of API connectors to provision" diff --git a/infra/examples-dev/gcp/variables.tf b/infra/examples-dev/gcp/variables.tf index 9558621af7..9eabb21a5e 100644 --- a/infra/examples-dev/gcp/variables.tf +++ b/infra/examples-dev/gcp/variables.tf @@ -273,6 +273,7 @@ variable "custom_api_connectors" { })), []) settings_to_provide = optional(map(string), {}) + rules_file = optional(string, null) })) description = "map of custom API connectors to provision" diff --git a/infra/modules/aws-host/variables.tf b/infra/modules/aws-host/variables.tf index e2762a671e..0a261dcf55 100644 --- a/infra/modules/aws-host/variables.tf +++ b/infra/modules/aws-host/variables.tf @@ -197,7 +197,7 @@ variable "api_connectors" { })), []) settings_to_provide = optional(map(string), {}) - rules_file = optional(string, null) + rules_file = optional(string, null) })) description = "map of API connectors to provision" diff --git a/infra/modules/gcp-host/variables.tf b/infra/modules/gcp-host/variables.tf index d903540c94..6771926610 100644 --- a/infra/modules/gcp-host/variables.tf +++ b/infra/modules/gcp-host/variables.tf @@ -199,7 +199,7 @@ variable "api_connectors" { })), []) settings_to_provide = optional(map(string), {}) - rules_file = optional(string, null) + rules_file = optional(string, null) })) description = "map of API connectors to provision" From 595c8b462b01bae47a95960fa9d98c384b45d5f3 Mon Sep 17 00:00:00 2001 From: Erik Schultink Date: Wed, 10 Sep 2025 12:05:54 -0700 Subject: [PATCH 4/6] support enabling template --- .../worklytics-connector-specs/main.tf | 21 +++++++++++++++---- .../worklytics-connector-specs/variables.tf | 8 +++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/infra/modules/worklytics-connector-specs/main.tf b/infra/modules/worklytics-connector-specs/main.tf index 6ff6796a95..efcad00909 100644 --- a/infra/modules/worklytics-connector-specs/main.tf +++ b/infra/modules/worklytics-connector-specs/main.tf @@ -15,6 +15,13 @@ resource "time_static" "deployment" { } locals { + + # create map of connector id --> { template_id: ... } + enabled_connectors_from_templates = merge( + { for v in var.enabled_connectors_from_templates : v => { template_id = v } }, + var.enabled_connectors_from_templates + ) + standard_config_values = { oauth_refresh_token_lock = { # NOTE: in GCP case, this is NEVER actually filled with a value; lock is done by labeling the secret @@ -1343,12 +1350,17 @@ locals { k => merge(v, { example_calls : try(v.example_api_calls, []) }) } enabled_google_workspace_connectors = { - for k, v in local.google_workspace_sources_backwards : k => v if contains(var.enabled_connectors, k) + for alias, v in local.enabled_connectors_from_templates : + alias => local.google_workspace_sources_backwards[v.template_id] if contains(keys(local.google_workspace_sources_backwards), v.template_id) } enabled_msft_365_connectors = { - for k, v in local.msft_365_connectors_backwards : k => v if contains(var.enabled_connectors, k) && length(try(var.msft_tenant_id, "")) > 0 + for alias, v in local.enabled_connectors_from_templates : + alias => local.msft_365_connectors_backwards[v.template_id] if contains(keys(local.msft_365_connectors_backwards), v.template_id) && length(try(var.msft_tenant_id, "")) > 0 + } + enabled_oauth_long_access_connectors = { + for alias, v in local.enabled_connectors_from_templates : + alias => local.oauth_long_access_connectors_backwards[v.template_id] if contains(keys(local.oauth_long_access_connectors_backwards), v.template_id) } - enabled_oauth_long_access_connectors = { for k, v in local.oauth_long_access_connectors_backwards : k => v if contains(var.enabled_connectors, k) } enabled_oauth_long_access_connectors_todos = { for k, v in local.enabled_oauth_long_access_connectors : k => v if v.external_token_todo != null } # list of pair of [(conn1, secret1), (conn1, secret2), ... (connN, secretM)] @@ -1365,7 +1377,8 @@ locals { ])) enabled_bulk_connectors = { - for k, v in local.bulk_connectors : k => v if contains(var.enabled_connectors, k) + for alias, v in local.enabled_connectors_from_templates : + alias => local.bulk_connectors[v.template_id] if contains(keys(local.bulk_connectors), v.template_id) } enabled_lockable_oauth_secrets_to_create = distinct(flatten([ diff --git a/infra/modules/worklytics-connector-specs/variables.tf b/infra/modules/worklytics-connector-specs/variables.tf index fd59ec36d5..cd3d0827c7 100644 --- a/infra/modules/worklytics-connector-specs/variables.tf +++ b/infra/modules/worklytics-connector-specs/variables.tf @@ -3,6 +3,14 @@ variable "enabled_connectors" { description = "ids of connectors to enable" } +variable "enabled_connectors_from_templates" { + type = map(object({ + template_id = string + })) + description = "map of connector id --> id of connector template to enable" + default = {} +} + variable "chat_gpt_enterprise_example_workspace_id" { type = string description = "Workspace id to use for example calls" From a04279194a00d51bdf24dd53f9ccda093cb9788c Mon Sep 17 00:00:00 2001 From: Erik Schultink Date: Wed, 10 Sep 2025 12:13:30 -0700 Subject: [PATCH 5/6] piping to enable connectors via templates --- infra/examples-dev/aws/google-workspace.tf | 15 ++++++++------- infra/examples-dev/aws/main.tf | 1 + infra/examples-dev/aws/msft-365.tf | 1 + infra/examples-dev/aws/variables.tf | 8 ++++++++ infra/examples-dev/gcp/google-workspace.tf | 15 ++++++++------- infra/examples-dev/gcp/msft-365.tf | 1 + infra/examples-dev/gcp/variables.tf | 9 +++++++++ .../main.tf | 7 ++++--- .../variables.tf | 8 ++++++++ .../worklytics-connectors-msft-365/main.tf | 1 + .../worklytics-connectors-msft-365/variables.tf | 8 ++++++++ infra/modules/worklytics-connectors/main.tf | 1 + infra/modules/worklytics-connectors/variables.tf | 8 ++++++++ 13 files changed, 66 insertions(+), 17 deletions(-) diff --git a/infra/examples-dev/aws/google-workspace.tf b/infra/examples-dev/aws/google-workspace.tf index e53bf0016f..28d4368b3d 100644 --- a/infra/examples-dev/aws/google-workspace.tf +++ b/infra/examples-dev/aws/google-workspace.tf @@ -14,13 +14,14 @@ module "worklytics_connectors_google_workspace" { google = google.google_workspace } - environment_id = var.environment_name - enabled_connectors = var.enabled_connectors - gcp_project_id = var.google_workspace_gcp_project_id - google_workspace_example_user = var.google_workspace_example_user - google_workspace_example_admin = var.google_workspace_example_admin - provision_gcp_sa_keys = var.google_workspace_provision_keys - todos_as_local_files = var.todos_as_local_files + environment_id = var.environment_name + enabled_connectors = var.enabled_connectors + enabled_connectors_from_templates = var.enabled_connectors_from_templates + gcp_project_id = var.google_workspace_gcp_project_id + google_workspace_example_user = var.google_workspace_example_user + google_workspace_example_admin = var.google_workspace_example_admin + provision_gcp_sa_keys = var.google_workspace_provision_keys + todos_as_local_files = var.todos_as_local_files } output "google_workspace_api_clients" { diff --git a/infra/examples-dev/aws/main.tf b/infra/examples-dev/aws/main.tf index 01f76daa69..9d58103bbf 100644 --- a/infra/examples-dev/aws/main.tf +++ b/infra/examples-dev/aws/main.tf @@ -24,6 +24,7 @@ module "worklytics_connectors" { # source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors?ref=rc-v0.5.9" enabled_connectors = var.enabled_connectors + enabled_connectors_from_templates = var.enabled_connectors_from_templates chat_gpt_enterprise_example_workspace_id = var.chat_gpt_enterprise_example_workspace_id confluence_example_cloud_id = var.confluence_example_cloud_id confluence_example_group_id = var.confluence_example_group_id diff --git a/infra/examples-dev/aws/msft-365.tf b/infra/examples-dev/aws/msft-365.tf index 90081cf9dc..2754a5cfef 100644 --- a/infra/examples-dev/aws/msft-365.tf +++ b/infra/examples-dev/aws/msft-365.tf @@ -5,6 +5,7 @@ module "worklytics_connectors_msft_365" { # source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors-msft-365?ref=rc-v0.5.9" enabled_connectors = var.enabled_connectors + enabled_connectors_from_templates = var.enabled_connectors_from_templates environment_id = var.environment_name msft_tenant_id = var.msft_tenant_id example_msft_user_guid = var.example_msft_user_guid diff --git a/infra/examples-dev/aws/variables.tf b/infra/examples-dev/aws/variables.tf index cda9926d23..a521eec780 100644 --- a/infra/examples-dev/aws/variables.tf +++ b/infra/examples-dev/aws/variables.tf @@ -219,6 +219,14 @@ variable "enabled_connectors" { description = "list of ids of connectors to enabled; see modules/worklytics-connector-specs" } +variable "enabled_connectors_from_templates" { + type = map(object({ + template_id = string + })) + description = "map of connector id --> id of connector template to enable" + default = {} +} + variable "non_production_connectors" { type = list(string) description = "connector ids in this list will be in development mode (not for production use)" diff --git a/infra/examples-dev/gcp/google-workspace.tf b/infra/examples-dev/gcp/google-workspace.tf index e53bf0016f..28d4368b3d 100644 --- a/infra/examples-dev/gcp/google-workspace.tf +++ b/infra/examples-dev/gcp/google-workspace.tf @@ -14,13 +14,14 @@ module "worklytics_connectors_google_workspace" { google = google.google_workspace } - environment_id = var.environment_name - enabled_connectors = var.enabled_connectors - gcp_project_id = var.google_workspace_gcp_project_id - google_workspace_example_user = var.google_workspace_example_user - google_workspace_example_admin = var.google_workspace_example_admin - provision_gcp_sa_keys = var.google_workspace_provision_keys - todos_as_local_files = var.todos_as_local_files + environment_id = var.environment_name + enabled_connectors = var.enabled_connectors + enabled_connectors_from_templates = var.enabled_connectors_from_templates + gcp_project_id = var.google_workspace_gcp_project_id + google_workspace_example_user = var.google_workspace_example_user + google_workspace_example_admin = var.google_workspace_example_admin + provision_gcp_sa_keys = var.google_workspace_provision_keys + todos_as_local_files = var.todos_as_local_files } output "google_workspace_api_clients" { diff --git a/infra/examples-dev/gcp/msft-365.tf b/infra/examples-dev/gcp/msft-365.tf index 36e0982ab4..73902e1c8e 100644 --- a/infra/examples-dev/gcp/msft-365.tf +++ b/infra/examples-dev/gcp/msft-365.tf @@ -5,6 +5,7 @@ module "worklytics_connectors_msft_365" { # source = "git::https://github.com/worklytics/psoxy//infra/modules/worklytics-connectors-msft-365?ref=rc-v0.5.9" enabled_connectors = var.enabled_connectors + enabled_connectors_from_templates = var.enabled_connectors_from_templates environment_id = var.environment_name msft_tenant_id = var.msft_tenant_id example_msft_user_guid = var.example_msft_user_guid diff --git a/infra/examples-dev/gcp/variables.tf b/infra/examples-dev/gcp/variables.tf index 9eabb21a5e..896f096e94 100644 --- a/infra/examples-dev/gcp/variables.tf +++ b/infra/examples-dev/gcp/variables.tf @@ -228,6 +228,15 @@ variable "enabled_connectors" { description = "list of ids of connectors to enabled; see modules/worklytics-connector-specs" } +variable "enabled_connectors_from_templates" { + type = map(object({ + template_id = string + })) + description = "map of connector id --> id of connector template to enable" + default = {} +} + + variable "non_production_connectors" { type = list(string) description = "connector ids in this list will be in development mode (not for production use" diff --git a/infra/modules/worklytics-connectors-google-workspace/main.tf b/infra/modules/worklytics-connectors-google-workspace/main.tf index c8768ff3b5..bc137f9c08 100644 --- a/infra/modules/worklytics-connectors-google-workspace/main.tf +++ b/infra/modules/worklytics-connectors-google-workspace/main.tf @@ -19,9 +19,10 @@ locals { module "worklytics_connector_specs" { source = "../../modules/worklytics-connector-specs" - enabled_connectors = var.enabled_connectors - google_workspace_example_admin = var.google_workspace_example_admin - google_workspace_example_user = var.google_workspace_example_user + enabled_connectors = var.enabled_connectors + enabled_connectors_from_templates = var.enabled_connectors_from_templates + google_workspace_example_admin = var.google_workspace_example_admin + google_workspace_example_user = var.google_workspace_example_user } module "google_workspace_connection" { diff --git a/infra/modules/worklytics-connectors-google-workspace/variables.tf b/infra/modules/worklytics-connectors-google-workspace/variables.tf index de563f52b4..03378e7685 100644 --- a/infra/modules/worklytics-connectors-google-workspace/variables.tf +++ b/infra/modules/worklytics-connectors-google-workspace/variables.tf @@ -14,6 +14,14 @@ variable "enabled_connectors" { description = "ids of connectors to enable" } +variable "enabled_connectors_from_templates" { + type = map(object({ + template_id = string + })) + description = "map of connector id --> id of connector template to enable" + default = {} +} + variable "gcp_project_id" { type = string description = "id of GCP project that will host OAuth Clients for Google Workspace API connectors" diff --git a/infra/modules/worklytics-connectors-msft-365/main.tf b/infra/modules/worklytics-connectors-msft-365/main.tf index 918e56feb6..80d0feb521 100644 --- a/infra/modules/worklytics-connectors-msft-365/main.tf +++ b/infra/modules/worklytics-connectors-msft-365/main.tf @@ -17,6 +17,7 @@ module "worklytics_connector_specs" { source = "../../modules/worklytics-connector-specs" enabled_connectors = var.enabled_connectors + enabled_connectors_from_templates = var.enabled_connectors_from_templates msft_tenant_id = var.msft_tenant_id example_msft_user_guid = var.example_msft_user_guid msft_teams_example_team_guid = var.msft_teams_example_team_guid diff --git a/infra/modules/worklytics-connectors-msft-365/variables.tf b/infra/modules/worklytics-connectors-msft-365/variables.tf index 4275aad042..9195270872 100644 --- a/infra/modules/worklytics-connectors-msft-365/variables.tf +++ b/infra/modules/worklytics-connectors-msft-365/variables.tf @@ -3,6 +3,14 @@ variable "enabled_connectors" { description = "ids of connectors to enable" } +variable "enabled_connectors_from_templates" { + type = map(object({ + template_id = string + })) + description = "map of connector id --> id of connector template to enable" + default = {} +} + variable "environment_id" { type = string description = "Qualifier to append to names/ids of resources. If not empty, A-Za-z0-9 or - characters only. Max length 10. Useful to distinguish between deployments into same GCP project." diff --git a/infra/modules/worklytics-connectors/main.tf b/infra/modules/worklytics-connectors/main.tf index a93fb7c5db..95a0fad8c0 100644 --- a/infra/modules/worklytics-connectors/main.tf +++ b/infra/modules/worklytics-connectors/main.tf @@ -6,6 +6,7 @@ module "worklytics_connector_specs" { source = "../../modules/worklytics-connector-specs" enabled_connectors = var.enabled_connectors + enabled_connectors_from_templates = var.enabled_connectors_from_templates chat_gpt_enterprise_example_workspace_id = var.chat_gpt_enterprise_example_workspace_id confluence_example_cloud_id = var.confluence_example_cloud_id confluence_example_group_id = var.confluence_example_group_id diff --git a/infra/modules/worklytics-connectors/variables.tf b/infra/modules/worklytics-connectors/variables.tf index abd88bdae6..9102e3835f 100644 --- a/infra/modules/worklytics-connectors/variables.tf +++ b/infra/modules/worklytics-connectors/variables.tf @@ -3,6 +3,14 @@ variable "enabled_connectors" { description = "ids of connectors to enable" } +variable "enabled_connectors_from_templates" { + type = map(object({ + template_id = string + })) + description = "map of connector id --> id of connector template to enable" + default = {} +} + variable "chat_gpt_enterprise_example_workspace_id" { type = string description = "Workspace id to use for example calls" From 9e677db52879e52e5623f5fd2aaba62b3aab3659 Mon Sep 17 00:00:00 2001 From: Erik Schultink Date: Wed, 10 Sep 2025 12:20:19 -0700 Subject: [PATCH 6/6] add test, fix bug --- .../enable_connectors.tftest.hcl | 296 ++++++++++++++++++ .../worklytics-connector-specs/main.tf | 2 +- 2 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 infra/modules/worklytics-connector-specs/enable_connectors.tftest.hcl diff --git a/infra/modules/worklytics-connector-specs/enable_connectors.tftest.hcl b/infra/modules/worklytics-connector-specs/enable_connectors.tftest.hcl new file mode 100644 index 0000000000..f184988483 --- /dev/null +++ b/infra/modules/worklytics-connector-specs/enable_connectors.tftest.hcl @@ -0,0 +1,296 @@ +# Test file for validating enabled_connectors and enabled_connectors_from_templates functionality +# Tests the worklytics-connector-specs module to ensure both approaches work correctly + +# Test 1: Standard enabled_connectors approach +run "standard_enabled_connectors" { + variables { + enabled_connectors = ["gcal", "outlook-cal", "zoom"] + enabled_connectors_from_templates = {} + include_google_workspace = true + include_msft = true + msft_tenant_id = "test-tenant-id" + } + + assert { + error_message = "Should have 3 enabled Google Workspace connectors (gcal)" + condition = length(output.enabled_google_workspace_connectors) == 1 + } + + assert { + error_message = "Should have 1 enabled Microsoft 365 connector (outlook-cal)" + condition = length(output.enabled_msft_365_connectors) == 1 + } + + assert { + error_message = "Should have 1 enabled OAuth connector (zoom)" + condition = length(output.enabled_oauth_long_access_connectors) == 1 + } + + assert { + error_message = "gcal connector should be enabled with correct ID" + condition = contains(keys(output.enabled_google_workspace_connectors), "gcal") + } + + assert { + error_message = "outlook-cal connector should be enabled with correct ID" + condition = contains(keys(output.enabled_msft_365_connectors), "outlook-cal") + } + + assert { + error_message = "zoom connector should be enabled with correct ID" + condition = contains(keys(output.enabled_oauth_long_access_connectors), "zoom") + } + + assert { + error_message = "gcal connector should have correct worklytics_connector_id" + condition = output.enabled_google_workspace_connectors["gcal"].worklytics_connector_id == "gcal-psoxy" + } + + assert { + error_message = "outlook-cal connector should have correct worklytics_connector_id" + condition = output.enabled_msft_365_connectors["outlook-cal"].worklytics_connector_id == "outlook-cal-psoxy" + } + + assert { + error_message = "zoom connector should have correct worklytics_connector_id" + condition = output.enabled_oauth_long_access_connectors["zoom"].worklytics_connector_id == "zoom-psoxy" + } +} + +# Test 2: enabled_connectors_from_templates approach with custom IDs +run "template_enabled_connectors" { + variables { + enabled_connectors = [] + enabled_connectors_from_templates = { + "zoom2" = { + template_id = "zoom" + } + "gcal2" = { + template_id = "gcal" + } + "outlook-cal2" = { + template_id = "outlook-cal" + } + } + include_google_workspace = true + include_msft = true + msft_tenant_id = "test-tenant-id" + } + + assert { + error_message = "Should have 1 enabled Google Workspace connector (gcal2)" + condition = length(output.enabled_google_workspace_connectors) == 1 + } + + assert { + error_message = "Should have 1 enabled Microsoft 365 connector (outlook-cal2)" + condition = length(output.enabled_msft_365_connectors) == 1 + } + + assert { + error_message = "Should have 1 enabled OAuth connector (zoom2)" + condition = length(output.enabled_oauth_long_access_connectors) == 1 + } + + assert { + error_message = "gcal2 connector should be enabled with custom ID" + condition = contains(keys(output.enabled_google_workspace_connectors), "gcal2") + } + + assert { + error_message = "outlook-cal2 connector should be enabled with custom ID" + condition = contains(keys(output.enabled_msft_365_connectors), "outlook-cal2") + } + + assert { + error_message = "zoom2 connector should be enabled with custom ID" + condition = contains(keys(output.enabled_oauth_long_access_connectors), "zoom2") + } + + assert { + error_message = "gcal2 connector should have correct worklytics_connector_id from template" + condition = output.enabled_google_workspace_connectors["gcal2"].worklytics_connector_id == "gcal-psoxy" + } + + assert { + error_message = "outlook-cal2 connector should have correct worklytics_connector_id from template" + condition = output.enabled_msft_365_connectors["outlook-cal2"].worklytics_connector_id == "outlook-cal-psoxy" + } + + assert { + error_message = "zoom2 connector should have correct worklytics_connector_id from template" + condition = output.enabled_oauth_long_access_connectors["zoom2"].worklytics_connector_id == "zoom-psoxy" + } + + assert { + error_message = "gcal2 connector should have correct source_kind from template" + condition = output.enabled_google_workspace_connectors["gcal2"].source_kind == "gcal" + } + + assert { + error_message = "outlook-cal2 connector should have correct source_kind from template" + condition = output.enabled_msft_365_connectors["outlook-cal2"].source_kind == "outlook-cal" + } + + assert { + error_message = "zoom2 connector should have correct source_kind from template" + condition = output.enabled_oauth_long_access_connectors["zoom2"].source_kind == "zoom" + } +} + +# Test 3: Combined approach - both enabled_connectors and enabled_connectors_from_templates +run "combined_enabled_connectors" { + variables { + enabled_connectors = ["zoom"] + enabled_connectors_from_templates = { + "zoom2" = { + template_id = "zoom" + } + "gcal" = { + template_id = "gcal" + } + } + include_google_workspace = true + include_msft = true + msft_tenant_id = "test-tenant-id" + } + + assert { + error_message = "Should have 1 enabled Google Workspace connector (gcal from template)" + condition = length(output.enabled_google_workspace_connectors) == 1 + } + + assert { + error_message = "Should have 2 enabled OAuth connectors (zoom from standard + zoom2 from template)" + condition = length(output.enabled_oauth_long_access_connectors) == 2 + } + + assert { + error_message = "gcal connector should be enabled from template" + condition = contains(keys(output.enabled_google_workspace_connectors), "gcal") + } + + assert { + error_message = "zoom connector should be enabled from standard approach" + condition = contains(keys(output.enabled_oauth_long_access_connectors), "zoom") + } + + assert { + error_message = "zoom2 connector should be enabled from template" + condition = contains(keys(output.enabled_oauth_long_access_connectors), "zoom2") + } + + assert { + error_message = "Both zoom connectors should have same worklytics_connector_id" + condition = output.enabled_oauth_long_access_connectors["zoom"].worklytics_connector_id == output.enabled_oauth_long_access_connectors["zoom2"].worklytics_connector_id + } + + assert { + error_message = "Both zoom connectors should have same source_kind" + condition = output.enabled_oauth_long_access_connectors["zoom"].source_kind == output.enabled_oauth_long_access_connectors["zoom2"].source_kind + } +} + +# Test 4: Empty configurations +run "empty_enabled_connectors" { + variables { + enabled_connectors = [] + enabled_connectors_from_templates = {} + include_google_workspace = true + include_msft = true + msft_tenant_id = "test-tenant-id" + } + + assert { + error_message = "Should have no enabled Google Workspace connectors" + condition = length(output.enabled_google_workspace_connectors) == 0 + } + + assert { + error_message = "Should have no enabled Microsoft 365 connectors" + condition = length(output.enabled_msft_365_connectors) == 0 + } + + assert { + error_message = "Should have no enabled OAuth connectors" + condition = length(output.enabled_oauth_long_access_connectors) == 0 + } +} + +# Test 5: Invalid template IDs should be ignored +run "invalid_template_ids" { + variables { + enabled_connectors = [] + enabled_connectors_from_templates = { + "valid_zoom" = { + template_id = "zoom" + } + "invalid_connector" = { + template_id = "non-existent-connector" + } + } + include_google_workspace = true + include_msft = true + msft_tenant_id = "test-tenant-id" + } + + assert { + error_message = "Should have 1 enabled OAuth connector (only valid_zoom)" + condition = length(output.enabled_oauth_long_access_connectors) == 1 + } + + assert { + error_message = "valid_zoom connector should be enabled" + condition = contains(keys(output.enabled_oauth_long_access_connectors), "valid_zoom") + } + + assert { + error_message = "invalid_connector should not be enabled" + condition = !contains(keys(output.enabled_oauth_long_access_connectors), "invalid_connector") + } +} + +# Test 6: Validate connector configurations are properly inherited +run "connector_configuration_inheritance" { + variables { + enabled_connectors = [] + enabled_connectors_from_templates = { + "zoom_custom" = { + template_id = "zoom" + } + } + include_google_workspace = true + include_msft = true + msft_tenant_id = "test-tenant-id" + } + + assert { + error_message = "zoom_custom connector should have correct target_host" + condition = output.enabled_oauth_long_access_connectors["zoom_custom"].target_host == "api.zoom.us" + } + + assert { + error_message = "zoom_custom connector should have correct source_auth_strategy" + condition = output.enabled_oauth_long_access_connectors["zoom_custom"].source_auth_strategy == "oauth2_refresh_token" + } + + assert { + error_message = "zoom_custom connector should have correct availability" + condition = output.enabled_oauth_long_access_connectors["zoom_custom"].availability == "ga" + } + + assert { + error_message = "zoom_custom connector should have correct display_name" + condition = output.enabled_oauth_long_access_connectors["zoom_custom"].display_name == "Zoom" + } + + assert { + error_message = "zoom_custom connector should have environment variables" + condition = length(output.enabled_oauth_long_access_connectors["zoom_custom"].environment_variables) > 0 + } + + assert { + error_message = "zoom_custom connector should have secured variables" + condition = length(output.enabled_oauth_long_access_connectors["zoom_custom"].secured_variables) > 0 + } +} diff --git a/infra/modules/worklytics-connector-specs/main.tf b/infra/modules/worklytics-connector-specs/main.tf index efcad00909..d636ac5f9a 100644 --- a/infra/modules/worklytics-connector-specs/main.tf +++ b/infra/modules/worklytics-connector-specs/main.tf @@ -18,7 +18,7 @@ locals { # create map of connector id --> { template_id: ... } enabled_connectors_from_templates = merge( - { for v in var.enabled_connectors_from_templates : v => { template_id = v } }, + { for v in var.enabled_connectors : v => { template_id = v } }, var.enabled_connectors_from_templates )