Releases: ThinkR-open/dockerfiler
dockerfiler 1.0.0
First major release, now on CRAN.
install.packages("dockerfiler")First major release. The version is bumped to 1.0.0 to signal API
maturity after a stabilisation cycle that overhauled the
input-validation surface, hardened the codegen against renv.lock /
DESCRIPTION injection, removed the vendored copy of {renv}, and
flipped the high-level generators' defaults to multi-arch
rocker/r-ver + binary packages from Posit Public Package Manager.
See below.
Breaking changes
- The vendored copy of
{renv}(~30,000 lines underinst/vendor/)
is removed. Lockfiles are now parsed withjsonlite::read_json()
(already in Imports). The exporteddockerfiler::renvsymbol is
removed: it was a public-API surface only because the vendor pattern
required it. The fallbackrenv_versionvalue, when both the user
argument is missing and the lockfile does not pin renv, is now
NULL(install the latest renv from the configured repos), aligned
with the existingrenv_version = NULLbehaviour. Closes #94. dock_from_renv()now defaults to running the runtime container as
therstudiouser (previously root). The generated Dockerfile gains
a defensiveRUN id -u rstudio || useradd -m -d /home/rstudio -s /bin/bash rstudio
early so the user is created if the FROM image does not already
ship one (no-op on rocker/* images, realuseraddonr-base,
ubuntu:*,debian:*). The renv cache is auto-derived to
/home/<user>/.cache/R/renvand chowned to<user>before the
USERdirective drops privilege; theUSERdirective itself is
emitted right before therenv::restore()cache-mount RUN, so
every step that needs root (apt-get, R installs) still runs as
root. Passuser = NULLto opt out and keep the previous root
behaviour. debian/ubuntu only; for alpine-based images you must
passuser = NULLand create the user yourself. Closes #100.dock_from_renv()defaultFROMflips from"rocker/r-base"
(amd64-only) to"rocker/r-ver"(multi-arch: linux/amd64 +
linux/arm64), and the R version from therenv.lockfile is now
appended at codegen time (e.g.rocker/r-ver:4.5.0). Apple
Silicon and ARM Linux hosts (Ampere, AWS Graviton) now build
natively without Rosetta. Pass the legacyFROM = "rocker/r-base"
to opt out.dock_from_desc()'s defaultFROMwas already
rocker/r-ver:<R version>and is unchanged. Closes #47.dock_from_renv()anddock_from_desc()defaultreposflips from
"https://cran.rstudio.com/"(source-only CRAN mirror) to
"https://p3m.dev/cran/latest"(Posit Public Package Manager),
with automatic rewrite to the__linux__/$VERSION_CODENAME/shape
at codegen time so the build pulls pre-compiled Linux binaries
instead of compiling from source. Build time on packages with
C/C++ deps drops from minutes to seconds. The PPM rewrite logic
now matches all three Posit-managed PPM hosts:
packagemanager.posit.co,packagemanager.rstudio.com, and
p3m.dev. Pass the legacy
repos = c(CRAN = "https://cran.rstudio.com/")to opt out.
Closes #57.
Security
dock_from_desc()anddock_from_renv()now validate every
user-supplied parameter that flows into a Dockerfile shell context
(FROM,AS,reposvalues and names,extra_sysreqs,
renv_version,renv_paths_cache,lockfilebasename,use_pak,
strict_install, plusr_versionread from the lockfile). Inputs
that contain shell metacharacters, newlines, or do not match the
documented format raise an explicit error at function entry,
rather than silently producing a malformed Dockerfile or one that
executes attacker-controlled commands atdocker buildtime.
This closes the post-#106 audit follow-up for all five sites
surfaced by Copilot review.- Fixed a long-standing code-injection path in
dock_from_renv():
therenvpackage version resolved from the lockfile
(lock$Packages$renv$Version) was interpolated raw into the
generatedR -e 'remotes::install_version("renv", version = "<x>")'
line without passing through.validate_renv_version(). A crafted
renv.lockcould break out of the inner R string and execute
arbitrary code as root atdocker buildtime. The user-supplied
renv_version=argument has been validated since the 1.0.0
shell-context hardening above, but the lockfile-fallback path was
missed; the bug itself predates 1.0.0 (it existed while the
vendored{renv}parser was in use). The validator is now applied
to the resolved value whatever its source. Found by an internal
security audit before release. - Tightened the
.validate_r_version()"X.Y.Z Patched" branch to
require a single literal space (it previously used\s, which in R
also matches a newline or tab): a lockfile whoseR$Versioncarried
an embedded newline would pass validation and then emit a two-line
FROMdirective. Not exploitable for command injection, but it
could silently breakdocker build. - Fixed a long-standing code-injection path in
dock_from_desc():
package names read from theDESCRIPTIONwere interpolated into
generated Dockerfile directives without validation.read.dcf()and
desc::desc_get_deps()both join DCF continuation lines with\n,
so a craftedPackage:field, or a craftedImports:/Depends:
/Suggests:/LinkingTo:entry, could carry a continuation line
that injects an extra Dockerfile directive (e.g. aRUN) executing
as root atdocker buildtime -- thePackage:field via the
COPY <pkg>_*.tar.gz /app.tar.gzline and the tar.gz-cleanup glob
on thebuild_from_source = FALSEpath, and the dependency names
via theremotes::install_version("<name>", ...)install RUNs on
the defaultbuild_from_source = TRUEpath. Both the package name
and every dependency-field name are now validated against the CRAN
package-name grammar at function entry. The bug predates 1.0.0.
Found by the same internal security audit as thedock_from_renv()
fix above.
New features
dock$ARG()and the internaladd_arg()helper gain adefault
parameter to emitARG <name>=<default>instead ofARG <name>.
Closes #8.dock_from_desc()anddock_from_renv()gain agithub_pat
parameter (default"none") controlling how a GitHub PAT is provided
toremotes::install_github()/remotes::install_local()/
renv::restore()for private dependency repositories. Set to
"build_arg"to emitARG GITHUB_PAT+ENVpropagation (passed
via--build-arg GITHUB_PAT=$GITHUB_PAT), or"secret"to use
BuildKit secret mounts (the PAT is never persisted in image
metadata; recommended for published images). Closes #18.dock_from_renv()gains arenv_paths_cacheparameter that
controls theRENV_PATHS_CACHEbuild-arg default, the propagated
ENVvalue, and the cache mount target. WhenNULL(the
default), the path is auto-derived fromuser:
/root/.cache/R/renvforuser = NULL, and
/home/<user>/.cache/R/renvotherwise. Users can override the
renv cache location at image build time with
--build-arg RENV_PATHS_CACHE=...without regenerating the
Dockerfile.dock_from_desc()gains astrict_installparameter (default
TRUE). WhenTRUE, every install RUN in the generated Dockerfile
is prefixed withoptions(warn = 2);so any R warning during
install (missing CRAN package, partial download, archived package,
404 on a remote) becomes a hard error and aborts the docker build.
This is a behaviour change for users regenerating their Dockerfile:
install RUNs now refuse to silently swallow warnings. Pass
strict_install = FALSEif your build environment routinely
emits benign warnings (locale defaulting, NTP time-verification,
ABI-version notices) that you do not want to fail the build.
Closes #9.
Bug fixes
r()no longer silently rewrites user code. The previous
implementation calledgsub(" [2,]", " ", code)(a typo for
{2,}) which deleted any digit2or comma preceded by a space:
r(c(1, 2, 3))returnedR -e 'c(1, , 3)'. The replacement
approach (gsub("[ ]{2,}", " ", code)) still collapsed runs of
spaces inside string literals (r(cat("a b"))would emit
R -e 'cat("a b")'). The fix usestrimws()on eachdeparse()
line thenpaste(collapse = " "): only the line-wrap indentation
added bydeparse()is removed, internal whitespace is preserved.
Closes #95.r()now wraps the deparsed R expression with
shQuote(., type = "sh")instead of inlining it inside a hand-rolled
single-quoted shell string. Apostrophes inside string literals no
longer break the emitted command:r(message("don't"))used to emit
R -e 'message("don't")', which the shell refuses to parse
(unterminated quoted string). The new wrapping is shell-safe by
construction.dock_from_desc(build_from_source = FALSE)no longer carries
a dead-code branch (if (missing(out))) on the locally-assigned
result ofpkgbuild::build().missing()only reports unsupplied
function arguments, so the branch was unreachable; the success path
always ran whenbuild()returned. The branch is removed; failures
ofpkgbuild::build()propagate normally viastop(). Closes #98.dock_from_desc(): fixed twolength(x > 0)typos in the dependency
handling (the intent waslength(x) > 0); the conditions now behave
as documented.- The
<pkg>_*.tar.gzcleanup glob indock_from_desc(build_from_source = FALSE)
is now built withglob2rx(), so a dot in a package name (e.g.
R.utils) is matched literally and a sibling package's tarball is no
longer swept up. - Internal tidy-ups with no user-visible effect: dropped a duplicate
@exportindockerignore.R; the codegen now uses the new
dock$ARG(name, default = ...)form instead of inlining the=.
Full changelog: h...
v0.2.5
What's Changed
- Replace native pipes by @HenningLorenzen-ext-bayer in #78
- update test and prep for CRAN submission by @dagousket in #79
- chore: clean roxygen doc and test tempfiles by @dagousket in #80
- allow multistage docker by @VincentGuyader in #84
- Task 3 - Feature: Add COMMENT by @jcrodriguez1989 in #81
- Add website to DESCRIPTION + update pkgdown action by @olivroy in #75
- add dedicated cache for
renv::restoreby @VincentGuyader in #85
New Contributors
- @HenningLorenzen-ext-bayer made their first contribution in #78
- @dagousket made their first contribution in #79
- @jcrodriguez1989 made their first contribution in #81
- @olivroy made their first contribution in #75
Full Changelog: v0.2.3...v0.2.5
dockerfiler 0.2.3
- remove sysreqs.r-hub.io to use {pak} instead for system requirement detection
- move from
pak::pkg_system_requirementstopak::pkg_sysreqs()thanks to @B0ydT dock_from_renvallow to specify user to use in Dockerfile- the
dependenciesparameter indock_from_renvif set toTRUEwill install required dependencies plus optional and development dependencies. defaut isNAonly required (hard) dependencies, - Set the minimum version of the {pak} package to 0.6.0.
- Parameterize the
sysreqs_platformused to find system dependencies in pkg_sysreqs (only debian/ubuntu based images are supported)
dockerfiler 0.2.2
-
fix : create a
use_pakparameters indock_from_renvto setrenv.config.pak.enabled = FALSEinstead ofrenv.config.pak.enabled = TRUEto avoid issues with {pak} duringrenv::restore() -
feat: use of {memoise} to cache call to
pak::pkg_system_requirements -
fix : dont depend anymore to {renv} use an internalised {renv} version (1.0.3)
-
fix : remove
renv:::lockfileand uselockfile_readinstead -
feat: Added
dock_from_renv(), to create a Dockerfile from a renv.lock file (@JosiahParry, @statnmap) -
feat: Added
parse_dockerfile(), to Create a Dockerfile object from a Dockerfile file (@JosiahParry) -
feat: Added
renv_versionparameter todock_from_renvto be able to fix the renv version to use duringrenv::restore()(@campbead)
dockerfiler 0.2.1
-
fix: graceful failing in case no internet
-
feat: Added
dock_from_renv(), to create a Dockerfile from a renv.lock file (@JosiahParry, @statnmap)