From 49e8a2ca662f1cacac709eaad33aa7f3037752ad Mon Sep 17 00:00:00 2001 From: Victor Bona Date: Mon, 13 Jul 2026 19:14:36 -0300 Subject: [PATCH] Release v0.1.2 CLI trust and login fixes --- CHANGELOG.md | 10 ++- README.md | 2 +- charts/devboxes/Chart.yaml | 10 ++- cli/Cargo.lock | 75 ++++++++++++++++--- cli/Cargo.toml | 4 +- cli/src/main.rs | 33 +++++++- controller/pyproject.toml | 2 +- .../src/devboxes_controller/__init__.py | 2 +- .../devboxes_controller/templates/docs.html | 6 +- .../devboxes_controller/templates/index.html | 6 +- .../devboxes_controller/templates/login.html | 4 +- controller/tests/test_app.py | 2 +- controller/uv.lock | 2 +- docs/configuration.md | 4 +- docs/golden-path.md | 2 +- package-lock.json | 4 +- package.json | 2 +- scripts/install.sh | 2 +- 18 files changed, 130 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3d6b39..239e0a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to Devboxes are documented here. The project follows [Keep a ## [Unreleased] +## [0.1.2] - 2026-07-13 + +### Fixed + +- Made `devbox login` honor `DEVBOX_TOKEN` for non-interactive authentication. +- Made the CLI trust operating-system certificate roots so self-hosted installations can use an administrator-installed private CA. + ## [0.1.1] - 2026-07-13 ### Added @@ -34,6 +41,7 @@ All notable changes to Devboxes are documented here. The project follows [Keep a - Portable Helm chart with values schema, namespace-scoped RBAC, configurable storage, ingress, LoadBalancer or NodePort SSH, ServiceMonitor, and disruption budget. - macOS and Linux CLI releases, SHA-256 verification installer, GHCR images, OCI chart publishing, image provenance attestations, and clean Kind install CI. -[Unreleased]: https://github.com/vicotrbb/devboxes/compare/v0.1.1...HEAD +[Unreleased]: https://github.com/vicotrbb/devboxes/compare/v0.1.2...HEAD +[0.1.2]: https://github.com/vicotrbb/devboxes/compare/v0.1.1...v0.1.2 [0.1.1]: https://github.com/vicotrbb/devboxes/compare/v0.1.0...v0.1.1 [0.1.0]: https://github.com/vicotrbb/devboxes/releases/tag/v0.1.0 diff --git a/README.md b/README.md index c5b9f89..07da1e0 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ kubectl -n devboxes create secret generic devboxes-workspace \ --from-file=SSH_AUTHORIZED_KEYS="$HOME/.ssh/id_ed25519.pub" helm install devboxes oci://ghcr.io/vicotrbb/charts/devboxes \ - --version 0.1.1 \ + --version 0.1.2 \ --namespace devboxes ``` diff --git a/charts/devboxes/Chart.yaml b/charts/devboxes/Chart.yaml index 82e8e5d..e96b4d5 100644 --- a/charts/devboxes/Chart.yaml +++ b/charts/devboxes/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: devboxes description: Self-hosted, ephemeral development environments on Kubernetes type: application -version: 0.1.1 -appVersion: "0.1.1" +version: 0.1.2 +appVersion: "0.1.2" kubeVersion: ">=1.29.0-0" home: https://github.com/vicotrbb/devboxes icon: https://raw.githubusercontent.com/vicotrbb/devboxes/main/docs/assets/devboxes-mark.svg @@ -16,5 +16,7 @@ annotations: artifacthub.io/license: Apache-2.0 artifacthub.io/category: integration-delivery artifacthub.io/changes: | - - kind: added - description: Initial public release + - kind: fixed + description: Honor DEVBOX_TOKEN during non-interactive CLI login + - kind: fixed + description: Trust operating-system certificate roots in the CLI diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 695db5a..a04a29e 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -196,6 +196,16 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -213,7 +223,7 @@ dependencies = [ [[package]] name = "devbox-cli" -version = "0.1.1" +version = "0.1.2" dependencies = [ "anyhow", "chrono", @@ -438,10 +448,10 @@ dependencies = [ "hyper", "hyper-util", "rustls", + "rustls-native-certs", "tokio", "tokio-rustls", "tower-service", - "webpki-roots", ] [[package]] @@ -710,6 +720,12 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "option-ext" version = "0.2.0" @@ -875,6 +891,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", + "rustls-native-certs", "rustls-pki-types", "serde", "serde_json", @@ -889,7 +906,6 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", ] [[package]] @@ -960,6 +976,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.15.0" @@ -993,6 +1021,38 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.228" @@ -1474,15 +1534,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "windows-core" version = "0.62.2" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index cb18e3f..911c25e 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "devbox-cli" -version = "0.1.1" +version = "0.1.2" edition = "2024" rust-version = "1.96" description = "Terminal client for self-hosted Kubernetes development environments" @@ -19,7 +19,7 @@ anyhow = "1" chrono = { version = "0.4", features = ["serde"] } clap = { version = "4", features = ["derive"] } dirs = "6" -reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } +reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls-native-roots"] } rpassword = "7" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/cli/src/main.rs b/cli/src/main.rs index eb762af..e9a0f96 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -149,8 +149,8 @@ async fn login(url: Option<&str>, provided_token: Option<&str>) -> Result<()> { "Devboxes API URL is not configured; pass `--url https://devboxes.example.com` or set DEVBOX_URL" ) })?; - let token = match provided_token { - Some(token) => token.to_owned(), + let token = match resolve_login_token(provided_token, std::env::var("DEVBOX_TOKEN").ok()) { + Some(token) => token, None => rpassword::prompt_password("Devboxes access token: ")?, }; let resolved = stored.resolve(Some(configured_url), Some(token.clone()))?; @@ -168,6 +168,16 @@ async fn login(url: Option<&str>, provided_token: Option<&str>) -> Result<()> { Ok(()) } +fn resolve_login_token( + provided_token: Option<&str>, + environment_token: Option, +) -> Option { + provided_token + .map(str::to_owned) + .filter(|token| !token.trim().is_empty()) + .or_else(|| environment_token.filter(|token| !token.trim().is_empty())) +} + fn validate_name(value: &str) -> std::result::Result { let valid_length = (1..=40).contains(&value.len()); let valid_edges = value @@ -391,7 +401,24 @@ fn human_expiry(box_info: &Devbox) -> String { #[cfg(test)] mod tests { - use super::{ssh_arguments, validate_name}; + use super::{resolve_login_token, ssh_arguments, validate_name}; + + #[test] + fn login_token_prefers_the_flag_and_supports_the_environment() { + assert_eq!( + resolve_login_token(Some("flag-token"), Some("environment-token".to_owned())), + Some("flag-token".to_owned()) + ); + assert_eq!( + resolve_login_token(None, Some("environment-token".to_owned())), + Some("environment-token".to_owned()) + ); + assert_eq!( + resolve_login_token(Some(""), Some("environment-token".to_owned())), + Some("environment-token".to_owned()) + ); + assert_eq!(resolve_login_token(None, Some(" ".to_owned())), None); + } #[test] fn devbox_names_match_the_controller_contract() { diff --git a/controller/pyproject.toml b/controller/pyproject.toml index 892ba8e..329cbfb 100644 --- a/controller/pyproject.toml +++ b/controller/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "devboxes-controller" -version = "0.1.1" +version = "0.1.2" description = "Controller and dashboard for self-hosted Kubernetes development environments" readme = "README.md" requires-python = ">=3.12" diff --git a/controller/src/devboxes_controller/__init__.py b/controller/src/devboxes_controller/__init__.py index 5b6cc3c..f16cea6 100644 --- a/controller/src/devboxes_controller/__init__.py +++ b/controller/src/devboxes_controller/__init__.py @@ -1,3 +1,3 @@ """Devboxes controller package.""" -__version__ = "0.1.1" +__version__ = "0.1.2" diff --git a/controller/src/devboxes_controller/templates/docs.html b/controller/src/devboxes_controller/templates/docs.html index 8813fb6..f317e2b 100644 --- a/controller/src/devboxes_controller/templates/docs.html +++ b/controller/src/devboxes_controller/templates/docs.html @@ -5,9 +5,9 @@ Documentation · Devboxes - - - + + + diff --git a/controller/src/devboxes_controller/templates/index.html b/controller/src/devboxes_controller/templates/index.html index 908ce42..1cb0453 100644 --- a/controller/src/devboxes_controller/templates/index.html +++ b/controller/src/devboxes_controller/templates/index.html @@ -5,9 +5,9 @@ Devboxes - - - + + + diff --git a/controller/src/devboxes_controller/templates/login.html b/controller/src/devboxes_controller/templates/login.html index 0a2c76e..3c1f695 100644 --- a/controller/src/devboxes_controller/templates/login.html +++ b/controller/src/devboxes_controller/templates/login.html @@ -5,8 +5,8 @@ Sign in · Devboxes - - + +
diff --git a/controller/tests/test_app.py b/controller/tests/test_app.py index 66c5fcc..e2b6a08 100644 --- a/controller/tests/test_app.py +++ b/controller/tests/test_app.py @@ -32,7 +32,7 @@ def test_browser_login_and_dashboard_session() -> None: assert dashboard.headers["x-content-type-options"] == "nosniff" assert "Kubernetes connected" in dashboard.text assert "cluster default storage" in dashboard.text - styles = client.get("/static/styles.css?v=0.1.1") + styles = client.get("/static/styles.css?v=0.1.2") assert "[hidden]" in styles.text assert "display: none !important" in styles.text payload = client.get("/api/v1/devboxes").json() diff --git a/controller/uv.lock b/controller/uv.lock index 08d4655..2f3108d 100644 --- a/controller/uv.lock +++ b/controller/uv.lock @@ -382,7 +382,7 @@ wheels = [ [[package]] name = "devboxes-controller" -version = "0.1.1" +version = "0.1.2" source = { editable = "." } dependencies = [ { name = "fastapi" }, diff --git a/docs/configuration.md b/docs/configuration.md index 6294963..ee50189 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -3,9 +3,9 @@ Use a values file for durable installations: ```bash -helm show values oci://ghcr.io/vicotrbb/charts/devboxes --version 0.1.1 > values.yaml +helm show values oci://ghcr.io/vicotrbb/charts/devboxes --version 0.1.2 > values.yaml helm upgrade --install devboxes oci://ghcr.io/vicotrbb/charts/devboxes \ - --version 0.1.1 \ + --version 0.1.2 \ --namespace devboxes \ --create-namespace \ --values values.yaml diff --git a/docs/golden-path.md b/docs/golden-path.md index b322f80..c610808 100644 --- a/docs/golden-path.md +++ b/docs/golden-path.md @@ -38,7 +38,7 @@ kubectl create namespace devboxes # Create devboxes-auth and devboxes-workspace here, as described below. helm upgrade --install devboxes oci://ghcr.io/vicotrbb/charts/devboxes \ - --version 0.1.1 \ + --version 0.1.2 \ --namespace devboxes \ --values values.yaml ``` diff --git a/package-lock.json b/package-lock.json index 27bdc4a..d8e41fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "devboxes-repository-tooling", - "version": "0.1.1", + "version": "0.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "devboxes-repository-tooling", - "version": "0.1.1", + "version": "0.1.2", "devDependencies": { "@eslint/js": "10.0.1", "eslint": "10.7.0", diff --git a/package.json b/package.json index cadd8b9..98ede96 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "devboxes-repository-tooling", - "version": "0.1.1", + "version": "0.1.2", "private": true, "type": "module", "description": "JavaScript and documentation quality gates for Devboxes", diff --git a/scripts/install.sh b/scripts/install.sh index 5423d77..ac7fa20 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -3,7 +3,7 @@ set -eu release="${DEVBOXES_RELEASE:-devboxes}" namespace="${DEVBOXES_NAMESPACE:-devboxes}" -version="${DEVBOXES_VERSION:-0.1.1}" +version="${DEVBOXES_VERSION:-0.1.2}" repository="${DEVBOXES_CHART_REPOSITORY:-oci://ghcr.io/vicotrbb/charts/devboxes}" chart_source="${DEVBOXES_CHART_SOURCE:-auto}" controller_secret="${DEVBOXES_CONTROLLER_SECRET:-devboxes-auth}"