Skip to content

feat: add passthrough config mechanism for Connect, Package Manager, and Workbench#75

Open
ian-flores wants to merge 3 commits intomainfrom
feat-passthrough-config
Open

feat: add passthrough config mechanism for Connect, Package Manager, and Workbench#75
ian-flores wants to merge 3 commits intomainfrom
feat-passthrough-config

Conversation

@ian-flores
Copy link
Collaborator

Summary

  • Adds escape-hatch passthrough fields to all three product configs (Connect, Package Manager, Workbench) so users can set arbitrary config values without waiting for operator releases
  • Connect & PM: additional map with Section.Key format, passthrough overrides typed fields
  • Workbench: additionalConfigs map with config file name keys, raw content appended per file
  • Site CRD propagation for all three products
  • Fixes pre-existing typo: WorkbenchLauncherKubnernetesResourcesConfigSectionWorkbenchLauncherKubernetesResourcesConfigSection

Motivation

The operator currently defines ~25-33% of each product's config values as typed Go struct fields. Adding a new setting requires modifying 4+ files, running codegen, and releasing a new operator version. This passthrough mechanism lets users set any config value immediately.

Design

Connect & Package Manager (gcfg format)

config:
  Server:
    Address: "typed-value.com"
  additional:
    "Server.DataDir": "/custom/path"
    "NewSection.NewKey": "any-value"
  • Keys use Section.Key format matching gcfg structure
  • Passthrough values override typed fields when both set the same key
  • New sections are created automatically

Workbench (multiple config files)

config:
  additionalConfigs:
    "rserver.conf": |
      session-timeout-minutes=120
      custom-setting=value
    "rsession.conf": |
      r-cran-repos=https://custom.repo.com
  additionalSessionConfigs:
    "repos.conf": |
      CRAN=https://custom.cran.com
  • Keys are config file names
  • Content appended after generated config
  • Per-file approach handles Workbench's multiple formats (INI, DCF, JSON, newline-delimited)

Test plan

  • Connect: passthrough-only, override, empty map, nil, malformed keys, complex scenario (6 tests)
  • Package Manager: new section, override, empty, add to existing, malformed keys, slice override (6 tests)
  • Workbench: append to existing, new file, empty, nil — for both IniConfig and SessionIniConfig (7 tests)
  • All existing tests pass (go test ./api/core/v1beta1/...)
  • envtest integration tests (require local kubebuilder — pre-existing setup gap)
  • Deploy to test cluster and verify config files are generated correctly

…and Workbench

Add escape-hatch passthrough fields to all three product configs so users
can set arbitrary config values without waiting for operator releases.

Connect & Package Manager:
- Add `additional` map[string]string on config structs
- Keys use "Section.Key" format (e.g., "Server.DataDir")
- Passthrough values override typed fields when both are set
- Rewrite GenerateGcfg() to use intermediate representation for merge

Workbench:
- Add `additionalConfigs` map[string]string on WorkbenchIniConfig and
  WorkbenchSessionIniConfig
- Keys are config file names (e.g., "rserver.conf")
- Raw content appended after generated config per file

Site CRD propagation added for all three products.

Also fixes typo: WorkbenchLauncherKubnernetesResourcesConfigSection
→ WorkbenchLauncherKubernetesResourcesConfigSection
@claude
Copy link

claude bot commented Feb 9, 2026

Claude finished @ian-flores's task —— View job


Review Complete

  • Read review guidelines
  • Create pending review
  • Analyze PR diff and changed files
  • Review API changes (Connect, Package Manager, Workbench configs)
  • Review Controller changes
  • Review generated code
  • Submit review

Submitted a review with 2 issues to address:

  1. Non-deterministic map iteration in Connect/PM config generation - sort keys for consistent output
  2. Potential nil pointer dereference in Workbench controller when propagating additional configs

Overall, the passthrough mechanism is well-designed with good test coverage.

Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

This PR implements a well-designed passthrough config mechanism for all three products. The design choices are sound: Section.Key format for gcfg products (Connect/PM) and file-based appending for Workbench's multiple config formats.

Issues to Address

1. Non-deterministic map iteration (Connect & Package Manager)

  • api/core/v1beta1/connect_config.go:310 and api/core/v1beta1/package_manager_config.go:98
  • Iterating over Additional map has non-deterministic ordering in Go
  • When multiple keys target the same new section, their order within that section will vary between runs
  • Suggestion: Sort the keys before processing:
keys := make([]string, 0, len(configStruct.Additional))
for key := range configStruct.Additional {
    keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
    // process
}

2. Potential nil pointer dereference (Workbench controller)

  • internal/controller/core/site_controller_workbench.go:402 and :407
  • If targetWorkbench.Spec.Config.WorkbenchIniConfig or WorkbenchSessionIniConfig is nil, the assignment will panic
  • Suggestion: Add nil guards:
if site.Spec.Workbench.AdditionalConfigs != nil {
    if targetWorkbench.Spec.Config.WorkbenchIniConfig == nil {
        targetWorkbench.Spec.Config.WorkbenchIniConfig = &v1beta1.WorkbenchIniConfig{}
    }
    targetWorkbench.Spec.Config.WorkbenchIniConfig.AdditionalConfigs = site.Spec.Workbench.AdditionalConfigs
}

Positives

  • Good test coverage: Edge cases like malformed keys, empty maps, nil maps, and override scenarios are well tested
  • Typo fix: WorkbenchLauncherKubnernetesResourcesConfigSectionWorkbenchLauncherKubernetesResourcesConfigSection is a good cleanup
  • Consistent naming: AdditionalConfig for single-file products vs AdditionalConfigs/AdditionalSessionConfigs for Workbench makes the behavior clear
  • SplitN(..., 2) approach: Correctly handles multi-dot keys like Good.Section.Key
  • Shared sectionEntry pattern: Well-structured for maintaining key ordering; duplication between Connect/PM is acceptable for now

Notes

  • The Workbench AdditionalConfigs map iteration (workbench_config.go:173) also has non-deterministic order, but since each filename is independent (not affecting order within a file), this is lower priority
  • CRD updates, deepcopy, and client-go generated code all look correct

…lm chart

- Sort Additional map keys before iterating in Connect and PM
  GenerateGcfg() for deterministic output
- Add nil guards for WorkbenchIniConfig and WorkbenchSessionIniConfig
  in site controller before propagating additional configs
- Regenerate Helm chart CRDs to match kustomize
WorkbenchIniConfig and WorkbenchSessionIniConfig are embedded value
types (not pointers) in WorkbenchConfig, so they cannot be nil.
Remove the incorrect nil guards that caused compilation errors.
Also fix formatting flagged by CI.
@statik
Copy link
Collaborator

statik commented Feb 11, 2026

thanks for creating this! we have long felt the pain of needing this escape hatch. I think this would unblock @brendanhcullen, who needs support for setting Connect OAuth2.RegisterOnFirstLogin = false on academy training sites.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants