Skip to content

Commit 1d6bdff

Browse files
Copilotpelikhan
andcommitted
Add absolute path validation for mount specifications per MCP spec v1.7.0
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
1 parent fb0840a commit 1d6bdff

2 files changed

Lines changed: 88 additions & 2 deletions

File tree

internal/config/rules/rules.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ func TimeoutPositive(timeout int, fieldName, jsonPath string) *ValidationError {
106106

107107
// MountFormat validates a mount specification in the format "source:dest:mode"
108108
// Returns nil if valid, *ValidationError if invalid
109+
// Per MCP Gateway specification v1.7.0 section 4.1.5:
110+
// - Host path MUST be an absolute path
111+
// - Container path MUST be an absolute path
112+
// - Mode MUST be either "ro" (read-only) or "rw" (read-write)
109113
func MountFormat(mount, jsonPath string, index int) *ValidationError {
110114
parts := strings.Split(mount, ":")
111115
if len(parts) != 3 {
@@ -125,7 +129,17 @@ func MountFormat(mount, jsonPath string, index int) *ValidationError {
125129
Field: "mounts",
126130
Message: fmt.Sprintf("mount source cannot be empty in '%s'", mount),
127131
JSONPath: fmt.Sprintf("%s.mounts[%d]", jsonPath, index),
128-
Suggestion: "Provide a valid source path",
132+
Suggestion: "Provide a valid absolute source path (e.g., '/host/path')",
133+
}
134+
}
135+
136+
// Validate source is an absolute path (MCP spec requirement)
137+
if !strings.HasPrefix(source, "/") {
138+
return &ValidationError{
139+
Field: "mounts",
140+
Message: fmt.Sprintf("mount source must be an absolute path, got '%s'", source),
141+
JSONPath: fmt.Sprintf("%s.mounts[%d]", jsonPath, index),
142+
Suggestion: "Use an absolute path starting with '/' (e.g., '/var/data' instead of 'data')",
129143
}
130144
}
131145

@@ -135,7 +149,17 @@ func MountFormat(mount, jsonPath string, index int) *ValidationError {
135149
Field: "mounts",
136150
Message: fmt.Sprintf("mount destination cannot be empty in '%s'", mount),
137151
JSONPath: fmt.Sprintf("%s.mounts[%d]", jsonPath, index),
138-
Suggestion: "Provide a valid destination path",
152+
Suggestion: "Provide a valid absolute destination path (e.g., '/app/data')",
153+
}
154+
}
155+
156+
// Validate dest is an absolute path (MCP spec requirement)
157+
if !strings.HasPrefix(dest, "/") {
158+
return &ValidationError{
159+
Field: "mounts",
160+
Message: fmt.Sprintf("mount destination must be an absolute path, got '%s'", dest),
161+
JSONPath: fmt.Sprintf("%s.mounts[%d]", jsonPath, index),
162+
Suggestion: "Use an absolute path starting with '/' (e.g., '/app/data' instead of 'app/data')",
139163
}
140164
}
141165

internal/config/rules/rules_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,68 @@ func TestMountFormat(t *testing.T) {
236236
shouldErr: true,
237237
errMsg: "invalid mount mode",
238238
},
239+
{
240+
name: "invalid source - relative path",
241+
mount: "relative/path:/container/path:ro",
242+
jsonPath: "mcpServers.github",
243+
index: 0,
244+
shouldErr: true,
245+
errMsg: "mount source must be an absolute path",
246+
},
247+
{
248+
name: "invalid dest - relative path",
249+
mount: "/host/path:relative/path:ro",
250+
jsonPath: "mcpServers.github",
251+
index: 0,
252+
shouldErr: true,
253+
errMsg: "mount destination must be an absolute path",
254+
},
255+
{
256+
name: "invalid source - dot relative",
257+
mount: "./config:/app/config:ro",
258+
jsonPath: "mcpServers.github",
259+
index: 0,
260+
shouldErr: true,
261+
errMsg: "mount source must be an absolute path",
262+
},
263+
{
264+
name: "invalid dest - dot relative",
265+
mount: "/host/config:./config:ro",
266+
jsonPath: "mcpServers.github",
267+
index: 0,
268+
shouldErr: true,
269+
errMsg: "mount destination must be an absolute path",
270+
},
271+
{
272+
name: "invalid source - parent relative",
273+
mount: "../config:/app/config:ro",
274+
jsonPath: "mcpServers.github",
275+
index: 0,
276+
shouldErr: true,
277+
errMsg: "mount source must be an absolute path",
278+
},
279+
{
280+
name: "invalid dest - parent relative",
281+
mount: "/host/config:../config:ro",
282+
jsonPath: "mcpServers.github",
283+
index: 0,
284+
shouldErr: true,
285+
errMsg: "mount destination must be an absolute path",
286+
},
287+
{
288+
name: "valid mount - root paths",
289+
mount: "/:/root:ro",
290+
jsonPath: "mcpServers.github",
291+
index: 0,
292+
shouldErr: false,
293+
},
294+
{
295+
name: "valid mount - deep nested paths",
296+
mount: "/var/lib/docker/volumes/data:/app/data/volumes:rw",
297+
jsonPath: "mcpServers.github",
298+
index: 0,
299+
shouldErr: false,
300+
},
239301
}
240302

241303
for _, tt := range tests {

0 commit comments

Comments
 (0)