Skip to content

Commit c2556b3

Browse files
committed
fix(auth): enable production delegation
Configure API trust for hosted MCP delegation tokens and replace static secret-like test fixtures to prevent scanner noise. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9ff1e38a-b018-4cf7-a5e9-5044a2efd03c
1 parent 914c11a commit c2556b3

3 files changed

Lines changed: 42 additions & 36 deletions

File tree

‎api/cloudbuild.yaml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ steps:
1919
gcloud run deploy $_SERVICE_NAME \
2020
--image=us.gcr.io/$PROJECT_ID/$_SERVICE_NAME:$SHORT_SHA \
2121
--region=$_REGION --platform managed --allow-unauthenticated \
22+
--update-env-vars=MCP_AUTH_ISSUER=$_MCP_AUTH_ISSUER,MCP_AUTH_AUDIENCE=$_MCP_AUTH_AUDIENCE,MCP_AUTH_JWKS_URL=$_MCP_AUTH_JWKS_URL \
2223
--port=8000
2324
options:
2425
substitutionOption: ALLOW_LOOSE
2526

2627
substitutions:
2728
_SERVICE_NAME: http-sms-api
2829
_REGION: us-east1
30+
_MCP_AUTH_ISSUER: https://mcp.httpsms.com
31+
_MCP_AUTH_AUDIENCE: https://api.httpsms.com
32+
_MCP_AUTH_JWKS_URL: https://mcp.httpsms.com/.well-known/jwks.json

‎mcp/internal/config/config_test.go‎

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package config_test
22

33
import (
4+
"crypto/rand"
5+
"crypto/rsa"
6+
"crypto/x509"
7+
"encoding/pem"
48
"os"
9+
"sync"
510
"testing"
611
"time"
712

@@ -16,20 +21,22 @@ import (
1621
func setValidEnv(t *testing.T) {
1722
t.Helper()
1823

24+
privateKeyPEM := generatedTestPrivateKeyPEM(t)
1925
t.Setenv("ENV", "local")
2026
t.Setenv("MCP_BASE_URL", "https://mcp.httpsms.com")
2127
t.Setenv("HTTPSMS_API_URL", "https://api.httpsms.com")
2228
t.Setenv("REDIS_URL", "redis://localhost:6379")
2329
t.Setenv("FIREBASE_PROJECT_ID", "httpsms")
2430
t.Setenv("FIREBASE_API_KEY", "test-firebase-api-key")
2531
t.Setenv("FIREBASE_AUTH_DOMAIN", "httpsms.firebaseapp.com")
26-
t.Setenv("MCP_SIGNING_PRIVATE_KEY", testPrivateKeyPEM)
32+
t.Setenv("MCP_SIGNING_PRIVATE_KEY", privateKeyPEM)
2733
t.Setenv("MCP_SIGNING_PRIVATE_KEY_FILE", "")
2834
t.Setenv("MCP_SIGNING_KEY_ID", "test-key-1")
2935
}
3036

3137
func TestLoadSucceedsWithAValidEnvironment(t *testing.T) {
3238
setValidEnv(t)
39+
privateKeyPEM := generatedTestPrivateKeyPEM(t)
3340

3441
cfg, err := config.Load()
3542

@@ -41,7 +48,7 @@ func TestLoadSucceedsWithAValidEnvironment(t *testing.T) {
4148
assert.Equal(t, "redis://localhost:6379", cfg.RedisURL)
4249
assert.Equal(t, "httpsms", cfg.FirebaseProjectID)
4350
assert.Equal(t, "test-key-1", cfg.SigningKeyID)
44-
assert.Equal(t, []byte(testPrivateKeyPEM), cfg.SigningPrivateKeyPEM)
51+
assert.Equal(t, []byte(privateKeyPEM), cfg.SigningPrivateKeyPEM)
4552
assert.Equal(t, "https://mcp.httpsms.com/mcp", cfg.MCPAudience)
4653
assert.Equal(t, "https://api.httpsms.com", cfg.APIAudience)
4754
assert.Equal(t, 15*time.Minute, cfg.AccessTokenTTL)
@@ -158,14 +165,15 @@ func TestLoadRejectsMalformedSigningKeyPEM(t *testing.T) {
158165

159166
func TestLoadReadsSigningKeyFromFile(t *testing.T) {
160167
setValidEnv(t)
168+
privateKeyPEM := generatedTestPrivateKeyPEM(t)
161169
t.Setenv("MCP_SIGNING_PRIVATE_KEY", "")
162-
keyFile := writeTempKeyFile(t, testPrivateKeyPEM)
170+
keyFile := writeTempKeyFile(t, privateKeyPEM)
163171
t.Setenv("MCP_SIGNING_PRIVATE_KEY_FILE", keyFile)
164172

165173
cfg, err := config.Load()
166174

167175
require.NoError(t, err)
168-
assert.Equal(t, []byte(testPrivateKeyPEM), cfg.SigningPrivateKeyPEM)
176+
assert.Equal(t, []byte(privateKeyPEM), cfg.SigningPrivateKeyPEM)
169177
}
170178

171179
func TestLoadRejectsUnreadableSigningKeyFile(t *testing.T) {
@@ -266,37 +274,31 @@ func TestLoadReportsEveryProblemAtOnce(t *testing.T) {
266274
require.ErrorContains(t, err, "REDIS_URL")
267275
}
268276

269-
// testPrivateKeyPEM is a throwaway 2048-bit RSA private key used only to
270-
// exercise config.Load's PEM validation. It is not used to sign anything and
271-
// is not the same key used by any other package's tests.
272-
const testPrivateKeyPEM = `-----BEGIN RSA PRIVATE KEY-----
273-
MIIEpAIBAAKCAQEAsaRrsPaMlhkOb2j7UOaCShBBZNZ5nz0AGJq3HHW92Rd+VQ3l
274-
/vl1Zed0laz9lUyxWqR6vVR0fuK5reBVaN1GYHV9GgT9x1HM9cTg6eN0n8qpblWo
275-
DBKq8Qi4o2D7sNr2tl3SWbrUfKaKnBd6bFRHihJyEZXwc6zCXoPQ7eBQ7ozy99g7
276-
nyXtBse5Z5VY563W+hRbqOqHzzZ3qFwDv1Gy0VQZuMz2Paik1cY+XhVIdA2D3pAh
277-
UxDxG1TYkBKxsLuM+LmH3HgUGba+Pu9QGYe8PaH5SqGGX3EZxLDyClaaxQgmsZpt
278-
KzlwNSZk2sPAvCrYQxto8gelflYPw0jOSX/6EQIDAQABAoIBAEhQrcJZa7vCsXyr
279-
GPvDCrEJ0wUwxkwLshlSCk7co49XoAcR5FoaxS7ZvT0dMhHwKZbDtG+UjOQGeh4N
280-
X9eTlI255laMR583bp9yKTktbhGKl9ShrApWIx6CNV/VIEDLsnlk0jfS9aNUzMJk
281-
UGL/ICxV+/equTrtziZZtNjRY0DolFbo7swFhwey9K4bT7JGl5W+fpRLz3ucjN0z
282-
mBU7yI6CAM7YXH0kR4DXSZKiEUZ8xf0fbbraBpjbrA9hTVSWvouEtBJfyIjs6oXy
283-
ktchAWydNILqjiQzsNWLI/Vt3PdG9Gs2QT7ZpDxjuOiP7J9CDphDqhLoutD+bHJ8
284-
K4i+s/0CgYEAzaRj9KVt8x8IGv68gHShL+4eqXB6MAItLYFlLMDWWo5QK3l7ppFi
285-
dwHf3GpAdftQxzCy/R2TARu9oC822DiJJE+8YFci9uIH06adW1nqMPdIorPkvF8Y
286-
fKB7Sudw/2ILjeT0wg2AAaDw2VutVvSEpm5j9zA0NSUyKhNYt5thXbcCgYEA3SS7
287-
FfFM3EWhsjlKoa6RY6djTZzt7osMGy8u52nqPiFZR7fCbhrxJYROh2UmFn0/J8RB
288-
gLoHN4ZbmBze6cro8aTScFmz7cK6bT/eCLq0NopAL+OFP9jGkawo5UMZ7/hfBX8P
289-
gMoBD97VkTZw75uAyuVwbKMfPKF6lsFKUMNN5ncCgYEAxawQ3TksAHjC3NgjMMNr
290-
sdwOI0fYXE+rR8PLEoLnSbLlA3VKU+oKoWTu4DxObFrA4khAtah5B6a318Oqz5tA
291-
0OPIqz73gCPz7BKLziUXRixd6PBNnnk2242UFoN1Djgb7TC5ydMaSfZ/riA+9ogi
292-
/qy8cP8oIDH6D5H7RLsak+8CgYEAiPzY25XXS9fiezmcLp2puHaXQBvHE+6UeD55
293-
KqbkkMotuQxu56/O07OqxZp1xpadSa/795bFI7MaCBdSSrcEJ7Q3G5ulptHqlARt
294-
MTEes25epoulHlDVaKWhy6sOZSWRDyGPY/M+Ryt9Vm/H89V7KbSJOPKvReqturdP
295-
psnk9q8CgYB0knFbkzt3R7mowiiXqj4MhfO4baCPk9PeOslujQIJoX1Ca+/wQdox
296-
F2m9w4bRMrdsT19eMrRZsJYslJc6s2tNlCuUDMgFk3FUrmpFDQlq/taUCB/wDUxp
297-
3SBuTr9BHx8yJc9p6hYkjI3HZ+aqsImZIxN/23OFEvtOH2z3m8JPnA==
298-
-----END RSA PRIVATE KEY-----
299-
`
277+
var (
278+
testPrivateKeyOnce sync.Once
279+
testPrivateKeyPEM string
280+
testPrivateKeyErr error
281+
)
282+
283+
func generatedTestPrivateKeyPEM(t *testing.T) string {
284+
t.Helper()
285+
286+
testPrivateKeyOnce.Do(func() {
287+
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
288+
if err != nil {
289+
testPrivateKeyErr = err
290+
return
291+
}
292+
293+
testPrivateKeyPEM = string(pem.EncodeToMemory(&pem.Block{
294+
Type: "RSA PRIVATE KEY",
295+
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
296+
}))
297+
})
298+
299+
require.NoError(t, testPrivateKeyErr)
300+
return testPrivateKeyPEM
301+
}
300302

301303
// writeTempKeyFile writes contents to a new file inside t.TempDir() and
302304
// returns its path.

‎mcp/internal/tools/api_keys_test.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func TestCreatePhoneAPIKeyToolIsMarkedNotIdempotentAndNotDestructive(t *testing.
9898
func TestCreatePhoneAPIKeyNeverLeaksSecretOutsideStructuredResult(t *testing.T) {
9999
keys := newTestKeySet(t)
100100
ctx := contextWithPrincipal(t, keys, allScopes)
101-
const secret = "unique-phone-api-key-secret-4b9f9e6c-do-not-log"
101+
const secret = "test-phone-api-key"
102102
stub := &stubClient{createKeyResult: httpsms.PhoneAPIKey{ID: "key-1", Name: "android-phone", APIKey: secret}}
103103
session := newSession(t, ctx, keys, stub)
104104

0 commit comments

Comments
 (0)