Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
331c082
Refactor debug framework to parse yaml config
kiril-keranov Feb 10, 2026
8420be7
Add YamlHandler thin wrapper
kiril-keranov Feb 10, 2026
3d11f1f
Overlay JBP_CONFIG over default values
kiril-keranov Feb 10, 2026
34338f1
Try validating fields
kiril-keranov Feb 10, 2026
350f3c8
Try warning on field validation
kiril-keranov Feb 10, 2026
da6996f
Adjust print err
kiril-keranov Feb 11, 2026
e72ec55
Refactor frameworks that have enabled config option
kiril-keranov Feb 11, 2026
30c0cc0
Adjust luna framework + refactoring
kiril-keranov Feb 11, 2026
fc9e7f9
Fix issue
kiril-keranov Feb 11, 2026
93be3dd
Add validations + refactoring
kiril-keranov Feb 11, 2026
2d1d045
Adjust validation
kiril-keranov Feb 11, 2026
fd1b8d3
Adjust jrebel and jma frameworks with the missing props
kiril-keranov Feb 12, 2026
637ec9b
Adjust google stack drive and sealights frameworks
kiril-keranov Feb 12, 2026
4277f8f
Fix framework and tests
kiril-keranov Feb 13, 2026
4d85b49
Add config and refactor jprofiler frmrk
kiril-keranov Feb 13, 2026
edba3dc
Fix jprofiler agent options
kiril-keranov Feb 13, 2026
b921f2d
Debug log
kiril-keranov Feb 13, 2026
a29983f
Adjust info log
kiril-keranov Feb 13, 2026
614d4cc
Try fixing nowait
kiril-keranov Feb 13, 2026
156bccb
Fix nowait for jprofiler
kiril-keranov Feb 13, 2026
8616ee1
Fix jma argument property
kiril-keranov Feb 13, 2026
9715ea1
Fix jmathresholds + typos
kiril-keranov Feb 16, 2026
3f4e022
Fix jma properties
kiril-keranov Feb 16, 2026
12df9f4
Add enabled config for aspectj weaver agent frmrk
kiril-keranov Feb 16, 2026
f223464
Adjust adding non-empty thresholds
kiril-keranov Feb 16, 2026
ccc7e59
Fix typo
kiril-keranov Feb 16, 2026
af00e57
Fix typos in comments
kiril-keranov Feb 16, 2026
e740bdb
Fix inconsistent naming
kiril-keranov Feb 16, 2026
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
6 changes: 3 additions & 3 deletions src/integration/frameworks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ func testFrameworks(platform switchblade.Platform, fixtures string) func(*testin
deployment, logs, err := platform.Deploy.
WithEnv(map[string]string{
"BP_JAVA_VERSION": "11",
"JBP_CONFIG_CLIENT_CERTIFICATE_MAPPER": "'{enabled: true}'",
"JBP_CONFIG_CLIENT_CERTIFICATE_MAPPER": "{ enabled: true }",
}).
Execute(name, filepath.Join(fixtures, "containers", "tomcat"))
Expect(err).NotTo(HaveOccurred(), logs.String)
Expand All @@ -550,7 +550,7 @@ func testFrameworks(platform switchblade.Platform, fixtures string) func(*testin
deployment, logs, err := platform.Deploy.
WithEnv(map[string]string{
"BP_JAVA_VERSION": "11",
"JBP_CONFIG_CLIENT_CERTIFICATE_MAPPER": "'{enabled: false}'",
"JBP_CONFIG_CLIENT_CERTIFICATE_MAPPER": "{ enabled: false }",
}).
Execute(name, filepath.Join(fixtures, "containers", "tomcat"))
Expect(err).NotTo(HaveOccurred(), logs.String)
Expand Down Expand Up @@ -851,7 +851,7 @@ func testFrameworks(platform switchblade.Platform, fixtures string) func(*testin
deployment, logs, err := platform.Deploy.
WithEnv(map[string]string{
"BP_JAVA_VERSION": "11",
"JBP_CONFIG_JPROFILER_PROFILER": "'{enabled: true}'",
"JBP_CONFIG_JPROFILER_PROFILER": "{ enabled: true }",
}).
Execute(name, filepath.Join(fixtures, "containers", "spring_boot_staged"))
Expect(err).NotTo(HaveOccurred(), logs.String)
Expand Down
3 changes: 1 addition & 2 deletions src/java/common/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ package common
import (
"encoding/json"
"fmt"
"github.com/cloudfoundry/libbuildpack"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/cloudfoundry/libbuildpack"
)

// Context holds shared dependencies for buildpack components
Expand Down
26 changes: 26 additions & 0 deletions src/java/common/yaml_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package common

import (
"bytes"
"go.yaml.in/yaml/v3"
)

// YamlHandler provides a thin wrapper around yaml.v3's Marshal and Unmarshal.
type YamlHandler struct{}

// Unmarshal decodes the YAML data into the provided destination.
func (h YamlHandler) Unmarshal(data []byte, out any) error {
return yaml.Unmarshal(data, out)
}

// Marshal encodes the given value into YAML.
func (h YamlHandler) Marshal(in any) ([]byte, error) {
return yaml.Marshal(in)
}

// ValidateFields is used to detect unknown fields during parsing of JBP_CONFIG* configurations
func (h YamlHandler) ValidateFields(data []byte, out interface{}) error {
dec := yaml.NewDecoder(bytes.NewReader(data))
dec.KnownFields(true)
return dec.Decode(out)
}
40 changes: 39 additions & 1 deletion src/java/frameworks/aspectj_weaver_agent.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package frameworks

import (
"github.com/cloudfoundry/java-buildpack/src/java/common"
"fmt"
"github.com/cloudfoundry/java-buildpack/src/java/common"
"os"
"path/filepath"
"strings"
Expand All @@ -22,6 +22,15 @@ func NewAspectJWeaverAgentFramework(ctx *common.Context) *AspectJWeaverAgentFram

// Detect determines if AspectJ Weaver JAR and configuration exist in the application
func (a *AspectJWeaverAgentFramework) Detect() (string, error) {
config, err := a.loadConfig()
if err != nil {
a.context.Log.Warning("Failed to load aspectj weaver agent config: %s", err.Error())
return "", nil // Don't fail the build
}

if !config.isEnabled() {
return "", nil
}
// Look for aspectjweaver-*.jar in the application
aspectjJar, err := a.findAspectJWeaver()
if err != nil || aspectjJar == "" {
Expand Down Expand Up @@ -127,3 +136,32 @@ func (a *AspectJWeaverAgentFramework) findAspectJWeaver() (string, error) {

return "", nil
}

func (a *AspectJWeaverAgentFramework) loadConfig() (*aspectjWeaverConfig, error) {
// initialize default values
ajwConfig := aspectjWeaverConfig{
Enabled: true,
}
config := os.Getenv("JBP_CONFIG_ASPECTJ_WEAVER_AGENT")
if config != "" {
yamlHandler := common.YamlHandler{}
err := yamlHandler.ValidateFields([]byte(config), &ajwConfig)
if err != nil {
a.context.Log.Warning("Unknown user config values: %s", err.Error())
}
// overlay JBP_CONFIG_ASPECTJ_WEAVER_AGENT over default values
if err = yamlHandler.Unmarshal([]byte(config), &ajwConfig); err != nil {
return nil, fmt.Errorf("failed to parse JBP_CONFIG_ASPECTJ_WEAVER_AGENT: %w", err)
}
}
return &ajwConfig, nil
}

type aspectjWeaverConfig struct {
Enabled bool `yaml:"enabled"`
}

// isEnabled checks if aspectj weaver agent is enabled
func (a *aspectjWeaverConfig) isEnabled() bool {
return a.Enabled
}
46 changes: 29 additions & 17 deletions src/java/frameworks/client_certificate_mapper.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package frameworks

import (
"github.com/cloudfoundry/java-buildpack/src/java/common"
"fmt"
"github.com/cloudfoundry/java-buildpack/src/java/common"
"os"
"path/filepath"
)
Expand All @@ -23,7 +23,13 @@ func NewClientCertificateMapperFramework(ctx *common.Context) *ClientCertificate
// Enabled by default to support mTLS scenarios, can be disabled via configuration
func (c *ClientCertificateMapperFramework) Detect() (string, error) {
// Check if explicitly disabled via configuration
if !c.isEnabled() {
config, err := c.loadConfig()
if err != nil {
c.context.Log.Warning("Failed to load client certificate mapper config: %s", err.Error())
return "", nil // Don't fail the build
}

if !config.isEnabled() {
return "", nil
}

Expand Down Expand Up @@ -77,25 +83,31 @@ func (c *ClientCertificateMapperFramework) Finalize() error {
return nil
}

// isEnabled checks if client certificate mapper is enabled
// Default is true (enabled) to support mTLS scenarios unless explicitly disabled
func (c *ClientCertificateMapperFramework) isEnabled() bool {
// Check JBP_CONFIG_CLIENT_CERTIFICATE_MAPPER environment variable
func (c *ClientCertificateMapperFramework) loadConfig() (*clientCertificateMapperConfig, error) {
// initialize default values
mapperConfig := clientCertificateMapperConfig{
Enabled: true,
}
config := os.Getenv("JBP_CONFIG_CLIENT_CERTIFICATE_MAPPER")

// Parse the config to check for enabled: false
// For simplicity, if JBP_CONFIG_CLIENT_CERTIFICATE_MAPPER is set and contains "enabled", check its value
// A more robust implementation would parse YAML
if config != "" {
// Simple check: if it contains "enabled: false" or "'enabled': false"
if contains(config, "enabled: false") || contains(config, "'enabled': false") {
return false
yamlHandler := common.YamlHandler{}
err := yamlHandler.ValidateFields([]byte(config), &mapperConfig)
if err != nil {
c.context.Log.Warning("Unknown user config values: %s", err.Error())
}
if contains(config, "enabled: true") || contains(config, "'enabled': true") {
return true
// overlay JBP_CONFIG_CLIENT_CERTIFICATE_MAPPER over default values
if err = yamlHandler.Unmarshal([]byte(config), &mapperConfig); err != nil {
return nil, fmt.Errorf("failed to parse JBP_CONFIG_CLIENT_CERTIFICATE_MAPPER: %w", err)
}
}
return &mapperConfig, nil
}

// Default to enabled (to support mTLS client certificate authentication)
return true
type clientCertificateMapperConfig struct {
Enabled bool `yaml:"enabled"`
}

// isEnabled checks if client certificate mapper is enabled
func (c *clientCertificateMapperConfig) isEnabled() bool {
return c.Enabled
}
64 changes: 31 additions & 33 deletions src/java/frameworks/container_security_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,17 @@ func (c *ContainerSecurityProviderFramework) Finalize() error {
return fmt.Errorf("failed to write security properties: %w", err)
}

config, err := c.loadConfig()
if err != nil {
c.context.Log.Warning("Failed to load container security provider config: %s", err.Error())
}
// Add key manager and trust manager configuration if specified
keyManagerEnabled := c.getKeyManagerEnabled()
keyManagerEnabled := config.getKeyManagerEnabled()
if keyManagerEnabled != "" {
javaOpts += fmt.Sprintf(" -Dorg.cloudfoundry.security.keymanager.enabled=%s", keyManagerEnabled)
}

trustManagerEnabled := c.getTrustManagerEnabled()
trustManagerEnabled := config.getTrustManagerEnabled()
if trustManagerEnabled != "" {
javaOpts += fmt.Sprintf(" -Dorg.cloudfoundry.security.trustmanager.enabled=%s", trustManagerEnabled)
}
Expand Down Expand Up @@ -214,44 +218,38 @@ func (c *ContainerSecurityProviderFramework) getDefaultSecurityProviders() []str
}
}

// getKeyManagerEnabled returns the key_manager_enabled configuration value
func (c *ContainerSecurityProviderFramework) getKeyManagerEnabled() string {
config := os.Getenv("JBP_CONFIG_CONTAINER_SECURITY_PROVIDER")
if config == "" {
return ""
func (c *ContainerSecurityProviderFramework) loadConfig() (*containerSecurityProviderConfig, error) {
// initialize default values
secConfig := containerSecurityProviderConfig{
KeyManagerEnabled: "",
TrustManagerEnabled: "",
}

// Parse configuration for key_manager_enabled
// Format: {key_manager_enabled: true} or {'key_manager_enabled': 'true'}
if contains(config, "key_manager_enabled") {
if contains(config, "true") {
return "true"
config := os.Getenv("JBP_CONFIG_CONTAINER_SECURITY_PROVIDER")
if config != "" {
yamlHandler := common.YamlHandler{}
err := yamlHandler.ValidateFields([]byte(config), &secConfig)
if err != nil {
c.context.Log.Warning("Unknown user config values: %s", err.Error())
}
if contains(config, "false") {
return "false"
// overlay JBP_CONFIG_CONTAINER_SECURITY_PROVIDER over default values
if err = yamlHandler.Unmarshal([]byte(config), &secConfig); err != nil {
return nil, fmt.Errorf("failed to parse JBP_CONFIG_CONTAINER_SECURITY_PROVIDER: %w", err)
}
}
return &secConfig, nil
}

return ""
// getKeyManagerEnabled returns the key_manager_enabled configuration value
func (c *containerSecurityProviderConfig) getKeyManagerEnabled() string {
return c.KeyManagerEnabled
}

// getTrustManagerEnabled returns the trust_manager_enabled configuration value
func (c *ContainerSecurityProviderFramework) getTrustManagerEnabled() string {
config := os.Getenv("JBP_CONFIG_CONTAINER_SECURITY_PROVIDER")
if config == "" {
return ""
}

// Parse configuration for trust_manager_enabled
// Format: {trust_manager_enabled: true} or {'trust_manager_enabled': 'true'}
if contains(config, "trust_manager_enabled") {
if contains(config, "true") {
return "true"
}
if contains(config, "false") {
return "false"
}
}
func (c *containerSecurityProviderConfig) getTrustManagerEnabled() string {
return c.TrustManagerEnabled
}

return ""
type containerSecurityProviderConfig struct {
KeyManagerEnabled string `yaml:"key_manager_enabled"`
TrustManagerEnabled string `yaml:"trust_manager_enabled"`
}
Loading