Publish harness and TUI open-source

initial sync from the monorepo
This commit is contained in:
grokkybara[bot] 2026-07-16 06:46:02 +01:00
commit c68e39f604
2734 changed files with 1437016 additions and 0 deletions

View file

@ -0,0 +1,991 @@
//! Unit tests for the external stream: pinned allowlists, per-event schema
//! snapshots, canary leak tests, gate enforcement, and the tighten-only
//! remote policy. Everything asserting wire shape goes through the
//! in-memory exporters *behind the export-time validators*, so the tests pin
//! what actually leaves the process.
use super::config::ContentGates;
use super::schema::{self, AttrValue, ExternalKey, ExternalRecord, MetricIncrement};
use super::test_support::{TestStream, build, emit_event_into, emit_into};
use crate::events;
use opentelemetry::logs::AnyValue;
fn gates_off() -> ContentGates {
ContentGates::default()
}
fn gates_all_on() -> ContentGates {
ContentGates {
log_user_prompts: true,
log_tool_details: true,
}
}
/// Exported (event_name, sorted attr key/value-debug pairs) for assertions.
fn exported_events(stream: &TestStream) -> Vec<(String, Vec<(String, String)>)> {
stream
.logs
.get_emitted_logs()
.expect("in-memory logs")
.iter()
.map(|log| {
let record = &log.record;
let mut attrs: Vec<(String, String)> = record
.attributes_iter()
.map(|(k, v)| {
let value = match v {
AnyValue::String(s) => s.as_str().to_owned(),
AnyValue::Int(i) => i.to_string(),
AnyValue::Boolean(b) => b.to_string(),
other => format!("{other:?}"),
};
(k.as_str().to_owned(), value)
})
.collect();
attrs.sort();
(record.event_name().unwrap_or("?").to_owned(), attrs)
})
.collect()
}
fn attr_keys(event: &(String, Vec<(String, String)>)) -> Vec<&str> {
event.1.iter().map(|(k, _)| k.as_str()).collect()
}
fn attr(event: &(String, Vec<(String, String)>), key: &str) -> Option<String> {
event
.1
.iter()
.find(|(k, _)| k == key)
.map(|(_, v)| v.clone())
}
/// All exported metric (name, sorted data-point attr keys) pairs.
fn exported_metric_names(stream: &TestStream) -> Vec<String> {
stream
.metrics
.get_finished_metrics()
.expect("in-memory metrics")
.iter()
.flat_map(|rm| {
rm.scope_metrics()
.flat_map(|s| s.metrics().map(|m| m.name().to_owned()))
.collect::<Vec<_>>()
})
.collect()
}
// ─────────────────────────────────────────────────────────────────────────────
// Pinned allowlists
// ─────────────────────────────────────────────────────────────────────────────
#[test]
fn external_allowed_keys_are_pinned() {
// Keep this an independent copy — don't reference ALL_KEYS or
// ExternalKey::as_str, or the assert becomes a tautology and stops gating
// schema changes. Adding a key exports a new field: confirm it carries no
// user content, then update this pin.
let expected: &[&str] = &[
"session.id",
"turn_number",
"prompt.id",
"event.sequence",
"user.id",
"organization.id",
"team.id",
"deployment.id",
"model",
"permission_mode",
"mcp_server_count",
"plugin_count",
"skill_count",
"hook_count",
"memory_enabled",
"is_git_repo",
"client_identifier",
"duration_secs",
"turn_count",
"tool_call_count",
"compaction_count",
"prompt_length",
"prompt",
"screen_mode",
"outcome",
"duration_ms",
"error_category",
"cancellation_category",
"stop_reason",
"input_tokens",
"output_tokens",
"reasoning_tokens",
"cache_read_tokens",
"status_code",
"tool_name",
"success",
"file_extension",
"tool_parameters",
"file_path",
"decision",
"access_kind",
"source",
"status",
"transport_type",
"tool_count",
"error_type",
"mcp_server.name",
"to_mode",
"trigger",
"skill_source",
"skill.name",
"install_kind",
"plugin_scope",
"plugin_name",
"plugin_version",
"compaction_trigger",
"compaction_outcome",
"tokens_before",
"tokens_after",
"phase",
"subagent_type",
"auth_method",
"from_model",
"to_model",
"error_code",
"tip",
"action",
];
let actual: Vec<&str> = schema::ALL_KEYS.iter().map(|k| k.as_str()).collect();
assert_eq!(
actual, expected,
"EXTERNAL_ALLOWED_KEYS changed: a new key is a wire-schema change — confirm it carries \
no user content, then update this pin."
);
// Notably absent: the internal allowlist's file-path family.
for forbidden in ["path", "cwd", "repo_path", "worktree", "gcs_path"] {
assert!(
!schema::external_allowed_keys().contains(forbidden),
"{forbidden} must never be externally allowlisted"
);
}
}
#[test]
fn metric_attr_keys_are_pinned() {
let expected: &[&str] = &[
"type",
"model",
"outcome",
"tool_name",
"decision",
"access_kind",
"permission_mode",
"error_category",
"session.id",
"app.version",
"user.id",
"organization.id",
"team.id",
"deployment.id",
];
assert_eq!(
schema::METRIC_ALLOWED_ATTR_KEYS,
expected,
"metric attribute keys changed — wire-schema change"
);
assert!(
!schema::METRIC_ALLOWED_ATTR_KEYS.contains(&"prompt.id"),
"prompt.id is events-only (unbounded cardinality on metrics)"
);
}
#[test]
fn event_names_are_pinned() {
use schema::ExternalEventName as E;
let expected: &[(E, &str)] = &[
(E::SessionStart, "grok_code.session_start"),
(E::SessionEnd, "grok_code.session_end"),
(E::UserPrompt, "grok_code.user_prompt"),
(E::TurnCompleted, "grok_code.turn_completed"),
(E::ApiRequest, "grok_code.api_request"),
(E::ApiError, "grok_code.api_error"),
(E::ToolResult, "grok_code.tool_result"),
(E::ToolDecision, "grok_code.tool_decision"),
(E::McpServerConnection, "grok_code.mcp_server_connection"),
(
E::PermissionModeChanged,
"grok_code.permission_mode_changed",
),
(E::SkillActivated, "grok_code.skill_activated"),
(E::PluginLoaded, "grok_code.plugin_loaded"),
(E::Compaction, "grok_code.compaction"),
(E::Subagent, "grok_code.subagent"),
(E::Auth, "grok_code.auth"),
(E::InternalError, "grok_code.internal_error"),
(E::ModelSwitched, "grok_code.model_switched"),
(E::ContextualTip, "grok_code.contextual_tip"),
];
assert_eq!(expected.len(), <E as strum::EnumCount>::COUNT);
for (variant, name) in expected {
assert_eq!(variant.as_str(), *name, "event name is a wire commitment");
}
}
#[test]
fn client_identifier_allowlist_is_pinned() {
let expected: &[&str] = &[
"grok-pager",
"grok-tui",
"grok-shell",
"grok-web",
"grok-desktop",
"grok-code-extension",
"nebula",
"zed",
];
assert_eq!(schema::KNOWN_CLIENT_IDENTIFIERS, expected);
assert_eq!(
schema::sanitize_client_identifier("grok-pager"),
"grok-pager"
);
assert_eq!(
schema::sanitize_client_identifier("Evil Corp Internal Tool v2"),
"other",
"unknown client identifiers are externally controlled free text and must collapse"
);
}
#[test]
fn screen_mode_allowlist_is_pinned() {
let expected: &[&str] = &["fullscreen", "inline", "minimal", "headless"];
assert_eq!(schema::KNOWN_SCREEN_MODES, expected);
assert_eq!(schema::sanitize_screen_mode("minimal"), "minimal");
assert_eq!(
schema::sanitize_screen_mode("my-custom-fork-mode"),
"other",
"unknown screen modes are externally controlled free text and must collapse"
);
}
#[test]
fn tool_name_sanitization() {
assert_eq!(schema::sanitize_tool_name("read_file"), "read_file");
assert_eq!(
schema::sanitize_tool_name("nebula__post_message"),
"mcp_tool"
);
assert_eq!(
schema::sanitize_tool_name("SuperSecretProjectTool"),
"custom_tool",
"unknown tool names must not pass verbatim"
);
}
#[test]
fn file_extension_reduction() {
assert_eq!(
schema::file_extension("/Users/alice/proj/main.rs"),
Some("rs".into())
);
assert_eq!(schema::file_extension("src/App.TSX"), Some("tsx".into()));
assert_eq!(schema::file_extension("Makefile"), None);
// 10-char cap.
assert_eq!(
schema::file_extension("x.aaaaaaaaaaaaaaaa"),
Some("aaaaaaaaaa".into())
);
}
// ─────────────────────────────────────────────────────────────────────────────
// Schema snapshots (gates off / on) through the wire-view harness
// ─────────────────────────────────────────────────────────────────────────────
fn sentinel_session_harness() -> events::SessionHarness {
events::SessionHarness {
session_id: "sess-1".into(),
client_identifier: Some("grok-pager".into()),
model_id: "grok-4".into(),
agent_name: "grok-build-plan".into(),
permission_mode: crate::enums::PermissionMode::Ask,
mcp_server_names: vec!["secret-server".into(), "other".into()],
plugin_names: vec!["p1".into()],
skill_names: vec!["s1".into(), "s2".into(), "s3".into()],
lsp_server_names: vec![],
hook_names: vec!["h1".into()],
agents_md_dir_names: vec!["proj".into()],
memory_enabled: true,
is_git_repo: true,
auto_update: None,
}
}
#[test]
fn session_start_snapshot_counts_not_names() {
let stream = build(gates_off());
emit_event_into(&stream, &sentinel_session_harness());
let events = exported_events(&stream);
assert_eq!(events.len(), 1);
let ev = &events[0];
assert_eq!(ev.0, "grok_code.session_start");
let mut keys = attr_keys(ev);
keys.sort();
assert_eq!(
keys,
vec![
"client_identifier",
"event.sequence",
"hook_count",
"is_git_repo",
"mcp_server_count",
"memory_enabled",
"model",
"permission_mode",
"plugin_count",
"session.id",
"skill_count",
]
);
assert_eq!(attr(ev, "mcp_server_count").as_deref(), Some("2"));
assert_eq!(attr(ev, "skill_count").as_deref(), Some("3"));
assert_eq!(attr(ev, "session.id").as_deref(), Some("sess-1"));
// Names (MCP/plugin/skill/hook) never appear, only counts.
let blob = format!("{events:?}");
assert!(!blob.contains("secret-server"), "MCP name leaked: {blob}");
}
#[test]
fn session_new_increments_session_count_only() {
let stream = build(gates_off());
emit_event_into(
&stream,
&events::SessionNew {
session_id: "sess-2".into(),
client_identifier: None,
client_version: None,
is_git_repo: false,
permission_mode: crate::enums::PermissionMode::Ask,
},
);
assert!(exported_events(&stream).is_empty(), "metric-only mapping");
let names = exported_metric_names(&stream);
assert_eq!(names, vec!["grok_code.session.count".to_owned()]);
}
#[test]
fn api_request_snapshot_and_token_usage() {
let stream = build(gates_off());
emit_event_into(
&stream,
&events::ModelResponseReceived {
model_id: "grok-4".into(),
duration_ms: 1200,
stop_reason: Some("stop".into()),
prompt_tokens: Some(100),
completion_tokens: Some(50),
reasoning_tokens: Some(25),
cached_prompt_tokens: None,
},
);
let events = exported_events(&stream);
let ev = &events[0];
assert_eq!(ev.0, "grok_code.api_request");
assert_eq!(attr(ev, "input_tokens").as_deref(), Some("100"));
assert_eq!(attr(ev, "output_tokens").as_deref(), Some("50"));
assert_eq!(attr(ev, "reasoning_tokens").as_deref(), Some("25"));
assert_eq!(attr(ev, "cache_read_tokens"), None);
assert_eq!(
exported_metric_names(&stream),
vec!["grok_code.token.usage"]
);
}
/// One failed turn ⇒ exactly one `error.count` increment, even though the
/// failure emits `ApiError` (and possibly `RateLimitHit`) *alongside*
/// `TurnCompleted{Error}`. `TurnCompleted{Error}` is the single increment
/// source; the api_error log events carry no metric (Bugbot regression:
/// double-counted errors at customer collectors).
#[test]
fn one_failed_turn_increments_error_count_exactly_once() {
let stream = build(gates_off());
// The turn-error path emits all three for a rate-limited failure.
emit_event_into(
&stream,
&events::RateLimitHit {
model_id: "grok-4".into(),
attempts: 3,
},
);
emit_event_into(
&stream,
&events::ApiError {
error_category: "rate_limit".into(),
model_id: "grok-4".into(),
status_code: Some(429),
duration_ms: Some(10),
},
);
emit_event_into(
&stream,
&events::TurnCompleted {
outcome: events::Outcome::Error,
duration_ms: 10,
tool_call_count: 0,
model_id: "grok-4".into(),
cancellation_category: None,
error_category: Some("rate_limit".into()),
},
);
// Both api_error events exported as log records…
let names: Vec<String> = exported_events(&stream)
.iter()
.map(|e| e.0.clone())
.collect();
assert_eq!(
names.iter().filter(|n| *n == "grok_code.api_error").count(),
2
);
// …but error.count incremented exactly once.
let total: u64 = stream
.metrics
.get_finished_metrics()
.unwrap()
.iter()
.flat_map(|rm| rm.scope_metrics())
.flat_map(|s| s.metrics())
.filter(|m| m.name() == "grok_code.error.count")
.map(|m| match m.data() {
opentelemetry_sdk::metrics::data::AggregatedMetrics::U64(
opentelemetry_sdk::metrics::data::MetricData::Sum(sum),
) => sum.data_points().map(|p| p.value()).sum::<u64>(),
_ => 0,
})
.sum();
assert_eq!(total, 1, "one failed turn must count exactly one error");
}
#[test]
fn turn_error_increments_error_count() {
let stream = build(gates_off());
emit_event_into(
&stream,
&events::TurnCompleted {
outcome: events::Outcome::Error,
duration_ms: 10,
tool_call_count: 0,
model_id: "grok-4".into(),
cancellation_category: None,
error_category: Some("server_error".into()),
},
);
let mut names = exported_metric_names(&stream);
names.sort();
assert_eq!(names, vec!["grok_code.error.count", "grok_code.turn.count"]);
}
#[test]
fn tool_result_gates_off_collapses_and_reduces() {
let stream = build(gates_off());
emit_event_into(
&stream,
&events::ToolCallCompleted {
tool_name: "nebula__post_message".into(),
outcome: xai_file_utils::events::types::ToolOutcome::Success,
duration_ms: 42,
file_path: Some("/Users/alice/secret-project/main.rs".into()),
parameters: Some(serde_json::json!({"text": "CANARY_TOOL_ARGS"})),
},
);
let events = exported_events(&stream);
let ev = &events[0];
assert_eq!(ev.0, "grok_code.tool_result");
assert_eq!(attr(ev, "tool_name").as_deref(), Some("mcp_tool"));
assert_eq!(attr(ev, "file_extension").as_deref(), Some("rs"));
assert_eq!(attr(ev, "file_path"), None, "full path is details-gated");
assert_eq!(
attr(ev, "tool_parameters"),
None,
"params are details-gated"
);
let blob = format!("{events:?}");
assert!(
!blob.contains("CANARY_TOOL_ARGS"),
"tool args leaked: {blob}"
);
assert!(!blob.contains("secret-project"), "path leaked: {blob}");
}
#[test]
fn tool_result_details_gate_exposes_verbatim_scrubbed() {
let stream = build(gates_all_on());
// Use the *real* home dir: `redact_user_paths` collapses the current
// user's home (env-derived), not arbitrary foreign paths.
let home = dirs::home_dir()
.map(|h| h.to_string_lossy().into_owned())
.unwrap_or_else(|| "/home/testuser".into());
let path = format!("{home}/proj/main.rs");
emit_event_into(
&stream,
&events::ToolCallCompleted {
tool_name: "nebula__post_message".into(),
outcome: xai_file_utils::events::types::ToolOutcome::Success,
duration_ms: 42,
file_path: Some(path.clone()),
parameters: Some(serde_json::json!({"key": "sk-CANARYabcdefghij1234567890"})),
},
);
let events = exported_events(&stream);
let ev = &events[0];
assert_eq!(
attr(ev, "tool_name").as_deref(),
Some("nebula__post_message"),
"details gate exposes the verbatim name"
);
let exported_path = attr(ev, "file_path").expect("details gate exposes the path");
// Secrets are STILL scrubbed inside gated content; the home dir collapses.
let blob = format!("{events:?}");
assert!(
!blob.contains("CANARY"),
"secret inside gated params leaked: {blob}"
);
assert!(
!exported_path.contains(&home),
"home dir not collapsed in gated path: {exported_path}"
);
assert!(exported_path.contains("proj/main.rs"));
}
#[test]
fn user_prompt_gates_off_drops_text() {
let stream = build(gates_off());
emit_event_into(
&stream,
&events::PromptSubmitted {
prompt_length: 26,
model_id: "grok-4".into(),
client_identifier: None,
screen_mode: Some("minimal".into()),
prompt_text: Some("CANARY_PROMPT secret user text".into()),
},
);
let events = exported_events(&stream);
let ev = &events[0];
assert_eq!(ev.0, "grok_code.user_prompt");
assert_eq!(attr(ev, "prompt_length").as_deref(), Some("26"));
// screen_mode is ungated session metadata, not prompt content.
assert_eq!(attr(ev, "screen_mode").as_deref(), Some("minimal"));
assert_eq!(attr(ev, "prompt"), None);
let blob = format!("{events:?}");
assert!(
!blob.contains("CANARY_PROMPT"),
"prompt text leaked: {blob}"
);
}
/// `screen_mode` is externally controlled free text (ACP `_meta.screenMode`);
/// unknown values must collapse to `"other"` on the wire, and an absent value
/// must emit no attribute at all.
#[test]
fn user_prompt_screen_mode_sanitized_and_optional() {
let stream = build(gates_off());
emit_event_into(
&stream,
&events::PromptSubmitted {
prompt_length: 5,
model_id: "grok-4".into(),
client_identifier: None,
screen_mode: Some("Evil Free Text".into()),
prompt_text: None,
},
);
emit_event_into(
&stream,
&events::PromptSubmitted {
prompt_length: 5,
model_id: "grok-4".into(),
client_identifier: None,
screen_mode: None,
prompt_text: None,
},
);
let events = exported_events(&stream);
assert_eq!(attr(&events[0], "screen_mode").as_deref(), Some("other"));
assert_eq!(attr(&events[1], "screen_mode"), None);
}
#[test]
fn user_prompt_gate_on_exports_scrubbed_text() {
let stream = build(gates_all_on());
emit_event_into(
&stream,
&events::PromptSubmitted {
prompt_length: 10,
model_id: "grok-4".into(),
client_identifier: None,
screen_mode: None,
prompt_text: Some("fix the bug; token sk-CANARYabcdefghij1234567890".into()),
},
);
let events = exported_events(&stream);
let ev = &events[0];
let prompt = attr(ev, "prompt").expect("gate on ⇒ prompt exported");
assert!(prompt.contains("fix the bug"));
assert!(
!prompt.contains("CANARY"),
"secret inside prompt not scrubbed"
);
}
#[test]
fn mcp_connection_collapses_server_name_by_default() {
let stream = build(gates_off());
emit_event_into(
&stream,
&events::McpServerFailed {
server_name: "corp-internal-jira".into(),
error_type: events::McpErrorType::Timeout,
duration_ms: 1000,
timeout_sec: 30,
},
);
let events = exported_events(&stream);
let ev = &events[0];
assert_eq!(ev.0, "grok_code.mcp_server_connection");
assert_eq!(attr(ev, "status").as_deref(), Some("failed"));
assert_eq!(attr(ev, "mcp_server.name").as_deref(), Some("mcp_server"));
assert_eq!(attr(ev, "error_type").as_deref(), Some("timeout"));
assert!(!format!("{events:?}").contains("corp-internal-jira"));
}
#[test]
fn tool_decision_snapshot() {
let stream = build(gates_off());
emit_event_into(
&stream,
&events::PermissionDecisionPayload {
tool_name: "run_terminal_cmd".into(),
access_kind: events::AccessKind::Bash,
decision: events::PermissionOutcome::Deny,
wait_ms: 1500,
permission_mode: crate::enums::PermissionMode::Ask,
source: Some("user_reject".into()),
subagent_session_id: None,
subagent_type: None,
},
);
let events = exported_events(&stream);
let ev = &events[0];
assert_eq!(ev.0, "grok_code.tool_decision");
assert_eq!(attr(ev, "tool_name").as_deref(), Some("run_terminal_cmd"));
assert_eq!(attr(ev, "decision").as_deref(), Some("deny"));
assert_eq!(attr(ev, "access_kind").as_deref(), Some("bash"));
assert_eq!(attr(ev, "permission_mode").as_deref(), Some("ask"));
assert_eq!(attr(ev, "source").as_deref(), Some("user_reject"));
assert_eq!(
exported_metric_names(&stream),
vec!["grok_code.tool.decision"]
);
}
#[test]
fn skill_activated_name_gated() {
let stream = build(gates_off());
emit_event_into(
&stream,
&events::SkillDispatched {
skill_name: "internal-deploy-runbook".into(),
plugin_source: None,
},
);
let events = exported_events(&stream);
let ev = &events[0];
assert_eq!(attr(ev, "skill_source").as_deref(), Some("local"));
assert_eq!(attr(ev, "skill.name"), None);
assert!(!format!("{events:?}").contains("internal-deploy-runbook"));
}
#[test]
fn contextual_tip_maps_every_tip_and_action() {
use events::{ContextualTipAction as A, ContextualTipKind as K};
let cases = [
(K::Undo, A::Shown, "undo", "shown"),
(K::Undo, A::Accepted, "undo", "accepted"),
(K::PlanMode, A::Shown, "plan_mode", "shown"),
(K::PlanMode, A::Accepted, "plan_mode", "accepted"),
(K::ImageInput, A::Shown, "image_input", "shown"),
(K::ImageInput, A::Accepted, "image_input", "accepted"),
(K::SendNow, A::Shown, "send_now", "shown"),
(K::SendNow, A::Accepted, "send_now", "accepted"),
(K::SmallScreen, A::Shown, "small_screen", "shown"),
(K::SmallScreen, A::Accepted, "small_screen", "accepted"),
(K::WordSelect, A::Shown, "word_select", "shown"),
(K::WordSelect, A::Accepted, "word_select", "accepted"),
];
for (tip, action, tip_label, action_label) in cases {
let stream = build(gates_off());
emit_event_into(&stream, &events::ContextualTip { tip, action });
let events = exported_events(&stream);
let ev = &events[0];
assert_eq!(ev.0, "grok_code.contextual_tip");
assert_eq!(attr(ev, "tip").as_deref(), Some(tip_label));
assert_eq!(attr(ev, "action").as_deref(), Some(action_label));
}
}
#[test]
fn unmapped_events_produce_nothing() {
use crate::events::TelemetryEvent as _;
// ~70 events without an `external = …` arm cost nothing and export nothing.
let ev = events::SlashCommandUsed {
command: "secret command".into(),
args_provided: true,
};
assert!(ev.external_record().is_none());
}
/// Workspace-origin exclusion: events emitted exclusively via
/// `EmitterOrigin::Workspace` (`log_session_event_with_origin`) must not carry
/// an external mapping — the fan-out hook deliberately lives only in the
/// Shell-origin wrappers. The workspace-only surface today is the
/// xai-grok-workspace sampler events, which live outside this crate and have
/// no `telemetry_event!` binding here; this pin guards the in-crate set.
#[test]
fn workspace_only_events_have_no_external_mapping() {
use crate::events::TelemetryEvent as _;
// Trace-upload lifecycle events are session-metrics/internal-only.
assert!(
crate::session_metrics::TraceUploadAttempted {
session_id: String::new(),
turn_number: 0,
upload_method: "proxy".into(),
}
.external_record()
.is_none()
);
}
// ─────────────────────────────────────────────────────────────────────────────
// Emit-path behavior: ctx injection, sequence, identity, truncation
// ─────────────────────────────────────────────────────────────────────────────
#[test]
fn mapping_supplied_session_id_wins_and_sequence_increments() {
let stream = build(gates_off());
emit_event_into(&stream, &sentinel_session_harness());
emit_event_into(&stream, &sentinel_session_harness());
let events = exported_events(&stream);
assert_eq!(events.len(), 2);
assert_eq!(attr(&events[0], "event.sequence").as_deref(), Some("0"));
assert_eq!(attr(&events[1], "event.sequence").as_deref(), Some("1"));
assert_eq!(attr(&events[0], "session.id").as_deref(), Some("sess-1"));
}
#[test]
fn identity_attrs_attached_when_set_and_blank_ids_never_export() {
let stream = build(gates_off());
super::set_identity_on(
&stream.ext,
super::IdentityAttrs {
user_id: Some("user-42".into()),
organization_id: Some(String::new()), // blank: must not export
team_id: None,
deployment_id: Some("dep-7".into()),
},
);
emit_event_into(&stream, &sentinel_session_harness());
let events = exported_events(&stream);
let ev = &events[0];
assert_eq!(attr(ev, "user.id").as_deref(), Some("user-42"));
assert_eq!(attr(ev, "deployment.id").as_deref(), Some("dep-7"));
assert_eq!(attr(ev, "organization.id"), None, "blank ids never export");
assert_eq!(attr(ev, "team.id"), None);
}
#[test]
fn long_attr_values_truncated() {
let stream = build(gates_off());
let long_model = "m".repeat(1000);
emit_into(
&stream,
ExternalRecord {
event: Some(schema::ExternalEventName::ApiRequest),
attrs: vec![(ExternalKey::Model, AttrValue::Str(long_model))],
gated: vec![],
metrics: vec![],
},
);
let events = exported_events(&stream);
let model = attr(&events[0], "model").unwrap();
assert!(
model.len() < 200,
"value not truncated: {} chars",
model.len()
);
assert!(model.ends_with("…[truncated]"));
}
// ─────────────────────────────────────────────────────────────────────────────
// Export-time validators (fail-closed)
// ─────────────────────────────────────────────────────────────────────────────
#[test]
fn validating_metric_exporter_drops_export_on_bad_attr_key() {
use opentelemetry::metrics::MeterProvider as _;
let stream = build(gates_off());
// Bypass emit.rs: increment with an attribute key outside the pinned set.
let meter = stream
.ext
.meter_provider
.as_ref()
.unwrap()
.meter(schema::SCOPE_NAME);
let rogue = meter.u64_counter("grok_code.session.count").build();
rogue.add(
1,
&[opentelemetry::KeyValue::new("prompt", "CANARY_METRIC_LEAK")],
);
stream
.ext
.meter_provider
.as_ref()
.unwrap()
.force_flush()
.unwrap();
let exported = stream.metrics.get_finished_metrics().unwrap();
let blob = format!("{exported:?}");
assert!(
!blob.contains("CANARY_METRIC_LEAK"),
"metric export with rogue attr must be dropped entirely: {blob}"
);
assert!(
stream
.ext
.health
.metric_exports_dropped
.load(std::sync::atomic::Ordering::Relaxed)
>= 1
);
}
#[test]
fn redacting_log_exporter_drops_record_with_closed_gate_key() {
// A bug that attaches a gated key with the gate off must be caught at the
// exporter even though emit.rs should never produce it.
let stream = build(gates_off());
use opentelemetry::logs::{LogRecord as _, Logger as _};
let logger = stream.ext.logger.as_ref().unwrap();
let mut record = logger.create_log_record();
record.set_event_name("grok_code.user_prompt");
record.add_attribute("prompt", "CANARY_GATED_LEAK");
logger.emit(record);
stream
.ext
.logger_provider
.as_ref()
.unwrap()
.force_flush()
.unwrap();
let blob = format!("{:?}", stream.logs.get_emitted_logs().unwrap());
assert!(
!blob.contains("CANARY_GATED_LEAK"),
"closed-gate key must be dropped by the exporter: {blob}"
);
}
#[test]
fn redacting_log_exporter_drops_record_with_unknown_key() {
let stream = build(gates_off());
use opentelemetry::logs::{LogRecord as _, Logger as _};
let logger = stream.ext.logger.as_ref().unwrap();
let mut record = logger.create_log_record();
record.set_event_name("grok_code.api_request");
record.add_attribute("command", "echo CANARY_UNKNOWN_KEY");
logger.emit(record);
stream
.ext
.logger_provider
.as_ref()
.unwrap()
.force_flush()
.unwrap();
let blob = format!("{:?}", stream.logs.get_emitted_logs().unwrap());
assert!(
!blob.contains("CANARY_UNKNOWN_KEY"),
"unknown key leaked: {blob}"
);
}
// ─────────────────────────────────────────────────────────────────────────────
// Remote policy: tighten-only
// ─────────────────────────────────────────────────────────────────────────────
#[test]
fn remote_force_disable_stops_emission() {
let stream = build(gates_off());
super::apply_remote_policy_on(
&stream.ext,
super::ExternalOtelRemotePolicy {
force_disable: true,
lock_content_gates: false,
},
);
assert!(
!stream.ext.active.load(std::sync::atomic::Ordering::Relaxed),
"force_disable must clear the emission gate"
);
}
#[test]
fn remote_gate_lock_forces_gates_off_and_never_on() {
let stream = build(gates_all_on());
super::apply_remote_policy_on(
&stream.ext,
super::ExternalOtelRemotePolicy {
force_disable: false,
lock_content_gates: true,
},
);
assert_eq!(*stream.ext.gates.read(), ContentGates::default());
// The policy carries no loosen/enable direction by construction: applying
// a default policy to an off-gates stream changes nothing.
let stream2 = build(gates_off());
super::apply_remote_policy_on(&stream2.ext, super::ExternalOtelRemotePolicy::default());
assert_eq!(*stream2.ext.gates.read(), ContentGates::default());
assert!(
stream2
.ext
.active
.load(std::sync::atomic::Ordering::Relaxed)
);
}
// ─────────────────────────────────────────────────────────────────────────────
// Metric increment derivation
// ─────────────────────────────────────────────────────────────────────────────
#[test]
fn metric_increments_pass_model_through_scrub_and_attach_session_id() {
let stream = build(gates_off());
emit_into(
&stream,
ExternalRecord {
event: None,
attrs: vec![(ExternalKey::SessionId, AttrValue::Str("sess-9".into()))],
gated: vec![],
metrics: vec![MetricIncrement::TokenUsage {
token_type: "input",
model: "sk-CANARYabcdefghij1234567890".into(),
count: 7,
}],
},
);
let exported = stream.metrics.get_finished_metrics().unwrap();
let blob = format!("{exported:?}");
assert!(blob.contains("grok_code.token.usage"));
assert!(
blob.contains("sess-9"),
"session.id missing from metric: {blob}"
);
assert!(
!blob.contains("CANARY"),
"model-id metric attribute must pass the secret scrub: {blob}"
);
}