-
Notifications
You must be signed in to change notification settings - Fork 39
Feat: one-command local quickstart (--demo) + Cortex README #716
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "os" | ||
| "path/filepath" | ||
| ) | ||
|
|
||
| // demoCADirDefault is the default CA directory for --demo, relative to the | ||
| // current working directory — no absolute path is baked into the binary. | ||
| // Override with --ca-dir. The built-in config is written into this same | ||
| // directory (demo.yaml), next to the generated CA. | ||
| const demoCADirDefault = "cortex-ca" | ||
|
|
||
| // demoConfigYAML returns the built-in --demo config with caDir interpolated: a | ||
| // forward-only proxy with the TLS bridge on (auto-generated CA in caDir) and | ||
| // the LLM / MCP / A2A parsers, so an agent's egress is decrypted and parsed. | ||
| // Kept in sync with the root README. | ||
| // | ||
| // The listeners the demo actually uses are pinned to loopback: this runs on a | ||
| // laptop, so a wildcard bind would expose an open forward proxy and the | ||
| // unauthenticated session API (which carries decrypted bodies and any injected | ||
| // tokens) to the LAN. The preset only fills empty addresses, so these explicit | ||
| // values win. The enforce-redirect transparent listener isn't used here (no | ||
| // iptables) and main.go skips starting it under --demo. | ||
| // | ||
| // The YAML body is flush-left on purpose — a raw string literal preserves | ||
| // leading whitespace, so indenting these lines in source would corrupt the YAML. | ||
| func demoConfigYAML(caDir string) string { | ||
| return `# Built-in config for: authbridge-proxy --demo | ||
| # Forward-only proxy + TLS bridge (auto-generated CA) + LLM/MCP/A2A parsers. | ||
| # The running proxy watches this file — edit it to hot-reload. | ||
| mode: proxy-sidecar | ||
| listener: | ||
| roles: [forward] | ||
| forward_proxy_addr: 127.0.0.1:8081 | ||
| session_api_addr: 127.0.0.1:9094 | ||
| tls_bridge: | ||
| mode: enabled | ||
| ca_dir: "` + caDir + `" | ||
| generate_ca: true | ||
| pipeline: | ||
| outbound: | ||
| plugins: [inference-parser, mcp-parser, a2a-parser] | ||
| ` | ||
| } | ||
|
|
||
| // writeDemoConfig writes the built-in --demo config next to the CA (in caDir) | ||
| // and returns its path, so --demo reuses the normal file-based load + | ||
| // hot-reload path — edits to the file are picked up live. caDir is | ||
| // caller-resolved (cwd-relative by default, or --ca-dir); no absolute path is | ||
| // baked into the binary. Overwrites any prior copy so the preset is canonical. | ||
| func writeDemoConfig(caDir string) (string, error) { | ||
| if err := os.MkdirAll(caDir, 0o755); err != nil { | ||
| return "", err | ||
| } | ||
| path := filepath.Join(caDir, "demo.yaml") | ||
| if err := os.WriteFile(path, []byte(demoConfigYAML(caDir)), 0o644); err != nil { | ||
| return "", err | ||
| } | ||
| return path, nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "path/filepath" | ||
| "slices" | ||
| "testing" | ||
|
|
||
| "github.com/rossoctl/cortex/authbridge/authlib/config" | ||
| ) | ||
|
|
||
| // writeDemoConfig must produce a config file inside caDir that loads, presets, | ||
| // and validates cleanly and describes a forward-only TLS-bridge observe | ||
| // pipeline pointed at that dir — otherwise --demo would fail at boot instead of | ||
| // giving users a working, hot-reloadable local demo. | ||
| func TestDemoConfig_WriteLoadsAndValidates(t *testing.T) { | ||
| caDir := t.TempDir() | ||
|
|
||
| p, err := writeDemoConfig(caDir) | ||
| if err != nil { | ||
| t.Fatalf("writeDemoConfig: %v", err) | ||
| } | ||
| if filepath.Dir(p) != caDir { | ||
| t.Errorf("config written to %q, want inside %q", p, caDir) | ||
| } | ||
|
|
||
| cfg, err := config.Load(p) | ||
| if err != nil { | ||
| t.Fatalf("Load: %v", err) | ||
| } | ||
| config.ApplyPreset(cfg) | ||
| if err := config.Validate(cfg); err != nil { | ||
| t.Fatalf("Validate: %v", err) | ||
| } | ||
|
|
||
| if cfg.Mode != config.ModeProxySidecar { | ||
| t.Errorf("Mode = %q, want %q", cfg.Mode, config.ModeProxySidecar) | ||
| } | ||
|
|
||
| roles := cfg.Listener.ActiveRoles() | ||
| if !roles[config.RoleForward] || roles[config.RoleReverse] { | ||
| t.Errorf("expected forward-only roles, got %v", roles) | ||
| } | ||
|
|
||
| // The listeners the demo uses must bind loopback, never a wildcard that | ||
| // would expose an open forward proxy or the unauthenticated session API | ||
| // (decrypted bodies + injected tokens) to the LAN. The transparent listener | ||
| // isn't started under --demo (main.go gates it), so it's not asserted here. | ||
| if got := cfg.Listener.ForwardProxyAddr; got != "127.0.0.1:8081" { | ||
| t.Errorf("ForwardProxyAddr = %q, want loopback 127.0.0.1:8081", got) | ||
| } | ||
| if got := cfg.Listener.SessionAPIAddr; got != "127.0.0.1:9094" { | ||
| t.Errorf("SessionAPIAddr = %q, want loopback 127.0.0.1:9094", got) | ||
| } | ||
|
|
||
| if cfg.TLSBridge == nil { | ||
| t.Fatalf("expected tls_bridge config, got nil") | ||
| } | ||
| if cfg.TLSBridge.Mode != "enabled" || !cfg.TLSBridge.GenerateCA { | ||
| t.Errorf("expected tls_bridge enabled with generate_ca, got %+v", cfg.TLSBridge) | ||
| } | ||
| if cfg.TLSBridge.CADir != caDir { | ||
| t.Errorf("CADir = %q, want %q", cfg.TLSBridge.CADir, caDir) | ||
| } | ||
|
|
||
| // Assert the exact parser set and order, not just the count — a swapped or | ||
| // renamed plugin would otherwise pass silently. | ||
| gotPlugins := make([]string, len(cfg.Pipeline.Outbound.Plugins)) | ||
| for i, p := range cfg.Pipeline.Outbound.Plugins { | ||
| gotPlugins[i] = p.Name | ||
| } | ||
| wantPlugins := []string{"inference-parser", "mcp-parser", "a2a-parser"} | ||
| if !slices.Equal(gotPlugins, wantPlugins) { | ||
| t.Errorf("outbound plugins = %v, want %v", gotPlugins, wantPlugins) | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Escape
caDirbefore embedding it in YAML.Direct interpolation makes paths such as Windows
C:\..., or filenames containing quotes/newlines, produce invalid or altered YAML beforeconfig.Loadcan start the proxy.Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents