From cd8a2823b9aea13fdcd1b18ffa3e3958cd52c068 Mon Sep 17 00:00:00 2001 From: Shane Halloran Date: Thu, 19 Oct 2023 10:38:23 +0100 Subject: [PATCH] Add sanitize() function, which wipes personal data and adds user URLs (#29) --------- Co-authored-by: Colin Gillespie --- DESCRIPTION | 5 ++--- NAMESPACE | 1 + NEWS.md | 4 ++++ R/quarto-helpers.R | 4 ++-- R/sanitise.R | 12 ++++++++++++ R/summarise_users.R | 1 + man/sanitise.Rd | 14 ++++++++++++++ tests/testthat/test-check.R | 5 ++--- tests/testthat/test-sanitise.R | 17 +++++++++++++++++ 9 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 R/sanitise.R create mode 100644 man/sanitise.Rd create mode 100644 tests/testthat/test-sanitise.R diff --git a/DESCRIPTION b/DESCRIPTION index bf23a57..824d128 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,14 +1,14 @@ Type: Package Package: audit.connect Title: Posit Connect Health Check -Version: 0.6.3 +Version: 0.7.0 Authors@R: person("Jumping", "Rivers", , "info@jumpingrivers.com", role = c("aut", "cre")) Description: Posit Connect Health Check. Deploys various content types to assess whether Connect is functioning correctly. License: file LICENSE Imports: - audit.base (>= 0.6.9), + audit.base (>= 0.6.10), cli, connectapi (>= 0.1.3.1), dplyr, @@ -22,7 +22,6 @@ Imports: quarto (>= 1.3), rlang, rsconnect (>= 1.1.0), - serverHeaders, stringr, tibble Suggests: diff --git a/NAMESPACE b/NAMESPACE index 24c6783..e1619cc 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -21,6 +21,7 @@ export(create_config) export(get_quarto_locked_user_apps) export(get_quarto_old_users) export(get_quarto_user_roles) +export(sanitise) import(audit.base) importFrom(dplyr,"%>%") importFrom(rlang,.data) diff --git a/NEWS.md b/NEWS.md index 0b1eb1f..7c964f6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +# audit.connect 0.7.0 _2023-10-18_ + - feat: `audit_object |> audit.connect::sanitize()` removes personal user data + - feat: Add in user URL when summarising users + # audit.connect 0.6.4 _2023-10-01_ - feat: Check for Posit name leakage diff --git a/R/quarto-helpers.R b/R/quarto-helpers.R index d1a8d07..b5c1ac7 100644 --- a/R/quarto-helpers.R +++ b/R/quarto-helpers.R @@ -9,7 +9,7 @@ get_quarto_old_users = function(out) { dplyr::filter(!.data$locked) old_users$email = tolower(old_users$email) old_users$domain = stringr::str_match(old_users$email, "@(.*)")[, 2] - old_users = dplyr::arrange(old_users, domain, email) + old_users = dplyr::arrange(old_users, .data$domain, .data$email) old_users = old_users %>% dplyr::mutate(last_log_on_diff = lubridate::interval(.data$active_time, lubridate::now()) / months(1), #nolint @@ -24,7 +24,7 @@ get_quarto_old_users = function(out) { dplyr::reframe(email = paste(.data$email, collapse = ", ")) %>% dplyr::mutate(last_log_in = factor(.data$last_log_in, c("12 months+", "6 months+", "3 months+"), - ordered = T)) %>% + ordered = TRUE)) %>% dplyr::arrange(.data$last_log_in) old_users$n = stringr::str_count(old_users$email, ",") + 1 old_users diff --git a/R/sanitise.R b/R/sanitise.R new file mode 100644 index 0000000..7c9e505 --- /dev/null +++ b/R/sanitise.R @@ -0,0 +1,12 @@ +#' Sanitise {audit.connect} object +#' +#' This function removes user-identifying data from an {audit.connect} object +#' @param audit_connect_check An object from audit.connect::check() +#' @export +sanitise = function(audit_connect_check) { + # Wipe any user-identifiable data + for (value in c("email", "first_name", "last_name", "username")) { + audit_connect_check$users_details$user_list$users[, value] = NA_character_ + } + audit_connect_check +} diff --git a/R/summarise_users.R b/R/summarise_users.R index ea94296..5136746 100644 --- a/R/summarise_users.R +++ b/R/summarise_users.R @@ -7,6 +7,7 @@ summarise_users = function(server, token, debug_level) { user_list = list() user_list$user_account_limit = settings$license$users user_list$users = suppress(connectapi::get_users(client, limit = Inf)) + user_list$users$url = paste0(server, "connect/#/people/users/", user_list$users$guid) if (is_evaluation(settings)) { apps = NA diff --git a/man/sanitise.Rd b/man/sanitise.Rd new file mode 100644 index 0000000..e175a31 --- /dev/null +++ b/man/sanitise.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/sanitise.R +\name{sanitise} +\alias{sanitise} +\title{Sanitise {audit.connect} object} +\usage{ +sanitise(audit_connect_check) +} +\arguments{ +\item{audit_connect_check}{An object from audit.connect::check()} +} +\description{ +This function removes user-identifying data from an {audit.connect} object +} diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R index 947dc77..b246ea9 100644 --- a/tests/testthat/test-check.R +++ b/tests/testthat/test-check.R @@ -3,15 +3,14 @@ test_that("High level test", { create_config(default = TRUE) expect_error(check(server = "aaa.bbb")) # Run standard check - rtn = check() + rtn = suppressMessages(check()) expect_true(is.list(rtn)) check_names = c("setup", "posit_version", "server_headers", "feature_usage", "audit_details", "users_details", "versions", "sys_deps", "results") %in% names(rtn) expect_true(all(check_names)) - - expect_equal(ncol(rtn$results), 5) + expect_equal(ncol(rtn$results), 6) # Check Quarto report # Copy over necessary files diff --git a/tests/testthat/test-sanitise.R b/tests/testthat/test-sanitise.R new file mode 100644 index 0000000..2ef08d3 --- /dev/null +++ b/tests/testthat/test-sanitise.R @@ -0,0 +1,17 @@ +describe("Checking sanitize function", { + testthat::skip_on_ci() + # Skip report checks for speed + create_config(default = FALSE, type = "force") + rtn = suppressMessages(check()) + sanitize_rtn = sanitise(rtn) + + it("Check users have been changed", + expect_false(identical(rtn[["users_details"]], + sanitize_rtn[["users_details"]])) + ) + + it("Check everything else has stayed the same", { + rtn[["users_details"]] = sanitize_rtn[["users_details"]] = NULL + expect_identical(rtn, sanitize_rtn) + }) +})