# E2E Issues Found

## Bugs Fixed

### BUG-001: `upgrade --dry-run` fails with "Release not found" (CRITICAL)
- **Severity**: High
- **Test**: P6-001 through P6-006
- **Description**: All `upgrade --dry-run` commands failed with `ILUM-023: Release 'ilum' not found` even though the release existed and was deployed.
- **Root Cause**: `HelmClient._run()` had a blanket dry-run shortcut (lines 81-87 of `helm.py`) that returned a fake `HelmResult` with `json_data=None` for ALL commands, including read-only queries like `helm list` and `helm get values`. When `list_releases()` returned no data, `release_exists()` returned `False`, causing `plan_upgrade()` to raise `ReleaseNotFoundError`.
- **Fix**: Added `read_only: bool = False` parameter to `_run()`. Read-only methods (`list_releases`, `get_values`, `history`, `get_values_all`, `search_repo`, `repo_add`, `repo_update`, `version`) now pass `read_only=True` to bypass the dry-run shortcut and execute against the real cluster.
- **File**: `src/ilum/core/helm.py`

### BUG-002: `upgrade --values /nonexistent.yaml` silently succeeds
- **Severity**: Medium
- **Test**: P6-007
- **Description**: Passing a nonexistent values file to `upgrade` did not produce an error. The file was silently ignored, and the command reported "Nothing to upgrade."
- **Root Cause**: Neither `upgrade_cmd.py` nor `install_cmd.py` validated that `--values` files exist before proceeding with the operation.
- **Fix**: Added early validation in both `upgrade_cmd.py` and `install_cmd.py` that checks `vf.exists()` for each values file and raises `ConfigError(error_code="ILUM-030")` if missing.
- **Files**: `src/ilum/cli/upgrade_cmd.py`, `src/ilum/cli/install_cmd.py`

### BUG-003: `airgap images` crashes with `TypeError: unhashable type: 'list'`
- **Severity**: High
- **Test**: P8-006 through P8-009
- **Description**: All `airgap images` commands crashed with a traceback. The error occurred in `_discover_images()` which passed a `list[str]` to `resolver.resolve_enables()` that expects a single `str`.
- **Root Cause**: `_discover_images()` called `resolver.resolve_enables(modules)` with the full module list instead of iterating over each module name individually.
- **Fix**: Changed to iterate: `for mod_name in modules: enable_flags.extend(resolver.resolve_enables(mod_name))`.
- **File**: `src/ilum/cli/airgap_cmd.py`

### BUG-004: `helm template` uses invalid release name `.`
- **Severity**: Medium
- **Test**: P8-006
- **Description**: After fixing BUG-003, `airgap images` still failed because `HelmClient.template()` used `.` as the release name in `helm template . <chart>`, which is invalid in Helm v3.20+.
- **Root Cause**: The `.` release name doesn't match the regex `^([-a-z0-9]*)?(\.([-a-z0-9]*)?)*$` required by newer Helm versions.
- **Fix**: Changed the release name from `.` to `ilum-template` in the `template()` method.
- **File**: `src/ilum/core/helm.py`

### BUG-005: `doctor -o json` outputs Rich table mixed with JSON
- **Severity**: Medium
- **Test**: P11-004
- **Description**: Running `ilum doctor -o json` produced both a Rich-formatted table AND JSON output to stdout, making the JSON unparseable by tools like `jq` or `python -m json.tool`.
- **Root Cause**: `DoctorRunner.run_all()` always called `self._render(results)` which outputs the Rich table, regardless of the requested output format. The JSON formatter then appended clean JSON after the table.
- **Fix**: Added `render: bool = True` parameter to `run_all()`. When the output format is JSON or YAML, `doctor_cmd.py` now calls `run_all(render=False)` to suppress the table, producing clean machine-readable output.
- **Files**: `src/ilum/doctor/runner.py`, `src/ilum/cli/doctor_cmd.py`

## UX Issues Noted

### UX-001: No drift warning after external helm change
- **Severity**: Medium
- **Test**: P6-010
- **Description**: After making a direct `helm upgrade` change (injecting drift), `ilum upgrade --dry-run` did not show a drift warning. This is expected behavior when no previous CLI snapshot exists to compare against (the CLI needs at least one prior CLI-initiated operation to establish a baseline for drift detection).

### UX-002: `uninstall` succeeds silently on non-existent release
- **Severity**: Low
- **Test**: P9-002
- **Description**: Running `ilum uninstall --yes` when no release exists returns exit code 0 instead of failing or warning. Not harmful but could confuse scripts checking exit codes.

## Security Checks Passed

- SEC-001: `status` output does not contain `CHANGEMEPLEASE` (P4-020)
- SEC-002: `logs` output does not contain `CHANGEMEPLEASE` (P4-021)
- SEC-003: Audit log does not contain default password placeholders (P8-023)
- SEC-004: Config file permissions are 600 (owner-only read/write) (P7-010)
- SEC-005: Snapshot directory has restrictive owner permissions (P8-024)

## Performance Results

- `module list`: ~650ms (well under 10s threshold)
- `status`: ~1,030ms (well under 30s threshold)

## Test Coverage Summary

| Phase | Tests | Passed | Description |
|-------|-------|--------|-------------|
| 0 | 7 | 7 | Environment Validation |
| 1 | 36 | 36 | Read-Only Commands |
| 2 | 25 | 25 | Init & Config Init |
| 3 | 7 | 7 | Connect |
| 4 | 23 | 23 | Status/Info Commands |
| 5 | 13 | 13 | Module Enable/Disable |
| 6 | 11 | 11 | Upgrade & Configuration |
| 7 | 10 | 10 | Config Management Deep |
| 8 | 27 | 27 | Advanced Scenarios |
| 9 | 5 | 5 | Uninstall/Cleanup |
| 10 | 11 | 11 | Full Lifecycle Regression |
| 11 | 35 | 35 | Dependency Detection, Cluster Lifecycle & Quickstart |
| **Total** | **210** | **210** | |
