@@ -9,31 +9,33 @@ import (
99 "net/http"
1010 "os"
1111 "os/exec"
12+ "regexp"
1213 "slices"
1314 "strings"
1415 "syscall"
1516 "time"
1617)
1718
1819type resolvedEndpoint struct {
19- method string
20- command string
21- args []string
22- env []string
23- timeout time.Duration
20+ method string
21+ command string
22+ args []string
23+ env []string
24+ timeout time.Duration
25+ pathParams []string
2426}
2527
2628type Endpoint struct {
27- Path string `json:"path,omitempty" toml:"path,commented"`
28- Token string `json:"token,omitempty" toml:"token,commented"`
29- Method string `json:"method,omitempty" toml:"method,commented"`
30- Cmd []string `json:"cmd,omitempty" toml:"cmd,commented"`
31- Env []string `json:"env ,omitempty" toml:"env ,commented"`
32- Detached bool `json:"detached,omitempty" toml:"detached,commented"`
33- UID uint32 `json:"uid,omitempty" toml:"uid,commented"`
34- GID uint32 `json:"gid,omitempty" toml:"gid,commented"`
35- Timeout string `json:"timeout,omitempty" toml:"timeout,commented"`
36- NoAuth bool `json:"no_auth,omitempty" toml:"no_auth,commented"`
29+ Path string `json:"path,omitempty" toml:"path,commented"`
30+ Token string `json:"token,omitempty" toml:"token,commented"`
31+ Method string `json:"method,omitempty" toml:"method,commented"`
32+ Cmd []string `json:"cmd,omitempty" toml:"cmd,commented"`
33+ EnvAllowlist []string `json:"env_allowlist ,omitempty" toml:"env_allowlist ,commented"`
34+ Detached bool `json:"detached,omitempty" toml:"detached,commented"`
35+ UID uint32 `json:"uid,omitempty" toml:"uid,commented"`
36+ GID uint32 `json:"gid,omitempty" toml:"gid,commented"`
37+ Timeout string `json:"timeout,omitempty" toml:"timeout,commented"`
38+ NoAuth bool `json:"no_auth,omitempty" toml:"no_auth,commented"`
3739
3840 resolvedEndpoint
3941}
@@ -72,19 +74,28 @@ func (e *Endpoint) validate() error {
7274 return nil
7375}
7476
77+ var re = regexp .MustCompile (`{([^{}]*)}` )
78+
7579func (e * Endpoint ) resolve () {
7680 e .method = cmp .Or (e .Method , http .MethodPost )
7781 e .command , e .args = e .Cmd [0 ], e .Cmd [1 :]
7882
79- e .env = make ([]string , 0 , len (e .Env ))
80- for _ , key := range e .Env {
81- e .env = append (e .env , key , os .Getenv (key ))
83+ e .env = make ([]string , 0 , len (e .EnvAllowlist ))
84+ for _ , key := range e .EnvAllowlist {
85+ e .env = append (e .env , key + "=" + os .Getenv (key ))
8286 }
8387
8488 if e .Timeout != "" {
8589 t , _ := time .ParseDuration (e .Timeout ) // validated at [Endpoint.validate]
8690 e .timeout = t
8791 }
92+
93+ e .pathParams = make ([]string , 0 , 4 )
94+
95+ matches := re .FindAllStringSubmatch (e .Path , - 1 )
96+ for _ , v := range matches {
97+ e .pathParams = append (e .pathParams , v [1 ])
98+ }
8899}
89100
90101func (e * Endpoint ) redact () Endpoint {
@@ -107,15 +118,15 @@ type ExecResult struct {
107118 Error string `json:"error,omitempty"`
108119}
109120
110- func (e * Endpoint ) run (ctx context.Context ) * ExecResult {
121+ func (e * Endpoint ) run (ctx context.Context , env [] string ) * ExecResult {
111122 if e .Detached {
112- return e .runDetached ()
123+ return e .runDetached (env )
113124 }
114125
115- return e .runWait (ctx )
126+ return e .runWait (ctx , env )
116127}
117128
118- func (e * Endpoint ) runWait (ctx context.Context ) * ExecResult {
129+ func (e * Endpoint ) runWait (ctx context.Context , env [] string ) * ExecResult {
119130 if e .timeout != 0 {
120131 c , cancel := context .WithTimeout (ctx , e .timeout )
121132 ctx = c
@@ -131,7 +142,7 @@ func (e *Endpoint) runWait(ctx context.Context) *ExecResult {
131142 cmd .Stdout = & stdout
132143 cmd .Stderr = & stderr
133144
134- cmd .Env = e .env
145+ cmd .Env = slices . Concat ( e .env , env )
135146
136147 if e .UID != 0 || e .GID != 0 {
137148 cmd .SysProcAttr = & syscall.SysProcAttr {}
@@ -162,9 +173,9 @@ func (e *Endpoint) runWait(ctx context.Context) *ExecResult {
162173 return & execResult
163174}
164175
165- func (e * Endpoint ) runDetached () * ExecResult {
176+ func (e * Endpoint ) runDetached (env [] string ) * ExecResult {
166177 cmd := exec .Command (e .command , e .args ... ) //nolint:gosec,noctx // command and args come from trusted config // noctx is intentional
167- cmd .Env = e .env
178+ cmd .Env = slices . Concat ( e .env , env )
168179
169180 if f , err := os .OpenFile ("/dev/null" , os .O_WRONLY , 0 ); err == nil {
170181 cmd .Stdout , cmd .Stderr , cmd .Stdin = f , f , nil
0 commit comments