From f189598c357ee16d0aaf72d706ab1413ce2c61fb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:46:23 +0000 Subject: [PATCH 1/3] Initial plan From 7196ef4f237148f0579abff64e5de3f8d44e094d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 00:49:59 +0000 Subject: [PATCH 2/3] Allow SHA-256 digests in container image references Update containerPattern regex and JSON schema to accept optional @sha256:<64-hex-chars> suffix on container image references. This enables digest-pinned references like: - image:tag@sha256:abc123... - image@sha256:abc123... Add test cases for valid and invalid digest patterns. Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/a36ac9ee-c2c2-4156-83d6-c836034383c3 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- .../schema/mcp-gateway-config.schema.json | 2 +- internal/config/validation_schema.go | 2 +- internal/config/validation_schema_test.go | 24 +++++++++++++++++ .../config/validation_string_patterns_test.go | 27 +++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/internal/config/schema/mcp-gateway-config.schema.json b/internal/config/schema/mcp-gateway-config.schema.json index 754024c1..7e5ad7d3 100644 --- a/internal/config/schema/mcp-gateway-config.schema.json +++ b/internal/config/schema/mcp-gateway-config.schema.json @@ -76,7 +76,7 @@ "type": "string", "description": "Container image for the MCP server (e.g., 'ghcr.io/example/mcp-server:latest'). This field is required for stdio servers per MCP Gateway Specification section 4.1.2.", "minLength": 1, - "pattern": "^[a-zA-Z0-9][a-zA-Z0-9./_-]*(:([a-zA-Z0-9._-]+|latest))?$" + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9./_-]*(:([a-zA-Z0-9._-]+|latest))?(@sha256:[a-fA-F0-9]{64})?$" }, "entrypoint": { "type": "string", diff --git a/internal/config/validation_schema.go b/internal/config/validation_schema.go index b562c66b..555e6c92 100644 --- a/internal/config/validation_schema.go +++ b/internal/config/validation_schema.go @@ -59,7 +59,7 @@ func isTransientHTTPError(statusCode int) bool { var ( // Compile regex patterns from schema for additional validation - containerPattern = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9./_-]*(:([a-zA-Z0-9._-]+|latest))?$`) + containerPattern = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9./_-]*(:([a-zA-Z0-9._-]+|latest))?(@sha256:[a-fA-F0-9]{64})?$`) urlPattern = regexp.MustCompile(`^https?://.+`) mountPattern = regexp.MustCompile(`^[^:]+:[^:]+:(ro|rw)$`) domainVarPattern = regexp.MustCompile(`^\$\{[A-Z_][A-Z0-9_]*\}$`) diff --git a/internal/config/validation_schema_test.go b/internal/config/validation_schema_test.go index 8a380e01..b4c3f573 100644 --- a/internal/config/validation_schema_test.go +++ b/internal/config/validation_schema_test.go @@ -365,6 +365,30 @@ func TestValidateStringPatterns(t *testing.T) { }, shouldErr: false, }, + { + name: "valid container pattern - tag with sha256 digest", + config: &StdinConfig{ + MCPServers: map[string]*StdinServerConfig{ + "test": { + Type: "stdio", + Container: "ghcr.io/owner/image:v1.2.3@sha256:2763823c67a0adca3fce6e3bdfee41a674e3bf22f0e6b2eee94ed3a72ebcd519", + }, + }, + }, + shouldErr: false, + }, + { + name: "valid container pattern - sha256 digest only", + config: &StdinConfig{ + MCPServers: map[string]*StdinServerConfig{ + "test": { + Type: "stdio", + Container: "ghcr.io/owner/image@sha256:2763823c67a0adca3fce6e3bdfee41a674e3bf22f0e6b2eee94ed3a72ebcd519", + }, + }, + }, + shouldErr: false, + }, { name: "invalid container pattern - starts with special char", config: &StdinConfig{ diff --git a/internal/config/validation_string_patterns_test.go b/internal/config/validation_string_patterns_test.go index aa04c61d..19c28563 100644 --- a/internal/config/validation_string_patterns_test.go +++ b/internal/config/validation_string_patterns_test.go @@ -64,6 +64,19 @@ func TestValidateStringPatternsComprehensive(t *testing.T) { serverType: "", shouldError: false, }, + // Valid container patterns with SHA-256 digest + { + name: "valid container with tag and sha256 digest", + container: "ghcr.io/github/github-mcp-server:v0.32.0@sha256:2763823c67a0adca3fce6e3bdfee41a674e3bf22f0e6b2eee94ed3a72ebcd519", + serverType: "stdio", + shouldError: false, + }, + { + name: "valid container with sha256 digest only", + container: "ghcr.io/github/github-mcp-server@sha256:2763823c67a0adca3fce6e3bdfee41a674e3bf22f0e6b2eee94ed3a72ebcd519", + serverType: "stdio", + shouldError: false, + }, // Invalid container patterns { name: "invalid container starts with special char", @@ -86,6 +99,20 @@ func TestValidateStringPatternsComprehensive(t *testing.T) { shouldError: true, errorField: "container", }, + { + name: "invalid container sha256 digest too short", + container: "ghcr.io/github/github-mcp-server@sha256:short", + serverType: "stdio", + shouldError: true, + errorField: "container", + }, + { + name: "invalid container wrong digest algorithm", + container: "ghcr.io/github/github-mcp-server@md5:2763823c67a0adca3fce6e3bdfee41a674e3bf22f0e6b2eee94ed3a72ebcd519", + serverType: "stdio", + shouldError: true, + errorField: "container", + }, { name: "invalid container empty string accepted (empty is valid)", container: "", From 86b59ae28f340e7f378aab316c97f5a6f61a0475 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 8 Apr 2026 02:15:46 +0000 Subject: [PATCH 3/3] Update error hint and schema description to mention @sha256 digest support Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/c0572733-6f1d-4e16-98d8-4d1cafd9413b Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- internal/config/schema/mcp-gateway-config.schema.json | 2 +- internal/config/validation_schema.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/config/schema/mcp-gateway-config.schema.json b/internal/config/schema/mcp-gateway-config.schema.json index 7e5ad7d3..c317d00d 100644 --- a/internal/config/schema/mcp-gateway-config.schema.json +++ b/internal/config/schema/mcp-gateway-config.schema.json @@ -74,7 +74,7 @@ }, "container": { "type": "string", - "description": "Container image for the MCP server (e.g., 'ghcr.io/example/mcp-server:latest'). This field is required for stdio servers per MCP Gateway Specification section 4.1.2.", + "description": "Container image for the MCP server (e.g., 'ghcr.io/example/mcp-server:latest' or 'ghcr.io/example/mcp-server@sha256:'). This field is required for stdio servers per MCP Gateway Specification section 4.1.2.", "minLength": 1, "pattern": "^[a-zA-Z0-9][a-zA-Z0-9./_-]*(:([a-zA-Z0-9._-]+|latest))?(@sha256:[a-fA-F0-9]{64})?$" }, diff --git a/internal/config/validation_schema.go b/internal/config/validation_schema.go index 555e6c92..002cda3e 100644 --- a/internal/config/validation_schema.go +++ b/internal/config/validation_schema.go @@ -506,7 +506,7 @@ func validateStringPatterns(stdinCfg *StdinConfig) error { if server.Container != "" && !containerPattern.MatchString(server.Container) { return rules.InvalidPattern("container", server.Container, fmt.Sprintf("%s.container", jsonPath), - "Use a valid container image format (e.g., 'ghcr.io/owner/image:tag' or 'owner/image:latest')") + "Use a valid container image format (e.g., 'ghcr.io/owner/image:tag', 'owner/image:latest', or 'ghcr.io/owner/image:tag@sha256:')") } // Validate mount patterns