local_clear_auth_env <- function() { withr::local_envvar(c( DATABRICKS_AUTH_TYPE = NA_character_, DATABRICKS_CONFIG_FILE = NA_character_, DATABRICKS_CONFIG_PROFILE = NA_character_, ARM_CLIENT_ID = NA_character_, ARM_CLIENT_SECRET = NA_character_, ARM_TENANT_ID = NA_character_ ), .local_envir = parent.frame()) withr::local_options( use_databrickscfg = FALSE, db_profile = NULL, brickster_oauth_client = NULL, .local_envir = parent.frame() ) } test_that("auth functions - baseline behaviour", { local_clear_auth_env() host <- "http://some_url" token <- "dapi123" wsid <- "123" # set values temporarily withr::local_envvar( DATABRICKS_WSID = wsid, DATABRICKS_HOST = host, DATABRICKS_TOKEN = token ) # read env var function should behave expect_identical(read_env_var("host"), host) expect_identical(read_env_var("token"), token) expect_identical(read_env_var("wsid"), wsid) expect_error(read_env_var("nope")) # higher level funcs should return as expected expect_identical(db_host(), "some_url") expect_identical(db_token(), token) expect_identical(db_wsid(), wsid) # when not specified should error withr::with_envvar( new = c(DATABRICKS_HOST = ""), expect_error(db_host()) ) expect_identical( db_host(id = "mock", prefix = "dev-"), "dev-mock.cloud.databricks.com" ) expect_identical( db_host(id = "mock"), "mock.cloud.databricks.com" ) # oauth functions require host to be specified and valid expect_error(db_oauth_client( host = NULL, client_id = NULL, client_secret = NULL )) expect_identical( db_oauth_client(host = "", client_id = NULL, client_secret = NULL)$auth_url, "https:///oidc/v1/authorize" ) expect_identical( db_oauth_client(host = "", client_id = NULL, client_secret = NULL)$is_m2m, FALSE ) expect_identical( db_oauth_client( host = "", client_id = NULL, client_secret = NULL )$client$token_url, "https:///oidc/v1/token" ) expect_s3_class( db_oauth_client(host = "", client_id = NULL, client_secret = NULL)$client, "httr2_oauth_client" ) }) test_that("auth functions - switching profile", { local_clear_auth_env() host <- "http://some_url" token <- "dapi123" wsid <- "123" host_prod <- "http://some_url_two" token_prod <- "dapi321" wsid_prod <- "321" # set values temporarily withr::local_envvar( DATABRICKS_WSID = wsid, DATABRICKS_HOST = host, DATABRICKS_TOKEN = token, DATABRICKS_HOST_PROD = host_prod, DATABRICKS_TOKEN_PROD = token_prod, DATABRICKS_WSID_PROD = wsid_prod ) # read env var function should behave expect_identical(read_env_var("host", NULL), host) expect_identical(read_env_var("token", NULL), token) expect_identical(read_env_var("wsid", NULL), wsid) expect_identical(read_env_var("host", "prod"), host_prod) expect_identical(read_env_var("token", "prod"), token_prod) expect_identical(read_env_var("wsid", "prod"), wsid_prod) # higher level funcs should return as expected expect_identical(db_host(profile = NULL), "some_url") expect_identical(db_token(profile = NULL), token) expect_identical(db_wsid(profile = NULL), wsid) expect_identical(db_host(profile = "prod"), "some_url_two") expect_identical(db_token(profile = "prod"), token_prod) expect_identical(db_wsid(profile = "prod"), wsid_prod) # switching profiles via option checks # default expect_identical(db_host(), "some_url") expect_identical(db_token(), token) expect_identical(db_wsid(), wsid) # prod test withr::local_options(list(db_profile = "prod")) expect_identical(db_host(), "some_url_two") expect_identical(db_token(), token_prod) expect_identical(db_wsid(), wsid_prod) # back to default withr::local_options(list(db_profile = NULL)) expect_identical(db_host(), "some_url") expect_identical(db_token(), token) expect_identical(db_wsid(), wsid) }) test_that("auth functions - reading .databrickscfg", { local_clear_auth_env() withr::local_options(use_databrickscfg = TRUE) withr::local_envvar(DATABRICKS_CONFIG_FILE = "databricks.cfg") withr::local_file("databricks.cfg", { writeLines( c( '[DEFAULT]', 'host = http://some-host', 'token = some-token', 'wsid = 123456' ), "databricks.cfg" ) }) # using read_databrickscfg directly token <- expect_no_condition(read_databrickscfg("token", profile = NULL)) host <- expect_no_condition(read_databrickscfg("host", profile = NULL)) wsid <- expect_no_condition(read_databrickscfg("wsid", profile = NULL)) expect_type(token, "character") expect_type(host, "character") expect_type(wsid, "character") # using read_databrickscfg directly token <- expect_no_condition(read_databrickscfg("token", profile = "DEFAULT")) host <- expect_no_condition(read_databrickscfg("host", profile = "DEFAULT")) wsid <- expect_no_condition(read_databrickscfg("wsid", profile = "DEFAULT")) expect_type(token, "character") expect_type(host, "character") expect_type(wsid, "character") # via wrappers token_w <- db_token(profile = "DEFAULT") host_w <- db_host(profile = "DEFAULT") wsid_w <- db_wsid(profile = "DEFAULT") expect_identical(token, token_w) expect_identical("some-host", host_w) expect_identical(wsid, wsid_w) # via wrappers token_w <- db_token(profile = NULL) host_w <- db_host(profile = NULL) wsid_w <- db_wsid(profile = NULL) expect_identical(token, token_w) expect_identical("some-host", host_w) expect_identical(wsid, wsid_w) }) test_that("auth functions - m2m credentials from env", { local_clear_auth_env() withr::local_envvar( DATABRICKS_CLIENT_ID = "client-id", DATABRICKS_CLIENT_SECRET = "client-secret" ) expect_identical(db_client_id(), "client-id") expect_identical(db_client_secret(), "client-secret") expect_true( db_oauth_client( host = "some-host", client_id = db_client_id(), client_secret = db_client_secret() )$is_m2m ) }) test_that("auth functions - m2m credentials from .databrickscfg", { local_clear_auth_env() withr::local_options(use_databrickscfg = TRUE) withr::local_envvar(DATABRICKS_CONFIG_FILE = "databricks.cfg") withr::local_file("databricks.cfg", { writeLines( c( '[DEFAULT]', 'host = http://some-host', 'client_id = client-id', 'client_secret = client-secret' ), "databricks.cfg" ) }) expect_identical(db_client_id(), "client-id") expect_identical(db_client_secret(), "client-secret") expect_true( db_oauth_client( host = "some-host", client_id = db_client_id(), client_secret = db_client_secret() )$is_m2m ) }) test_that("auth functions - azure m2m credentials from env", { local_clear_auth_env() withr::local_envvar( ARM_CLIENT_ID = "azure-client-id", ARM_CLIENT_SECRET = "azure-client-secret", ARM_TENANT_ID = "azure-tenant-id", DATABRICKS_AUTH_TYPE = "azure-client-secret" ) client <- db_oauth_client( host = "some-host", client_id = NULL, client_secret = NULL ) expect_identical(db_azure_client_id(), "azure-client-id") expect_identical(db_azure_client_secret(), "azure-client-secret") expect_identical(db_azure_tenant_id(), "azure-tenant-id") expect_true(client$is_m2m) expect_identical(client$auth_mode, "azure-client-secret") expect_identical( client$client$token_url, "https://login.microsoftonline.com/azure-tenant-id/oauth2/v2.0/token" ) expect_identical( client$scope, "2ff814a6-3304-4ab8-85cb-cd0e6f879c1d/.default" ) expect_identical( client$token_params, list() ) }) test_that("auth functions - azure m2m credentials from .databrickscfg", { local_clear_auth_env() withr::local_options(use_databrickscfg = TRUE) withr::local_envvar(DATABRICKS_CONFIG_FILE = "databricks.cfg") withr::local_file("databricks.cfg", { writeLines( c( '[DEFAULT]', 'host = http://some-host', 'azure_client_id = azure-client-id', 'azure_client_secret = azure-client-secret', 'azure_tenant_id = azure-tenant-id', 'auth_type = azure-client-secret' ), "databricks.cfg" ) }) client <- db_oauth_client( host = "some-host", client_id = NULL, client_secret = NULL ) expect_identical(db_azure_client_id(), "azure-client-id") expect_identical(db_azure_client_secret(), "azure-client-secret") expect_identical(db_azure_tenant_id(), "azure-tenant-id") expect_true(client$is_m2m) expect_identical(client$auth_mode, "azure-client-secret") }) test_that("auth functions - default fallback selects azure m2m before u2m", { local_clear_auth_env() withr::local_envvar( ARM_CLIENT_ID = "azure-client-id", ARM_CLIENT_SECRET = "azure-client-secret", ARM_TENANT_ID = "azure-tenant-id" ) client <- db_oauth_client( host = "some-host", client_id = NULL, client_secret = NULL ) expect_true(client$is_m2m) expect_identical(client$auth_mode, "azure-client-secret") }) test_that("auth functions - auth type ordering and override", { local_clear_auth_env() withr::local_envvar( DATABRICKS_CLIENT_ID = "dbx-client-id", DATABRICKS_CLIENT_SECRET = "dbx-client-secret", ARM_CLIENT_ID = "azure-client-id", ARM_CLIENT_SECRET = "azure-client-secret", ARM_TENANT_ID = "azure-tenant-id" ) default_client <- db_oauth_client(host = "some-host") expect_identical(default_client$auth_mode, "oauth-m2m") expect_identical(default_client$client$id, "dbx-client-id") withr::local_envvar(DATABRICKS_AUTH_TYPE = "azure-client-secret") azure_client <- db_oauth_client(host = "some-host") expect_identical(azure_client$auth_mode, "azure-client-secret") expect_identical(azure_client$client$id, "azure-client-id") }) test_that("auth functions - auth type override requires matching credentials", { local_clear_auth_env() withr::local_envvar( ARM_CLIENT_ID = "azure-client-id", ARM_CLIENT_SECRET = "azure-client-secret", ARM_TENANT_ID = "azure-tenant-id", DATABRICKS_AUTH_TYPE = "oauth-m2m" ) expect_error( db_oauth_client(host = "some-host"), "DATABRICKS_CLIENT_ID" ) }) test_that("auth functions - invalid auth type errors", { local_clear_auth_env() withr::local_envvar(DATABRICKS_AUTH_TYPE = "not-real") expect_error( db_oauth_client(host = "some-host", client_id = NULL, client_secret = NULL), "Supported values" ) }) test_that("auth functions - env auth type overrides .databrickscfg auth type", { local_clear_auth_env() withr::local_options(use_databrickscfg = TRUE) withr::local_envvar( DATABRICKS_CONFIG_FILE = "databricks.cfg", DATABRICKS_AUTH_TYPE = "oauth-u2m", DATABRICKS_CLIENT_ID = "dbx-client-id", DATABRICKS_CLIENT_SECRET = "dbx-client-secret", ARM_CLIENT_ID = "azure-client-id", ARM_CLIENT_SECRET = "azure-client-secret", ARM_TENANT_ID = "azure-tenant-id" ) withr::local_file("databricks.cfg", { writeLines( c( '[DEFAULT]', 'host = http://some-host', 'auth_type = azure-client-secret' ), "databricks.cfg" ) }) client <- db_oauth_client(host = "some-host") expect_identical(client$auth_mode, "oauth-u2m") }) test_that("auth functions - host handling", { local_clear_auth_env() expect_identical( db_host(id = "mock", prefix = "dev-"), "dev-mock.cloud.databricks.com" ) expect_identical( db_host(id = "mock"), "mock.cloud.databricks.com" ) expect_identical( db_host(id = "mock", prefix = "dev-"), "dev-mock.cloud.databricks.com" ) # input and output pairs to check hostname_mapping <- list( "https://mock.cloud.databricks.com" = "mock.cloud.databricks.com", "https://mock.cloud.databricks.com/" = "mock.cloud.databricks.com", "http://mock.cloud.databricks.com" = "mock.cloud.databricks.com" # "mock.cloud.databricks.com" = "mock.cloud.databricks.com", # "mock.cloud.databricks.com/" = "mock.cloud.databricks.com", # "mock.cloud.databricks.com//" = "mock.cloud.databricks.com", # "://mock.cloud.databricks.com" = NULL, # "//mock.cloud.databricks.com" = "mock.cloud.databricks.com", # "tps://mock.cloud.databricks.com" = "mock.cloud.databricks.com" ) purrr::iwalk(hostname_mapping, function(output, input) { withr::with_envvar( new = c(DATABRICKS_HOST = input), { expect_no_error(db_host()) expect_identical(db_host(), output) } ) }) }) test_that("auth functions - workbench managed credentials detection", { local_clear_auth_env() db_home <- withr::local_tempdir("posit-workbench") withr::local_file(.file = "databricks.cfg", code = { writeLines( c( '[workbench]', 'host = http://some-host', 'token = some-token' ), file.path(db_home, "databricks.cfg") ) }) # Two env variables need to be set on Workbench for detection to succeed # DATABRICKS_CONFIG_FILE with the path to the databricks.cfg file # DATABRICKS_CONFIG_PROFILE = "workbench" to set the profile correctly withr::with_envvar( new = c( DATABRICKS_CONFIG_FILE = file.path(db_home, "databricks.cfg"), DATABRICKS_CONFIG_PROFILE = "workbench" ), code = { token_w <- db_token() host_w <- db_host() expect_type(token_w, "character") expect_type(host_w, "character") expect_identical("some-host", host_w) expect_identical("some-token", token_w) } ) }) test_that("auth functions - workbench managed credentials override env var", { local_clear_auth_env() db_home <- withr::local_tempdir("posit-workbench") withr::local_file(.file = "databricks.cfg", code = { writeLines( c( '[workbench]', 'host = http://some-host', 'token = some-token' ), file.path(db_home, "databricks.cfg") ) }) # Two env variables need to be set on Workbench for detection to succeed # DATABRICKS_CONFIG_FILE with the path to the databricks.cfg file # DATABRICKS_CONFIG_PROFILE = "workbench" to set the profile correctly # Add different `DATABRICKS_HOST` and `DATABRICKS_TOKEN` env variables to ensure # the credentials from Workbench still get used withr::local_envvar( DATABRICKS_CONFIG_FILE = file.path(db_home, "databricks.cfg"), DATABRICKS_CONFIG_PROFILE = "workbench", DATABRICKS_HOST = "env-based-host", DATABRICKS_TOKEN = "env-based-token" ) token_w <- db_token() host_w <- db_host() expect_type(token_w, "character") expect_type(host_w, "character") expect_identical("some-host", host_w) expect_identical("some-token", token_w) })