audit() (see
vignette("getting-started", package = "dsROCrate")) builds
the whole RO-Crate in one call. This tutorial shows what happens inside:
we create the crate with init() and add the Five Safes one
at a time, which is useful to inspect each component, or to include only
some of them.
# server access (administrator account on the demo server)
USERNAME <- "administrator"
USERPASS <- "password"
# credentials of `dsuser`, only used to generate activity in section 3
DSUSERPASS <- "P@ssw0rd"
# Five Safes details
PROJECT <- "CNSIM"
TABLES <- "CNSIM1"
USER <- "dsuser"
con <- opalr::opal.login(
username = USERNAME,
password = USERPASS,
url = SERVER
)Note: safe_setting() and
safe_output() need an administrator or a user with the
Audit system permission, so use such an account for the
whole tutorial. See
vignette("audit-permissions", package = "dsROCrate").
init() creates an empty RO-Crate that follows the 5s-crate profile (via {rocrateR})
and records the connection and the study details. The next functions
read them from the crate, so you only write them once.
| Type | Entities |
|---|---|
| CreativeWork | 2 |
| Dataset | 1 |
Safe Output is built from the server’s DataSHIELD logs, so
there must be recent activity from the audited user. If you are using
your own server and already have activity, skip this section. Here we
log in as dsuser, assign a table and run two functions:
# registers the OpalDriver class in the current session
DSOpal::Opal()
builder <- DSI::newDSLoginBuilder()
builder$append(
server = "study1",
url = SERVER,
user = USER,
password = DSUSERPASS,
driver = "OpalDriver"
)
conns <- DSI::datashield.login(logins = builder$build())
#>
#> Logging into the collaborating servers
DSI::datashield.assign.table(
conns["study1"],
symbol = "dsROCrate_test",
table = paste0(PROJECT, ".", TABLES[1]),
errors.print = TRUE
)
dsBaseClient::ds.ls(datasources = conns["study1"])
dsBaseClient::ds.summary("dsROCrate_test", datasources = conns["study1"])
DSI::datashield.logout(conns)The packages {DSI}, {DSOpal} and
{dsBaseClient} are needed for this section.
Run safe_people() first: the later steps use the people
in the crate to leave administrator and auditor accounts out of the
permissions they record.
Adds a Person entity for the user and sets them as the
author of the crate.
| Type | Entities |
|---|---|
| CreativeWork | 2 |
| Dataset | 1 |
| Person | 1 |
Adds the Project entity and links it to its members.
| Type | Entities |
|---|---|
| CreativeWork | 2 |
| Dataset | 1 |
| Person | 1 |
| Project | 1 |
Adds the tables (and resources) of the project, who may access them, and the lineage between resources and tables, when available.
| Type | Entities |
|---|---|
| CreativeWork | 2 |
| Dataset | 2 |
| Person | 1 |
| Project | 1 |
| ReadAction | 1 |
Adds the disclosure control settings and the software installed on the server.
| Type | Entities |
|---|---|
| CreativeWork | 11 |
| Dataset | 2 |
| Person | 1 |
| Project | 1 |
| PropertyValue | 11 |
| ReadAction | 1 |
| SoftwareApplication | 4 |
Adds the logs of the user’s DataSHIELD operations in a period of time
(default: the last 24 hours), and a table that maps each operation to
the symbols, tables and columns it used. Set the period with
logs_from and logs_to.
crate <- crate |>
safe_output(
logs_from = Sys.time() - 24 * 60^2,
logs_to = Sys.time()
)
#> Found 195 records... Imported 195 records. Simplifying...
#> Warning: A `path` wasn't provided! The logs will be included in the RO-Crate
#> object, under the `content` tag!
crate_summary(crate)| Type | Entities |
|---|---|
| CreativeWork | 11 |
| Dataset | 2 |
| File | 2 |
| Person | 1 |
| Project | 1 |
| PropertyValue | 11 |
| ReadAction | 1 |
| SoftwareApplication | 4 |
If no path was given to init(), the logs
are stored inside the crate and safe_output() warns you
about it. To store them as files instead, call
init(..., path = "path/to/directory").
You can inspect the complete crate with
print(crate).
The crate can be stored as an RO-Crate bag/archive with
rocrateR::bag_rocrate():
# temporary directory, only for demo purposes
tmp_path_bag <- file.path(tempdir(), "dsROCrate-building-crates")
dir.create(tmp_path_bag, showWarnings = FALSE)
path_to_rocrate_bag <- crate |>
rocrateR::bag_rocrate(path = tmp_path_bag, overwrite = TRUE)
#> RO-Crate successfully 'bagged'!
#> For details, see: /var/folders/59/4_l6kbyj2qsczmk2b52qg_f40000gn/T//RtmpTwb5vi/dsROCrate-building-crates/rocrate-dbba4a15e4ea6b051c9c0e1a1ecf5aaa.zipand its contents explored with:
path_to_rocrate_bag |>
rocrateR::unbag_rocrate(
output = file.path(tmp_path_bag, "ROC"),
quiet = TRUE
) |>
fs::dir_tree()
#> /private/var/folders/59/4_l6kbyj2qsczmk2b52qg_f40000gn/T/RtmpTwb5vi/dsROCrate-building-crates/ROC
#> ├── bag-info.txt
#> ├── bagit.txt
#> ├── data
#> │ ├── 20261015T061400-dslogs-dsuser.log
#> │ ├── 20261015T061400-dslogs-dsuser_mappings.csv
#> │ └── ro-crate-metadata.json
#> ├── manifest-sha512.txt
#> └── tagmanifest-sha512.txtNote: the crate also keeps the server connection in
its attributes (so that the safe_*() functions need no
connection argument). It is not written to the bag, but
avoid saving the R object with saveRDS(); save the bag
instead.