Skip to content

Commit adf6682

Browse files
committed
fix(proxy): sync with main branch InjectTarget changes
PR #201 was merged to main, replacing config.InjectTarget struct with []string rule specs (rulesengine syntax). Update the integration test file to use the []string format, and sync config/, proxy/proxy.go, and other test files from main to fix the build. Generated by Coder Agents
1 parent ab7e8b4 commit adf6682

7 files changed

Lines changed: 181 additions & 295 deletions

config/config.go

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -141,26 +141,19 @@ func NewAppConfigFromCliConfig(cfg CliConfig, targetCMD []string, environ []stri
141141
}, nil
142142
}
143143

144-
// buildSessionCorrelation merges CLI and YAML inject target sources,
145-
// parses each target string, and validates the resulting configuration.
146-
// environ is passed explicitly (rather than reading os.Environ inside)
147-
// so that callers and tests can supply a controlled environment.
144+
// buildSessionCorrelation merges CLI and YAML inject target sources
145+
// and validates the resulting configuration. Inject targets use the same
146+
// "domain=... path=..." syntax as --allow rules so that matching semantics
147+
// are identical. environ is passed explicitly (rather than reading
148+
// os.Environ inside) so that callers and tests can supply a controlled
149+
// environment.
148150
func buildSessionCorrelation(cfg CliConfig, environ []string) (SessionCorrelationConfig, error) {
149151
// Merge YAML targets with CLI targets.
150-
rawTargets := append(cfg.InjectSessionIDTargets.Value(), cfg.InjectSessionIDTarget.Value()...)
151-
152-
var targets []InjectTarget
153-
for _, raw := range rawTargets {
154-
t, err := ParseInjectTarget(raw)
155-
if err != nil {
156-
return SessionCorrelationConfig{}, err
157-
}
158-
targets = append(targets, t)
159-
}
152+
targets := append(cfg.InjectSessionIDTargets.Value(), cfg.InjectSessionIDTarget.Value()...)
160153

161154
if len(targets) == 0 && cfg.SessionCorrelationEnabled.Value() {
162-
if t := DefaultInjectTargetFromEnv(environ); t != nil {
163-
targets = []InjectTarget{*t}
155+
if t := DefaultInjectTargetFromEnv(environ); t != "" {
156+
targets = []string{t}
164157
}
165158
}
166159

config/session_correlation.go

Lines changed: 41 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"fmt"
55
"net/url"
66
"strings"
7+
8+
"github.com/coder/boundary/rulesengine"
79
)
810

911
// Header names and paths for session correlation.
@@ -27,14 +29,6 @@ const (
2729
CoderAgentURLEnv = "CODER_AGENT_URL"
2830
)
2931

30-
// InjectTarget represents a parsed target for session correlation header
31-
// injection. Requests matching the domain (and optional path glob) will
32-
// receive the session ID and sequence number headers.
33-
type InjectTarget struct {
34-
Domain string
35-
Path string
36-
}
37-
3832
// SessionCorrelationConfig holds configuration for session correlation
3933
// header injection. When enabled, boundary injects its session ID and
4034
// sequence number as custom headers on matching outbound requests so
@@ -45,63 +39,22 @@ type SessionCorrelationConfig struct {
4539
// Deployments without AI Bridge in front should set this to false.
4640
Enabled bool
4741

48-
// InjectTargets is the list of domain/path patterns that should
49-
// receive session correlation headers.
50-
InjectTargets []InjectTarget
51-
}
52-
53-
// ParseInjectTarget parses a string of the form "domain=... path=..."
54-
// into an InjectTarget. The domain key is required; path is optional.
55-
func ParseInjectTarget(raw string) (InjectTarget, error) {
56-
raw = strings.TrimSpace(raw)
57-
if raw == "" {
58-
return InjectTarget{}, fmt.Errorf("inject target must not be empty")
59-
}
60-
61-
var target InjectTarget
62-
seen := make(map[string]bool)
63-
for _, part := range strings.Fields(raw) {
64-
key, value, ok := strings.Cut(part, "=")
65-
if !ok {
66-
return InjectTarget{}, fmt.Errorf(
67-
"inject target: malformed key-value pair %q, expected key=value", part,
68-
)
69-
}
70-
if seen[key] {
71-
return InjectTarget{}, fmt.Errorf(
72-
"inject target: duplicate key %q (use separate flags for multiple targets)", key,
73-
)
74-
}
75-
seen[key] = true
76-
switch key {
77-
case "domain":
78-
if value == "" {
79-
return InjectTarget{}, fmt.Errorf("inject target: domain must not be empty")
80-
}
81-
target.Domain = value
82-
case "path":
83-
target.Path = value
84-
default:
85-
return InjectTarget{}, fmt.Errorf("inject target: unknown key %q", key)
86-
}
87-
}
88-
89-
if target.Domain == "" {
90-
return InjectTarget{}, fmt.Errorf("inject target: domain is required")
91-
}
92-
93-
return target, nil
42+
// InjectTargets is the list of raw rule specs (same syntax as --allow)
43+
// that should receive session correlation headers. Each string uses the
44+
// rulesengine "domain=... path=..." format so that inject target
45+
// matching is identical to allow-rule matching.
46+
InjectTargets []string
9447
}
9548

96-
// DefaultInjectTargetFromEnv derives an InjectTarget from the CODER_AGENT_URL
97-
// variable in the provided environment slice. It returns nil if the variable is
98-
// absent, empty, or not a valid URL with a host. The derived target uses
99-
// DefaultAIBridgePath as the path glob so that all AI Bridge traffic on the
100-
// control-plane host is matched.
49+
// DefaultInjectTargetFromEnv derives an inject target rule string from the
50+
// CODER_AGENT_URL variable in the provided environment slice. It returns ""
51+
// if the variable is absent, empty, or not a valid URL with a host. The
52+
// derived target uses DefaultAIBridgePath as the path glob so that all AI
53+
// Bridge traffic on the control-plane host is matched.
10154
//
10255
// The environ parameter is accepted rather than reading os.Environ directly so
10356
// that callers (and tests) can supply an arbitrary environment.
104-
func DefaultInjectTargetFromEnv(environ []string) *InjectTarget {
57+
func DefaultInjectTargetFromEnv(environ []string) string {
10558
var raw string
10659
for _, e := range environ {
10760
k, v, ok := strings.Cut(e, "=")
@@ -111,23 +64,22 @@ func DefaultInjectTargetFromEnv(environ []string) *InjectTarget {
11164
}
11265
}
11366
if raw == "" {
114-
return nil
67+
return ""
11568
}
11669

11770
u, err := url.Parse(raw)
11871
if err != nil || u.Host == "" {
119-
return nil
72+
return ""
12073
}
12174

122-
return &InjectTarget{
123-
Domain: u.Hostname(),
124-
Path: DefaultAIBridgePath,
125-
}
75+
return fmt.Sprintf("domain=%s path=%s", u.Hostname(), DefaultAIBridgePath)
12676
}
12777

12878
// ValidateSessionCorrelation checks that the session correlation config
129-
// is internally consistent. It returns an error describing the first
130-
// problem found, or nil if the config is valid.
79+
// is internally consistent. When enabled it verifies that at least one
80+
// inject target is configured and that every target string is a valid
81+
// rulesengine rule. It returns an error describing the first problem
82+
// found, or nil if the config is valid.
13183
func ValidateSessionCorrelation(cfg SessionCorrelationConfig) error {
13284
if !cfg.Enabled {
13385
return nil
@@ -139,5 +91,26 @@ func ValidateSessionCorrelation(cfg SessionCorrelationConfig) error {
13991
)
14092
}
14193

94+
// Reject empty target strings before passing to the parser.
95+
for _, t := range cfg.InjectTargets {
96+
if strings.TrimSpace(t) == "" {
97+
return fmt.Errorf("inject target: must not be empty")
98+
}
99+
}
100+
101+
// Validate each target parses as a rulesengine rule.
102+
rules, err := rulesengine.ParseAllowSpecs(cfg.InjectTargets)
103+
if err != nil {
104+
return fmt.Errorf("inject target: %w", err)
105+
}
106+
107+
// Inject targets must specify a domain; path-only rules are not
108+
// meaningful for header injection.
109+
for i, r := range rules {
110+
if r.HostPattern == nil {
111+
return fmt.Errorf("inject target %q: domain is required", cfg.InjectTargets[i])
112+
}
113+
}
114+
142115
return nil
143116
}

0 commit comments

Comments
 (0)