Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ BUZZ_DEV_VIEWER=

# Optional public Builderlab URL, exposed as import.meta.env.VITE_BUZZ_BUILDERLAB_URL.
# Read by Vite from .env.local or the build process environment (process wins,
# including empty). Unset means empty; no deployment URL is supplied by the repo.
# including empty). Defaults to https://app.builderlab.xyz; set an empty value
# to disable Builderlab sign-in and the bundled plugin's native grants.
# Packaging embeds the value; changing the launched app's environment has no effect.
# Restart Vite for development changes; rebuild/repackage for distributed apps.
# BUZZ_BUILDERLAB_URL=https://builderlab.example.com
15 changes: 15 additions & 0 deletions browser-host/vite-config.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,21 @@ it("loads the broker's Vite config without native-compatibility warnings", () =>
);
}
delete process.env.BUZZ_DATABRICKS_HOST;
// A fresh checkout uses production for both dev and packaged frontends.
// Explicit empty values retain the deployment opt-out.
for (const local of ['', 'BUZZ_BUILDERLAB_URL=']) {
writeFileSync('.env.local', local);
delete process.env.BUZZ_BUILDERLAB_URL;
for (const command of ['serve', 'build']) {
const result = await loadConfigFromFile(
{ command, mode: command === 'serve' ? 'development' : 'production' }, configFile,
);
assert.equal(
result.config.define['import.meta.env.VITE_BUZZ_BUILDERLAB_URL'],
JSON.stringify(local ? '' : 'https://app.builderlab.xyz'),
);
}
}
// Desktop shares .env.local/process inputs with the native build.
// An explicit empty process value clears the frontend URL too.
writeFileSync('.env.local', 'BUZZ_BUILDERLAB_URL=https://app.builderlab.xyz/');
Expand Down
34 changes: 26 additions & 8 deletions crates/plugin-manager/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn builderlab_origin(local: &Path, process: Option<String>) -> Result<String, &'
let raw = values
.get(BUILDERLAB_URL_KEY)
.map(String::as_str)
.unwrap_or("");
.unwrap_or("https://app.builderlab.xyz");
if raw.is_empty() {
return Ok(String::new());
}
Expand Down Expand Up @@ -51,18 +51,30 @@ mod tests {
use super::*;

#[test]
fn local_url_and_process_overrides_produce_an_exact_origin() {
fn defaults_to_production_unless_explicitly_disabled() {
let directory = tempfile::tempdir().unwrap();
let local = directory.path().join(".env.local");
assert_eq!(
builderlab_origin(&local, None).unwrap(),
"https://app.builderlab.xyz"
);
assert_eq!(builderlab_origin(&local, Some(String::new())).unwrap(), "");
std::fs::write(&local, "BUZZ_BUILDERLAB_URL=\n").unwrap();
assert_eq!(builderlab_origin(&local, None).unwrap(), "");
}

#[test]
fn local_url_and_process_overrides_produce_an_exact_origin() {
let directory = tempfile::tempdir().unwrap();
let local = directory.path().join(".env.local");
std::fs::write(
&local,
"\u{feff}export BUZZ_BUILDERLAB_URL=\"https://APP.BUILDERLAB.XYZ:443/deployment/\" # comment\n",
"\u{feff}export BUZZ_BUILDERLAB_URL=\"https://OVERRIDE.EXAMPLE:443/deployment/\" # comment\n",
)
.unwrap();
assert_eq!(
builderlab_origin(&local, None).unwrap(),
"https://app.builderlab.xyz"
"https://override.example"
);
assert_eq!(
builderlab_origin(&local, Some("https://login.example:8443/path/".into())).unwrap(),
Expand Down Expand Up @@ -99,19 +111,22 @@ mod tests {
let directory = tempfile::tempdir().unwrap();
let local = directory.path().join(".env.local");
std::fs::write(&local, "PRIVATE_VALUE='unterminated").unwrap();
assert_eq!(builderlab_origin(&local, None).unwrap(), "");
assert_eq!(
builderlab_origin(&local, None).unwrap(),
"https://app.builderlab.xyz"
);

for quote in ["'", "\"", "`"] {
std::fs::write(
&local,
format!(
"PRIVATE_VALUE={quote}multiline\nBUZZ_BUILDERLAB_URL=https://hidden.example\n{quote}\nINVALID=unquoted value\nexport BUZZ_BUILDERLAB_URL=https://app.builderlab.xyz/\nTRAILING='unfinished\n"
"PRIVATE_VALUE={quote}multiline\nBUZZ_BUILDERLAB_URL=https://hidden.example\n{quote}\nINVALID=unquoted value\nexport BUZZ_BUILDERLAB_URL=https://after-multiline.example/\nTRAILING='unfinished\n"
),
)
.unwrap();
assert_eq!(
builderlab_origin(&local, None).unwrap(),
"https://app.builderlab.xyz"
"https://after-multiline.example"
);
}
for quote in ["'", "\""] {
Expand All @@ -122,7 +137,10 @@ mod tests {
),
)
.unwrap();
assert_eq!(builderlab_origin(&local, None).unwrap(), "");
assert_eq!(
builderlab_origin(&local, None).unwrap(),
"https://app.builderlab.xyz"
);
}
}
}
29 changes: 20 additions & 9 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Deployment configuration: current-feature parity

Buzz Foundation supports configuration for capabilities that exist here, not a
port of every OG Buzz feature. Keep deployment values in local/CI configuration,
not in source. Build defaults are readable binary data, **never secret storage**.
port of every OG Buzz feature. Keep deployment overrides in local/CI configuration.
Build defaults are readable binary data, **never secret storage**.

## Supported inputs and surfaces

| Input | Consumer and boundary |
| --- | --- |
| `BUZZ_BUILDERLAB_URL` | Shared frontend/native build: public login URL and the bundled plugin's exact HTTPS host grant; no runtime override. |
| `BUZZ_BUILDERLAB_URL` | Shared frontend/native build: public login URL and the bundled plugin's native grants; no runtime override. |
| `BUZZ_DEFAULT_COMMUNITY_URL` | Packaged frontend build: secure relay origin to select once, after identity setup, only when this viewer has no saved community record. Saved choices, including Personal space, always win. Unset in OSS builds. |
| `BUZZ_DATABRICKS_HOST` | Frontend build and dev server: `https://` Databricks workspace URL passed as `DATABRICKS_HOST` to every bundled `goose-acp`, which then prefers it to the host in goose's config. Unset in OSS builds. See [Databricks host](#databricks-host). |
| `BUZZ_RELAY_URL` | Live development broker's default community, not an agent relay override or a packaged default. |
Expand Down Expand Up @@ -67,8 +67,10 @@ builds.

## Builderlab URL build input

Set `BUZZ_BUILDERLAB_URL` in repository-root `.env.local` for development, or in
the process running `bin/pnpm build` / `bin/pnpm tauri build` for packaging:
Development and packaged builds default to `https://app.builderlab.xyz`, matching
the desktop release workflow. To use another deployment, set `BUZZ_BUILDERLAB_URL`
in repository-root `.env.local` for development, or in the process running
`bin/pnpm build` / `bin/pnpm tauri build` for packaging:

```sh
BUZZ_BUILDERLAB_URL=https://app.builderlab.xyz bin/pnpm tauri build
Expand All @@ -79,14 +81,23 @@ repository-root `.env.local` and process values using the native dotenv pattern.
For desktop, supply the full URL in `.env.local` or the build process environment
so both stages receive it. Vite's additional `.env` and mode-specific files do
not configure native grants. Process values take precedence, including an
explicit empty value. When unset or empty, login is unconfigured and no network
origin is granted. Local builds have no deployment default. The desktop release
workflow supplies the production URL by default; see [release configuration](releases.md#builderlab-url).
explicit empty value. Set `BUZZ_BUILDERLAB_URL=` to leave login unconfigured and
clear the bundled plugin's native grants. The desktop release workflow supplies the
production URL by default; see [release configuration](releases.md#builderlab-url).

Any HTTPS host is supported, including an explicit port or deployment path. URL
credentials, query parameters and fragments are rejected by the native build.
The desktop's native plugin catalog supplies the effective manifest, granting
only the configured URL's exact origin. Never put credentials in this input.
the configured URL's exact origin. For recognized Builderlab deployments, its
existing Apps policy also grants file access and the mapped control-plane origin
(`https://compose-ctrl.builderlab.xyz` for production). Never put credentials in
this input.

The build origin also controls whether a Builderlab session can be reused by
identity backup when its separately configured service URL has the same origin.
Backup still requires its own service URL, namespace and user choice. The existing
identity-binding validator accepts production Builderlab or the configured origin;
production binding was already allowed before this default.

The bundled Builderlab login consumes this public URL and appends `/api/goose`.

Expand Down
3 changes: 3 additions & 0 deletions src/bundled/reminders/RemindDialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ it("reveals labelled custom fields and saves a future time with the note", async
screen.getByRole("combobox", { name: "When" }).focus();
await user.keyboard("{Enter}");
await screen.findByRole("option", { name: "Custom date & time" });
await vi.waitFor(() =>
expect(screen.getByRole("option", { selected: true })).toHaveFocus(),
);
await user.keyboard("{End}{Enter}");
fireEvent.change(screen.getByLabelText("Reminder date"), {
target: { value: "" },
Expand Down
2 changes: 1 addition & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export default defineConfig(async ({ command, mode }) => {
),
"import.meta.env.VITE_BUZZ_COMMUNITY_ALIASES": JSON.stringify(aliases),
"import.meta.env.VITE_BUZZ_BUILDERLAB_URL": JSON.stringify(
env.BUZZ_BUILDERLAB_URL ?? "",
env.BUZZ_BUILDERLAB_URL ?? "https://app.builderlab.xyz",
),
"import.meta.env.VITE_BUZZ_OPEN_RELAY": JSON.stringify(openOrigin),
"import.meta.env.VITE_BUZZ_DATABRICKS_HOST":
Expand Down
Loading