Skip to content

Commit 58e4b87

Browse files
Merge branch 'master' into COMP-1146-fix-error-messages
2 parents 0f7fd53 + 913f750 commit 58e4b87

23 files changed

+1143
-258
lines changed

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Wave requires several environment variables for registry authentication:
5151
- Uses Micronaut's configuration system with property injection
5252

5353
## Technology Stack
54-
- **Framework**: Micronaut 4.x with Netty runtime
54+
- **Framework**: Micronaut 4.10.6 with Netty runtime
5555
- **Language**: Groovy with Java 21+
5656
- **Build Tool**: Gradle with custom conventions
5757
- **Container**: JIB for multi-platform builds (AMD64/ARM64)

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.31.2
1+
1.32.0

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ dependencies {
4949
implementation 'io.seqera:jedis-lock:1.0.0'
5050
implementation 'io.seqera:lib-data-queue-redis:1.1.1'
5151
implementation 'io.seqera:lib-data-stream-redis:1.1.2'
52+
implementation 'io.seqera:lib-jedis-pool:1.0.0'
5253
implementation 'io.micronaut:micronaut-http-client'
5354
implementation 'io.micronaut:micronaut-jackson-databind'
5455
implementation 'io.micronaut.groovy:micronaut-runtime-groovy'
@@ -91,7 +92,6 @@ dependencies {
9192
implementation 'org.postgresql:postgresql:42.7.7' // PostgreSQL Driver
9293
//object storage dependency
9394
implementation 'io.micronaut.objectstorage:micronaut-object-storage-aws'
94-
implementation 'io.micronaut.objectstorage:micronaut-object-storage-local'
9595
// include sts to allow the use of service account role - https://stackoverflow.com/a/73306570
9696
// this sts dependency is require by micronaut-aws-parameter-store,
9797
// not directly used by the app, for this reason keeping `runtimeOnly`

changelog.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
# Wave changelog
2+
1.32.0 - 12 Jan 2026
3+
- Upgrade to Micronaut 4.10.6 (#951) [6dda24c2b]
4+
- Use noarch node selector for mirror and transfer jobs (#953) [54f985174]
5+
- Replace RedisFactory with JedisPoolFactory from lib-jedis-pool [c8040227b]
6+
- Add missing HTTP Security Header (#955) [c48b8511c]
7+
28
1.31.2 - 17 Dec 2025
39
- Add JavaDocs to PixiOpts and update tests for new default pixi image (#950) [7f49bb8b4]
410
- docs: Style template build content (#948) [aa40d5513]

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@
1616
# along with this program. If not, see <https://www.gnu.org/licenses/>.
1717
#
1818

19-
micronautVersion=4.9.4
19+
micronautVersion=4.10.6
2020
micronautEnvs=local,mail,aws-ses
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Wave, containers provisioning service
3+
* Copyright (c) 2023-2024, Seqera Labs
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
package io.seqera.wave.configuration
20+
21+
import javax.annotation.Nullable
22+
import javax.annotation.PostConstruct
23+
24+
import groovy.transform.CompileStatic
25+
import groovy.transform.ToString
26+
import groovy.util.logging.Slf4j
27+
import io.micronaut.context.annotation.Requires
28+
import io.micronaut.context.annotation.Value
29+
import jakarta.inject.Singleton
30+
31+
/**
32+
* Configuration for HTTP security headers
33+
*
34+
* @author Munish Chouhan <[email protected]>
35+
*/
36+
@ToString(includeNames = true, includePackage = false)
37+
@CompileStatic
38+
@Slf4j
39+
@Singleton
40+
@Requires(property = 'wave.security.http-headers.enabled', value = 'true', defaultValue = 'true')
41+
class SecurityHeadersConfig {
42+
43+
/**
44+
* Enable or disable security headers globally
45+
*/
46+
@Value('${wave.security.http-headers.enabled:true}')
47+
Boolean enabled
48+
49+
/**
50+
* HSTS max-age in seconds
51+
* default to 1 year (31536000 seconds)
52+
* This tell browsers to only use HTTPS for one year (31,536,000 seconds) or custom value set by user,
53+
* preventing downgrade attacks and improving security by ensuring encrypted connections by default,
54+
* for more information check https://hstspreload.org/#submission-requirements
55+
*/
56+
@Value('${wave.security.http-headers.hsts.max-age:31536000}')
57+
Long hstsMaxAge
58+
59+
/**
60+
* Include subdomains in HSTS
61+
*/
62+
@Value('${wave.security.http-headers.hsts.include-sub-domains:true}')
63+
Boolean hstsIncludeSubDomains
64+
65+
/**
66+
* X-Frame-Options header value (default: `DENY`)
67+
*/
68+
@Nullable
69+
@Value('${wave.security.http-headers.frame-options}')
70+
String frameOptions
71+
72+
/**
73+
* X-Content-Type-Options header value
74+
*/
75+
@Nullable
76+
@Value('${wave.security.http-headers.content-type-options}')
77+
String contentTypeOptions
78+
79+
/**
80+
* Referrer-Policy header value
81+
*/
82+
@Nullable
83+
@Value('${wave.security.http-headers.referrer-policy}')
84+
String referrerPolicy
85+
86+
/**
87+
* Permissions-Policy header value
88+
*/
89+
@Nullable
90+
@Value('${wave.security.http-headers.permissions-policy}')
91+
String permissionsPolicy
92+
93+
/**
94+
* Content-Security-Policy header value
95+
*/
96+
@Nullable
97+
@Value('${wave.security.http-headers.content-security-policy}')
98+
String contentSecurityPolicy
99+
100+
@PostConstruct
101+
private void init() {
102+
log.info("Security headers config: enabled=${enabled}; hsts-max-age=${hstsMaxAge}; hsts-include-sub-domains=${hstsIncludeSubDomains}; " +
103+
"frame-options=${frameOptions}; content-type-options=${contentTypeOptions}; referrer-policy=${referrerPolicy}; " +
104+
"permissions-policy=${permissionsPolicy}; csp=${contentSecurityPolicy}")
105+
}
106+
107+
/**
108+
* Build the HSTS header value
109+
*/
110+
String getHstsValue() {
111+
if (hstsMaxAge == null) {
112+
return null
113+
}
114+
final result = new StringBuilder("max-age=${hstsMaxAge}")
115+
if (hstsIncludeSubDomains) {
116+
result.append("; includeSubDomains")
117+
}
118+
return result.toString()
119+
}
120+
}

src/main/groovy/io/seqera/wave/filter/FilterOrder.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ package io.seqera.wave.filter
2727
*/
2828
interface FilterOrder {
2929

30+
final int SECURITY_HEADERS = -120
3031
final int DENY_CRAWLER = -110
3132
final int DENY_PATHS = -100
3233
final int RATE_LIMITER = -50
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Wave, containers provisioning service
3+
* Copyright (c) 2023-2024, Seqera Labs
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
package io.seqera.wave.filter
20+
21+
import groovy.transform.CompileStatic
22+
import groovy.util.logging.Slf4j
23+
import io.micronaut.context.annotation.Requires
24+
import io.micronaut.core.order.Ordered
25+
import io.micronaut.http.HttpResponse
26+
import io.micronaut.http.MutableHttpResponse
27+
import io.micronaut.http.annotation.ResponseFilter
28+
import io.micronaut.http.annotation.ServerFilter
29+
import io.seqera.wave.configuration.SecurityHeadersConfig
30+
import jakarta.inject.Inject
31+
import static io.micronaut.http.annotation.ServerFilter.MATCH_ALL_PATTERN
32+
33+
/**
34+
* HTTP filter to add security headers to all responses
35+
*
36+
* @author Munish Chouhan <[email protected]>
37+
*/
38+
@Slf4j
39+
@CompileStatic
40+
@ServerFilter(MATCH_ALL_PATTERN)
41+
@Requires(property = 'wave.security.http-headers.enabled', value = 'true', defaultValue = 'true')
42+
class SecurityHeadersFilter implements Ordered {
43+
44+
@Inject
45+
private SecurityHeadersConfig config
46+
47+
@Override
48+
int getOrder() {
49+
return FilterOrder.SECURITY_HEADERS
50+
}
51+
52+
@ResponseFilter
53+
void responseFilter(HttpResponse<?> response) {
54+
if (response instanceof MutableHttpResponse) {
55+
addSecurityHeaders((MutableHttpResponse<?>) response)
56+
}
57+
}
58+
59+
/**
60+
* Add security headers to the HTTP response
61+
*
62+
* @param response The mutable HTTP response to add headers to
63+
*/
64+
protected void addSecurityHeaders(MutableHttpResponse<?> response) {
65+
// Add HSTS header
66+
final hstsValue = config.getHstsValue()
67+
if (hstsValue) {
68+
response.header('Strict-Transport-Security', hstsValue)
69+
}
70+
71+
// Add X-Frame-Options
72+
if (config.frameOptions) {
73+
response.header('X-Frame-Options', config.frameOptions)
74+
}
75+
76+
// Add X-Content-Type-Options
77+
if (config.contentTypeOptions) {
78+
response.header('X-Content-Type-Options', config.contentTypeOptions)
79+
}
80+
81+
// Add Referrer-Policy
82+
if (config.referrerPolicy) {
83+
response.header('Referrer-Policy', config.referrerPolicy)
84+
}
85+
86+
// Add Permissions-Policy
87+
if (config.permissionsPolicy) {
88+
response.header('Permissions-Policy', config.permissionsPolicy)
89+
}
90+
91+
// Add Content-Security-Policy
92+
if (config.contentSecurityPolicy) {
93+
response.header('Content-Security-Policy', config.contentSecurityPolicy)
94+
}
95+
96+
log.trace "Added security headers to response"
97+
}
98+
}

src/main/groovy/io/seqera/wave/redis/JedisPoolMetricsBinder.groovy

Lines changed: 0 additions & 60 deletions
This file was deleted.

0 commit comments

Comments
 (0)