dockerls 1.0.0__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 (235) hide show
  1. dockerls-1.0.0/LICENSE +21 -0
  2. dockerls-1.0.0/PKG-INFO +563 -0
  3. dockerls-1.0.0/README.md +512 -0
  4. dockerls-1.0.0/dockerls/__init__.py +31 -0
  5. dockerls-1.0.0/dockerls/application/__init__.py +0 -0
  6. dockerls-1.0.0/dockerls/application/dto/__init__.py +3 -0
  7. dockerls-1.0.0/dockerls/application/dto/analysis.py +257 -0
  8. dockerls-1.0.0/dockerls/application/services/__init__.py +0 -0
  9. dockerls-1.0.0/dockerls/application/services/alternatives_lookup.py +167 -0
  10. dockerls-1.0.0/dockerls/application/services/composite_repository.py +106 -0
  11. dockerls-1.0.0/dockerls/application/services/cross_validation.py +233 -0
  12. dockerls-1.0.0/dockerls/application/services/ecosystems.py +350 -0
  13. dockerls-1.0.0/dockerls/application/services/fallback_scanner.py +97 -0
  14. dockerls-1.0.0/dockerls/application/services/hardening_analysis.py +174 -0
  15. dockerls-1.0.0/dockerls/application/services/migration.py +297 -0
  16. dockerls-1.0.0/dockerls/application/services/progress.py +56 -0
  17. dockerls-1.0.0/dockerls/application/services/remediation.py +321 -0
  18. dockerls-1.0.0/dockerls/application/services/scan_history_store.py +88 -0
  19. dockerls-1.0.0/dockerls/application/services/scanner_factory.py +88 -0
  20. dockerls-1.0.0/dockerls/application/services/source_registry.py +151 -0
  21. dockerls-1.0.0/dockerls/application/services/tag_history_store.py +76 -0
  22. dockerls-1.0.0/dockerls/application/services/teardown.py +50 -0
  23. dockerls-1.0.0/dockerls/application/services/verdict.py +298 -0
  24. dockerls-1.0.0/dockerls/application/services/version_discovery.py +108 -0
  25. dockerls-1.0.0/dockerls/application/use_cases/__init__.py +0 -0
  26. dockerls-1.0.0/dockerls/application/use_cases/analyze_dockerfile.py +103 -0
  27. dockerls-1.0.0/dockerls/application/use_cases/analyze_image.py +173 -0
  28. dockerls-1.0.0/dockerls/application/use_cases/build_image.py +1795 -0
  29. dockerls-1.0.0/dockerls/application/use_cases/compare_images.py +91 -0
  30. dockerls-1.0.0/dockerls/application/use_cases/fleet_scan.py +240 -0
  31. dockerls-1.0.0/dockerls/application/use_cases/recommend_images.py +1078 -0
  32. dockerls-1.0.0/dockerls/application/use_cases/registry_audit.py +133 -0
  33. dockerls-1.0.0/dockerls/application/use_cases/search_images.py +23 -0
  34. dockerls-1.0.0/dockerls/application/use_cases/upgrade_base.py +167 -0
  35. dockerls-1.0.0/dockerls/cache/__init__.py +0 -0
  36. dockerls-1.0.0/dockerls/cache/sqlite_cache.py +184 -0
  37. dockerls-1.0.0/dockerls/cli/__init__.py +0 -0
  38. dockerls-1.0.0/dockerls/cli/analysis_baseline.py +98 -0
  39. dockerls-1.0.0/dockerls/cli/app.py +294 -0
  40. dockerls-1.0.0/dockerls/cli/commands/__init__.py +0 -0
  41. dockerls-1.0.0/dockerls/cli/commands/advisor.py +262 -0
  42. dockerls-1.0.0/dockerls/cli/commands/alternatives.py +291 -0
  43. dockerls-1.0.0/dockerls/cli/commands/analyze.py +429 -0
  44. dockerls-1.0.0/dockerls/cli/commands/analyze_dockerfile.py +104 -0
  45. dockerls-1.0.0/dockerls/cli/commands/base_cmd.py +244 -0
  46. dockerls-1.0.0/dockerls/cli/commands/base_image.py +551 -0
  47. dockerls-1.0.0/dockerls/cli/commands/build.py +1300 -0
  48. dockerls-1.0.0/dockerls/cli/commands/cache_cmd.py +104 -0
  49. dockerls-1.0.0/dockerls/cli/commands/compare.py +177 -0
  50. dockerls-1.0.0/dockerls/cli/commands/controls.py +110 -0
  51. dockerls-1.0.0/dockerls/cli/commands/doctor.py +566 -0
  52. dockerls-1.0.0/dockerls/cli/commands/export.py +81 -0
  53. dockerls-1.0.0/dockerls/cli/commands/fleet.py +159 -0
  54. dockerls-1.0.0/dockerls/cli/commands/health.py +84 -0
  55. dockerls-1.0.0/dockerls/cli/commands/login.py +53 -0
  56. dockerls-1.0.0/dockerls/cli/commands/policy_cmd.py +111 -0
  57. dockerls-1.0.0/dockerls/cli/commands/provenance_cmd.py +162 -0
  58. dockerls-1.0.0/dockerls/cli/commands/recommend.py +761 -0
  59. dockerls-1.0.0/dockerls/cli/commands/registry_audit_cmd.py +103 -0
  60. dockerls-1.0.0/dockerls/cli/commands/sbom.py +144 -0
  61. dockerls-1.0.0/dockerls/cli/commands/search.py +86 -0
  62. dockerls-1.0.0/dockerls/cli/commands/verify.py +115 -0
  63. dockerls-1.0.0/dockerls/cli/commands/version.py +12 -0
  64. dockerls-1.0.0/dockerls/cli/commands/vex_cmd.py +117 -0
  65. dockerls-1.0.0/dockerls/cli/dependencies.py +530 -0
  66. dockerls-1.0.0/dockerls/cli/image_names.py +79 -0
  67. dockerls-1.0.0/dockerls/cli/options.py +42 -0
  68. dockerls-1.0.0/dockerls/cli/progress.py +145 -0
  69. dockerls-1.0.0/dockerls/cli/publish_prompt.py +123 -0
  70. dockerls-1.0.0/dockerls/cli/rendering.py +214 -0
  71. dockerls-1.0.0/dockerls/cli/runtime.py +65 -0
  72. dockerls-1.0.0/dockerls/cli/scan_failure.py +71 -0
  73. dockerls-1.0.0/dockerls/cli/text.py +39 -0
  74. dockerls-1.0.0/dockerls/cli/validators.py +35 -0
  75. dockerls-1.0.0/dockerls/cli/vulnerability_view.py +154 -0
  76. dockerls-1.0.0/dockerls/domain/__init__.py +0 -0
  77. dockerls-1.0.0/dockerls/domain/entities/__init__.py +75 -0
  78. dockerls-1.0.0/dockerls/domain/entities/declared_metadata.py +147 -0
  79. dockerls-1.0.0/dockerls/domain/entities/dockerfile_analysis.py +318 -0
  80. dockerls-1.0.0/dockerls/domain/entities/image.py +109 -0
  81. dockerls-1.0.0/dockerls/domain/entities/image_facts.py +137 -0
  82. dockerls-1.0.0/dockerls/domain/entities/recommendation.py +33 -0
  83. dockerls-1.0.0/dockerls/domain/entities/scan_result.py +129 -0
  84. dockerls-1.0.0/dockerls/domain/entities/vulnerability.py +232 -0
  85. dockerls-1.0.0/dockerls/domain/interfaces/__init__.py +17 -0
  86. dockerls-1.0.0/dockerls/domain/interfaces/cache_store.py +18 -0
  87. dockerls-1.0.0/dockerls/domain/interfaces/dockerfile_validator.py +99 -0
  88. dockerls-1.0.0/dockerls/domain/interfaces/eol_checker.py +11 -0
  89. dockerls-1.0.0/dockerls/domain/interfaces/image_repository.py +15 -0
  90. dockerls-1.0.0/dockerls/domain/interfaces/scanner.py +15 -0
  91. dockerls-1.0.0/dockerls/domain/security_controls.py +362 -0
  92. dockerls-1.0.0/dockerls/domain/value_objects/__init__.py +49 -0
  93. dockerls-1.0.0/dockerls/domain/value_objects/attack_surface.py +198 -0
  94. dockerls-1.0.0/dockerls/domain/value_objects/base_recipe.py +600 -0
  95. dockerls-1.0.0/dockerls/domain/value_objects/base_upgrade.py +292 -0
  96. dockerls-1.0.0/dockerls/domain/value_objects/build_labels.py +99 -0
  97. dockerls-1.0.0/dockerls/domain/value_objects/build_policy.py +412 -0
  98. dockerls-1.0.0/dockerls/domain/value_objects/confidence.py +156 -0
  99. dockerls-1.0.0/dockerls/domain/value_objects/fleet.py +174 -0
  100. dockerls-1.0.0/dockerls/domain/value_objects/gate.py +327 -0
  101. dockerls-1.0.0/dockerls/domain/value_objects/hardening.py +303 -0
  102. dockerls-1.0.0/dockerls/domain/value_objects/image_reference.py +90 -0
  103. dockerls-1.0.0/dockerls/domain/value_objects/inheritance.py +352 -0
  104. dockerls-1.0.0/dockerls/domain/value_objects/network_policy.py +280 -0
  105. dockerls-1.0.0/dockerls/domain/value_objects/production_readiness.py +145 -0
  106. dockerls-1.0.0/dockerls/domain/value_objects/provenance.py +211 -0
  107. dockerls-1.0.0/dockerls/domain/value_objects/recipe_diff.py +188 -0
  108. dockerls-1.0.0/dockerls/domain/value_objects/registry_audit.py +195 -0
  109. dockerls-1.0.0/dockerls/domain/value_objects/registry_target.py +225 -0
  110. dockerls-1.0.0/dockerls/domain/value_objects/remediation_score.py +62 -0
  111. dockerls-1.0.0/dockerls/domain/value_objects/scan_history.py +183 -0
  112. dockerls-1.0.0/dockerls/domain/value_objects/scan_plan.py +193 -0
  113. dockerls-1.0.0/dockerls/domain/value_objects/scanner_db.py +143 -0
  114. dockerls-1.0.0/dockerls/domain/value_objects/security_score.py +160 -0
  115. dockerls-1.0.0/dockerls/domain/value_objects/security_tier.py +122 -0
  116. dockerls-1.0.0/dockerls/domain/value_objects/tag_history.py +180 -0
  117. dockerls-1.0.0/dockerls/domain/value_objects/tool_release.py +253 -0
  118. dockerls-1.0.0/dockerls/domain/value_objects/tristate.py +47 -0
  119. dockerls-1.0.0/dockerls/domain/value_objects/vex.py +249 -0
  120. dockerls-1.0.0/dockerls/exit_codes.py +23 -0
  121. dockerls-1.0.0/dockerls/exporters/__init__.py +0 -0
  122. dockerls-1.0.0/dockerls/exporters/base.py +17 -0
  123. dockerls-1.0.0/dockerls/exporters/csv_exporter.py +85 -0
  124. dockerls-1.0.0/dockerls/exporters/factory.py +31 -0
  125. dockerls-1.0.0/dockerls/exporters/html_exporter.py +105 -0
  126. dockerls-1.0.0/dockerls/exporters/json_exporter.py +19 -0
  127. dockerls-1.0.0/dockerls/exporters/markdown_exporter.py +84 -0
  128. dockerls-1.0.0/dockerls/exporters/sarif_exporter.py +245 -0
  129. dockerls-1.0.0/dockerls/infrastructure/__init__.py +0 -0
  130. dockerls-1.0.0/dockerls/infrastructure/config/__init__.py +0 -0
  131. dockerls-1.0.0/dockerls/infrastructure/config/policy_file.py +165 -0
  132. dockerls-1.0.0/dockerls/infrastructure/config/settings.py +197 -0
  133. dockerls-1.0.0/dockerls/infrastructure/database/__init__.py +0 -0
  134. dockerls-1.0.0/dockerls/infrastructure/database/models.py +78 -0
  135. dockerls-1.0.0/dockerls/infrastructure/dockerfile_validator.py +1899 -0
  136. dockerls-1.0.0/dockerls/infrastructure/evidence.py +99 -0
  137. dockerls-1.0.0/dockerls/infrastructure/hashing.py +165 -0
  138. dockerls-1.0.0/dockerls/infrastructure/logging/__init__.py +0 -0
  139. dockerls-1.0.0/dockerls/infrastructure/logging/setup.py +98 -0
  140. dockerls-1.0.0/dockerls/infrastructure/network/__init__.py +0 -0
  141. dockerls-1.0.0/dockerls/infrastructure/network/guarded_client.py +107 -0
  142. dockerls-1.0.0/dockerls/infrastructure/network/host_guard.py +117 -0
  143. dockerls-1.0.0/dockerls/infrastructure/redaction.py +135 -0
  144. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/alpine.dockerfile +44 -0
  145. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/debian.dockerfile +45 -0
  146. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/distroless.dockerfile +34 -0
  147. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/go-alpine.dockerfile +52 -0
  148. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/go-debian.dockerfile +54 -0
  149. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/go-distroless.dockerfile +43 -0
  150. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/go-scratch.dockerfile +48 -0
  151. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/go.dockerfile +50 -0
  152. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/gradle-alpine.dockerfile +51 -0
  153. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/gradle.dockerfile +52 -0
  154. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/java-alpine.dockerfile +50 -0
  155. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/java-debian.dockerfile +50 -0
  156. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/java-distroless.dockerfile +39 -0
  157. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/java-ubuntu.dockerfile +54 -0
  158. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/java.dockerfile +60 -0
  159. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/maven-alpine.dockerfile +56 -0
  160. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/maven.dockerfile +57 -0
  161. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/node-alpine.dockerfile +47 -0
  162. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/node-debian.dockerfile +54 -0
  163. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/node-distroless.dockerfile +46 -0
  164. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/node-ubuntu.dockerfile +63 -0
  165. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/node.dockerfile +61 -0
  166. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/php-alpine.dockerfile +45 -0
  167. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/php-debian.dockerfile +45 -0
  168. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/php-ubuntu.dockerfile +49 -0
  169. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/php.dockerfile +44 -0
  170. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/python-alpine.dockerfile +51 -0
  171. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/python-debian.dockerfile +54 -0
  172. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/python-distroless.dockerfile +51 -0
  173. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/python-ubuntu.dockerfile +60 -0
  174. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/python.dockerfile +58 -0
  175. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/ruby-alpine.dockerfile +48 -0
  176. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/ruby-debian.dockerfile +50 -0
  177. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/rust-alpine.dockerfile +50 -0
  178. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/rust-debian.dockerfile +48 -0
  179. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/rust-scratch.dockerfile +44 -0
  180. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/rust.dockerfile +54 -0
  181. dockerls-1.0.0/dockerls/infrastructure/templates/hardening/ubuntu.dockerfile +49 -0
  182. dockerls-1.0.0/dockerls/infrastructure/toolchain/__init__.py +0 -0
  183. dockerls-1.0.0/dockerls/infrastructure/toolchain/db_metadata.py +115 -0
  184. dockerls-1.0.0/dockerls/infrastructure/toolchain/installer.py +435 -0
  185. dockerls-1.0.0/dockerls/integrations/__init__.py +0 -0
  186. dockerls-1.0.0/dockerls/integrations/dhi/__init__.py +0 -0
  187. dockerls-1.0.0/dockerls/integrations/dhi/catalog.py +457 -0
  188. dockerls-1.0.0/dockerls/integrations/dhi/definition.py +151 -0
  189. dockerls-1.0.0/dockerls/integrations/dhi/repository.py +238 -0
  190. dockerls-1.0.0/dockerls/integrations/dockerhub/__init__.py +0 -0
  191. dockerls-1.0.0/dockerls/integrations/dockerhub/client.py +318 -0
  192. dockerls-1.0.0/dockerls/integrations/dockerhub/urls.py +75 -0
  193. dockerls-1.0.0/dockerls/integrations/endoflife/__init__.py +0 -0
  194. dockerls-1.0.0/dockerls/integrations/endoflife/checker.py +216 -0
  195. dockerls-1.0.0/dockerls/integrations/engine/__init__.py +0 -0
  196. dockerls-1.0.0/dockerls/integrations/engine/batch.py +197 -0
  197. dockerls-1.0.0/dockerls/integrations/engine/client.py +330 -0
  198. dockerls-1.0.0/dockerls/integrations/engine/locator.py +96 -0
  199. dockerls-1.0.0/dockerls/integrations/exploitdb/__init__.py +0 -0
  200. dockerls-1.0.0/dockerls/integrations/exploitdb/client.py +271 -0
  201. dockerls-1.0.0/dockerls/integrations/grype/__init__.py +0 -0
  202. dockerls-1.0.0/dockerls/integrations/grype/scanner.py +336 -0
  203. dockerls-1.0.0/dockerls/integrations/registry/__init__.py +0 -0
  204. dockerls-1.0.0/dockerls/integrations/registry/hardened.py +284 -0
  205. dockerls-1.0.0/dockerls/integrations/registry/inspector.py +420 -0
  206. dockerls-1.0.0/dockerls/integrations/registry/oci.py +259 -0
  207. dockerls-1.0.0/dockerls/integrations/registry/private.py +79 -0
  208. dockerls-1.0.0/dockerls/integrations/registry/urls.py +36 -0
  209. dockerls-1.0.0/dockerls/integrations/scan_errors.py +67 -0
  210. dockerls-1.0.0/dockerls/integrations/scan_target.py +57 -0
  211. dockerls-1.0.0/dockerls/integrations/signing/__init__.py +0 -0
  212. dockerls-1.0.0/dockerls/integrations/signing/cosign.py +484 -0
  213. dockerls-1.0.0/dockerls/integrations/threat_intel/__init__.py +0 -0
  214. dockerls-1.0.0/dockerls/integrations/threat_intel/client.py +290 -0
  215. dockerls-1.0.0/dockerls/integrations/trivy/__init__.py +0 -0
  216. dockerls-1.0.0/dockerls/integrations/trivy/cache_pool.py +176 -0
  217. dockerls-1.0.0/dockerls/integrations/trivy/scanner.py +447 -0
  218. dockerls-1.0.0/dockerls/utils/__init__.py +0 -0
  219. dockerls-1.0.0/dockerls/utils/auth.py +108 -0
  220. dockerls-1.0.0/dockerls/utils/executables.py +39 -0
  221. dockerls-1.0.0/dockerls/utils/ignore_file.py +130 -0
  222. dockerls-1.0.0/dockerls/utils/rate_limit.py +130 -0
  223. dockerls-1.0.0/dockerls/utils/resources.py +183 -0
  224. dockerls-1.0.0/dockerls/utils/retry.py +31 -0
  225. dockerls-1.0.0/dockerls/utils/safe_yaml.py +166 -0
  226. dockerls-1.0.0/dockerls/utils/subprocess_runner.py +216 -0
  227. dockerls-1.0.0/dockerls/utils/validation.py +72 -0
  228. dockerls-1.0.0/dockerls.egg-info/PKG-INFO +563 -0
  229. dockerls-1.0.0/dockerls.egg-info/SOURCES.txt +233 -0
  230. dockerls-1.0.0/dockerls.egg-info/dependency_links.txt +1 -0
  231. dockerls-1.0.0/dockerls.egg-info/entry_points.txt +2 -0
  232. dockerls-1.0.0/dockerls.egg-info/requires.txt +25 -0
  233. dockerls-1.0.0/dockerls.egg-info/top_level.txt +1 -0
  234. dockerls-1.0.0/pyproject.toml +126 -0
  235. dockerls-1.0.0/setup.cfg +4 -0
dockerls-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Ivomsantiago
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,563 @@
1
+ Metadata-Version: 2.4
2
+ Name: dockerls
3
+ Version: 1.0.0
4
+ Summary: Enterprise Docker Image Security Advisor
5
+ Author: Ivomsantiago
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Ivomsantiago/DockerLs
8
+ Project-URL: Repository, https://github.com/Ivomsantiago/DockerLs
9
+ Project-URL: Issues, https://github.com/Ivomsantiago/DockerLs/issues
10
+ Keywords: docker,security,vulnerability,scanner,devops,devsecops
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Security
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.11
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: typer>=0.12
28
+ Requires-Dist: rich>=13.0
29
+ Requires-Dist: pydantic>=2.0
30
+ Requires-Dist: pydantic-settings>=2.5
31
+ Requires-Dist: sqlalchemy>=2.0
32
+ Requires-Dist: httpx>=0.27
33
+ Requires-Dist: tenacity>=8.0
34
+ Requires-Dist: loguru>=0.7
35
+ Requires-Dist: pyyaml>=6.0
36
+ Requires-Dist: idna>=3.15
37
+ Provides-Extra: keyring
38
+ Requires-Dist: keyring>=25.0; extra == "keyring"
39
+ Provides-Extra: dev
40
+ Requires-Dist: pytest>=8.0; extra == "dev"
41
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
42
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
43
+ Requires-Dist: ruff>=0.5; extra == "dev"
44
+ Requires-Dist: mypy>=1.10; extra == "dev"
45
+ Requires-Dist: bandit>=1.7; extra == "dev"
46
+ Requires-Dist: pip-audit>=2.7; extra == "dev"
47
+ Requires-Dist: types-PyYAML>=6.0; extra == "dev"
48
+ Requires-Dist: jsonschema>=4.0; extra == "dev"
49
+ Requires-Dist: hypothesis>=6.100; extra == "dev"
50
+ Dynamic: license-file
51
+
52
+ # DockerLs
53
+
54
+ [![CI](https://github.com/Ivomsantiago/DockerLs/actions/workflows/ci.yml/badge.svg)](https://github.com/Ivomsantiago/DockerLs/actions/workflows/ci.yml)
55
+ [![CodeQL](https://github.com/Ivomsantiago/DockerLs/actions/workflows/codeql.yml/badge.svg)](https://github.com/Ivomsantiago/DockerLs/actions/workflows/codeql.yml)
56
+ [![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/)
57
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
58
+
59
+ **DockerLs ajuda você a escolher a imagem Docker mais segura para produção —
60
+ e a provar por quê.**
61
+
62
+ Em vez de você pesquisar tag por tag no Docker Hub e adivinhar qual é mais
63
+ confiável, o DockerLs escaneia várias de uma vez (Trivy e/ou Grype), compara
64
+ com alternativas mais seguras (Chainguard, Distroless, Docker Hardened
65
+ Images) e recomenda uma — com o motivo escrito, não só um número.
66
+
67
+ ```bash
68
+ dockerls recommend node
69
+ ```
70
+
71
+ isso já basta para ver a ideia funcionando. O resto deste documento existe
72
+ pra te dar o resto do contexto: o que instalar, todos os comandos, e por que
73
+ as respostas dele são diferentes das de um scanner comum.
74
+
75
+ ---
76
+
77
+ ## Índice
78
+
79
+ - [Por que não é só mais um scanner](#por-que-não-é-só-mais-um-scanner)
80
+ - [Instalação](#instalação)
81
+ - [Comece por aqui](#comece-por-aqui)
82
+ - [Todos os comandos](#todos-os-comandos)
83
+ - [Guia completo: criando e usando uma imagem hardened do zero](#guia-completo-criando-e-usando-uma-imagem-hardened-do-zero)
84
+ - [Configuração](#configuração)
85
+ - [Exit codes (pra CI)](#exit-codes-pra-ci)
86
+ - [Desenvolvimento](#desenvolvimento)
87
+ - [Licença](#licença)
88
+
89
+ ---
90
+
91
+ ## Por que não é só mais um scanner
92
+
93
+ Um scanner comum responde "quantas vulnerabilidades essa imagem tem?". Isso
94
+ quase nunca é a pergunta que importa. As perguntas de verdade são "qual
95
+ imagem eu deveria usar?" e "o que eu faço com o que foi encontrado?" — e é
96
+ sobre essas duas que o DockerLs foi pensado.
97
+
98
+ | | Scanner comum | DockerLs |
99
+ |---|---|---|
100
+ | Escopo | uma imagem que você já escolheu | **todas as tags candidatas**, ranqueadas |
101
+ | Fontes | um registry | Docker Hub + Chainguard + Distroless + Docker Hardened Images, no mesmo pipeline |
102
+ | Identidade | a tag que você digitou | **digest do manifesto**, resolvido antes do scan — uma tag se move, um digest não |
103
+ | Configuração da imagem | fora do escopo | **Hardening Score** medido no config OCI publicado (root, portas, entrypoint) |
104
+ | Superfície de ataque | confundida com tamanho | **Attack Surface Score** próprio: shell, gerenciador de pacotes, ferramentas de debug |
105
+ | Exploração real | só a severidade da distro | CISA KEV + FIRST EPSS + Exploit-DB pesam no score e aparecem na tabela |
106
+ | Dado que falta | vira "zero" ou "seguro" | vira `unknown` — nunca credita, nunca penaliza por adivinhação |
107
+ | Falha de scan | vira "0 vulnerabilidades" | vira `UNVERIFIED`, com causa classificada, fora da recomendação |
108
+ | Confiança de dois scanners | não existe | validação cruzada; divergência material é sinalizada, não escondida |
109
+ | A imagem mudou desde ontem? | você não sabe | `analyze` registra e avisa quando a tag mudou de digest ou o CVE count mudou |
110
+ | Prova do que foi medido | um número na tela | JSON bruto de cada scan + manifesto de evidência por execução |
111
+
112
+ O princípio que organiza tudo isso: **uma imagem que não pôde ser medida
113
+ nunca é apresentada como uma imagem segura.** Ela some da recomendação e vai
114
+ para uma lista à parte, com o motivo.
115
+
116
+ Quer o detalhe fino de cada um desses pontos — o algoritmo de pontuação, o
117
+ modelo de confiança, a arquitetura interna? Está tudo na
118
+ **[referência completa](docs/REFERENCE.md)**.
119
+
120
+ ### O que mais ele faz, além de recomendar
121
+
122
+ - **SBOM assinado** (`sbom --attest`) — CycloneDX/SPDX anexado ao manifesto
123
+ via cosign, visível pra quem faz `docker pull`, não só um arquivo no seu
124
+ disco.
125
+ - **VEX** (`vex`) — publica suas exceções de CVE (findings que você já
126
+ avaliou e decidiu ignorar) num formato que outras ferramentas entendem.
127
+ - **Procedência** (`provenance`) — confere um documento de build e prepara a
128
+ atestação.
129
+ - **Auditoria de Dockerfile** (`analyze-dockerfile`, `controls`) — regras de
130
+ hardening mapeadas para controles publicados (CIS, NIST, OWASP).
131
+ - **`build` com portão de segurança** — valida, constrói, escaneia e recusa
132
+ publicar se houver CVE explorado de verdade (CISA KEV), mesmo que a distro
133
+ classifique como "médio".
134
+ - **`fleet`** — varre uma árvore inteira de repositórios e resume o estado
135
+ de todos os Dockerfiles de uma vez.
136
+
137
+ ---
138
+
139
+ ## Instalação
140
+
141
+ ```bash
142
+ pip install dockerls
143
+ ```
144
+
145
+ Também dá para instalar com suporte a keyring (guarda credenciais do Docker
146
+ Hub no sistema, em vez de texto puro):
147
+
148
+ ```bash
149
+ pip install "dockerls[keyring]"
150
+ ```
151
+
152
+ ### O que você precisa ter instalado
153
+
154
+ | Precisa de | Pra quê | Se faltar |
155
+ |---|---|---|
156
+ | **Python 3.11+** | tudo | nada roda |
157
+ | **Trivy** ou **Grype** | medir vulnerabilidade de verdade (`recommend`, `analyze`, `compare`, `advisor`, etc.) | ainda funciona, mas os resultados saem marcados como "não verificado" |
158
+ | **Docker** (o daemon) | só o comando `build` | `build` falha; todo o resto continua normal |
159
+ | **git** | opcional — usado pra registrar de onde veio o build | sai sem esse detalhe, marcado como incompleto |
160
+ | **cosign** | opcional — assinar SBOM/imagens (`sbom --attest`, `build --sign`) | funciona sem, mas nada sai assinado |
161
+ | **Go 1.24+** | opcional — só se você quiser compilar a engine que acelera runs grandes | dispensável, a CLI funciona 100% sem isso |
162
+
163
+ Pra conferir tudo de uma vez e instalar o que faltar:
164
+
165
+ ```bash
166
+ dockerls doctor # confere o ambiente
167
+ dockerls doctor --install # instala Trivy/Grype pra você
168
+ dockerls health # confere conectividade com CISA KEV, EPSS, Exploit-DB etc.
169
+ ```
170
+
171
+ Nos bastidores, parte da orquestração de scans (`recommend` com muitas tags)
172
+ pode rodar num binário auxiliar escrito em Go — é 100% opcional, a CLI
173
+ volta sozinha pro caminho em Python se ele não estiver compilado ou
174
+ instalado. Detalhes de como compilar em [`engine/README.md`](engine/README.md).
175
+
176
+ ---
177
+
178
+ ## Comece por aqui
179
+
180
+ ```bash
181
+ # Qual versão do Node é a mais segura pra usar agora?
182
+ dockerls recommend node
183
+
184
+ # Quero saber tudo sobre essa tag específica
185
+ dockerls analyze node:22-alpine
186
+
187
+ # Já uso essa imagem — o que eu conserto nela?
188
+ dockerls advisor node:22-alpine
189
+
190
+ # Duas imagens, lado a lado
191
+ dockerls compare node:22-alpine node:22-bookworm-slim
192
+
193
+ # Alternativas mais seguras pra imagem que eu já rodo
194
+ dockerls alternatives node:18-alpine
195
+
196
+ # Construir uma imagem já validando, escaneando e (se quiser) assinando
197
+ dockerls build . -t minhaapp:1.0 --fail-on high
198
+
199
+ # Exportar o relatório pra anexar num PR ou mandar pro SIEM
200
+ dockerls export node:22-alpine --format sarif --output results.sarif
201
+ ```
202
+
203
+ Toda vez que você roda `analyze` contra a mesma imagem, o DockerLs lembra:
204
+ se a tag mudou de digest, ou se a contagem de CVE mudou desde a última vez
205
+ (mesmo no mesmo digest — a base do scanner pode aprender sobre um CVE novo),
206
+ ele avisa.
207
+
208
+ ---
209
+
210
+ ## Todos os comandos
211
+
212
+ | Comando | Pra que serve | Exit codes |
213
+ |---|---|---|
214
+ | `search` | Lista as tags que existem de uma imagem | `0` `1` |
215
+ | `recommend` | Ranqueia as tags mais seguras e recomenda uma | `0` `1` `2` `3` |
216
+ | `advisor` | Plano de correção completo pra melhor imagem (ou pra uma tag específica) | `0` `1` |
217
+ | `alternatives` | Alternativas mais seguras pra imagem que você já roda, com trade-offs | `0` `1` `2` |
218
+ | `analyze` | Raio-x completo de uma tag: CVEs, CVSS, origem, correção, histórico | `0` `1` `2` |
219
+ | `compare` | Duas ou mais imagens, lado a lado | `0` `1` `2` `3` |
220
+ | `build` | Valida, constrói, escaneia e (se você quiser) publica e assina | `0` `1` `2` |
221
+ | `base` | Confere as bases do Dockerfile contra o registry e atualiza os digests | `0` `1` `2` |
222
+ | `base-image` | Gera um Dockerfile de base já enxuto, a partir de um menu | `0` `1` |
223
+ | `analyze-dockerfile` | Valida um Dockerfile inteiro contra regras de hardening | `0` `1` `2` |
224
+ | `controls` | Mostra os controles (CIS, NIST, OWASP) por trás de cada regra | `0` `1` |
225
+ | `sbom` | Gera e opcionalmente assina o inventário de componentes da imagem | `0` `1` |
226
+ | `vex` | Publica suas exceções de CVE num formato que outras ferramentas entendem | `0` `1` |
227
+ | `provenance` | Confere um documento de procedência e prepara a atestação | `0` `1` `2` |
228
+ | `verify` | Confere a assinatura de uma imagem com cosign | `0` `1` `2` |
229
+ | `registry-audit` | O que o registry conta sobre uma imagem publicada | `0` `1` `2` |
230
+ | `fleet` | Varre vários Dockerfiles de um repositório de uma vez | `0` `1` `2` |
231
+ | `policy` | Mostra e valida a política declarada em `.dockerls-policy.yaml` | `0` `1` |
232
+ | `export` | Exporta o relatório em JSON, CSV, HTML, Markdown ou SARIF | `0` `1` |
233
+ | `doctor` | Confere se scanner, base de dados e o resto do ambiente estão prontos (e instala o que falta) | `0` `1` |
234
+ | `health` | Checa a conectividade com os serviços externos (KEV, EPSS, Exploit-DB, registries) | `0` `1` |
235
+ | `cache` | Inspeciona e limpa o cache de análises | `0` `1` |
236
+ | `login` / `logout` | Guarda ou remove credenciais do Docker Hub no keyring do sistema | `0` `1` |
237
+ | `version` | Mostra a versão instalada | `0` |
238
+
239
+ Cada um desses tem opções que não cabem aqui — a lista completa, com
240
+ exemplos de saída real, está na **[referência completa](docs/REFERENCE.md)**.
241
+
242
+ ---
243
+
244
+ ## Guia completo: criando e usando uma imagem hardened do zero
245
+
246
+ Uma sessão de terminal única, do gerador até a imagem em produção. Todo
247
+ output abaixo é real — rodado neste repositório, com Trivy de verdade.
248
+
249
+ ### 1. Escolher sistema operacional, runtime e pacotes — antes do build
250
+
251
+ A pergunta certa não é "quais pacotes eu tiro depois", é "quais eu realmente
252
+ preciso". `base-image` faz essa escolha acontecer antes de qualquer coisa
253
+ existir: sem `--with`, ele mostra um menu com o custo de cada pacote em
254
+ superfície de ataque, não só o que ele serve.
255
+
256
+ ```console
257
+ $ dockerls base-image --os alpine --runtime node
258
+
259
+ Packages in the base image
260
+ Each one exists in every application that consumes this base, and every CVE in
261
+ it becomes triage for someone who does not even know it is there.
262
+
263
+ 1. ca-certificates (already present in most bases)
264
+ used for: validating TLS when talking to any HTTPS service
265
+ custa: practically none; without it every TLS connection fails
266
+ verification
267
+ 2. tzdata
268
+ used for: time zones; without it the container stays on UTC and local
269
+ dates are wrong
270
+ custa: a few MB of data, no new executable
271
+ 3. curl
272
+ used for: HTTP HEALTHCHECK and network diagnostics
273
+ custa: a full HTTP client inside the container -- what an attacker uses
274
+ to fetch the second stage
275
+ 4. wget
276
+ used for: an alternative to curl for downloading files
277
+ custa: the same cost as curl; having both doubles the surface, not the
278
+ use
279
+ 5. bash
280
+ used for: scripts relying on features the Alpine `sh` does not have
281
+ custa: a more capable shell is a more useful shell for whoever breaks in
282
+ ...
283
+ 9. tini
284
+ used for: a minimal init that forwards signals and reaps orphaned
285
+ processes
286
+ custa: almost nothing, and it fixes the pid 1 that ignores SIGTERM
287
+
288
+ Comma-separated numbers (empty = no packages): 1,2,9
289
+ ```
290
+
291
+ Repare no `curl`: o propósito ("HEALTHCHECK e diagnóstico de rede") é
292
+ legítimo, mas o custo dito ali do lado é o mesmo que um atacante usa pra
293
+ buscar o segundo estágio de um ataque. O menu não esconde isso pra depois —
294
+ mostra na hora de marcar.
295
+
296
+ Em pipeline não tem menu pra responder. `--with` aceita a mesma lista
297
+ separada por vírgula e pula direto pro Dockerfile:
298
+
299
+ ```console
300
+ $ dockerls base-image --os alpine --runtime node \
301
+ --with "ca-certificates,tzdata,tini" -o Dockerfile \
302
+ --owner "team-x" --title minhaapp
303
+
304
+ npm and yarn will be removed from the final image (--keep-manager keeps them).
305
+
306
+ Dockerfile written to Dockerfile.
307
+
308
+ Next step
309
+ dockerls build -t minhaapp:1.0 --fail-on critical .
310
+ Building and scanning is what turns this recipe into a claim about security;
311
+ until then it is only an intention.
312
+ ```
313
+
314
+ Existem três pacotes que esse catálogo se recusa a oferecer, mesmo por
315
+ `--with` — são recusas documentadas, não omissões:
316
+
317
+ | Pacote | Por que não |
318
+ |---|---|
319
+ | `sudo` | numa imagem que já roda sem privilégio, `sudo` existe pra cruzar a fronteira que acabou de ser estabelecida — e é setuid pra isso |
320
+ | `su-exec` | trocar de usuário em runtime desfaz o `USER` da imagem; se o processo precisa de outro usuário, declare isso no `USER` |
321
+ | `docker` | o cliente Docker dentro do container implica acesso ao socket do daemon, que equivale a root no host |
322
+
323
+ ### 2. A versão do runtime vem fixa por família — trocando e resolvendo o digest de novo
324
+
325
+ Cada combinação de `--os`/`--runtime` mapeia pra uma versão específica,
326
+ travada no catálogo (`RUNTIME_BASES`, em
327
+ `dockerls/domain/value_objects/base_recipe.py`) — não é um parâmetro:
328
+ `node:22-alpine`, `python:3.12-alpine`, `golang:1.23-alpine`,
329
+ `eclipse-temurin:21-jre-alpine`, e o equivalente em Debian/Ubuntu/distroless
330
+ pra cada um. Se você precisa de outra versão, o caminho é editar a linha
331
+ `FROM` manualmente e resolver o digest de novo:
332
+
333
+ ```console
334
+ $ sed -i 's/FROM node:22-alpine@\${BASE_DIGEST}/FROM node:20-alpine/; s/ARG BASE_DIGEST=.*/ARG BASE_DIGEST=/' Dockerfile
335
+ $ dockerls base .
336
+
337
+ Dockerfile
338
+
339
+ line 14 UNPINNED
340
+ node:20-alpine
341
+ moving tag, no digest: what you tested and what goes to production can be
342
+ different bytes with no change on your part
343
+ ->
344
+ node:20-alpine@sha256:fb4cd12c85ee03686f6af5362a0b0d56d50c58a04632e6c0fb8363f609
345
+ 372293 (line 14)
346
+
347
+ 1 without a digest
348
+
349
+ 1 update(s) written to Dockerfile.
350
+ Rebuild and scan before publishing: changing the base digest changes the image,
351
+ and only a scan tells you whether for the better.
352
+ ```
353
+
354
+ `base` não sabe (nem tenta adivinhar) se a troca de versão é segura — ele só
355
+ garante que, seja qual for a tag, ela fica pinada por digest antes de ir pra
356
+ frente. A resposta sobre segurança vem do scan, no passo 5.
357
+
358
+ ### 3. Nota pra quem usa PowerShell
359
+
360
+ `--with ""` falha no PowerShell com `Got unexpected extra argument(s)`. Não é
361
+ bug do DockerLs: o PowerShell descarta argumentos de string vazia ao chamar
362
+ executáveis nativos, e isso empurra o parsing dos flags seguintes. A forma
363
+ correta é `--with=` (sem espaço, sem aspas) ou, se precisar passar outros
364
+ argumentos complicados, `dockerls --% base-image ...` pra desligar o parsing
365
+ do PowerShell inteiro a partir dali.
366
+
367
+ ### 4. Validar antes de construir
368
+
369
+ ```console
370
+ $ dockerls analyze-dockerfile .
371
+
372
+ Summary: 9 passed | 4 warnings | 0 errors
373
+
374
+ PASS base_image_pinned Base image tag is not 'latest' (still a
375
+ moving tag -- `dockerls base` pins it by
376
+ digest)
377
+ PASS non_root_user Container runs as non-root user: node
378
+ WARN multi_stage_build Single-stage build detected
379
+ PASS secrets_not_in_env No obvious secrets in ENV variables or ARG
380
+ defaults
381
+ WARN package_cache_clean Package manager cache not cleaned
382
+ WARN healthcheck_present No HEALTHCHECK directive
383
+ PASS security_labels Security labels present
384
+ PASS minimal_base Using minimal base image
385
+ PASS no_sudo No sudo usage detected
386
+ WARN dockerignore_exists .dockerignore not found
387
+ PASS add_not_used_for_copy No ADD directives (COPY is used to bring
388
+ files in)
389
+ PASS no_unverified_remote_scr… No remote script is piped straight into a
390
+ shell
391
+ PASS no_setuid_binaries_added No setuid or setgid bit is set in the build
392
+
393
+ Security Score: 90/100 Tier: A Production Ready: Yes
394
+ ```
395
+
396
+ Isso roda sem Docker, sem scanner, sem rede — é análise estática do texto do
397
+ Dockerfile. Os warnings aqui (sem multi-stage, sem HEALTHCHECK, sem
398
+ `.dockerignore`) são exatamente o que aparece de novo como sugestão depois do
399
+ build, no passo 5.
400
+
401
+ ### 5. Build com portão de segurança
402
+
403
+ `--production` liga de uma vez o perfil inteiro: gate em critical, exige que
404
+ o scan realmente tenha rodado, bases pinadas por digest, usuário
405
+ não-privilegiado, procedência verificada (hash do Dockerfile, do contexto e
406
+ da imagem final, amarrados), labels de ownership obrigatórias e atribuição de
407
+ findings (base vs. suas camadas). `--fail-on critical,kev` soma mais um
408
+ critério: falhar também se algum CVE encontrado está no catálogo CISA KEV —
409
+ sendo explorado ativamente, mesmo que não seja CRITICAL.
410
+
411
+ ```console
412
+ $ dockerls build . -t minhaapp:1.0 --production --fail-on critical,kev `
413
+ --owner "team-x" `
414
+ --source "https://github.com/suaorg/minhaapp" `
415
+ --security-contact "security@suaorg.com"
416
+
417
+ Production profile
418
+ fail_on critical
419
+ require_scan True
420
+ require_pinned_bases True
421
+ require_nonroot True
422
+ required_labels org.opencontainers.image.source, org.opencontainers.image.vendor, security.contact
423
+ require_provenance True
424
+
425
+ ╭──────────────────╮
426
+ │ Build Successful │
427
+ │ minhaapp:1.0 │
428
+ ╰──────────────────╯
429
+
430
+ ╭────────────────────────╮
431
+ │ Security Score: 85/100 │
432
+ │ Tier: B │
433
+ ╰────────────────────────╯
434
+
435
+ Validation: 8 passed | 5 warnings | 0 errors
436
+
437
+ ╭───────────────────────╮
438
+ │ Security Scan Results │
439
+ ╰───────────────────────╯
440
+ CRITICAL: 0
441
+ HIGH: 0
442
+ MEDIUM: 0
443
+ LOW: 0
444
+
445
+ ╭────────────────────────╮
446
+ │ Supply chain: VERIFIED │
447
+ ╰────────────────────────╯
448
+ input and output digested, and the input did not change during the build
449
+
450
+ INPUT (measured before the build)
451
+ Dockerfile sha256:e696d147012323b8b1c27de847b48f566ab4a8282b2377ba00fe35215a71a249
452
+ Contexto sha256:a8d265c6ff3c1a57b43ad00c24f9d07b13531923d66acaa5948c85697476252c (1 files)
453
+
454
+ OUTPUT (measured after the build)
455
+ Image sha256:5e5a079bbd616d166b155f15dac48c9c603a9d605876c732fde620a7aa7958bc
456
+ ```
457
+
458
+ Sem `--owner`, `--source` e `--security-contact`, esse mesmo comando falha —
459
+ de propósito: `required_labels` é parte do perfil `--production`, e o motivo
460
+ está no próprio erro quando isso acontece: "sem isso ninguém sabe pra quem
461
+ ligar quando essa imagem aparecer num alerta às três da manhã".
462
+
463
+ ### 6. Usando a imagem depois de construída
464
+
465
+ ```console
466
+ $ docker run --rm minhaapp:1.0 id
467
+ uid=1000(node) gid=1000(node) groups=1000(node),1000(node)
468
+ ```
469
+
470
+ `uid=1000`, não `uid=0`. É o `USER node` do Dockerfile confirmado em
471
+ execução, não só lido no texto — a mesma checagem que `non_root_user` faz de
472
+ forma estática no passo 4, agora contra o container de verdade.
473
+
474
+ ### 7. Fechando o loop
475
+
476
+ ```console
477
+ $ dockerls analyze minhaapp:1.0
478
+
479
+ Analysis: minhaapp:1.0
480
+
481
+ Score 96.0
482
+ Tier A
483
+ Critical 0
484
+ High 0
485
+ Medium 0
486
+ Low 0
487
+ Total Vulns 0
488
+ Fixable 0 (n/a)
489
+ Remediation Score 100/100
490
+ EOL No
491
+ LTS No
492
+ Scanner trivy
493
+ ```
494
+
495
+ O mesmo `analyze` que você rodaria contra `node:22-alpine` pra decidir se
496
+ confia nela funciona igual contra o que você acabou de construir. Não existe
497
+ um comando separado pra "auditar a própria imagem" — é o mesmo raio-x, na
498
+ mesma régua.
499
+
500
+ ---
501
+
502
+ ## Configuração
503
+
504
+ Resolvida nesta ordem: flag na linha de comando → variável de ambiente →
505
+ `~/.config/dockerls/config.toml` (ou `$XDG_CONFIG_HOME/...`) → padrão
506
+ embutido.
507
+
508
+ ```toml
509
+ # ~/.config/dockerls/config.toml
510
+ max_tags = 200
511
+ workers = 20
512
+ log_level = "DEBUG"
513
+ ```
514
+
515
+ Variáveis de ambiente mais usadas:
516
+
517
+ | Variável | Pra quê |
518
+ |---|---|
519
+ | `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN` | Autenticação no Docker Hub |
520
+ | `DOCKERLS_ENABLE_THREAT_INTEL` | `false` desativa as consultas a CISA KEV / EPSS / Exploit-DB |
521
+ | `DOCKERLS_GITHUB_TOKEN` | Token só-leitura pra elevar o limite de requisições do catálogo DHI |
522
+ | `DOCKERLS_<NOME_DA_CONFIG>` | Sobrescreve qualquer configuração (ex.: `DOCKERLS_MAX_TAGS=200`) |
523
+
524
+ Toda a lista de configurações, com valores padrão, está na
525
+ **[referência completa](docs/REFERENCE.md#configuração)**.
526
+
527
+ ---
528
+
529
+ ## Exit codes (pra CI)
530
+
531
+ A maioria dos comandos segue o mesmo contrato: `0` quando está tudo dentro
532
+ do esperado, `1` quando é uma falha técnica (nada foi medido — scanner
533
+ ausente, rede indisponível) **ou** quando `--fail-on` foi violado, e um
534
+ código próprio (`2` ou `3`, dependendo do comando) quando *foi medido* e o
535
+ resultado não bate com o que você pediu — por exemplo, nenhuma tag atingiu
536
+ o baseline em `recommend`. A distinção que importa: nada nesse contrato
537
+ confunde "não consegui olhar" com "olhei, e é inseguro".
538
+
539
+ ```bash
540
+ dockerls recommend node --max-critical 0
541
+ echo $? # 0 = achou uma imagem dentro do baseline | 2 = achou candidatas, nenhuma dentro do baseline
542
+ ```
543
+
544
+ ---
545
+
546
+ ## Desenvolvimento
547
+
548
+ ```bash
549
+ make dev # instala as dependências de desenvolvimento
550
+ make test # roda os testes
551
+ make lint # roda o linter
552
+ make audit # roda tudo: lint + tipos + testes + segurança
553
+ make engine # compila a engine em Go (opcional, precisa de Go 1.24+)
554
+ ```
555
+
556
+ Mais detalhes sobre CI/CD, arquitetura interna e como contribuir estão na
557
+ [referência completa](docs/REFERENCE.md#desenvolvimento).
558
+
559
+ ---
560
+
561
+ ## Licença
562
+
563
+ MIT. Veja [LICENSE](LICENSE).