Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": "go.sum|package-lock.json|^.secrets.baseline$",
"lines": null
},
"generated_at": "2025-11-28T15:02:26Z",
"generated_at": "2025-12-02T13:23:17Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -118,7 +118,7 @@
"hashed_secret": "03e60e3e0d9675b19754e2a81bbb48a26af858e7",
"is_secret": false,
"is_verified": false,
"line_number": 943,
"line_number": 950,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down
1 change: 1 addition & 0 deletions cloudinfo/catalog_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type CatalogJson struct {
Configuration []struct {
Key string `json:"key"`
Type string `json:"type"`
TypeMetadata string `json:"type_metadata"`
Description string `json:"description"`
DefaultValue interface{} `json:"default_value"`
Required bool `json:"required"`
Expand Down
13 changes: 10 additions & 3 deletions cloudinfo/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ func (infoSvc *CloudInfoService) GetConfigAndDependenciesStates(configDetails *C
return states, nil
}

// IsDeployable checks if a config and all its members are deployable. If any one memeber is deployable, return true.
// IsDeployable checks if a config and all its members are deployable. If any one member is deployable, return true.
// trackStackInputs tracks inputs that should not be overridden.
// This function initializes a map of inputs that should be preserved in the stack configuration.
func trackStackInputs(stackConfig *ConfigDetails) map[string]map[string]interface{} {
Expand Down Expand Up @@ -873,10 +873,17 @@ func validateCatalogInputsInStackDefinition(stackJson Stack, catalogConfig Catal
for _, stackInput := range stackJson.Inputs {
if catalogInput.Key == stackInput.Name {
found = true
expectedType := convertGoTypeToExpectedType(stackInput.Type)
if !isValidType(catalogInput.Type, expectedType) {
expectedType := stackInput.Type
if expectedType == "" {
expectedType = stackInput.TypeMetadata
}
expectedType = convertGoTypeToExpectedType(expectedType)
if catalogInput.Type != "" && !isValidType(catalogInput.Type, expectedType) {
typeMismatches = append(typeMismatches, fmt.Sprintf("catalog configuration type mismatch in product '%s', flavor '%s': %s expected type: %s, got: %s", productName, flavorName, catalogInput.Key, expectedType, catalogInput.Type))
}
if catalogInput.TypeMetadata != "" && !isValidType(catalogInput.TypeMetadata, expectedType) {
typeMismatches = append(typeMismatches, fmt.Sprintf("catalog configuration type_metadata mismatch in product '%s', flavor '%s': %s expected type: %s, got: %s", productName, flavorName, catalogInput.Key, expectedType, catalogInput.TypeMetadata))
}
// Check if the default value type matches the expected type
if catalogInput.DefaultValue != nil {
defaultValueType := reflect.TypeOf(catalogInput.DefaultValue).String()
Expand Down
12 changes: 12 additions & 0 deletions cloudinfo/projects_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,18 @@ func (suite *ProjectsServiceTestSuite) TestCreateStackFromConfigFile() {
"catalog configuration type mismatch in product 'Product Name', flavor 'Flavor Name': input3 expected type: array, got: bool\n" +
"catalog configuration type mismatch in product 'Product Name', flavor 'Flavor Name': input4 expected type: bool, got: array"),
},
{
name: "catalog input type_metadata mismatch, should return an error",
stackConfig: &ConfigDetails{
ProjectID: "mockProjectID",
ConfigID: "54321",
},
stackConfigPath: "testdata/stack_definition_with_type_metadata_only.json",
catalogJsonPath: "testdata/ibm_catalog_with_type_metadata_only.json",
expectedConfig: nil,
expectedError: fmt.Errorf("catalog configuration type_metadata mismatch in product 'Product Name', flavor 'Flavor Name': input5 expected type: string, got: int\n" +
Copy link
Contributor

@whoffler whoffler Dec 2, 2025

Choose a reason for hiding this comment

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

Should this read

"catalog configuration type_metadata mismatch in product 'Product Name', flavor 'Flavor Name': input5 expected type: int, got: string\n"

?

Copy link
Member Author

Choose a reason for hiding this comment

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

expectedType is string from stack definition and catalog catalogInput.TypeMetadata is int, so this should be correct!

stack def-

  "inputs": [
    {
      "name": "input5",
      "required": false,
      "type_metadata": "string",
      "hidden": false,
      "default": "stack_value_5"
    },

catalog val-

          "configuration": [
            {
              "key": "input5",
              "type_metadata": "int",
              "description": "Description for input5",
              "default_value": "default_value_5",
              "required": false,
              "display_name": "Input 5"
            },

"catalog configuration type_metadata mismatch in product 'Product Name', flavor 'Flavor Name': input6 expected type: string, got: bool"),
Copy link
Contributor

Choose a reason for hiding this comment

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

And this

"catalog configuration type_metadata mismatch in product 'Product Name', flavor 'Flavor Name': input6 expected type: bool, got: string"),

?

Copy link
Member Author

Choose a reason for hiding this comment

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

here also

stack def-

    {
      "name": "input6",
      "required": false,
      "type_metadata": "string",
      "hidden": false,
      "default": "stack_value_6"
    },

catalog val-

            {
              "key": "input6",
              "type_metadata": "bool",
              "description": "Description for input6",
              "default_value": "",
              "required": false,
              "display_name": "Input 6"
            },

},
{
// This is checking the type of the actual default value
name: "catalog input default type mismatch, should return an error",
Expand Down
13 changes: 7 additions & 6 deletions cloudinfo/projects_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import (

type Stack struct {
Inputs []struct {
Name string `json:"name"`
Description string `json:"description"`
Required bool `json:"required"`
Type string `json:"type"`
Hidden bool `json:"hidden"`
Default interface{} `json:"default"`
Name string `json:"name"`
Description string `json:"description"`
Required bool `json:"required"`
Type string `json:"type"`
TypeMetadata string `json:"type_metadata"`
Hidden bool `json:"hidden"`
Default interface{} `json:"default"`
} `json:"inputs"`
Outputs []struct {
Name string `json:"name"`
Expand Down
96 changes: 96 additions & 0 deletions cloudinfo/testdata/ibm_catalog_with_type_metadata_only.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{
"products": [
{
"label": "Product Label",
"name": "Product Name",
"product_kind": "Product Kind",
"tags": ["tag1", "tag2"],
"keywords": ["keyword1", "keyword2"],
"short_description": "Short description",
"long_description": "Long description",
"offering_docs_url": "http://example.com/docs",
"offering_icon_url": "http://example.com/icon",
"provider_name": "Provider Name",
"features": [
{
"title": "Feature Title",
"description": "Feature Description"
}
],
"support_details": "Support details",
"flavors": [
{
"label": "Flavor Label",
"name": "Flavor Name",
"working_directory": "Working Directory",
"compliance": {
"authority": "Authority",
"profiles": [
{
"profile_name": "Profile Name",
"profile_version": "Profile Version"
}
]
},
"iam_permissions": [
{
"service_name": "Service Name",
"role_crns": ["crn1", "crn2"]
}
],
"architecture": {
"features": [
{
"title": "Architecture Feature Title",
"description": "Architecture Feature Description"
}
],
"diagrams": [
{
"diagram": {
"url": "http://example.com/diagram",
"caption": "Diagram Caption",
"type": "Diagram Type",
"thumbnail_url": "http://example.com/thumbnail"
},
"description": "Diagram Description"
}
]
},
"configuration": [
{
"key": "input5",
"type_metadata": "int",
"description": "Description for input5",
"default_value": "default_value_5",
"required": false,
"display_name": "Input 5"
},
{
"key": "input6",
"type_metadata": "bool",
"description": "Description for input6",
"default_value": "",
"required": false,
"display_name": "Input 6"
},
{
"key": "input7",
"description": "Description for input7",
"default_value": "some_value",
"required": false,
"display_name": "Input 7"
}
],
"outputs": [
{
"key": "output1",
"description": "Description for output1"
}
],
"install_type": "Install Type"
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"inputs": [
{
"name": "input5",
"required": false,
"type_metadata": "string",
"hidden": false,
"default": "stack_value_5"
},
{
"name": "input6",
"required": false,
"type_metadata": "string",
"hidden": false,
"default": "stack_value_6"
},
{
"name": "input7",
"required": false,
"type_metadata": "string",
"hidden": false,
"default": "stack_value_7"
}
],
"outputs": [
{
"name": "output1",
"value": "ref:../members/member1/outputs/output1"
}
],
"members": [
{
"inputs": [
{
"name": "input5",
"value": "ref:../../inputs/input5"
}
],
"name": "member1",
"version_locator": "version1"
}
]
}