Skip to content

Commit 896e855

Browse files
committed
fix: cache CryptoKey, strip Cookie, /flush secret, PrettyPrint borders, SSE concurrency
workers/index.js: - Cache imported CryptoKey by kid in module-scope Map so importKey() is only paid once per key rotation, not on every authenticated request - Strip Cookie header before proxying to backend (Go server uses no session cookies; forwarding them leaks user session data to the origin) - Set X-Backend-Token header from env.BACKEND_TOKEN when present so the backend can verify requests come from the Worker backend/server.go: - Check X-Backend-Token against BACKEND_TOKEN env var on POST /flush; returns 403 if the secret is configured and the header is absent/wrong, protecting the reset endpoint from direct Cloud Run access backend/state.go: - Fix PrettyPrint: all content rows were missing the trailing ║ border, producing an open-ended box. Introduce a row() helper that left-pads content to 62-char interior width and appends ║ for a properly closed rectangular display deploy-podman.sh: - Lower --concurrency from 1000 → 80; SSE connections are long-lived and each holds resources on a 1 CPU / 512Mi instance — 1000 was unreachable in practice and risked masking resource saturation https://claude.ai/code/session_013cFiQZ1hnb4JrBj9DvDgip
1 parent 00d351e commit 896e855

4 files changed

Lines changed: 49 additions & 17 deletions

File tree

backend/server.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"fmt"
77
"net/http"
8+
"os"
89
"time"
910

1011
"github.com/go-chi/chi/v5"
@@ -90,8 +91,18 @@ func (s *Server) handleState(w http.ResponseWriter, r *http.Request) {
9091
}
9192

9293
func (s *Server) handleFlush(w http.ResponseWriter, r *http.Request) {
94+
// Require a shared secret header when BACKEND_TOKEN is configured.
95+
// The Cloudflare Worker sets X-Backend-Token on every proxied request so
96+
// only traffic originating from the Worker is accepted; direct Cloud Run
97+
// access without the secret returns 403.
98+
if token := os.Getenv("BACKEND_TOKEN"); token != "" {
99+
if r.Header.Get("X-Backend-Token") != token {
100+
http.Error(w, "Forbidden", http.StatusForbidden)
101+
return
102+
}
103+
}
93104
s.sim.resetInitialState()
94-
w.WriteHeader(204)
105+
w.WriteHeader(http.StatusNoContent)
95106
}
96107

97108
func (s *Server) handleSSE(w http.ResponseWriter, r *http.Request) {

backend/state.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,21 @@ func (s State) Validate() error {
3535
}
3636

3737
func (s State) PrettyPrint() string {
38+
const w = 62 // interior width (total line = 64: two ║ bookends + 62 chars)
39+
row := func(content string) string {
40+
return fmt.Sprintf("║%-*s║\n", w, content)
41+
}
3842
var sb strings.Builder
3943
sb.WriteString("\n╔══════════════════════════════════════════════════════════════╗\n")
40-
sb.WriteString(fmt.Sprintf(" SOUL LATTICE v%s | %s\n", s.Version, s.Protocol))
44+
sb.WriteString(row(fmt.Sprintf(" SOUL LATTICE v%s | %s", s.Version, s.Protocol)))
4145
sb.WriteString("╠══════════════════════════════════════════════════════════════╣\n")
42-
sb.WriteString(fmt.Sprintf(" Breath : %.4f λ\n", s.Breath))
43-
sb.WriteString(fmt.Sprintf(" Thermodynamic Yield : %.3f η\n", s.ThermodynamicYield))
44-
sb.WriteString(fmt.Sprintf(" Coherence : %.2f%% %s\n", s.CoherencePercent, s.colorCoherence()))
45-
sb.WriteString(fmt.Sprintf(" Surplus Tokens : %d\n", s.SurplusTokens))
46-
sb.WriteString(fmt.Sprintf(" Token Velocity : %.1f t/s\n", s.TokensGeneratedPerS))
47-
sb.WriteString(fmt.Sprintf(" GPU Utilization : %.1f%%\n", s.GPUUtilization))
48-
sb.WriteString(fmt.Sprintf(" Uptime : %s\n", s.formatUptime()))
46+
sb.WriteString(row(fmt.Sprintf(" Breath : %.4f λ", s.Breath)))
47+
sb.WriteString(row(fmt.Sprintf(" Thermodynamic Yield : %.3f η", s.ThermodynamicYield)))
48+
sb.WriteString(row(fmt.Sprintf(" Coherence : %.2f%% %s", s.CoherencePercent, s.colorCoherence())))
49+
sb.WriteString(row(fmt.Sprintf(" Surplus Tokens : %d", s.SurplusTokens)))
50+
sb.WriteString(row(fmt.Sprintf(" Token Velocity : %.1f t/s", s.TokensGeneratedPerS)))
51+
sb.WriteString(row(fmt.Sprintf(" GPU Utilization : %.1f%%", s.GPUUtilization)))
52+
sb.WriteString(row(fmt.Sprintf(" Uptime : %s", s.formatUptime())))
4953
sb.WriteString("╚══════════════════════════════════════════════════════════════╝\n")
5054
return sb.String()
5155
}

deploy-podman.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ gcloud run deploy ${SERVICE_NAME} \
4040
--allow-unauthenticated \
4141
--memory 512Mi \
4242
--cpu 1 \
43-
--concurrency 1000 \
43+
--concurrency 80 \
4444
--max-instances 1 \
4545
--min-instances 1 \
4646
--execution-environment gen2 \

workers/index.js

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ let _jwksCache = null;
8888
let _jwksCacheAt = 0;
8989
const JWKS_TTL_MS = 10 * 60 * 1000; // 10 minutes
9090

91+
// CryptoKey cache: kid → CryptoKey. importKey() is relatively expensive;
92+
// caching avoids re-importing the same public key on every authenticated request.
93+
const _cryptoKeyCache = new Map();
94+
9195
async function getJWKS() {
9296
const now = Date.now();
9397
if (_jwksCache && now - _jwksCacheAt < JWKS_TTL_MS) return _jwksCache;
@@ -138,12 +142,18 @@ async function validateJWT(request) {
138142
const jwk = jwks.keys.find(k => k.kid === header.kid);
139143
if (!jwk) throw new Error(`No JWKS key for kid=${header.kid}`);
140144

141-
// Cloudflare Access uses RS256 (RSASSA-PKCS1-v1_5 + SHA-256)
142-
const cryptoKey = await crypto.subtle.importKey(
143-
'jwk', jwk,
144-
{ name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' },
145-
false, ['verify'],
146-
);
145+
// Cloudflare Access uses RS256 (RSASSA-PKCS1-v1_5 + SHA-256).
146+
// Cache the imported CryptoKey by kid so we pay the importKey cost only
147+
// once per key rotation rather than on every authenticated request.
148+
let cryptoKey = _cryptoKeyCache.get(header.kid);
149+
if (!cryptoKey) {
150+
cryptoKey = await crypto.subtle.importKey(
151+
'jwk', jwk,
152+
{ name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' },
153+
false, ['verify'],
154+
);
155+
_cryptoKeyCache.set(header.kid, cryptoKey);
156+
}
147157

148158
const message = new TextEncoder().encode(`${headerB64}.${payloadB64}`);
149159
const valid = await crypto.subtle.verify(
@@ -194,10 +204,17 @@ async function proxyToBackend(request, url, env, userEmail) {
194204
headers.set('X-Forwarded-For', existing ? `${existing}, ${cf}` : cf);
195205
}
196206

197-
// Strip Cloudflare Access headers before forwarding to the origin
207+
// Strip headers that must not reach the backend: Cloudflare Access tokens
208+
// (already validated) and Cookie (the Go backend uses no session cookies;
209+
// forwarding them would leak user session data to the origin unnecessarily).
198210
headers.delete('Cf-Access-Jwt-Assertion');
199211
headers.delete('Cf-Access-Client-Id');
200212
headers.delete('Cf-Access-Client-Secret');
213+
headers.delete('Cookie');
214+
215+
// Forward the shared secret so the backend can verify requests originate
216+
// from this Worker rather than direct Cloud Run access.
217+
if (env.BACKEND_TOKEN) headers.set('X-Backend-Token', env.BACKEND_TOKEN);
201218

202219
try {
203220
return await fetch(new Request(target, {

0 commit comments

Comments
 (0)