Synced from monorepo

Changes:
- grok-shell: request workspaces:read/write OAuth2 scopes
- security: fix SSRF bypass via HTTP redirect in hook runner
- fix(grok-build): enterprise STT WSS URL + API-key voice bearer
- Harden identity-change purge and sync-marker invariants
- sandbox + workspace-server: delete the legacy ready-file arm
- Show billing URL when browser cannot open
- fix(pager): show folder-trust UI in minimal mode
- fix(pager): drain task_backgrounded before no-wait headless exit
- grok-agent-sdk: stop SDK-spawned agents from staging self-updates they can never adopt
- Split settings_modal into directory module
- Delegate VS Code SSH file links
- grok-shell: release the workspace session binding when a session is removed
- keep skills reachable when their name collides with a client builtin
- Preserve semantic link targets
This commit is contained in:
grokkybara[bot] 2026-07-16 20:27:30 +01:00
commit 8adf9013a0
117 changed files with 16998 additions and 14540 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "xai-grok-pager-bin"
version = "0.1.220-alpha.4"
version = "0.2.101"
edition.workspace = true
license = "Apache-2.0"
authors = ["xAI"]
@ -92,6 +92,5 @@ default-bazel = [
"sandbox-enforce",
]
jemalloc = ["dep:tikv-jemallocator", "dep:tikv-jemalloc-sys", "dep:tikv-jemalloc-ctl"]
# Forward the sandbox-enforcement feature to the library.
sandbox-enforce = ["xai-grok-pager/sandbox-enforce"]
release-dist = ["xai-grok-pager/release-dist"]

View file

@ -200,6 +200,11 @@ async fn run_setup_command(json: bool) {
"Your team doesn't have a managed configuration yet. A team admin can set one up at console.x.ai."
);
}
SetupOutcome::Skipped => {
eprintln!(
"Managed configuration was not applied this run (another process held the apply lock, or the credential changed during the fetch). Run `grok setup` again."
);
}
SetupOutcome::Failed(e) => {
eprintln!("Couldn't apply managed configuration. {e}");
std::process::exit(1);
@ -1081,9 +1086,16 @@ async fn run_agent_command(
leader_eligible,
);
tracing::info!(use_leader, ?policy_disable_reason, "leader mode resolved");
if stdio_direct_update_eligible(is_stdio, use_leader)
&& should_check_for_updates(no_auto_update)
{
let managed_install = is_managed_install(
std::env::current_exe().ok(),
&xai_grok_shell::util::grok_home::grok_home(),
);
if stdio_auto_update_enabled(
is_stdio,
use_leader,
should_check_for_updates(no_auto_update),
managed_install,
) {
let update_config = update_config.clone();
tokio::spawn(async move {
auto_update::run_update_if_available(
@ -1094,6 +1106,8 @@ async fn run_agent_command(
.await
.ok();
});
} else if is_stdio && !use_leader && !managed_install {
tracing::debug!("stdio auto-update skipped: not the managed install");
}
if use_leader {
if !agent_args.plugin_dirs.is_empty() {
@ -2082,8 +2096,8 @@ fn build_update_config() -> UpdateConfig {
}
config
}
/// Centralized gate for all auto-update checks. Add new suppression
/// rules here — not at each call site.
/// Central gate for auto-update checks; add new suppression rules here,
/// not at call sites.
fn should_check_for_updates(no_auto_update_flag: bool) -> bool {
if cfg!(debug_assertions) {
return false;
@ -2091,21 +2105,35 @@ fn should_check_for_updates(no_auto_update_flag: bool) -> bool {
if no_auto_update_flag {
return false;
}
if std::env::var_os("GROK_DISABLE_AUTOUPDATER").is_some() {
!std::env::var_os("GROK_DISABLE_AUTOUPDATER")
.is_some_and(|v| env_flag_enabled(&v.to_string_lossy()))
}
/// Gate for the stdio agent's background auto-update: only the direct stdio
/// agent, from the managed install. Other modes update in `run_agent_command`.
fn stdio_auto_update_enabled(
is_stdio: bool,
use_leader: bool,
updates_enabled: bool,
managed_install: bool,
) -> bool {
is_stdio && !use_leader && updates_enabled && managed_install
}
/// True when `exe` is the binary `<grok_home>/bin/grok` resolves to, the
/// install that adopts a staged update on respawn. Both sides are
/// canonicalized; any failure reports unmanaged and skips the update. The
/// npm shim hardcodes `~/.grok`, so a custom `GROK_HOME` skips here too.
fn is_managed_install(exe: Option<std::path::PathBuf>, grok_home: &std::path::Path) -> bool {
if grok_home.as_os_str().is_empty() {
return false;
}
true
}
/// Mode-gate for the direct stdio agent's background auto-update.
///
/// Only the *direct* stdio agent is newly eligible: every other agent mode
/// already self-updates at the top of `run_agent_command`, and a leader-backed
/// stdio process is a thin bridge whose updates are owned by the leader
/// (`LeaderAutoUpdateConfig`). Update suppression (`--no-auto-update`,
/// `GROK_DISABLE_AUTOUPDATER`, debug builds) is layered on separately via
/// [`should_check_for_updates`].
fn stdio_direct_update_eligible(is_stdio: bool, use_leader: bool) -> bool {
is_stdio && !use_leader
let Some(exe) = exe else {
return false;
};
let managed = xai_grok_config::grok_application_in(grok_home);
match (dunce::canonicalize(&exe), dunce::canonicalize(&managed)) {
(Ok(exe), Ok(managed)) => exe == managed,
_ => false,
}
}
/// Map the mutually-exclusive channel flags to a channel name. clap enforces
/// that at most one is set, so the order is irrelevant.
@ -2380,27 +2408,55 @@ mod tests {
xai_grok_shell::heap_profile::dump_to_path(dump.path()).expect("shell dump");
dump.assert_nonempty_dump();
}
/// Only the direct (non-leader) stdio agent is newly eligible for the
/// background auto-update. Leader-backed stdio defers to the leader's own
/// updater, and non-stdio modes already update at the top of
/// `run_agent_command`.
#[cfg(unix)]
#[test]
fn stdio_direct_update_eligible_only_for_non_leader_stdio() {
fn is_managed_install_matches_only_the_bin_grok_target() {
let home =
std::env::temp_dir().join(format!("grok-pager-managed-install-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&home);
std::fs::create_dir_all(home.join("bin")).unwrap();
std::fs::create_dir_all(home.join("downloads")).unwrap();
assert!(!is_managed_install(
Some(home.join("bin").join("grok")),
&home
));
assert!(!is_managed_install(None, &home));
assert!(!is_managed_install(
Some(home.join("bin").join("grok")),
std::path::Path::new("")
));
let target = home.join("downloads").join("grok-1.2.3");
std::fs::write(&target, b"binary").unwrap();
std::os::unix::fs::symlink(&target, home.join("bin").join("grok")).unwrap();
assert!(is_managed_install(
Some(home.join("bin").join("grok")),
&home
));
assert!(is_managed_install(Some(target.clone()), &home));
let pinned = home.join("bin").join("grok-9.9.9");
std::fs::write(&pinned, b"binary").unwrap();
assert!(!is_managed_install(Some(pinned), &home));
let _ = std::fs::remove_dir_all(&home);
}
/// Pins the gate composition; a dropped conjunct fails its named case.
#[test]
fn stdio_auto_update_requires_direct_stdio_enabled_and_managed() {
assert!(stdio_auto_update_enabled(true, false, true, true));
assert!(
stdio_direct_update_eligible(true, false),
"direct stdio agent should be eligible",
!stdio_auto_update_enabled(true, true, true, true),
"leader bridge"
);
assert!(
!stdio_direct_update_eligible(true, true),
"leader-backed stdio defers to the leader's updater",
!stdio_auto_update_enabled(false, false, true, true),
"non-stdio"
);
assert!(
!stdio_direct_update_eligible(false, false),
"non-stdio modes update at the top of run_agent_command",
!stdio_auto_update_enabled(true, false, false, true),
"updates off"
);
assert!(
!stdio_direct_update_eligible(false, true),
"non-stdio leader path is not stdio-eligible",
!stdio_auto_update_enabled(true, false, true, false),
"pinned binary"
);
}
use clap::Parser as _;