diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml
index 89c42b0..21c6b1a 100644
--- a/.github/workflows/R-CMD-check.yaml
+++ b/.github/workflows/R-CMD-check.yaml
@@ -21,13 +21,15 @@ jobs:
- {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
- {os: ubuntu-latest, r: 'release'}
- {os: ubuntu-latest, r: 'oldrel-1'}
+ # Minimum R in DESCRIPTION
+ - {os: ubuntu-latest, r: '4.1'}
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v5
- uses: r-lib/actions/setup-pandoc@v2
diff --git a/DESCRIPTION b/DESCRIPTION
index f40af20..f2cc385 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,7 +1,7 @@
Type: Package
Package: audit.base
Title: Base package for Posit Checks
-Version: 0.7.10
+Version: 0.7.11
Authors@R:
person("Jumping", "Rivers", , "info@jumpingrivers.com", role = c("aut", "cre"))
Description: Base package for sharing classes between posit audit
diff --git a/NEWS.md b/NEWS.md
index dcb0fa1..e768f2b 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,6 @@
+# audit.base 0.7.11 _2026-10-16_
+ * chore: The sys-deps check and the R, Python, Quarto and Posit version lookups are tested offline against fixtures, and CI also checks on R 4.1, the minimum version (#64)
+
# audit.base 0.7.10 _2026-10-16_
* chore: The package is MIT licensed (#63)
diff --git a/R/get_latest_versions_remote.R b/R/get_latest_versions_remote.R
index 0fe6655..0f97d52 100644
--- a/R/get_latest_versions_remote.R
+++ b/R/get_latest_versions_remote.R
@@ -22,9 +22,7 @@ get_latest_versions_remote = function() {
# The latest patch of each Quarto minor release. Most releases are prereleases, so the newest 100
# reach back several minors; older minors come from the fixed list
get_quarto_versions = function() {
- releases = jsonlite::read_json(
- "https://api.github.com/repos/quarto-dev/quarto-cli/releases?per_page=100"
- )
+ releases = fetch_json("https://api.github.com/repos/quarto-dev/quarto-cli/releases?per_page=100")
stable = purrr::discard(releases, ~ isTRUE(.x$prerelease))
tags = stringr::str_remove(purrr::map_chr(stable, "tag_name"), "^v")
old = c("1.0.38", "1.1.189", "1.2.475", "1.3.450", "1.4.557", "1.5.57", "1.6.43")
@@ -42,7 +40,7 @@ latest_patch_per_minor = function(versions) {
get_latest_versions_from_posit = function(type = c("r", "python")) {
type = match.arg(type)
url = glue::glue("https://cdn.posit.co/{type}/versions.json")
- versions = unlist(jsonlite::read_json(url))
+ versions = unlist(fetch_json(url))
versions = unname(versions)
tibble::tibble(
patch = get_patch(versions),
@@ -56,3 +54,8 @@ get_latest_versions_from_posit = function(type = c("r", "python")) {
dplyr::slice(1) %>%
dplyr::pull(versions)
}
+
+# JSON from a URL as nested lists
+fetch_json = function(url) {
+ jsonlite::fromJSON(url, simplifyVector = FALSE)
+}
diff --git a/R/get_pkg_requirements.R b/R/get_pkg_requirements.R
index 5859b2d..d2a9681 100644
--- a/R/get_pkg_requirements.R
+++ b/R/get_pkg_requirements.R
@@ -14,12 +14,10 @@ get_pkg_requirements = function(
"Connecting to {url} for system requirements"
)
- res = httr::GET(url, httr::timeout(60))
- r = httr::content(res)
- if (httr::http_error(res)) {
- reason = if (is.list(r) && is.character(r$error)) r$error else httr::http_status(res)$message # nolint
+ r = read_p3m(url)
+ if (!is.null(r$error)) {
cli::cli_warn(
- "Posit Package Manager can't list system requirements for {distribution} {release}: {reason}"
+ "Posit Package Manager can't list system requirements for {distribution} {release}: {r$error}"
)
return(NA)
}
@@ -29,3 +27,14 @@ get_pkg_requirements = function(
~ tibble::tibble(pkg = .x$name, sys_libs = unlist(.x$requirements$packages))
)
}
+
+# P3M's response as a list. On an HTTP error, `error` holds P3M's reason
+read_p3m = function(url) {
+ res = httr::GET(url, httr::timeout(60))
+ r = httr::content(res)
+ if (!httr::http_error(res)) {
+ return(r)
+ }
+ reason = if (is.list(r) && is.character(r$error)) r$error else httr::http_status(res)$message
+ list(error = reason)
+}
diff --git a/R/get_posit_remote_versions.R b/R/get_posit_remote_versions.R
index 438da93..f4d6e62 100644
--- a/R/get_posit_remote_versions.R
+++ b/R/get_posit_remote_versions.R
@@ -8,7 +8,7 @@ get_posit_remote_versions = function(type = c("connect", "workbench")) {
} else {
"https://docs.posit.co/ide/news/"
}
- page = rvest::read_html(url)
+ page = read_posit_news(url)
sections = rvest::html_elements(page, "section")
v_tibbles = purrr::map_df(sections, extract_posit_cves)
all_v = get_all_remote_versions(page) %>%
@@ -47,3 +47,7 @@ get_all_remote_versions = function(page) {
v = stringr::str_extract(versions, "20[0-9]{2}\\.[0-9]{2}\\.[0-9]{1,2}")
tibble::tibble(version = v[!is.na(v)], cve = "")
}
+
+read_posit_news = function(url) {
+ rvest::read_html(url)
+}
diff --git a/R/get_uv_python_versions.R b/R/get_uv_python_versions.R
index 663d90e..f1593dc 100644
--- a/R/get_uv_python_versions.R
+++ b/R/get_uv_python_versions.R
@@ -1,6 +1,6 @@
get_uv_python_versions = function() {
url = "https://raw.githubusercontent.com/astral-sh/uv/main/crates/uv-python-managed/download-metadata.json" # nolint: line_length_linter
- raw_json = jsonlite::fromJSON(url, simplifyVector = FALSE)
+ raw_json = fetch_json(url)
if (length(raw_json) == 0) {
warning("Fetched Python JSON is empty -- check the URL/branch/tag.")
diff --git a/tests/testthat/fixtures/p3m-ubuntu-24.04.json b/tests/testthat/fixtures/p3m-ubuntu-24.04.json
new file mode 100644
index 0000000..c624909
--- /dev/null
+++ b/tests/testthat/fixtures/p3m-ubuntu-24.04.json
@@ -0,0 +1,41 @@
+{
+ "requirements": [
+ {
+ "name": "curl",
+ "requirements": {
+ "packages": [
+ "libcurl4-openssl-dev",
+ "libssl-dev"
+ ]
+ }
+ },
+ {
+ "name": "fftw",
+ "requirements": {
+ "packages": [
+ "libfftw3-dev"
+ ]
+ }
+ },
+ {
+ "name": "sf",
+ "requirements": {
+ "packages": [
+ "libgdal-dev",
+ "gdal-bin",
+ "libgeos-dev",
+ "libproj-dev",
+ "libsqlite3-dev"
+ ]
+ }
+ },
+ {
+ "name": "xml2",
+ "requirements": {
+ "packages": [
+ "libxml2-dev"
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/testthat/fixtures/posit-news.html b/tests/testthat/fixtures/posit-news.html
new file mode 100644
index 0000000..3846fab
--- /dev/null
+++ b/tests/testthat/fixtures/posit-news.html
@@ -0,0 +1,33 @@
+
+
+
+Introduction
+This document contains the notes associated with each release of Posit Connect.
+
+
+
+
+
diff --git a/tests/testthat/fixtures/quarto-releases.json b/tests/testthat/fixtures/quarto-releases.json
new file mode 100644
index 0000000..255e947
--- /dev/null
+++ b/tests/testthat/fixtures/quarto-releases.json
@@ -0,0 +1,18 @@
+[
+ {
+ "tag_name": "v1.11.6",
+ "prerelease": true
+ },
+ {
+ "tag_name": "v1.10.19",
+ "prerelease": false
+ },
+ {
+ "tag_name": "v1.10.18",
+ "prerelease": false
+ },
+ {
+ "tag_name": "v1.9.38",
+ "prerelease": false
+ }
+]
\ No newline at end of file
diff --git a/tests/testthat/fixtures/r-versions.json b/tests/testthat/fixtures/r-versions.json
new file mode 100644
index 0000000..2f60a94
--- /dev/null
+++ b/tests/testthat/fixtures/r-versions.json
@@ -0,0 +1,10 @@
+{
+ "r_versions": [
+ "next",
+ "devel",
+ "4.6.1",
+ "4.6.0",
+ "4.5.3",
+ "4.5.2"
+ ]
+}
\ No newline at end of file
diff --git a/tests/testthat/fixtures/uv-metadata.json b/tests/testthat/fixtures/uv-metadata.json
new file mode 100644
index 0000000..109fa50
--- /dev/null
+++ b/tests/testthat/fixtures/uv-metadata.json
@@ -0,0 +1,86 @@
+{
+ "cpython-3.16.0a1-linux-x86_64-gnu": {
+ "name": "cpython",
+ "arch": {
+ "family": "x86_64",
+ "variant": null
+ },
+ "os": "linux",
+ "libc": "gnu",
+ "major": 3,
+ "minor": 16,
+ "patch": 0,
+ "prerelease": "a1",
+ "variant": null
+ },
+ "cpython-3.14.8-linux-x86_64-gnu": {
+ "name": "cpython",
+ "arch": {
+ "family": "x86_64",
+ "variant": null
+ },
+ "os": "linux",
+ "libc": "gnu",
+ "major": 3,
+ "minor": 14,
+ "patch": 8,
+ "prerelease": "",
+ "variant": null
+ },
+ "cpython-3.14.7-linux-x86_64-gnu": {
+ "name": "cpython",
+ "arch": {
+ "family": "x86_64",
+ "variant": null
+ },
+ "os": "linux",
+ "libc": "gnu",
+ "major": 3,
+ "minor": 14,
+ "patch": 7,
+ "prerelease": "",
+ "variant": null
+ },
+ "cpython-3.14.8-darwin-aarch64-none": {
+ "name": "cpython",
+ "arch": {
+ "family": "aarch64",
+ "variant": null
+ },
+ "os": "darwin",
+ "libc": "none",
+ "major": 3,
+ "minor": 14,
+ "patch": 8,
+ "prerelease": "",
+ "variant": null
+ },
+ "cpython-3.14.8-linux-x86_64-musl": {
+ "name": "cpython",
+ "arch": {
+ "family": "x86_64",
+ "variant": null
+ },
+ "os": "linux",
+ "libc": "musl",
+ "major": 3,
+ "minor": 14,
+ "patch": 8,
+ "prerelease": "",
+ "variant": null
+ },
+ "cpython-3.13.16-linux-x86_64-gnu": {
+ "name": "cpython",
+ "arch": {
+ "family": "x86_64",
+ "variant": null
+ },
+ "os": "linux",
+ "libc": "gnu",
+ "major": 3,
+ "minor": 13,
+ "patch": 16,
+ "prerelease": "",
+ "variant": null
+ }
+}
\ No newline at end of file
diff --git a/tests/testthat/helper-fixtures.R b/tests/testthat/helper-fixtures.R
new file mode 100644
index 0000000..f76e4c7
--- /dev/null
+++ b/tests/testthat/helper-fixtures.R
@@ -0,0 +1,31 @@
+# Offline stand-ins for the remote lookups, read from tests/testthat/fixtures
+read_fixture_json = function(name) {
+ jsonlite::read_json(testthat::test_path("fixtures", name))
+}
+
+# The NEWS page fixture serves both Connect and Workbench
+local_posit_news = function(env = parent.frame()) {
+ testthat::local_mocked_bindings(
+ read_posit_news = function(url) {
+ rvest::read_html(testthat::test_path("fixtures", "posit-news.html"))
+ },
+ .env = env
+ )
+}
+
+local_version_json = function(env = parent.frame()) {
+ testthat::local_mocked_bindings(
+ fetch_json = function(url) {
+ if (grepl("quarto-cli", url, fixed = TRUE)) {
+ read_fixture_json("quarto-releases.json")
+ } else if (grepl("cdn.posit.co/r/", url, fixed = TRUE)) {
+ read_fixture_json("r-versions.json")
+ } else if (grepl("download-metadata.json", url, fixed = TRUE)) {
+ read_fixture_json("uv-metadata.json")
+ } else {
+ stop("No fixture for ", url)
+ }
+ },
+ .env = env
+ )
+}
diff --git a/tests/testthat/test-check_sys_deps.R b/tests/testthat/test-check_sys_deps.R
index f89d712..5209052 100644
--- a/tests/testthat/test-check_sys_deps.R
+++ b/tests/testthat/test-check_sys_deps.R
@@ -1,25 +1,39 @@
-test_that("Testing sys deps", {
- testthat::skip_on_ci()
- if (Sys.info()["sysname"] != "Linux") {
- testthat::skip()
- }
- os_release = readLines("/etc/os-release")
- installed_libs = get_installed_libs()
- deps = check_sys_deps(os_release, installed_libs)
- expect_equal(colnames(deps), c("pkg", "sys_libs"))
-
- out = list(sys_deps = deps)
- q = get_quarto_sys_deps(out)
- expect_equal(colnames(q), c("sys_libs", "pkg", "n"))
- expect_true(all(is.integer(q$n)))
+test_that("check_sys_deps() lists the packages whose system libraries aren't installed", {
+ local_mocked_bindings(read_p3m = function(url) {
+ expect_match(url, "distribution=ubuntu&release=24.04", fixed = TRUE)
+ read_fixture_json("p3m-ubuntu-24.04.json")
+ })
+ ubuntu = c(
+ "PRETTY_NAME=\"Ubuntu 24.04.3 LTS\"",
+ "ID=ubuntu",
+ "ID_LIKE=debian",
+ "VERSION_ID=\"24.04\""
+ )
+ # apt list --installed, after its "Listing..." header
+ apt = c(
+ "libssl-dev/noble-updates,noble-security,now 3.0.13-0ubuntu3.6 amd64 [installed]",
+ "libcurl4-openssl-dev/noble-updates,now 8.5.0-2ubuntu10.6 amd64 [installed]",
+ "libxml2-dev/noble-updates,now 2.9.14+dfsg-1.3ubuntu3.5 amd64 [installed,automatic]"
+ )
+ installed = clean_libs(ubuntu, apt)
+ expect_identical(installed, c("libcurl4-openssl-dev", "libssl-dev", "libxml2-dev"))
- # Empty state
- out = list(
- sys_deps = tibble::tibble(
- pkg = character(0),
- sys_libs = character(0)
+ missing = suppressMessages(check_sys_deps(ubuntu, installed))
+ expected = tibble::tibble(
+ pkg = c("sf", "fftw", "sf", "sf", "sf", "sf"),
+ sys_libs = c(
+ "gdal-bin",
+ "libfftw3-dev",
+ "libgdal-dev",
+ "libgeos-dev",
+ "libproj-dev",
+ "libsqlite3-dev"
)
)
- q = get_quarto_sys_deps(out)
- expect_equal(colnames(q), c("sys_libs", "pkg", "n"))
+ expect_identical(missing, expected)
+
+ for (sys_deps in list(missing, missing[0, ])) {
+ q = get_quarto_sys_deps(list(sys_deps = sys_deps))
+ expect_equal(colnames(q), c("sys_libs", "pkg", "n"))
+ }
})
diff --git a/tests/testthat/test-get_latest_versions_remote.R b/tests/testthat/test-get_latest_versions_remote.R
index de151a3..e4828be 100644
--- a/tests/testthat/test-get_latest_versions_remote.R
+++ b/tests/testthat/test-get_latest_versions_remote.R
@@ -2,3 +2,28 @@ test_that("latest_patch_per_minor() keeps every minor when a new one ships", {
versions = c("1.11.2", "1.10.19", "1.10.3", "1.11.0", "1.9.38", "1.12.0-rc1")
expect_identical(latest_patch_per_minor(versions), c("1.11.2", "1.10.19", "1.9.38"))
})
+
+test_that("get_latest_versions_remote() keeps the latest stable patch of each release", {
+ local_version_json()
+ versions = get_latest_versions_remote()
+ # Quarto 1.0 to 1.6 come from the fixed list; prereleases, musl and macOS builds are dropped
+ expected = tibble::tibble(
+ software = rep(c("python", "quarto", "r"), c(2, 9, 2)),
+ version = c(
+ "3.14.8",
+ "3.13.16",
+ "1.10.19",
+ "1.9.38",
+ "1.6.43",
+ "1.5.57",
+ "1.4.557",
+ "1.3.450",
+ "1.2.475",
+ "1.1.189",
+ "1.0.38",
+ "4.6.1",
+ "4.5.3"
+ )
+ )
+ expect_identical(versions, expected)
+})
diff --git a/tests/testthat/test-get_pkg_requirements.R b/tests/testthat/test-get_pkg_requirements.R
index b691d03..ccc9100 100644
--- a/tests/testthat/test-get_pkg_requirements.R
+++ b/tests/testthat/test-get_pkg_requirements.R
@@ -1,9 +1,5 @@
-test_that("Test pkg requirements", {
- pkgs = get_pkg_requirements(
- distribution = "ubuntu",
- release = "22.04"
- )
- expect_true(ncol(pkgs) == 2)
- expect_true(nrow(pkgs) > 750)
- expect_true("fftw" %in% pkgs$pkg)
+test_that("P3M's reason for rejecting a system reaches the user", {
+ local_mocked_bindings(read_p3m = function(url) list(error = "Unsupported system"))
+ expect_warning(suppressMessages(get_pkg_requirements("rockylinux", "8")), "Unsupported system")
+ expect_identical(suppressMessages(suppressWarnings(get_pkg_requirements("rockylinux", "8"))), NA)
})
diff --git a/tests/testthat/test-os-helper-functions.R b/tests/testthat/test-os-helper-functions.R
index 6675b72..f100713 100644
--- a/tests/testthat/test-os-helper-functions.R
+++ b/tests/testthat/test-os-helper-functions.R
@@ -45,12 +45,6 @@ test_that("Unsupported systems warn and give NA instead of stopping", {
expect_equal(colnames(out), c("sys_libs", "pkg", "n"))
})
-test_that("P3M's reason for rejecting a system reaches the user", {
- skip_if_offline("packagemanager.posit.co")
- expect_warning(get_pkg_requirements("rockylinux", "8"), "Unsupported system")
- expect_identical(suppressWarnings(get_pkg_requirements("rockylinux", "8")), NA)
-})
-
test_that("clean_libs() keeps the dots in RHEL package names", {
rhel = c("ID=\"rhel\"", "ID_LIKE=\"fedora\"", "VERSION_ID=\"8.10\"")
yum = c(
diff --git a/tests/testthat/test-posit_versions.R b/tests/testthat/test-posit_versions.R
index 96e3496..08b7232 100644
--- a/tests/testthat/test-posit_versions.R
+++ b/tests/testthat/test-posit_versions.R
@@ -1,43 +1,33 @@
-test_that("Testing check server", {
- types = c("workbench", "connect", "drivers")
- for (type in types) {
- versions = get_posit_versions(type)
- expect_equal(ncol(versions), 2)
- expect_gt(nrow(versions), 2)
- }
- type = "connect"
- versions = get_posit_versions(type)
- # Up to date
- latest_version = versions[1, ]$version
-
- expect_message(
- audit_posit_version(latest_version, type),
- regexp = "up to date"
- )
+test_that("get_posit_versions() reads versions and CVEs from the NEWS page", {
+ local_posit_news()
+ versions = get_posit_versions("connect")
+ expect_identical(unique(versions$version), c("2026.10.0", "2025.09.0", "2025.07.0"))
+ cves = sort(unique(stats::na.omit(versions$cve)))
+ expect_identical(cves, c("CVE-2025-47906", "CVE-2025-47907"))
- expect_message(
- audit_posit_version(paste0(latest_version, ".pro1"), type),
- regexp = "up to date"
- )
+ expect_message(audit_posit_version("2026.10.0", "connect"), "up to date")
+ expect_message(audit_posit_version("2026.10.0.pro1", "connect"), "up to date")
+ expect_message(audit_posit_version("2025.07.0", "connect"), "2 newer versions that fix 2 CVEs")
+})
- expect_message(audit_posit_version("2022.10.0", type), regexp = "out of date")
+test_that("get_posit_versions() falls back to the cache when the NEWS page can't be read", {
+ local_mocked_bindings(read_posit_news = function(url) stop("HTTP 503"))
+ for (type in c("connect", "workbench")) {
+ expect_message(get_posit_versions(type), "HTTP 503.*Falling back to cache")
+ versions = suppressMessages(get_posit_versions(type))
+ expect_identical(versions, get_posit_versions(type, remote = FALSE))
+ expect_gt(nrow(versions), 2)
+ }
+ expect_gt(nrow(get_posit_versions("drivers")), 2)
})
-test_that("Testing check Posit versions", {
- type = "connect"
- remote = get_posit_remote_versions(type)
- local = get_posit_versions(type, remote = FALSE)
- expect_true(
- all(remote$version %in% local$version),
- info = "Try running update_all_versions()"
- )
- type = "workbench"
- remote = get_posit_remote_versions(type)
- local = get_posit_versions(type, remote = FALSE)
- expect_true(
- all(remote$version %in% local$version),
- info = "Try running update_all_versions()"
- )
+test_that("The cached Posit versions are up to date", {
+ skip_if_offline("docs.posit.co")
+ for (type in c("connect", "workbench")) {
+ remote = get_posit_remote_versions(type)
+ local = get_posit_versions(type, remote = FALSE)
+ expect_true(all(remote$version %in% local$version), info = "Try running update_all_versions()")
+ }
})
test_that("get_posit_versions() keeps CVE IDs and marks versions without one as NA", {
diff --git a/tests/testthat/test-quarto-helpers.R b/tests/testthat/test-quarto-helpers.R
index f30ec35..b8b8c9a 100644
--- a/tests/testthat/test-quarto-helpers.R
+++ b/tests/testthat/test-quarto-helpers.R
@@ -1,17 +1,21 @@
-test_that("Quarto Outputs", {
- out = list()
- out$posit_version = "2022.10.0"
- msg = get_quarto_posit_version_msg(out, type = "connect")
- expect_true(stringr::str_detect(msg, "CVEs"))
-
- out$posit_version = "2012.10.0"
- msg = get_quarto_posit_version_msg(out, "connect")
- expect_true(stringr::str_detect(msg, "in our database"))
-
- out$posit_version = get_posit_versions("connect")[1, ]$version
- msg = get_quarto_posit_version_msg(out, "connect")
- expect_true(stringr::str_detect(msg, "is up to date"))
+test_that("The Posit version message and status agree", {
+ local_posit_news()
+ cases = tibble::tribble(
+ ~posit_version, ~status, ~msg,
+ "2026.10.0", "current", "is up to date",
+ "2025.07.0", "outdated", "fix 2 CVEs",
+ "2012.10.0", "unknown", "in our database"
+ )
+ for (i in seq_len(nrow(cases))) {
+ out = list(posit_version = cases$posit_version[i])
+ msg = get_quarto_posit_version_msg(out, "connect")
+ expect_match(msg, cases$msg[i], label = cases$posit_version[i])
+ expect_identical(get_quarto_posit_version_status(out, "connect"), cases$status[i])
+ }
+})
+test_that("Server headers are tabulated for the report", {
+ skip_if_offline("google.com")
out = list(server_headers = serverHeaders::check("google.com"))
q = get_quarto_server_header(out)
expect_equal(colnames(q), c("header", "status", "message", "value"))
@@ -19,17 +23,6 @@ test_that("Quarto Outputs", {
expect_true(nrow(q) >= 6)
})
-test_that("Posit version status matches the message", {
- out = list(posit_version = "2022.10.0")
- expect_equal(get_quarto_posit_version_status(out, "connect"), "outdated")
-
- out$posit_version = "2012.10.0"
- expect_equal(get_quarto_posit_version_status(out, "connect"), "unknown")
-
- out$posit_version = get_posit_versions("connect")[1, ]$version
- expect_equal(get_quarto_posit_version_status(out, "connect"), "current")
-})
-
test_that("version_status maps row numbers", {
expect_equal(version_status(NA_integer_), "unknown")
expect_equal(version_status(1L), "current")
diff --git a/tests/testthat/test-software-versions.R b/tests/testthat/test-software-versions.R
index 8fd0f3a..9682046 100644
--- a/tests/testthat/test-software-versions.R
+++ b/tests/testthat/test-software-versions.R
@@ -76,6 +76,7 @@ test_that("Testing augment_installed (future))", {
test_that("Ensure that software versions are up to date", {
testthat::skip_on_ci()
+ skip_if_offline("cdn.posit.co")
versions = get_latest_versions(remote = FALSE)
latest = get_latest_versions_remote()