rstudio / rstudio/packrat

Packrat and Authenticated Private Repositories

Open
#499 10 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
R
Stars
409
Forks
89
PR merge metrics
No merged PRs in 30d

Description

I have a number of packages that I'd like to host on an authenticated private repository (specifically using Artifactory). I would also like to be able to use this repository with packrat.

Authentication is done over an HTTPS connection in the form https://user:token@example.com/path/to/repo/. When used with packrat, this URL, which contains private data in user:token, is stored in packrat/packrat.lock, which I'd like to be able to source control for portability/reproducibility purposes.

I am curious what the packrat developers think of this situation. Can this be supported with a new packrat feature? Or is this a foundational issue with the way base R uses only a URL string to link to repositories?

Note: Issues arise in utils::available.packages (when packages are cached locally) if user is an email address (another @ character), which others have experienced, and @dehowell addressed in the .Rprofile patch below. Though once fixed, the above issues regarding packrat.lock still apply.

# Set artifactory-cran as the repository for R packages. This is a virtual repository in Artifactory
# that combines:
# artifactory-cran-local - our local, non-public packages
# cran-r-project - packages in the public CRAN
local({
  user = utils::URLencode("<YOUR_EMAIL>", reserved=TRUE)
  # API key generated by Artifactory
  token = "<YOUR_ARTIFACTORY_API_KEY>"
  url = "artifactory.example.com/artifactory/artifactory-cran/"
  options(repos = c("artifactory-cran" = paste0( "https://", user, ":", token, "@", url)))
})

# The build in URLencode function handles a URL containing an email username
# poorly, which prevents R from downloading the CRAN package index from Artifactory.
# The following block replaces the built-in available.packages function with a wrapped
# version that uses a modified version of URLencode.
local({
  library(utils)
  original <- utils::available.packages

  wrapped <- function(...) {
    # Monkey-patch URLencode for this execution
    URLencode.original <- utils::URLencode
    URLencode.wrapped <- function(URL, reserved=FALSE, repeated=TRUE) {
      URLencode.original(URL, reserved, repeated)
    }
    unlockBinding("URLencode", asNamespace("utils"))
    assign("URLencode", URLencode.wrapped, envir=asNamespace("utils"))

    # Call original available.packages
    result <- original(...)

    # Restore the original URLencode function
    assign("URLencode", URLencode, envir=asNamespace("utils"))
    lockBinding("URLencode", asNamespace("utils"))

    result
  }

  unlockBinding("available.packages", as.environment("package:utils"))
  assign("available.packages", wrapped, envir=as.environment("package:utils"))
  lockBinding("available.packages", as.environment("package:utils"))

  unlockBinding("available.packages", asNamespace("utils"))
  assign("available.packages", wrapped, envir=asNamespace("utils"))
  lockBinding("available.packages", asNamespace("utils"))  
})


# Set the download method for compatibility with packrat.
# Artifactory 404s with a JSON payload on /PACKAGES.rds and /PACKAGES.gz.
# Packrat requires curl for downloading the package index, but curl doesn't throw
# an error on a 404, which means that R tries to parse the JSON using the package index
# parser. -f will cause curl to throw an error on the 404 instead.
options(download.file.method = 'curl', download.file.extra = '-f')```

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Review how repository URLs are written to packrat/packrat.lock and how utils::available.packages consumes them; use the supplied .Rprofile workaround as context. Define a supported authentication path for private Artifactory repositories that preserves reproducible lockfiles without exposing credentials, then verify the behavior with an authenticated repository.

Written by the indexing model from the issue text.

Assessment

Tech stack
r
Domain
security, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.