qualys-cli 0.3.0__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/CHANGELOG.md +9 -0
  2. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/PKG-INFO +1 -1
  3. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/pyproject.toml +1 -1
  4. qualys_cli-0.3.1/src/qualys_cli/__init__.py +1 -0
  5. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/_docs/usage.html +2 -2
  6. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/extras.py +17 -11
  7. qualys_cli-0.3.1/tests/test_completion.py +61 -0
  8. qualys_cli-0.3.0/src/qualys_cli/__init__.py +0 -1
  9. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/.gitignore +0 -0
  10. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/LICENSE +0 -0
  11. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/README.md +0 -0
  12. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/__main__.py +0 -0
  13. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/audit.py +0 -0
  14. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/auth.py +0 -0
  15. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/cache.py +0 -0
  16. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/cli.py +0 -0
  17. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/client.py +0 -0
  18. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/__init__.py +0 -0
  19. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/asset.py +0 -0
  20. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/ca.py +0 -0
  21. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/cs.py +0 -0
  22. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/csam.py +0 -0
  23. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/edr.py +0 -0
  24. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/etm.py +0 -0
  25. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/fim.py +0 -0
  26. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/pc.py +0 -0
  27. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/pm.py +0 -0
  28. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/scanauth.py +0 -0
  29. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/sub.py +0 -0
  30. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/tc.py +0 -0
  31. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/user.py +0 -0
  32. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/vm.py +0 -0
  33. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/commands/was.py +0 -0
  34. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/config.py +0 -0
  35. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/detection_stats.py +0 -0
  36. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/flair.py +0 -0
  37. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/formatters.py +0 -0
  38. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/history.py +0 -0
  39. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/http_server.py +0 -0
  40. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/mcp_server.py +0 -0
  41. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/metrics.py +0 -0
  42. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/platforms.py +0 -0
  43. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/src/qualys_cli/queries.py +0 -0
  44. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/__init__.py +0 -0
  45. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/conftest.py +0 -0
  46. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_agent_mode.py +0 -0
  47. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_all_commands_smoke.py +0 -0
  48. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_asset.py +0 -0
  49. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_asset_tags.py +0 -0
  50. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_audit.py +0 -0
  51. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_ca.py +0 -0
  52. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_client.py +0 -0
  53. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_csam.py +0 -0
  54. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_detection_stats.py +0 -0
  55. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_detection_stats_cmd.py +0 -0
  56. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_error_handling.py +0 -0
  57. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_etm.py +0 -0
  58. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_features.py +0 -0
  59. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_fim_edr.py +0 -0
  60. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_flair.py +0 -0
  61. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_formatters.py +0 -0
  62. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_global_flags.py +0 -0
  63. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_help.py +0 -0
  64. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_high_fixes.py +0 -0
  65. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_isolation.py +0 -0
  66. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_kcs_mitigation.py +0 -0
  67. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_kev.py +0 -0
  68. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_main.py +0 -0
  69. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_mcp_live.py +0 -0
  70. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_med_fixes.py +0 -0
  71. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_pc.py +0 -0
  72. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_pm.py +0 -0
  73. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_resiliency.py +0 -0
  74. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_review_fixes.py +0 -0
  75. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_scanauth.py +0 -0
  76. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_security_fixes.py +0 -0
  77. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_sub.py +0 -0
  78. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_tc.py +0 -0
  79. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_user.py +0 -0
  80. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_vm.py +0 -0
  81. {qualys_cli-0.3.0 → qualys_cli-0.3.1}/tests/test_was.py +0 -0
@@ -6,6 +6,15 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.1] — 2026-11-04
10
+
11
+ ### Fixed
12
+ - `qualys-cli completion <shell>` printed only a "Tip:" line instead of the
13
+ completion script, so shell tab completion could not be set up. It asked
14
+ Typer for the script with Click's env-var format (`zsh_source`) instead of
15
+ Typer's (`source_zsh`); the script is now generated in-process. Workaround
16
+ for 0.3.0: `_QUALYS_CLI_COMPLETE=source_zsh qualys-cli > <fpath-dir>/_qualys-cli`.
17
+
9
18
  ## [0.3.0] — 2026-11-03
10
19
 
11
20
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: qualys-cli
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Unified command-line interface for the Qualys Cloud Platform REST APIs (VM, PC, PM, ETM, WAS, TotalCloud, Cloud Agent, Container Security, CSAM, Subscription, Asset, and User management).
5
5
  Project-URL: Homepage, https://www.qualys.com
6
6
  Author-email: Qualys <support@qualys.com>
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "qualys-cli"
7
- version = "0.3.0"
7
+ version = "0.3.1"
8
8
  description = "Unified command-line interface for the Qualys Cloud Platform REST APIs (VM, PC, PM, ETM, WAS, TotalCloud, Cloud Agent, Container Security, CSAM, Subscription, Asset, and User management)."
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  license = { file = "LICENSE" }
@@ -0,0 +1 @@
1
+ __version__ = "0.3.1"
@@ -612,7 +612,7 @@ body.filtering.no-match section.module{display:none}
612
612
  <aside class="sidebar" aria-label="Documentation navigation">
613
613
  <div class="side-header">
614
614
  <img src="https://ik.imagekit.io/qualys/image/logo/qualys.svg" alt="Qualys">
615
- <span class="ver">v0.3.0</span>
615
+ <span class="ver">v0.3.1</span>
616
616
  </div>
617
617
  <div class="side-search">
618
618
  <input type="search" id="filter" placeholder="Search commands…"
@@ -696,7 +696,7 @@ body.filtering.no-match section.module{display:none}
696
696
  <div class="hero-stats">
697
697
  <div class="hero-stat"><span class="n">28</span><span class="l">Modules</span></div>
698
698
  <div class="hero-stat"><span class="n">271</span><span class="l">Commands</span></div>
699
- <div class="hero-stat"><span class="n">v0.3.0</span><span class="l">Version</span></div>
699
+ <div class="hero-stat"><span class="n">v0.3.1</span><span class="l">Version</span></div>
700
700
  <div class="hero-stat"><span class="n">3.12+</span><span class="l">Python</span></div>
701
701
  <div class="hero-stat"><span class="n">MIT</span><span class="l">License</span></div>
702
702
  </div>
@@ -603,23 +603,29 @@ completion_app = typer.Typer(invoke_without_command=False, help="Print a shell-c
603
603
  def completion(
604
604
  shell: str = typer.Argument("bash", help="bash | zsh | fish | powershell"),
605
605
  ) -> None:
606
- """Print the completion script for *shell* to stdout — eval / source it."""
606
+ """Print the completion script for *shell* to stdout — eval / source it.
607
+
608
+ zsh: qualys-cli completion zsh > ~/.oh-my-zsh/custom/completions/_qualys-cli
609
+ bash: eval "$(qualys-cli completion bash)"
610
+ """
611
+ # Defined in typer._completion_shared; typer.completion only re-exports it
612
+ # implicitly, which strict mypy (no_implicit_reexport) rejects.
613
+ from typer._completion_shared import get_completion_script
614
+
607
615
  shell = shell.lower()
608
616
  valid = {"bash", "zsh", "fish", "powershell"}
609
617
  if shell not in valid:
610
618
  _err.print(f"[bold red]Unsupported shell:[/bold red] {shell}. Choose one of {sorted(valid)}.")
611
619
  raise typer.Exit(2)
612
- env = os.environ | {"_QUALYS_CLI_COMPLETE": f"{shell}_source"}
613
- proc = subprocess.run(
614
- ["qualys-cli"], env=env, capture_output=True, text=True, check=False,
615
- )
616
- sys.stdout.write(proc.stdout)
617
- if proc.returncode != 0:
618
- _err.print(
619
- "[dim]Tip: install the script by piping it into a file in your shell's "
620
- "completions directory. See: https://typer.tiangolo.com/tutorial/options-autocompletion/[/dim]"
620
+ # Generated in-process. The previous implementation re-ran `qualys-cli`
621
+ # with _QUALYS_CLI_COMPLETE=<shell>_source — Click's env format — but
622
+ # Typer expects source_<shell>; it answered "Shell source not supported",
623
+ # so no script was ever printed and tab completion could not be set up.
624
+ sys.stdout.write(
625
+ get_completion_script(
626
+ prog_name="qualys-cli", complete_var="_QUALYS_CLI_COMPLETE", shell=shell,
621
627
  )
622
- raise typer.Exit(proc.returncode)
628
+ )
623
629
 
624
630
 
625
631
  # ---------------------------------------------------------------------------
@@ -0,0 +1,61 @@
1
+ """Shell tab-completion: script generation and the completion engine it calls."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import pytest
6
+ from typer.testing import CliRunner
7
+
8
+ from qualys_cli.cli import app
9
+
10
+ runner = CliRunner()
11
+
12
+
13
+ @pytest.mark.parametrize(
14
+ ("shell", "marker"),
15
+ [
16
+ ("zsh", "#compdef qualys-cli"),
17
+ ("bash", "complete -o"),
18
+ ("fish", "complete --command qualys-cli"),
19
+ ("powershell", "Register-ArgumentCompleter"),
20
+ ],
21
+ )
22
+ def test_completion_prints_script(shell: str, marker: str) -> None:
23
+ result = runner.invoke(app, ["completion", shell])
24
+ assert result.exit_code == 0, result.output
25
+ assert marker in result.stdout
26
+ # The script must call back into the CLI with the matching env var.
27
+ assert "_QUALYS_CLI_COMPLETE" in result.stdout
28
+
29
+
30
+ def test_completion_rejects_unknown_shell() -> None:
31
+ result = runner.invoke(app, ["completion", "tcsh"])
32
+ assert result.exit_code == 2
33
+
34
+
35
+ def _complete(line: str) -> str:
36
+ result = runner.invoke(
37
+ app,
38
+ [],
39
+ prog_name="qualys-cli",
40
+ env={"_QUALYS_CLI_COMPLETE": "complete_zsh", "_TYPER_COMPLETE_ARGS": line},
41
+ )
42
+ assert result.exit_code == 0, result.output
43
+ return result.stdout
44
+
45
+
46
+ def test_completion_engine_lists_modules() -> None:
47
+ out = _complete("qualys-cli ")
48
+ for module in ("vm", "pc", "cs", "etm", "pm", "ca", "was", "csam"):
49
+ assert f'"{module}":' in out
50
+
51
+
52
+ def test_completion_engine_lists_module_resources() -> None:
53
+ out = _complete("qualys-cli cs ")
54
+ for resource in ("image", "k8s-resource", "secret-detector", "qid-list", "tag"):
55
+ assert f'"{resource}":' in out
56
+
57
+
58
+ def test_completion_engine_lists_resource_actions() -> None:
59
+ out = _complete("qualys-cli etm finding ")
60
+ for action in ("list", "get", "count"):
61
+ assert f'"{action}":' in out
@@ -1 +0,0 @@
1
- __version__ = "0.3.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes