Skip to content

config new --push: schema validation checks parameters shape but POST sends body unwrapped as configuration #605

Description

@MichalProchazkaP3

Summary

kbagent config new --component-id <c> --push --no-files --configuration-file body.json validates body.json against the component's configSchema as if body.json is configuration.parameters, but the actual Storage API POST sends body.json verbatim as the whole configuration object — without wrapping it in a parameters key.

For components whose configSchema describes parameters (e.g. kds-team.app-custom-python), this means:

  • A correctly nested body ({"storage": {...}, "parameters": {venv, source, code, ...}}) fails schema validation.
  • An incorrectly flattened body ({venv, source, code, ...} sitting at the JSON root, no parameters wrapper) passes validation and gets created — producing a live configuration that Keboola's UI/runtime can't read (it looks for configuration.parameters.*), silently falling back to a blank/default template. No error is ever raised; --push reports success.

Environment

  • kbagent v0.79.0 (installed via the uv tool path, keboola-cli package)
  • Windows 11

Steps to reproduce

  1. Dry-run with a correctly nested body:

    {
      "storage": {},
      "parameters": {
        "venv": "3.13",
        "source": "code",
        "code": "print(1)",
        "packages": [],
        "user_properties": {}
      }
    }
    kbagent config new --component-id kds-team.app-custom-python --name "Test" \
      --project <alias> --push --no-files --configuration-file body.json --dry-run
    

    → fails:

    ✗ Schema validation failed:
      • <root>: 'venv' is a required property
      • <root>: 'user_properties' is a required property
      • <root>: 'source' is a required property
    
  2. Remove the storage/parameters wrapper so venv/source/code/packages/user_properties sit directly at the JSON root → validation passes, --push (without --dry-run) succeeds and returns a created config id.

  3. kbagent config detail --project <alias> --component-id kds-team.app-custom-python --config-id <id> → the returned configuration has no parameters key at all; venv/code/etc. sit directly under configuration.

  4. Opening that config in the Keboola UI shows the component's default boilerplate (Python 3.14, default print(ci.configuration.parameters) sample code, empty packages) instead of the pushed content, because the UI/runtime reads configuration.parameters.*, which is empty.

Root cause (traced in the installed package)

  • keboola_agent_cli/services/config_service.py::_validate_config_body (called from create_config) validates the caller-supplied body directly against the component's AI-Service JSON schema, which describes the shape of configuration.parameters — so it expects venv/source/user_properties/etc. at the root of whatever is passed in.
  • keboola_agent_cli/services/config_service.py::create_configkeboola_agent_cli/client/configs.py::create_config sends that same body verbatim as the Storage API's configuration field:
    data: dict[str, Any] = {
        "name": name,
        "description": description,
        "configuration": json.dumps(configuration),
    }
    with no wrapping into {"parameters": ...}.

The two code paths disagree about what "the body" represents (bare parameters vs. the full configuration object), so there is no single body shape that is simultaneously schema-valid and correct for the real Storage API contract.

Suggested fix

Pick one contract and make both paths agree, e.g.:

  • Treat --configuration/--configuration-file as the full configuration object ({storage, parameters}) consistently, and validate only its .parameters sub-object against the component schema; or
  • Treat it as parameters-only consistently, and have create_config/client.create_config wrap it as {"parameters": body} (merging in any storage passed separately) before POSTing.

At minimum, validate the actual outgoing Storage API payload (post-transform) against the schema rather than the raw CLI input, so a mismatch between "what gets validated" and "what gets sent" can't silently pass.

Impact

Silent config-shape corruption: --push reports success and config detail looks superficially fine (it's just missing a parameters key, easy to overlook), but the resulting configuration is non-functional in the Keboola UI and would presumably fail at runtime too, since components read ci.configuration.parameters.


Found while building a kds-team.app-custom-python extractor config with kbagent as part of an AI-assisted workflow (Claude Code).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions