vibeguard-cli 1.0.4__tar.gz → 1.0.5__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 (138) hide show
  1. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/CLAUDE.md +6 -0
  2. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/PKG-INFO +1 -1
  3. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/docs/progress.md +53 -14
  4. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/pyproject.toml +1 -1
  5. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/__init__.py +1 -1
  6. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/bootstrap.py +16 -2
  7. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/downloader.py +11 -1
  8. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/__init__.py +4 -0
  9. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/manifests/trivy.toml +14 -4
  10. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/runners/local.py +26 -1
  11. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/.github/workflows/publish.yml +0 -0
  12. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/.github/workflows/vibeguard.yml +0 -0
  13. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/.gitignore +0 -0
  14. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/.vibeguardignore +0 -0
  15. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/CHANGELOG.md +0 -0
  16. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/LICENSE +0 -0
  17. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/README.md +0 -0
  18. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/action.yml +0 -0
  19. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/docs/CI_INTEGRATION.md +0 -0
  20. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/docs/CONTRIBUTING_SCANNERS.md +0 -0
  21. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/docs/context.md +0 -0
  22. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/docs/license.md +0 -0
  23. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/docs/plan.md +0 -0
  24. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/docs/upgrade.md +0 -0
  25. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/__init__.py +0 -0
  26. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/apply.py +0 -0
  27. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/auth_cmd.py +0 -0
  28. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/banners.py +0 -0
  29. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/baseline_cmd.py +0 -0
  30. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/config_cmd.py +0 -0
  31. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/display.py +0 -0
  32. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/doctor.py +0 -0
  33. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/fix.py +0 -0
  34. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/import_cmd.py +0 -0
  35. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/init_cmd.py +0 -0
  36. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/keys.py +0 -0
  37. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/live_cmd.py +0 -0
  38. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/main.py +0 -0
  39. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/patch.py +0 -0
  40. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/report.py +0 -0
  41. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/cli/scan.py +0 -0
  42. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/__init__.py +0 -0
  43. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/auth.py +0 -0
  44. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/baseline.py +0 -0
  45. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/bundles.py +0 -0
  46. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/cache.py +0 -0
  47. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/config.py +0 -0
  48. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/dedup.py +0 -0
  49. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/example_detector.py +0 -0
  50. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/exit_codes.py +0 -0
  51. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/ignore.py +0 -0
  52. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/keyring.py +0 -0
  53. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/license.py +0 -0
  54. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/llm.py +0 -0
  55. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/path_classifier.py +0 -0
  56. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/repo_detector.py +0 -0
  57. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/sarif_import.py +0 -0
  58. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/telemetry.py +0 -0
  59. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/triage.py +0 -0
  60. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/url_validator.py +0 -0
  61. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/core/validate.py +0 -0
  62. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/models/__init__.py +0 -0
  63. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/models/auth.py +0 -0
  64. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/models/baseline.py +0 -0
  65. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/models/finding.py +0 -0
  66. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/models/patch.py +0 -0
  67. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/models/scan_result.py +0 -0
  68. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/models/triage.py +0 -0
  69. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/reporters/__init__.py +0 -0
  70. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/reporters/badge.py +0 -0
  71. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/reporters/html.py +0 -0
  72. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/reporters/sarif.py +0 -0
  73. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/manifests/bandit.toml +0 -0
  74. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/manifests/cargo_audit.toml +0 -0
  75. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/manifests/checkov.toml +0 -0
  76. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/manifests/dockle.toml +0 -0
  77. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/manifests/gitleaks.toml +0 -0
  78. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/manifests/npm_audit.toml +0 -0
  79. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/manifests/nuclei.toml +0 -0
  80. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/manifests/pip_audit.toml +0 -0
  81. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/manifests/semgrep.toml +0 -0
  82. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/manifests/trufflehog.toml +0 -0
  83. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/__init__.py +0 -0
  84. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/bandit.py +0 -0
  85. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/cargo_audit.py +0 -0
  86. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/checkov.py +0 -0
  87. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/dockle.py +0 -0
  88. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/gitleaks.py +0 -0
  89. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/npm_audit.py +0 -0
  90. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/nuclei.py +0 -0
  91. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/pip_audit.py +0 -0
  92. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/semgrep.py +0 -0
  93. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/trivy.py +0 -0
  94. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/parsers/trufflehog.py +0 -0
  95. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/runners/__init__.py +0 -0
  96. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/runners/base.py +0 -0
  97. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/src/vibeguard/scanners/runners/docker.py +0 -0
  98. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/__init__.py +0 -0
  99. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/conftest.py +0 -0
  100. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_apply_cmd.py +0 -0
  101. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_banners.py +0 -0
  102. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_baseline.py +0 -0
  103. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_baseline_cmd.py +0 -0
  104. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_bootstrap.py +0 -0
  105. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_bundles.py +0 -0
  106. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_cache.py +0 -0
  107. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_checkov_parser.py +0 -0
  108. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_ci_mode.py +0 -0
  109. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_cli.py +0 -0
  110. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_dedup.py +0 -0
  111. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_dockle_parser.py +0 -0
  112. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_exit_codes.py +0 -0
  113. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_fix_cmd.py +0 -0
  114. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_keyring.py +0 -0
  115. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_keys_cmd.py +0 -0
  116. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_license.py +0 -0
  117. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_live_cmd.py +0 -0
  118. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_llm.py +0 -0
  119. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_models.py +0 -0
  120. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_nuclei_parser.py +0 -0
  121. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_parsers/__init__.py +0 -0
  122. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_parsers/test_bandit.py +0 -0
  123. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_parsers/test_cargo_audit.py +0 -0
  124. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_parsers/test_gitleaks.py +0 -0
  125. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_parsers/test_npm_audit.py +0 -0
  126. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_parsers/test_pip_audit.py +0 -0
  127. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_parsers/test_semgrep.py +0 -0
  128. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_parsers/test_trivy.py +0 -0
  129. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_parsers/test_trufflehog.py +0 -0
  130. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_patch_cmd.py +0 -0
  131. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_patch_model.py +0 -0
  132. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_repo_detector.py +0 -0
  133. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_reporters/__init__.py +0 -0
  134. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_reporters/test_badge.py +0 -0
  135. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_reporters/test_html.py +0 -0
  136. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_reporters/test_sarif.py +0 -0
  137. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_sarif_import.py +0 -0
  138. {vibeguard_cli-1.0.4 → vibeguard_cli-1.0.5}/tests/test_url_validator.py +0 -0
@@ -168,6 +168,12 @@ Base 100, deductions: Critical -20, High -10, Medium -5, Low -2. Grades: A+ ≥9
168
168
  2. Update this file (CLAUDE.md) if architecture or commands change
169
169
  3. Commit and push to git
170
170
 
171
+ **Versioning & Release:**
172
+ - After each iteration that is pushed live, bump the version by 0.01 (e.g., 1.0.5 → 1.0.6)
173
+ - Version must be updated in BOTH `pyproject.toml` and `src/vibeguard/__init__.py`
174
+ - To release: `git tag v<version> && git push origin v<version>` (triggers CI/CD)
175
+ - CI/CD pipeline: tests → build → publish to PyPI → create GitHub Release
176
+
171
177
  **Planning:**
172
178
  - Implementation plans are stored in `docs/plan.md`
173
179
  - Use plan mode for non-trivial features before implementation
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vibeguard-cli
3
- Version: 1.0.4
3
+ Version: 1.0.5
4
4
  Summary: Unified security scanner orchestrator for local repos
5
5
  Author: VibeGuard Team
6
6
  License: MIT
@@ -1,7 +1,7 @@
1
1
  # VibeGuard CLI - Development Progress
2
2
 
3
3
  ## Current Status
4
- **Phase**: Post-Sprint 6 — Panel Auth Fix
4
+ **Phase**: Post-Sprint 6 — v1.0.5 Scanner Auto-Download + pipx Fix
5
5
  **Last Updated**: 2026-02-06
6
6
 
7
7
  ---
@@ -51,25 +51,64 @@ Full implementation log: `vibeguard-panel/docs/panelplan-implementation.md`
51
51
 
52
52
  **Status**: Backend deployed. Panel changes need Vercel redeploy.
53
53
 
54
- ### PyPI Publication PUBLISHED (2026-02-06)
54
+ ### v1.0.5: Scanner Auto-Download + pipx Fix (2026-02-06)
55
55
 
56
- - [x] **vibeguard-cli 1.0.0 live on PyPI**: https://pypi.org/project/vibeguard-cli/
56
+ **Problem**: Users installing via `pipx` had most scanners skipped. Only Gitleaks and TruffleHog worked (standalone binaries). Semgrep, Bandit, pip-audit, Checkov were pip-installed into pipx's isolated venv but their executables weren't found by the runner. Trivy download failed due to non-standard URL naming.
57
+
58
+ **Fixes:**
59
+ - [x] **Trivy auto-download fixed** — added custom `os_map`/`arch_map` to download config
60
+ - Trivy uses `macOS` not `darwin`, `64bit` not `amd64`, `ARM64` not `arm64`
61
+ - New manifest fields: `[install.download.os_map]` and `[install.download.arch_map]`
62
+ - Updated Trivy version to 0.69.1 (latest)
63
+ - Supported on all platforms: macOS ARM64/AMD64, Linux ARM64/AMD64, Windows AMD64
64
+ - [x] **pipx scanner discovery fixed** — runner now checks `sys.prefix/bin/` directory
65
+ - `LocalRunner.is_available()` checks: system PATH → venv bin → `~/.vibeguard/bin/`
66
+ - `bootstrap._is_binary_available()` also checks venv bin
67
+ - Pip-installed tools (Semgrep, Bandit, pip-audit, Checkov) now found in pipx venv
68
+ - [x] Added `os_map`/`arch_map` fields to `DownloadConfig` in both `scanners/__init__.py` and `core/downloader.py`
69
+ - [x] Updated `core/bootstrap.py` to pass new fields through
70
+
71
+ **Files changed:**
72
+ - `src/vibeguard/scanners/manifests/trivy.toml` — download URL + custom OS/arch mapping
73
+ - `src/vibeguard/scanners/__init__.py` — `os_map`/`arch_map` on DownloadConfig + manifest parsing
74
+ - `src/vibeguard/core/downloader.py` — `os_map`/`arch_map` on DownloadConfig + apply in URL building
75
+ - `src/vibeguard/core/bootstrap.py` — pass `os_map`/`arch_map`, check venv bin in `_is_binary_available()`
76
+ - `src/vibeguard/scanners/runners/local.py` — `_get_venv_bin_dir()` + check in `is_available()`
77
+
78
+ **Tests:** 741 passed, ruff clean.
79
+
80
+ ---
81
+
82
+ ### PyPI Publication ✅ PUBLISHED + AUTOMATED (2026-02-06)
83
+
84
+ - [x] **vibeguard-cli v1.0.4 live on PyPI**: https://pypi.org/project/vibeguard-cli/
57
85
  - [x] Install: `pip install vibeguard-cli`
58
86
  - [x] Both wheel (.whl) and sdist (.tar.gz) uploaded
59
- - [x] Manual upload via twine (token-based)
60
- - [x] Updated `.github/workflows/publish.yml` for automated future releases:
61
- - Switched from API token secrets to **OIDC trusted publishing** (no secrets needed)
62
- - Tests and linting must pass before publish (removed `continue-on-error`)
87
+ - [x] Manual upload via twine for v1.0.0 (initial release)
88
+ - [x] **Automated CI/CD pipeline fully working** (v1.0.4 all 4 jobs green):
89
+ - Run Tests (1m16s) unit tests pass, scanner-dependent tests excluded
90
+ - Build Package (17s) wheel + sdist built and verified
91
+ - Publish to PyPI (16s) — OIDC trusted publishing (no secrets needed)
92
+ - Create GitHub Release (6s) — auto-created with install instructions
93
+ - [x] `.github/workflows/publish.yml` configured:
94
+ - OIDC trusted publishing via `pypa/gh-action-pypi-publish@release/v1`
95
+ - Tests and linting must pass before publish
63
96
  - `id-token: write` permission scoped to publish jobs only
64
97
  - Triggers on: git tag push (`v*.*.*`) or manual workflow dispatch
65
98
  - TestPyPI option via workflow dispatch toggle
66
- - GitHub Release auto-created with install instructions on tag push
67
- - Upgraded `softprops/action-gh-release` to v2
68
-
69
- **One-time setup required for automated publishing:**
70
- 1. Go to https://pypi.org/manage/project/vibeguard-cli/settings/publishing/
71
- 2. Add trusted publisher: GitHub, owner: `faheem91`, repo: `vibeguard-cli-2`, workflow: `publish.yml`, environment: `pypi`
72
- 3. Future releases: bump version in `pyproject.toml` + `__init__.py`, then `git tag v1.1.0 && git push origin v1.1.0`
99
+ - GitHub Release auto-created on tag push (`softprops/action-gh-release@v2`)
100
+ - Scanner-dependent tests excluded from CI (no semgrep/gitleaks on runner)
101
+
102
+ **CI fixes applied (v1.0.1–v1.0.4):**
103
+ - Added `ignore = ["UP042"]` to ruff config (str+Enum pattern used throughout)
104
+ - Fixed f-string without placeholders (F541) in config_cmd.py and auth_cmd.py
105
+ - Widened `line-length` from 100 to 120 in pyproject.toml
106
+ - Excluded scanner-dependent tests: `test_cli.py`, `test_live_cmd.py`, scan tests
107
+
108
+ **Future releases:** bump version in `pyproject.toml` + `__init__.py`, then:
109
+ ```bash
110
+ git tag v1.1.0 && git push origin v1.1.0
111
+ ```
73
112
 
74
113
  ---
75
114
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "vibeguard-cli"
7
- version = "1.0.4"
7
+ version = "1.0.5"
8
8
  description = "Unified security scanner orchestrator for local repos"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,3 +1,3 @@
1
1
  """VibeGuard CLI - Unified security scanner orchestrator."""
2
2
 
3
- __version__ = "1.0.4"
3
+ __version__ = "1.0.5"
@@ -6,6 +6,7 @@ import subprocess # nosec B404 # noqa: S404 # needed for pip install
6
6
  import sys
7
7
  from dataclasses import dataclass
8
8
  from enum import Enum
9
+ from pathlib import Path
9
10
 
10
11
  from vibeguard.core.downloader import DownloadConfig, download_binary, get_cached_binary
11
12
  from vibeguard.scanners import ScannerManifest, load_manifest
@@ -68,8 +69,19 @@ class BootstrapSummary:
68
69
 
69
70
 
70
71
  def _is_binary_available(binary_name: str) -> bool:
71
- """Check if a binary is available in PATH."""
72
- return shutil.which(binary_name) is not None
72
+ """Check if a binary is available in PATH or the current venv's bin directory."""
73
+ if shutil.which(binary_name) is not None:
74
+ return True
75
+
76
+ # Check current Python environment's bin directory (handles pipx installs)
77
+ prefix = Path(sys.prefix)
78
+ bin_dir = prefix / ("Scripts" if sys.platform == "win32" else "bin")
79
+ if bin_dir.is_dir():
80
+ for ext in ("", ".exe"):
81
+ if (bin_dir / f"{binary_name}{ext}").is_file():
82
+ return True
83
+
84
+ return False
73
85
 
74
86
 
75
87
  def _is_docker_available() -> bool:
@@ -102,6 +114,8 @@ async def _try_download(manifest: ScannerManifest) -> bool:
102
114
  archive_type=manifest.download_config.archive_type,
103
115
  windows_archive_type=manifest.download_config.windows_archive_type,
104
116
  windows_arch=manifest.download_config.windows_arch,
117
+ os_map=manifest.download_config.os_map,
118
+ arch_map=manifest.download_config.arch_map,
105
119
  )
106
120
 
107
121
  binary_path = await download_binary(dl_config)
@@ -82,6 +82,8 @@ class DownloadConfig(BaseModel):
82
82
  archive_type: str = "tar.gz"
83
83
  windows_archive_type: str | None = None # Override for Windows
84
84
  windows_arch: str | None = None # Override arch for Windows (e.g., "x64" instead of "amd64")
85
+ os_map: dict[str, str] | None = None # Custom OS name mapping (e.g., {"darwin": "macOS"})
86
+ arch_map: dict[str, str] | None = None # Custom arch name mapping (e.g., {"amd64": "64bit"})
85
87
 
86
88
 
87
89
  class PlatformInfo(NamedTuple):
@@ -148,6 +150,14 @@ async def download_binary(config: DownloadConfig) -> Path | None:
148
150
  # Determine archive type and arch (Windows may use different values)
149
151
  archive_type = config.archive_type
150
152
  arch = platform_info.arch
153
+ os_name = platform_info.os
154
+
155
+ # Apply custom OS/arch mappings if provided (e.g., Trivy uses "macOS" not "darwin")
156
+ if config.os_map:
157
+ os_name = config.os_map.get(os_name, os_name)
158
+ if config.arch_map:
159
+ arch = config.arch_map.get(arch, arch)
160
+
151
161
  if platform_info.os == "windows":
152
162
  if config.windows_archive_type:
153
163
  archive_type = config.windows_archive_type
@@ -157,7 +167,7 @@ async def download_binary(config: DownloadConfig) -> Path | None:
157
167
  # Build download URL
158
168
  url = config.url_template.format(
159
169
  version=config.version,
160
- os=platform_info.os,
170
+ os=os_name,
161
171
  arch=arch,
162
172
  )
163
173
  # Handle Windows archive type in URL if different from default
@@ -24,6 +24,8 @@ class DownloadConfig(BaseModel):
24
24
  archive_type: str = "tar.gz"
25
25
  windows_archive_type: str | None = None # Override for Windows
26
26
  windows_arch: str | None = None # Override arch for Windows (e.g., "x64")
27
+ os_map: dict[str, str] | None = None # Custom OS name mapping (e.g., darwin → macOS)
28
+ arch_map: dict[str, str] | None = None # Custom arch name mapping (e.g., amd64 → 64bit)
27
29
 
28
30
 
29
31
  class PipConfig(BaseModel):
@@ -89,6 +91,8 @@ def load_manifest(name: str) -> ScannerManifest:
89
91
  archive_type=download_data.get("archive_type", "tar.gz"),
90
92
  windows_archive_type=download_data.get("windows_archive_type"),
91
93
  windows_arch=download_data.get("windows_arch"),
94
+ os_map=download_data.get("os_map"),
95
+ arch_map=download_data.get("arch_map"),
92
96
  )
93
97
 
94
98
  # Parse pip config if present
@@ -4,7 +4,7 @@
4
4
  [scanner]
5
5
  name = "trivy"
6
6
  display_name = "Trivy"
7
- version = "0.50.4"
7
+ version = "0.69.1"
8
8
  tier = "core"
9
9
  categories = ["vulnerability", "sca"]
10
10
  languages = ["*"]
@@ -20,13 +20,23 @@ binary_name = "trivy"
20
20
 
21
21
  [install.download]
22
22
  # Auto-download binary from GitHub releases
23
- # Note: Trivy uses non-standard naming (Linux-64bit, windows-64bit)
24
- # TODO: Add per-scanner OS/arch mapping for full platform support
25
- url_template = "https://github.com/aquasecurity/trivy/releases/download/v{version}/trivy_{version}_{os}-64bit.tar.gz"
23
+ # Trivy naming: trivy_{version}_{os}-{arch}.tar.gz
24
+ # e.g., trivy_0.69.1_macOS-ARM64.tar.gz, trivy_0.69.1_Linux-64bit.tar.gz
25
+ url_template = "https://github.com/aquasecurity/trivy/releases/download/v{version}/trivy_{version}_{os}-{arch}.tar.gz"
26
26
  binary_name = "trivy"
27
27
  archive_type = "tar.gz"
28
28
  windows_archive_type = "zip"
29
29
 
30
+ # Trivy uses non-standard platform names
31
+ [install.download.os_map]
32
+ linux = "Linux"
33
+ darwin = "macOS"
34
+ windows = "windows"
35
+
36
+ [install.download.arch_map]
37
+ amd64 = "64bit"
38
+ arm64 = "ARM64"
39
+
30
40
  [install.docker]
31
41
  image = "aquasec/trivy:latest"
32
42
  mount_mode = "ro"
@@ -10,6 +10,22 @@ from vibeguard.core.downloader import VIBEGUARD_BIN_DIR
10
10
  from vibeguard.scanners.runners.base import BaseRunner, RunResult
11
11
 
12
12
 
13
+ def _get_venv_bin_dir() -> Path | None:
14
+ """Get the bin/Scripts directory of the current Python environment.
15
+
16
+ This handles pipx installs where pip-installed tools end up in the
17
+ isolated venv's bin directory, not on the system PATH.
18
+ """
19
+ prefix = Path(sys.prefix)
20
+ if sys.platform == "win32":
21
+ bin_dir = prefix / "Scripts"
22
+ else:
23
+ bin_dir = prefix / "bin"
24
+ if bin_dir.is_dir():
25
+ return bin_dir
26
+ return None
27
+
28
+
13
29
  class LocalRunner(BaseRunner):
14
30
  """Run scanners using locally installed binaries."""
15
31
 
@@ -29,12 +45,21 @@ class LocalRunner(BaseRunner):
29
45
  return "local"
30
46
 
31
47
  def is_available(self) -> bool:
32
- """Check if binary is available in PATH or downloaded cache."""
48
+ """Check if binary is available in PATH, venv bin, or downloaded cache."""
33
49
  # First check system PATH
34
50
  self._binary_path = shutil.which(self.binary_name)
35
51
  if self._binary_path:
36
52
  return True
37
53
 
54
+ # Check current Python environment's bin directory (handles pipx installs)
55
+ venv_bin = _get_venv_bin_dir()
56
+ if venv_bin:
57
+ for ext in ("", ".exe"):
58
+ candidate = venv_bin / f"{self.binary_name}{ext}"
59
+ if candidate.is_file():
60
+ self._binary_path = str(candidate)
61
+ return True
62
+
38
63
  # Check downloaded binaries in ~/.vibeguard/bin/
39
64
  if self.version:
40
65
  downloaded = self._find_downloaded_binary()
File without changes
File without changes
File without changes
File without changes