Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions backend/internal/service/openai_codex_account_identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func applyCodexAccountIdentityEmbeddedMetadata(values map[string]any, account *A
if !applyCodexAccountIdentityFields(metadata, account, apiKeyID) {
return false
}
rebuilt, err := json.Marshal(metadata)
rebuilt, err := marshalCodexTurnMetadata(metadata)
if err != nil {
return false
}
Expand Down Expand Up @@ -267,7 +267,7 @@ func applyCodexAccountIdentityHeaders(headers http.Header, account *Account, api
if raw := strings.TrimSpace(headers.Get(openAIWSTurnMetadataHeader)); raw != "" {
metadata := map[string]any{}
if err := json.Unmarshal([]byte(raw), &metadata); err == nil && metadata != nil && applyCodexAccountIdentityFields(metadata, account, apiKeyID) {
if rebuilt, err := json.Marshal(metadata); err == nil {
if rebuilt, err := marshalCodexTurnMetadata(metadata); err == nil {
headers.Set(openAIWSTurnMetadataHeader, string(rebuilt))
}
}
Expand Down
4 changes: 2 additions & 2 deletions backend/internal/service/openai_codex_fingerprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ func rewriteCodexTurnMetadataFields(h http.Header, fields map[string]any) {
for k, v := range fields {
metadata[k] = v
}
rebuilt, err := json.Marshal(metadata)
rebuilt, err := marshalCodexTurnMetadata(metadata)
if err != nil {
return
}
Expand Down Expand Up @@ -595,7 +595,7 @@ func rewriteClientMetadataEmbeddedTurnMetadata(clientMetadata map[string]any, fi
for k, v := range fields {
metadata[k] = v
}
if rebuilt, err := json.Marshal(metadata); err == nil {
if rebuilt, err := marshalCodexTurnMetadata(metadata); err == nil {
clientMetadata["x-codex-turn-metadata"] = string(rebuilt)
}
}
39 changes: 39 additions & 0 deletions backend/internal/service/openai_codex_turn_metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package service

import (
"encoding/json"
"unicode/utf16"
)

// Turn metadata is also used as an HTTP header, including when carried in WS JSON.
func marshalCodexTurnMetadata(metadata map[string]any) ([]byte, error) {
raw, err := json.Marshal(metadata)
if err != nil {
return nil, err
}
for i, b := range raw {
if b < 0x7f {
continue
}
out := make([]byte, 0, len(raw)+16)
out = append(out, raw[:i]...)
appendEscape := func(r rune) {
const hex = "0123456789abcdef"
out = append(out, '\\', 'u', hex[r>>12&15], hex[r>>8&15], hex[r>>4&15], hex[r&15])
}
for _, r := range string(raw[i:]) {
switch {
case r < 0x7f:
out = append(out, byte(r))
case r <= 0xffff:
appendEscape(r)
default:
high, low := utf16.EncodeRune(r)
appendEscape(high)
appendEscape(low)
}
}
return out, nil
}
return raw, nil
}
88 changes: 88 additions & 0 deletions backend/internal/service/openai_codex_turn_metadata_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package service

import (
"encoding/json"
"net/http"
"testing"

"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
)

func TestCodexTurnMetadataRewritePreservesHeaderSafeJSON(t *testing.T) {
account := newTestOAuthAccount(1, map[string]any{codexFingerprintModeExtraKey: "session"})
account.Credentials = map[string]any{"chatgpt_account_id": "test-account"}
ids := resolveCodexFingerprintIDsFromRequest(account, http.Header{})
require.NotNil(t, ids)

rewriters := map[string]func(*testing.T, string) string{
"account_header": func(t *testing.T, raw string) string {
h := make(http.Header)
h.Set(openAIWSTurnMetadataHeader, raw)
applyCodexAccountIdentityHeaders(h, account, 77)
return h.Get(openAIWSTurnMetadataHeader)
},
"account_body_map": func(t *testing.T, raw string) string {
cm := map[string]any{openAIWSTurnMetadataHeader: raw}
require.True(t, applyCodexAccountIdentityClientMetadataMap(map[string]any{"client_metadata": cm}, account, 77))
value, ok := cm[openAIWSTurnMetadataHeader].(string)
require.True(t, ok)
return value
},
"account_body_raw": func(t *testing.T, raw string) string {
body, err := json.Marshal(map[string]any{"client_metadata": map[string]any{openAIWSTurnMetadataHeader: raw}})
require.NoError(t, err)
updated, changed, err := applyCodexAccountIdentityClientMetadataRaw(body, account, 77)
require.NoError(t, err)
require.True(t, changed)
return gjson.GetBytes(updated, "client_metadata."+openAIWSTurnMetadataHeader).String()
},
"fingerprint_header": func(t *testing.T, raw string) string {
h := make(http.Header)
h.Set(openAIWSTurnMetadataHeader, raw)
applyCodexFingerprintHeaders(h, ids)
return h.Get(openAIWSTurnMetadataHeader)
},
"fingerprint_body_map": func(t *testing.T, raw string) string {
cm := map[string]any{openAIWSTurnMetadataHeader: raw}
require.True(t, applyCodexFingerprintClientMetadata(map[string]any{"client_metadata": cm}, ids))
value, ok := cm[openAIWSTurnMetadataHeader].(string)
require.True(t, ok)
return value
},
"fingerprint_body_raw": func(t *testing.T, raw string) string {
body, err := json.Marshal(map[string]any{"client_metadata": map[string]any{openAIWSTurnMetadataHeader: raw}})
require.NoError(t, err)
updated, changed, err := applyCodexFingerprintClientMetadataRaw(body, ids)
require.NoError(t, err)
require.True(t, changed)
return gjson.GetBytes(updated, "client_metadata."+openAIWSTurnMetadataHeader).String()
},
}

for _, raw := range []string{
`{"installation_id":"client-install","workspaces":{"C:\\work\\中文🚀":{}}}`,
`{"installation_id":"client-install","workspaces":{"C:\\work\\中文🚀":{"label":"café"}},"literal":"\\u4e2d","quote":"\"\\","controls":"\b\f\n\r\t\u0000\u007f","timestamp":1789302780858,"enabled":true}`,
`{"installation_id":"client-install","workspaces":{"C:\\work\\\u4e2d\u6587\ud83d\ude80":{"label":"caf\u00e9"}},"literal":"\\u4e2d","quote":"\"\\","controls":"\b\f\n\r\t\u0000\u007f","timestamp":1789302780858,"enabled":true}`,
`{"installation_id":"client-install","workspaces":{"C:\\work\\ascii":{}},"literal":"\\u4e2d"}`,
} {
var original map[string]any
require.NoError(t, json.Unmarshal([]byte(raw), &original))
for name, rewrite := range rewriters {
t.Run(name, func(t *testing.T) {
updated := rewrite(t, raw)
var decoded map[string]any
require.NoError(t, json.Unmarshal([]byte(updated), &decoded))
for key, value := range original {
if key != "installation_id" {
require.Equal(t, value, decoded[key], key)
}
}
require.NotEqual(t, original["installation_id"], decoded["installation_id"])
for _, b := range []byte(updated) {
require.True(t, b >= 0x20 && b < 0x7f, "non-printable ASCII header byte: 0x%02x", b)
}
})
}
}
}
Loading