From aa84eb0fdb5d31d9d48388af8448b52e6978386a Mon Sep 17 00:00:00 2001 From: Marie Idleman Date: Wed, 15 Jul 2026 08:25:03 -0500 Subject: [PATCH 1/5] Fix npm run pwb --credentials flag and show it in install/status output --credentials= was never wired into the top-level dispatcher and always failed with "Unknown subcommand". Also surfaces the configured credential type in the install summary and status output, only when configure-datasources.sh actually succeeds. --- .../environments/wb-local/install-workbench.sh | 15 +++++++++++++-- .../workbench-dev/workbench-local.sh | 18 ++++++++++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/docker/environments/wb-local/install-workbench.sh b/docker/environments/wb-local/install-workbench.sh index f8778011a499..86213b22c364 100644 --- a/docker/environments/wb-local/install-workbench.sh +++ b/docker/environments/wb-local/install-workbench.sh @@ -344,14 +344,22 @@ if ! TAG=${POSITRON_TAG} ARCH_SUFFIX=${ARCH_SUFFIX} GITHUB_TOKEN=${GITHUB_TOKEN} fi # Configure data sources (one credential type: databricks, snowflake, or azure) +CREDENTIALS_OK=false if [ -n "${CREDENTIALS}" ]; then echo "Configuring data source: ${CREDENTIALS}..." + # Clear any marker from a previous run before attempting this one, so a + # failed attempt here can never leave behind a stale success marker. + rm -f /var/lib/wb-local-credentials 2>/dev/null || true if [ -f "/tmp/configure-datasources.sh" ]; then - if ! /tmp/configure-datasources.sh "${CREDENTIALS}"; then + if /tmp/configure-datasources.sh "${CREDENTIALS}"; then + CREDENTIALS_OK=true + # Record success so a later 'npm run pwb -- status' can show it too. + printf '%s\n' "${CREDENTIALS}" > /var/lib/wb-local-credentials 2>/dev/null || true + else log_error "Failed to configure data source: ${CREDENTIALS}" fi else - echo "Skipping data source configuration (configure-datasources.sh not found)" + log_error "Skipping data source configuration (configure-datasources.sh not found)" fi else echo "No --credentials specified - skipping data source configuration" @@ -403,6 +411,9 @@ POSITRON_FULL_VERSION="${POSITRON_VERSION}-${POSITRON_BUILD}" echo "Positron version: ${POSITRON_FULL_VERSION}" echo "Workbench version: ${WB_VERSION}" +if [ "${CREDENTIALS_OK}" = true ]; then + echo "Credentials: ${CREDENTIALS}" +fi echo "Workbench URL: http://localhost:8787" # Report any errors that occurred diff --git a/docker/environments/workbench-dev/workbench-local.sh b/docker/environments/workbench-dev/workbench-local.sh index 97cdb5064f09..dc73b84a2db4 100644 --- a/docker/environments/workbench-dev/workbench-local.sh +++ b/docker/environments/workbench-dev/workbench-local.sh @@ -322,6 +322,12 @@ cmd_install() { ' # Record the exact Workbench package URL so status can show the build. docker exec -e WB_URL="${WB_URL}" test bash -c 'printf "%s\n" "$WB_URL" > /var/lib/wb-local-source' || true + # install-workbench.sh writes /var/lib/wb-local-credentials itself, only on a + # successful configure-datasources.sh run. Without --credentials there's + # nothing to configure, so clear any stale marker from a prior install here. + if [ -z "$creds" ]; then + docker exec test bash -c 'rm -f /var/lib/wb-local-credentials' || true + fi } cmd_up() { @@ -441,16 +447,23 @@ wb_source_build() { docker exec test bash -c 'if [ -f /var/lib/wb-local-source ]; then basename "$(cat /var/lib/wb-local-source)"; fi' 2>/dev/null || true } +# The configured managed-credential type (databricks/snowflake/azure), recorded +# at install time. Empty if the stack was installed without --credentials. +wb_credentials_type() { + docker exec test bash -c 'if [ -f /var/lib/wb-local-credentials ]; then cat /var/lib/wb-local-credentials; fi' 2>/dev/null || true +} + # Clean post-startup summary, with the same labels install-workbench.sh prints # so a resume reads the same as a fresh install. The header reflects real # readiness: this image's init script has no 'status' verb, so we check for the # running rserver process directly. wb_print_ready() { - local v wb pos src + local v wb pos src creds v="$(wb_versions)" wb="$(printf '%s' "$v" | cut -f1)" pos="$(printf '%s' "$v" | cut -f2)" src="$(wb_source_build)" + creds="$(wb_credentials_type)" echo '' if docker exec test bash -c 'pgrep -x rserver >/dev/null 2>&1'; then # allow-any-unicode-next-line @@ -461,6 +474,7 @@ wb_print_ready() { printf 'Positron version: %s\n' "$pos" printf 'Workbench version: %s\n' "$wb" [ -n "$src" ] && printf 'Workbench build: %s\n' "$src" + [ -n "$creds" ] && printf 'Credentials: %s\n' "$creds" printf 'Workbench URL: %s (user1 / WB_PASSWORD)\n' "http://localhost:8787" printf 'Connect URL: %s\n' "http://localhost:3939" echo '' @@ -539,7 +553,7 @@ main() { case "$sub" in up) cmd_up "$@" ;; # Flag-style invocations (no explicit "up") route to cmd_up with the flag. - --reinstall|--ttl|--ttl=*|--no-ttl) cmd_up "$sub" "$@" ;; + --reinstall|--ttl|--ttl=*|--no-ttl|--credentials=*) cmd_up "$sub" "$@" ;; status) cmd_status "$@" ;; logs) cmd_logs "$@" ;; shell) cmd_shell "$@" ;; From a80a24487358dbc2a621d84645e25fb360737821 Mon Sep 17 00:00:00 2001 From: Marie Idleman Date: Wed, 15 Jul 2026 09:49:54 -0500 Subject: [PATCH 2/5] Rename README-positron-workbench.md to README.md Matches the naming used by the sibling wb-local README and drops redundant self-reference to the containing directory's own name. --- .../workbench-dev/{README-positron-workbench.md => README.md} | 0 docker/environments/workbench-dev/workbench-local.sh | 4 ++-- test/e2e/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename docker/environments/workbench-dev/{README-positron-workbench.md => README.md} (100%) diff --git a/docker/environments/workbench-dev/README-positron-workbench.md b/docker/environments/workbench-dev/README.md similarity index 100% rename from docker/environments/workbench-dev/README-positron-workbench.md rename to docker/environments/workbench-dev/README.md diff --git a/docker/environments/workbench-dev/workbench-local.sh b/docker/environments/workbench-dev/workbench-local.sh index dc73b84a2db4..d33495ebeef3 100644 --- a/docker/environments/workbench-dev/workbench-local.sh +++ b/docker/environments/workbench-dev/workbench-local.sh @@ -389,7 +389,7 @@ cmd_up() { if [ ! -f "${SCRIPT_DIR}/connect/connect.lic" ]; then echo "WARNING: no Connect license at ${SCRIPT_DIR}/connect.lic -- the connect container" >&2 echo " will not become healthy and 'test' won't start (startup will time out)." >&2 - echo " Add connect.lic (see docker/environments/workbench-dev/README-positron-workbench.md)." >&2 + echo " Add connect.lic (see docker/environments/workbench-dev/README.md)." >&2 fi # --remove-orphans clears a leftover container from a prior run under a # different service name that would otherwise hold the same ports. @@ -541,7 +541,7 @@ ACCESS Workbench http://localhost:8787 (user1 / WB_PASSWORD from docker/environments/workbench-dev/.env) Connect http://localhost:3939 -SETUP (details: docker/environments/workbench-dev/README-positron-workbench.md) +SETUP (details: docker/environments/workbench-dev/README.md) gh auth login (once, include read:packages) workbench.lic + connect.lic in docker/environments/workbench-dev/ GITHUB_TOKEN and docker login ghcr.io are derived from gh automatically. optional: fzf (arrow-key pickers; falls back to a numbered prompt) diff --git a/test/e2e/README.md b/test/e2e/README.md index eaaf1e112ef7..be94221ace49 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -134,7 +134,7 @@ We use Playwright as the test framework for end-to-end tests in Positron. Make s > [!TIP] > To manually run and debug Positron against Workbench (`e2e-workbench` project), see -> [`docker/environments/workbench-dev/README-positron-workbench.md`](../../docker/environments/workbench-dev/README-positron-workbench.md) (`npm run pwb`). +> [`docker/environments/workbench-dev/README.md`](../../docker/environments/workbench-dev/README.md) (`npm run pwb`). #### Running Specific Tests From de271aad8ecfcf14dff9d8be3157984fdcbe8b84 Mon Sep 17 00:00:00 2001 From: Marie Idleman Date: Wed, 15 Jul 2026 09:53:49 -0500 Subject: [PATCH 3/5] Rename docker/environments/workbench-dev to pwb-local workbench-dev implied a debugging/breakpoint setup that this stack doesn't provide; pwb-local matches the npm run pwb command and the naming convention of sibling *-local directories. --- .github/actions/setup-workbench-docker/action.yml | 8 ++++---- .github/workflows/test-e2e-workbench-ubuntu.yml | 2 +- .../{workbench-dev => pwb-local}/.env.example | 0 .../environments/{workbench-dev => pwb-local}/.gitignore | 0 .../environments/{workbench-dev => pwb-local}/README.md | 8 ++++---- .../{workbench-dev => pwb-local}/connect/.gitignore | 0 .../docker-compose.workbench.yml | 0 .../{workbench-dev => pwb-local}/workbench-local-lib.sh | 0 .../{workbench-dev => pwb-local}/workbench-local.sh | 8 ++++---- package.json | 2 +- test/e2e/README.md | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) rename docker/environments/{workbench-dev => pwb-local}/.env.example (100%) rename docker/environments/{workbench-dev => pwb-local}/.gitignore (100%) rename docker/environments/{workbench-dev => pwb-local}/README.md (95%) rename docker/environments/{workbench-dev => pwb-local}/connect/.gitignore (100%) rename docker/environments/{workbench-dev => pwb-local}/docker-compose.workbench.yml (100%) rename docker/environments/{workbench-dev => pwb-local}/workbench-local-lib.sh (100%) rename docker/environments/{workbench-dev => pwb-local}/workbench-local.sh (99%) diff --git a/.github/actions/setup-workbench-docker/action.yml b/.github/actions/setup-workbench-docker/action.yml index ffe10436801a..8f3a97424247 100644 --- a/.github/actions/setup-workbench-docker/action.yml +++ b/.github/actions/setup-workbench-docker/action.yml @@ -39,11 +39,11 @@ runs: shell: bash run: | # Create connect directory if it doesn't exist - mkdir -p docker/environments/workbench-dev/connect + mkdir -p docker/environments/pwb-local/connect # Copy Connect license to the location expected by docker-compose volume mount if [ -f "${{ inputs.connect-license-path }}" ]; then - cp "${{ inputs.connect-license-path }}" docker/environments/workbench-dev/connect/connect.lic - echo "Connect license copied to docker/environments/workbench-dev/connect/connect.lic" + cp "${{ inputs.connect-license-path }}" docker/environments/pwb-local/connect/connect.lic + echo "Connect license copied to docker/environments/pwb-local/connect/connect.lic" else echo "Warning: Connect license not found at ${{ inputs.connect-license-path }}" fi @@ -53,7 +53,7 @@ runs: run: | docker compose \ -p "${{ inputs.run-id }}" \ - -f docker/environments/workbench-dev/docker-compose.workbench.yml \ + -f docker/environments/pwb-local/docker-compose.workbench.yml \ up -d - name: Setup workbench scripts diff --git a/.github/workflows/test-e2e-workbench-ubuntu.yml b/.github/workflows/test-e2e-workbench-ubuntu.yml index 36061c5b6ff0..bf926ada312e 100644 --- a/.github/workflows/test-e2e-workbench-ubuntu.yml +++ b/.github/workflows/test-e2e-workbench-ubuntu.yml @@ -225,4 +225,4 @@ jobs: - name: Stop Docker containers if: always() run: | - docker compose -p ${{ github.run_id }} -f docker/environments/workbench-dev/docker-compose.workbench.yml down || true + docker compose -p ${{ github.run_id }} -f docker/environments/pwb-local/docker-compose.workbench.yml down || true diff --git a/docker/environments/workbench-dev/.env.example b/docker/environments/pwb-local/.env.example similarity index 100% rename from docker/environments/workbench-dev/.env.example rename to docker/environments/pwb-local/.env.example diff --git a/docker/environments/workbench-dev/.gitignore b/docker/environments/pwb-local/.gitignore similarity index 100% rename from docker/environments/workbench-dev/.gitignore rename to docker/environments/pwb-local/.gitignore diff --git a/docker/environments/workbench-dev/README.md b/docker/environments/pwb-local/README.md similarity index 95% rename from docker/environments/workbench-dev/README.md rename to docker/environments/pwb-local/README.md index c66d892ca91f..9475ca430183 100644 --- a/docker/environments/workbench-dev/README.md +++ b/docker/environments/pwb-local/README.md @@ -6,7 +6,7 @@ pick, in one command. ## Prerequisites - Docker Desktop with 8+ CPUs and 16 GB RAM. -- `workbench.lic` and `connect.lic` in `docker/environments/workbench-dev/`. +- `workbench.lic` and `connect.lic` in `docker/environments/pwb-local/`. - `.env` is created from `.env.example` on first run; you are prompted for `WB_PASSWORD` if it is unset. - Optional: `fzf` for arrow-key pickers (without it you get a numbered prompt). @@ -19,7 +19,7 @@ pick, in one command. precedence). Pulling the container images needs the `read:packages` scope, but you don't have to figure that out up front: if the token you're using is missing it, `npm run pwb` tells you exactly how to add it. -2. Drop `workbench.lic` and `connect.lic` into `docker/environments/workbench-dev/`. +2. Drop `workbench.lic` and `connect.lic` into `docker/environments/pwb-local/`. 3. `npm run pwb`. First run asks which Positron and Workbench you want, installs them, and brings @@ -68,7 +68,7 @@ install; re-run with `--reinstall --credentials=` to switch. | `snowflake` | `/etc/rstudio/snowflake.conf` + `allow-refresh-snowflake-roles` | `SNOWFLAKE_ACCOUNT_`, `SNOWFLAKE_CLIENT_ID_`, `SNOWFLAKE_CLIENT_SECRET_` | | `azure` | OpenID auth in `rserver.conf` + `openid-client-secret` + JIT home dirs | `AZURE_SERVICE_PRINCIPAL_CLIENT_SECRET_` | -1. Put the values for your provider in `docker/environments/workbench-dev/.env` (templated in +1. Put the values for your provider in `docker/environments/pwb-local/.env` (templated in `.env.example`). They live in the team 1Password vault. Wrap each value in single quotes -- `.env` is sourced by the shell, so a secret containing a `$`, space, or `#` is mangled (or errors out) without them. The trailing underscore @@ -84,7 +84,7 @@ install; re-run with `--reinstall --credentials=` to switch. | Service | URL | Login | | --- | --- | --- | -| Workbench | http://localhost:8787 | `user1` / `WB_PASSWORD` (from `docker/environments/workbench-dev/.env`) | +| Workbench | http://localhost:8787 | `user1` / `WB_PASSWORD` (from `docker/environments/pwb-local/.env`) | | Connect | http://localhost:3939 | bootstrapped per run | ## Troubleshooting diff --git a/docker/environments/workbench-dev/connect/.gitignore b/docker/environments/pwb-local/connect/.gitignore similarity index 100% rename from docker/environments/workbench-dev/connect/.gitignore rename to docker/environments/pwb-local/connect/.gitignore diff --git a/docker/environments/workbench-dev/docker-compose.workbench.yml b/docker/environments/pwb-local/docker-compose.workbench.yml similarity index 100% rename from docker/environments/workbench-dev/docker-compose.workbench.yml rename to docker/environments/pwb-local/docker-compose.workbench.yml diff --git a/docker/environments/workbench-dev/workbench-local-lib.sh b/docker/environments/pwb-local/workbench-local-lib.sh similarity index 100% rename from docker/environments/workbench-dev/workbench-local-lib.sh rename to docker/environments/pwb-local/workbench-local-lib.sh diff --git a/docker/environments/workbench-dev/workbench-local.sh b/docker/environments/pwb-local/workbench-local.sh similarity index 99% rename from docker/environments/workbench-dev/workbench-local.sh rename to docker/environments/pwb-local/workbench-local.sh index d33495ebeef3..13fd09d56d32 100644 --- a/docker/environments/workbench-dev/workbench-local.sh +++ b/docker/environments/pwb-local/workbench-local.sh @@ -389,7 +389,7 @@ cmd_up() { if [ ! -f "${SCRIPT_DIR}/connect/connect.lic" ]; then echo "WARNING: no Connect license at ${SCRIPT_DIR}/connect.lic -- the connect container" >&2 echo " will not become healthy and 'test' won't start (startup will time out)." >&2 - echo " Add connect.lic (see docker/environments/workbench-dev/README.md)." >&2 + echo " Add connect.lic (see docker/environments/pwb-local/README.md)." >&2 fi # --remove-orphans clears a leftover container from a prior run under a # different service name that would otherwise hold the same ports. @@ -538,11 +538,11 @@ VERSION PICKERS specific n-1/n-2 build. ACCESS - Workbench http://localhost:8787 (user1 / WB_PASSWORD from docker/environments/workbench-dev/.env) + Workbench http://localhost:8787 (user1 / WB_PASSWORD from docker/environments/pwb-local/.env) Connect http://localhost:3939 -SETUP (details: docker/environments/workbench-dev/README.md) - gh auth login (once, include read:packages) workbench.lic + connect.lic in docker/environments/workbench-dev/ +SETUP (details: docker/environments/pwb-local/README.md) + gh auth login (once, include read:packages) workbench.lic + connect.lic in docker/environments/pwb-local/ GITHUB_TOKEN and docker login ghcr.io are derived from gh automatically. optional: fzf (arrow-key pickers; falls back to a numbered prompt) EOF diff --git a/package.json b/package.json index 5e53997c94cd..73fc3c9e9df9 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "build-check": "./scripts/build-check.sh", "build-start": "./scripts/build-start.sh", "build-stop": "./scripts/build-stop.sh", - "pwb": "bash docker/environments/workbench-dev/workbench-local.sh", + "pwb": "bash docker/environments/pwb-local/workbench-local.sh", "arm:start": "bash -c \"cd docker/environments/arm-local && ./run-with-license.sh ubuntu24\"", "arm:start:rocky": "bash -c \"cd docker/environments/arm-local && ./run-with-license.sh rocky8\"", "arm:connect": "bash -c \"cd docker/environments/arm-local && ./connect.sh\"", diff --git a/test/e2e/README.md b/test/e2e/README.md index be94221ace49..51b842b7f051 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -134,7 +134,7 @@ We use Playwright as the test framework for end-to-end tests in Positron. Make s > [!TIP] > To manually run and debug Positron against Workbench (`e2e-workbench` project), see -> [`docker/environments/workbench-dev/README.md`](../../docker/environments/workbench-dev/README.md) (`npm run pwb`). +> [`docker/environments/pwb-local/README.md`](../../docker/environments/pwb-local/README.md) (`npm run pwb`). #### Running Specific Tests From b125273809d269532bc8a6ce1d7d9f1ff00c641f Mon Sep 17 00:00:00 2001 From: Marie Idleman Date: Wed, 15 Jul 2026 10:11:16 -0500 Subject: [PATCH 4/5] update readme --- docker/environments/pwb-local/README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docker/environments/pwb-local/README.md b/docker/environments/pwb-local/README.md index 9475ca430183..9ed14a030a8b 100644 --- a/docker/environments/pwb-local/README.md +++ b/docker/environments/pwb-local/README.md @@ -15,15 +15,18 @@ pick, in one command. ## Quick start -1. `gh auth login` once (or export a `GITHUB_TOKEN` PAT, which takes - precedence). Pulling the container images needs the `read:packages` scope, - but you don't have to figure that out up front: if the token you're using is - missing it, `npm run pwb` tells you exactly how to add it. +1. Login once, when prompted for a password, enter your **GitHub Personal Access Token**, not your GitHub password. The token needs `read:packages` scope. + + ```bash + docker login ghcr.io -u + ``` + 2. Drop `workbench.lic` and `connect.lic` into `docker/environments/pwb-local/`. -3. `npm run pwb`. +3. Create `.env` from `.env.example`. Secrets are in 1Password. +4. `npm run pwb`. First run asks which Positron and Workbench you want, installs them, and brings -the stack up. Open http://localhost:8787 and log in as `user1`. +the stack up. Open http://localhost:8787 and log in as `user1` and password as set in `WB_PASSWORD`. ## Commands From 0accdfa6cb21d6636dd51433d1a332cc17c7a1b8 Mon Sep 17 00:00:00 2001 From: Marie Idleman Date: Wed, 15 Jul 2026 10:12:52 -0500 Subject: [PATCH 5/5] Don't count missing configure-datasources.sh as an install error log_error was appending this informational message to ERRORS[], triggering a spurious "N error(s) occurred" warning in the install summary even though nothing actually failed. --- docker/environments/pwb-local/.env.example | 2 +- docker/environments/wb-local/install-workbench.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/environments/pwb-local/.env.example b/docker/environments/pwb-local/.env.example index 9b139d35fa2a..e34374db54dc 100644 --- a/docker/environments/pwb-local/.env.example +++ b/docker/environments/pwb-local/.env.example @@ -1,4 +1,4 @@ -# Copy to docker/environments/workbench-dev/.env and fill in. Required values are prompted if missing. +# Copy to docker/environments/pwb-local/.env and fill in. Required values are prompted if missing. E2E_POSTGRES_USER=testuser E2E_POSTGRES_PASSWORD=testpassword WB_PASSWORD=testpassword diff --git a/docker/environments/wb-local/install-workbench.sh b/docker/environments/wb-local/install-workbench.sh index 86213b22c364..65c68a81cdee 100644 --- a/docker/environments/wb-local/install-workbench.sh +++ b/docker/environments/wb-local/install-workbench.sh @@ -359,7 +359,7 @@ if [ -n "${CREDENTIALS}" ]; then log_error "Failed to configure data source: ${CREDENTIALS}" fi else - log_error "Skipping data source configuration (configure-datasources.sh not found)" + echo "Skipping data source configuration (configure-datasources.sh not found)" fi else echo "No --credentials specified - skipping data source configuration"