okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
96704f7
main
1// MCP form command quoting, environment parsing, and credential retention semantics. 2// Wire-format command tokenization and sentinel deletion operate inside unexported form 3// submission models before reaching any daemon RPC, unreachable by daemon E2E. 4package tui 5 6import ( 7"strings" 8"testing" 9 10"albedo/cli/internal/config" 11"albedo/cli/internal/daemon" 12 13 tea"charm.land/bubbletea/v2" 14"github.com/charmbracelet/x/ansi" 15) 16 17func typeMCP (m CapabilityPageModel ,text string )CapabilityPageModel { 18m ,_ = m .Update (tea.KeyPressMsg {Code :tea .KeyExtended ,Text :text }) 19return m 20} 21 22func key (m CapabilityPageModel ,k rune )CapabilityPageModel { 23m ,_ = m .Update (tea.KeyPressMsg {Code :k }) 24return m 25} 26 27func ctrl (m CapabilityPageModel ,k rune )CapabilityPageModel { 28m ,_ = m .Update (tea.KeyPressMsg {Code :k ,Mod :tea .ModCtrl }) 29return m 30} 31 32func mcpPage (t * testing.T )CapabilityPageModel { 33t .Helper () 34m := NewCapabilityPageModel (nil ,"s" ,"mcp" ) 35m .SetSize (100 ,30 ) 36m .Loading = false 37m .ExtensionEnabled = true 38return m 39} 40 41func TestAddingAnHTTPServerAsksForAuthBeforeSaving (t * testing.T ) { 42m := mcpPage (t ) 43m = ctrl (m ,'o' ) 44if m .Form == nil || m .Form .current ()!= fieldURL { 45t .Fatal ("ctrl+o should open the add form on the URL" ) 46 } 47m = typeMCP (m ,"http://100.64.0.19:8787/mcp" ) 48if got := m .Form .Inputs [fieldName ].Value ();got != "mcp-100-64-0-19" { 49t .Fatalf ("name should follow the URL, got %q" ,got ) 50 } 51m = key (m ,tea .KeyEnter )// name 52m = key (m ,tea .KeyEnter )// bearer token 53if m .Form .current ()!= fieldToken || m .Saving { 54t .Fatalf ("enter should walk to the bearer token without saving, at %q" ,m .Form .current ()) 55 } 56m = typeMCP (m ,"sensitive-token" ) 57if strings .Contains (ansi .Strip (m .View ()),"sensitive-token" )|| ! strings .Contains (ansi .Strip (m .View ()),"bearer token" ) { 58t .Fatalf ("the token field must be labelled and masked:\n%s" ,ansi .Strip (m .View ())) 59 } 60sub ,err := m .Form .submission (nil ) 61if err != nil { 62t .Fatal (err ) 63 } 64if sub .Name != "mcp-100-64-0-19" || sub .Server .Type != "http" || sub .Server .URL != "http://100.64.0.19:8787/mcp" || (sub .Secrets .BearerToken == nil || * sub .Secrets .BearerToken != "sensitive-token" ) { 65t .Fatalf ("unexpected submission %+v" ,sub ) 66 } 67} 68 69func TestStdioServerParsesItsCommandAndSuggestsAName (t * testing.T ) { 70m := mcpPage (t ) 71m = ctrl (m ,'o' ) 72m = key (m ,tea .KeyUp ) 73m = key (m ,tea .KeyRight ) 74if m .Form .Transport != "stdio" { 75t .Fatal ("← → should switch the transport" ) 76 } 77m = key (m ,tea .KeyDown ) 78m = typeMCP (m ,`npx -y @modelcontextprotocol/server-filesystem "/tmp/my dir"` ) 79m = key (m ,tea .KeyDown ) 80m = key (m ,tea .KeyDown ) 81m = typeMCP (m ,"TOKEN=abc DEBUG=1" ) 82sub ,err := m .Form .submission (nil ) 83if err != nil { 84t .Fatal (err ) 85 } 86if sub .Name != "filesystem" || sub .Server .Command != "npx" || strings .Join (sub .Server .Args ,"|" )!= "-y|@modelcontextprotocol/server-filesystem|/tmp/my dir" { 87t .Fatalf ("unexpected stdio submission %+v" ,sub ) 88 } 89env := sub .Secrets .Env 90if env ["TOKEN" ]== nil || * env ["TOKEN" ]!= "abc" || env ["DEBUG" ]== nil || * env ["DEBUG" ]!= "1" || ! sub .Secrets .RemoveBearerToken { 91t .Fatalf ("env should be stored privately, got %+v" ,sub .Secrets ) 92 } 93if strings .Contains (ansi .Strip (m .View ()),"abc" ) { 94t .Fatal ("env values must be masked" ) 95 } 96} 97 98func TestEditingKeepsOrRemovesStoredSecrets (t * testing.T ) { 99stored := daemon.MCPSecretNames {BearerToken :true ,Headers : []string {"X-Key" }} 100enabled := false 101f := newMCPForm ("docs" , config.MCPServer {Type :"http" ,URL :"https://docs.example/mcp" ,Enabled :& enabled },stored ) 102sub ,err := f .submission ([]capabilityItem {{ID :"docs" }}) 103if err != nil || sub .Secrets .BearerToken != nil || sub .Secrets .RemoveBearerToken || sub .Secrets .Headers != nil || sub .Secrets .ClearHeaders || sub .Server .Enabled == nil { 104t .Fatalf ("a blank edit must keep stored secrets and other fields: %+v %v" ,sub ,err ) 105 } 106 107f .Inputs [fieldToken ].SetValue ("-" ) 108f .Inputs [fieldHeader ].SetValue ("X-Key" ) 109f .Inputs [fieldValue ].SetValue ("-" ) 110sub ,_ = f .submission (nil ) 111removed := sub .Secrets .Headers 112header ,named := removed ["X-Key" ] 113if ! sub .Secrets .RemoveBearerToken || ! named || header != nil { 114t .Fatalf ("- should remove stored secrets: %+v" ,sub .Secrets ) 115 } 116}