mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(desktop): reject baked agent credentials (BUZZ-SEC-051)
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
// so the build-time validation below and the runtime parse cannot drift.
|
||||
include!("src/commands/reconnect_hook_config.rs");
|
||||
|
||||
mod build_agent_env_policy {
|
||||
include!("src/managed_agents/build_agent_env_policy.rs");
|
||||
}
|
||||
|
||||
use base64::Engine as _;
|
||||
|
||||
fn main() {
|
||||
@@ -33,9 +37,8 @@ fn main() {
|
||||
println!("cargo:rustc-env=BUZZ_DESKTOP_BUILD_BUZZ_AGENT_MODEL={model}");
|
||||
}
|
||||
|
||||
// Generic KEY=VALUE pairs to inject into every spawned agent process.
|
||||
// Newline-delimited; each line must be non-empty and contain exactly one
|
||||
// `=` separator with a non-empty key. OSS builds leave this unset.
|
||||
// Explicitly allowlisted, non-secret KEY=VALUE settings to inject into
|
||||
// every spawned agent process. OSS builds leave this unset.
|
||||
// The validated value is base64-encoded before emitting so the single-line
|
||||
// Cargo build-script output carries all pairs (Cargo output is line-oriented;
|
||||
// a raw multiline value would be silently truncated to the first line).
|
||||
@@ -60,6 +63,14 @@ fn main() {
|
||||
line
|
||||
);
|
||||
}
|
||||
if !build_agent_env_policy::is_allowed_build_agent_env_key(key) {
|
||||
panic!(
|
||||
"BUZZ_BUILD_AGENT_ENV line {}: key {:?} is not approved non-secret build configuration; allowed keys: {:?}",
|
||||
line_no + 1,
|
||||
key,
|
||||
build_agent_env_policy::ALLOWED_BUILD_AGENT_ENV_KEYS
|
||||
);
|
||||
}
|
||||
}
|
||||
let encoded = base64::engine::general_purpose::STANDARD.encode(raw.as_bytes());
|
||||
println!("cargo:rustc-env=BUZZ_DESKTOP_BUILD_AGENT_ENV={encoded}");
|
||||
|
||||
@@ -234,8 +234,8 @@ pub async fn get_runtime_file_config(
|
||||
|
||||
/// Return the key names of all non-empty baked build env vars.
|
||||
///
|
||||
/// Internal (Block) builds bake provider credentials and other env pairs into
|
||||
/// the binary at compile time via `BUZZ_BUILD_AGENT_ENV`. The backend readiness
|
||||
/// Internal (Block) builds bake provider/model defaults and a small allowlist
|
||||
/// of non-secret settings into the binary at compile time. The backend readiness
|
||||
/// gate already treats these keys as satisfying their requirements (Layer 1 of
|
||||
/// `resolve_effective_agent_env`). This command exposes the *key names only* —
|
||||
/// never the values — so the frontend dialogs can apply the same logic and avoid
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
//! Build-time agent env passthrough.
|
||||
//!
|
||||
//! Internal builds (buzz-releases) bake arbitrary `KEY=VALUE` pairs into the
|
||||
//! binary via `BUZZ_BUILD_AGENT_ENV` (base64-encoded, newline-delimited).
|
||||
//! Internal builds (buzz-releases) bake a small allowlist of non-secret
|
||||
//! `KEY=VALUE` settings into the binary via `BUZZ_BUILD_AGENT_ENV`
|
||||
//! (base64-encoded, newline-delimited).
|
||||
//! OSS builds leave the compile-time var unset — nothing is injected.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use base64::Engine as _;
|
||||
|
||||
use super::build_agent_env_policy::is_allowed_build_agent_env_key;
|
||||
|
||||
/// Return the baked-in build-time env pairs as a map.
|
||||
///
|
||||
/// Internal builds (buzz-releases) bake provider/model defaults and arbitrary
|
||||
/// `KEY=VALUE` pairs into the binary at compile time. This function returns
|
||||
/// Internal builds (buzz-releases) bake provider/model defaults and allowlisted
|
||||
/// non-secret settings into the binary at compile time. This function returns
|
||||
/// those pairs as an owned map so callers can fold them into an in-process env
|
||||
/// at the **lowest** precedence layer — user/persona values layered on top
|
||||
/// override these baked defaults (last-write-wins, matching the existing
|
||||
@@ -53,7 +56,9 @@ fn build_env_map(
|
||||
if let Ok(decoded) = base64::engine::general_purpose::STANDARD.decode(raw.as_bytes()) {
|
||||
if let Ok(text) = std::str::from_utf8(&decoded) {
|
||||
for (key, value) in parse_agent_env_lines(text) {
|
||||
map.insert(key.to_string(), value.to_string());
|
||||
if is_allowed_build_agent_env_key(key) {
|
||||
map.insert(key.to_string(), value.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,6 +116,7 @@ mod tests {
|
||||
baked_build_env, build_buzz_agent_provider_defaults, build_env_map,
|
||||
discovery_env_with_baked_floor, parse_agent_env_lines,
|
||||
};
|
||||
use crate::managed_agents::build_agent_env_policy::is_allowed_build_agent_env_key;
|
||||
|
||||
#[test]
|
||||
fn buzz_agent_provider_defaults_empty_in_oss_build() {
|
||||
@@ -301,6 +307,25 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_agent_env_policy_rejects_credentials_at_build_and_runtime_boundaries() {
|
||||
use base64::Engine as _;
|
||||
|
||||
assert!(is_allowed_build_agent_env_key("DATABRICKS_MODEL"));
|
||||
for key in ["GITHUB_TOKEN", "ANTHROPIC_API_KEY", "DB_PASSWORD"] {
|
||||
assert!(!is_allowed_build_agent_env_key(key), "{key}");
|
||||
}
|
||||
|
||||
let raw = "DATABRICKS_MODEL=reviewed-model\nGITHUB_TOKEN=must-not-be-embedded";
|
||||
let blob = base64::engine::general_purpose::STANDARD.encode(raw.as_bytes());
|
||||
let map = build_env_map(None, None, Some(&blob));
|
||||
assert_eq!(
|
||||
map.get("DATABRICKS_MODEL").map(String::as_str),
|
||||
Some("reviewed-model")
|
||||
);
|
||||
assert!(!map.contains_key("GITHUB_TOKEN"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_env_map_user_env_overrides_baked_via_btreemap_extend() {
|
||||
// Validates the precedence fold used in agent_models.rs:
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/// Non-secret settings that internal release builds may embed through
|
||||
/// `BUZZ_BUILD_AGENT_ENV`.
|
||||
pub(crate) const ALLOWED_BUILD_AGENT_ENV_KEYS: &[&str] = &[
|
||||
"BUZZ_AGENT_THINKING_EFFORT",
|
||||
"DATABRICKS_HOST",
|
||||
"DATABRICKS_MODEL",
|
||||
];
|
||||
|
||||
/// Return whether `key` is approved non-secret build configuration.
|
||||
pub(crate) fn is_allowed_build_agent_env_key(key: &str) -> bool {
|
||||
ALLOWED_BUILD_AGENT_ENV_KEYS.contains(&key)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
mod agent_env;
|
||||
pub(crate) mod agent_events;
|
||||
pub(crate) mod agent_snapshot;
|
||||
mod build_agent_env_policy;
|
||||
pub(crate) mod team_snapshot;
|
||||
pub(crate) use agent_env::{
|
||||
baked_build_env, build_buzz_agent_provider_defaults, discovery_env_with_baked_floor,
|
||||
|
||||
Reference in New Issue
Block a user