r if(Sys.getenv('CONNECT_SERVER') == '') { "<h4>ERROR: You must set the CONNECT_SERVER environment variable</h4>\n" }
r if(Sys.getenv('CONTENT_INFO_PIN') == '') { "<h4>ERROR: You must set the CONTENT_INFO_PIN environment variable ex. 'username/content-info'</h4>\n" }
r if(Sys.getenv('USER_INFO_PIN') == '') { "<h4>ERROR: You must set the USER_INFO_PIN environment variable ex. 'username/user-info'</h4>\n" }
r if(Sys.getenv('GROUP_INFO_PIN') == '') { "<h4>ERROR: You must set the GROUP_INFO_PIN environment variable ex. 'username/group-info'</h4>\n" }
r if(Sys.getenv('CONNECT_API_KEY') == '') { "<h4>ERROR: You must set the CONNECT_API_KEY environment variable</h4>\n" }
r if(Sys.getenv('CONNECT_API_KEY') == '' || Sys.getenv('CONNECT_SERVER') == '') { knitr::knit_exit() }
This report depends on the existence of the following pins:
content-info
user-info
group-info
The content-info
pin can be generated by running pin-content-list.Rmd
(intended to be run on a schedule).
# Register RStudio Connect library(pins) board_register("rsconnect", server = Sys.getenv('CONNECT_SERVER')) # Retrieve Pin content <- pin_get(name = Sys.getenv('CONTENT_INFO_PIN'), board = "rsconnect")
Create a summary table of the number of content items under each access type.
acl
Access Control List - Specific users or groupslogged_in
All users - login requiredall
Anyone - no login requiredlibrary(dplyr) library(gt) df <- content %>% select(guid, name, title, owner_guid, access_type, created_time, last_deployed_time, content_url, dashboard_url) df %>% count(access_type, sort = TRUE) %>% gt() %>% tab_header( title = "Sharing Settings", subtitle = "RStudio Connect Server Content Audit" ) %>% cols_label( access_type = "Access Type", n = "Count" )
Filter the content list to examine only content items with access_type == 'acl'
. This will contain two sub-types of content relevant for auditing:
# Filter content list by 'acl' access_type acl_only <- df %>% filter(access_type == 'acl')
/permissions
API endpoint.library(httr) # Function for initializing an empty permissions tibble empty_permissions <- function() { cols <- c('id','content_guid','principal_guid','principal_type','role') cols %>% purrr::map_dfc(setNames, object = list(character())) } # Function for calling the content `/permissions` API endpoint get_permissions <- function(guid) { permissions <- GET(paste0(Sys.getenv("CONNECT_SERVER"),"__api__/v1/content/",guid,"/permissions"), add_headers(Authorization = paste("Key", Sys.getenv("CONNECT_API_KEY")))) if (status_code(permissions) == 200){ result <- tidyr::unnest_wider(tibble::tibble(dat = content(permissions)), dat) if (dim(result)[1] == 0){ empty_permissions() } else { result } } else { empty_permissions() } } # Get permissions for all ACL-type content items # Content that is accessible only by the publisher-owner (no additional users or groups) will return no records acl_info <- purrr::map(acl_only$guid, get_permissions) acl_tibble <- tidyr::unnest(tibble::tibble(dat = acl_info), dat) # Join acl_tibble with acl_only acl_result <- acl_tibble %>% left_join(acl_only, by=c("content_guid" = "guid")) %>% rename(content_owner = owner_guid) # View the table result library(reactable) acl_result %>% select(content_guid, principal_guid, principal_type, role, name, content_owner) %>% reactable(searchable = TRUE, highlight = TRUE, columns=list( content_guid = colDef(name = "Content GUID"), name = colDef(name = "Content Name"), content_owner = colDef(name = "Content Owner"), principal_guid = colDef(name = "Principal GUID"), principal_type = colDef(name = "Principal Type"), role = colDef(name = "Share Access Role") ))
For each content item shared with specific users or groups, report the user/group and list whether they have viewer or collaborator access.
Note: The user-info
and group-info
pins can be generated by running pin-users-groups.Rmd
(intended to be run on a schedule).
library(pins) library(dplyr) # Get the user info Pin user_list <- pin_get(name = Sys.getenv("USER_INFO_PIN"), board = "rsconnect") # Get the group info Pin group_list <- pin_get(name = Sys.getenv("GROUP_INFO_PIN"), board = "rsconnect") # Add user names to the permission info pr_users <- acl_result %>% filter(principal_type == 'user') %>% left_join(user_list, by=c("principal_guid" = "guid")) # Add group names to the permission info pr_groups <- acl_result %>% filter(principal_type == 'group') %>% left_join(group_list, by=c("principal_guid" = "guid"))
# Create a pin for all content permissions that have been explicitly shared with other (specific) users. pins::pin(pr_users, name = "acl-users-table", description = "Results pulled from the content /permissions API, where the content has been shared with a user.", board = "rsconnect") # Create a pin for all content items that have been explicitly shared with specific groups. pins::pin(pr_groups, name = "acl-groups-table", description = "Results pulled from the content /permissions API, where the content has been shared with a group.", board = "rsconnect")
# Write the content permissions result table response out to a CSV file for download write.csv(acl_result, "rsc-acl-permissions.csv", row.names=FALSE)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.