Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Priv #13

Open
wants to merge 43 commits into
base: main
Choose a base branch
from
Open

Priv #13

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5b16f20
#3 privileges work
sckott Oct 21, 2024
3892677
#3 #4 added brainstorming code for policies as real code, fixed a tes…
sckott Oct 24, 2024
304dd47
only run examples if interactive
sckott Oct 29, 2024
5b4b5a9
#5 add with_db_user fxn
sckott Oct 29, 2024
65159c4
remove pkg loading messages/warnings
sckott Nov 4, 2024
b3ee90e
docs url fix
sckott Nov 4, 2024
f7c607d
add fxn rls_privileges to get overview of table and column level priv…
sckott Nov 4, 2024
14bfa57
run on all branches
sckott Nov 5, 2024
14b5fe5
add new vignette with basic important info on privileges and policies…
sckott Nov 5, 2024
b49b76a
gitignore s7 file
sckott Nov 8, 2024
898d48a
dont check system clock in r cmd check
sckott Nov 8, 2024
2ad5c83
limit to 4 sql commands we support in vignette
sckott Nov 8, 2024
6fd941a
#4 rework privilege methods
sckott Nov 8, 2024
564d0b2
styling
sckott Nov 8, 2024
0c1ae51
update man files
sckott Nov 8, 2024
2754bf9
added row policy fns
sckott Nov 12, 2024
5d98b0a
make passwd table setup example actually work from scratch
sckott Nov 12, 2024
b0f8b7b
#4 more tabular work for privileges and row policies
sckott Nov 12, 2024
de0687c
add as_con s3 method for privilege class
sckott Nov 13, 2024
45a156e
cleanup translate_privilege, add fxn rls policy exists, add test help…
sckott Nov 13, 2024
8c362fd
organize pkgdown config file
sckott Nov 13, 2024
e6304a9
overwrite = true in all dbWriteTable in test
sckott Nov 13, 2024
c6f8653
add helper fxn from tests for dropping all policies to pkg fxn, make …
sckott Nov 14, 2024
4da1d2b
add clean command to Makefile to clean out check folder and targz man…
sckott Nov 14, 2024
020da39
removed tests for old rls fxns, added some new tests
sckott Nov 14, 2024
8038f3b
move old rls create and construct fxns to inst/ignore; fix some small…
sckott Nov 14, 2024
75a0933
moved as_con to a separate R file
sckott Nov 14, 2024
66fa7fa
update vignette to use current fxns for row and column level stuff
sckott Nov 14, 2024
c5a9a4a
#10 make more examples self contained and clean up, not done yet
sckott Nov 15, 2024
b4cfcdc
fix #10 all examples i think are self contained and clean up
sckott Nov 15, 2024
d7b02b7
Merge branch 'priv' into with
sckott Dec 6, 2024
221da97
Merge pull request #11 from getwilds/with
sckott Dec 6, 2024
537fd89
fix namespace and with_db_user
sckott Dec 6, 2024
5533fd5
pkgdown config: remove some, add one
sckott Dec 6, 2024
86d8284
add lightswitch for dark/light toggle in pkgdown docs
sckott Dec 6, 2024
f706160
add more info on current_user here and there
sckott Dec 10, 2024
0673c25
fix #15 add restrictive fxn for as part of RLS policy; update vignette
sckott Dec 11, 2024
062efa6
change rls_run to rls_perform, fix missing param def for restrictive fun
sckott Dec 11, 2024
2076fa0
fix pkgdown reference for perform fxn
sckott Dec 11, 2024
66698eb
change output of rls_perform to a tibble upon success; remains error …
sckott Dec 11, 2024
7922b36
add rls_role_exists to easily check for roles or users
sckott Dec 11, 2024
c0ef212
drop NSE for row policy existing and new functions, just use sql input
sckott Dec 11, 2024
a738528
inject helper message into postgres default check for each test run w…
sckott Jan 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions .github/workflows/R-check.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
on:
push:
branches: [main]
pull_request:
branches: [main]
on: [push, pull_request]

name: R-check

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
docs
inst/doc
endtoend-*
R/s7stuff.R
17 changes: 13 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,30 @@ Authors@R: c(
)
Description: Row level security helpers. Currenlty supports
PostgreSQL and Redshift flavored PostgreSQL.
URL: https://github.com/getwilds/rls, http://getwilds.org/rls
URL: https://github.com/getwilds/rls, https://getwilds.org/rls
BugReports: https://github.com/getwilds/rls/issues
License: MIT + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
Roxygen: list(markdown = TRUE, roclets = c("collate", "namespace", "rd",
"roxyglobals::global_roclet"))
RoxygenNote: 7.3.2
Imports:
DBI,
dplyr,
dbplyr,
RPostgres,
tibble,
withr,
glue,
cli,
rlang,
RPostgres,
tibble
magrittr
Suggests:
knitr,
rmarkdown,
roxyglobals,
testthat (>= 3.0.0)
Config/testthat/edition: 3
VignetteBuilder: knitr
Config/roxyglobals/filename: globals.R
Config/roxyglobals/unique: FALSE
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ eg:
${RSCRIPT} -e "devtools::run_examples(run_dontrun = TRUE)"

check: build
_R_CHECK_CRAN_INCOMING_=FALSE R CMD CHECK --as-cran --no-manual `ls -1tr ${PACKAGE}*gz | tail -n1`
_R_CHECK_SYSTEM_CLOCK_=FALSE _R_CHECK_CRAN_INCOMING_=FALSE R CMD CHECK --as-cran --no-manual `ls -1tr ${PACKAGE}*gz | tail -n1`
@rm -f `ls -1tr ${PACKAGE}*gz | tail -n1`
@rm -rf ${PACKAGE}.Rcheck

clean:
@rm -f `ls -1tr ${PACKAGE}*gz | tail -n1`
@rm -rf ${PACKAGE}.Rcheck

Expand Down
71 changes: 68 additions & 3 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,18 +1,83 @@
# Generated by roxygen2: do not edit by hand

S3method(print,rls_policy)
S3method(as_con,PqConnection)
S3method(as_con,privilege)
S3method(as_con,row_policy)
S3method(as_priv,privilege)
S3method(as_priv,tbl_sql)
S3method(as_row_policy,row_policy)
S3method(as_row_policy,tbl_sql)
S3method(print,privilege)
S3method(print,row_policy)
export("%>%")
export(as_priv)
export(as_row_policy)
export(auto_pipe)
export(commands)
export(from)
export(grant)
export(has_postgres)
export(restrictive)
export(revoke)
export(rls_check_status)
export(rls_construct_policy)
export(rls_create_policy)
export(rls_col_policy)
export(rls_column_privileges)
export(rls_current_user)
export(rls_disable)
export(rls_drop_policies)
export(rls_drop_policy)
export(rls_enable)
export(rls_list_roles)
export(rls_perform)
export(rls_permissions)
export(rls_policies)
export(rls_policy_exists)
export(rls_privileges)
export(rls_role_exists)
export(rls_table_privileges)
export(rls_tbl)
export(row_policy)
export(rows_existing)
export(rows_new)
export(setup_example_table)
export(to)
export(translate_privilege)
export(translate_row_policy)
export(with_db_user)
import(dbplyr)
importFrom(DBI,dbExecute)
importFrom(DBI,dbExistsTable)
importFrom(DBI,dbGetQuery)
importFrom(DBI,dbRemoveTable)
importFrom(RPostgres,Postgres)
importFrom(cli,ansi_collapse)
importFrom(cli,cat_line)
importFrom(cli,cli_abort)
importFrom(cli,format_error)
importFrom(dbplyr,copy_inline)
importFrom(dbplyr,sql)
importFrom(dbplyr,translate_sql)
importFrom(dplyr,"%>%")
importFrom(dplyr,bind_rows)
importFrom(dplyr,filter)
importFrom(dplyr,pull)
importFrom(dplyr,rows_append)
importFrom(dplyr,tbl)
importFrom(glue,glue)
importFrom(glue,glue_safe)
importFrom(magrittr,"%>%")
importFrom(rlang,abort)
importFrom(rlang,as_name)
importFrom(rlang,caller_arg)
importFrom(rlang,caller_env)
importFrom(rlang,enquo)
importFrom(rlang,enquos)
importFrom(rlang,has_length)
importFrom(rlang,is_character)
importFrom(rlang,is_empty)
importFrom(rlang,is_scalar_character)
importFrom(rlang,quo_is_null)
importFrom(tibble,as_tibble)
importFrom(tibble,tibble)
importFrom(tibble,tribble)
importFrom(withr,defer)
18 changes: 18 additions & 0 deletions R/as_con.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#' As connection
#' @keywords internal
#' @return an S3 class object
as_con <- function(x) {
UseMethod("as_con")
}
#' @export
as_con.row_policy <- function(x) {
return(x$data$src$con)
}
#' @export
as_con.privilege <- function(x) {
return(x$data$src$con)
}
#' @export
as_con.PqConnection <- function(x) {
return(x)
}
39 changes: 39 additions & 0 deletions R/as_priv.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#' As privilege
#' @param x some input
#' @export
#' @return an object of S3 class "privilege"
as_priv <- function(x) {
UseMethod("as_priv")
}
#' @export
as_priv.privilege <- function(x) {
return(x)
}
#' @export
as_priv.tbl_sql <- function(x) {
tmp <- list(
data = x,
user = NULL,
privilege = list(),
type = NULL
)
structure(tmp, class = "privilege")
}
#' @export
#' @importFrom cli cat_line
print.privilege <- function(x, ...) {
cat_line("<privilege>")
if (!is_really_empty(x$user)) cat_me("user", x$user)
if (!is_really_empty(x$privilege)) {
cat_me("type", x$type)
for (i in x$privilege) {
cat_me(x = i$commands, y = i$cols %|||% "<all cols>", indent = " ")
}
}
print(x$data)
}

cat_me <- function(x, y, indent = " ") {
y <- paste0(y, collapse = ", ")
cat_line(glue("{indent}{x}: {y}", .trim = FALSE))
}
49 changes: 49 additions & 0 deletions R/as_row_policy.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#' As row policy
#' @param x some input
#' @export
#' @return an object of S3 class "row_policy"
as_row_policy <- function(x) {
UseMethod("as_row_policy")
}
#' @export
as_row_policy.row_policy <- function(x) {
return(x)
}
#' @export
as_row_policy.tbl_sql <- function(x) {
tmp <- list(
data = x,
name = NULL,
as = NULL,
commands = NULL,
user = NULL,
existing_rows = NULL,
new_rows = NULL,
type = NULL
)
structure(tmp, class = "row_policy")
}
#' @export
print.row_policy <- function(x, ...) {
cat_line(glue("<row_policy> {x$name}"))
cat_me("as", x$as %||% "PERMISSIVE")
if (!is_really_empty(x$user)) {
cat_me("user", x$user)
}
if (!is_really_empty(x$commands)) {
cat_me("commands", x$commands)
}
if (!is_really_empty(x$existing_rows)) {
cat_me("existing rows", x$existing_rows)
}
if (!is_really_empty(x$new_rows)) {
cat_me("new rows", x$new_rows)
}
if (!is_really_empty(x$privilege)) {
cat_me("type", x$type)
for (i in x$privilege) {
cat_me(x = i$commands, y = i$cols %|||% "<all cols>", indent = " ")
}
}
print(x$data)
}
56 changes: 40 additions & 16 deletions R/drop.R
Original file line number Diff line number Diff line change
@@ -1,34 +1,43 @@
#' Drop a row level security policy
#' Drop row level security policies
#'
#' @export
#' @importFrom glue glue
#' @importFrom DBI dbExecute
#' @inheritParams rls_create_policy
#' @param con a DBI database connection object
#' @param policy (list) a policy derived from running [row_policy()] and
#' friends
#' @param name (character) a policy name. optional
#' @param table (character) a table name. optional
#' @details If `policy` is supplied, `name` and `table` are not required. If
#' `policy` is not supplied, `name` and `table` need to be supplied.
#' @return a scalar numeric that specifies the number of rows affected
#' by the statement, invisibly
#' @return For `rls_drop_policy`, a scalar numeric that specifies the number
#' of rows affected by the statement, invisibly. For `rls_drop_policies`,
#' return `NULL` invisibly
#' @references <https://www.postgresql.org/docs/current/sql-droppolicy.html>
#' @examplesIf interactive() && has_postgres()
#' @details `rls_drop_policy` drops a single policy, and `rls_drop_policies`
#' drops all policies in the database defined by the `con`
#' @examplesIf has_postgres()
#' library(DBI)
#' library(RPostgres)
#' con <- dbConnect(Postgres())
#'
#' dbCreateTable(con, "atable", mtcars)
#' dbWriteTable(con, "atable", mtcars, overwrite = TRUE)
#'
#' policy1 <- rls_tbl(con, "atable") %>%
#' row_policy("hide_confidential") %>%
#' rows_existing(TRUE)
#' rls_perform(policy1)
#'
#' policy1 <- rls_construct_policy(
#' name = "hide_confidential",
#' on = "atable",
#' using = "(true)"
#' )
#' policy1
#' rls_create_policy(con, policy1)
#' rls_policies(con)
#' rls_drop_policy(con, policy1)
#' rls_policies(con)
#'
#' rls_perform(policy1)
#' rls_policies(con)
#' rls_drop_policies(con)
#' rls_policies(con)
#'
#' dbRemoveTable(con, "atable")
#' dbDisconnect(con)
rls_drop_policy <- function(con, policy = NULL, name = NULL, table = NULL) {
is_conn(con)
Expand All @@ -38,11 +47,26 @@ rls_drop_policy <- function(con, policy = NULL, name = NULL, table = NULL) {
)
if (!is.null(policy)) {
name <- policy$name
table <- policy$table
table <- attr(policy$data, "table")
} else {
if (is.null(name) && is.null(table)) {
rlang::abort("if `policy` is NULL, name & table must be non-NULL")
if (is.null(name) || is.null(table)) {
rlang::abort("if `policy` is NULL, `name` & `table` must be non-NULL")
}
}
invisible(dbExecute(con, glue("{drop_statement} POLICY {name} ON {table}")))
}

#' @export
#' @rdname rls_drop_policy
rls_drop_policies <- function(con) {
pols <- rls_policies(con)
if (NROW(pols) == 0) return(invisible())
for (i in seq_len(NROW(pols))) {
invisible(
rls_drop_policy(con,
name = pols$policyname[i],
table = pols$tablename[i]
)
)
}
}
2 changes: 1 addition & 1 deletion R/enable.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#' library(RPostgres)
#' con <- dbConnect(Postgres())
#' dbListTables(con)
#' dbWriteTable(con, "mtcars", mtcars, temporary = TRUE)
#' dbWriteTable(con, "mtcars", mtcars, overwrite = TRUE)
#' rls_enable(con, table = "mtcars")
#' rls_check_status(con, "mtcars")
#' rls_disable(con, table = "mtcars")
Expand Down
Loading
Loading