Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
d625e58
chore(deps): bump agent-client-protocol from 0.11.1 to 0.12.1 (#9381)
dependabot[bot] May 23, 2026
8689fdf
chore(deps): bump image from 0.24.9 to 0.25.10 (#9383)
dependabot[bot] May 23, 2026
ce004f7
fix(agents): serialize per-session agent creation to stop duplicate M…
fresh3nough May 23, 2026
c4d64d1
Fix desktop chat search session limiting (#9366)
angiejones May 24, 2026
e1cc44f
Build summon instructions per turn (#9329)
DOsinga May 25, 2026
ba16de9
docs: stats update (#9410)
angiejones May 25, 2026
a11843a
Simplify UI customization (#9353)
DOsinga May 26, 2026
6d544e7
chore(deps): bump qs from 6.14.2 to 6.15.2 in /evals/open-model-gym/m…
dependabot[bot] May 26, 2026
bf0da95
Add Turkish desktop locale (#9392)
seneroner77-cmd May 26, 2026
27dc0d5
Improve dependency hygiene (#9360)
jh-block May 26, 2026
dcdc7f6
fix(desktop): stop the main window growing taller on every launch (#9…
officialasishkumar May 26, 2026
b332f50
Russian language support (#9406)
besdar May 26, 2026
b0cd61a
chore(release): bump version to 1.36.0 (minor) (#9417)
github-actions[bot] May 26, 2026
7dc904e
add databricks ai gateway provider (#9274)
baxen May 26, 2026
1749354
Prefer goose aliases for Databricks v2 inventory (#9430)
baxen May 27, 2026
794402d
fix(ci): build linux x86_64 standard inside manylinux_2_28 for glibc …
88plug May 27, 2026
d90b349
feat: add /model slash command to CLI for session model switching (#8…
baxen May 27, 2026
27b41d9
local inference: stricter GGUF requirements, auto detection of tool c…
jh-block May 27, 2026
d017295
fix: tolerate missing responses output (#9449)
angiejones May 27, 2026
4f43ae4
fix(ui): preserve pending env vars in Add Extension form (#9285)
williams145 May 27, 2026
10ac6b1
feat: make tool output size limit configurable via GOOSE_MAX_TOOL_RES…
DOsinga May 27, 2026
1125e8d
fix: make azure api-version query param optional (#9221)
DOsinga May 27, 2026
35d1fc7
fix(desktop): start new chat in current window from recipe param moda…
michaelneale May 27, 2026
a18b92e
fix(desktop): refresh provider list in Switch Models picker (#9408)
officialasishkumar May 27, 2026
4c88f4b
feat(providers): add Alibaba (Qwen via DashScope) declarative provide…
jezweb May 27, 2026
e9b0d92
feat(providers): add Perplexity as a declarative OpenAI-compatible pr…
jliounis May 27, 2026
c9945bc
chore(deps): bump sha2 from 0.10.9 to 0.11.0 (#8963)
dependabot[bot] May 27, 2026
9c403b1
refactor: convert desktop v1 and goose-server extensions to ACP+ (#9448)
alexhancock May 27, 2026
27d68ba
doc: Add Scaleway provider (#9423)
Quentinchampenois May 28, 2026
d10d009
CLI to list skills with token counts (#9326)
jamadeo May 28, 2026
2116f88
feat: add `tui` feature flag to gate the tui command (#9428)
r0x0d May 28, 2026
1cb5cb0
Add Scholar Sidekick MCP extension (#9433)
mlava May 28, 2026
104cc17
Add ACP session system prompt setter (#9478)
baxen May 29, 2026
a3bdb91
fix(acp): forward ACP server context window size to clients (#9455)
matt2e May 29, 2026
25ff547
Expose raw provider supported models over ACP (#9475)
baxen May 29, 2026
13f7be2
feat: replay acp images on session load (#9496)
kalvinnchau May 29, 2026
8af2f76
feat(providers): add xAI SuperGrok OAuth subscription provider (#9420)
michaelneale Jun 1, 2026
5508079
chore: update canonical model registry (#9551)
baxen Jun 1, 2026
5e160e5
Honor blocking Stop hook decisions (#9468)
johnmatthewtennant Jun 1, 2026
f69a178
fix(otel): skip OTLP signals when protocol=grpc to avoid background-t…
joahg Jun 1, 2026
cd8f718
Fix scheduled recipe session params (#9553)
angiejones Jun 1, 2026
586bb15
fix(extension-manager): forward custom headers through OAuth connect …
hydrosquall Jun 2, 2026
942a456
Revert "refactor: convert desktop v1 and goose-server extensions to A…
alexhancock Jun 2, 2026
fdc1994
chore(release): bump version to 1.37.0 (minor) (#9557)
github-actions[bot] Jun 2, 2026
7982086
Pick the last canonical model (#9568)
DOsinga Jun 2, 2026
030dbb0
feat(security): Add directionality to egress logging (#9546)
dorien-koelemeijer Jun 2, 2026
502ee50
chore(release): release version 1.37.0 (#9565)
github-actions[bot] Jun 2, 2026
cd12199
Bench marking (#9465)
DOsinga Jun 2, 2026
003252f
Import sesssions (#9474)
DOsinga Jun 2, 2026
9626b4c
Replace review subprocess timeout with turn limits (#9571)
lucasconti-dev Jun 2, 2026
30034b9
Add Hugging Face OAuth support, add auth tab to settings (#9552)
jh-block Jun 3, 2026
f6caaa0
Fixed intermittent missing extension override on ui and cleanup (#9575)
lifeizhou-ap Jun 3, 2026
08e7480
Use LRU cache for token counting (#9586)
jh-block Jun 3, 2026
83a4abf
fix: quote release PR search phrase in pre-release.sh (#9573)
alexhancock Jun 3, 2026
0e4a367
chore(deps): bump the cargo-minor-and-patch group across 1 directory …
dependabot[bot] Jun 3, 2026
302dafc
chore(deps): bump mockall from 0.13.1 to 0.14.0 (#9511)
dependabot[bot] Jun 3, 2026
1ab48f5
chore(deps): bump pkcs8 from 0.10.2 to 0.11.0 (#9510)
dependabot[bot] Jun 3, 2026
dc3a63a
chore(deps): bump strum from 0.27.2 to 0.28.0 (#9509)
dependabot[bot] Jun 3, 2026
1205a4a
chore(deps): bump clap_mangen from 0.2.33 to 0.3.0 (#9508)
dependabot[bot] Jun 3, 2026
1a52f21
chore(deps): bump tokenizers from 0.21.4 to 0.22.2 (#9503)
dependabot[bot] Jun 3, 2026
34f33fc
chore(deps): bump EmbarkStudios/cargo-deny-action from 2.0.19 to 2.0.…
dependabot[bot] Jun 3, 2026
9646f70
chore(deps): bump ossf/scorecard-action from 2.4.1 to 2.4.3 (#9501)
dependabot[bot] Jun 3, 2026
1cc5aa6
chore(deps): bump pnpm/action-setup from 6.0.5 to 6.0.8 (#9500)
dependabot[bot] Jun 3, 2026
dc59e41
Lifei/acp session setup refactor (#9488)
lifeizhou-ap Jun 4, 2026
6251e56
feat(sdk): minimal uniffi setup for cross language sdk (#9593)
alexhancock Jun 4, 2026
ec519ee
feat: Only send custom notifications when ACP client specifies this c…
lifeizhou-ap Jun 4, 2026
65b72b2
refactor: remove dead component and useNavigationSessions cleanup (#9…
lifeizhou-ap Jun 5, 2026
2f99664
feat: acp methods for config extensions (#9581)
lifeizhou-ap Jun 5, 2026
826f13f
create goose-providers crate with canonical models, conversation and …
jamadeo Jun 5, 2026
4904e3c
Image read tool (#9607)
DOsinga Jun 5, 2026
e5fd568
move formats/openai.rs into goose-providers crate, along with several…
jamadeo Jun 8, 2026
8eb6cd6
fix: compatibility of config extension acp call in TUI (#9683)
lifeizhou-ap Jun 9, 2026
0ab4b84
chore: pause tui release (#9685)
lifeizhou-ap Jun 9, 2026
e309083
fix: goose-sdk release compat check with new schema (#9697)
lifeizhou-ap Jun 9, 2026
f4ecdae
feat: use acp list sessions and manage sessions in Desktop (#9687)
lifeizhou-ap Jun 9, 2026
d396767
chore: refresh canonical model registry (#9709)
baxen Jun 9, 2026
f52d717
feat(security): enable prompt injection mitigation by default for int…
dorien-koelemeijer Jun 10, 2026
390dfb8
feat(security): Re-adjust pattern-based detection for prompt injectio…
dorien-koelemeijer Jun 10, 2026
10e665a
expose ACP thinking effort config option (#9711)
morgmart Jun 10, 2026
d2ab786
feat: acp list session with keyword and type filter (#9695)
lifeizhou-ap Jun 10, 2026
9455f8a
docs: fix typo in MCP blog post (#9641)
Nukually Jun 10, 2026
fde407c
Update analyze extension instructions (#9585)
DOsinga Jun 10, 2026
40315b5
feat: steering messages with ACP (#9560)
michaelneale Jun 10, 2026
be91189
feat: use acp search session in Desktop (#9717)
lifeizhou-ap Jun 10, 2026
58185fe
pin goose-sdk package in tui (#9712)
lifeizhou-ap Jun 10, 2026
32722e6
feat: surface Anthropic stream refusals as visible errors (#9724)
kalvinnchau Jun 10, 2026
e8d5622
feat(acp): support GOOSE_SERVER__SECRET_KEY at goose serve acp endpoi…
kalvinnchau Jun 10, 2026
523aaee
feat: custom acp method to get session info (#9729)
lifeizhou-ap Jun 11, 2026
4207b7e
docs: fix stale session navigation/delete docs (Session History) (#9727)
michaelneale Jun 11, 2026
db1f0fc
feat(lang): add Hindi Desktop locale (#9733)
Abhijay007 Jun 11, 2026
c6a3b5b
fix: preserve unparseable extension entries during config refresh (#9…
mvanhorn Jun 11, 2026
86e2f04
Add canonical thinking modes (#9743)
jh-block Jun 11, 2026
f23347f
fix: page through all Databricks AI Gateway v2 endpoints when listing…
kalvinnchau Jun 11, 2026
8b5a7b8
feat(security): unified OTLP logging schema for cross-tool detection …
dorien-koelemeijer Jun 12, 2026
ec03984
Merge remote-tracking branch 'upstream/main' into chore/sync-upstream…
earayu Jun 13, 2026
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/goose/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ icu_locale = { version = "=2.1.1", default-features = false }
llama-cpp-sys-2 = { workspace = true, optional = true }
image = { version = "0.24.9", default-features = false, features = ["png", "jpeg", "gif", "webp"] }
subtle = { version = "2.5", default-features = false, features = ["std"] }
gethostname = "1.1.0"

[target.'cfg(target_os = "windows")'.dependencies]
winapi = { workspace = true }
Expand Down
10 changes: 9 additions & 1 deletion crates/goose/src/agents/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1719,7 +1719,15 @@ impl Agent {
.count();

let working_dir = session.working_dir.clone();
let reply_stream_span = tracing::info_span!(target: "goose::agents::agent", "reply_stream", trace_output = tracing::field::Empty, session.id = %session_config.id);
let reply_stream_span = tracing::info_span!(
target: "goose::agents::agent",
"reply_stream",
trace_output = tracing::field::Empty,
session.id = %session_config.id,
session.user = %crate::session_context::session_user(),
session.host = %crate::session_context::session_host(),
session.agent_type = "goose",
);
let inner = Box::pin(async_stream::try_stream! {
let mut turns_taken = 0u32;
let max_turns = session_config.max_turns.unwrap_or_else(|| {
Expand Down
14 changes: 10 additions & 4 deletions crates/goose/src/agents/tool_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,18 @@ impl Agent {
.map_err(|_| anyhow::anyhow!("Confirmation channel closed for request {}", request.id))?;

if let Some(finding_id) = get_security_finding_id_from_results(&request.id, inspection_results) {
let action = match confirmation.permission {
Permission::AllowOnce | Permission::AlwaysAllow => "ALLOW",
_ => "BLOCK",
};
tracing::info!(
monotonic_counter.goose.prompt_injection_user_decisions = 1,
decision = ?confirmation.permission,
finding_id = %finding_id,
tool_request_id = %request.id,
"Prompt injection detection: user decision on command injection finding"
security.event_type = "user_decision",
security.action = action,
security.finding_id = %finding_id,
tool.request_id = %request.id,
user.decision = ?confirmation.permission,
"security finding: user decision"
);
}

Expand Down
123 changes: 83 additions & 40 deletions crates/goose/src/otel/otlp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,15 @@ pub fn promote_config_to_env(config: &crate::config::Config) {
}

fn create_resource() -> Resource {
use crate::session_context::{session_host, session_user};

let mut builder = Resource::builder_empty()
.with_attributes([
KeyValue::new("service.name", "goose"),
KeyValue::new("service.version", env!("CARGO_PKG_VERSION")),
KeyValue::new("service.namespace", "goose"),
KeyValue::new("host.name", session_host()),
KeyValue::new("user.name", session_user()),
])
.with_detector(Box::new(EnvResourceDetector::new()))
.with_detector(Box::new(TelemetryResourceDetector));
Expand Down Expand Up @@ -304,7 +308,12 @@ fn create_otlp_logs_layer() -> OtlpResult<OtlpLogsLayer> {
};

let bridge = OpenTelemetryTracingBridge::builder(&logger_provider)
.with_tracing_span_attributes(TracingSpanAttributes::allowlist(["session.id"]))
.with_tracing_span_attributes(TracingSpanAttributes::allowlist([
"session.id",
"session.user",
"session.host",
"session.agent_type",
]))
.build();
*LOGGER_PROVIDER.lock().unwrap_or_else(|e| e.into_inner()) = Some(logger_provider);

Expand Down Expand Up @@ -598,45 +607,79 @@ mod tests {
shutdown_otlp();
}

#[test_case(
&[],
Resource::builder_empty()
.with_attributes([KeyValue::new("service.name", "goose"), KeyValue::new("service.version", env!("CARGO_PKG_VERSION")), KeyValue::new("service.namespace", "goose")])
.with_detector(Box::new(TelemetryResourceDetector))
.build();
"no env vars uses goose defaults"
)]
#[test_case(
&[("OTEL_SERVICE_NAME", "custom")],
Resource::builder_empty()
.with_attributes([KeyValue::new("service.name", "goose"), KeyValue::new("service.version", env!("CARGO_PKG_VERSION")), KeyValue::new("service.namespace", "goose")])
.with_detector(Box::new(TelemetryResourceDetector))
.with_service_name("custom")
.build();
"OTEL_SERVICE_NAME overrides service.name"
)]
#[test_case(
&[("OTEL_RESOURCE_ATTRIBUTES", "deployment.environment=prod")],
Resource::builder_empty()
.with_attributes([KeyValue::new("service.name", "goose"), KeyValue::new("service.version", env!("CARGO_PKG_VERSION")), KeyValue::new("service.namespace", "goose")])
.with_detector(Box::new(TelemetryResourceDetector))
.with_attribute(KeyValue::new("deployment.environment", "prod"))
.build();
"OTEL_RESOURCE_ATTRIBUTES adds custom attributes"
)]
#[test_case(
&[("OTEL_SERVICE_NAME", "custom"), ("OTEL_RESOURCE_ATTRIBUTES", "deployment.environment=prod")],
Resource::builder_empty()
.with_attributes([KeyValue::new("service.name", "goose"), KeyValue::new("service.version", env!("CARGO_PKG_VERSION")), KeyValue::new("service.namespace", "goose")])
.with_detector(Box::new(TelemetryResourceDetector))
.with_service_name("custom")
.with_attribute(KeyValue::new("deployment.environment", "prod"))
.build();
"OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES combine"
)]
fn test_create_resource(env: &[(&'static str, &'static str)], expected: Resource) {
let _guard = clear_otel_env(env);
assert_eq!(create_resource(), expected);
#[test]
fn test_create_resource_defaults() {
let _guard = clear_otel_env(&[]);
let resource = create_resource();
let attrs: Vec<_> = resource.iter().collect();
let get = |key: &str| {
attrs
.iter()
.find(|(k, _)| k.as_str() == key)
.map(|(_, v)| v.to_string())
};

assert_eq!(get("service.name").as_deref(), Some("goose"));
assert_eq!(
get("service.version").as_deref(),
Some(env!("CARGO_PKG_VERSION"))
);
assert_eq!(get("service.namespace").as_deref(), Some("goose"));
assert!(get("host.name").is_some(), "host.name should be set");
assert!(get("user.name").is_some(), "user.name should be set");
}

#[test]
fn test_create_resource_otel_service_name_overrides() {
let _guard = clear_otel_env(&[("OTEL_SERVICE_NAME", "custom")]);
let resource = create_resource();
let attrs: Vec<_> = resource.iter().collect();
let get = |key: &str| {
attrs
.iter()
.find(|(k, _)| k.as_str() == key)
.map(|(_, v)| v.to_string())
};

assert_eq!(get("service.name").as_deref(), Some("custom"));
assert_eq!(get("service.namespace").as_deref(), Some("goose"));
}

#[test]
fn test_create_resource_otel_resource_attributes() {
let _guard = clear_otel_env(&[("OTEL_RESOURCE_ATTRIBUTES", "deployment.environment=prod")]);
let resource = create_resource();
let attrs: Vec<_> = resource.iter().collect();
let get = |key: &str| {
attrs
.iter()
.find(|(k, _)| k.as_str() == key)
.map(|(_, v)| v.to_string())
};

assert_eq!(get("service.name").as_deref(), Some("goose"));
assert_eq!(get("deployment.environment").as_deref(), Some("prod"));
}

#[test]
fn test_create_resource_combined() {
let _guard = clear_otel_env(&[
("OTEL_SERVICE_NAME", "custom"),
("OTEL_RESOURCE_ATTRIBUTES", "deployment.environment=prod"),
]);
let resource = create_resource();
let attrs: Vec<_> = resource.iter().collect();
let get = |key: &str| {
attrs
.iter()
.find(|(k, _)| k.as_str() == key)
.map(|(_, v)| v.to_string())
};

assert_eq!(get("service.name").as_deref(), Some("custom"));
assert_eq!(get("deployment.environment").as_deref(), Some("prod"));
assert!(get("host.name").is_some());
assert!(get("user.name").is_some());
}

#[test_case(&[("RUST_LOG", "")], Level::INFO; "default is info")]
Expand Down
34 changes: 25 additions & 9 deletions crates/goose/src/security/adversary_inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ impl ToolInspector for AdversaryInspector {
}

let tool_description = Self::format_tool_call(request);
let tool_call_name = match &request.tool_call {
Ok(tc) => tc.name.to_string(),
Err(_) => "unknown".to_string(),
};

tracing::debug!(
tool_request_id = %request.id,
Expand All @@ -397,9 +401,13 @@ impl ToolInspector for AdversaryInspector {
{
Ok((true, reason)) => {
tracing::debug!(
tool_request_id = %request.id,
reason = %reason,
"Adversary: ALLOW"
security.event_type = "adversary_detection",
security.action = "ALLOW",
security.confidence = 1.0_f32,
security.explanation = %reason,
tool.name = %tool_call_name,
tool.request_id = %request.id,
"adversary review: ALLOW"
);
results.push(InspectionResult {
tool_request_id: request.id.clone(),
Expand All @@ -412,9 +420,13 @@ impl ToolInspector for AdversaryInspector {
}
Ok((false, reason)) => {
tracing::warn!(
tool_request_id = %request.id,
reason = %reason,
"Adversary: BLOCK"
security.event_type = "adversary_detection",
security.action = "BLOCK",
security.confidence = 1.0_f32,
security.explanation = %reason,
tool.name = %tool_call_name,
tool.request_id = %request.id,
"adversary review: BLOCK"
);
results.push(InspectionResult {
tool_request_id: request.id.clone(),
Expand All @@ -427,9 +439,13 @@ impl ToolInspector for AdversaryInspector {
}
Err(e) => {
tracing::warn!(
tool_request_id = %request.id,
error = %e,
"Adversary inspector failed, allowing tool call (fail-open)"
security.event_type = "adversary_detection",
security.action = "ALLOW",
security.confidence = 0.0_f32,
security.explanation = %format!("error (fail-open): {}", e),
tool.name = %tool_call_name,
tool.request_id = %request.id,
"adversary review: error (fail-open)"
);
results.push(InspectionResult {
tool_request_id: request.id.clone(),
Expand Down
15 changes: 9 additions & 6 deletions crates/goose/src/security/egress_inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,12 +354,15 @@ impl ToolInspector for EgressInspector {

for dest in &destinations {
tracing::info!(
egress_kind = dest.kind.as_str(),
domain = dest.domain.as_str(),
destination = dest.destination.as_str(),
direction = direction.as_str(),
tool_name = name,
"egress destination detected"
security.event_type = "egress",
security.action = "LOG",
security.threat_type = "data_exfiltration",
network.destination = dest.destination.as_str(),
network.domain = dest.domain.as_str(),
network.egress_kind = dest.kind.as_str(),
network.direction = direction.as_str(),
tool.name = name,
"network egress detected"
);
}

Expand Down
42 changes: 25 additions & 17 deletions crates/goose/src/security/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,22 +162,26 @@ impl SecurityManager {
let tool_call_json =
serde_json::to_string(&tool_call).unwrap_or_else(|_| "{}".to_string());

let action = if above_threshold { "BLOCK" } else { "LOG" };

tracing::warn!(
monotonic_counter.goose.prompt_injection_finding = 1,
threat_type = "command_injection",
above_threshold = above_threshold,
tool_name = %tool_call.name,
tool_request_id = %tool_request.id,
tool_call_json = %tool_call_json,
confidence = analysis_result.confidence,
explanation = %sanitized_explanation,
finding_id = %finding_id,
threshold = config_threshold,
security.event_type = "prompt_injection_scan",
security.action = action,
security.confidence = analysis_result.confidence,
security.threshold = config_threshold,
security.above_threshold = above_threshold,
security.threat_type = "command_injection",
security.finding_id = %finding_id,
security.explanation = %sanitized_explanation,
tool.name = %tool_call.name,
tool.request_id = %tool_request.id,
tool.call_json = %tool_call_json,
"{}",
if above_threshold {
"Prompt injection detection: Current tool call flagged as malicious after security analysis (above threshold)"
"prompt injection scan: finding above threshold"
} else {
"Prompt injection detection: Security finding below threshold (logged but not blocking execution)"
"prompt injection scan: finding below threshold"
}
);
if above_threshold {
Expand All @@ -196,12 +200,16 @@ impl SecurityManager {

tracing::info!(
monotonic_counter.goose.prompt_injection_tool_call_passed = 1,
tool_name = %tool_call.name,
tool_request_id = %tool_request.id,
tool_call_json = %tool_call_json,
confidence = analysis_result.confidence,
explanation = %sanitized_explanation,
"Current tool call passed security analysis"
security.event_type = "prompt_injection_scan",
security.action = "ALLOW",
security.confidence = analysis_result.confidence,
security.threshold = config_threshold,
security.above_threshold = false,
security.threat_type = "command_injection",
tool.name = %tool_call.name,
tool.request_id = %tool_request.id,
tool.call_json = %tool_call_json,
"prompt injection scan: tool call passed"
);
}
}
Expand Down
19 changes: 10 additions & 9 deletions crates/goose/src/security/scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,16 @@ impl PromptInjectionScanner {
self.combine_confidences(tool_result.confidence, context_result.ml_confidence);

tracing::info!(
tool_confidence = %tool_result.confidence,
context_confidence = ?context_result.ml_confidence,
final_confidence = %final_confidence,
used_command_ml = tool_result.ml_confidence.is_some(),
used_prompt_ml = context_result.ml_confidence.is_some(),
used_pattern_detection = tool_result.used_pattern_detection,
threshold = %threshold,
malicious = final_confidence >= threshold,
"Security analysis complete"
security.event_type = "prompt_injection_scan",
security.confidence = final_confidence,
security.threshold = threshold,
security.above_threshold = final_confidence >= threshold,
scanner.tool_confidence = tool_result.confidence,
scanner.context_confidence = ?context_result.ml_confidence,
scanner.used_command_ml = tool_result.ml_confidence.is_some(),
scanner.used_prompt_ml = context_result.ml_confidence.is_some(),
scanner.used_pattern_detection = tool_result.used_pattern_detection,
"prompt injection scan: analysis complete"
);

let final_result = DetailedScanResult {
Expand Down
14 changes: 14 additions & 0 deletions crates/goose/src/session_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ pub fn current_session_id() -> Option<String> {
SESSION_ID.try_with(|id| id.clone()).ok().flatten()
}

/// Local OS user running goose, shared by the OTLP `user.name` resource
/// attribute and the `session.user` span attribute so the two never drift.
pub fn session_user() -> String {
std::env::var("USER")
.or_else(|_| std::env::var("LOGNAME"))
.unwrap_or_else(|_| "unknown".to_string())
}

/// Hostname of the machine running goose, shared by the OTLP `host.name`
/// resource attribute and the `session.host` span attribute.
pub fn session_host() -> String {
gethostname::gethostname().to_string_lossy().to_string()
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading
Loading