Skip to content

Commit 2c24fea

Browse files
Cherry-picks for v2.11.11-RC.1 (#7480)
Includes the following: - #7380 - #7384 - #7385 - #7388 - #7395 - #7400 - #7399 - #7401 - #7402 - #7423 - #7424 - #7411 - #7428 - #7429 - #7431 - #7435 - #7433 - #7443 - #7455 - #7465 - #7466 - #7460 - #7484 - #7479 Signed-off-by: Neil Twigg <[email protected]>
2 parents 14e2916 + 36fddba commit 2c24fea

32 files changed

+1584
-344
lines changed

.github/workflows/release.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ jobs:
3333
3434
- name: Install cosign
3535
# Use commit hash here to avoid a re-tagging attack, as this is a third-party action
36-
# Commit d7543c93d881b35a8faa02e8e3605f69b7a1ce62 = tag v3.10.0
37-
uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62
36+
# Commit faadad0cce49287aee09b3a48701e75088a2c6ad = tag v4.0.0
37+
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad
3838

3939
- name: Install syft
4040
# Use commit hash here to avoid a re-tagging attack, as this is a third-party action
41-
# Commit f8bdd1d8ac5e901a77a92f111440fdb1b593736b = tag v0.20.6
42-
uses: anchore/sbom-action/download-syft@f8bdd1d8ac5e901a77a92f111440fdb1b593736b
41+
# Commit 8e94d75ddd33f69f691467e42275782e4bfefe84 = tag v0.20.9
42+
uses: anchore/sbom-action/download-syft@8e94d75ddd33f69f691467e42275782e4bfefe84
4343
with:
4444
syft-version: "v1.27.1"
4545

.goreleaser.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ builds:
2121
env:
2222
# This is the toolchain version we use for releases. To override, set the env var, e.g.:
2323
# GORELEASER_TOOLCHAIN="go1.22.8" TARGET='linux_amd64' goreleaser build --snapshot --clean --single-target
24-
- GOTOOLCHAIN={{ envOrDefault "GORELEASER_TOOLCHAIN" "go1.24.7" }}
24+
- GOTOOLCHAIN={{ envOrDefault "GORELEASER_TOOLCHAIN" "go1.25.3" }}
2525
- GO111MODULE=on
2626
- CGO_ENABLED=0
2727
goos:
@@ -38,6 +38,8 @@ builds:
3838
- mips64le
3939
- s390x
4040
- ppc64le
41+
# RISC-V currently only supported on Linux
42+
- riscv64
4143
goarm:
4244
- 6
4345
- 7
@@ -52,6 +54,12 @@ builds:
5254
goarch: arm64
5355
- goos: freebsd
5456
goarch: 386
57+
- goos: darwin
58+
goarch: riscv64
59+
- goos: windows
60+
goarch: riscv64
61+
- goos: freebsd
62+
goarch: riscv64
5563
mod_timestamp: "{{ .CommitTimestamp }}"
5664

5765
nfpms:

go.mod

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@ module github.com/nats-io/nats-server/v2
22

33
go 1.24.0
44

5+
toolchain go1.24.9
6+
57
require (
68
github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op
79
github.com/google/go-tpm v0.9.6
8-
github.com/klauspost/compress v1.18.0
10+
github.com/klauspost/compress v1.18.1
911
github.com/minio/highwayhash v1.0.3
1012
github.com/nats-io/jwt/v2 v2.8.0
11-
github.com/nats-io/nats.go v1.46.1
13+
github.com/nats-io/nats.go v1.47.0
1214
github.com/nats-io/nkeys v0.4.11
1315
github.com/nats-io/nuid v1.0.1
1416
go.uber.org/automaxprocs v1.6.0
15-
golang.org/x/crypto v0.42.0
16-
golang.org/x/sys v0.36.0
17-
golang.org/x/time v0.13.0
17+
golang.org/x/crypto v0.43.0
18+
golang.org/x/sys v0.37.0
19+
golang.org/x/time v0.14.0
1820
)

go.sum

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
44
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
55
github.com/google/go-tpm v0.9.6 h1:Ku42PT4LmjDu1H5C5ISWLlpI1mj+Zq7sPGKoRw2XROA=
66
github.com/google/go-tpm v0.9.6/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
7-
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
8-
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
7+
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
8+
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
99
github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q=
1010
github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
1111
github.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g=
1212
github.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA=
13-
github.com/nats-io/nats.go v1.46.1 h1:bqQ2ZcxVd2lpYI97xYASeRTY3I5boe/IVmuUDPitHfo=
14-
github.com/nats-io/nats.go v1.46.1/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
13+
github.com/nats-io/nats.go v1.47.0 h1:YQdADw6J/UfGUd2Oy6tn4Hq6YHxCaJrVKayxxFqYrgM=
14+
github.com/nats-io/nats.go v1.47.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
1515
github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0=
1616
github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE=
1717
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
@@ -24,12 +24,12 @@ github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMT
2424
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
2525
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
2626
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
27-
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
28-
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
27+
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
28+
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
2929
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
30-
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
31-
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
32-
golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
33-
golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
30+
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
31+
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
32+
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
33+
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
3434
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
3535
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

server/.tmp

66 Bytes
Binary file not shown.

server/ciphersuites.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package server
1515

1616
import (
17+
"crypto/fips140"
1718
"crypto/tls"
1819
)
1920

@@ -94,6 +95,16 @@ var curvePreferenceMap = map[string]tls.CurveID{
9495
// reorder to default to the highest level of security. See:
9596
// https://blog.bracebin.com/achieving-perfect-ssl-labs-score-with-go
9697
func defaultCurvePreferences() []tls.CurveID {
98+
if fips140.Enabled() {
99+
// X25519 is not FIPS-approved by itself, but it is when
100+
// combined with MLKEM768.
101+
return []tls.CurveID{
102+
tls.X25519MLKEM768, // post-quantum
103+
tls.CurveP256,
104+
tls.CurveP384,
105+
tls.CurveP521,
106+
}
107+
}
97108
return []tls.CurveID{
98109
tls.X25519, // faster than P256, arguably more secure
99110
tls.CurveP256,

server/client.go

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"net/url"
3030
"regexp"
3131
"runtime"
32+
"slices"
3233
"strconv"
3334
"strings"
3435
"sync"
@@ -4257,7 +4258,7 @@ func (c *client) setupResponseServiceImport(acc *Account, si *serviceImport, tra
42574258

42584259
// Will remove a header if present.
42594260
func removeHeaderIfPresent(hdr []byte, key string) []byte {
4260-
start := bytes.Index(hdr, []byte(key))
4261+
start := getHeaderKeyIndex(key, hdr)
42614262
// key can't be first and we want to check that it is preceded by a '\n'
42624263
if start < 1 || hdr[start-1] != '\n' {
42634264
return hdr
@@ -4375,22 +4376,13 @@ func sliceHeader(key string, hdr []byte) []byte {
43754376
if len(hdr) == 0 {
43764377
return nil
43774378
}
4378-
index := bytes.Index(hdr, stringToBytes(key+":"))
4379-
hdrLen := len(hdr)
4380-
// Check that we have enough characters, this will handle the -1 case of the key not
4381-
// being found and will also handle not having enough characters for trailing CRLF.
4382-
if index < 2 {
4383-
return nil
4384-
}
4385-
// There should be a terminating CRLF.
4386-
if index >= hdrLen-1 || hdr[index-1] != '\n' || hdr[index-2] != '\r' {
4379+
index := getHeaderKeyIndex(key, hdr)
4380+
if index == -1 {
43874381
return nil
43884382
}
4389-
// The key should be immediately followed by a : separator.
4383+
// Skip over the key and the : separator.
43904384
index += len(key) + 1
4391-
if index >= hdrLen || hdr[index-1] != ':' {
4392-
return nil
4393-
}
4385+
hdrLen := len(hdr)
43944386
// Skip over whitespace before the value.
43954387
for index < hdrLen && hdr[index] == ' ' {
43964388
index++
@@ -4406,6 +4398,65 @@ func sliceHeader(key string, hdr []byte) []byte {
44064398
return hdr[start:index:index]
44074399
}
44084400

4401+
// getHeaderKeyIndex returns an index into the header slice for the given key.
4402+
// Returns -1 if not found.
4403+
func getHeaderKeyIndex(key string, hdr []byte) int {
4404+
if len(hdr) == 0 {
4405+
return -1
4406+
}
4407+
bkey := stringToBytes(key)
4408+
keyLen, hdrLen := len(key), len(hdr)
4409+
var offset int
4410+
for {
4411+
index := bytes.Index(hdr[offset:], bkey)
4412+
// Check that we have enough characters, this will handle the -1 case of the key not
4413+
// being found and will also handle not having enough characters for trailing CRLF.
4414+
if index < 2 {
4415+
return -1
4416+
}
4417+
index += offset
4418+
// There should be a terminating CRLF.
4419+
if index >= hdrLen-1 || hdr[index-1] != '\n' || hdr[index-2] != '\r' {
4420+
offset = index + keyLen
4421+
continue
4422+
}
4423+
// The key should be immediately followed by a : separator.
4424+
if index+keyLen >= hdrLen {
4425+
return -1
4426+
}
4427+
if hdr[index+keyLen] != ':' {
4428+
offset = index + keyLen
4429+
continue
4430+
}
4431+
return index
4432+
}
4433+
}
4434+
4435+
func setHeader(key, val string, hdr []byte) []byte {
4436+
start := getHeaderKeyIndex(key, hdr)
4437+
if start >= 0 {
4438+
valStart := start + len(key) + 1
4439+
// Preserve single whitespace if used.
4440+
hdrLen := len(hdr)
4441+
if valStart < hdrLen && hdr[valStart] == ' ' {
4442+
valStart++
4443+
}
4444+
valEnd := bytes.Index(hdr[valStart:], []byte("\r"))
4445+
if valEnd < 0 {
4446+
return hdr // malformed headers
4447+
}
4448+
valEnd += valStart
4449+
suffix := slices.Clone(hdr[valEnd:])
4450+
newHdr := append(hdr[:valStart], val...)
4451+
return append(newHdr, suffix...)
4452+
}
4453+
if len(hdr) > 0 && bytes.HasSuffix(hdr, []byte("\r\n")) {
4454+
hdr = hdr[:len(hdr)-2]
4455+
val += "\r\n"
4456+
}
4457+
return fmt.Appendf(hdr, "%s: %s\r\n", key, val)
4458+
}
4459+
44094460
// For bytes.HasPrefix below.
44104461
var (
44114462
jsRequestNextPreB = []byte(jsRequestNextPre)

server/client_test.go

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3040,7 +3040,7 @@ func TestSliceHeader(t *testing.T) {
30403040
require_True(t, bytes.Equal(sliced, copied))
30413041
}
30423042

3043-
func TestSliceHeaderOrdering(t *testing.T) {
3043+
func TestSliceHeaderOrderingPrefix(t *testing.T) {
30443044
hdr := []byte("NATS/1.0\r\n\r\n")
30453045

30463046
// These headers share the same prefix, the longer subject
@@ -3060,6 +3060,105 @@ func TestSliceHeaderOrdering(t *testing.T) {
30603060
require_True(t, bytes.Equal(sliced, copied))
30613061
}
30623062

3063+
func TestSliceHeaderOrderingSuffix(t *testing.T) {
3064+
hdr := []byte("NATS/1.0\r\n\r\n")
3065+
3066+
// These headers share the same suffix, the longer subject
3067+
// must not invalidate the existence of the shorter one.
3068+
hdr = genHeader(hdr, "Previous-Nats-Msg-Id", "user")
3069+
hdr = genHeader(hdr, "Nats-Msg-Id", "control")
3070+
3071+
sliced := sliceHeader("Nats-Msg-Id", hdr)
3072+
copied := getHeader("Nats-Msg-Id", hdr)
3073+
3074+
require_NotNil(t, sliced)
3075+
require_NotNil(t, copied)
3076+
require_True(t, bytes.Equal(sliced, copied))
3077+
require_Equal(t, string(copied), "control")
3078+
}
3079+
3080+
func TestRemoveHeaderIfPresentOrderingPrefix(t *testing.T) {
3081+
hdr := []byte("NATS/1.0\r\n\r\n")
3082+
3083+
// These headers share the same prefix, the longer subject
3084+
// must not invalidate the existence of the shorter one.
3085+
hdr = genHeader(hdr, JSExpectedLastSubjSeqSubj, "foo")
3086+
hdr = genHeader(hdr, JSExpectedLastSubjSeq, "24")
3087+
3088+
hdr = removeHeaderIfPresent(hdr, JSExpectedLastSubjSeq)
3089+
ehdr := genHeader(nil, JSExpectedLastSubjSeqSubj, "foo")
3090+
require_True(t, bytes.Equal(hdr, ehdr))
3091+
}
3092+
3093+
func TestRemoveHeaderIfPresentOrderingSuffix(t *testing.T) {
3094+
hdr := []byte("NATS/1.0\r\n\r\n")
3095+
3096+
// These headers share the same suffix, the longer subject
3097+
// must not invalidate the existence of the shorter one.
3098+
hdr = genHeader(hdr, "Previous-Nats-Msg-Id", "user")
3099+
hdr = genHeader(hdr, "Nats-Msg-Id", "control")
3100+
3101+
hdr = removeHeaderIfPresent(hdr, "Nats-Msg-Id")
3102+
ehdr := genHeader(nil, "Previous-Nats-Msg-Id", "user")
3103+
require_True(t, bytes.Equal(hdr, ehdr))
3104+
}
3105+
3106+
func TestSetHeaderOrderingPrefix(t *testing.T) {
3107+
for _, space := range []bool{true, false} {
3108+
title := "Normal"
3109+
if !space {
3110+
title = "Trimmed"
3111+
}
3112+
t.Run(title, func(t *testing.T) {
3113+
hdr := []byte("NATS/1.0\r\n\r\n")
3114+
3115+
// These headers share the same prefix, the longer subject
3116+
// must not invalidate the existence of the shorter one.
3117+
hdr = genHeader(hdr, JSExpectedLastSubjSeqSubj, "foo")
3118+
hdr = genHeader(hdr, JSExpectedLastSubjSeq, "24")
3119+
if !space {
3120+
hdr = bytes.ReplaceAll(hdr, []byte(" "), nil)
3121+
}
3122+
3123+
hdr = setHeader(JSExpectedLastSubjSeq, "12", hdr)
3124+
ehdr := genHeader(nil, JSExpectedLastSubjSeqSubj, "foo")
3125+
ehdr = genHeader(ehdr, JSExpectedLastSubjSeq, "12")
3126+
if !space {
3127+
ehdr = bytes.ReplaceAll(ehdr, []byte(" "), nil)
3128+
}
3129+
require_True(t, bytes.Equal(hdr, ehdr))
3130+
})
3131+
}
3132+
}
3133+
3134+
func TestSetHeaderOrderingSuffix(t *testing.T) {
3135+
for _, space := range []bool{true, false} {
3136+
title := "Normal"
3137+
if !space {
3138+
title = "Trimmed"
3139+
}
3140+
t.Run(title, func(t *testing.T) {
3141+
hdr := []byte("NATS/1.0\r\n\r\n")
3142+
3143+
// These headers share the same suffix, the longer subject
3144+
// must not invalidate the existence of the shorter one.
3145+
hdr = genHeader(hdr, "Previous-Nats-Msg-Id", "user")
3146+
hdr = genHeader(hdr, "Nats-Msg-Id", "control")
3147+
if !space {
3148+
hdr = bytes.ReplaceAll(hdr, []byte(" "), nil)
3149+
}
3150+
3151+
hdr = setHeader("Nats-Msg-Id", "other", hdr)
3152+
ehdr := genHeader(nil, "Previous-Nats-Msg-Id", "user")
3153+
ehdr = genHeader(ehdr, "Nats-Msg-Id", "other")
3154+
if !space {
3155+
ehdr = bytes.ReplaceAll(ehdr, []byte(" "), nil)
3156+
}
3157+
require_True(t, bytes.Equal(hdr, ehdr))
3158+
})
3159+
}
3160+
}
3161+
30633162
func TestInProcessAllowedConnectionType(t *testing.T) {
30643163
tmpl := `
30653164
listen: "127.0.0.1:-1"

0 commit comments

Comments
 (0)