-
Notifications
You must be signed in to change notification settings - Fork 8
Support v1beta2 licenses #3141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
crdant
wants to merge
53
commits into
main
Choose a base branch
from
feature/crdant/supports-license-v1beta2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Support v1beta2 licenses #3141
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Creates comprehensive test fixtures for KOTS license validation testing as part of implementing v1beta2 license support using TDD methodology. These fixtures enable testing before implementation. Fixtures include: - license-v1beta1.yaml: Valid v1beta1 license for backward compatibility testing - license-v1beta2.yaml: Valid v1beta2 license with signature v2 format - license-v1beta2-missing-appslug.yaml: Invalid license missing required appSlug - license-v1beta2-no-ec-enabled.yaml: Invalid license with EC disabled - license-invalid-version.yaml: Invalid license with unsupported v1beta3 version These fixtures will be used in upcoming tests for license validation, version detection, and error handling before implementing the actual license helper functions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Updates kotskinds dependency to include LicenseWrapper support for handling both v1beta1 and v1beta2 License CRDs. This enables version-agnostic license parsing required for supporting multiple license API versions. Also includes transitive dependency updates to controller-runtime v0.22.3 and protobuf v1.36.8. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Updates test fixtures to use simpler entitlement structure that matches the format used in actual KOTS licenses, making tests more realistic and easier to maintain. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Adds comprehensive test coverage for ParseLicense() and ParseLicenseFromBytes() with both v1beta1 and v1beta2 license formats. Tests verify: - Version detection (IsV1/IsV2) - Common field access through LicenseWrapper - Error handling for invalid versions and malformed YAML - File-based and byte-based parsing These tests drive the implementation changes in the next commit (TDD red phase). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…support Updates ParseLicense() to return licensewrapper.LicenseWrapper instead of *kotsv1beta1.License, enabling version-agnostic handling of both v1beta1 and v1beta2 licenses. Changes: - ParseLicense() now returns LicenseWrapper with version detection - New ParseLicenseFromBytes() for parsing from byte arrays - Leverages kotskinds licensewrapper.LoadLicenseFromBytes() for automatic version detection and unified access patterns This completes Phase 1 of the v1beta2 license migration (TDD green phase). All tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…bstraction Updates the metrics reporter to use the LicenseWrapper type instead of direct *kotsv1beta1.License pointers. This change supports the multi-version license abstraction layer, allowing the metrics system to work with both v1beta1 and v1beta2 licenses through a unified interface. Changes: - LicenseID() now accepts LicenseWrapper and uses GetLicenseID() method - License() now returns LicenseWrapper instead of *kotsv1beta1.License - Removed nil checks as empty wrapper is safer than nil pointer 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…n license support Migrates the installer CLI commands to use LicenseWrapper instead of direct *kotsv1beta1.License pointers. This enables the installer to work with both v1beta1 and v1beta2 license formats through a unified abstraction layer. Changes to install.go: - installConfig.license field now uses LicenseWrapper type - getLicenseFromFilepath() returns LicenseWrapper - All license field accesses updated to use wrapper methods (GetLicenseID, GetAppSlug, GetChannelID, GetChannelName, etc.) - checkChannelExistence() accepts LicenseWrapper parameter - maybePromptForAppUpdate() uses wrapper methods for license checks - printSuccessMessage() updated to work with LicenseWrapper Changes to release.go: - getCurrentAppChannelRelease() accepts LicenseWrapper parameter - License ID access updated to use GetLicenseID() method Note: This commit still has 2 compilation errors remaining that require Phase 4 changes to addons.InstallOptions and kubeutils.RecordInstallationOptions structs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…e abstraction Updates core package types to use licensewrapper.LicenseWrapper instead of *kotsv1beta1.License to support multiple license API versions (v1beta1 and v1beta2). Changes: - pkg/addons: Updates InstallOptions and KubernetesInstallOptions License field - pkg/kubeutils: Updates RecordInstallationOptions License field and calls to wrapper methods (IsDisasterRecoverySupported(), IsEmbeddedClusterMultiNodeEnabled()) This enables transparent handling of both v1beta1 and v1beta2 licenses throughout the addon installation and Kubernetes utility layers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…lti-version support Completes the migration to licensewrapper.LicenseWrapper in infrastructure managers, enabling support for both v1beta1 and v1beta2 license API versions. Changes: - api/internal/managers/kubernetes/infra: Updates all internal functions to accept LicenseWrapper, switches to helpers.ParseLicenseFromBytes() for parsing, updates field accesses to use wrapper methods - api/internal/managers/linux/infra: Updates all internal functions to accept LicenseWrapper, switches to helpers.ParseLicenseFromBytes() for parsing, updates field accesses to use wrapper methods Result: Project now compiles successfully with full LicenseWrapper support across all major components (CLI, metrics, packages, and managers). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…ion support This commit refactors the template engine and related components to use LicenseWrapper, enabling support for both v1beta1 and v1beta2 license formats: - Template engine now accepts LicenseWrapper instead of concrete v1beta1 License type - All license field access goes through wrapper methods (GetAppSlug, GetLicenseID, IsSnapshotSupported, etc.) - App config and release managers updated to accept LicenseWrapper parameters - Install controller now uses helpers.ParseLicenseFromBytes for license parsing - Added comprehensive tests with wrapper helpers for both v1beta1 and v1beta2 - Tests verify backward compatibility with v1beta1 while supporting v1beta2 This change maintains backward compatibility while enabling the system to work with both license versions through the abstraction layer. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…e support Updates installer CLI test files to work with the LicenseWrapper abstraction introduced in previous refactoring commits. Changes include: - Wraps v1beta1 license objects in LicenseWrapper before passing to updated functions (maybePromptForAppUpdate, getCurrentAppChannelRelease) - Adds required apiVersion and kind headers to all test license YAML strings to satisfy licensewrapper.LoadLicenseFromPath validation requirements - Imports licensewrapper package in both test files These changes ensure all CLI tests pass with the new multi-version license support while maintaining existing test coverage and behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…er compatibility After code review, several test files needed updates to provide proper Kubernetes resource format (with apiVersion and kind) for license test data, as licensewrapper.LoadLicenseFromBytes() requires these fields. Changes: - api/internal/managers/app/install/install_test.go: Use proper YAML format - pkg/kubeutils/installation_test.go: Wrap licenses in LicenseWrapper with proper closing braces - Other test files: Minor formatting improvements All tests now pass successfully.
Integration tests were creating inline license fixtures without proper Kubernetes resource headers. licensewrapper.LoadLicenseFromBytes() requires apiVersion and kind fields for version detection. Fixed both linux and kubernetes install test fixtures to include: - apiVersion: kots.io/v1beta1 - kind: License This ensures integration tests work with the new LicenseWrapper abstraction. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Removes the unused sigs.k8s.io/yaml import that is no longer needed after migrating to LicenseWrapper. The kyaml package was previously used for unmarshaling license data, but this is now handled by the licensewrapper.LoadLicenseFromBytes() function. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Updates the install and upgrade infrastructure managers to use LicenseWrapper methods instead of directly accessing license Spec fields. Key changes: - install.go: Fixes IsDisasterRecoverySupported() method call (was missing parentheses, treating it as a field instead of a method) - upgrade.go: Migrates from kyaml.Unmarshal to LoadLicenseFromBytes() for license parsing, and updates all license field access to use wrapper methods (GetLicenseID(), IsDisasterRecoverySupported(), IsEmbeddedClusterMultiNodeEnabled()) This ensures the infrastructure layer works correctly with both v1beta1 and v1beta2 license formats through the unified wrapper interface. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
… access Updates the template engine to work correctly with LicenseWrapper: - Changes nil checks from checking the wrapper directly to using GetLicenseID() == "" to determine if license data is present - Updates channel access to use GetChannels() and GetChannelName() wrapper methods instead of direct Spec.Channels access - Removes unnecessary error returns from licenseFieldValue() for consistency with string return type - Adds missing closing brace in license_test.go - Wraps test licenses in ChannelName tests to match production usage These changes ensure templates work with both v1beta1 and v1beta2 licenses through the unified wrapper interface. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…ntly
Updates the install and upgrade CLI commands to use LicenseWrapper getter
methods and properly handle entitlement values:
install.go:
- Fixes metrics reporter to use GetLicenseID() and GetAppSlug() instead of
accessing Spec fields directly
- Fixes addon install options to use installCfg.license instead of
flags.license for consistency
- Fixes expires_at entitlement parsing to properly extract string value
using type assertion on Value() interface{} result instead of accessing
StrVal field directly
upgrade.go:
- Updates license field type from *kotsv1beta1.License to
licensewrapper.LicenseWrapper
- Updates metrics reporter to use GetLicenseID() and GetAppSlug() wrapper
methods
These changes complete the CLI migration to LicenseWrapper, enabling support
for both v1beta1 and v1beta2 license formats.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
… calls
When Engine has no license, e.license is a zero-value LicenseWrapper{V1: nil, V2: nil}.
Calling GetLicenseID() on this would panic with nil pointer dereference.
Changed to check e.license.V1 == nil && e.license.V2 == nil directly before accessing.
LicenseFieldValue now returns empty string instead of error when license or release data is missing. This is more consistent with template behavior where missing data results in empty strings rather than template errors. Updated test expectations: - TestEngine_LicenseFieldValueWithoutLicense: expect empty string - TestEngine_LicenseFieldValue_EndpointWithoutReleaseData: expect empty string
Restore the original behavior where LicenseFieldValue returns an error when the license is nil, rather than silently returning an empty string. This maintains backward compatibility with existing code that may depend on error handling for missing licenses. Changes: - Update licenseFieldValue() to return (string, error) instead of string - Return explicit errors when license or release data is nil - Update tests to expect errors instead of empty strings This follows the fail-fast principle where missing critical data should produce explicit errors rather than silently propagating empty values. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Fix the expires_at entitlement access to properly use the LicenseWrapper
API. The EntitlementField.GetValue() returns an EntitlementValue by value,
and we need to call Value() on it to get the underlying interface{} value.
Changes:
- Get EntitlementValue from EntitlementField using GetValue()
- Call Value() method to extract the underlying value
- Properly type assert to string before parsing the expiration date
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
…ts-license-v1beta2
|
This PR has been released (on staging) and is available for download with a embedded-cluster-smoke-test-staging-app license ID. Online Installer: Airgap Installer (may take a few minutes before the airgap bundle is built): Happy debugging! |
This commit fixes test failures after merging main by:
1. Updating error message expectations in CLI tests to match the new
LicenseWrapper error format ("failed to parse license file" instead
of "failed to parse the license file")
2. Adding missing licenseID fields to all test license YAML fixtures
in Test_verifyLicense, which are now required for the LicenseWrapper
to recognize licenses as valid (licenses without IDs were being
treated as missing licenses)
3. Removing malformed test cases from pkg/helpers/parse_test.go that
had duplicate field definitions and wrong field types, which were
preventing compilation
All affected tests now pass:
- Test_verifyLicense: All 13 test cases passing ✅
- Test_buildInstallConfig_License: All 6 test cases passing ✅
- pkg/helpers parsing tests: All test cases passing ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
Updates TestSetupInfra to use complete Kubernetes object format for license data. The licensewrapper.LoadLicenseFromBytes() function requires a proper Kubernetes object with apiVersion and kind fields. This fixes all 9 TestSetupInfra test cases that were failing with: "Object 'Kind' is missing in spec: licenseID: test-license" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
emosbaugh
requested changes
Oct 31, 2025
Convert `licensewrapper.LicenseWrapper` from value-based to pointer-based passing throughout the embedded-cluster codebase for better ergonomics. Phase 1: Core Type Changes - Updated `ParseLicense` and `ParseLicenseFromBytes` in pkg/helpers/parse.go to return `*licensewrapper.LicenseWrapper` instead of value - Changed error returns from empty struct to nil - Updated `LicenseID` and `License` functions in pkg/metrics/reporter.go to use pointer types with proper nil checks - All tests updated and passing Phase 2: API Client - Updated `Client` interface `SyncLicense` method to return pointer - Converted `client` struct `license` field to pointer type - Updated `NewClient` constructor to accept pointer - Added nil checks before accessing license methods - Updated all test cases to use pointer types - All tests passing Rationale: Maintains consistency with historical patterns where the team has always used pointer types for license structs (*kotsv1beta1.License). This improves team ergonomics and developer experience. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Complete conversion of `licensewrapper.LicenseWrapper` from value-based to pointer-based passing across CLI, template engine, managers, and utilities. Phase 3: CLI Commands - Updated `installConfig` and `upgradeConfig` structs to use pointer license - Converted `verifyLicense`, `checkChannelExistence`, `maybePromptForAppUpdate`, and `printSuccessMessage` functions to use pointers - Updated `newReplicatedAPIClient`, `syncLicense`, and `getCurrentAppChannelRelease` - Added nil checks before accessing license methods - All function signatures now consistently use `*licensewrapper.LicenseWrapper` Phase 4: Template Engine - Updated `Engine` struct license field to pointer type - Converted `WithLicense` option function to accept pointer - Added nil checks in all license accessor methods: - `LicenseAppSlug`, `LicenseID`, `LicenseIsEmbeddedClusterDownloadEnabled` - `licenseFieldValue`, `licenseDockerCfg`, `channelName` - Ensures template rendering handles nil licenses gracefully Phase 5: Infrastructure Managers - Updated `recordInstallation`, `installAddOns`, and `initInstallComponentsList` in both Kubernetes and Linux infra managers - Converted function signatures to use pointer types - Maintains compatibility with updated option structs Phase 6: App Managers - Updated `appConfigManager` and `appReleaseManager` structs - Converted `WithLicense` option functions in both managers to use pointers - Ensures compatibility with template engine pointer types Phase 7: Kubernetes Utilities - Updated `RecordInstallationOptions`, `InstallOptions`, and `KubernetesInstallOptions` structs - Changed `License` fields to pointer types - Maintains consistency across all option passing patterns All builds successful. Core tests passing. Ready for comprehensive validation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Completes Phase 8 of the LicenseWrapper pointer conversion by fixing
test files to use pointer-based LicenseWrapper instead of value-based.
Changes:
- Updated test helper functions to return *licensewrapper.LicenseWrapper
- wrapLicense() in api/pkg/template/license_test.go
- wrapLicenseForExecuteTests() in api/pkg/template/execute_test.go
- Fixed struct literals to use pointer syntax:
- Changed `licensewrapper.LicenseWrapper{...}` to `&licensewrapper.LicenseWrapper{...}`
- Updated in: install_test.go, release_test.go, install_test.go (linux), installation_test.go
- Fixed function calls where LoadLicenseFromBytes() returns value type:
- Changed `WithLicense(wrapper)` to `WithLicense(&wrapper)` in license_test.go:643
All core package tests now pass:
- pkg/helpers/
- pkg/metrics/
- pkg-new/replicatedapi/
- api/pkg/template/
- pkg/addons/
Build verification completed successfully for installer and local-artifact-mirror.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
Fixes two issues in cmd/installer/cli/install_test.go: - Line 559: Change variable declaration from value type to pointer type (var license licensewrapper.LicenseWrapper -> var license *licensewrapper.LicenseWrapper) - Line 984: Update test assertion to check for nil instead of calling method on nil pointer (assert.Empty(license.GetLicenseID()) -> assert.Nil(license)) These fixes resolve compilation errors and nil pointer dereference panics in test cases where no license is provided, completing the LicenseWrapper pointer conversion refactor. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Adds X-Replicated-License-Version header to reporting info to distinguish between v1beta1 and v1beta2 licenses when syncing with the Replicated API. Changes: - reporting.go: Add license version header (v1beta1 or v1beta2) based on the license wrapper's version - client_test.go: Add comprehensive test coverage for license version reporting with both v1beta1 and v1beta2 licenses This enables the Replicated API to track which license version is being used by embedded clusters for better analytics and support. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Adds the X-Replicated-License-Version header to license sync requests when using v1beta2 licenses. This allows the Replicated API to distinguish between v1beta1 and v1beta2 license formats. Changes: - Add header injection in injectHeaders() for v1beta2 licenses only - Update tests to validate header presence for v1beta2 and absence for v1beta1 - Add new test case for v1beta2 license sync requests The header is set to "v1beta2" only when license.IsV2() returns true. v1beta1 licenses do not include this header. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…ts-license-v1beta2
Embed license YAML test data directly in test files instead of reading from external testdata files. This improves test portability and makes the test data more visible and maintainable. Changes: - pkg/helpers/parse_test.go: Embed license YAML as string constants - api/pkg/template/license_test.go: Embed v1beta1 and v1beta2 license data - Remove os.ReadFile dependencies from both test files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Replaces direct Spec field access with the GetAppSlug() getter method in the error message on line 831. This prevents panic when handling v2 licenses or malformed license structures where Spec may be nil. The comparison on line 829 already correctly uses GetAppSlug(), so this change ensures consistency and safety throughout the verifyLicense function. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Adds defensive nil checks at 7 locations where LicenseWrapper pointers are dereferenced to prevent potential nil pointer panics. These checks follow defense-in-depth security principles by validating the license pointer before use, even in code paths where the license should already be validated. Changes: - cmd/installer/cli/install.go: Added nil check before addon install options configuration (line 680-683) and in KOTS installer closure (line 706-709) - cmd/installer/cli/upgrade.go: Added nil check before metrics reporter initialization (line 127-130) and in license sync condition (line 263) - api/internal/managers/linux/infra/install.go: Added nil checks in initInstallComponentsList (line 76-78) and getAddonInstallOpts (line 299-301) - pkg/kubeutils/installation.go: Added nil check in RecordInstallation (line 136-139) These defensive checks provide additional safety against nil pointer dereferences in the license handling code paths, complementing the earlier changes to use getter methods instead of direct field access. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Updates test assertions to use GetLicenseID() and GetAppSlug() getter methods instead of directly accessing license.Spec fields. This aligns test code with production patterns and ensures tests work correctly with both v1beta1 and v1beta2 license formats. Changes: - Line 649: license.Spec.LicenseID -> license.GetLicenseID() - Line 650: license.Spec.AppSlug -> license.GetAppSlug() This completes Phase 3 of the license v1beta2 support work, ensuring test code follows the same defensive patterns as production code. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…tion Adds defensive nil check for license before creating the metrics reporter in the install command. The verifyAndPrompt function can return successfully with a nil license in certain scenarios (no release and no license), but the subsequent metricsReporter initialization at line 147 attempts to call GetLicenseID() and GetAppSlug() on the potentially nil license pointer. This nil check ensures the license is present before attempting to access its methods, preventing a panic in the no-license-no-release edge case. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Removes the duplicate Test_buildInstallConfig_License test from install_test.go which was causing a vet error for function redeclaration. The canonical version of this test remains in install_config_test.go (line 538) and has been properly updated to use GetLicenseID() and GetAppSlug() getter methods instead of direct Spec field access. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
bdfb9f1 to
02d4ee8
Compare
Updates three test cases to match actual error messages from the license parsing code. The error message is "failed to parse license file" without the article "the", but test expectations incorrectly included it. Fixed test cases: - invalid license file - not YAML - invalid license file - wrong kind - corrupt license file - invalid YAML This resolves test failures where assertions were checking for error messages that didn't match the actual implementation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…ts-license-v1beta2
Updates type signatures to use licensewrapper.LicenseWrapper instead of kotsv1beta1.License after merge from main. This ensures consistency with the v1beta2 license support implementation. Changes: - Update ClientFactory type to accept *licensewrapper.LicenseWrapper - Update dryrun.ReplicatedAPIClient to use *licensewrapper.LicenseWrapper - Use licensewrapper.LoadLicenseFromBytes for parsing license data 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Adds support for v1beta1 and v1beta2 license formats
TL;DR
Implements comprehensive multi-version license support through LicenseWrapper abstraction, enabling customers to use either v1beta1 or v1beta2 license formats interchangeably across all installation, upgrade, and template rendering operations while maintaining full backwards compatibility.
Details
The embedded-cluster codebase previously coupled tightly to the kotsv1beta1.License type, preventing support for newer v1beta2 license formats that include enhanced entitlement structures and metadata. This migration introduces the LicenseWrapper abstraction from kotskinds (commit 174e89c93554), which provides version-agnostic access to license fields and entitlements, allowing the system to transparently handle both license versions without code duplication or conditional logic scattered throughout the codebase.
Architecture Overview
The implementation follows a three-layer approach:
Parsing Layer - Updated
pkg/helpers/parse.goto returnlicensewrapper.LicenseWrapperinstead of rawkotsv1beta1.Licensetypes, withLoadLicenseFromBytes()handling version detection and appropriate struct initialization.Business Logic Layer - Migrated all production code across CLI commands (
cmd/installer/cli/), infrastructure managers (api/internal/managers/), and template engine (api/pkg/template/) to use LicenseWrapper types exclusively, replacing direct struct field access with wrapper methods.API Layer - Replaced direct
.Spec.*field access patterns with wrapper getter methods likeGetAppSlug(),GetLicenseID(),GetChannelName(), andIsEmbeddedClusterMultiNodeEnabled(), ensuring consistent behavior regardless of underlying license version.Key Changes by Component
Parser Infrastructure (pkg/helpers/)
licensewrapper.LicenseWrapperwith automatic version detectionlicensewrapper.LoadLicenseFromBytes()for both v1beta1 and v1beta2 parsingInstaller CLI (cmd/installer/cli/)
*kotsv1beta1.Licensetolicensewrapper.LicenseWrapperin upgradeConfig struct.StrValaccessInfrastructure Managers (api/internal/managers/)
LoadLicenseFromBytes()instead of raw unmarshalingIsDisasterRecoverySupported()andIsEmbeddedClusterMultiNodeEnabled()wrapper methodsTemplate Engine (api/pkg/template/)
licensewrapper.LicenseWrapperinstead of raw license pointerValue()method on entitlement fields, supporting both v1beta1 direct values and v1beta2 structured entitlementsGetChannels(),GetChannelID(), andGetChannelName()methodsV1/V2checks instead of method calls where appropriatePackage-Level Types (pkg/)
Validation and Testing
The implementation includes extensive test coverage:
Test results confirm successful migration:
go build ./....Spec.*license access in production code*kotsv1beta1.Licensetypes in production codeBackwards Compatibility
Existing v1beta1 licenses continue to work without any changes:
Breaking Changes
None. This is a purely internal refactoring that maintains API compatibility:
Impact
Customers can now:
The system maintains:
Dependency Update
Updated kotskinds to commit 174e89c93554 which includes:
Related Documentation
docs/plans/2025-10-31-complete-licensewrapper-migration.mddocs/research/2025-10-31-license-wrapper-remaining-work.mdpkg/helpers/testdata/license-*.yaml🤖 Generated with Claude Code