{"record":{"id":"d0ba2ba6004d005e","repo":"astrid-runtime/astrid","slug":"guard-uplink-authenticated-as-anonymous-instead-of","errorCode":null,"errorMessage":"guard uplink authenticated as anonymous instead of requested principal '{principal}'","messagePattern":"guard uplink authenticated as anonymous instead of requested principal '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/mcp/session_guard.rs","lineNumber":65,"sourceCode":"    validate_guard_auth(principal, c.is_authenticated())?;\n\n    debug!(%principal, \"MCP session guard: daemon uplink established\");\n    let mut client = c;\n    loop {\n        match client.read_raw_frame().await {\n            Ok(Some(_)) => {},\n            Ok(None) => anyhow::bail!(\"daemon closed guard uplink\"),\n            Err(e) => return Err(e).context(\"guard uplink read failed\"),\n        }\n    }\n}\n\nfn validate_guard_auth(principal: &astrid_core::PrincipalId, authenticated: bool) -> Result<()> {\n    if authenticated || *principal == astrid_core::PrincipalId::anonymous() {\n        return Ok(());\n    }\n\n    anyhow::bail!(\n        \"guard uplink authenticated as anonymous instead of requested principal '{principal}'\"\n    )\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn guard_auth_accepts_authenticated_principal() {\n        let principal = astrid_core::PrincipalId::new(\"sibyl-code\").unwrap();\n        assert!(validate_guard_auth(&principal, true).is_ok());\n    }\n\n    #[test]\n    fn guard_auth_rejects_anonymous_fallback_for_named_principal() {\n        let principal = astrid_core::PrincipalId::new(\"sibyl-code\").unwrap();\n        let err = validate_guard_auth(&principal, false)","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/mcp/session_guard.rs#L47-L83","documentation":"validate_guard_auth rejects a session guard whose uplink ended up authenticated only as anonymous when the caller requested a specific principal. The guard passes only if the uplink is authenticated, or if the requested principal is deliberately anonymous. This guards against silently falling back to anonymous credentials for a named principal.","triggerScenarios":"hold_guard_uplink (or test guard_auth_rejects_anonymous_fallback_for_named_principal) calls validate_guard_auth with authenticated == false while principal != PrincipalId::anonymous(), i.e. the daemon's auth handshake failed or fell back to anonymous.","commonSituations":"Missing or expired agent credentials so the daemon authenticates the uplink as anonymous; misconfigured auth for the principal; daemon version that no longer supports the auth handshake; caller actually intended anonymous access but passed a named principal.","solutions":["Ensure valid credentials for the requested principal are available before opening the guard uplink.","If anonymous access is intended, pass PrincipalId::anonymous() explicitly instead of a named principal.","Re-run the daemon auth handshake and verify the daemon reports authenticated = true for the uplink.","Check daemon and CLI version compatibility for the authentication protocol."],"exampleFix":"// before\nlet principal = context::resolve_agent(Some(\"agent-7\"))?; // creds missing -> anonymous\nhold_guard_uplink(client, &principal).await?;\n// after\nlet principal = context::resolve_agent(Some(\"agent-7\"))?;\nensure_agent_credentials(&principal).await?; // fail before connect, not after\nhold_guard_uplink(client, &principal).await?;","handlingStrategy":"validation","validationCode":"// fail before opening the uplink if credentials for the named principal are absent\nif *principal != astrid_core::PrincipalId::anonymous() && !has_credentials(principal) {\n    anyhow::bail!(\"no credentials for principal '{principal}'; uplink would fall back to anonymous\");\n}","typeGuard":"fn is_named_principal(p: &astrid_core::PrincipalId) -> bool {\n    *p != astrid_core::PrincipalId::anonymous()\n}","tryCatchPattern":"match hold_guard_uplink(client, principal).await {\n    Err(e) if e.to_string().contains(\"authenticated as anonymous\") => {\n        eprintln!(\"guard auth failed; re-run login/credential setup for {principal}\");\n        return Err(e);\n    },\n    other => other,\n}","preventionTips":["Always complete the daemon auth handshake and check `authenticated` before entering the guard hold loop.","Pass PrincipalId::anonymous() explicitly when anonymous access is intended.","Rotate/renew agent credentials before they expire; expired creds silently downgrade to anonymous.","Add a test like guard_auth_rejects_anonymous_fallback_for_named_principal to CI for any auth flow change."],"tags":["authentication","mcp","ipc","principal","rust"],"backgroundTag":"authentication-required","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}