Skip to content

fix(catalog): check shell compatibility range during module selection - #213

Open
kavix wants to merge 5 commits into
wso2:mainfrom
kavix:fix/catalog-shell-compatibility
Open

kavix wants to merge 5 commits into
wso2:mainfrom
kavix:fix/catalog-shell-compatibility

Conversation

@kavix

@kavix kavix commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes an issue where wso2 product install <product> installed a module version whose declared shell compatibility range is not satisfied by the running shell, causing failures only when subsequently executing the module.

Closes #160

Changes

  1. Pre-install Shell Range Validation in internal/catalog/select.go:

    • During Select(), evaluates version.Compatibility.Shell against the current shell semver using semver.ParseRange.
    • If unsatisfied, skips the candidate and evaluates older published versions.
    • If no compatible version is found across the channel, returns an incompatibleShell diagnostic error (modules.incompatible_shell, Exit 69 ModuleTrust) naming both the required range and the running shell version, with recovery: Update the module or the WSO2 CLI so the shell version is supported.
    • This refusal is clearly distinguished from protocol negotiation errors (protocolMismatch, Exit 69 ModuleTrust).
  2. Compatibility Verification for Installed Modules (internal/modules/resolve.go & internal/install/update.go):

    • Added (Receipt).CheckCompatibility(ShellIdentity) validating protocol, shell range, and platform.
    • Installer.statuses checks installed modules using receipt.CheckCompatibility(i.Shell) and flags Status.Incompatible.
  3. Status Reporting in wso2 product list (internal/app/module.go):

    • Modules with incompatible shells are marked as incompatible in the update column rather than reporting current.
    • When an update is published for an incompatible module, UPDATE reflects both states: vX.Y.Z available (incompatible).
    • The summary reflects incompatible products (N product(s) incompatible with this shell and cannot be launched. Reinstall the product or update the WSO2 CLI so a compatible version is installed.) and inhibits reporting Every installed product is current. when any installed module is incompatible.
  4. Documentation:

    • Updated docs/reference/module-manifest.md, docs/guides/troubleshoot-module.md, docs/reference/commands.md, docs/reference/module-catalog.md, and docs/adr/0006-monorepo-modules-and-generated-catalog.md to reflect that the gate is protocol ∩ shell range ∩ platform.

@coderabbitai

coderabbitai Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 835b6e17-2f8e-4196-8ecc-70e7a41bfe68

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Needs a closer look

It changes the core module-selection gate that governs install behavior across the catalog, modules, install, and app layers, which warrants final human review.

Pull request overview

This PR closes the gap described in issue #160, where wso2 module install accepted a module version whose declared compatibility.shell range the running shell does not satisfy — install succeeded, module list reported it current, and it only failed at launch. The fix moves the shell-range check earlier so it is enforced at catalog selection (before anything is written) as well as at launch, mirroring how the protocol gate already works, and it surfaces incompatible installed modules in module list.

Changes:

  • internal/catalog/select.go: filters selectable versions by whether the declared shell range contains the shell's version, falling back to older satisfying versions and returning a distinct modules.incompatible_shell (exit 69) refusal with a shell-update recovery when none qualify.
  • internal/modules/resolve.go + internal/install/update.go: adds Receipt.CheckCompatibility (protocol, shell range, platform, in launch-gate order) and a Status.Incompatible flag computed for installed modules.
  • internal/app/module.go: adds a stateIncompatible classification so the update column shows incompatible and the summary no longer calls an unlaunchable module current; docs and tests updated accordingly.
File summaries
File Description
internal/catalog/select.go Adds the pre-install shell-range gate and the incompatibleShell diagnostic.
internal/catalog/select_test.go Unit tests for refusal, protocol/shell distinction, and older-version fallback.
internal/modules/resolve.go Adds Receipt.CheckCompatibility mirroring the launch gate order.
internal/modules/resolve_test.go Tests each incompatibility code returned by CheckCompatibility.
internal/install/update.go Adds Status.Incompatible and computes it in statuses.
internal/install/update_test.go Verifies an out-of-range installed module is flagged incompatible.
internal/app/module.go Adds stateIncompatible to the column/summary classification.
internal/app/module_internal_test.go Covers incompatible cases in summary/column agreement tests.
internal/app/module_test.go End-to-end product list incompatible-not-current test.
test/acceptance/moduleinstall_test.go Acceptance tests pinning refusal and older-version selection.
test/acceptance/acceptance_test.go Adds buildShellVersioned helper.
test/acceptance/catalog_fixture_test.go Adds per-tag shellRanges override.
docs/reference/module-manifest.md, docs/guides/troubleshoot-module.md Reflect that the shell range is now checked at selection.
Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/catalog/select.go

@kanushka kanushka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, this covers all five acceptance criteria in #160 and the tests are solid. A few things to address before merge; inline comments cover the code. Not anchorable inline:

  • Stale gate docs: internal/devorigin/devorigin.go:221 says the shell range is "checked only when the module is launched", and docs/reference/module-catalog.md:27, docs/adr/0006-monorepo-modules-and-generated-catalog.md:44 and test/acceptance/moduleinstall_test.go:231 still say the gate is protocol ∩ platform "and nothing else". Please update them to protocol ∩ shell range ∩ platform, keeping the point that the module's own version is never compared.
  • docs/reference/commands.md (Module inventory): the example and UPDATE column description don't mention the new incompatible value or its summary line.
  • PR description: the command is wso2 product list now, not wso2 module list.

Comment thread internal/catalog/select.go Outdated
Comment thread internal/install/update.go Outdated
Comment thread internal/catalog/select.go Outdated
Comment thread internal/app/module.go
Comment thread internal/catalog/select.go Outdated
Comment thread internal/catalog/select_test.go Outdated
@kavix
kavix requested a review from kanushka September 19, 2026 01:44
@kavix

kavix commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

@kanushka can u review this when u had a chance?

@kanushka

Copy link
Copy Markdown
Contributor

Before merging, could you please:

  • run gofmt on internal/catalog/select_test.go;
  • update docs/architecture.md so catalog selection includes the shell compatibility range;
  • align stateOf with the documented behavior. An incompatible pinned product currently appears only as pinned. If update availability should take precedence, please document and test that exception.

@kanushka kanushka left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

stateOf ranks a pin above incompatibility, contrary to its comment.

Comment thread internal/app/module.go Outdated
Comment on lines 618 to 622
// stateOf classifies one module. The order matters: a module that is not
// installed has no pin or installed version for the rest to be about, and a
// pin overrides the channel (catalog.Policy documents that), so those two are
// installed has no pin or installed version for the rest to be about, an
// incompatible module cannot be launched regardless of channel or pin, and a
// pin overrides the channel (catalog.Policy documents that), so those are
// asked about first.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The comment says an incompatible module "cannot be launched regardless of channel or pin" and is asked about first, but the switch checks Pinned and Update before Incompatible. A pinned, incompatible module shows pinned to vX in the online module list and is counted as pinned in the summary, while moduleListOffline shows incompatible. Could Incompatible move above Pinned (with its precedence against Update settled), or the comment and docs be corrected?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed: moved Incompatible above Pinned while keeping Update first (so an updatable module surfaces the update command that resolves compatibility, while an un-updatable pinned module is properly flagged as incompatible and cannot be launched). Updated the doc comment, tests, and documentation accordingly.

kavix added 4 commits October 10, 2026 14:56
Refuses module versions whose declared shell compatibility range is not satisfied by the running shell before downloading or installing artifacts. Falls back to older versions published in the catalog that satisfy the shell range. Marks incompatible installed modules as 'incompatible' in 'wso2 module list' rather than reporting them as 'current'.

Closes wso2#160
…ity over pin

Signed-off-by: kavix <kavix@yahoo.com>
@kavix
kavix force-pushed the fix/catalog-shell-compatibility branch from 82b768b to dfbff13 Compare October 10, 2026 09:28
@kavix

kavix commented Oct 10, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @kanushka! Updated the branch with all requested changes:

  • Rebased onto latest main and resolved documentation merge conflicts cleanly.
  • Updated stateOf precedence: placed Incompatible above Pinned while keeping Update first, updated its doc comment, and added corresponding unit and CLI integration tests.
  • Updated docs/architecture.md to include the shell compatibility range during catalog selection.
  • Ran gofmt on test files.

@kavix
kavix requested a review from kanushka October 10, 2026 09:31

@kanushka kanushka left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, this covers all five acceptance criteria in #160 and the stateOf precedence is fixed. Remaining before merge:

  • Update offered, then refused. Status.Update comes from the index alone and doesn't check whether the newer version is compatible. stateOf puts Update above Incompatible, so product list can show "v0.2.0 available … run wso2 product update" for a module whose v0.2.0 is also out of range, and product update then fails with modules.incompatible_shell. Either only set Update when the newer version passes the gate, or show both states. Whichever you choose, please document it in docs/reference/commands.md (the exception isn't documented yet).
  • The summary remedy is wrong in some cases (internal/app/module.go:690-692). Incompatible comes from CheckCompatibility (protocol, shell range, platform), but the summary always says "Update the WSO2 CLI". That's wrong when the CLI is too new for the module, or when the platform doesn't match (launch says reinstall for this OS/arch). Please word it so it covers all three cases, and name the command to run.
  • Stale wording:
    • internal/devorigin/devorigin.go:242 still says "it would install and then refuse to launch". So do the comments at Makefile:179 and around 218. After this PR, install refuses first.
    • The negotiateProtocol doc comment in resolve.go still says the gate is protocol ∩ platform.
  • Doc example order: in commands.md the example shows the pinned line before the incompatible line, but the code emits incompatible first.

Nits:

  • The len(quoted)==0 fallback in select.go can never be reached.
  • checkShellCompatibility has no doc comment.
  • The PR body says the protocol refusal exits with 70, but it uses ModuleTrust (69).

… wording, and stale docs

Signed-off-by: kavix <kavix@yahoo.com>
@kavix
kavix requested a review from kanushka October 12, 2026 15:39
@kavix

kavix commented Oct 12, 2026

Copy link
Copy Markdown
Contributor Author

@kanushka all review comments have been addressed and tested in 4559980.

This branch has not been deployed

No deployments
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.

wso2 module install accepts a module whose declared shell range this shell does not satisfy

3 participants