├── .Rbuildignore ├── .github ├── .gitignore ├── ISSUE_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── R-CMD-check.yaml │ ├── build-image.yaml │ ├── close-stale-issues.yaml │ ├── make-release.yaml │ ├── pkgdown.yaml │ └── test-coverage.yaml ├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DESCRIPTION ├── Dockerfile ├── INSTALL_EXTRAS.md ├── LICENSE ├── NAMESPACE ├── NEWS.md ├── R ├── common_graphs.R ├── create_tidyrisk_skeleton.R ├── data.R ├── encode.R ├── evaluator-deprecated.R ├── evaluator-package.R ├── import.R ├── load_data.R ├── openfair.R ├── report.R ├── simulate.R ├── summarize.R ├── tidyrisk_factor.R ├── tidyrisk_scenario.R ├── utils-pipe.R ├── utils.R └── validate.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── codecov.yml ├── cran-comments.md ├── data-raw └── regenerate_data.R ├── data ├── mc_capabilities.rda ├── mc_domain_summary.rda ├── mc_domains.rda ├── mc_mappings.rda ├── mc_qualitative_scenarios.rda ├── mc_quantitative_scenarios.rda ├── mc_scenario_summary.rda └── mc_simulation_results.rda ├── evaluator.Rproj ├── inst ├── WORDLIST ├── explore_scenarios │ ├── explore_scenarios.Rmd │ └── tests │ │ └── explore-scenarios.R ├── extdata │ ├── domains.csv │ ├── qualitative_mappings.csv │ └── risk_tolerances.csv ├── openfair_example │ ├── openfair_example.Rmd │ └── tests │ │ ├── openfair_example-expected │ │ ├── 001.json │ │ └── 001.png │ │ └── openfair_example.R ├── rmd │ ├── analyze_risk.Rmd │ ├── img │ │ └── evaluator_hex_48px.png │ ├── open-sans-import.html │ ├── risk_dashboard.Rmd │ └── styles │ │ ├── html-styles.css │ │ ├── open-sans-import.html │ │ └── word-styles-reference.docx ├── rstudio │ └── addins.dcf ├── run_analysis.R └── survey │ └── survey.xlsx ├── man ├── as_tibble.tidyrisk_scenario.Rd ├── calculate_max_losses.Rd ├── compare_tef_vuln.Rd ├── create_templates.Rd ├── create_tidyrisk_scenario_skeleton.Rd ├── derive_control_key.Rd ├── derive_controls.Rd ├── dollar_millions.Rd ├── encode_scenarios.Rd ├── evaluator-deprecated.Rd ├── evaluator-package.Rd ├── explore_scenarios.Rd ├── exposure_histogram.Rd ├── figures │ └── logo.png ├── generate_event_outcomes_plot.Rd ├── generate_heatmap.Rd ├── generate_report.Rd ├── generate_scatterplot-deprecated.Rd ├── get_base_fontfamily.Rd ├── get_mean_control_strength.Rd ├── identify_outliers.Rd ├── import_capabilities.Rd ├── import_scenarios.Rd ├── import_spreadsheet.Rd ├── is_tidyrisk_scenario.Rd ├── load_data-deprecated.Rd ├── loss_exceedance_curve.Rd ├── loss_scatterplot.Rd ├── mc_capabilities.Rd ├── mc_domain_summary.Rd ├── mc_domains.Rd ├── mc_mappings.Rd ├── mc_qualitative_scenarios.Rd ├── mc_quantitative_scenarios.Rd ├── mc_scenario_summary.Rd ├── mc_simulation_results.Rd ├── new_tidyrisk_scenario.Rd ├── openfair_example.Rd ├── openfair_tef_tc_diff_lm.Rd ├── openfair_tef_tc_diff_plm_sr.Rd ├── pipe.Rd ├── print.tidyrisk_scenario.Rd ├── read_qualitative_inputs.Rd ├── read_quantitative_inputs.Rd ├── risk_dashboard.Rd ├── run_simulation.Rd ├── run_simulations.Rd ├── sample_diff.Rd ├── sample_lef.Rd ├── sample_lm.Rd ├── sample_tc.Rd ├── sample_tef.Rd ├── sample_vuln.Rd ├── select_loss_opportunities.Rd ├── split_sheet.Rd ├── summarize_domains.Rd ├── summarize_iterations.Rd ├── summarize_scenario.Rd ├── summarize_to_disk.Rd ├── theme_evaluator.Rd ├── tidyrisk_factor.Rd ├── tidyrisk_factory.Rd ├── validate_scenarios.Rd ├── validate_tidyrisk_scenario.Rd ├── vec_cast.tidyrisk_factor.Rd └── vec_ptype_abbr.tidyrisk_scenario.Rd ├── meta_tags.html ├── pkgdown ├── extra.css └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── renv.lock ├── renv ├── .gitignore ├── activate.R └── settings.dcf ├── scripts ├── create_templates.R ├── deploy_scenario_explorer.R ├── generate_sample_reports.R ├── init.R ├── run.R └── run_analysis.R ├── tests ├── spelling.R ├── testthat.R └── testthat │ ├── test-common-graphs.R │ ├── test-encode.R │ ├── test-explore-scenarios.R │ ├── test-import.R │ ├── test-load-data.R │ ├── test-openfair-example.R │ ├── test-openfair.R │ ├── test-reports.R │ ├── test-run-analysis.R │ ├── test-simulate.R │ ├── test-summarize.R │ ├── test-test-tidyrisk-factor.R │ ├── test-tidyrisk-scenario.R │ ├── test-utils.R │ └── test-validate.R └── vignettes ├── customization.Rmd ├── process.Rmd └── usage.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^renv$ 2 | ^renv\.lock$ 3 | ^CRAN-RELEASE$ 4 | ^.*\.Rproj$ 5 | ^\.Rproj\.user$ 6 | .travis.yml 7 | CODE_OF_CONDUCT.md 8 | CONTRIBUTING.md 9 | INSTALL_EXTRAS.md 10 | README.Rmd 11 | cran-comments.md 12 | ^appveyor\.yml$ 13 | ^codecov\.yml$ 14 | ^data-raw$ 15 | ^docs$ 16 | ^_pkgdown\.yml$ 17 | ^index.Rmd$ 18 | meta_tags.html 19 | ^\.github$ 20 | pkgdown 21 | ^reports$ 22 | ^scripts$ 23 | ^Dockerfile$ 24 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please briefly describe your problem and what output you expect. 2 | 3 | Please include a minimal reproducible example (AKA a reprex). If you've never 4 | heard of a [reprex](http://reprex.tidyverse.org/) before, start by 5 | reading . 6 | 7 | Including a *sanitized* version of your input files (specificaly, `survey.xlsx`) 8 | is often crucial to allowing others to help identify and correct problems. 9 | If you attach input files, please take care not to include sensitive information 10 | on your submission! 11 | 12 | --- 13 | 14 | Brief description of the problem 15 | 16 | ```r 17 | # insert reprex here 18 | ``` 19 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | day: "sunday" 9 | assignees: 10 | - "davidski"" 11 | 12 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag. 2 | # https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | pull_request: 9 | branches: 10 | - main 11 | - master 12 | 13 | name: R-CMD-check 14 | 15 | jobs: 16 | R-CMD-check: 17 | runs-on: macOS-latest 18 | steps: 19 | - uses: actions/checkout@v2 20 | - uses: r-lib/actions/setup-pandoc@v1 21 | - uses: r-lib/actions/setup-r@v1 22 | - name: Install dependencies 23 | run: | 24 | install.packages(c("remotes", "rcmdcheck")) 25 | remotes::install_deps(dependencies = TRUE) 26 | shell: Rscript {0} 27 | - name: Check 28 | run: rcmdcheck::rcmdcheck(args = "--no-manual", error_on = "error") 29 | shell: Rscript {0} 30 | -------------------------------------------------------------------------------- /.github/workflows/build-image.yaml: -------------------------------------------------------------------------------- 1 | name: Docker Image 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | - name: Docker meta 16 | id: docker_meta 17 | uses: docker/metadata-action@v3 18 | with: 19 | images: ghcr.io/davidski/evaluator # list of Docker images to use as base name for tags 20 | tags: | 21 | type=sha 22 | - name: Set up QEMU 23 | uses: docker/setup-qemu-action@v1 24 | - name: Set up Docker Buildx 25 | uses: docker/setup-buildx-action@v1 26 | - name: Login to GitHub Container Registry 27 | uses: docker/login-action@v1 28 | with: 29 | registry: ghcr.io 30 | username: ${{ github.repository_owner }} 31 | password: ${{ secrets.CR_PAT }} 32 | - name: Build and push 33 | id: docker_build 34 | uses: docker/build-push-action@v2 35 | with: 36 | push: ${{ github.event_name != 'pull_request' }} 37 | labels: ${{ steps.docker_meta.outputs.labels }} 38 | tags: ${{ steps.docker_meta.outputs.tags }} 39 | build-args: | 40 | arg1=value1 41 | arg2=value2 42 | -------------------------------------------------------------------------------- /.github/workflows/close-stale-issues.yaml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues and PR' 2 | on: 3 | schedule: 4 | - cron: '30 1 * * *' 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v4 11 | with: 12 | stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.' 13 | stale-pr-message: 'This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.' 14 | close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.' 15 | days-before-stale: 60 16 | days-before-close: 7 17 | days-before-pr-close: -1 18 | exempt-issue-labels: preserve 19 | 20 | -------------------------------------------------------------------------------- /.github/workflows/make-release.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | # Sequence of patterns matched against refs/tags 4 | tags: 5 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 6 | 7 | name: Create Release 8 | 9 | jobs: 10 | build: 11 | name: Create Release 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v2 16 | - name: Create Release 17 | id: create_release 18 | uses: softprops/action-gh-release@v1 19 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | - master 6 | workflow_dispatch: 7 | 8 | name: pkgdown 9 | 10 | permissions: 11 | id-token: write 12 | contents: write 13 | 14 | jobs: 15 | pkgdown: 16 | runs-on: macOS-latest 17 | env: 18 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 19 | steps: 20 | - uses: actions/checkout@v2 21 | 22 | - uses: r-lib/actions/setup-r@v1 23 | 24 | - uses: r-lib/actions/setup-pandoc@v1 25 | 26 | - name: Query dependencies 27 | run: | 28 | install.packages('remotes') 29 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) 30 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") 31 | shell: Rscript {0} 32 | 33 | - name: Cache R packages 34 | uses: actions/cache@v2 35 | with: 36 | path: ${{ env.R_LIBS_USER }} 37 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} 38 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- 39 | 40 | - name: Install dependencies 41 | run: | 42 | remotes::install_deps(dependencies = TRUE) 43 | install.packages("pkgdown", type = "binary") 44 | shell: Rscript {0} 45 | 46 | - name: Install package 47 | run: R CMD INSTALL . 48 | 49 | - name: Build site and reports 50 | run: | 51 | Rscript -e 'pkgdown::build_site(preview = FALSE)' 52 | Rscript ./scripts/generate_sample_reports.R 53 | 54 | - name: Configure AWS credentials 55 | uses: aws-actions/configure-aws-credentials@v1 56 | with: 57 | role-to-assume: ${{ secrets.AWS_ROLE_ARN }} 58 | role-session-name: ${{ secrets.AWS_SESSION_NAME }} 59 | #aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 60 | #aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 61 | aws-region: us-west-2 62 | 63 | - name: Copy files to the website with the AWS CLI 64 | run: | 65 | aws s3 cp --recursive docs s3://${{ secrets.DEPLOY_BUCKET }}/ 66 | #aws s3 sync . s3://my-s3-test-website-bucket 67 | 68 | - name: Copy reports to the website with the AWS CLI 69 | run: | 70 | aws s3 cp --recursive reports s3://${{ secrets.DEPLOY_BUCKET }}/reports/ 71 | #aws s3 sync . s3://my-s3-test-website-bucket 72 | 73 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | - master 6 | pull_request: 7 | branches: 8 | - main 9 | - master 10 | 11 | name: test-coverage 12 | 13 | jobs: 14 | test-coverage: 15 | runs-on: macOS-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - uses: r-lib/actions/setup-r@v1 22 | 23 | - uses: r-lib/actions/setup-pandoc@v1 24 | 25 | - name: Query dependencies 26 | run: | 27 | install.packages('remotes') 28 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) 29 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") 30 | shell: Rscript {0} 31 | 32 | - name: Cache R packages 33 | uses: actions/cache@v2 34 | with: 35 | path: ${{ env.R_LIBS_USER }} 36 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} 37 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- 38 | 39 | - name: Install dependencies 40 | run: | 41 | install.packages(c("remotes")) 42 | remotes::install_deps(dependencies = TRUE) 43 | remotes::install_cran("covr") 44 | shell: Rscript {0} 45 | 46 | - name: Test coverage 47 | run: covr::codecov() 48 | shell: Rscript {0} 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | input_files 5 | inst/doc 6 | docs/CNAME 7 | reports 8 | docs 9 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at davidski@deadheaven.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Pull requests are awesome! By participating in this project, you agree to abide by the Evaluator [code of conduct](CODE_OF_CONDUCT.md). 4 | 5 | Fork, then clone the repo: 6 | 7 | git clone https://github.com//evaluator.git 8 | 9 | Make sure the tests pass: 10 | 11 | devtools::test() 12 | 13 | Make your change. Add tests for your change. Make the tests pass: 14 | 15 | devtools::test() 16 | 17 | Push to your fork and [submit a pull request][pr]. 18 | 19 | [pr]: https://github.com/davidski/evaluator/compare/ 20 | 21 | At this point you're waiting on me! 22 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: evaluator 2 | Title: Quantified Risk Assessment Toolkit 3 | Version: 0.4.4 4 | Authors@R: c(person("David", "Severski", email = "davidski@deadheaven.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-7867-0459"))) 5 | Description: An open source risk analysis toolkit based on the OpenFAIR ontology 6 | and risk analysis standard 7 | . Empowers an organization to 8 | perform a quantifiable, repeatable, and data-driven risk review. 9 | Depends: R (>= 3.3.0) 10 | License: MIT + file LICENSE 11 | Encoding: UTF-8 12 | LazyData: true 13 | Imports: 14 | cli, 15 | dplyr, 16 | ggplot2, 17 | mc2d, 18 | magrittr, 19 | purrr, 20 | readr, 21 | readxl, 22 | rlang, 23 | rstudioapi, 24 | scales, 25 | stringi, 26 | tibble, 27 | tidyr, 28 | vctrs, 29 | viridis 30 | Roxygen: list(markdown = TRUE) 31 | RoxygenNote: 7.1.2 32 | Suggests: 33 | DT, 34 | EnvStats, 35 | covr, 36 | knitr, 37 | flexdashboard (>= 0.4), 38 | forcats, 39 | furrr, 40 | markdown, 41 | mockery, 42 | pander (>= 0.6.1), 43 | psych, 44 | rmarkdown (>= 1.9), 45 | shiny, 46 | shinytest, 47 | spelling, 48 | statip, 49 | sysfonts, 50 | testthat 51 | SystemRequirements: pandoc 52 | VignetteBuilder: knitr 53 | Config/testthat/edition: 3 54 | URL: https://evaluator.tidyrisk.org 55 | BugReports: https://github.com/davidski/evaluator/issues 56 | Language: en-US 57 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rocker/tidyverse:4.0.3 as builder 2 | 3 | ARG EVALUATOR_VERSION 4 | ENV BUILD_DATE=2020-11-27 5 | ARG ADD=shiny 6 | 7 | LABEL org.opencontainers.image.licenses="MIT" \ 8 | org.opencontainers.image.source="https://github.com/davidski/evaluator" \ 9 | org.opencontainers.image.documentation="https://evaluator.tidyrisk.org" \ 10 | maintainer="David F. Severski " \ 11 | org.openctainers.image.authors="David F. Severski " 12 | 13 | RUN /rocker_scripts/install_shiny_server.sh 14 | 15 | COPY . /src/ 16 | WORKDIR /src 17 | 18 | RUN apt-get update \ 19 | && apt-get install -y zlib1g-dev libproj-dev libpng-dev libxml2-dev \ 20 | && install2.r --deps=TRUE remotes \ 21 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 22 | 23 | RUN apt-get clean \ 24 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 25 | 26 | COPY /scripts/create_templates.R /usr/local/bin/create_templates 27 | COPY /scripts/run_analysis.R /usr/local/bin/run_analysis 28 | 29 | VOLUME /data 30 | 31 | EXPOSE 8787 32 | EXPOSE 3838 33 | -------------------------------------------------------------------------------- /INSTALL_EXTRAS.md: -------------------------------------------------------------------------------- 1 | # Installation Extras 2 | 3 | While using the full power of Evaluator is easier with some basic proficency with the R langauge, making quantitative risk analysis available to a broader audience has always been a core goal of this project. Users with less R experience may appreciate these notes on setting up a R environment. 4 | 5 | # Docker 6 | 7 | The simplest method applicable to most users is the corresponding [evaluator-docker](https://github.com/davidski/evaluator-docker) project. This Dockerfile (and the corresponding pre-built image on [Docker Hub](https://hub.docker.com/r/davidski/evaluator-docker/)) is the fastest and surest means of getting started with Evaluator. 8 | 9 | # MacOS 10 | 11 | For Mac users running homebrew, the following terminal commands can be used to 12 | set up a functional environment. 13 | 14 | ``` 15 | # R and RStudio under homebrew derived from @hrbrmstr's post 16 | # https://rud.is/b/2015/10/22/installing-r-on-os-x-100-homebrew-edition/ 17 | 18 | # Core R and RStudio 19 | brew install homebrew/science/R 20 | brew install Caskroom/cask/rstudio 21 | 22 | # Latex required for PDF knitting 23 | brew cask install mactex 24 | 25 | # extra libraries to make other packages easier to work with 26 | brew install libsvg curl libxml2 gdal geos boost 27 | 28 | # font installation 29 | brew tap caskroom/fonts 30 | brew cask install font-fira-code font-iosevka font-inconsolata font-open-sans-condensed font-open-sans font-roboto-condensed 31 | R -e 'install.package("extrafont", repos="http://cran.cnr.berkeley.edu")' 32 | R -e 'extrafont::font_import(prompt = FALSE)' 33 | ``` 34 | 35 | Then install the Evaluator library either directly from CRAN via `install.packages('evaluator')` or from GitHub via `devtools::install_github('davidski/evaluator')`. 36 | 37 | # Windows 38 | 39 | Windows users should use [chocolately](https://chocolatey.org/install) for a simple `homebrew`-like package manager experience. 40 | 41 | - Install R 42 | 43 | - `choco install --yes r` 44 | 45 | - Install miktex for PDF knitting 46 | 47 | - `choco install --yes miktex` 48 | 49 | - Install RStudio (not available on Chocolately) 50 | 51 | - https://www.rstudio.com/products/rstudio/download/#download -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2017 2 | COPYRIGHT HOLDER: David F. Severski 3 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(as.data.frame,tidyrisk_scenario) 4 | S3method(as_tibble,tidyrisk_scenario) 5 | S3method(print,tidyrisk_scenario) 6 | export("%>%") 7 | export(calculate_max_losses) 8 | export(compare_tef_vuln) 9 | export(create_templates) 10 | export(create_tidyrisk_scenario_skeleton) 11 | export(derive_control_key) 12 | export(derive_controls) 13 | export(dollar_millions) 14 | export(encode_scenarios) 15 | export(explore_scenarios) 16 | export(exposure_histogram) 17 | export(generate_event_outcomes_plot) 18 | export(generate_heatmap) 19 | export(generate_report) 20 | export(generate_scatterplot) 21 | export(get_base_fontfamily) 22 | export(get_mean_control_strength) 23 | export(identify_outliers) 24 | export(import_capabilities) 25 | export(import_scenarios) 26 | export(import_spreadsheet) 27 | export(is_tidyrisk_scenario) 28 | export(load_data) 29 | export(loss_exceedance_curve) 30 | export(loss_scatterplot) 31 | export(new_tidyrisk_scenario) 32 | export(openfair_example) 33 | export(openfair_tef_tc_diff_lm) 34 | export(openfair_tef_tc_diff_plm_sr) 35 | export(read_qualitative_inputs) 36 | export(read_quantitative_inputs) 37 | export(risk_dashboard) 38 | export(run_simulation) 39 | export(run_simulations) 40 | export(sample_diff) 41 | export(sample_lef) 42 | export(sample_lm) 43 | export(sample_tc) 44 | export(sample_tef) 45 | export(sample_vuln) 46 | export(select_loss_opportunities) 47 | export(summarize_domains) 48 | export(summarize_iterations) 49 | export(summarize_scenario) 50 | export(summarize_scenarios) 51 | export(summarize_to_disk) 52 | export(theme_evaluator) 53 | export(tidyrisk_scenario) 54 | export(validate_scenarios) 55 | export(validate_tidyrisk_scenario) 56 | export(vec_ptype_abbr.tidyrisk_scenario) 57 | import(dplyr) 58 | import(ggplot2) 59 | importFrom(cli,cat_bullet) 60 | importFrom(cli,cat_line) 61 | importFrom(cli,cat_print) 62 | importFrom(cli,cat_rule) 63 | importFrom(cli,style_bold) 64 | importFrom(dplyr,"%>%") 65 | importFrom(dplyr,anti_join) 66 | importFrom(dplyr,arrange) 67 | importFrom(dplyr,bind_rows) 68 | importFrom(dplyr,case_when) 69 | importFrom(dplyr,desc) 70 | importFrom(dplyr,do) 71 | importFrom(dplyr,filter) 72 | importFrom(dplyr,group_by) 73 | importFrom(dplyr,group_by_at) 74 | importFrom(dplyr,left_join) 75 | importFrom(dplyr,mutate) 76 | importFrom(dplyr,mutate_at) 77 | importFrom(dplyr,percent_rank) 78 | importFrom(dplyr,progress_estimated) 79 | importFrom(dplyr,pull) 80 | importFrom(dplyr,rename) 81 | importFrom(dplyr,row_number) 82 | importFrom(dplyr,rowwise) 83 | importFrom(dplyr,select) 84 | importFrom(dplyr,summarize) 85 | importFrom(dplyr,tally) 86 | importFrom(dplyr,ungroup) 87 | importFrom(dplyr,union) 88 | importFrom(ggplot2,"%+replace%") 89 | importFrom(ggplot2,element_blank) 90 | importFrom(ggplot2,element_text) 91 | importFrom(ggplot2,theme) 92 | importFrom(ggplot2,theme_minimal) 93 | importFrom(magrittr,"%>%") 94 | importFrom(mc2d,rpert) 95 | importFrom(purrr,every) 96 | importFrom(purrr,flatten) 97 | importFrom(purrr,is_list) 98 | importFrom(purrr,is_null) 99 | importFrom(purrr,keep) 100 | importFrom(purrr,map) 101 | importFrom(purrr,map_dbl) 102 | importFrom(purrr,map_depth) 103 | importFrom(purrr,map_df) 104 | importFrom(purrr,map_dfr) 105 | importFrom(purrr,map_int) 106 | importFrom(purrr,map_lgl) 107 | importFrom(purrr,modify) 108 | importFrom(purrr,pluck) 109 | importFrom(purrr,pmap) 110 | importFrom(purrr,safely) 111 | importFrom(purrr,simplify) 112 | importFrom(purrr,simplify_all) 113 | importFrom(purrr,some) 114 | importFrom(purrr,transpose) 115 | importFrom(purrr,walk2) 116 | importFrom(readr,col_character) 117 | importFrom(readr,col_double) 118 | importFrom(readr,col_integer) 119 | importFrom(readr,cols) 120 | importFrom(readr,read_csv) 121 | importFrom(readr,write_csv) 122 | importFrom(readxl,read_excel) 123 | importFrom(rlang,.data) 124 | importFrom(rlang,as_function) 125 | importFrom(rlang,ensym) 126 | importFrom(rlang,exec) 127 | importFrom(rlang,list2) 128 | importFrom(rlang,set_names) 129 | importFrom(rstudioapi,insertText) 130 | importFrom(scales,comma) 131 | importFrom(scales,dollar) 132 | importFrom(scales,percent) 133 | importFrom(stats,median) 134 | importFrom(stats,quantile) 135 | importFrom(stats,sd) 136 | importFrom(stringi,stri_split_fixed) 137 | importFrom(tibble,add_row) 138 | importFrom(tibble,as_tibble) 139 | importFrom(tibble,deframe) 140 | importFrom(tibble,rownames_to_column) 141 | importFrom(tibble,tibble) 142 | importFrom(tidyr,gather) 143 | importFrom(tidyr,nest) 144 | importFrom(tidyr,separate_rows) 145 | importFrom(tidyr,unnest) 146 | importFrom(utils,data) 147 | importFrom(vctrs,new_vctr) 148 | importFrom(vctrs,stop_incompatible_cast) 149 | importFrom(vctrs,vec_assert) 150 | importFrom(vctrs,vec_cast) 151 | importFrom(vctrs,vec_data) 152 | importFrom(vctrs,vec_proxy_equal) 153 | importFrom(viridis,scale_fill_viridis) 154 | importFrom(viridis,viridis) 155 | -------------------------------------------------------------------------------- /R/create_tidyrisk_skeleton.R: -------------------------------------------------------------------------------- 1 | #' Create a skeleton tidyrisk scenario object in the current document 2 | #' 3 | #' Inserts a code block into the active document in RStudio for creating a 4 | #' \link{tidyrisk_scenario} object. This is an easy way of rapidly running 5 | #' a simulation. 6 | #' 7 | #' @export 8 | #' @importFrom rstudioapi insertText 9 | create_tidyrisk_scenario_skeleton <- function() { 10 | rstudioapi::insertText(text = 11 | "my_scenario <- tidyrisk_scenario( 12 | tef_params = list(min = 1, mode = 10, max = 100, shape = 3, func = \"mc2d::rpert\"), 13 | tc_params = list(min = .20, mode = .30, max = .70, shape = 2, func = \"mc2d::rpert\"), 14 | # note that diff_params can take multiple controls, hence the nested list 15 | diff_params = list(list(min = .25, mode = .50, max = .60, shape = 3, func = \"mc2d::rpert\")), 16 | lm_params = list(min = 100, mode = 1000, max = 10000, shape = 3, func = \"mc2d::rpert\")) 17 | 18 | my_results <- run_simulation(my_scenario, iterations = 1000) 19 | " 20 | ) 21 | } 22 | 23 | -------------------------------------------------------------------------------- /R/data.R: -------------------------------------------------------------------------------- 1 | #' Capabilities 2 | #' 3 | #' A sample set of capabilities for the demonstration (and artificial) 4 | #' MetroCare information security program. 5 | #' 6 | #' @source 7 | #' This is hypothetical information. Any similarity to any other 8 | #' entity is completely coincidental. 9 | #' 10 | #' @format 11 | #' \describe{ 12 | #' \item{capability_id}{unique id of the capability} 13 | #' \item{domain_id}{domain id to which the capability applies} 14 | #' \item{capability}{full text summary of the capability} 15 | #' \item{diff}{qualitative label of control effectiveness} 16 | #' } 17 | "mc_capabilities" 18 | 19 | #' Qualitative to quantitative mappings 20 | #' 21 | #' A sample set of qualitative to quantitative mappings for the demonstration 22 | #' (and artificial) MetroCare information security program. 23 | #' 24 | #' @source 25 | #' This is hypothetical information. Any similarity to any other 26 | #' entity is completely coincidental. 27 | #' 28 | #' @format 29 | #' \describe{ 30 | #' \item{type}{The element in the OpenFAIR ontology to which this mapping applies} 31 | #' \item{label}{Qualitative label} 32 | #' \item{l}{BetaPERT low value} 33 | #' \item{ml}{BetaPERT most likely value} 34 | #' \item{h}{BetaPERT high value} 35 | #' \item{conf}{BetaPERT confidence value} 36 | #' } 37 | "mc_mappings" 38 | 39 | #' Domain mappings 40 | #' 41 | #' A sample set of the domains for the demonstration (and artificial) 42 | #' MetroCare information security program. 43 | #' 44 | #' @source 45 | #' This is hypothetical information. Any similarity to any other 46 | #' entity is completely coincidental. 47 | #' 48 | #' @format 49 | #' \describe{ 50 | #' \item{domain_id}{abbreviated name of the domain} 51 | #' \item{domain}{full title of the domain} 52 | #' } 53 | "mc_domains" 54 | 55 | #' Domain-level risk summary 56 | #' 57 | #' A sample set of quantified information security risk exposure, summarized 58 | #' at the domain level, for the demonstration (and artificial) 59 | #' MetroCare information security program. 60 | #' 61 | #' @source 62 | #' This is hypothetical information. Any similarity to any other 63 | #' entity is completely coincidental. 64 | #' 65 | #' @format 66 | #' \describe{ 67 | #' \item{domain_id}{abbreviated name of the domain} 68 | #' \item{loss_events_mean}{mean number of loss events} 69 | #' \item{loss_events_min}{minimum number of loss events} 70 | #' \item{loss_events_max}{maximum number of loss events} 71 | #' \item{loss_events_median}{median number of loss events} 72 | #' \item{ale_max}{minimum annual loss expected} 73 | #' \item{ale_median}{median annual loss expected} 74 | #' \item{ale_mean}{mean annual loss expected} 75 | #' \item{ale_max}{maximum annual loss expected} 76 | #' \item{ale_sd}{standard deviation annual loss expected} 77 | #' \item{ale_var}{value at risk, ale} 78 | #' \item{mean_threat_events}{mean threat events} 79 | #' \item{mean_avoided_events}{mean avoided events} 80 | #' \item{mean_tc_exceedance}{mean threat capability exceedance} 81 | #' \item{mean_diff_exceedance}{mean difficulty exceedance} 82 | #' \item{mean_vuln}{mean vulnerability of the scenario} 83 | #' } 84 | "mc_domain_summary" 85 | 86 | #' Scenario-level risk summary 87 | #' 88 | #' A sample set of quantified information security risk exposure, summarized 89 | #' at the scenario level, for the demonstration (and artificial) 90 | #' MetroCare information security program. 91 | #' 92 | #' @source 93 | #' This is hypothetical information. Any similarity to any other 94 | #' entity is completely coincidental. 95 | #' 96 | #' @format 97 | #' \describe{ 98 | #' \item{scenario_id}{ID of the scenario} 99 | #' \item{domain_id}{domain id} 100 | #' \item{control_description}{control description} 101 | #' \item{results}{nested data frame of simulation results for the scenario} 102 | #' \item{loss_events_mean}{mean number of loss events} 103 | #' \item{loss_events_median}{median number of loss events} 104 | #' \item{loss_events_min}{minimum number of loss events} 105 | #' \item{loss_events_max}{maximum number of loss events} 106 | #' \item{ale_median}{median annual loss expected} 107 | #' \item{ale_max}{maximum annual loss expected} 108 | #' \item{ale_var}{value at risk, ale} 109 | #' \item{sle_min}{minimum single loss expectancy} 110 | #' \item{sle_max}{maximum single loss expectancy} 111 | #' \item{sle_mean}{mean single loss expectancy} 112 | #' \item{sle_median}{median single loss expectancy} 113 | #' \item{mean_tc_exceedance}{mean threat capability exceedance} 114 | #' \item{mean_diff_exceedance}{mean difficulty exceedance} 115 | #' \item{mean_vuln}{mean vulnerability of the scenario} 116 | #' } 117 | "mc_scenario_summary" 118 | 119 | #' Quantified information risk scenarios 120 | #' 121 | #' A sample set of quantified information security risk scenarios for the 122 | #' demonstration (and artificial) MetroCare information security program. 123 | #' 124 | #' @source 125 | #' This is hypothetical information. Any similarity to any other 126 | #' entity is completely coincidental. 127 | #' 128 | #' @format 129 | #' A dataset of quantified risk scenarios, with parameters 130 | #' describing the distribution of each input. 131 | #' 132 | #' \describe{ 133 | #' \item{scenario_id}{id of the scenario, primary key} 134 | #' \item{scenario_description}{full text description of the risk scenario} 135 | #' \item{tcomm}{description of the threat community} 136 | #' \item{domain_id}{domain id} 137 | #' \item{control_descriptons}{named list of the text description of controls involved} 138 | #' \item{scenario}{\code{\link{tidyrisk_scenario}} objects} 139 | #' } 140 | "mc_quantitative_scenarios" 141 | 142 | #' Qualitative information security risk scenarios 143 | #' 144 | #' A sample set of qualitative information security risk scenarios for the 145 | #' demonstration (and artificial) MetroCare information security program. 146 | #' 147 | #' No connection with any other similarly named entity is intended or implied. 148 | #' 149 | #' @source 150 | #' This is hypothetical information. Any similarity to any other 151 | #' entity is completely coincidental. 152 | #' @format 153 | #' \describe{ 154 | #' \item{scenario_id}{id of the scenario, primary key} 155 | #' \item{scenario}{full text description of the risk scenario} 156 | #' \item{tcomm}{full text name of threat community} 157 | #' \item{tef}{qualitative label of threat frequency} 158 | #' \item{tc}{qualitative label of threat capability} 159 | #' \item{lm}{qualitative label of loss magnitude} 160 | #' \item{domain_id}{domain id} 161 | #' \item{controls}{comma delimited list of controls ids} 162 | #' } 163 | "mc_qualitative_scenarios" 164 | 165 | #' Simulation results 166 | #' 167 | #' A sample set of information security risk scenario simulation results 168 | #' for the demonstration (and artificial) MetroCare information security 169 | #' program. 170 | #' 171 | #' @source 172 | #' This is hypothetical information. Any similarity to any other 173 | #' entity is completely coincidental. 174 | #' 175 | #' @format 176 | #' \describe{ 177 | #' \item{scenario_id}{id of the scenario} 178 | #' \item{domain_id}{domain id} 179 | #' \item{results}{nested data frame of simulation results for the scenario} 180 | #' } 181 | "mc_simulation_results" 182 | -------------------------------------------------------------------------------- /R/evaluator-deprecated.R: -------------------------------------------------------------------------------- 1 | #' @title Deprecated functions in package \pkg{evaluator}. 2 | #' @description The functions listed below are deprecated and will be defunct in 3 | #' the near future. When possible, alternative functions with similar 4 | #' functionality are also mentioned. Help pages for deprecated functions are 5 | #' available at \code{help("-deprecated")}. 6 | #' @name evaluator-deprecated 7 | #' @keywords internal 8 | NULL 9 | -------------------------------------------------------------------------------- /R/evaluator-package.R: -------------------------------------------------------------------------------- 1 | #' @keywords internal 2 | "_PACKAGE" 3 | 4 | # The following block is used by usethis to automatically manage 5 | # roxygen namespace tags. Modify with care! 6 | ## usethis namespace: start 7 | ## usethis namespace: end 8 | NULL 9 | 10 | ## quiets concerns of R CMD check re: the .'s that appear in pipelines 11 | ## technique from Jenny Bryan's googlesheet package 12 | utils::globalVariables(c(".")) 13 | -------------------------------------------------------------------------------- /R/simulate.R: -------------------------------------------------------------------------------- 1 | #' Run simulations for a scenario 2 | #' 3 | #' Given a quantitative scenario object of type `tidyrisk_scenario`, run an 4 | #' OpenFAIR Monte Carlo simulation. 5 | #' 6 | #' @importFrom dplyr progress_estimated bind_rows mutate row_number 7 | #' @importFrom purrr safely is_null map_lgl transpose simplify keep some 8 | #' @importFrom tidyr nest 9 | #' @importFrom rlang .data exec 10 | #' 11 | #' @param scenario A \link{tidyrisk_scenario} object. 12 | #' @param iterations Number of iterations to run on each scenario. 13 | #' @param simulation_count **DEPRECATED** Number of simulations to perform. 14 | #' @param ale_maximum Maximum practical annual losses. 15 | #' @param verbose Whether verbose console output is requested. 16 | #' 17 | #' @export 18 | #' @return Dataframe of results. 19 | #' @examples 20 | #' data(mc_quantitative_scenarios) 21 | #' run_simulation(mc_quantitative_scenarios$scenario[[1]], 10) 22 | run_simulation <- function(scenario, iterations = 10000L, 23 | ale_maximum = NULL, 24 | verbose = FALSE, simulation_count = NULL) { 25 | 26 | if (!is.null(simulation_count)) stop("simulation_count is deprecated. use `iterations` instead.", call. = FALSE) 27 | 28 | if (!is_tidyrisk_scenario(scenario)) { 29 | stop("Scenario must be a tidyrisk_scenario object", call. = FALSE) 30 | } 31 | 32 | # check for required elements 33 | required_elements <- formals(scenario$model) %>% names %>% 34 | setdiff(c("n", "verbose")) 35 | if (purrr::some(scenario$parameters[required_elements], is.null)) { 36 | stop("Missing one or more required elements.", call. = FALSE) 37 | } 38 | 39 | #model <- rlang::sym(model) # convert characters to symbol 40 | func <- scenario$model 41 | params <- c(scenario$parameters, list(n = iterations, verbose = verbose)) 42 | wrapped_calc <- function(x, .pb = NULL) { 43 | if ((!is.null(.pb)) & inherits(.pb, "Progress") && (.pb$i < .pb$n)) .pb$tick()$print() 44 | 45 | safe_calculate <- purrr::safely(eval(rlang::parse_expr(func))) 46 | rlang::exec("safe_calculate", !!!params) 47 | } 48 | 49 | simulation_results <- wrapped_calc(scenario) 50 | 51 | if (!is.null(simulation_results$error)) { 52 | stop("Errors encountered with scenarios:\n", 53 | scenario, 54 | paste0("Error: ", simulation_results$error, 55 | collapse = "\n")) 56 | } 57 | 58 | simulation_results <- simulation_results$result 59 | 60 | # apply a maximum per year ALE, if requested 61 | if (!(is.null(ale_maximum))) simulation_results$ale <- pmin(simulation_results$ale, ale_maximum) 62 | 63 | # store the date on which this simulation was generated 64 | attr(simulation_results, "generated_on") <- Sys.time() 65 | # store the number of iterations performed 66 | attr(simulation_results, "iterations") <- iterations 67 | 68 | simulation_results 69 | 70 | } 71 | 72 | 73 | 74 | #' Run simulations for a list of scenarios 75 | #' 76 | #' Given a list of quantitative scenario objects of type `tidyrisk_scenario`, 77 | #' run a OpenFAIR Monte Carlo simulation for each scenario. 78 | #' 79 | #' @inheritParams run_simulation 80 | #' @param ... Additional `tidyrisk_scenario` objects to simulate. 81 | #' 82 | #' @importFrom purrr map every 83 | #' @importFrom dplyr mutate 84 | #' @importFrom rlang .data 85 | #' 86 | #' @return A list of one dataframe of results for each scenario. 87 | #' @export 88 | #' @examples 89 | #' # fetch three scenarios for this example 90 | #' data(mc_quantitative_scenarios) 91 | #' scenario_a <- mc_quantitative_scenarios$scenario[[1]] 92 | #' scenario_b <- mc_quantitative_scenarios$scenario[[2]] 93 | #' scenario_c <- mc_quantitative_scenarios$scenario[[3]] 94 | #' run_simulations(scenario_a, scenario_b, scenario_c, iterations = 10) 95 | #' 96 | run_simulations <- function(scenario, ..., iterations = 10000L, 97 | ale_maximum = NULL, 98 | verbose = FALSE, simulation_count = NULL) { 99 | 100 | scenarios <- list(scenario, ...) 101 | if (!purrr::every(scenarios, is_tidyrisk_scenario)) { 102 | stop("All scenarios must be tidyrisk_scenario objects", call. = FALSE) 103 | } 104 | 105 | if (!is.null(simulation_count)) stop("simulation_count is deprecated. use `iterations` instead.", call. = FALSE) 106 | 107 | map(scenarios, run_simulation, iterations, ale_maximum, verbose) 108 | 109 | } 110 | -------------------------------------------------------------------------------- /R/tidyrisk_factor.R: -------------------------------------------------------------------------------- 1 | # Constructors ------------------------------------------------------------ 2 | 3 | #' Construct a tidyrisk_factor object 4 | #' 5 | #' @param samples samples 6 | #' @param factor_label fl 7 | #' @param details details 8 | #' @name tidyrisk_factor 9 | NULL 10 | 11 | #' @rdname tidyrisk_factor 12 | #' @importFrom vctrs vec_assert new_vctr 13 | new_tidyrisk_factor <- function(samples = double(), factor_label = character(), 14 | details = list()) { 15 | vctrs::vec_assert(samples, double()) 16 | vctrs::vec_assert(factor_label, character()) 17 | if (!factor_label %in% c("TF", "TEF", "TC", "DIFF", "LM", "PLM", "SLF", "SLM")) { 18 | stop("Factor label is not a supported OpenFAIR type.", call. = FALSE) 19 | } 20 | vctrs::vec_assert(details, list()) 21 | vctrs::new_vctr(samples, factor_label = factor_label, details = details, 22 | class = "tidyrisk_factor") 23 | } 24 | 25 | #' @rdname tidyrisk_factor 26 | tidyrisk_factor <- function(samples, factor_label, details = list()) { 27 | samples <- vctrs::vec_cast(samples, double()) 28 | factor_label <- vctrs::vec_cast(factor_label, character()) 29 | details <- vctrs::vec_cast(details, list()) 30 | new_tidyrisk_factor(samples, factor_label, details) 31 | } 32 | 33 | factor_label <- function(x) attr(x, "factor_label") 34 | details <- function(x) attr(x, "details") 35 | 36 | vec_ptype_abbr.tidyrisk_factor <- function(x) { 37 | "r_fctr" 38 | } 39 | 40 | is_tidyrisk_factor <- function(x) { 41 | inherits(x, "tidyrisk_factor") 42 | } 43 | 44 | as_tidyrisk_factor <- function(x, factor_label) { 45 | vec_cast(x, new_tidyrisk_factor(x, factor_label)) 46 | } 47 | 48 | # Formatters -------------------------------------------------------------- 49 | 50 | #' @importFrom cli cat_line cat_bullet cat_rule cat_print style_bold 51 | #' @importFrom vctrs vec_data 52 | #' @importFrom purrr walk2 53 | format.tidyrisk_factor <- function(x, ...) { 54 | cli::cat_line("# Factor samples: ", length(vctrs::vec_data(x))) 55 | cli::cat_line("# Factor label: ", factor_label(x)) 56 | if (length(details(x)) == 0) { 57 | cli::cat_bullet("# Summary details: None.") 58 | } else { 59 | purrr::walk2(names(details(x)), details(x) 60 | ~ cli::cat_bullet("# Summary detail: ", cli::style_bold(.x), 61 | " ", .y)) 62 | cli::cat_rule() 63 | } 64 | cli::cat_print(vctrs::vec_data(x)) 65 | 66 | invisible(x) 67 | } 68 | 69 | #' @importFrom vctrs vec_data 70 | summary.tidyrisk_factor <- function(object, ...) { 71 | samples <- vctrs::vec_data(object) 72 | switch(factor_label(object), 73 | LM = { 74 | if (length(samples) == 0 || sum(samples, na.rm = TRUE) == 0) { 75 | list(ale = 0, sle_max = 0, sle_min = 0, sle_mean = 0, 76 | sle_median = 0) 77 | } else { 78 | list(ale = sum(samples), 79 | sle_max = max(samples), 80 | sle_min = min(samples[samples > 0]), 81 | sle_mean = mean(samples[samples > 0]), 82 | sle_median = stats::median(samples[samples > 0]) 83 | ) 84 | }}, 85 | list() 86 | ) 87 | } 88 | 89 | # Casts ------------------------------------------------------------------- 90 | 91 | #' Cast a `tidyrisk_factor` vector to a specified type 92 | #' 93 | #' @inheritParams vctrs::vec_cast 94 | #' 95 | #' @method vec_cast tidyrisk_factor 96 | #' @importFrom vctrs vec_cast 97 | vec_cast.tidyrisk_factor <- function(x, to) UseMethod("vec_cast.tidyrisk_factor") 98 | 99 | #' @method vec_cast.tidyrisk_factor default 100 | #' @importFrom vctrs stop_incompatible_cast 101 | vec_cast.tidyrisk_factor.default <- function(x, to) { 102 | stop_incompatible_cast(x, to) 103 | } 104 | 105 | #' @method vec_cast.tidyrisk_factor class_pred 106 | vec_cast.tidyrisk_factor.class_pred <- function(x, to) { 107 | 108 | # first go tidyrisk_factor -> factor 109 | # then recast as tidyrisk_factor with correct attributes 110 | 111 | tidyrisk_factor( 112 | samples = x, 113 | factor_label = "TF" 114 | ) 115 | 116 | } 117 | 118 | # Arithmetic and Comparisons ---------------------------------------------- 119 | 120 | #' @importFrom vctrs vec_proxy_equal vec_data 121 | #' @keywords internal 122 | vec_proxy_compare.tidyrisk_factor <- function(x) { 123 | # allows you to compare two class_pred objects robustly 124 | # converting to character would confuse NA with equivocal 125 | vctrs::vec_data(x) 126 | } 127 | 128 | # Misc -------------------------------------------------------------------- 129 | 130 | #' Create a tidyrisk_factor sample function 131 | #' 132 | #' @param factor_label abbreviation of the OpenFAIR element 133 | #' @importFrom rlang as_function 134 | tidyrisk_factory <- function(factor_label = "TC") { 135 | 136 | function(.n = 1, ..., .func) { 137 | my_func <- rlang::as_function(.func) 138 | #dots <- enquos(...) 139 | 140 | samples <- my_func(n = .n, ...) 141 | tidyrisk_factor(samples = samples, factor_label = factor_label) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /R/tidyrisk_scenario.R: -------------------------------------------------------------------------------- 1 | # Constructors ------------------------------------------------------------ 2 | 3 | #' Construct a quantitative scenario object 4 | #' 5 | #' Supply one or more named lists in the format of `foo_params`, 6 | #' where each `foo` is an OpenFAIR factor name (e.g. tef, tc, diff, lm). 7 | #' Each factor should include a function name (`func`) to which the 8 | #' other named elements in the list are passed as parameters when 9 | #' sampling. 10 | #' 11 | #' 12 | #' @param ... One or more named OpenFAIR factor with parameters for sampling 13 | #' @param model Name of model to run 14 | #' @importFrom rlang list2 15 | #' @importFrom purrr every 16 | #' @export 17 | new_tidyrisk_scenario <- function(..., model = "openfair_tef_tc_diff_lm") { 18 | dots <- rlang::list2(...) 19 | if (any(names(dots) == "")) { 20 | stop("One or more parameters is unnamed.", call. = FALSE) 21 | } 22 | stopifnot(purrr::every(dots, is.list), is.character(model)) 23 | names(dots) <- gsub( "_params", "", names(dots)) 24 | scenario <- list( 25 | parameters = dots, 26 | model = model) 27 | class(scenario) <- c("tidyrisk_scenario", "list") 28 | scenario 29 | } 30 | 31 | #' @export 32 | #' @importFrom purrr modify 33 | #' @importFrom rlang list2 34 | #' @importFrom vctrs vec_cast 35 | #' @rdname new_tidyrisk_scenario 36 | tidyrisk_scenario <- function(..., model = "openfair_tef_tc_diff_lm") { 37 | dots <- rlang::list2(...) 38 | purrr::modify(dots, vctrs::vec_cast, list()) 39 | model <- vctrs::vec_cast(model, character()) 40 | validate_tidyrisk_scenario(new_tidyrisk_scenario(!!!dots, model = model)) 41 | } 42 | 43 | #' Validates that a scenario object is well formed 44 | #' 45 | #' @param x An object 46 | #' @export 47 | #' @importFrom purrr every pluck 48 | validate_tidyrisk_scenario <- function(x) { 49 | # iterating a ragged list is currently not working as expected 50 | #if (!purrr::every(x$parameters, purrr::pluck, "func", .default = FALSE)) { 51 | # stop( 52 | # "All parameters must have a `func` element, specifing the sampling function", 53 | # call. = FALSE 54 | # ) 55 | #} 56 | 57 | x 58 | 59 | } 60 | 61 | #' Test if the object is a tidyrisk_scenario 62 | #' 63 | #' This function returns `TRUE` for tidyrisk_scenario (or subclasses) 64 | #' and `FALSE` for all other objects. 65 | #' 66 | #' @param x An object 67 | #' @return `TRUE` if the object inherits from the `tidyrisk_scenario` class. 68 | #' @export 69 | is_tidyrisk_scenario <- function(x) { 70 | inherits(x, "tidyrisk_scenario") 71 | } 72 | 73 | #' Set an abbreviation when displaying an S3 column in a tibble 74 | #' 75 | #' @param x An object 76 | #' @export 77 | vec_ptype_abbr.tidyrisk_scenario <- function(x) { 78 | "r_scen" 79 | } 80 | 81 | # Formatters -------------------------------------------------------------- 82 | 83 | 84 | #' Default printing of a tidyrisk_scenario 85 | #' 86 | #' Basic printing of a tidyrisk scenario 87 | #' 88 | #' @param x A tidyrisk_scenario 89 | #' @param ... Currently not used 90 | #' @export 91 | #' @importFrom cli cat_line 92 | print.tidyrisk_scenario <- function(x, ...) { 93 | cli::cat_line("# Scenario model: ", x$model) 94 | cli::cat_line("# Defined parameters: ", paste0(names(x$parameters), collapse = ", ")) 95 | #NextMethod(x) 96 | 97 | invisible(x) 98 | } 99 | 100 | #' Coerce the parameters of a tidyrisk_scenario to a tibble 101 | #' 102 | #' @param x A tidyrisk_scenario 103 | #' @param ... Currently not used 104 | #' @export 105 | #' @importFrom cli cat_line 106 | #' @importFrom purrr map_depth 107 | #' @importFrom dplyr bind_rows 108 | as_tibble.tidyrisk_scenario <- function(x, ...) { 109 | cli::cat_line("# Scenario model: ", x$model) 110 | purrr::map_depth(x$parameters, .depth = 1, dplyr::bind_rows, .id = "id") %>% 111 | dplyr::bind_rows(.id = "openfair_factor") 112 | } 113 | 114 | #' @rdname as_tibble.tidyrisk_scenario 115 | #' @export 116 | as.data.frame.tidyrisk_scenario <- as_tibble.tidyrisk_scenario 117 | -------------------------------------------------------------------------------- /R/utils-pipe.R: -------------------------------------------------------------------------------- 1 | #' Pipe operator 2 | #' 3 | #' See \code{magrittr::\link[magrittr]{\%>\%}} for details. 4 | #' 5 | #' @name %>% 6 | #' @rdname pipe 7 | #' @keywords internal 8 | #' @export 9 | #' @importFrom magrittr %>% 10 | #' @usage lhs \%>\% rhs 11 | NULL 12 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | #' Helper function to verify package availability 2 | #' 3 | #' @importFrom purrr map_df 4 | #' @importFrom tibble tibble 5 | #' @param packages Packages to verify are available. 6 | #' @param func Calling function. 7 | #' 8 | #' @return Invisible 9 | #' @noRd 10 | #' @keywords internal 11 | #' \dontrun{ 12 | #' check_availability(packages = c("ggplot2", "dplyr"), func = "my_function") 13 | #' } 14 | check_availability <- function(packages, func) { 15 | res <- purrr::map_df(packages, 16 | ~ tibble::tibble(package = .x, 17 | available = requireNamespace(.x, quietly=TRUE))) 18 | if (sum(res$available) != length(packages)) { 19 | stop(func, " requires the following packages which are not available: ", 20 | paste0(res[res$available == FALSE, ]$package, collapse = ", "), "\n", 21 | "Please install and try again.", call. = FALSE) 22 | } 23 | 24 | invisible() 25 | 26 | } 27 | 28 | #' Format dollar amounts in terms of millions of USD 29 | #' 30 | #' Given a number, return a string formatted in terms of millions of dollars. 31 | #' 32 | #' @importFrom dplyr %>% 33 | #' @param x A number. 34 | #' @return String in the format of $xM. 35 | #' @export 36 | #' @examples 37 | #' dollar_millions(1.523 * 10^6) 38 | dollar_millions <- function(x) { 39 | # paste0('$', x / 10 ^ 6, 'M') 40 | x <- (x/10^6) %>% round(digits = 2) 41 | paste0("$", x, "M") 42 | } 43 | 44 | #' Unnest a summarized results dataframe, adding outlier information 45 | #' 46 | #' Given a summarized results dataframe, unnest the summary results 47 | #' column and use the value at risk (VaR) column to identify all the 48 | #' elements that are outliers (having a VaR >= two standard deviations) 49 | #' 50 | #' @param results Scenario summary results 51 | #' @importFrom dplyr mutate 52 | #' @importFrom tidyr unnest 53 | #' @export 54 | #' @return The supplied dataframe with the following additional columns: 55 | #' - `ale_var_zscore` - Annual loss z-score 56 | #' - `outlier` - Logical flag when the z-score is greater than or equal to two 57 | #' @examples 58 | #' data(mc_scenario_summary) 59 | #' identify_outliers(mc_scenario_summary) 60 | identify_outliers <- function(results) { 61 | results %>% #tidyr::unnest(summary) %>% 62 | dplyr::mutate(ale_var_zscore = as.vector(scale(.data$ale_var)), 63 | outlier = .data$ale_var_zscore >= 2) 64 | } 65 | 66 | 67 | #' Calculate maximum losses 68 | #' 69 | #' Calculate the biggest single annual loss for each scenario, as well as 70 | #' the minimum and maximum ALE across all iterations. Calculations both 71 | #' with and without outliers (if passed) are returned. 72 | #' 73 | #' @importFrom dplyr filter group_by summarize ungroup union 74 | #' @importFrom tidyr unnest 75 | #' @importFrom rlang .data 76 | #' @param simulation_results Simulation results dataframe. 77 | #' @param scenario_outliers Optional vector of IDs of outlier scenarios. 78 | #' @return A dataframe with the following columns: 79 | #' - `iteration` - index of the iteration 80 | #' - `biggest_single_scenario_loss` - the biggest annual loss in that iteration, 81 | #' - `min_loss` - the smallest annual loss in that iteration, 82 | #' - `max_loss` - the total annual losses in that iteration 83 | #' - `outliers` - logical of whether or not outliers are included 84 | #' @export 85 | #' @examples 86 | #' data(mc_simulation_results) 87 | #' calculate_max_losses(mc_simulation_results) 88 | calculate_max_losses <- function(simulation_results, scenario_outliers = NULL) { 89 | max_loss <- tidyr::unnest(simulation_results, .data$results) %>% 90 | dplyr::filter(!.data$scenario_id %in% scenario_outliers) %>% 91 | dplyr::group_by(.data$iteration) %>% 92 | dplyr::summarize(biggest_single_scenario_loss = max(.data$ale), 93 | min_loss = min(.data$ale), max_loss = sum(.data$ale), 94 | outliers = FALSE) %>% 95 | dplyr::ungroup() 96 | # if we're not passed any outliers, don't bother calculating outliers 97 | if (is.null(scenario_outliers)) return(max_loss) 98 | 99 | max_loss_w_outliers <- tidyr::unnest(simulation_results, .data$results) %>% 100 | dplyr::group_by(.data$iteration) %>% 101 | dplyr::summarize(biggest_single_scenario_loss = max(.data$ale), 102 | min_loss = min(.data$ale), 103 | max_loss = sum(.data$ale), outliers = TRUE) %>% 104 | dplyr::ungroup() 105 | dplyr::union(max_loss, max_loss_w_outliers) 106 | } 107 | -------------------------------------------------------------------------------- /R/validate.R: -------------------------------------------------------------------------------- 1 | #' Validate qualitative scenario data 2 | #' 3 | #' Run a set of basic consistency checks on the key qualitative data inputs 4 | #' (scenarios, capabilities, domains, and mappings). 5 | #' 6 | #' Checks that: 7 | #' - All scenarios are distinct 8 | #' - All controls referenced in scenarios are defined in the controls table 9 | #' - All controls are distinct 10 | #' 11 | #' @importFrom dplyr tally filter left_join rename anti_join rowwise ungroup 12 | #' @importFrom rlang .data 13 | #' @importFrom stringi stri_split_fixed 14 | #' @importFrom tidyr separate_rows 15 | #' @param scenarios Dataframe of qualitative scenarios. 16 | #' @param capabilities Dataframe of capabilities. 17 | #' @param domains Dataframe of domain mappings. 18 | #' @param mappings Dataframe of qualitative to quantitative mappings. 19 | #' 20 | #' @export 21 | #' @return An invisible boolean as to success/failure of validation steps. 22 | #' @examples 23 | #' \dontrun{ 24 | #' validate_scenarios(scenarios, capabilities, domains, mappings) 25 | #' } 26 | validate_scenarios <- function(scenarios, capabilities, domains, mappings) { 27 | 28 | validated <- TRUE 29 | 30 | # Verify there are no duplicate scenarios 31 | scenarios %>% dplyr::group_by_at(.vars = "scenario_id") %>% dplyr::tally() %>% 32 | dplyr::filter(.data$n > 1) %>% 33 | dplyr::left_join(scenarios, by = "scenario_id") %>% 34 | dplyr::rename(times_duplicated = .data$n) -> 35 | duplicate_scenarios 36 | if (nrow(duplicate_scenarios) != 0) { 37 | warning(paste("Duplicate scenarios found:", 38 | duplicate_scenarios$scenario_id, collapse = "\n"), 39 | call. = FALSE) 40 | validated <- FALSE 41 | } 42 | 43 | # Are all the capabilities referenced in the scenarios defined? 44 | missing_capabilities <- scenarios %>% 45 | tidyr::separate_rows(.data$controls, sep = ", ", convert = FALSE) %>% 46 | dplyr::anti_join(capabilities, by = c("controls" = "capability_id")) 47 | if (nrow(missing_capabilities) != 0) { 48 | warning(paste("Scenarios with undefined capabilities:", 49 | missing_capabilities$scenario_id, collapse = "\n"), 50 | call. = FALSE) 51 | validated <- FALSE 52 | } 53 | 54 | # Verify there are no duplicate controls 55 | capabilities %>% dplyr::group_by_at(.vars = "capability_id") %>% dplyr::tally() %>% 56 | dplyr::filter(.data$n > 1) %>% 57 | dplyr::left_join(capabilities, by = "capability_id") %>% 58 | dplyr::rename(times_duplicated = .data$n) -> duplicate_capabilities 59 | if (nrow(duplicate_capabilities) != 0) { 60 | warning(paste("Duplicate capabilities found:", 61 | duplicate_capabilities$capability_id, collapse = "\n"), 62 | call. = FALSE) 63 | validated <- FALSE 64 | } 65 | 66 | ## ----check_qualitative_mappings------------------------------------------ 67 | stop_message <- NULL 68 | 69 | # TEF 70 | if (!all((tolower(distinct(scenarios, .data$tef)$tef) %in% filter(mappings, .data$type=="tef")$label))) { 71 | stop_message <- paste(stop_message, 72 | "There are qualitative TEF values in the scenarios which are not found in the mappings", sep = "\n") 73 | } 74 | # TC 75 | if (!all((tolower(distinct(scenarios, .data$tc)$tc) %in% filter(mappings, .data$type=="tc")$label))) { 76 | stop_message <- paste(stop_message, 77 | "There are qualitative TC values in the scenarios which are not found in the mappings", sep = "\n") 78 | } 79 | # DIFF 80 | if (!all((tolower(distinct(capabilities, .data$diff)$diff) %in% tolower(filter(mappings, .data$type=="diff")$label)))) { 81 | stop_message <- paste(stop_message, 82 | "There are qualitative DIFF values in the capabilities which are not found in the mappings", sep = "\n") 83 | } 84 | # LM 85 | if (!all((tolower(distinct(scenarios, .data$lm)$lm) %in% filter(mappings, .data$type=="lm")$label))) { 86 | stop_message <- paste(stop_message, 87 | "There are qualitative LM values in the scenarios which not found in the mappings", sep = "\n") 88 | } 89 | 90 | if (!is.null(stop_message)) { 91 | warning(stop_message, call. = FALSE) 92 | validated <- FALSE 93 | } 94 | 95 | # add the number of controls applicable to each scenario as a validation step 96 | scenarios <- scenarios %>% 97 | dplyr::rowwise() %>% 98 | dplyr::mutate(control_count = 99 | length(stringi::stri_split_fixed(.data$controls, 100 | ", ", 101 | simplify = TRUE))) %>% 102 | dplyr::ungroup() 103 | 104 | invisible(validated) 105 | } 106 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: 3 | github_document: default 4 | --- 5 | 6 | 7 | 8 | ```{r, echo = FALSE} 9 | knitr::opts_chunk$set( 10 | collapse = TRUE, 11 | comment = "#>", 12 | fig.path = "README-" 13 | ) 14 | ``` 15 | 16 | # evaluator evaluator Logo 17 | 18 | 19 | [![R build status](https://github.com/davidski/evaluator/workflows/R-CMD-check/badge.svg)](https://github.com/davidski/evaluator/actions) 20 | [![Coverage Status](https://codecov.io/gh/davidski/evaluator/branch/master/graph/badge.svg)](https://codecov.io/github/davidski/evaluator?branch=master) 21 | [![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/evaluator)](https://cran.r-project.org/package=evaluator) 22 | ![downloads](https://cranlogs.r-pkg.org/badges/grand-total/evaluator) 23 | 24 | 25 | ## Overview 26 | 27 | evaluator is an open source quantitative risk analysis toolkit. Based on the OpenFAIR 28 | [ontology](https://publications.opengroup.org/c20b) and 29 | risk analysis [standard](https://publications.opengroup.org/c20a), 30 | evaluator empowers an organization to perform a quantifiable, repeatable, and 31 | data-driven risk review. 32 | 33 | Three sample outputs of this toolkit are available: 34 | 35 | 1) A [sample risk analysis](https://evaluator.tidyrisk.org/reports/evaluator_risk_analysis.html) report 36 | 2) A one page [risk dashboard](https://evaluator.tidyrisk.org/reports/evaluator_risk_dashboard.html) 37 | 3) A demonstration copy of [Scenario Explorer](https://davidski.shinyapps.io/scenario_explorer) 38 | 39 | ## Installation 40 | 41 | Install evaluator via the standard CRAN mechanisms. If you wish to use the 42 | optional, but recommended, reporting functions, also install the 43 | suggested dependencies. These additional packages are not needed for 44 | modeling, but are used in the generation of reports. 45 | 46 | ```{r install_cran, eval=FALSE} 47 | install.packages("evaluator", dependencies = TRUE) 48 | ``` 49 | 50 | If you wish to run the development (and potentially bleeding edge) version of 51 | evaluator, you can install directly from GitHub with the following `devtools` 52 | command. 53 | 54 | ```{r github_install, eval=FALSE} 55 | # install.pacakges("devtools") 56 | devtools::install_github("davidski/evaluator", dependencies = TRUE) 57 | ``` 58 | 59 | Optionally, Docker images with all dependencies pre-installed are 60 | available on the [Docker Hub](https://hub.docker.com/r/tidyrisk). 61 | 62 | ## Usage 63 | 64 | The primary workflow for evaluator involves gathering data in Excel then 65 | running the analysis from within the R and Evaluator environment: 66 | 67 | From Excel: 68 | 69 | 1. Populate the evaluator-supplied data acquisition spreadsheet 70 | 71 | From Evaluator: 72 | 73 | 2. Import the data 74 | 3. Prepare the data for simulation 75 | 4. Run the simulations 76 | 5. Summarize the results 77 | 6. Generate draft reports for customization 78 | 79 | A detailed guide is available in the vignette accessed via 80 | `vignette("usage", package="evaluator")`. A short screencast showing 81 | the basic workflow (not including generation of reports) is available below: 82 | 83 | [![demo](https://asciinema.org/a/qIBU3lhPkWHGMYD9O2GU1YgcU.png)](https://asciinema.org/a/qIBU3lhPkWHGMYD9O2GU1YgcU?s=2&autoplay=1) 84 | 85 | ## Where to Go from Here 86 | 87 | While evaluator is a powerful tool, it does not attempt to address interactions 88 | between risk scenarios, rolling up multiple levels of risk into aggregations, or 89 | other advanced topics. As you become more comfortable with quantitative risk 90 | analysis, you may wish to dive deeper into these areas (and I hope you do!). 91 | The following resources may help you explore these and other topics in risk 92 | management. 93 | 94 | ### Alternative Software 95 | 96 | - [RiskLens](https://www.risklens.com), a commercial analysis suite, founded 97 | by the original creator of the FAIR methodology 98 | - [FAIR Tool](https://github.com/zugo01/FAIRTool), a Shiny and R based two 99 | scenario simulator, authored by Ezeugo Aguta under an MIT license 100 | - [FAIR-U](https://www.fairinstitute.org/fair-u), a free educational tool for 101 | learning FAIR analysis, powered by RiskLens 102 | - [Open FAIR Risk Analysis Tool](https://publications.opengroup.org/i181), 103 | an Excel and SIPMath base tool with a limited open license 104 | 105 | ### Blogs/Books/Training 106 | 107 | - Russell C. Thomas's excellent and provocative blog post on systemic [Risk Management](https://exploringpossibilityspace.blogspot.com/2013/08/risk-management-out-with-old-in-with-new.html) 108 | - [Measuring and Managing Information Risk](https://smile.amazon.com/gp/product/0124202314) 109 | - [OpenFAIR certification](https://www.opengroup.org/certifications/openfair) 110 | - [Hubbard Decision Research calibration training](https://hubbardresearch.com/training/) 111 | 112 | ### Associations 113 | 114 | - [FAIR Institute](https://www.fairinstitute.org) 115 | - [Society of Information Risk Analysts (SIRA)](https://www.societyinforisk.org/) 116 | 117 | ## Contributing 118 | 119 | This project is governed by a 120 | [Code of Conduct](https://evaluator.tidyrisk.org/CODE_OF_CONDUCT.html). By 121 | participating in this project you agree to abide by these terms. 122 | 123 | ## License 124 | 125 | The [MIT License](LICENSE) applies. 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # evaluator evaluator Logo 5 | 6 | 7 | 8 | [![R build 9 | status](https://github.com/davidski/evaluator/workflows/R-CMD-check/badge.svg)](https://github.com/davidski/evaluator/actions) 10 | [![Coverage 11 | Status](https://codecov.io/gh/davidski/evaluator/branch/master/graph/badge.svg)](https://codecov.io/github/davidski/evaluator?branch=master) 12 | [![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/evaluator)](https://cran.r-project.org/package=evaluator) 13 | ![downloads](https://cranlogs.r-pkg.org/badges/grand-total/evaluator) 14 | 15 | 16 | ## Overview 17 | 18 | evaluator is an open source quantitative risk analysis toolkit. Based on 19 | the OpenFAIR [ontology](https://publications.opengroup.org/c20b) and 20 | risk analysis [standard](https://publications.opengroup.org/c20a), 21 | evaluator empowers an organization to perform a quantifiable, 22 | repeatable, and data-driven risk review. 23 | 24 | Three sample outputs of this toolkit are available: 25 | 26 | 1. A [sample risk 27 | analysis](https://evaluator.tidyrisk.org/reports/evaluator_risk_analysis.html) 28 | report 29 | 2. A one page [risk 30 | dashboard](https://evaluator.tidyrisk.org/reports/evaluator_risk_dashboard.html) 31 | 3. A demonstration copy of [Scenario 32 | Explorer](https://davidski.shinyapps.io/scenario_explorer) 33 | 34 | ## Installation 35 | 36 | Install evaluator via the standard CRAN mechanisms. If you wish to use 37 | the optional, but recommended, reporting functions, also install the 38 | suggested dependencies. These additional packages are not needed for 39 | modeling, but are used in the generation of reports. 40 | 41 | ``` r 42 | install.packages("evaluator", dependencies = TRUE) 43 | ``` 44 | 45 | If you wish to run the development (and potentially bleeding edge) 46 | version of evaluator, you can install directly from GitHub with the 47 | following `devtools` command. 48 | 49 | ``` r 50 | # install.pacakges("devtools") 51 | devtools::install_github("davidski/evaluator", dependencies = TRUE) 52 | ``` 53 | 54 | Optionally, Docker images with all dependencies pre-installed are 55 | available on the [Docker Hub](https://hub.docker.com/r/tidyrisk). 56 | 57 | ## Usage 58 | 59 | The primary workflow for evaluator involves gathering data in Excel then 60 | running the analysis from within the R and Evaluator environment: 61 | 62 | From Excel: 63 | 64 | 1. Populate the evaluator-supplied data acquisition spreadsheet 65 | 66 | From Evaluator: 67 | 68 | 2. Import the data 69 | 3. Prepare the data for simulation 70 | 4. Run the simulations 71 | 5. Summarize the results 72 | 6. Generate draft reports for customization 73 | 74 | A detailed guide is available in the vignette accessed via 75 | `vignette("usage", package="evaluator")`. A short screencast showing the 76 | basic workflow (not including generation of reports) is available below: 77 | 78 | [![demo](https://asciinema.org/a/qIBU3lhPkWHGMYD9O2GU1YgcU.png)](https://asciinema.org/a/qIBU3lhPkWHGMYD9O2GU1YgcU?s=2&autoplay=1) 79 | 80 | ## Where to Go from Here 81 | 82 | While evaluator is a powerful tool, it does not attempt to address 83 | interactions between risk scenarios, rolling up multiple levels of risk 84 | into aggregations, or other advanced topics. As you become more 85 | comfortable with quantitative risk analysis, you may wish to dive deeper 86 | into these areas (and I hope you do!). The following resources may help 87 | you explore these and other topics in risk management. 88 | 89 | ### Alternative Software 90 | 91 | - [RiskLens](https://www.risklens.com), a commercial analysis suite, 92 | founded by the original creator of the FAIR methodology 93 | - [FAIR Tool](https://github.com/zugo01/FAIRTool), a Shiny and R based 94 | two scenario simulator, authored by Ezeugo Aguta under an MIT 95 | license 96 | - [FAIR-U](https://www.fairinstitute.org/fair-u), a free educational 97 | tool for learning FAIR analysis, powered by RiskLens 98 | - [Open FAIR Risk Analysis 99 | Tool](https://publications.opengroup.org/i181), an Excel and SIPMath 100 | base tool with a limited open license 101 | 102 | ### Blogs/Books/Training 103 | 104 | - Russell C. Thomas’s excellent and provocative blog post on systemic 105 | [Risk 106 | Management](https://exploringpossibilityspace.blogspot.com/2013/08/risk-management-out-with-old-in-with-new.html) 107 | - [Measuring and Managing Information 108 | Risk](https://smile.amazon.com/gp/product/0124202314) 109 | - [OpenFAIR 110 | certification](https://www.opengroup.org/certifications/openfair) 111 | - [Hubbard Decision Research calibration 112 | training](https://hubbardresearch.com/training/) 113 | 114 | ### Associations 115 | 116 | - [FAIR Institute](https://www.fairinstitute.org) 117 | - [Society of Information Risk Analysts 118 | (SIRA)](https://www.societyinforisk.org/) 119 | 120 | ## Contributing 121 | 122 | This project is governed by a [Code of 123 | Conduct](https://evaluator.tidyrisk.org/CODE_OF_CONDUCT.html). By 124 | participating in this project you agree to abide by these terms. 125 | 126 | ## License 127 | 128 | The [MIT License](LICENSE) applies. 129 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://evaluator.tidyrisk.org 2 | 3 | template: 4 | params: 5 | bootswatch: flatly 6 | ganalytics: UA-87348339-3 7 | 8 | navbar: 9 | left: 10 | - icon: fa-home fa-lg 11 | href: index.html 12 | - text: "Geting Started" 13 | href: articles/usage.html 14 | - text: "Reference" 15 | href: reference/index.html 16 | - text: "Articles" 17 | menu: 18 | - text: "Advanced Customization" 19 | href: articles/customization.html 20 | - text: "Process" 21 | href: articles/process.html 22 | - text: Presentations 23 | menu: 24 | - text: "Tidyrisk Training Workshop" 25 | href: https://www.slideshare.net/davidski1/tidyrisk-workshop 26 | - text: "SiRAcon 2018" 27 | href: https://www.slideshare.net/davidski1/evaluator-siracon-2018-presentation 28 | - text: "News" 29 | href: news/index.html 30 | right: 31 | - icon: fa-github fa-lg fab 32 | text: "github" 33 | href: https://github.com/davidski/evaluator/ 34 | 35 | reference: 36 | - title: Evaluator 37 | contents: 38 | - evaluator 39 | - title: Data Import and Cleansing Functions 40 | contents: 41 | - create_templates 42 | - derive_controls 43 | - encode_scenarios 44 | - starts_with("import") 45 | - read_qualitative_inputs 46 | - read_quantitative_inputs 47 | - openfair_example 48 | - split_sheet 49 | - validate_scenarios 50 | - title: Modelling Functions 51 | desc: OpenFAIR modelling components 52 | contents: 53 | - compare_tef_vuln 54 | - get_mean_control_strength 55 | - starts_with("openfair_") 56 | - run_simulation 57 | - run_simulations 58 | - starts_with("sample") 59 | - select_loss_opportunities 60 | - title: Reporting Functions 61 | contents: 62 | - starts_with("calculate") 63 | - derive_control_key 64 | - dollar_millions 65 | - explore_scenarios 66 | - exposure_histogram 67 | - starts_with("generate") 68 | - get_base_fontfamily 69 | - identify_outliers 70 | - loss_exceedance_curve 71 | - loss_scatterplot 72 | - risk_dashboard 73 | - theme_evaluator 74 | - title: Sample Data Set 75 | desc: Demonstration data set for the hypothetical MetroCare Hospital 76 | contents: 77 | - starts_with("mc_") 78 | - title: Summarization Functions 79 | contents: 80 | - starts_with("summarize") 81 | - title: Tidyrisk Scenario Class Functions 82 | contents: 83 | - contains("tidyrisk_scenario") 84 | - title: Tidyrisk Factor Class Functions 85 | contents: 86 | - contains("tidyrisk_factor") 87 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Update 2 | 3 | This is a minor update, removing some dependencies and substituting others 4 | with SUGGESTS when full removals could not easily be supported. This is in 5 | response to CRAN notices of incompatibility with a forthcoming knitr 6 | release. 7 | 8 | ## Test environments 9 | 10 | * local Windows 10 64 install, R 4.1 11 | * local OS X, R 4.1 12 | * OS X (via GitHub Actions), R-release 13 | * win-builder (R-devel and R-release) 14 | * R-Hub 15 | * "devian-gcc-devel-nold" - R-devel --enable-long-double=no 16 | * Windows (R-release and R-devel) 17 | * Linux (R-release and R-devel) 18 | 19 | ## R CMD check results 20 | 21 | * There are no NOTES, ERRORS, or WARNINGS. 22 | 23 | ## Downstream dependencies 24 | 25 | The `collector` package (also authored by me) depends on this package. 26 | `collector` is currently archived on CRAN, but a resubmission of this 27 | package is in process. 28 | -------------------------------------------------------------------------------- /data-raw/regenerate_data.R: -------------------------------------------------------------------------------- 1 | ## Regenerate sample data sets 2 | #library(evaluator) 3 | library(purrr) 4 | library(dplyr) 5 | library(future) 6 | plan(multiprocess) 7 | 8 | # read in and save domain mappings 9 | mc_domains <- readr::read_csv(here::here("inst/extdata/domains.csv"), 10 | col_types = readr::cols( 11 | domain_id = readr::col_character(), 12 | domain = readr::col_character() 13 | )) 14 | usethis::use_data(mc_domains, overwrite = TRUE) 15 | 16 | # read in capabilities 17 | mc_capabilities <- import_capabilities(domains = mc_domains) 18 | usethis::use_data(mc_capabilities, overwrite = TRUE) 19 | 20 | # read in mappings 21 | mc_mappings <- readr::read_csv(here::here("inst/extdata/qualitative_mappings.csv"), 22 | col_types = readr::cols( 23 | type = readr::col_character(), 24 | label = readr::col_character(), 25 | l = readr::col_double(), 26 | ml = readr::col_double(), 27 | h = readr::col_double(), 28 | conf = readr::col_double())) 29 | usethis::use_data(mc_mappings, overwrite = TRUE) 30 | 31 | # read in and save qualitative scenarios 32 | mc_qualitative_scenarios <- import_scenarios(domains = mc_domains) 33 | usethis::use_data(mc_qualitative_scenarios, overwrite = TRUE) 34 | 35 | # generate and save quantitative scenarios 36 | mc_quantitative_scenarios <- encode_scenarios( 37 | mc_qualitative_scenarios, mc_capabilities, mc_mappings) 38 | usethis::use_data(mc_quantitative_scenarios, overwrite = TRUE) 39 | 40 | # run simulations and save results 41 | mc_simulation_results <- mc_quantitative_scenarios %>% 42 | mutate(results = furrr::future_map(scenario, run_simulation, iterations = 1000, .progress = TRUE)) %>% 43 | select(-c(scenario, tcomm, scenario_description), scenario_id, domain_id, results) 44 | 45 | usethis::use_data(mc_simulation_results, overwrite = TRUE) 46 | 47 | # calculate and save domain summary 48 | mc_domain_summary <- summarize_domains(mc_simulation_results) 49 | usethis::use_data(mc_domain_summary, overwrite = TRUE) 50 | 51 | # calculate and save scenario summary 52 | #scenario_summary <- mutate(simulation_results, summary = map(results, summarize_scenario)) 53 | mc_scenario_summary <- summarize_scenarios(mc_simulation_results) 54 | usethis::use_data(mc_scenario_summary, overwrite = TRUE) 55 | -------------------------------------------------------------------------------- /data/mc_capabilities.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/data/mc_capabilities.rda -------------------------------------------------------------------------------- /data/mc_domain_summary.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/data/mc_domain_summary.rda -------------------------------------------------------------------------------- /data/mc_domains.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/data/mc_domains.rda -------------------------------------------------------------------------------- /data/mc_mappings.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/data/mc_mappings.rda -------------------------------------------------------------------------------- /data/mc_qualitative_scenarios.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/data/mc_qualitative_scenarios.rda -------------------------------------------------------------------------------- /data/mc_quantitative_scenarios.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/data/mc_quantitative_scenarios.rda -------------------------------------------------------------------------------- /data/mc_scenario_summary.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/data/mc_scenario_summary.rda -------------------------------------------------------------------------------- /data/mc_simulation_results.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/data/mc_simulation_results.rda -------------------------------------------------------------------------------- /evaluator.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | LineEndingConversion: Posix 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | Afer 2 | Aguta 3 | AppVeyor 4 | Arial 5 | BetaPERT 6 | CMM 7 | COBIT 8 | CONF 9 | CSF 10 | customizations 11 | deprecations 12 | dplyr 13 | DSS 14 | DT 15 | Ezeugo 16 | flexdashboard 17 | ggplot 18 | HITRUST 19 | https 20 | lef 21 | LEF 22 | lm 23 | LM 24 | MacBook 25 | MetroCare 26 | NIST 27 | ogsys 28 | OpenFAIR 29 | opengroup 30 | ORCID 31 | overridable 32 | pandoc 33 | PCI 34 | PLM 35 | pre 36 | rda 37 | rds 38 | reimport 39 | repo 40 | reproducability 41 | RiskLens 42 | rmarkdown 43 | Rmarkdown 44 | RMarkdown 45 | roxygen 46 | RPubs 47 | RStudio 48 | screencast 49 | shinytest 50 | severski 51 | signoff 52 | SIPMath 53 | SIRA 54 | SLE 55 | SLM 56 | statip 57 | subclasses 58 | summarization 59 | tc 60 | TCap 61 | tef 62 | TEF 63 | Tibble 64 | tibble 65 | tibbles 66 | tidyrisk 67 | tidyverse 68 | Unnest 69 | unnest 70 | VaR 71 | VeryLow 72 | vuln 73 | VULN 74 | www 75 | xlsx 76 | xM 77 | -------------------------------------------------------------------------------- /inst/explore_scenarios/tests/explore-scenarios.R: -------------------------------------------------------------------------------- 1 | app <- ShinyDriver$new("../explore_scenarios.Rmd", seed = 7767) 2 | #app <- ShinyDriver$new(here::here("inst/explore_scenarios/explore_scenarios.Rmd", seed = 7767) 3 | app$snapshotInit("explore-scenarios") 4 | 5 | app$snapshot() 6 | -------------------------------------------------------------------------------- /inst/extdata/domains.csv: -------------------------------------------------------------------------------- 1 | domain_id, domain 2 | ISMP, Information Security Management Program 3 | AC, Access Control 4 | HR, Human Resources Security 5 | RISK, Risk Management 6 | POL, Security Policy 7 | ORG, Organization of Information Security 8 | COMP, Compliance 9 | ASSET, Asset Management 10 | PHY, Physical and Environmental Security 11 | OPS, Communications and Operations Management 12 | ADM,"Information Systems Acquisition, Development, and Maintenance" 13 | IM, Information Security Incident Management 14 | BC, Business Continuity Management 15 | PRI, Privacy Practices -------------------------------------------------------------------------------- /inst/extdata/qualitative_mappings.csv: -------------------------------------------------------------------------------- 1 | type,label,l,ml,h,conf 2 | tef,frequent,10,24,52,4 3 | tef,occasional,1,6,12,4 4 | tef,rare,0,0.1,1,4 5 | tc,high,0.50,0.75,0.98,3 6 | tc,medium,0.33,0.50,0.60,3 7 | tc,low,0,0.16,0.30,4 8 | diff,5 - Optimized,0.70,0.85,0.98,4 9 | diff,4 - Managed,0.50,0.70,0.84,4 10 | diff,3 - Defined,0.33,0.50,0.60,4 11 | diff,2 - Repeatable,0.20,0.30,0.50,4 12 | diff,1 - Initial,0,0.10,0.30,4 13 | lm,high,1000000,5000000,16000000,4 14 | lm,medium,10000,20000,500000,4 15 | lm,low,100,200,10000,1 16 | -------------------------------------------------------------------------------- /inst/extdata/risk_tolerances.csv: -------------------------------------------------------------------------------- 1 | level,amount 2 | medium,10000000 3 | high,50000000 4 | -------------------------------------------------------------------------------- /inst/openfair_example/openfair_example.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "OpenFAIR Example" 3 | runtime: shiny 4 | output: 5 | flexdashboard::flex_dashboard: 6 | orientation: columns 7 | vertical_layout: fill 8 | source_code: embed 9 | navbar: 10 | - { title: "About", href: "https://evaluator.tidyrisk.org", align: right } 11 | --- 12 | 13 | ```{r setup, include=FALSE} 14 | library(dplyr) 15 | library(evaluator) 16 | library(flexdashboard) 17 | library(ggplot2) 18 | library(mc2d) 19 | library(scales) 20 | library(shiny) 21 | ``` 22 | 23 | ```{r common_functions, include=FALSE} 24 | ``` 25 | 26 | ```{r core_functions, include=FALSE} 27 | # determine the proper base font to use for graphs 28 | basefont <- get_base_fontfamily() 29 | 30 | values <- reactiveValues() 31 | 32 | values$iterations <- 1000 33 | 34 | observeEvent(input$runmodel, { 35 | 36 | values$iterations <- input$iterations 37 | 38 | TEFestimate <- list(func = "mc2d::rpert", min = input$tefl, 39 | mode = input$tefml, max = input$tefh, 40 | shape = input$tefconf) 41 | TCestimate <- list(func = "mc2d::rpert", min = input$tcapl, 42 | mode = input$tcapml, max = input$tcaph, 43 | shape = input$tcapconf) 44 | DIFFestimate <- list(list(func = "mc2d::rpert", min = input$csl, 45 | mode = input$csml, max = input$csh, 46 | shape = input$csconf)) 47 | LMestimate <- list(func = "mc2d::rpert", min = input$lml, 48 | mode = input$lmml, max = input$lmh, 49 | shape = input$lmconf) 50 | single_scen <- tidyrisk_scenario( 51 | tef_params = TEFestimate, 52 | tc_params = TCestimate, 53 | diff_params = DIFFestimate, 54 | lm_params = LMestimate) 55 | 56 | values$simulation_result <- run_simulation(single_scen, iterations = values$iterations) 57 | 58 | }) 59 | ``` 60 | 61 | Scenario Parameters {.sidebar data-width=400} 62 | ----------------------------------------------------------------------- 63 | 64 | ### TEF 65 | 66 | Frequency of action (events per year) by the actor. 67 | 68 | ```{r input_tef} 69 | fillRow(height = 50, 70 | numericInput("tefl", "Min:", 10, min = 0, max = 100), 71 | numericInput("tefml", "ML:", 20, min = 0, max = 100), 72 | numericInput("tefh", "Max:", 100, min = 0, max = 100), 73 | numericInput("tefconf", "Shape:", 1, min = 1, max = 5) 74 | ) 75 | ``` 76 | 77 | ### TC 78 | 79 | Capabilities (in %) of the threat actor. 80 | 81 | ```{r input_tcap} 82 | fillRow(height = 50, 83 | numericInput("tcapl", "Min:", .20, min = 0, max = 1, step = 0.01), 84 | numericInput("tcapml", "ML:", .30, min = 0, max = 1, step = 0.01), 85 | numericInput("tcaph", "Max:", .70, min = 0, max = 1, step = 0.01), 86 | numericInput("tcapconf", "Shape:", 1, min = 1, max = 5) 87 | ) 88 | ``` 89 | 90 | ### DIFF 91 | 92 | Difficulty (in %) presented by the controls. 93 | 94 | ```{r input_diff} 95 | fillRow(height = 50, 96 | numericInput("csl", "Min:", .40, min = 0, max = 1, step = 0.01), 97 | numericInput("csml", "ML:", .50, min = 0, max = 1, step = 0.01), 98 | numericInput("csh", "Max:", .60, min = 0, max = 1, step = 0.01), 99 | numericInput("csconf", "Shape:", 2, min = 1, max = 5) 100 | ) 101 | ``` 102 | 103 | ### LM 104 | 105 | Total losses (in $) for a single adverse event. 106 | 107 | ```{r input_lm} 108 | fillRow(height = 50, 109 | numericInput("lml", "Min:", 100, min = 0, step = 0.01), 110 | numericInput("lmml", "ML:", 500, min = 0, step = 0.01), 111 | numericInput("lmh", "Max:", 10000, min = 0, step = 0.01), 112 | numericInput("lmconf", "Shape:", 1, min = 1, max = 5) 113 | ) 114 | ``` 115 | 116 | ### Params {.no-title} 117 | 118 | ```{r} 119 | numericInput("iterations", "# Iterations:", 100, min = 10, max = 10000, 120 | step = 100) 121 | actionButton("runmodel", "Run Model") 122 | ``` 123 | 124 | Results {.tabset data-width=600} 125 | ---------------------------------------------------------------------- 126 | 127 | ### Loss Distribution 128 | 129 | ```{r plot_distribution} 130 | renderPlot({ 131 | if (input$runmodel != 0) { 132 | gg <- ggplot(values$simulation_result, aes(x = ale)) 133 | gg <- gg + geom_histogram(binwidth = diff(range(values$simulation_result$ale) / 50), 134 | aes(y = ..density..), 135 | color = "black", 136 | fill = "white") 137 | gg <- gg + geom_density(fill = "steelblue", alpha = 1/3) 138 | gg <- gg + scale_x_continuous(labels = comma) 139 | gg <- gg + labs(x = "Annual Expected Losses") 140 | gg <- gg + theme_evaluator(base_family = basefont) 141 | print(gg) 142 | } 143 | }) 144 | ``` 145 | 146 | ### Details 147 | 148 | #### Loss Summary {.no-title} 149 | 150 | ```{r detail1} 151 | renderPrint({ 152 | if (input$runmodel != 0) { 153 | print(summary(values$simulation_result$ale)) 154 | } 155 | }) 156 | ``` 157 | 158 | #### 95% Value at Risk {.no-title} 159 | 160 | ```{r detail2} 161 | renderText({ 162 | if (input$runmodel != 0) { 163 | VAR <- summarize_scenario(values$simulation_result) %>% pull(ale_var) 164 | print(paste0("Losses at 95th percentile are $", 165 | format(VAR, nsmall = 2, big.mark = ",") 166 | )) 167 | } 168 | }) 169 | ``` 170 | 171 | #### Scenario Result Summary {.no-title} 172 | 173 | ```{r detail3} 174 | renderTable({ 175 | if (input$runmodel != 0) { 176 | summarize_scenario(values$simulation_result) 177 | } 178 | }) 179 | ``` 180 | 181 | #### Loss Samples {data-height=200} 182 | 183 | ```{r detail4} 184 | DT::renderDataTable( 185 | if (input$runmodel != 0) { 186 | dat <- data.frame(Losses = values$simulation_result$ale) %>% 187 | arrange(desc(Losses)) %>% 188 | transmute(Losses = scales::dollar(Losses)) 189 | DT::datatable(dat, rownames = FALSE) 190 | } 191 | ) 192 | ``` 193 | 194 | ### Event Distribution 195 | 196 | ```{r loss_events} 197 | renderPlot({ 198 | if (input$runmodel != 0) { 199 | VULNsamples <- values$simulation_result %>% 200 | summarize(loss_events = sum(loss_events, na.rm = TRUE), 201 | avoided_events = sum(threat_events, na.rm = TRUE) - loss_events) %>% 202 | tidyr::gather("key", "value", loss_events, avoided_events) %>% 203 | mutate(value = value / sum(value, na.rm = TRUE)) 204 | gg <- ggplot(VULNsamples, aes(x = key, y = value)) + 205 | geom_col(fill = "steelblue") + 206 | labs(x = "Event Type", y = "Percent") + 207 | scale_y_continuous(labels = scales::percent) + 208 | theme_evaluator(base_family = evaluator::get_base_fontfamily()) 209 | print(gg) 210 | } 211 | }) 212 | ``` 213 | -------------------------------------------------------------------------------- /inst/openfair_example/tests/openfair_example-expected/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/inst/openfair_example/tests/openfair_example-expected/001.png -------------------------------------------------------------------------------- /inst/openfair_example/tests/openfair_example.R: -------------------------------------------------------------------------------- 1 | app <- ShinyDriver$new("../openfair_example.Rmd", seed = 95592) 2 | app$snapshotInit("openfair_example") 3 | 4 | app$setInputs(tefml = character(0)) 5 | app$setInputs(tefml = 30) 6 | app$setInputs(iterations = 100) 7 | app$setInputs(runmodel = "click") 8 | app$snapshot() 9 | -------------------------------------------------------------------------------- /inst/rmd/img/evaluator_hex_48px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/inst/rmd/img/evaluator_hex_48px.png -------------------------------------------------------------------------------- /inst/rmd/open-sans-import.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /inst/rmd/styles/html-styles.css: -------------------------------------------------------------------------------- 1 | p { 2 | font-family: Open Sans, sans-serif; 3 | } 4 | 5 | ul li { 6 | font-family: Open Sans, sans-serif; 7 | } 8 | 9 | ol li { 10 | font-family: Open Sans, sans-serif; 11 | } 12 | 13 | 14 | h1 { 15 | font-family: Open Sans Condensed, sans-serif; 16 | color: #430098; 17 | } 18 | 19 | h2, h3, h4, h5, h6 { 20 | font-family: Open Sans Condensed, sans-serif; 21 | color: #7C858C; 22 | } 23 | 24 | a { 25 | color: #6e5baa; 26 | } 27 | 28 | p { 29 | color: #333D47; 30 | } 31 | 32 | body { 33 | font-family: Open Sans, sans-serif; 34 | color: #333D47; 35 | } 36 | 37 | /* flexdashboard styles */ 38 | .section.sidebar { 39 | top: 51px; 40 | background-color: #C3C5C8; 41 | } 42 | 43 | .bg-danger { 44 | background-color: #d60057; 45 | } 46 | 47 | .bg-warning { 48 | background-color: #c227b9; 49 | } 50 | 51 | .bg-primary { 52 | color: #fff; 53 | background-color: #00a1df; 54 | } 55 | 56 | 57 | .navbar-inverse { 58 | background-color: #211746; 59 | border-color: #1967be; 60 | } 61 | .navbar-inverse .navbar-brand { 62 | color: #ffffff; 63 | } 64 | .navbar-inverse .navbar-brand:hover, 65 | .navbar-inverse .navbar-brand:focus { 66 | color: #ffffff; 67 | background-color: none; 68 | } 69 | .navbar-inverse .navbar-text { 70 | color: #ffffff; 71 | } 72 | .navbar-inverse .navbar-nav > li > a { 73 | color: #ffffff; 74 | } 75 | .navbar-inverse .navbar-nav > li > a:hover, 76 | .navbar-inverse .navbar-nav > li > a:focus { 77 | color: #ffffff; 78 | background-color: #00a1df; 79 | } 80 | .navbar-inverse .navbar-nav > .active > a, 81 | .navbar-inverse .navbar-nav > .active > a:hover, 82 | .navbar-inverse .navbar-nav > .active > a:focus { 83 | color: #ffffff; 84 | background-color: #00a1df; 85 | } 86 | .navbar-inverse .navbar-nav > .disabled > a, 87 | .navbar-inverse .navbar-nav > .disabled > a:hover, 88 | .navbar-inverse .navbar-nav > .disabled > a:focus { 89 | color: #ffffff; 90 | background-color: transparent; 91 | } 92 | .navbar-inverse .navbar-toggle { 93 | border-color: transparent; 94 | } 95 | .navbar-inverse .navbar-toggle:hover, 96 | .navbar-inverse .navbar-toggle:focus { 97 | background-color: #00a1df; 98 | } 99 | .navbar-inverse .navbar-toggle .icon-bar { 100 | background-color: #ffffff; 101 | } 102 | .navbar-inverse .navbar-collapse, 103 | .navbar-inverse .navbar-form { 104 | border-color: #1a6ecc; 105 | } 106 | .navbar-inverse .navbar-nav > .open > a, 107 | .navbar-inverse .navbar-nav > .open > a:hover, 108 | .navbar-inverse .navbar-nav > .open > a:focus { 109 | background-color: #00a1df; 110 | color: #ffffff; 111 | } 112 | @media (max-width: 767px) { 113 | .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { 114 | border-color: #00a1df; 115 | } 116 | .navbar-inverse .navbar-nav .open .dropdown-menu .divider { 117 | background-color: #00a1df; 118 | } 119 | .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { 120 | color: #ffffff; 121 | } 122 | .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, 123 | .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { 124 | color: #ffffff; 125 | background-color: #00a1df; 126 | } 127 | .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, 128 | .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, 129 | .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { 130 | color: #ffffff; 131 | background-color: #00a1df; 132 | } 133 | .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, 134 | .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, 135 | .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { 136 | color: #ffffff; 137 | background-color: transparent; 138 | } 139 | } 140 | .navbar-inverse .navbar-link { 141 | color: #ffffff; 142 | } 143 | .navbar-inverse .navbar-link:hover { 144 | color: #ffffff; 145 | } 146 | .navbar-inverse .btn-link { 147 | color: #ffffff; 148 | } 149 | .navbar-inverse .btn-link:hover, 150 | .navbar-inverse .btn-link:focus { 151 | color: #ffffff; 152 | } 153 | .navbar-inverse .btn-link[disabled]:hover, 154 | fieldset[disabled] .navbar-inverse .btn-link:hover, 155 | .navbar-inverse .btn-link[disabled]:focus, 156 | fieldset[disabled] .navbar-inverse .btn-link:focus { 157 | color: #ffffff; 158 | } 159 | -------------------------------------------------------------------------------- /inst/rmd/styles/open-sans-import.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /inst/rmd/styles/word-styles-reference.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/inst/rmd/styles/word-styles-reference.docx -------------------------------------------------------------------------------- /inst/rstudio/addins.dcf: -------------------------------------------------------------------------------- 1 | Name: Create Tidyrisk Scenario 2 | Description: Insert the skeleton for a tidyrisk scenario in the current document 3 | Binding: create_tidyrisk_scenario_skeleton 4 | Interactive: false 5 | -------------------------------------------------------------------------------- /inst/run_analysis.R: -------------------------------------------------------------------------------- 1 | # Quick Start script for Evaluator workflow 2 | # Process documented at https://evaluator.tidyrisk.org/articles/usage.html 3 | 4 | # This script is intended as a starting point for taking a directory of 5 | # inputs as created by evaluator::create_templates(), running simulations, 6 | # saving the result details & summary files, and preparing the default static 7 | # reports. The analyst MUST edit the template input files before running 8 | # this script to produce valid results. 9 | 10 | # Committing this script, along with the other contents of the base evaluator 11 | # directory, to source control provides a reproducable set of inputs & outputs 12 | # for a single analysis. 13 | 14 | # Setup ------------------------------------------------------------------- 15 | library(evaluator) 16 | library(readr) 17 | library(purrr) 18 | library(dplyr) 19 | library(furrr) 20 | plan(multiprocess) 21 | 22 | if (!exists("base_dir") || !dir.exists(base_dir)) { 23 | stop("Set base_dir to your evaluator working directory before running this script.") 24 | } 25 | 26 | inputs_dir <- file.path(base_dir, "inputs") 27 | results_dir <- file.path(base_dir, "results") 28 | 29 | message("Beginning analysis run with input directory (", inputs_dir, ")", 30 | " and results directory (", results_dir, ")...") 31 | 32 | # Load and Validate ------------------------------------------------------- 33 | message("Loading and validating inputs...") 34 | 35 | domains <- read_csv(file.path(inputs_dir, "domains.csv"), 36 | col_types = cols(.default = col_character())) 37 | import_spreadsheet(file.path(inputs_dir, "survey.xlsx"), domains, inputs_dir) 38 | 39 | qual_inputs <- read_qualitative_inputs(inputs_dir) 40 | qualitative_scenarios <- qual_inputs$qualitative_scenarios 41 | mappings <- qual_inputs$mappings 42 | capabilities <- qual_inputs$capabilities 43 | validate_scenarios(qualitative_scenarios, capabilities, domains, mappings) 44 | 45 | # Encode ------------------------------------------------------------------ 46 | message("Encoding qualitative scenarios...") 47 | quantitative_scenarios <- encode_scenarios(qualitative_scenarios, capabilities, 48 | mappings) 49 | saveRDS(quantitative_scenarios, 50 | file = file.path(inputs_dir, "quantitative_scenarios.rds")) 51 | 52 | # Simulate ---------------------------------------------------------------- 53 | message("Running simulations...") 54 | simulation_results <- quantitative_scenarios %>% 55 | mutate(results = furrr::future_map(scenario, run_simulation, 56 | iterations = 10000L, .progress = TRUE)) %>% 57 | select(-c(scenario, tcomm, scenario_description), scenario_id, domain_id, results) 58 | saveRDS(simulation_results, file = file.path(results_dir, "simulation_results.rds")) 59 | 60 | # Summarize --------------------------------------------------------------- 61 | message("Summarizing results...") 62 | summarize_to_disk(simulation_results = simulation_results, results_dir) 63 | 64 | # Report --------------------------------------------------------------- 65 | message("Generating reports...") 66 | 67 | ## Risk Dashboard 68 | risk_dashboard(inputs_dir, results_dir, 69 | file.path(results_dir, "risk_dashboard.html")) 70 | 71 | ## Long Form Report 72 | generate_report(inputs_dir, results_dir, 73 | file.path(results_dir, "risk_report.docx"), 74 | format = "word") 75 | 76 | message("Analysis complete.") 77 | -------------------------------------------------------------------------------- /inst/survey/survey.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/inst/survey/survey.xlsx -------------------------------------------------------------------------------- /man/as_tibble.tidyrisk_scenario.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidyrisk_scenario.R 3 | \name{as_tibble.tidyrisk_scenario} 4 | \alias{as_tibble.tidyrisk_scenario} 5 | \alias{as.data.frame.tidyrisk_scenario} 6 | \title{Coerce the parameters of a tidyrisk_scenario to a tibble} 7 | \usage{ 8 | \method{as_tibble}{tidyrisk_scenario}(x, ...) 9 | 10 | \method{as.data.frame}{tidyrisk_scenario}(x, ...) 11 | } 12 | \arguments{ 13 | \item{x}{A tidyrisk_scenario} 14 | 15 | \item{...}{Currently not used} 16 | } 17 | \description{ 18 | Coerce the parameters of a tidyrisk_scenario to a tibble 19 | } 20 | -------------------------------------------------------------------------------- /man/calculate_max_losses.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{calculate_max_losses} 4 | \alias{calculate_max_losses} 5 | \title{Calculate maximum losses} 6 | \usage{ 7 | calculate_max_losses(simulation_results, scenario_outliers = NULL) 8 | } 9 | \arguments{ 10 | \item{simulation_results}{Simulation results dataframe.} 11 | 12 | \item{scenario_outliers}{Optional vector of IDs of outlier scenarios.} 13 | } 14 | \value{ 15 | A dataframe with the following columns: 16 | \itemize{ 17 | \item \code{iteration} - index of the iteration 18 | \item \code{biggest_single_scenario_loss} - the biggest annual loss in that iteration, 19 | \item \code{min_loss} - the smallest annual loss in that iteration, 20 | \item \code{max_loss} - the total annual losses in that iteration 21 | \item \code{outliers} - logical of whether or not outliers are included 22 | } 23 | } 24 | \description{ 25 | Calculate the biggest single annual loss for each scenario, as well as 26 | the minimum and maximum ALE across all iterations. Calculations both 27 | with and without outliers (if passed) are returned. 28 | } 29 | \examples{ 30 | data(mc_simulation_results) 31 | calculate_max_losses(mc_simulation_results) 32 | } 33 | -------------------------------------------------------------------------------- /man/compare_tef_vuln.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/openfair.R 3 | \name{compare_tef_vuln} 4 | \alias{compare_tef_vuln} 5 | \title{Calculate number of loss events which occur in a simulated period} 6 | \usage{ 7 | compare_tef_vuln(tef, vuln, n = NULL) 8 | } 9 | \arguments{ 10 | \item{tef}{Threat event frequency (n).} 11 | 12 | \item{vuln}{Vulnerability (percentage).} 13 | 14 | \item{n}{Number of samples to generate.} 15 | } 16 | \value{ 17 | List containing samples (as a vector) and details (as a list). 18 | } 19 | \description{ 20 | Composition function for use in \code{\link{sample_lef}}. Given a count of 21 | the number of threat events (TEF) and the level of vulnerability (as a 22 | percentage), calculate how many of those become loss events (LEF). 23 | } 24 | \examples{ 25 | compare_tef_vuln(tef = 500, vuln = .25) 26 | } 27 | \seealso{ 28 | Other OpenFAIR helpers: 29 | \code{\link{get_mean_control_strength}()}, 30 | \code{\link{openfair_tef_tc_diff_lm}()}, 31 | \code{\link{sample_diff}()}, 32 | \code{\link{sample_lef}()}, 33 | \code{\link{sample_lm}()}, 34 | \code{\link{sample_tc}()}, 35 | \code{\link{sample_vuln}()}, 36 | \code{\link{select_loss_opportunities}()} 37 | } 38 | \concept{OpenFAIR helpers} 39 | -------------------------------------------------------------------------------- /man/create_templates.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/load_data.R 3 | \name{create_templates} 4 | \alias{create_templates} 5 | \title{Create a directory structure for risk analysis, pre-populated with templates} 6 | \usage{ 7 | create_templates(base_directory) 8 | } 9 | \arguments{ 10 | \item{base_directory}{Parent directory under which to create starter files.} 11 | } 12 | \value{ 13 | A dataframe of the starter filenames, along with a flag on whether a file was copied. 14 | } 15 | \description{ 16 | Copy the sample files into an \code{inputs} subdirectory. This makes the starter 17 | files available for customizing and data collection. The \code{inputs} 18 | directory will be created if not already present. Preexisting files, if 19 | present, will not be overwritten. Also creates an empty \code{results} 20 | subdirectory as a default location for evaluator output. 21 | } 22 | \examples{ 23 | \dontrun{ 24 | create_templates("~/evaluator") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /man/create_tidyrisk_scenario_skeleton.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/create_tidyrisk_skeleton.R 3 | \name{create_tidyrisk_scenario_skeleton} 4 | \alias{create_tidyrisk_scenario_skeleton} 5 | \title{Create a skeleton tidyrisk scenario object in the current document} 6 | \usage{ 7 | create_tidyrisk_scenario_skeleton() 8 | } 9 | \description{ 10 | Inserts a code block into the active document in RStudio for creating a 11 | \link{tidyrisk_scenario} object. This is an easy way of rapidly running 12 | a simulation. 13 | } 14 | -------------------------------------------------------------------------------- /man/derive_control_key.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/encode.R 3 | \name{derive_control_key} 4 | \alias{derive_control_key} 5 | \title{Derive control ID to control description mappings} 6 | \usage{ 7 | derive_control_key(capability_ids, capabilities) 8 | } 9 | \arguments{ 10 | \item{capability_ids}{Comma-delimited list of capabilities in scope for a scenario.} 11 | 12 | \item{capabilities}{Dataframe of master list of all qualitative capabilities.} 13 | } 14 | \value{ 15 | A named list of control IDs and descriptions. 16 | } 17 | \description{ 18 | Given a comma-separated list of control IDs, return a named list 19 | of descriptions for each control with the names set to the control 20 | IDs. 21 | } 22 | \examples{ 23 | data(mc_capabilities) 24 | capability_ids <- c("CAP-01", "CAP-03") 25 | derive_control_key(capability_ids, mc_capabilities) 26 | } 27 | -------------------------------------------------------------------------------- /man/derive_controls.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/encode.R 3 | \name{derive_controls} 4 | \alias{derive_controls} 5 | \title{Derive control difficulty parameters for a given qualitative scenario} 6 | \usage{ 7 | derive_controls(capability_ids, capabilities, mappings) 8 | } 9 | \arguments{ 10 | \item{capability_ids}{Comma-delimited list of capabilities in scope for a scenario.} 11 | 12 | \item{capabilities}{Dataframe of master list of all qualitative capabilities.} 13 | 14 | \item{mappings}{Qualitative mappings dataframe.} 15 | } 16 | \value{ 17 | A named list of quantitative estimate parameters for the capabilities 18 | applicable to a given scenario. 19 | } 20 | \description{ 21 | Given a comma-separated list of control IDs in a scenario, identify 22 | the qualitative rankings associated with each scenario, convert to 23 | their quantitative parameters, and return a dataframe of the set of 24 | parameters. 25 | } 26 | \examples{ 27 | data(mc_capabilities) 28 | capability_ids <- c("1, 3") 29 | mappings <- data.frame(type = "diff", label = "1 - Immature", l = 0, ml = 2, h = 10, 30 | conf = 3, stringsAsFactors = FALSE) 31 | derive_controls(capability_ids, mc_capabilities, mappings) 32 | } 33 | -------------------------------------------------------------------------------- /man/dollar_millions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{dollar_millions} 4 | \alias{dollar_millions} 5 | \title{Format dollar amounts in terms of millions of USD} 6 | \usage{ 7 | dollar_millions(x) 8 | } 9 | \arguments{ 10 | \item{x}{A number.} 11 | } 12 | \value{ 13 | String in the format of $xM. 14 | } 15 | \description{ 16 | Given a number, return a string formatted in terms of millions of dollars. 17 | } 18 | \examples{ 19 | dollar_millions(1.523 * 10^6) 20 | } 21 | -------------------------------------------------------------------------------- /man/encode_scenarios.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/encode.R 3 | \name{encode_scenarios} 4 | \alias{encode_scenarios} 5 | \title{Encode qualitative data to quantitative parameters} 6 | \usage{ 7 | encode_scenarios(scenarios, capabilities, mappings) 8 | } 9 | \arguments{ 10 | \item{scenarios}{Qualitative risk scenarios dataframe.} 11 | 12 | \item{capabilities}{Qualitative program capabilities dataframe.} 13 | 14 | \item{mappings}{Qualitative to quantitative mapping dataframe.} 15 | } 16 | \value{ 17 | A dataframe of capabilities for the scenario and parameters for quantified simulation. 18 | } 19 | \description{ 20 | Given an input of: 21 | \itemize{ 22 | \item qualitative risk scenarios 23 | \item qualitative capabilities 24 | \item translation table from qualitative labels to quantitative parameters 25 | } 26 | } 27 | \details{ 28 | Create a unified dataframe of quantitative scenarios ready for simulation. 29 | } 30 | \examples{ 31 | data(mc_qualitative_scenarios, mc_capabilities, mc_mappings) 32 | encode_scenarios(mc_qualitative_scenarios, mc_capabilities, mc_mappings) 33 | } 34 | -------------------------------------------------------------------------------- /man/evaluator-deprecated.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/common_graphs.R, R/evaluator-deprecated.R, 3 | % R/load_data.R 4 | \name{generate_scatterplot} 5 | \alias{generate_scatterplot} 6 | \alias{evaluator-deprecated} 7 | \alias{load_data} 8 | \title{Deprecated functions in package \pkg{evaluator}.} 9 | \usage{ 10 | generate_scatterplot(simulation_results, scenario_id) 11 | 12 | load_data( 13 | input_directory = "~/evaluator/inputs", 14 | results_directory = "~/evaluator/results" 15 | ) 16 | } 17 | \description{ 18 | The functions listed below are deprecated and will be defunct in 19 | the near future. When possible, alternative functions with similar 20 | functionality are also mentioned. Help pages for deprecated functions are 21 | available at \code{help("-deprecated")}. 22 | } 23 | \section{\code{generate_scatterplot}}{ 24 | 25 | Instead of \code{generate_scatterplot}, use \code{\link{loss_scatterplot}}. 26 | } 27 | 28 | \section{\code{load_data}}{ 29 | 30 | Instead of \code{load_data}, use \code{\link{read_quantitative_inputs}} 31 | and \code{\link{read_qualitative_inputs}} as appropriate. 32 | } 33 | 34 | \keyword{internal} 35 | -------------------------------------------------------------------------------- /man/evaluator-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/evaluator-package.R 3 | \docType{package} 4 | \name{evaluator-package} 5 | \alias{evaluator} 6 | \alias{evaluator-package} 7 | \title{evaluator: Quantified Risk Assessment Toolkit} 8 | \description{ 9 | \if{html}{\figure{logo.png}{options: align='right' alt='logo' width='120'}} 10 | 11 | An open source risk analysis toolkit based on the OpenFAIR ontology and risk analysis standard . Empowers an organization to perform a quantifiable, repeatable, and data-driven risk review. 12 | } 13 | \seealso{ 14 | Useful links: 15 | \itemize{ 16 | \item \url{https://evaluator.tidyrisk.org} 17 | \item Report bugs at \url{https://github.com/davidski/evaluator/issues} 18 | } 19 | 20 | } 21 | \author{ 22 | \strong{Maintainer}: David Severski \email{davidski@deadheaven.com} (\href{https://orcid.org/0000-0001-7867-0459}{ORCID}) 23 | 24 | } 25 | \keyword{internal} 26 | -------------------------------------------------------------------------------- /man/explore_scenarios.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/report.R 3 | \name{explore_scenarios} 4 | \alias{explore_scenarios} 5 | \title{Launch the Scenario Explorer web application} 6 | \usage{ 7 | explore_scenarios( 8 | input_directory = "~/evaluator/inputs", 9 | results_directory = "~/evaluator/results", 10 | styles = NULL, 11 | intermediates_dir = tempdir(), 12 | quiet = TRUE, 13 | ... 14 | ) 15 | } 16 | \arguments{ 17 | \item{input_directory}{Location of input files to be read by \code{\link{read_quantitative_inputs}}.} 18 | 19 | \item{results_directory}{Directory where the \code{simulations_results.rds} file is stored.} 20 | 21 | \item{styles}{Optional full path to CSS file to override default styles.} 22 | 23 | \item{intermediates_dir}{Location for intermediate knit files.} 24 | 25 | \item{quiet}{\code{TRUE} to suppress printing of pandoc output.} 26 | 27 | \item{...}{Any other parameters to pass to \code{rmarkdown::run}.} 28 | } 29 | \value{ 30 | Invisible NULL. 31 | } 32 | \description{ 33 | Evaluator provides a simple Shiny-based web application for interactive 34 | exploration of simulation results. This allows a user to interactively 35 | review simulation output without generating an extensive report. For users 36 | comfortable with R, working directly with the result dataframes will usually 37 | be preferable, with the Explorer application provided as a bare-bones data 38 | exploration tool. 39 | } 40 | \examples{ 41 | \dontrun{ 42 | explore_scenarios("~/inputs", "~/results") 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /man/exposure_histogram.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/common_graphs.R 3 | \name{exposure_histogram} 4 | \alias{exposure_histogram} 5 | \title{Display a histogram of losses for a scenario} 6 | \usage{ 7 | exposure_histogram(simulation_result, bins = 30, show_var_95 = FALSE) 8 | } 9 | \arguments{ 10 | \item{simulation_result}{Simulation result from \code{run_simulation}.} 11 | 12 | \item{bins}{Number of bins to use for the histogram.} 13 | 14 | \item{show_var_95}{Set to TRUE to show the 95 percentile value at risk line.} 15 | } 16 | \value{ 17 | A ggplot object. 18 | } 19 | \description{ 20 | Given a results dataframe for a specific scenario, create a histogram of 21 | the annualized loss exposure. This provides a detailed view on the results 22 | for a particular scenario. 23 | } 24 | \examples{ 25 | data(mc_simulation_results) 26 | result <- mc_simulation_results$results[[1]] 27 | exposure_histogram(result) 28 | } 29 | \seealso{ 30 | Other result graphs: 31 | \code{\link{generate_event_outcomes_plot}()}, 32 | \code{\link{generate_heatmap}()}, 33 | \code{\link{generate_scatterplot-deprecated}}, 34 | \code{\link{loss_exceedance_curve}()}, 35 | \code{\link{loss_scatterplot}()} 36 | } 37 | \concept{result graphs} 38 | -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/man/figures/logo.png -------------------------------------------------------------------------------- /man/generate_event_outcomes_plot.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/common_graphs.R 3 | \name{generate_event_outcomes_plot} 4 | \alias{generate_event_outcomes_plot} 5 | \title{Display the distribution of threat events contained vs. realized across 6 | all domains} 7 | \usage{ 8 | generate_event_outcomes_plot(domain_summary, domain_id = domain_id) 9 | } 10 | \arguments{ 11 | \item{domain_summary}{Domain-level summary from \code{domain_summary}.} 12 | 13 | \item{domain_id}{Variable to group plot by.} 14 | } 15 | \value{ 16 | A ggplot object. 17 | } 18 | \description{ 19 | Creates a barbell plot showing the number and percentage of events 20 | contained (not resulting in loss) vs the number and percentage of 21 | loss events (threat events resulting in losses). 22 | } 23 | \examples{ 24 | data(mc_domain_summary) 25 | generate_event_outcomes_plot(mc_domain_summary) 26 | } 27 | \seealso{ 28 | Other result graphs: 29 | \code{\link{exposure_histogram}()}, 30 | \code{\link{generate_heatmap}()}, 31 | \code{\link{generate_scatterplot-deprecated}}, 32 | \code{\link{loss_exceedance_curve}()}, 33 | \code{\link{loss_scatterplot}()} 34 | } 35 | \concept{result graphs} 36 | -------------------------------------------------------------------------------- /man/generate_heatmap.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/common_graphs.R 3 | \name{generate_heatmap} 4 | \alias{generate_heatmap} 5 | \title{Display a heatmap of impact by domain} 6 | \usage{ 7 | generate_heatmap(domain_summary) 8 | } 9 | \arguments{ 10 | \item{domain_summary}{Simulations summarized at a domain level via \code{summarize_domains}.} 11 | } 12 | \value{ 13 | A ggplot object. 14 | } 15 | \description{ 16 | Given a domain_summary and a list of all domains, generate a heatmap colored 17 | by the 95\% VaR. This plot displays the domains in which aggregate risk is 18 | greater than others. 19 | } 20 | \examples{ 21 | data(mc_domain_summary) 22 | generate_heatmap(mc_domain_summary) 23 | } 24 | \seealso{ 25 | Other result graphs: 26 | \code{\link{exposure_histogram}()}, 27 | \code{\link{generate_event_outcomes_plot}()}, 28 | \code{\link{generate_scatterplot-deprecated}}, 29 | \code{\link{loss_exceedance_curve}()}, 30 | \code{\link{loss_scatterplot}()} 31 | } 32 | \concept{result graphs} 33 | -------------------------------------------------------------------------------- /man/generate_report.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/report.R 3 | \name{generate_report} 4 | \alias{generate_report} 5 | \title{Generate sample analysis report} 6 | \usage{ 7 | generate_report( 8 | input_directory = "~/evaluator/inputs", 9 | results_directory = "~/evaluator/results", 10 | output_file, 11 | styles = NULL, 12 | include_header = NULL, 13 | focus_scenario_ids = c("RS-51", "RS-12"), 14 | format = "html", 15 | intermediates_dir = tempdir(), 16 | quiet = TRUE, 17 | ... 18 | ) 19 | } 20 | \arguments{ 21 | \item{input_directory}{Location of input files.} 22 | 23 | \item{results_directory}{Location of simulation results.} 24 | 25 | \item{output_file}{Full path to output file.} 26 | 27 | \item{styles}{Optional full path to CSS file to override default styles.} 28 | 29 | \item{include_header}{Optional full path to HTML to include in the HEAD section (HTML formats only).} 30 | 31 | \item{focus_scenario_ids}{IDs of scenarios of special interest.} 32 | 33 | \item{format}{Format to generate (html, pdf, word).} 34 | 35 | \item{intermediates_dir}{Location for intermediate knit files.} 36 | 37 | \item{quiet}{\code{TRUE} to suppress printing of pandoc output.} 38 | 39 | \item{...}{Any other parameters to pass straight to \code{rmarkdown::render}.} 40 | } 41 | \value{ 42 | Default return values of the \code{rmarkdown::render} function. 43 | } 44 | \description{ 45 | Given a set of input files and summarized simulation results, create a 46 | skeleton risk analysis report. This report attempts to summarize the results 47 | of the analysis at a top level, using 95\% Value at Risk (VaR) as the primary 48 | metric, while also providing more detailed analysis at both a per-domain and 49 | per-scenario level. 50 | } 51 | \details{ 52 | This report includes several sections where an analyst will need to modify and 53 | fill in details for their specific organization. Of particular note is the 54 | Recommendations section, which will always need to be updated. 55 | } 56 | \examples{ 57 | \dontrun{ 58 | generate_report("~/inputs", "~/results", "~/risk_report.html") 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /man/generate_scatterplot-deprecated.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/common_graphs.R 3 | \name{generate_scatterplot-deprecated} 4 | \alias{generate_scatterplot-deprecated} 5 | \title{Display a scatterplot for a particular scenario ID} 6 | \arguments{ 7 | \item{simulation_results}{Simulation results from \code{run_simulations}.} 8 | 9 | \item{scenario_id}{ID of the scenario to display.} 10 | } 11 | \value{ 12 | A ggplot object. 13 | } 14 | \description{ 15 | Given a detailed results dataframe and a specific scenario identifier, 16 | create a scatterplot of the number of loss events versus the total amount of 17 | expected annual loss expected for each simulation. This provides a 18 | detailed view on the results for a particular scenario. 19 | } 20 | \examples{ 21 | \dontrun{ 22 | data(mc_simulation_results) 23 | generate_scatterplot(mc_simulation_results, scenario_id = "RS-50") 24 | } 25 | } 26 | \seealso{ 27 | \code{\link{evaluator-deprecated}} 28 | 29 | Other result graphs: 30 | \code{\link{exposure_histogram}()}, 31 | \code{\link{generate_event_outcomes_plot}()}, 32 | \code{\link{generate_heatmap}()}, 33 | \code{\link{loss_exceedance_curve}()}, 34 | \code{\link{loss_scatterplot}()} 35 | } 36 | \concept{result graphs} 37 | \keyword{internal} 38 | -------------------------------------------------------------------------------- /man/get_base_fontfamily.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/common_graphs.R 3 | \name{get_base_fontfamily} 4 | \alias{get_base_fontfamily} 5 | \title{Select a base graphics font family} 6 | \usage{ 7 | get_base_fontfamily() 8 | } 9 | \value{ 10 | String of the preferred base font. 11 | } 12 | \description{ 13 | The Arial Narrow font is preferred. If not available, use a default \code{sans} 14 | family font. 15 | } 16 | \examples{ 17 | get_base_fontfamily() 18 | } 19 | -------------------------------------------------------------------------------- /man/get_mean_control_strength.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/openfair.R 3 | \name{get_mean_control_strength} 4 | \alias{get_mean_control_strength} 5 | \title{Calculate difficulty strength across multiple controls by taking the mean} 6 | \usage{ 7 | get_mean_control_strength(n, diff_parameters) 8 | } 9 | \arguments{ 10 | \item{n}{Number of threat events to generate control effectiveness samples.} 11 | 12 | \item{diff_parameters}{Parameters to pass to \code{\link{sample_diff}}.} 13 | } 14 | \value{ 15 | Vector of control effectiveness. 16 | } 17 | \description{ 18 | Given a set of estimation parameters, calculate control strength as the 19 | arithmetic mean of sampled control effectiveness. 20 | } 21 | \seealso{ 22 | Other OpenFAIR helpers: 23 | \code{\link{compare_tef_vuln}()}, 24 | \code{\link{openfair_tef_tc_diff_lm}()}, 25 | \code{\link{sample_diff}()}, 26 | \code{\link{sample_lef}()}, 27 | \code{\link{sample_lm}()}, 28 | \code{\link{sample_tc}()}, 29 | \code{\link{sample_vuln}()}, 30 | \code{\link{select_loss_opportunities}()} 31 | } 32 | \concept{OpenFAIR helpers} 33 | -------------------------------------------------------------------------------- /man/identify_outliers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{identify_outliers} 4 | \alias{identify_outliers} 5 | \title{Unnest a summarized results dataframe, adding outlier information} 6 | \usage{ 7 | identify_outliers(results) 8 | } 9 | \arguments{ 10 | \item{results}{Scenario summary results} 11 | } 12 | \value{ 13 | The supplied dataframe with the following additional columns: 14 | \itemize{ 15 | \item \code{ale_var_zscore} - Annual loss z-score 16 | \item \code{outlier} - Logical flag when the z-score is greater than or equal to two 17 | } 18 | } 19 | \description{ 20 | Given a summarized results dataframe, unnest the summary results 21 | column and use the value at risk (VaR) column to identify all the 22 | elements that are outliers (having a VaR >= two standard deviations) 23 | } 24 | \examples{ 25 | data(mc_scenario_summary) 26 | identify_outliers(mc_scenario_summary) 27 | } 28 | -------------------------------------------------------------------------------- /man/import_capabilities.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/import.R 3 | \name{import_capabilities} 4 | \alias{import_capabilities} 5 | \title{Import capabilities from survey spreadsheet} 6 | \usage{ 7 | import_capabilities(survey_file = NULL, domains = NULL) 8 | } 9 | \arguments{ 10 | \item{survey_file}{Path to survey Excel file. If not supplied, a default sample file is used.} 11 | 12 | \item{domains}{Dataframe of domains and domain IDs.} 13 | } 14 | \value{ 15 | Extracted capabilities as a dataframe. 16 | } 17 | \description{ 18 | Import capabilities from survey spreadsheet 19 | } 20 | \examples{ 21 | data(mc_domains) 22 | import_capabilities(domains = mc_domains) 23 | } 24 | -------------------------------------------------------------------------------- /man/import_scenarios.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/import.R 3 | \name{import_scenarios} 4 | \alias{import_scenarios} 5 | \title{Import scenarios from survey spreadsheet} 6 | \usage{ 7 | import_scenarios(survey_file = NULL, domains = NULL) 8 | } 9 | \arguments{ 10 | \item{survey_file}{Path to survey Excel file. Defaults to a sample file if not supplied.} 11 | 12 | \item{domains}{Dataframe of domains and domain IDs.} 13 | } 14 | \value{ 15 | Extracted qualitative scenarios as a dataframe. 16 | } 17 | \description{ 18 | Import scenarios from survey spreadsheet 19 | } 20 | \examples{ 21 | data(mc_domains) 22 | import_scenarios(domains = mc_domains) 23 | } 24 | -------------------------------------------------------------------------------- /man/import_spreadsheet.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/import.R 3 | \name{import_spreadsheet} 4 | \alias{import_spreadsheet} 5 | \title{Import the scenario spreadsheet} 6 | \usage{ 7 | import_spreadsheet( 8 | survey_file = system.file("survey", "survey.xlsx", package = "evaluator"), 9 | domains = NULL, 10 | output_dir = "~/evaluator/results" 11 | ) 12 | } 13 | \arguments{ 14 | \item{survey_file}{Path to survey Excel file. Defaults to an Evaluator-provided sample spreadsheet.} 15 | 16 | \item{domains}{Dataframe of domains and domain IDs. Defaults to built-in sample \code{domains} dataset.} 17 | 18 | \item{output_dir}{Output file directory.} 19 | } 20 | \value{ 21 | Dataframe of file information on the two newly created files. 22 | } 23 | \description{ 24 | This is a convenience wrapper around the \code{\link{import_scenarios}} and 25 | \code{\link{import_capabilities}} functions. Writes cleaned 26 | comma-separated formatted files for the scenarios and 27 | capabilities to disk. 28 | } 29 | -------------------------------------------------------------------------------- /man/is_tidyrisk_scenario.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidyrisk_scenario.R 3 | \name{is_tidyrisk_scenario} 4 | \alias{is_tidyrisk_scenario} 5 | \title{Test if the object is a tidyrisk_scenario} 6 | \usage{ 7 | is_tidyrisk_scenario(x) 8 | } 9 | \arguments{ 10 | \item{x}{An object} 11 | } 12 | \value{ 13 | \code{TRUE} if the object inherits from the \code{tidyrisk_scenario} class. 14 | } 15 | \description{ 16 | This function returns \code{TRUE} for tidyrisk_scenario (or subclasses) 17 | and \code{FALSE} for all other objects. 18 | } 19 | -------------------------------------------------------------------------------- /man/load_data-deprecated.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/load_data.R 3 | \name{load_data-deprecated} 4 | \alias{load_data-deprecated} 5 | \title{Load input and results files} 6 | \arguments{ 7 | \item{input_directory}{Location of input files.} 8 | 9 | \item{results_directory}{Location of simulation results.} 10 | } 11 | \value{ 12 | List of all key data objects. 13 | } 14 | \description{ 15 | Given an input directory and a directory of simulation results, load all 16 | of the key Evaluator data objects into memory. 17 | } 18 | \examples{ 19 | \dontrun{ 20 | load_data("~/evaluator/inputs", "~/evaluator/results") 21 | } 22 | 23 | } 24 | \seealso{ 25 | \code{\link{evaluator-deprecated}} 26 | } 27 | \keyword{internal} 28 | -------------------------------------------------------------------------------- /man/loss_exceedance_curve.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/common_graphs.R 3 | \name{loss_exceedance_curve} 4 | \alias{loss_exceedance_curve} 5 | \title{Display the loss exceedance curve for a group of one or more scenarios} 6 | \usage{ 7 | loss_exceedance_curve(iteration_results) 8 | } 9 | \arguments{ 10 | \item{iteration_results}{Iteration-level summary from \code{summarize_iterations}.} 11 | } 12 | \value{ 13 | A ggplot object. 14 | } 15 | \description{ 16 | Display the loss exceedance curve for a group of one or more scenarios 17 | } 18 | \examples{ 19 | data(mc_simulation_results) 20 | summarize_iterations(mc_simulation_results$results) \%>\% loss_exceedance_curve() 21 | } 22 | \seealso{ 23 | Other result graphs: 24 | \code{\link{exposure_histogram}()}, 25 | \code{\link{generate_event_outcomes_plot}()}, 26 | \code{\link{generate_heatmap}()}, 27 | \code{\link{generate_scatterplot-deprecated}}, 28 | \code{\link{loss_scatterplot}()} 29 | } 30 | \concept{result graphs} 31 | -------------------------------------------------------------------------------- /man/loss_scatterplot.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/common_graphs.R 3 | \name{loss_scatterplot} 4 | \alias{loss_scatterplot} 5 | \title{Display a scatterplot of loss events for a scenario} 6 | \usage{ 7 | loss_scatterplot(simulation_result) 8 | } 9 | \arguments{ 10 | \item{simulation_result}{Simulation results from \code{run_simulation}.} 11 | } 12 | \value{ 13 | A ggplot object. 14 | } 15 | \description{ 16 | Given a detailed results dataframe create a scatterplot of the number of 17 | loss events versus the total amount of expected annual loss for each 18 | simulation. This provides a detailed view on the results. 19 | } 20 | \examples{ 21 | data(mc_simulation_results) 22 | loss_scatterplot(mc_simulation_results$results[[1]]) 23 | } 24 | \seealso{ 25 | Other result graphs: 26 | \code{\link{exposure_histogram}()}, 27 | \code{\link{generate_event_outcomes_plot}()}, 28 | \code{\link{generate_heatmap}()}, 29 | \code{\link{generate_scatterplot-deprecated}}, 30 | \code{\link{loss_exceedance_curve}()} 31 | } 32 | \concept{result graphs} 33 | -------------------------------------------------------------------------------- /man/mc_capabilities.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{mc_capabilities} 5 | \alias{mc_capabilities} 6 | \title{Capabilities} 7 | \format{ 8 | \describe{ 9 | \item{capability_id}{unique id of the capability} 10 | \item{domain_id}{domain id to which the capability applies} 11 | \item{capability}{full text summary of the capability} 12 | \item{diff}{qualitative label of control effectiveness} 13 | } 14 | } 15 | \source{ 16 | This is hypothetical information. Any similarity to any other 17 | entity is completely coincidental. 18 | } 19 | \usage{ 20 | mc_capabilities 21 | } 22 | \description{ 23 | A sample set of capabilities for the demonstration (and artificial) 24 | MetroCare information security program. 25 | } 26 | \keyword{datasets} 27 | -------------------------------------------------------------------------------- /man/mc_domain_summary.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{mc_domain_summary} 5 | \alias{mc_domain_summary} 6 | \title{Domain-level risk summary} 7 | \format{ 8 | \describe{ 9 | \item{domain_id}{abbreviated name of the domain} 10 | \item{loss_events_mean}{mean number of loss events} 11 | \item{loss_events_min}{minimum number of loss events} 12 | \item{loss_events_max}{maximum number of loss events} 13 | \item{loss_events_median}{median number of loss events} 14 | \item{ale_max}{minimum annual loss expected} 15 | \item{ale_median}{median annual loss expected} 16 | \item{ale_mean}{mean annual loss expected} 17 | \item{ale_max}{maximum annual loss expected} 18 | \item{ale_sd}{standard deviation annual loss expected} 19 | \item{ale_var}{value at risk, ale} 20 | \item{mean_threat_events}{mean threat events} 21 | \item{mean_avoided_events}{mean avoided events} 22 | \item{mean_tc_exceedance}{mean threat capability exceedance} 23 | \item{mean_diff_exceedance}{mean difficulty exceedance} 24 | \item{mean_vuln}{mean vulnerability of the scenario} 25 | } 26 | } 27 | \source{ 28 | This is hypothetical information. Any similarity to any other 29 | entity is completely coincidental. 30 | } 31 | \usage{ 32 | mc_domain_summary 33 | } 34 | \description{ 35 | A sample set of quantified information security risk exposure, summarized 36 | at the domain level, for the demonstration (and artificial) 37 | MetroCare information security program. 38 | } 39 | \keyword{datasets} 40 | -------------------------------------------------------------------------------- /man/mc_domains.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{mc_domains} 5 | \alias{mc_domains} 6 | \title{Domain mappings} 7 | \format{ 8 | \describe{ 9 | \item{domain_id}{abbreviated name of the domain} 10 | \item{domain}{full title of the domain} 11 | } 12 | } 13 | \source{ 14 | This is hypothetical information. Any similarity to any other 15 | entity is completely coincidental. 16 | } 17 | \usage{ 18 | mc_domains 19 | } 20 | \description{ 21 | A sample set of the domains for the demonstration (and artificial) 22 | MetroCare information security program. 23 | } 24 | \keyword{datasets} 25 | -------------------------------------------------------------------------------- /man/mc_mappings.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{mc_mappings} 5 | \alias{mc_mappings} 6 | \title{Qualitative to quantitative mappings} 7 | \format{ 8 | \describe{ 9 | \item{type}{The element in the OpenFAIR ontology to which this mapping applies} 10 | \item{label}{Qualitative label} 11 | \item{l}{BetaPERT low value} 12 | \item{ml}{BetaPERT most likely value} 13 | \item{h}{BetaPERT high value} 14 | \item{conf}{BetaPERT confidence value} 15 | } 16 | } 17 | \source{ 18 | This is hypothetical information. Any similarity to any other 19 | entity is completely coincidental. 20 | } 21 | \usage{ 22 | mc_mappings 23 | } 24 | \description{ 25 | A sample set of qualitative to quantitative mappings for the demonstration 26 | (and artificial) MetroCare information security program. 27 | } 28 | \keyword{datasets} 29 | -------------------------------------------------------------------------------- /man/mc_qualitative_scenarios.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{mc_qualitative_scenarios} 5 | \alias{mc_qualitative_scenarios} 6 | \title{Qualitative information security risk scenarios} 7 | \format{ 8 | \describe{ 9 | \item{scenario_id}{id of the scenario, primary key} 10 | \item{scenario}{full text description of the risk scenario} 11 | \item{tcomm}{full text name of threat community} 12 | \item{tef}{qualitative label of threat frequency} 13 | \item{tc}{qualitative label of threat capability} 14 | \item{lm}{qualitative label of loss magnitude} 15 | \item{domain_id}{domain id} 16 | \item{controls}{comma delimited list of controls ids} 17 | } 18 | } 19 | \source{ 20 | This is hypothetical information. Any similarity to any other 21 | entity is completely coincidental. 22 | } 23 | \usage{ 24 | mc_qualitative_scenarios 25 | } 26 | \description{ 27 | A sample set of qualitative information security risk scenarios for the 28 | demonstration (and artificial) MetroCare information security program. 29 | } 30 | \details{ 31 | No connection with any other similarly named entity is intended or implied. 32 | } 33 | \keyword{datasets} 34 | -------------------------------------------------------------------------------- /man/mc_quantitative_scenarios.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{mc_quantitative_scenarios} 5 | \alias{mc_quantitative_scenarios} 6 | \title{Quantified information risk scenarios} 7 | \format{ 8 | A dataset of quantified risk scenarios, with parameters 9 | describing the distribution of each input. 10 | 11 | \describe{ 12 | \item{scenario_id}{id of the scenario, primary key} 13 | \item{scenario_description}{full text description of the risk scenario} 14 | \item{tcomm}{description of the threat community} 15 | \item{domain_id}{domain id} 16 | \item{control_descriptons}{named list of the text description of controls involved} 17 | \item{scenario}{\code{\link{tidyrisk_scenario}} objects} 18 | } 19 | } 20 | \source{ 21 | This is hypothetical information. Any similarity to any other 22 | entity is completely coincidental. 23 | } 24 | \usage{ 25 | mc_quantitative_scenarios 26 | } 27 | \description{ 28 | A sample set of quantified information security risk scenarios for the 29 | demonstration (and artificial) MetroCare information security program. 30 | } 31 | \keyword{datasets} 32 | -------------------------------------------------------------------------------- /man/mc_scenario_summary.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{mc_scenario_summary} 5 | \alias{mc_scenario_summary} 6 | \title{Scenario-level risk summary} 7 | \format{ 8 | \describe{ 9 | \item{scenario_id}{ID of the scenario} 10 | \item{domain_id}{domain id} 11 | \item{control_description}{control description} 12 | \item{results}{nested data frame of simulation results for the scenario} 13 | \item{loss_events_mean}{mean number of loss events} 14 | \item{loss_events_median}{median number of loss events} 15 | \item{loss_events_min}{minimum number of loss events} 16 | \item{loss_events_max}{maximum number of loss events} 17 | \item{ale_median}{median annual loss expected} 18 | \item{ale_max}{maximum annual loss expected} 19 | \item{ale_var}{value at risk, ale} 20 | \item{sle_min}{minimum single loss expectancy} 21 | \item{sle_max}{maximum single loss expectancy} 22 | \item{sle_mean}{mean single loss expectancy} 23 | \item{sle_median}{median single loss expectancy} 24 | \item{mean_tc_exceedance}{mean threat capability exceedance} 25 | \item{mean_diff_exceedance}{mean difficulty exceedance} 26 | \item{mean_vuln}{mean vulnerability of the scenario} 27 | } 28 | } 29 | \source{ 30 | This is hypothetical information. Any similarity to any other 31 | entity is completely coincidental. 32 | } 33 | \usage{ 34 | mc_scenario_summary 35 | } 36 | \description{ 37 | A sample set of quantified information security risk exposure, summarized 38 | at the scenario level, for the demonstration (and artificial) 39 | MetroCare information security program. 40 | } 41 | \keyword{datasets} 42 | -------------------------------------------------------------------------------- /man/mc_simulation_results.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{mc_simulation_results} 5 | \alias{mc_simulation_results} 6 | \title{Simulation results} 7 | \format{ 8 | \describe{ 9 | \item{scenario_id}{id of the scenario} 10 | \item{domain_id}{domain id} 11 | \item{results}{nested data frame of simulation results for the scenario} 12 | } 13 | } 14 | \source{ 15 | This is hypothetical information. Any similarity to any other 16 | entity is completely coincidental. 17 | } 18 | \usage{ 19 | mc_simulation_results 20 | } 21 | \description{ 22 | A sample set of information security risk scenario simulation results 23 | for the demonstration (and artificial) MetroCare information security 24 | program. 25 | } 26 | \keyword{datasets} 27 | -------------------------------------------------------------------------------- /man/new_tidyrisk_scenario.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidyrisk_scenario.R 3 | \name{new_tidyrisk_scenario} 4 | \alias{new_tidyrisk_scenario} 5 | \alias{tidyrisk_scenario} 6 | \title{Construct a quantitative scenario object} 7 | \usage{ 8 | new_tidyrisk_scenario(..., model = "openfair_tef_tc_diff_lm") 9 | 10 | tidyrisk_scenario(..., model = "openfair_tef_tc_diff_lm") 11 | } 12 | \arguments{ 13 | \item{...}{One or more named OpenFAIR factor with parameters for sampling} 14 | 15 | \item{model}{Name of model to run} 16 | } 17 | \description{ 18 | Supply one or more named lists in the format of \code{foo_params}, 19 | where each \code{foo} is an OpenFAIR factor name (e.g. tef, tc, diff, lm). 20 | Each factor should include a function name (\code{func}) to which the 21 | other named elements in the list are passed as parameters when 22 | sampling. 23 | } 24 | -------------------------------------------------------------------------------- /man/openfair_example.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/report.R 3 | \name{openfair_example} 4 | \alias{openfair_example} 5 | \title{Launch OpenFAIR demonstration web application} 6 | \usage{ 7 | openfair_example(intermediates_dir = tempdir(), quiet = TRUE) 8 | } 9 | \arguments{ 10 | \item{intermediates_dir}{Location for intermediate knit files.} 11 | 12 | \item{quiet}{\code{TRUE} to suppress printing of pandoc output.} 13 | } 14 | \value{ 15 | Invisible NULL 16 | } 17 | \description{ 18 | A simple web application to demonstrate OpenFAIR modeling. This application 19 | allows a user to enter beta PERT parameters and run simulations to see the 20 | distribution of results, with high level summary statistics. As a demonstration 21 | application, only TEF, TC, DIFF, and LM parameters may be entered. 22 | } 23 | \examples{ 24 | \dontrun{ 25 | openfair_example() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /man/openfair_tef_tc_diff_lm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/openfair.R 3 | \name{openfair_tef_tc_diff_lm} 4 | \alias{openfair_tef_tc_diff_lm} 5 | \title{Run an OpenFAIR simulation at the TEF/TC/DIFF/LM levels} 6 | \usage{ 7 | openfair_tef_tc_diff_lm(tef, tc, diff, lm, n = 10^4, verbose = FALSE) 8 | } 9 | \arguments{ 10 | \item{tef}{Parameters for TEF simulation} 11 | 12 | \item{tc}{Parameters for TC simulation} 13 | 14 | \item{diff}{Parameters for DIFF simulation} 15 | 16 | \item{lm}{Parameters for LM simulation} 17 | 18 | \item{n}{Number of iterations to run.} 19 | 20 | \item{verbose}{Whether to print progress indicators.} 21 | } 22 | \value{ 23 | Dataframe of scenario name, threat_event count, loss_event count, 24 | mean TC and DIFF exceedance, and ALE samples. 25 | } 26 | \description{ 27 | Run an OpenFAIR model with parameters provided for TEF, TC, DIFF, and 28 | LM sampling. If there are multiple controls provided for the scenario, the 29 | arithmetic mean (average) is taken across samples for all controls to get 30 | the effective control strength for each threat event. 31 | } 32 | \examples{ 33 | data(mc_quantitative_scenarios) 34 | params <- mc_quantitative_scenarios$scenario[[1]]$parameters 35 | openfair_tef_tc_diff_lm(params$tef, params$tc, params$diff, params$lm, 10) 36 | } 37 | \seealso{ 38 | Other OpenFAIR helpers: 39 | \code{\link{compare_tef_vuln}()}, 40 | \code{\link{get_mean_control_strength}()}, 41 | \code{\link{sample_diff}()}, 42 | \code{\link{sample_lef}()}, 43 | \code{\link{sample_lm}()}, 44 | \code{\link{sample_tc}()}, 45 | \code{\link{sample_vuln}()}, 46 | \code{\link{select_loss_opportunities}()} 47 | } 48 | \concept{OpenFAIR helpers} 49 | -------------------------------------------------------------------------------- /man/openfair_tef_tc_diff_plm_sr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/openfair.R 3 | \name{openfair_tef_tc_diff_plm_sr} 4 | \alias{openfair_tef_tc_diff_plm_sr} 5 | \title{Run an OpenFAIR simulation at the TEF/TC/DIFF/PLM/SR levels} 6 | \usage{ 7 | openfair_tef_tc_diff_plm_sr(tef, tc, diff, plm, sr, n = 10^4, verbose = FALSE) 8 | } 9 | \arguments{ 10 | \item{tef}{Parameters for TEF simulation.} 11 | 12 | \item{tc}{Parameters for TC simulation.} 13 | 14 | \item{diff}{Parameters for DIFF simulation.} 15 | 16 | \item{plm}{Parameters for PLM simulation.} 17 | 18 | \item{sr}{Parameters for SR simulation.} 19 | 20 | \item{n}{Number of iterations to run.} 21 | 22 | \item{verbose}{Whether to print progress indicators.} 23 | } 24 | \value{ 25 | Dataframe of scenario name, threat_event count, loss_event count, 26 | mean TC and DIFF exceedance, and ALE samples. 27 | } 28 | \description{ 29 | Run an OpenFAIR model with parameters provided for TEF, TC, DIFF, PLM, and 30 | SR sampling. If there are multiple controls provided for the scenario, the 31 | arithmetic mean (average) is taken across samples for all controls to get 32 | the effective control strength for each threat event. 33 | } 34 | \seealso{ 35 | Other OpenFAIR models: 36 | \code{\link{sample_tef}()} 37 | } 38 | \concept{OpenFAIR models} 39 | -------------------------------------------------------------------------------- /man/pipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-pipe.R 3 | \name{\%>\%} 4 | \alias{\%>\%} 5 | \title{Pipe operator} 6 | \usage{ 7 | lhs \%>\% rhs 8 | } 9 | \description{ 10 | See \code{magrittr::\link[magrittr]{\%>\%}} for details. 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/print.tidyrisk_scenario.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidyrisk_scenario.R 3 | \name{print.tidyrisk_scenario} 4 | \alias{print.tidyrisk_scenario} 5 | \title{Default printing of a tidyrisk_scenario} 6 | \usage{ 7 | \method{print}{tidyrisk_scenario}(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{A tidyrisk_scenario} 11 | 12 | \item{...}{Currently not used} 13 | } 14 | \description{ 15 | Basic printing of a tidyrisk scenario 16 | } 17 | -------------------------------------------------------------------------------- /man/read_qualitative_inputs.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/load_data.R 3 | \name{read_qualitative_inputs} 4 | \alias{read_qualitative_inputs} 5 | \title{Load qualitative inputs} 6 | \usage{ 7 | read_qualitative_inputs(input_directory = "~/evaluator/inputs") 8 | } 9 | \arguments{ 10 | \item{input_directory}{Location of input files.} 11 | } 12 | \value{ 13 | List of domains, mappings, capabilities, and qualitative_scenarios 14 | } 15 | \description{ 16 | Given an input directory, load the key qualitative objects into memory. 17 | } 18 | \details{ 19 | The key qualitative inputs for Evaluator processing include: 20 | \itemize{ 21 | \item \code{domains.csv}: domains and domain_ids 22 | \item \code{mappings.csv}: qualitative to quantitative mappings 23 | \item \code{capabilities.csv}: qualitative capabilities 24 | \item \code{qualitative_scenarios.csv}: qualitative risk scenarios 25 | } 26 | } 27 | \examples{ 28 | \dontrun{ 29 | read_qualitative_inputs("~/evaluator/inputs") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /man/read_quantitative_inputs.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/load_data.R 3 | \name{read_quantitative_inputs} 4 | \alias{read_quantitative_inputs} 5 | \title{Load quantitative inputs} 6 | \usage{ 7 | read_quantitative_inputs(input_directory = "~/evaluator/inputs") 8 | } 9 | \arguments{ 10 | \item{input_directory}{Location of input files.} 11 | } 12 | \value{ 13 | List of domains, quantitative_scenarios, and risk_tolerances 14 | } 15 | \description{ 16 | Given an input directory, load the quantitative objects into memory. 17 | } 18 | \details{ 19 | The key quantitative inputs for Evaluator processing include: 20 | \itemize{ 21 | \item \code{domains.csv} - domains and domain_ids 22 | \item \code{risk_tolerances.csv} - the risk tolerances of the organization 23 | \item \code{quantitative_scenarios.rds} - risk scenarios and quantified parameters 24 | } 25 | } 26 | \examples{ 27 | \dontrun{ 28 | read_quantitative_inputs("~/evaluator/inputs") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /man/risk_dashboard.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/report.R 3 | \name{risk_dashboard} 4 | \alias{risk_dashboard} 5 | \title{Launch a single page summary risk dashboard} 6 | \usage{ 7 | risk_dashboard( 8 | input_directory = "~/evaluator/inputs", 9 | results_directory = "~/evaluator/results", 10 | output_file, 11 | intermediates_dir = tempdir(), 12 | quiet = TRUE, 13 | ... 14 | ) 15 | } 16 | \arguments{ 17 | \item{input_directory}{Location of input files read by \code{\link{read_quantitative_inputs}}.} 18 | 19 | \item{results_directory}{Directory where the \code{simulation_results.rds} file is located.} 20 | 21 | \item{output_file}{Full path to the desired output file.} 22 | 23 | \item{intermediates_dir}{Location for intermediate knit files.} 24 | 25 | \item{quiet}{\code{TRUE} to suppress printing of pandoc output.} 26 | 27 | \item{...}{Any other parameters to pass to \code{rmarkdown::render}} 28 | } 29 | \value{ 30 | Default return values of the \code{rmarkdown::render} function. 31 | } 32 | \description{ 33 | Given the input files and the analysis summary file, create a basic one- 34 | page summary with an overview of the results per domain and scenario. 35 | Intended as a skeleton showing how the results could be displayed at an 36 | executive level. 37 | } 38 | \examples{ 39 | \dontrun{ 40 | risk_dashboard("~/inputs", "~/simulations") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /man/run_simulation.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/simulate.R 3 | \name{run_simulation} 4 | \alias{run_simulation} 5 | \title{Run simulations for a scenario} 6 | \usage{ 7 | run_simulation( 8 | scenario, 9 | iterations = 10000L, 10 | ale_maximum = NULL, 11 | verbose = FALSE, 12 | simulation_count = NULL 13 | ) 14 | } 15 | \arguments{ 16 | \item{scenario}{A \link{tidyrisk_scenario} object.} 17 | 18 | \item{iterations}{Number of iterations to run on each scenario.} 19 | 20 | \item{ale_maximum}{Maximum practical annual losses.} 21 | 22 | \item{verbose}{Whether verbose console output is requested.} 23 | 24 | \item{simulation_count}{\strong{DEPRECATED} Number of simulations to perform.} 25 | } 26 | \value{ 27 | Dataframe of results. 28 | } 29 | \description{ 30 | Given a quantitative scenario object of type \code{tidyrisk_scenario}, run an 31 | OpenFAIR Monte Carlo simulation. 32 | } 33 | \examples{ 34 | data(mc_quantitative_scenarios) 35 | run_simulation(mc_quantitative_scenarios$scenario[[1]], 10) 36 | } 37 | -------------------------------------------------------------------------------- /man/run_simulations.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/simulate.R 3 | \name{run_simulations} 4 | \alias{run_simulations} 5 | \title{Run simulations for a list of scenarios} 6 | \usage{ 7 | run_simulations( 8 | scenario, 9 | ..., 10 | iterations = 10000L, 11 | ale_maximum = NULL, 12 | verbose = FALSE, 13 | simulation_count = NULL 14 | ) 15 | } 16 | \arguments{ 17 | \item{scenario}{A \link{tidyrisk_scenario} object.} 18 | 19 | \item{...}{Additional \code{tidyrisk_scenario} objects to simulate.} 20 | 21 | \item{iterations}{Number of iterations to run on each scenario.} 22 | 23 | \item{ale_maximum}{Maximum practical annual losses.} 24 | 25 | \item{verbose}{Whether verbose console output is requested.} 26 | 27 | \item{simulation_count}{\strong{DEPRECATED} Number of simulations to perform.} 28 | } 29 | \value{ 30 | A list of one dataframe of results for each scenario. 31 | } 32 | \description{ 33 | Given a list of quantitative scenario objects of type \code{tidyrisk_scenario}, 34 | run a OpenFAIR Monte Carlo simulation for each scenario. 35 | } 36 | \examples{ 37 | # fetch three scenarios for this example 38 | data(mc_quantitative_scenarios) 39 | scenario_a <- mc_quantitative_scenarios$scenario[[1]] 40 | scenario_b <- mc_quantitative_scenarios$scenario[[2]] 41 | scenario_c <- mc_quantitative_scenarios$scenario[[3]] 42 | run_simulations(scenario_a, scenario_b, scenario_c, iterations = 10) 43 | 44 | } 45 | -------------------------------------------------------------------------------- /man/sample_diff.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/openfair.R 3 | \name{sample_diff} 4 | \alias{sample_diff} 5 | \title{Calculate the difficulty presented by controls, given a function and 6 | parameters for that function} 7 | \usage{ 8 | sample_diff(n, .func = NULL, params = NULL) 9 | } 10 | \arguments{ 11 | \item{n}{Number of samples to generate.} 12 | 13 | \item{.func}{Function to use to simulate DIFF, defaults to \code{\link[mc2d]{rpert}}.} 14 | 15 | \item{params}{Optional parameters to pass to \code{.func}.} 16 | } 17 | \value{ 18 | List containing type ("diff"), samples (as a vector), and details (as a list). 19 | } 20 | \description{ 21 | Calculate the difficulty presented by controls, given a function and 22 | parameters for that function 23 | } 24 | \seealso{ 25 | Other OpenFAIR helpers: 26 | \code{\link{compare_tef_vuln}()}, 27 | \code{\link{get_mean_control_strength}()}, 28 | \code{\link{openfair_tef_tc_diff_lm}()}, 29 | \code{\link{sample_lef}()}, 30 | \code{\link{sample_lm}()}, 31 | \code{\link{sample_tc}()}, 32 | \code{\link{sample_vuln}()}, 33 | \code{\link{select_loss_opportunities}()} 34 | } 35 | \concept{OpenFAIR helpers} 36 | -------------------------------------------------------------------------------- /man/sample_lef.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/openfair.R 3 | \name{sample_lef} 4 | \alias{sample_lef} 5 | \title{Sample loss event frequency} 6 | \usage{ 7 | sample_lef(n, .func = NULL, params = NULL) 8 | } 9 | \arguments{ 10 | \item{n}{Number of samples to generate.} 11 | 12 | \item{.func}{Function to use to simulate LEF, defaults to \code{\link[stats]{rnorm}}.} 13 | 14 | \item{params}{Optional parameters to pass to \code{.func}.} 15 | } 16 | \value{ 17 | List containing type ("lef"), samples (as a vector), and details (as a list). 18 | } 19 | \description{ 20 | Sample loss event frequency 21 | } 22 | \seealso{ 23 | Other OpenFAIR helpers: 24 | \code{\link{compare_tef_vuln}()}, 25 | \code{\link{get_mean_control_strength}()}, 26 | \code{\link{openfair_tef_tc_diff_lm}()}, 27 | \code{\link{sample_diff}()}, 28 | \code{\link{sample_lm}()}, 29 | \code{\link{sample_tc}()}, 30 | \code{\link{sample_vuln}()}, 31 | \code{\link{select_loss_opportunities}()} 32 | } 33 | \concept{OpenFAIR helpers} 34 | -------------------------------------------------------------------------------- /man/sample_lm.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/openfair.R 3 | \name{sample_lm} 4 | \alias{sample_lm} 5 | \title{Given a number of loss events and a loss distribution, calculate losses} 6 | \usage{ 7 | sample_lm(n, .func = NULL, params = NULL) 8 | } 9 | \arguments{ 10 | \item{n}{Number of samples to generate.} 11 | 12 | \item{.func}{Function to use to simulate TEF, defaults to \code{\link[mc2d]{rpert}}.} 13 | 14 | \item{params}{Optional parameters to pass to \code{.func}.} 15 | } 16 | \value{ 17 | List containing type ("lm"), samples (as a vector), and details (as a list). 18 | } 19 | \description{ 20 | Given a number of loss events and a loss distribution, calculate losses 21 | } 22 | \seealso{ 23 | Other OpenFAIR helpers: 24 | \code{\link{compare_tef_vuln}()}, 25 | \code{\link{get_mean_control_strength}()}, 26 | \code{\link{openfair_tef_tc_diff_lm}()}, 27 | \code{\link{sample_diff}()}, 28 | \code{\link{sample_lef}()}, 29 | \code{\link{sample_tc}()}, 30 | \code{\link{sample_vuln}()}, 31 | \code{\link{select_loss_opportunities}()} 32 | } 33 | \concept{OpenFAIR helpers} 34 | -------------------------------------------------------------------------------- /man/sample_tc.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/openfair.R 3 | \name{sample_tc} 4 | \alias{sample_tc} 5 | \title{Sample threat capabilities (TC) from a distribution function} 6 | \usage{ 7 | sample_tc(n, params = NULL, .func = NULL) 8 | } 9 | \arguments{ 10 | \item{n}{Number of samples to generate.} 11 | 12 | \item{params}{Optional parameters to pass to \code{.func}.} 13 | 14 | \item{.func}{Function to use to simulate TC, defaults to \code{\link[mc2d]{rpert}}.} 15 | } 16 | \value{ 17 | List containing type ("tc"), samples (as a vector), and details (as a list). 18 | } 19 | \description{ 20 | Sample threat capabilities (TC) from a distribution function 21 | } 22 | \seealso{ 23 | Other OpenFAIR helpers: 24 | \code{\link{compare_tef_vuln}()}, 25 | \code{\link{get_mean_control_strength}()}, 26 | \code{\link{openfair_tef_tc_diff_lm}()}, 27 | \code{\link{sample_diff}()}, 28 | \code{\link{sample_lef}()}, 29 | \code{\link{sample_lm}()}, 30 | \code{\link{sample_vuln}()}, 31 | \code{\link{select_loss_opportunities}()} 32 | } 33 | \concept{OpenFAIR helpers} 34 | -------------------------------------------------------------------------------- /man/sample_tef.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/openfair.R 3 | \name{sample_tef} 4 | \alias{sample_tef} 5 | \title{Calculate the number of simulated threat event frequencies (TEF)} 6 | \usage{ 7 | sample_tef(n, params = NULL, .func = NULL) 8 | } 9 | \arguments{ 10 | \item{n}{Number of samples to generate.} 11 | 12 | \item{params}{Optional parameters to pass to \code{.func}.} 13 | 14 | \item{.func}{Function to use to simulate TEF, defaults to \code{\link[mc2d]{rpert}}.} 15 | } 16 | \value{ 17 | List containing type ("tef"), samples (as a vector), and details (as a list). 18 | } 19 | \description{ 20 | Calculate the number of simulated threat event frequencies (TEF) 21 | } 22 | \seealso{ 23 | Other OpenFAIR models: 24 | \code{\link{openfair_tef_tc_diff_plm_sr}()} 25 | } 26 | \concept{OpenFAIR models} 27 | -------------------------------------------------------------------------------- /man/sample_vuln.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/openfair.R 3 | \name{sample_vuln} 4 | \alias{sample_vuln} 5 | \title{Calculate the vulnerability} 6 | \usage{ 7 | sample_vuln(n, .func = NULL, params = NULL) 8 | } 9 | \arguments{ 10 | \item{n}{Number of samples to generate.} 11 | 12 | \item{.func}{Function to use to simulate VULN, defaults to \code{\link[stats]{rbinom}}.} 13 | 14 | \item{params}{Optional parameters to pass to \code{.func}.} 15 | } 16 | \value{ 17 | List containing type ("vuln"), samples (as a vector), and details (as a list). 18 | } 19 | \description{ 20 | Calculate the vulnerability 21 | } 22 | \seealso{ 23 | Other OpenFAIR helpers: 24 | \code{\link{compare_tef_vuln}()}, 25 | \code{\link{get_mean_control_strength}()}, 26 | \code{\link{openfair_tef_tc_diff_lm}()}, 27 | \code{\link{sample_diff}()}, 28 | \code{\link{sample_lef}()}, 29 | \code{\link{sample_lm}()}, 30 | \code{\link{sample_tc}()}, 31 | \code{\link{select_loss_opportunities}()} 32 | } 33 | \concept{OpenFAIR helpers} 34 | -------------------------------------------------------------------------------- /man/select_loss_opportunities.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/openfair.R 3 | \name{select_loss_opportunities} 4 | \alias{select_loss_opportunities} 5 | \title{Determine which threat events result in loss opportunities} 6 | \usage{ 7 | select_loss_opportunities(tc, diff, n = NULL, ...) 8 | } 9 | \arguments{ 10 | \item{tc}{Threat capability (as a percentage).} 11 | 12 | \item{diff}{Difficulty (as a percentage).} 13 | 14 | \item{n}{Number of samples to generate.} 15 | 16 | \item{...}{Optional parameters (currently ignored).} 17 | } 18 | \value{ 19 | List containing boolean values of length TC (as a vector) and details (as a list). 20 | } 21 | \description{ 22 | Composition function for use in \code{\link{sample_vuln}}, does a simple 23 | compare of all threat events where the threat capability (TC) is greater 24 | than the difficulty (DIFF). 25 | } 26 | \examples{ 27 | threat_capabilities <- c(.1, .5, .9) 28 | difficulties <- c(.09, .6, .8) 29 | select_loss_opportunities(threat_capabilities, difficulties) 30 | } 31 | \seealso{ 32 | Other OpenFAIR helpers: 33 | \code{\link{compare_tef_vuln}()}, 34 | \code{\link{get_mean_control_strength}()}, 35 | \code{\link{openfair_tef_tc_diff_lm}()}, 36 | \code{\link{sample_diff}()}, 37 | \code{\link{sample_lef}()}, 38 | \code{\link{sample_lm}()}, 39 | \code{\link{sample_tc}()}, 40 | \code{\link{sample_vuln}()} 41 | } 42 | \concept{OpenFAIR helpers} 43 | -------------------------------------------------------------------------------- /man/split_sheet.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/import.R 3 | \name{split_sheet} 4 | \alias{split_sheet} 5 | \title{Split a sheet of the survey spreadsheet into either capabilities or threats} 6 | \usage{ 7 | split_sheet(dat, table_type = "capabilities") 8 | } 9 | \arguments{ 10 | \item{dat}{Raw sheet input from \code{\link[readxl]{read_excel}}.} 11 | 12 | \item{table_type}{Either \code{capabilities} or \code{threats}} 13 | } 14 | \value{ 15 | Extracted table as a dataframe 16 | } 17 | \description{ 18 | The default data collection Excel spreadsheet solicits threat 19 | scenarios and applicable controls for each domain. This function 20 | takes a single sheet from the spreadsheet, as read by \code{\link[readxl]{read_excel}} 21 | and pulls out either the capabilities or threats, as directed by the 22 | user. 23 | } 24 | -------------------------------------------------------------------------------- /man/summarize_domains.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/summarize.R 3 | \name{summarize_domains} 4 | \alias{summarize_domains} 5 | \title{Create domain-level summary of simulation results} 6 | \usage{ 7 | summarize_domains(simulation_results, domain_variable = "domain_id") 8 | } 9 | \arguments{ 10 | \item{simulation_results}{Simulation results dataframe.} 11 | 12 | \item{domain_variable}{Variable by which individual simulations should be grouped.} 13 | } 14 | \value{ 15 | Simulation results summarized across domains. 16 | } 17 | \description{ 18 | Given a dataframe of raw results from \code{\link{run_simulations}}, summarize 19 | the individual results at a per-domain level. This domain-level summary 20 | is a useful data structure for aggregate reporting. 21 | } 22 | \details{ 23 | Summary stats created include: 24 | \itemize{ 25 | \item Mean/Min/Max/Median are calculated for loss events 26 | \item Median/Max/VaR are calculated for annual loss expected (ALE) 27 | \item Mean/Median/Max/Min are calculated for single loss expected (SLE) 28 | \item Mean percentage of threat capability exceeding difficulty on successful threat events 29 | \item Mean percentage of difficulty exceeding threat capability on defended events 30 | \item Vulnerability percentage 31 | } 32 | } 33 | \examples{ 34 | \dontrun{ 35 | data(mc_simulation_results) 36 | summarize_domains(mc_simulation_results) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /man/summarize_iterations.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/summarize.R 3 | \name{summarize_iterations} 4 | \alias{summarize_iterations} 5 | \title{Create a summary of outcomes across all scenarios} 6 | \usage{ 7 | summarize_iterations(simulation_result, ..., .key = "iteration") 8 | } 9 | \arguments{ 10 | \item{simulation_result}{Results object for a single scenario.} 11 | 12 | \item{...}{Additional simulation result objects to summarize.} 13 | 14 | \item{.key}{Iteration ID field} 15 | } 16 | \value{ 17 | Dataframe. 18 | } 19 | \description{ 20 | Given a dataframe of raw results from \code{\link{run_simulations}}, summarize 21 | the individual results at a per-iteration level. 22 | } 23 | \details{ 24 | Summary stats created include: 25 | * Mean/Min/Max/Median are calculated for loss events 26 | * Median/Max/VaR are calculated for annual loss expected (ALE) 27 | * Mean/Median/Max/Min are calculated for single loss expected (SLE) 28 | * Mean percentage of threat capability exceeding difficulty on successful threat events 29 | * Mean percentage of difficulty exceeding threat capability on defended events 30 | * Vulnerability percentage 31 | * Z-score of ALE (outliers flagged as 2 >= z-score) 32 | } 33 | \examples{ 34 | data(mc_simulation_results) 35 | summarize_iterations(mc_simulation_results$results) 36 | } 37 | -------------------------------------------------------------------------------- /man/summarize_scenario.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/summarize.R 3 | \name{summarize_scenario} 4 | \alias{summarize_scenario} 5 | \alias{summarize_scenarios} 6 | \title{Create a summary of the simulation results for a single scenario} 7 | \usage{ 8 | summarize_scenario(simulation_result) 9 | 10 | summarize_scenarios(simulation_results) 11 | } 12 | \arguments{ 13 | \item{simulation_result}{Results object for a single scenario.} 14 | 15 | \item{simulation_results}{Simulation results dataframe.} 16 | } 17 | \value{ 18 | Dataframe of summary statistics. 19 | } 20 | \description{ 21 | Given a dataframe of raw results from \code{\link{run_simulations}}, create 22 | summary statistics for the scenario. This is generally the most granular 23 | level of useful data for reporting and analysis (full simulation results 24 | are rarely directly helpful). 25 | } 26 | \details{ 27 | Summary stats created include: 28 | * Mean/Min/Max/Median are calculated for loss events 29 | * Median/Max/VaR are calculated for annual loss expected (ALE) 30 | * Mean/Median/Max/Min are calculated for single loss expected (SLE) 31 | * Mean percentage of threat capability exceeding difficulty on successful threat events 32 | * Mean percentage of difficulty exceeding threat capability on defended events 33 | * Vulnerability percentage 34 | } 35 | \examples{ 36 | data(mc_simulation_results) 37 | # summarize a single scenario 38 | summarize_scenario(mc_simulation_results$results[[1]]) 39 | 40 | # summarize all scenarios in a data frame 41 | data(mc_simulation_results) 42 | summarize_scenarios(mc_simulation_results) 43 | } 44 | -------------------------------------------------------------------------------- /man/summarize_to_disk.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/summarize.R 3 | \name{summarize_to_disk} 4 | \alias{summarize_to_disk} 5 | \title{Create all summary files and write to disk} 6 | \usage{ 7 | summarize_to_disk(simulation_results, results_dir) 8 | } 9 | \arguments{ 10 | \item{simulation_results}{Simulation results dataframe.} 11 | 12 | \item{results_dir}{Directory to place simulation files.} 13 | } 14 | \value{ 15 | Tibble with paths to the created data files. 16 | } 17 | \description{ 18 | This is a wrapper around \code{\link{summarize_scenario}} and 19 | \code{\link{summarize_domains}}, calling both functions and writing the 20 | dataframes to a location on disk. 21 | } 22 | \examples{ 23 | \dontrun{ 24 | data(mc_simulation_results) 25 | summarize_to_disk(mc_simulation_results, results_dir = tempdir()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /man/theme_evaluator.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/common_graphs.R 3 | \name{theme_evaluator} 4 | \alias{theme_evaluator} 5 | \title{Default ggplot theme used by all Evaluator-supplied graphics} 6 | \usage{ 7 | theme_evaluator(base_family = "") 8 | } 9 | \arguments{ 10 | \item{base_family}{Font family.} 11 | } 12 | \value{ 13 | A ggplot theme object. 14 | } 15 | \description{ 16 | Returns a standardized ggplot theme used by all built-in Evaluator plots. 17 | } 18 | \examples{ 19 | library(ggplot2) 20 | p <- ggplot(mtcars) + geom_point(aes(wt, mpg, color = factor(gear))) + facet_wrap(~am) 21 | font_family <- get_base_fontfamily() 22 | p + theme_evaluator(font_family) 23 | } 24 | -------------------------------------------------------------------------------- /man/tidyrisk_factor.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidyrisk_factor.R 3 | \name{tidyrisk_factor} 4 | \alias{tidyrisk_factor} 5 | \alias{new_tidyrisk_factor} 6 | \title{Construct a tidyrisk_factor object} 7 | \usage{ 8 | new_tidyrisk_factor( 9 | samples = double(), 10 | factor_label = character(), 11 | details = list() 12 | ) 13 | 14 | tidyrisk_factor(samples, factor_label, details = list()) 15 | } 16 | \arguments{ 17 | \item{samples}{samples} 18 | 19 | \item{factor_label}{fl} 20 | 21 | \item{details}{details} 22 | } 23 | \description{ 24 | Construct a tidyrisk_factor object 25 | } 26 | -------------------------------------------------------------------------------- /man/tidyrisk_factory.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidyrisk_factor.R 3 | \name{tidyrisk_factory} 4 | \alias{tidyrisk_factory} 5 | \title{Create a tidyrisk_factor sample function} 6 | \usage{ 7 | tidyrisk_factory(factor_label = "TC") 8 | } 9 | \arguments{ 10 | \item{factor_label}{abbreviation of the OpenFAIR element} 11 | } 12 | \description{ 13 | Create a tidyrisk_factor sample function 14 | } 15 | -------------------------------------------------------------------------------- /man/validate_scenarios.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/validate.R 3 | \name{validate_scenarios} 4 | \alias{validate_scenarios} 5 | \title{Validate qualitative scenario data} 6 | \usage{ 7 | validate_scenarios(scenarios, capabilities, domains, mappings) 8 | } 9 | \arguments{ 10 | \item{scenarios}{Dataframe of qualitative scenarios.} 11 | 12 | \item{capabilities}{Dataframe of capabilities.} 13 | 14 | \item{domains}{Dataframe of domain mappings.} 15 | 16 | \item{mappings}{Dataframe of qualitative to quantitative mappings.} 17 | } 18 | \value{ 19 | An invisible boolean as to success/failure of validation steps. 20 | } 21 | \description{ 22 | Run a set of basic consistency checks on the key qualitative data inputs 23 | (scenarios, capabilities, domains, and mappings). 24 | } 25 | \details{ 26 | Checks that: 27 | \itemize{ 28 | \item All scenarios are distinct 29 | \item All controls referenced in scenarios are defined in the controls table 30 | \item All controls are distinct 31 | } 32 | } 33 | \examples{ 34 | \dontrun{ 35 | validate_scenarios(scenarios, capabilities, domains, mappings) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /man/validate_tidyrisk_scenario.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidyrisk_scenario.R 3 | \name{validate_tidyrisk_scenario} 4 | \alias{validate_tidyrisk_scenario} 5 | \title{Validates that a scenario object is well formed} 6 | \usage{ 7 | validate_tidyrisk_scenario(x) 8 | } 9 | \arguments{ 10 | \item{x}{An object} 11 | } 12 | \description{ 13 | Validates that a scenario object is well formed 14 | } 15 | -------------------------------------------------------------------------------- /man/vec_cast.tidyrisk_factor.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidyrisk_factor.R 3 | \name{vec_cast.tidyrisk_factor} 4 | \alias{vec_cast.tidyrisk_factor} 5 | \title{Cast a \code{tidyrisk_factor} vector to a specified type} 6 | \usage{ 7 | \method{vec_cast}{tidyrisk_factor}(x, to) 8 | } 9 | \arguments{ 10 | \item{x}{Vectors to cast.} 11 | 12 | \item{to}{Type to cast to. If \code{NULL}, \code{x} will be returned as is.} 13 | } 14 | \description{ 15 | Cast a \code{tidyrisk_factor} vector to a specified type 16 | } 17 | -------------------------------------------------------------------------------- /man/vec_ptype_abbr.tidyrisk_scenario.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidyrisk_scenario.R 3 | \name{vec_ptype_abbr.tidyrisk_scenario} 4 | \alias{vec_ptype_abbr.tidyrisk_scenario} 5 | \title{Set an abbreviation when displaying an S3 column in a tibble} 6 | \usage{ 7 | vec_ptype_abbr.tidyrisk_scenario(x) 8 | } 9 | \arguments{ 10 | \item{x}{An object} 11 | } 12 | \description{ 13 | Set an abbreviation when displaying an S3 column in a tibble 14 | } 15 | -------------------------------------------------------------------------------- /meta_tags.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /pkgdown/extra.css: -------------------------------------------------------------------------------- 1 | @import url(https://cdn.jsdelivr.net/gh/tonsky/FiraCode@1.206/distr/fira_code.css); 2 | 3 | pre, code { 4 | font-family: "Fira Code", Consolas, Inconsolata, monospace; 5 | } 6 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidski/evaluator/27d475bb06ecda7ba11feef3e219519f2d6ce404/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /renv.lock: -------------------------------------------------------------------------------- 1 | { 2 | "R": { 3 | "Version": "4.1.1", 4 | "Repositories": [ 5 | { 6 | "Name": "CRAN", 7 | "URL": "https://cran.rstudio.com" 8 | } 9 | ] 10 | }, 11 | "Packages": { 12 | "base64enc": { 13 | "Package": "base64enc", 14 | "Version": "0.1-3", 15 | "Source": "Repository", 16 | "Repository": "CRAN", 17 | "Hash": "543776ae6848fde2f48ff3816d0628bc" 18 | }, 19 | "cli": { 20 | "Package": "cli", 21 | "Version": "3.0.1", 22 | "Source": "Repository", 23 | "Repository": "CRAN", 24 | "Hash": "e3ae5d68dea0c55a12ea12a9fda02e61" 25 | }, 26 | "digest": { 27 | "Package": "digest", 28 | "Version": "0.6.28", 29 | "Source": "Repository", 30 | "Repository": "CRAN", 31 | "Hash": "49b5c6e230bfec487b8917d5a0c77cca" 32 | }, 33 | "ellipsis": { 34 | "Package": "ellipsis", 35 | "Version": "0.3.2", 36 | "Source": "Repository", 37 | "Repository": "CRAN", 38 | "Hash": "bb0eec2fe32e88d9e2836c2f73ea2077" 39 | }, 40 | "evaluate": { 41 | "Package": "evaluate", 42 | "Version": "0.14", 43 | "Source": "Repository", 44 | "Repository": "CRAN", 45 | "Hash": "ec8ca05cffcc70569eaaad8469d2a3a7" 46 | }, 47 | "fastmap": { 48 | "Package": "fastmap", 49 | "Version": "1.1.0", 50 | "Source": "Repository", 51 | "Repository": "CRAN", 52 | "Hash": "77bd60a6157420d4ffa93b27cf6a58b8" 53 | }, 54 | "glue": { 55 | "Package": "glue", 56 | "Version": "1.4.2", 57 | "Source": "Repository", 58 | "Repository": "CRAN", 59 | "Hash": "6efd734b14c6471cfe443345f3e35e29" 60 | }, 61 | "highr": { 62 | "Package": "highr", 63 | "Version": "0.9", 64 | "Source": "Repository", 65 | "Repository": "CRAN", 66 | "Hash": "8eb36c8125038e648e5d111c0d7b2ed4" 67 | }, 68 | "htmltools": { 69 | "Package": "htmltools", 70 | "Version": "0.5.2", 71 | "Source": "Repository", 72 | "Repository": "CRAN", 73 | "Hash": "526c484233f42522278ab06fb185cb26" 74 | }, 75 | "jquerylib": { 76 | "Package": "jquerylib", 77 | "Version": "0.1.4", 78 | "Source": "Repository", 79 | "Repository": "CRAN", 80 | "Hash": "5aab57a3bd297eee1c1d862735972182" 81 | }, 82 | "jsonlite": { 83 | "Package": "jsonlite", 84 | "Version": "1.7.2", 85 | "Source": "Repository", 86 | "Repository": "CRAN", 87 | "Hash": "98138e0994d41508c7a6b84a0600cfcb" 88 | }, 89 | "knitr": { 90 | "Package": "knitr", 91 | "Version": "1.36", 92 | "Source": "Repository", 93 | "Repository": "CRAN", 94 | "Hash": "46344b93f8854714cdf476433a59ed10" 95 | }, 96 | "magrittr": { 97 | "Package": "magrittr", 98 | "Version": "2.0.1", 99 | "Source": "Repository", 100 | "Repository": "CRAN", 101 | "Hash": "41287f1ac7d28a92f0a286ed507928d3" 102 | }, 103 | "purrr": { 104 | "Package": "purrr", 105 | "Version": "0.3.4", 106 | "Source": "Repository", 107 | "Repository": "CRAN", 108 | "Hash": "97def703420c8ab10d8f0e6c72101e02" 109 | }, 110 | "remotes": { 111 | "Package": "remotes", 112 | "Version": "2.4.1", 113 | "Source": "Repository", 114 | "Repository": "CRAN", 115 | "Hash": "feaca31e417db79fd1832e25b51a7717" 116 | }, 117 | "renv": { 118 | "Package": "renv", 119 | "Version": "0.13.2", 120 | "Source": "Repository", 121 | "Repository": "CRAN", 122 | "Hash": "079cb1f03ff972b30401ed05623cbe92" 123 | }, 124 | "rlang": { 125 | "Package": "rlang", 126 | "Version": "0.4.11", 127 | "Source": "Repository", 128 | "Repository": "CRAN", 129 | "Hash": "515f341d3affe0de9e4a7f762efb0456" 130 | }, 131 | "rmarkdown": { 132 | "Package": "rmarkdown", 133 | "Version": "2.11", 134 | "Source": "Repository", 135 | "Repository": "CRAN", 136 | "Hash": "320017b52d05a943981272b295750388" 137 | }, 138 | "rstudioapi": { 139 | "Package": "rstudioapi", 140 | "Version": "0.13", 141 | "Source": "Repository", 142 | "Repository": "CRAN", 143 | "Hash": "06c85365a03fdaf699966cc1d3cf53ea" 144 | }, 145 | "stringi": { 146 | "Package": "stringi", 147 | "Version": "1.7.5", 148 | "Source": "Repository", 149 | "Repository": "CRAN", 150 | "Hash": "cd50dc9b449de3d3b47cdc9976886999" 151 | }, 152 | "stringr": { 153 | "Package": "stringr", 154 | "Version": "1.4.0", 155 | "Source": "Repository", 156 | "Repository": "CRAN", 157 | "Hash": "0759e6b6c0957edb1311028a49a35e76" 158 | }, 159 | "tinytex": { 160 | "Package": "tinytex", 161 | "Version": "0.34", 162 | "Source": "Repository", 163 | "Repository": "CRAN", 164 | "Hash": "043daa786f4d254f0031534150e28d42" 165 | }, 166 | "vctrs": { 167 | "Package": "vctrs", 168 | "Version": "0.3.8", 169 | "Source": "Repository", 170 | "Repository": "CRAN", 171 | "Hash": "ecf749a1b39ea72bd9b51b76292261f1" 172 | }, 173 | "xfun": { 174 | "Package": "xfun", 175 | "Version": "0.26", 176 | "Source": "Repository", 177 | "Repository": "CRAN", 178 | "Hash": "a270216f7ffda25e53298293046d1d05" 179 | }, 180 | "yaml": { 181 | "Package": "yaml", 182 | "Version": "2.2.1", 183 | "Source": "Repository", 184 | "Repository": "CRAN", 185 | "Hash": "2826c5d9efb0a88f657c7a679c7106db" 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /renv/.gitignore: -------------------------------------------------------------------------------- 1 | local/ 2 | lock/ 3 | library/ 4 | python/ 5 | staging/ 6 | -------------------------------------------------------------------------------- /renv/settings.dcf: -------------------------------------------------------------------------------- 1 | external.libraries: 2 | ignored.packages: 3 | package.dependency.fields: Imports, Depends, LinkingTo 4 | snapshot.type: packrat 5 | use.cache: TRUE 6 | vcs.ignore.library: TRUE 7 | -------------------------------------------------------------------------------- /scripts/create_templates.R: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/r 2 | 3 | ## initialize templates 4 | 5 | message("Creating templates...") 6 | library(evaluator) 7 | create_templates("/data") 8 | message("Templates created.") 9 | 10 | -------------------------------------------------------------------------------- /scripts/deploy_scenario_explorer.R: -------------------------------------------------------------------------------- 1 | library(rsconnect) 2 | rsconnect::setAccountInfo(name = Sys.getenv("RSCONNECT_NAME"), 3 | token = Sys.getenv("RSCONNECT_TOKEN"), 4 | secret = Sys.getenv("RSCONNECT_SECRET")) 5 | 6 | # prep the test data files 7 | tmpdir <- tempdir() 8 | tmpdata <- file.path(tmpdir, "data") 9 | dir.create(tmpdata) 10 | tmpinputs <- file.path(tmpdir, "inputs") 11 | dir.create(tmpinputs, showWarnings = FALSE) 12 | 13 | data("mc_simulation_results", package = "evaluator", envir = environment()) 14 | saveRDS(mc_simulation_results, file = file.path(tmpdata, "simulation_results.rds")) 15 | 16 | res <- c("risk_tolerances.csv", "domains.csv") %>% 17 | purrr::map(~ file.copy(system.file("extdata", .x, package = "evaluator"), 18 | tmpinputs)) 19 | 20 | data("mc_quantitative_scenarios", envir = environment()) 21 | saveRDS(mc_quantitative_scenarios, file.path(tmpinputs, "quantitative_scenarios.rds")) 22 | 23 | deployApp(here::here("inst/explore_scenarios"), appName = "scenario_explorer", 24 | appTitle = "Scenario Explorer") 25 | -------------------------------------------------------------------------------- /scripts/generate_sample_reports.R: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env r 2 | 3 | # ensure devools is available 4 | if (!requireNamespace("devtools", quietly = TRUE)) remotes::install_cran("devtools") 5 | 6 | # Regenerate sample reports 7 | devtools::load_all() 8 | 9 | if (!requireNamespace("here", quietly = TRUE)) remotes::install_cran("here") 10 | 11 | tmpdir <- tempdir() 12 | tmpdata <- file.path(tmpdir, "data") 13 | dir.create(tmpdata, showWarnings = FALSE) 14 | tmpinputs <- file.path(tmpdir, "inputs") 15 | dir.create(tmpinputs, showWarnings = FALSE) 16 | 17 | output_dir <- here::here("reports") 18 | dir.create(output_dir, showWarnings = FALSE) 19 | 20 | data("mc_simulation_results", package = "evaluator", envir = environment()) 21 | saveRDS(mc_simulation_results, file = file.path(tmpdata, "simulation_results.rds")) 22 | data("mc_scenario_summary", package = "evaluator", envir = environment()) 23 | saveRDS(mc_scenario_summary, file = file.path(tmpdata, "scenario_summary.rds")) 24 | data("mc_domain_summary", package = "evaluator", envir = environment()) 25 | saveRDS(mc_domain_summary, file = file.path(tmpdata, "domain_summary.rds")) 26 | 27 | res <- c("domains.csv", "qualitative_mappings.csv", "risk_tolerances.csv") %>% 28 | purrr::map(~ file.copy(system.file("extdata", .x, package = "evaluator"), 29 | tmpinputs)) 30 | data("mc_qualitative_scenarios", envir = environment()) 31 | readr::write_csv(mc_qualitative_scenarios, file.path(tmpinputs, "qualitative_scenarios.csv")) 32 | data("mc_quantitative_scenarios", envir = environment()) 33 | saveRDS(mc_quantitative_scenarios, file.path(tmpinputs, "quantitative_scenarios.rds")) 34 | 35 | file <- file.path(output_dir, "evaluator_risk_analysis.html") 36 | 37 | generate_report(input_directory = tmpinputs, 38 | results_directory = tmpdata, 39 | output_file = file) 40 | 41 | file <- file.path(output_dir, "evaluator_risk_dashboard.html") 42 | 43 | risk_dashboard(input_directory = tmpinputs, 44 | results_directory = tmpdata, 45 | output_file = file) 46 | 47 | unlink(c(tmpdata, tmpinputs), recursive = TRUE) 48 | -------------------------------------------------------------------------------- /scripts/init.R: -------------------------------------------------------------------------------- 1 | # init.R 2 | # 3 | # Ensure packages are available for running Scenario Explorer on Heroku 4 | # 5 | 6 | my_packages = c("flexdashboard", "ggplot2", "scales", "viridis", 7 | "stringi", "dplyr", "readr", "tidyr", "modeest", "shiny", "DT") 8 | 9 | install_if_missing = function(p) { 10 | if (p %in% rownames(installed.packages()) == FALSE) { 11 | install.packages(p) 12 | } 13 | } 14 | 15 | invisible(sapply(my_packages, install_if_missing)) 16 | -------------------------------------------------------------------------------- /scripts/run.R: -------------------------------------------------------------------------------- 1 | library(rmarkdown) 2 | 3 | # Heroku-assigned port to bind 4 | port <- Sys.getenv('PORT') 5 | 6 | # Heroku app mount point 7 | setwd("/app") 8 | 9 | # run Scenario Explorer 10 | rmarkdown::run("explore_scenarios.Rmd", 11 | shiny_args = list( 12 | host = '0.0.0.0', 13 | port = as.numeric(port) 14 | ) 15 | ) 16 | -------------------------------------------------------------------------------- /scripts/run_analysis.R: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/r 2 | 3 | ## run analysis 4 | 5 | message("Running analysis...") 6 | base_dir <- "/data" 7 | source("/data/run_analysis.R", echo=FALSE) 8 | -------------------------------------------------------------------------------- /tests/spelling.R: -------------------------------------------------------------------------------- 1 | if(requireNamespace('spelling', quietly = TRUE)) 2 | spelling::spell_check_test(vignettes = TRUE, error = FALSE, 3 | skip_on_cran = TRUE) 4 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(evaluator) 3 | 4 | # ensure phantom.js is available on CI platforms 5 | if (Sys.getenv("NOT_CRAN", "") != "" || Sys.getenv("CI", "") != "") { 6 | if (!shinytest::dependenciesInstalled()) shinytest:::installDependencies() 7 | message("Using phantom.js from ", shinytest:::find_phantom(), "\n") 8 | } 9 | 10 | test_check("evaluator") 11 | -------------------------------------------------------------------------------- /tests/testthat/test-common-graphs.R: -------------------------------------------------------------------------------- 1 | test_that("Basefont selection works", { 2 | dat <- get_base_fontfamily() 3 | expect_type(dat, "character") 4 | expect_gt(nchar(dat), 1) 5 | }) 6 | test_that("Basefont returns sans when no fonts available", { 7 | mockery::stub(get_base_fontfamily, 'sysfonts::font_families', "") 8 | expect_equal(get_base_fontfamily(), "sans") 9 | }) 10 | test_that("Basefont returns Arial Narrow when available", { 11 | mockery::stub(get_base_fontfamily, 'sysfonts::font_families', "Arial Narrow") 12 | expect_equal(get_base_fontfamily(), "Arial Narrow") 13 | }) 14 | 15 | 16 | test_that("Theme functions", { 17 | gg <- theme_evaluator() 18 | expect_s3_class(gg, "gg") 19 | expect_s3_class(gg, "theme") 20 | }) 21 | 22 | test_that("Domain VaR heatmap", { 23 | data(mc_domain_summary) 24 | gg <- generate_heatmap(mc_domain_summary) 25 | expect_s3_class(gg, "gg") 26 | }) 27 | 28 | test_that("generate_scatterplot() throws a warning", { 29 | data(mc_simulation_results) 30 | expect_warning(generate_scatterplot(mc_simulation_results, scenario_id = "RS-50")) 31 | }) 32 | 33 | test_that("loss_scatterplot() functions", { 34 | data(mc_simulation_results) 35 | mc_simulation_results %>% filter(scenario_id == "RS-50") %>% 36 | unnest(.data$results) -> my_results 37 | gg <- loss_scatterplot(my_results) 38 | expect_s3_class(gg, "gg") 39 | }) 40 | 41 | test_that("Exposure histogram", { 42 | data(mc_simulation_results) 43 | gg <- mc_simulation_results %>% filter(scenario_id == "RS-50") %>% 44 | unnest(.data$results) %>% exposure_histogram() 45 | expect_s3_class(gg, "gg") 46 | }) 47 | 48 | test_that("Exposure histogram with VaR line", { 49 | data(mc_simulation_results) 50 | gg <- mc_simulation_results %>% filter(scenario_id == "RS-50") %>% 51 | unnest(.data$results) %>% exposure_histogram(show_var_95 = TRUE) 52 | expect_s3_class(gg, "gg") 53 | }) 54 | 55 | test_that("Domain-level outcomes", { 56 | data(mc_domain_summary) 57 | gg <- generate_event_outcomes_plot(mc_domain_summary) 58 | expect_s3_class(gg, "gg") 59 | }) 60 | 61 | test_that("Loss_exceedance_curve", { 62 | data("mc_simulation_results") 63 | gg <- summarize_iterations(mc_simulation_results$results) %>% 64 | loss_exceedance_curve() 65 | expect_s3_class(gg, "gg") 66 | }) 67 | -------------------------------------------------------------------------------- /tests/testthat/test-encode.R: -------------------------------------------------------------------------------- 1 | context("Encodings") 2 | test_that("Scenario Encoding", { 3 | qualitative_scenarios <- data.frame(scenario_id = 1:2, 4 | scenario = c("Scenario A.", "Scenario B."), 5 | tcomm = c("Organizational Leadership", "Organizational Leadership"), 6 | tef = c("frequent", "frequent"), 7 | tc = c("medium", "medium"), 8 | lm = c("medium", "medium"), 9 | domain_id = c("ORG", "ORG"), 10 | controls = c("1, 5, 7, 32, 14", 11 | "14, 15, 16"), 12 | stringsAsFactors = FALSE) 13 | capabilities <- data.frame(capability_id = c(1L, 5L, 7L, 32L, 14L, 15L, 16L), 14 | domain_id = c("ORG", "ORG", "ORG", "ORG", "ORG", "ORG", "ORG"), 15 | capability = c("Capability 1.", "Capability 5.", "Capability 7", "Capability 32.", "Capability 14.", "Capability 15.", "Capability 16."), 16 | diff = c("5 - Optimized", "4 - Managed", "1 - Initial", "4 - Managed", "4 - Managed", "2 - Repeatable", "2 - Repeatable"), 17 | stringsAsFactors = FALSE) 18 | mappings <- data.frame(type = c("tef", "tef", "tef", "tc", "tc", "tc", "diff", "diff", "diff", "diff", "diff", "lm", "lm", "lm"), 19 | label = c("frequent", "occasional", "rare", "high", "medium", "low", "5 - Optimized", "4 - Managed", "3 - Defined", "2 - Repeatable", "1 - Initial", "high", "medium", "low"), 20 | l = c(10L, 1L, 0L, 50L, 33L, 0L, 70L, 50L, 33L, 20L, 0L, 1000000L, 10000L, 100L), 21 | ml = c(24, 6, 0.1, 75, 50, 16, 85, 70, 50, 30, 10, 2e+06, 20000, 200), 22 | h = c(52L, 12L, 1L, 98L, 60L, 30L, 98L, 84L, 60L, 50L, 30L, 5000000L, 500000L, 10000L), 23 | conf = c(4L, 4L, 4L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 1L), 24 | stringsAsFactors = FALSE) 25 | dat <- encode_scenarios(qualitative_scenarios, capabilities, mappings) 26 | expect_equal(nrow(dat), 2) 27 | expect_true(is.data.frame(dat)) 28 | }) 29 | test_that("Control Encoding", { 30 | capability_ids <- "1, 7" 31 | capabilities <- data.frame(capability_id = c(1L, 5L, 7L, 32L, 14L, 15L, 16L), 32 | domain_id = c("ORG", "ORG", "ORG", "ORG", "ORG", "ORG", "ORG"), 33 | capability = c("Capability 1.", "Capability 5.", "Capability 7.", "Capability 32.", "Capability 14.", "Capability 15.", "Capability 16."), 34 | diff = c("5 - Optimized", "4 - Managed", "1 - Initial", "4 - Managed", "4 - Managed", "2 - Repeatable", "2 - Repeatable"), 35 | stringsAsFactors = FALSE) 36 | mappings <- data.frame(type = c("diff", "diff"), label = c("5 - Optimized", "1 - Initial"), 37 | l = c(70, 0), ml = c(80, 20), h = c(95, 30), 38 | conf = 3, stringsAsFactors = FALSE) 39 | dat <- derive_controls(capability_ids, capabilities, mappings) 40 | expect_type(dat, "list") 41 | expect_named(dat, c("1", "7")) 42 | expect_equal(length(dat), 2) 43 | }) 44 | 45 | test_that("Control ID Mappings", { 46 | capability_ids <- "1, 7" 47 | capabilities <- data.frame(capability_id = c(1L, 5L, 7L, 32L, 14L, 15L, 16L), 48 | domain_id = c("ORG", "ORG", "ORG", "ORG", "ORG", "ORG", "ORG"), 49 | capability = c("Capability 1.", "Capability 5.", "Capability 7.", "Capability 32.", "Capability 14.", "Capability 15.", "Capability 16."), 50 | diff = c("5 - Optimized", "4 - Managed", "1 - Initial", "4 - Managed", "4 - Managed", "2 - Repeatable", "2 - Repeatable"), 51 | stringsAsFactors = FALSE) 52 | dat <- derive_control_key(capability_ids, capabilities) 53 | expect_type(dat, "list") 54 | expect_named(dat, c("1", "7")) 55 | expect_equal(length(dat), 2) 56 | }) 57 | -------------------------------------------------------------------------------- /tests/testthat/test-explore-scenarios.R: -------------------------------------------------------------------------------- 1 | context("Scenario Explorer") 2 | # This file is for testing the applications in the apps/ directory. 3 | 4 | library(shinytest) 5 | 6 | 7 | test_that("explore_scenarios() works", { 8 | # Don't run these tests on the CRAN build servers 9 | skip_on_cran() 10 | 11 | # unsure how to pass parameters to a shiny flexdashboard 12 | skip("Shinytest scaffolding is not complete") 13 | 14 | # prep the test data files 15 | tmpdir <- tempdir() 16 | tmpdata <- file.path(tmpdir, "data") 17 | dir.create(tmpdata) 18 | tmpinputs <- file.path(tmpdir, "inputs") 19 | dir.create(tmpinputs, showWarnings = FALSE) 20 | 21 | data("mc_simulation_results", package = "evaluator", envir = environment()) 22 | saveRDS(mc_simulation_results, file = file.path(tmpdata, "simulation_results.rds")) 23 | 24 | res <- c("risk_tolerances.csv") %>% 25 | purrr::map(~ file.copy(system.file("extdata", .x, package = "evaluator"), 26 | tmpinputs)) 27 | 28 | data("mc_quantitative_scenarios", envir = environment()) 29 | saveRDS(mc_quantitative_scenarios, file.path(tmpinputs, "quantitative_scenarios.rds")) 30 | 31 | # Use compareImages=FALSE because the expected image screenshots were created 32 | # on a Mac, and they will differ from screenshots taken on the CI platform, 33 | # which runs on Linux. 34 | appdir <- system.file(package = "evaluator", "explore_scenarios") 35 | expect_pass(testApp(appdir, compareImages = FALSE)) 36 | unlink(c(tmpdata, tmpinputs), recursive = TRUE) 37 | }) 38 | 39 | -------------------------------------------------------------------------------- /tests/testthat/test-import.R: -------------------------------------------------------------------------------- 1 | context("Spreadsheet imports") 2 | test_that("Default scenarios import", { 3 | data(mc_domains) 4 | scenarios <- import_scenarios(domains = mc_domains) 5 | expect_equal(nrow(scenarios), 56) 6 | expect_equal(length(scenarios), 8) 7 | }) 8 | test_that("Scenarios import succeeds when using defaults", { 9 | data(mc_qualitative_scenarios) 10 | expect_equal(import_scenarios(), mc_qualitative_scenarios) 11 | }) 12 | test_that("Scenarios import fails when given bad input file", { 13 | expect_error(import_scenarios(survey_file = "/bad/nonexistant/file", "survey")) 14 | }) 15 | 16 | test_that("Default capabilities import", { 17 | data(mc_domains) 18 | dat <- import_capabilities(domains = mc_domains) 19 | expect_equal(nrow(dat), 60) 20 | expect_equal(length(dat), 4) 21 | }) 22 | test_that("Capabilities import fails when given bad input file", { 23 | expect_error(import_capabilities(survey_file = "/bad/nonexistant/file", "survey")) 24 | }) 25 | test_that("Capabilities import succeeds when using defaults", { 26 | data("mc_capabilities", envir = .GlobalEnv) 27 | src <- get("mc_capabilities", envir = .GlobalEnv) 28 | dat <- import_capabilities() 29 | expect_equal(dat, src) 30 | }) 31 | 32 | test_that("Higher-level import_spreadsheet functions", { 33 | dat <- import_spreadsheet(output_dir = tempdir()) 34 | expect_equal(nrow(dat), 2) 35 | }) 36 | test_that("Spreadsheet import fails when given bad output directory", { 37 | expect_error(import_spreadsheet(output_dir = "/bad/nonexistant/path", "output")) 38 | }) 39 | -------------------------------------------------------------------------------- /tests/testthat/test-load-data.R: -------------------------------------------------------------------------------- 1 | context("Data Loads") 2 | tmpdir <- tempdir() 3 | tmpdata <- file.path(tmpdir, "data") 4 | dir.create(tmpdata) 5 | tmpinputs <- file.path(tmpdir, "inputs") 6 | dir.create(tmpinputs, showWarnings = FALSE) 7 | 8 | data("mc_simulation_results", package = "evaluator", envir = environment()) 9 | saveRDS(mc_simulation_results, file = file.path(tmpdata, "simulation_results.rds")) 10 | data("mc_scenario_summary", package = "evaluator", envir = environment()) 11 | saveRDS(mc_scenario_summary, file = file.path(tmpdata, "scenario_summary.rds")) 12 | data("mc_domain_summary", package = "evaluator", envir = environment()) 13 | saveRDS(mc_domain_summary, file = file.path(tmpdata, "domain_summary.rds")) 14 | 15 | data("mc_capabilities", package = "evaluator", envir = environment()) 16 | readr::write_csv(mc_capabilities, file.path(tmpinputs, "capabilities.csv")) 17 | 18 | 19 | res <- c("domains.csv", "qualitative_mappings.csv", "risk_tolerances.csv") %>% 20 | purrr::map(~ file.copy(system.file("extdata", .x, package = "evaluator"), 21 | tmpinputs)) 22 | data("mc_qualitative_scenarios", envir = environment()) 23 | saveRDS(mc_qualitative_scenarios, file = file.path(tmpinputs, "qualitative_scenarios.rds")) 24 | readr::write_csv(mc_qualitative_scenarios, file.path(tmpinputs, "qualitative_scenarios.csv")) 25 | data("mc_quantitative_scenarios", envir = environment()) 26 | saveRDS(mc_quantitative_scenarios, file.path(tmpinputs, "quantitative_scenarios.rds")) 27 | 28 | test_that("Template files can be copied", { 29 | tmpdata <- file.path(tempdir(), "templates") 30 | dir.create(tmpdata, showWarnings = FALSE) 31 | res <- create_templates(tmpdata) 32 | expect_equal(sum(res$copied), 5) 33 | unlink(tmpdata, recursive = TRUE) 34 | }) 35 | 36 | test_that("Deprecated load data function works", { 37 | expect_warning(load_data(tmpinputs, tmpdata)) 38 | }) 39 | 40 | test_that("Qualitative inputs can be loaded",{ 41 | dat <- read_qualitative_inputs(tmpinputs) 42 | expect_is(dat, "list") 43 | }) 44 | 45 | test_that("Quantitative inputs can be loaded", { 46 | dat <- read_quantitative_inputs(tmpinputs) 47 | expect_is(dat, "list") 48 | }) 49 | 50 | unlink(c(tmpdata, tmpinputs), recursive = TRUE) 51 | -------------------------------------------------------------------------------- /tests/testthat/test-openfair-example.R: -------------------------------------------------------------------------------- 1 | context("OpenFAIR Example Shiny app") 2 | 3 | library(shinytest) 4 | 5 | test_that("openfairExample() works", { 6 | skip("Shiny testing is awkward, consider moving to stand alone pkg") 7 | 8 | # Don't run these tests on the CRAN build servers 9 | skip_on_cran() 10 | 11 | skip_if_not(rmarkdown::pandoc_available(), 12 | message = "Cannot run shinytest without pandoc available.") 13 | 14 | # Don't run on r-devel, which behaves badly on TravisCI 15 | skip_if(grepl("unstable", R.version.string), 16 | message = "Shinytest gives unpredictable results on R-devel") 17 | 18 | # Use compareImages=FALSE because the expected image screenshots were created 19 | # on a Mac, and they will differ from screenshots taken on the CI platform, 20 | # which runs on Linux. 21 | appdir <- system.file(package = "evaluator", "openfair_example") 22 | 23 | expect_pass(testApp(appdir, compareImages = FALSE)) 24 | }) 25 | -------------------------------------------------------------------------------- /tests/testthat/test-reports.R: -------------------------------------------------------------------------------- 1 | context("Reports") 2 | tmpdir <- tempdir(check = TRUE) 3 | tmpdata <- file.path(tmpdir, "data") 4 | dir.create(tmpdata) 5 | tmpinputs <- file.path(tmpdir, "inputs") 6 | dir.create(tmpinputs, showWarnings = FALSE) 7 | 8 | data("mc_simulation_results", package = "evaluator", envir = environment()) 9 | saveRDS(mc_simulation_results, file = file.path(tmpdata, "simulation_results.rds")) 10 | data("mc_scenario_summary", package = "evaluator", envir = environment()) 11 | saveRDS(mc_scenario_summary, file = file.path(tmpdata, "scenario_summary.rds")) 12 | data("mc_domain_summary", package = "evaluator", envir = environment()) 13 | saveRDS(mc_domain_summary, file = file.path(tmpdata, "domain_summary.rds")) 14 | 15 | res <- c("domains.csv", "qualitative_mappings.csv", "risk_tolerances.csv") %>% 16 | purrr::map(~ file.copy(system.file("extdata", .x, package = "evaluator"), 17 | tmpinputs)) 18 | data("mc_qualitative_scenarios", envir = environment()) 19 | write.csv(mc_qualitative_scenarios, file = file.path(tmpinputs, "qualitative_scenarios.csv"), 20 | row.names = FALSE) 21 | data("mc_quantitative_scenarios", envir = environment()) 22 | saveRDS(mc_quantitative_scenarios, file.path(tmpinputs, "quantitative_scenarios.rds")) 23 | 24 | 25 | test_that("Analyze report renders", { 26 | 27 | skip_if_not(rmarkdown::pandoc_available(), 28 | message = "Cannot test report generation without pandoc available.") 29 | purrr::walk(c("psych", "pander", "rmarkdown"), 30 | ~ skip_if_not_installed(.)) 31 | 32 | file <- tempfile(fileext = ".html") 33 | 34 | result <- evaluate_promise(generate_report(input_directory = tmpinputs, 35 | results_directory = tmpdata, 36 | output_file = file, 37 | quiet = FALSE)) 38 | expect_equivalent(normalizePath(result$result), normalizePath(file)) 39 | unlink(file) 40 | }) 41 | 42 | test_that("Risk Dashboard renders", { 43 | 44 | skip_if_not(rmarkdown::pandoc_available(), 45 | message = "Cannot test dashboard generation without pandoc available.") 46 | purrr::walk(c("rmarkdown", "shiny", "flexdashboard", "forcats"), 47 | ~ skip_if_not_installed(.)) 48 | 49 | file <- tempfile(fileext = ".html") 50 | 51 | result <- evaluate_promise(risk_dashboard(input_directory = tmpinputs, 52 | results_directory = tmpdata, 53 | output_file = file, 54 | quiet = FALSE)) 55 | expect_equivalent(normalizePath(result$result), normalizePath(file)) 56 | # there should be no warnings 57 | expect_condition(result$warnings, regexp = NA) 58 | unlink(file) 59 | }) 60 | 61 | unlink(c(tmpdata, tmpinputs), recursive = TRUE) 62 | -------------------------------------------------------------------------------- /tests/testthat/test-run-analysis.R: -------------------------------------------------------------------------------- 1 | context("Analysis Script") 2 | 3 | tmpdir <- tempdir() 4 | tmpwork <- file.path(tmpdir, "analysis") 5 | 6 | test_that("Minimum Viable Analysis script works", { 7 | 8 | # this is expensive to run, skip if the EVALUATOR_TEST_MVA envvar is not set 9 | skip_if_not(Sys.getenv("EVALUATOR_TEST_MVA") == TRUE, 10 | "Not running MVA test - EVALUATOR_TEST_MVA not set") 11 | 12 | create_templates(tmpwork) 13 | base_dir <- tmpwork 14 | source(system.file("run_analysis.R", package = "evaluator"), local = TRUE) 15 | expect_equivalent(file.exists(file.path(base_dir, "results", "risk_dashboard.html")), TRUE) 16 | expect_equivalent(file.exists(file.path(base_dir, "results", "risk_report.docx")), TRUE) 17 | }) 18 | 19 | unlink(tmpwork, recursive = TRUE) 20 | -------------------------------------------------------------------------------- /tests/testthat/test-simulate.R: -------------------------------------------------------------------------------- 1 | context("Simulation-Model Interface") 2 | 3 | # Simulation-Model Interface ---------------------------------------------- 4 | 5 | test_that("Simulation fails when given a simulation_count", { 6 | data("mc_quantitative_scenarios") 7 | good_scen <- mc_quantitative_scenarios$scenario[[1]] 8 | expect_error(run_simulation(good_scen, simulation_count = 10L), regexp = "iteration") 9 | }) 10 | 11 | test_that("Simulation fails when not given a scenario object", { 12 | data("mc_quantitative_scenarios") 13 | bad_scen <- mc_quantitative_scenarios$scenario[[1]] 14 | class(bad_scen) <- "list" 15 | expect_error(run_simulation(bad_scen, 10L), regexp = "object") 16 | }) 17 | 18 | test_that("Simulation respects maximum ALE", { 19 | data("mc_quantitative_scenarios") 20 | good_scen <- mc_quantitative_scenarios$scenario[[1]] 21 | results <- run_simulation(good_scen, 10L, ale_maximum = 100) 22 | expect_lte(max(results$ale), 100) 23 | }) 24 | 25 | test_that("Missing mandatory OpenFAIR factors are detected", { 26 | data("mc_quantitative_scenarios") 27 | bad_scen <- mc_quantitative_scenarios$scenario[[1]] 28 | bad_scen$parameters$tef <- NULL 29 | expect_error(run_simulation(bad_scen, 10L), regexp = "Missing") 30 | }) 31 | 32 | test_that("Bad scenario parameters throw an error", { 33 | data("mc_quantitative_scenarios") 34 | bad_scen <- mc_quantitative_scenarios$scenario[[1]] 35 | bad_scen$parameters$tef$func <- "stats::rlnorm" 36 | expect_error(run_simulation(bad_scen, 10L), regexp = "Error") 37 | }) 38 | 39 | test_that("Simulating multiple scenarios succeeds", { 40 | data("mc_quantitative_scenarios") 41 | scenarios <- mc_quantitative_scenarios[1:3, ]$scenario 42 | results <- run_simulations(scenarios[[1]], scenarios[[2]], scenarios[[3]], iterations = 10L) 43 | expect_is(results, "list") 44 | }) 45 | 46 | test_that("Multiple simulations run fails when not given a scenario object", { 47 | data("mc_quantitative_scenarios") 48 | bad_scen <- mc_quantitative_scenarios$scenario[[1]] 49 | class(bad_scen) <- "list" 50 | expect_error(run_simulations(bad_scen, iterations = 10L), regexp = "object") 51 | }) 52 | 53 | test_that("Multiple simulations deprecates the simulation_count parameters", { 54 | data("mc_quantitative_scenarios") 55 | good_scen <- mc_quantitative_scenarios$scenario[[1]] 56 | expect_error(run_simulations(good_scen, simulation_count = 10L), regexp = "iteration") 57 | }) 58 | -------------------------------------------------------------------------------- /tests/testthat/test-summarize.R: -------------------------------------------------------------------------------- 1 | context("Summarization") 2 | test_that("Simulation summary", { 3 | data("mc_simulation_results") 4 | data("mc_scenario_summary") 5 | summarized_scenarios <- summarize_scenarios(mc_simulation_results) 6 | expect_equivalent(as.data.frame(summarized_scenarios), 7 | as.data.frame(mc_scenario_summary), 8 | tolerance = .01) 9 | }) 10 | test_that("Scenario summary rejects non dataframe inputs", { 11 | data("mc_simulation_results") 12 | expect_error(summarize_scenario(mc_simulation_results$results), regexp = "dataframe") 13 | }) 14 | 15 | test_that("Simulation summary handles NAs for tc/diff exceedance", { 16 | data("mc_simulation_results") 17 | mc_simulation_results[[1, "results"]][[1]]$mean_tc_exceedance <- NA 18 | #simulation_results[1, "mean_tc_exceedance"] <- NA 19 | mc_simulation_results[[10, "results"]][[1]]$mean_diff_exceedance <- NA 20 | dat <- mutate(mc_simulation_results, 21 | result_summary = map(results, summarize_scenario)) %>% 22 | select(-results) 23 | summarized_tc_exceedance <- dplyr::filter(dat, scenario_id == "RS-18") %>% 24 | tidyr::unnest(result_summary) %>% 25 | dplyr::pull(mean_tc_exceedance) 26 | expect_gt(summarized_tc_exceedance, 0) 27 | }) 28 | 29 | test_that("Iteration-level summary", { 30 | data("mc_simulation_results") 31 | summarized_iterations <- summarize_iterations(mc_simulation_results$results) 32 | expect_lte(max(summarized_iterations$mean_tc_exceedance), 1) 33 | expect_gte(min(summarized_iterations$mean_tc_exceedance), 0) 34 | expect_lte(max(summarized_iterations$mean_diff_exceedance), 1) 35 | expect_gte(min(summarized_iterations$mean_diff_exceedance), 0) 36 | }) 37 | 38 | test_that("Domain summary", { 39 | data("mc_simulation_results") 40 | data("mc_domain_summary") 41 | 42 | summarized_domains <- summarize_domains(mc_simulation_results) 43 | 44 | expect_equivalent(as.data.frame(summarized_domains), 45 | as.data.frame(mc_domain_summary), tolerance = 0.01) 46 | }) 47 | test_that("Domain summary rejects non dataframe inputs", { 48 | data("mc_simulation_results") 49 | expect_error(summarize_domains(mc_simulation_results$results), regexp = "dataframe") 50 | }) 51 | 52 | test_that("Summarize to disk", { 53 | tmpdata <- file.path(tempdir(), "data") 54 | dir.create(tmpdata) 55 | 56 | result <- summarize_to_disk(evaluator::mc_simulation_results, 57 | results_dir = tmpdata) 58 | expect_equal(nrow(result), 2) 59 | unlink(tmpdata, recursive = TRUE) 60 | }) 61 | 62 | test_that("Summarize to disk - non-existant directory", { 63 | tmpdata <- file.path(tempdir(), "data") 64 | 65 | result <- summarize_to_disk(evaluator::mc_simulation_results, 66 | results_dir = tmpdata) 67 | expect_equal(nrow(result), 2) 68 | unlink(tmpdata, recursive = TRUE) 69 | }) 70 | 71 | -------------------------------------------------------------------------------- /tests/testthat/test-test-tidyrisk-factor.R: -------------------------------------------------------------------------------- 1 | context("Tidyrisk Factor class") 2 | 3 | test_that("Element object can be created", { 4 | element <- tidyrisk_factor(NA, factor_label = "TF") 5 | expect_s3_class(element, "tidyrisk_factor") 6 | 7 | }) 8 | test_that("Element object does not accept invalid OpenFAIR types", { 9 | expect_error(tidyrisk_factor(NA, factor_label = "ZZGO")) 10 | }) 11 | 12 | test_that("Element object summary functions without samples", { 13 | element <- tidyrisk_factor(NA, factor_label = "LM") 14 | expect_is(summary(element), "list") 15 | }) 16 | test_that("Element object summary functions with samples", { 17 | element <- tidyrisk_factor(c(1, 100), factor_label = "LM") 18 | expect_is(summary(element), "list") 19 | }) 20 | test_that("Element object summary functions on non LM types", { 21 | element <- tidyrisk_factor(c(1, 100), factor_label = "TC") 22 | expect_is(summary(element), "list") 23 | }) 24 | 25 | test_that("Factors can be logically compared", { 26 | tc_element <- tidyrisk_factor(c(10, 40, 100), factor_label = "TC") 27 | diff_element <- tidyrisk_factor(c(10, 30, 100), factor_label = "DIFF") 28 | }) 29 | -------------------------------------------------------------------------------- /tests/testthat/test-tidyrisk-scenario.R: -------------------------------------------------------------------------------- 1 | context("Tidyrisk Scenario class") 2 | test_that("Scenario object can be created and coerced to tibble", { 3 | tidyrisk_scenario( 4 | diff_params = list(list( 5 | "2" = list(min = 70L, mode = 85, max = 98L, shape = 4L, func = "mc2d::rpert"), 6 | "5" = list(min = 50L, mode = 70, max = 84L, shape = 4L, func = "mc2d::rpert"), 7 | "7" = list(min = 20L, mode = 30, max = 50L, shape = 4L, func = "mc2d::rpert"), 8 | "32" = list(min = 20L, mode = 30, max = 50L, shape = 4L, func = "mc2d::rpert"), 9 | "14" = list(min = 50L, mode = 70, max = 84L, shape = 4L, func = "mc2d::rpert"), 10 | "15" = list(min = 50L, mode = 70, max = 84L, shape = 4L, func = "mc2d::rpert"), 11 | "16" = list(min = 0L, mode = 10, max = 30L, shape = 4L, func = "mc2d::rpert") 12 | )), 13 | tef_params = list(list(min = 10L, mode = 24, max = 52L, shape = 4L, func = "mc2d::rpert")), 14 | tc_params = list(list(min = 33L, mode = 50, max = 60L, shape = 3L, func = "mc2d::rpert")), 15 | lm_params = list(list(min = 10000L, mode = 20000, max = 500000L, shape = 4L, 16 | func = "mc2d::rpert")) 17 | ) -> scenario 18 | expect_s3_class(scenario, "tidyrisk_scenario") 19 | expect_s3_class(as_tibble(scenario), "tbl") 20 | }) 21 | 22 | test_that("Unnamed parameters throw errors", { 23 | expect_error(tidyrisk_scenario( 24 | diff_params = list(list( 25 | "2" = list(min = 70L, mode = 85, max = 98L, shape = 4L, func = "mc2d::rpert"), 26 | "5" = list(min = 50L, mode = 70, max = 84L, shape = 4L, func = "mc2d::rpert"), 27 | "7" = list(min = 20L, mode = 30, max = 50L, shape = 4L, func = "mc2d::rpert"), 28 | "32" = list(min = 20L, mode = 30, max = 50L, shape = 4L, func = "mc2d::rpert"), 29 | "14" = list(min = 50L, mode = 70, max = 84L, shape = 4L, func = "mc2d::rpert"), 30 | "15" = list(min = 50L, mode = 70, max = 84L, shape = 4L, func = "mc2d::rpert"), 31 | "16" = list(min = 0L, mode = 10, max = 30L, shape = 4L, func = "mc2d::rpert") 32 | )), 33 | list(list(min = 10L, mode = 24, max = 52L, shape = 4L, func = "mc2d::rpert")), 34 | tc_params = list(list(min = 33L, mode = 50, max = 60L, shape = 3L, func = "mc2d::rpert")), 35 | lm_params = list(list(min = 10000L, mode = 20000, max = 500000L, shape = 4L, 36 | func = "mc2d::rpert"))), 37 | "unnamed") 38 | }) 39 | -------------------------------------------------------------------------------- /tests/testthat/test-utils.R: -------------------------------------------------------------------------------- 1 | context("Utilities") 2 | test_that("Missing packages are detected", { 3 | expect_error(check_availability(packages = c("ggplot2", "Missing"), func = "test"), 4 | "available: Missing") 5 | }) 6 | test_that("Found packages are detected silently", { 7 | expect_silent(check_availability(packages = c("stats"), func = "test")) 8 | }) 9 | 10 | test_that("Dollar Millions formats as expected", { 11 | expect_equal(dollar_millions(1.523 * 10^6), "$1.52M") 12 | }) 13 | 14 | test_that("Calculate max losses", { 15 | data("mc_simulation_results") 16 | dat <- calculate_max_losses(mc_simulation_results, c(1, 10)) 17 | expect_s3_class(dat, "data.frame") 18 | expect_equal(nrow(dat[dat$outliers == TRUE, ]), 1000) 19 | expect_equal(nrow(dat), 2000) 20 | }) 21 | 22 | test_that("calculate_max_losses handles NULL outliers", { 23 | data("mc_simulation_results") 24 | dat <- calculate_max_losses(mc_simulation_results) 25 | expect_s3_class(dat, "data.frame") 26 | expect_equal(nrow(dat), 1000) 27 | }) 28 | 29 | test_that("identify_outliers() identifies the expected number of outliers", { 30 | data("mc_scenario_summary") 31 | dat <- identify_outliers(mc_scenario_summary) 32 | expect_equal(sum(dat$outlier), 4) 33 | }) 34 | -------------------------------------------------------------------------------- /tests/testthat/test-validate.R: -------------------------------------------------------------------------------- 1 | context("Validation") 2 | qualitative_scenarios <- data.frame(scenario_id = c("1", "2"), 3 | scenario = c("Scenario A.", "Scenario B."), 4 | tcomm = c("Organizational Leadership", "Organizational Leadership"), 5 | tef = c("frequent", "frequent"), 6 | tc = c("medium", "medium"), 7 | lm = c("medium", "medium"), 8 | domain_id = c("ORG", "ORG"), 9 | controls = c("1, 5, 7, 32, 14", 10 | "14, 15, 16"), 11 | stringsAsFactors = FALSE) 12 | capabilities <- data.frame(capability_id = c("1", "5", "7", "32", "14", "15", "16"), 13 | domain_id = c("ORG", "ORG", "ORG", "ORG", "ORG", "ORG", "ORG"), 14 | capability = c("Capability 1.", "Capability 5.", "Capability 7", "Capability 32.", "Capability 14.", "Capability 15.", "Capability 16."), 15 | diff = c("5 - Optimized", "4 - Managed", "1 - Initial", "4 - Managed", "4 - Managed", "2 - Repeatable", "2 - Repeatable"), 16 | stringsAsFactors = FALSE) 17 | mappings <- data.frame(type = c("tef", "tef", "tef", "tc", "tc", "tc", "diff", "diff", "diff", "diff", "diff", "lm", "lm", "lm"), 18 | label = c("frequent", "occasional", "rare", "high", "medium", "low", "5 - Optimized", "4 - Managed", "3 - Defined", "2 - Repeatable", "1 - Initial", "high", "medium", "low"), 19 | l = c(10L, 1L, 0L, 50L, 33L, 0L, 70L, 50L, 33L, 20L, 0L, 1000000L, 10000L, 100L), 20 | ml = c(24, 6, 0.1, 75, 50, 16, 85, 70, 50, 30, 10, 2e+06, 20000, 200), 21 | h = c(52L, 12L, 1L, 98L, 60L, 30L, 98L, 84L, 60L, 50L, 30L, 5000000L, 500000L, 10000L), 22 | conf = c(4L, 4L, 4L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 1L), 23 | stringsAsFactors = FALSE) 24 | 25 | test_that("Duplicate scenarios detected", { 26 | qualitative_scenarios <- data.frame(scenario_id = c("1", "1"), 27 | scenario = c("Scenario A.", "Scenario B."), 28 | tcomm = c("Organizational Leadership", "Organizational Leadership"), 29 | tef = c("frequent", "frequent"), 30 | tc = c("medium", "medium"), 31 | lm = c("medium", "medium"), 32 | domain_id = c("ORG", "ORG"), 33 | controls = c("1, 5, 7, 32, 14", 34 | "14, 15, 16"), 35 | stringsAsFactors = FALSE) 36 | expect_warning(validate_scenarios(qualitative_scenarios, capabilities, domains, mappings), 37 | regexp = "Duplicate scenarios") 38 | }) 39 | test_that("Duplicate capabilities detected", { 40 | capabilities <- data.frame(capability_id = c("1", "5", "5", "32", "14", "15", "16"), 41 | domain_id = c("ORG", "ORG", "ORG", "ORG", "ORG", "ORG", "ORG"), 42 | capability = c("Capability 1.", "Capability 5.", "Capability 7", "Capability 32.", "Capability 14.", "Capability 15.", "Capability 16."), 43 | diff = c("5 - Optimized", "4 - Managed", "1 - Initial", "4 - Managed", "4 - Managed", "2 - Repeatable", "2 - Repeatable"), 44 | stringsAsFactors = FALSE) 45 | expect_warning(validate_scenarios(qualitative_scenarios, capabilities, domains, mappings), 46 | regexp = "Duplicate capabilities") 47 | }) 48 | 49 | 50 | test_that("Invalid TEF labels are handled", { 51 | data(mc_capabilities, mc_qualitative_scenarios) 52 | bad_scenarios <- mc_qualitative_scenarios 53 | bad_scenarios[1, "tef"] <- "invalid" 54 | expect_warning(validate_scenarios(bad_scenarios, mc_capabilities, domains, mappings), 55 | regexp = "qualitative TEF") 56 | 57 | }) 58 | 59 | test_that("Invalid TC labels are handled", { 60 | data(mc_capabilities, mc_qualitative_scenarios) 61 | bad_scenarios <- mc_qualitative_scenarios 62 | bad_scenarios[1, "tc"] <- "invalid" 63 | expect_warning(validate_scenarios(bad_scenarios, mc_capabilities, domains, mappings), 64 | regexp = "qualitative TC") 65 | 66 | }) 67 | 68 | test_that("Invalid DIFF labels are handled", { 69 | data(mc_capabilities, mc_qualitative_scenarios) 70 | bad_capabilities <- mc_capabilities 71 | bad_capabilities[1, "diff"] <- "invalid" 72 | expect_warning(validate_scenarios(mc_qualitative_scenarios, bad_capabilities, domains, mappings), 73 | regexp = "qualitative DIFF") 74 | 75 | }) 76 | 77 | test_that("Invalid LMs labels are handled", { 78 | data(mc_capabilities, mc_qualitative_scenarios) 79 | bad_scenarios <- mc_qualitative_scenarios 80 | bad_scenarios[1, "lm"] <- "invalid" 81 | expect_warning(validate_scenarios(bad_scenarios, mc_capabilities, domains, mappings), 82 | regexp = "qualitative LM") 83 | 84 | }) 85 | -------------------------------------------------------------------------------- /vignettes/customization.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Advanced Customization" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Advanced Customization} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | Evaluator makes several assumptions to get you up and running as quickly as 11 | possible. Advanced users may implement several different customizations 12 | including: 13 | 14 | ## Parameters 15 | 16 | - Risk tolerances - Organizational risk tolerances at a "medium" and "high" 17 | level are defined in `inputs/risk_tolerances.csv`. Risk tolerances are the 18 | aggregate economic loss thresholds defined by your organization. These are not 19 | necessarily the same as the size of potential losses from individual 20 | scenarios. A good proxy for risk tolerance is the budget authority implemented 21 | in your organization. The size of purchase signoff required at the executive 22 | level is generally a good indicator of the minimum floor for high risk 23 | tolerance. 24 | - Qualitative mappings - The translation of qualitative labels such as 25 | "Frequent" threat events and "Optimized" controls are defined in 26 | `inputs/qualitative_mappings.csv`. The values in this mapping may be changed 27 | but they must use lowercase and agree with the values used in the survey 28 | spreadsheet. Changing the number of levels used for any qualitative label 29 | (e.g. changing High/Medium/Low to High/Medium/Low/VeryLow) is possible as long 30 | as the survey spreadsheet uses the same labels. 31 | - The survey spreadsheet uses data validation to populate drop downs. If you 32 | change the mappings, the validation will need to be updated or removed to 33 | agree with your new mappings. 34 | 35 | ## Report Customization 36 | 37 | If you would rather work on the source RMarkdown file or direct editing and 38 | graphics tweaking, use `system.file("rmd, "analyze_risk.Rmd", package = "evaluator")` 39 | to find the location of the native template on your system. 40 | 41 | - Styling - Look and feel (fonts, colors, etc.) is defined in the 42 | `styles/html-styles.css` and `styles/word-styles-reference.docx` files. 43 | -------------------------------------------------------------------------------- /vignettes/process.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "An Evaluator-driven Risk Management Process" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{An Evaluator-driven Risk Management Process} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r setup, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | Working notes for building a risk assessment process using the Evaluator 18 | toolkit. This vignette details the basic flow used at some organizations to 19 | maintain reproducability of inputs and results. While other technologies and 20 | solutions may be employed, this workflow is intended to be easy to implement 21 | for users familiar with source control principles. 22 | 23 | ## Starting from Scratch 24 | 25 | - Create a starting Evaluator working directory via `create_templates()` 26 | - Customize the domains used in your organization by editing the `domains.csv` 27 | file to include the domains (and their abbreviations) which are appropriate for your 28 | risk domain and organization. 29 | - Edit the `survey.xlsx` spreadsheet to include the risk scenarios and the threats 30 | for each scenario which you wish to monitor on an ongoing basis. 31 | - Create a source code repository (such as a GitHub for Enterprise repo) for 32 | your ongoing risk analysis work. 33 | - Add a tag to designate the just committed files (without analysis) as your reference 34 | documentation. 35 | 36 | ## Performing an Analysis 37 | - Meet with subject matter experts for each domain and walk through each 38 | scenario and threat source. 39 | - Record answers in the survey.xlsx spreadsheet. 40 | - Run the analysis as detailed in the [usage](usage.html) vignette. 41 | - Commit the inputs and results to your source code repository. 42 | - Add a tag to reflect the state as of a certain point in time (i.e. FY18 Q1) 43 | 44 | ## What to Store 45 | 46 | If using the sample workflow, you will have two subdirectories located under 47 | a parent `evaluator` directory in your home folder. `inputs` contains the 48 | qualitative scenarios and input data files, while `results` stores the 49 | simulation results, including the summarized data files. Both directories 50 | together represent an analysis snapshot. 51 | 52 | ## Quick Start Script 53 | 54 | When using `create_templates()` a `run_analysis.R` file will be placed at the base 55 | of the `evaluator` directory. A sample ultra-quick workflow looks like: 56 | 57 | 1. Run `evaluator::create_templates("~/evaluator")` 58 | 2. Edit the inputs for your situation. 59 | 3. Run the quick start script with code like the following: 60 | 61 | ```{r eval=FALSE} 62 | base_dir <- "~/evaluator" 63 | source("~/evaluator/run_analysis.R") 64 | ``` 65 | --------------------------------------------------------------------------------