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.
- dockerls-1.0.0/LICENSE +21 -0
- dockerls-1.0.0/PKG-INFO +563 -0
- dockerls-1.0.0/README.md +512 -0
- dockerls-1.0.0/dockerls/__init__.py +31 -0
- dockerls-1.0.0/dockerls/application/__init__.py +0 -0
- dockerls-1.0.0/dockerls/application/dto/__init__.py +3 -0
- dockerls-1.0.0/dockerls/application/dto/analysis.py +257 -0
- dockerls-1.0.0/dockerls/application/services/__init__.py +0 -0
- dockerls-1.0.0/dockerls/application/services/alternatives_lookup.py +167 -0
- dockerls-1.0.0/dockerls/application/services/composite_repository.py +106 -0
- dockerls-1.0.0/dockerls/application/services/cross_validation.py +233 -0
- dockerls-1.0.0/dockerls/application/services/ecosystems.py +350 -0
- dockerls-1.0.0/dockerls/application/services/fallback_scanner.py +97 -0
- dockerls-1.0.0/dockerls/application/services/hardening_analysis.py +174 -0
- dockerls-1.0.0/dockerls/application/services/migration.py +297 -0
- dockerls-1.0.0/dockerls/application/services/progress.py +56 -0
- dockerls-1.0.0/dockerls/application/services/remediation.py +321 -0
- dockerls-1.0.0/dockerls/application/services/scan_history_store.py +88 -0
- dockerls-1.0.0/dockerls/application/services/scanner_factory.py +88 -0
- dockerls-1.0.0/dockerls/application/services/source_registry.py +151 -0
- dockerls-1.0.0/dockerls/application/services/tag_history_store.py +76 -0
- dockerls-1.0.0/dockerls/application/services/teardown.py +50 -0
- dockerls-1.0.0/dockerls/application/services/verdict.py +298 -0
- dockerls-1.0.0/dockerls/application/services/version_discovery.py +108 -0
- dockerls-1.0.0/dockerls/application/use_cases/__init__.py +0 -0
- dockerls-1.0.0/dockerls/application/use_cases/analyze_dockerfile.py +103 -0
- dockerls-1.0.0/dockerls/application/use_cases/analyze_image.py +173 -0
- dockerls-1.0.0/dockerls/application/use_cases/build_image.py +1795 -0
- dockerls-1.0.0/dockerls/application/use_cases/compare_images.py +91 -0
- dockerls-1.0.0/dockerls/application/use_cases/fleet_scan.py +240 -0
- dockerls-1.0.0/dockerls/application/use_cases/recommend_images.py +1078 -0
- dockerls-1.0.0/dockerls/application/use_cases/registry_audit.py +133 -0
- dockerls-1.0.0/dockerls/application/use_cases/search_images.py +23 -0
- dockerls-1.0.0/dockerls/application/use_cases/upgrade_base.py +167 -0
- dockerls-1.0.0/dockerls/cache/__init__.py +0 -0
- dockerls-1.0.0/dockerls/cache/sqlite_cache.py +184 -0
- dockerls-1.0.0/dockerls/cli/__init__.py +0 -0
- dockerls-1.0.0/dockerls/cli/analysis_baseline.py +98 -0
- dockerls-1.0.0/dockerls/cli/app.py +294 -0
- dockerls-1.0.0/dockerls/cli/commands/__init__.py +0 -0
- dockerls-1.0.0/dockerls/cli/commands/advisor.py +262 -0
- dockerls-1.0.0/dockerls/cli/commands/alternatives.py +291 -0
- dockerls-1.0.0/dockerls/cli/commands/analyze.py +429 -0
- dockerls-1.0.0/dockerls/cli/commands/analyze_dockerfile.py +104 -0
- dockerls-1.0.0/dockerls/cli/commands/base_cmd.py +244 -0
- dockerls-1.0.0/dockerls/cli/commands/base_image.py +551 -0
- dockerls-1.0.0/dockerls/cli/commands/build.py +1300 -0
- dockerls-1.0.0/dockerls/cli/commands/cache_cmd.py +104 -0
- dockerls-1.0.0/dockerls/cli/commands/compare.py +177 -0
- dockerls-1.0.0/dockerls/cli/commands/controls.py +110 -0
- dockerls-1.0.0/dockerls/cli/commands/doctor.py +566 -0
- dockerls-1.0.0/dockerls/cli/commands/export.py +81 -0
- dockerls-1.0.0/dockerls/cli/commands/fleet.py +159 -0
- dockerls-1.0.0/dockerls/cli/commands/health.py +84 -0
- dockerls-1.0.0/dockerls/cli/commands/login.py +53 -0
- dockerls-1.0.0/dockerls/cli/commands/policy_cmd.py +111 -0
- dockerls-1.0.0/dockerls/cli/commands/provenance_cmd.py +162 -0
- dockerls-1.0.0/dockerls/cli/commands/recommend.py +761 -0
- dockerls-1.0.0/dockerls/cli/commands/registry_audit_cmd.py +103 -0
- dockerls-1.0.0/dockerls/cli/commands/sbom.py +144 -0
- dockerls-1.0.0/dockerls/cli/commands/search.py +86 -0
- dockerls-1.0.0/dockerls/cli/commands/verify.py +115 -0
- dockerls-1.0.0/dockerls/cli/commands/version.py +12 -0
- dockerls-1.0.0/dockerls/cli/commands/vex_cmd.py +117 -0
- dockerls-1.0.0/dockerls/cli/dependencies.py +530 -0
- dockerls-1.0.0/dockerls/cli/image_names.py +79 -0
- dockerls-1.0.0/dockerls/cli/options.py +42 -0
- dockerls-1.0.0/dockerls/cli/progress.py +145 -0
- dockerls-1.0.0/dockerls/cli/publish_prompt.py +123 -0
- dockerls-1.0.0/dockerls/cli/rendering.py +214 -0
- dockerls-1.0.0/dockerls/cli/runtime.py +65 -0
- dockerls-1.0.0/dockerls/cli/scan_failure.py +71 -0
- dockerls-1.0.0/dockerls/cli/text.py +39 -0
- dockerls-1.0.0/dockerls/cli/validators.py +35 -0
- dockerls-1.0.0/dockerls/cli/vulnerability_view.py +154 -0
- dockerls-1.0.0/dockerls/domain/__init__.py +0 -0
- dockerls-1.0.0/dockerls/domain/entities/__init__.py +75 -0
- dockerls-1.0.0/dockerls/domain/entities/declared_metadata.py +147 -0
- dockerls-1.0.0/dockerls/domain/entities/dockerfile_analysis.py +318 -0
- dockerls-1.0.0/dockerls/domain/entities/image.py +109 -0
- dockerls-1.0.0/dockerls/domain/entities/image_facts.py +137 -0
- dockerls-1.0.0/dockerls/domain/entities/recommendation.py +33 -0
- dockerls-1.0.0/dockerls/domain/entities/scan_result.py +129 -0
- dockerls-1.0.0/dockerls/domain/entities/vulnerability.py +232 -0
- dockerls-1.0.0/dockerls/domain/interfaces/__init__.py +17 -0
- dockerls-1.0.0/dockerls/domain/interfaces/cache_store.py +18 -0
- dockerls-1.0.0/dockerls/domain/interfaces/dockerfile_validator.py +99 -0
- dockerls-1.0.0/dockerls/domain/interfaces/eol_checker.py +11 -0
- dockerls-1.0.0/dockerls/domain/interfaces/image_repository.py +15 -0
- dockerls-1.0.0/dockerls/domain/interfaces/scanner.py +15 -0
- dockerls-1.0.0/dockerls/domain/security_controls.py +362 -0
- dockerls-1.0.0/dockerls/domain/value_objects/__init__.py +49 -0
- dockerls-1.0.0/dockerls/domain/value_objects/attack_surface.py +198 -0
- dockerls-1.0.0/dockerls/domain/value_objects/base_recipe.py +600 -0
- dockerls-1.0.0/dockerls/domain/value_objects/base_upgrade.py +292 -0
- dockerls-1.0.0/dockerls/domain/value_objects/build_labels.py +99 -0
- dockerls-1.0.0/dockerls/domain/value_objects/build_policy.py +412 -0
- dockerls-1.0.0/dockerls/domain/value_objects/confidence.py +156 -0
- dockerls-1.0.0/dockerls/domain/value_objects/fleet.py +174 -0
- dockerls-1.0.0/dockerls/domain/value_objects/gate.py +327 -0
- dockerls-1.0.0/dockerls/domain/value_objects/hardening.py +303 -0
- dockerls-1.0.0/dockerls/domain/value_objects/image_reference.py +90 -0
- dockerls-1.0.0/dockerls/domain/value_objects/inheritance.py +352 -0
- dockerls-1.0.0/dockerls/domain/value_objects/network_policy.py +280 -0
- dockerls-1.0.0/dockerls/domain/value_objects/production_readiness.py +145 -0
- dockerls-1.0.0/dockerls/domain/value_objects/provenance.py +211 -0
- dockerls-1.0.0/dockerls/domain/value_objects/recipe_diff.py +188 -0
- dockerls-1.0.0/dockerls/domain/value_objects/registry_audit.py +195 -0
- dockerls-1.0.0/dockerls/domain/value_objects/registry_target.py +225 -0
- dockerls-1.0.0/dockerls/domain/value_objects/remediation_score.py +62 -0
- dockerls-1.0.0/dockerls/domain/value_objects/scan_history.py +183 -0
- dockerls-1.0.0/dockerls/domain/value_objects/scan_plan.py +193 -0
- dockerls-1.0.0/dockerls/domain/value_objects/scanner_db.py +143 -0
- dockerls-1.0.0/dockerls/domain/value_objects/security_score.py +160 -0
- dockerls-1.0.0/dockerls/domain/value_objects/security_tier.py +122 -0
- dockerls-1.0.0/dockerls/domain/value_objects/tag_history.py +180 -0
- dockerls-1.0.0/dockerls/domain/value_objects/tool_release.py +253 -0
- dockerls-1.0.0/dockerls/domain/value_objects/tristate.py +47 -0
- dockerls-1.0.0/dockerls/domain/value_objects/vex.py +249 -0
- dockerls-1.0.0/dockerls/exit_codes.py +23 -0
- dockerls-1.0.0/dockerls/exporters/__init__.py +0 -0
- dockerls-1.0.0/dockerls/exporters/base.py +17 -0
- dockerls-1.0.0/dockerls/exporters/csv_exporter.py +85 -0
- dockerls-1.0.0/dockerls/exporters/factory.py +31 -0
- dockerls-1.0.0/dockerls/exporters/html_exporter.py +105 -0
- dockerls-1.0.0/dockerls/exporters/json_exporter.py +19 -0
- dockerls-1.0.0/dockerls/exporters/markdown_exporter.py +84 -0
- dockerls-1.0.0/dockerls/exporters/sarif_exporter.py +245 -0
- dockerls-1.0.0/dockerls/infrastructure/__init__.py +0 -0
- dockerls-1.0.0/dockerls/infrastructure/config/__init__.py +0 -0
- dockerls-1.0.0/dockerls/infrastructure/config/policy_file.py +165 -0
- dockerls-1.0.0/dockerls/infrastructure/config/settings.py +197 -0
- dockerls-1.0.0/dockerls/infrastructure/database/__init__.py +0 -0
- dockerls-1.0.0/dockerls/infrastructure/database/models.py +78 -0
- dockerls-1.0.0/dockerls/infrastructure/dockerfile_validator.py +1899 -0
- dockerls-1.0.0/dockerls/infrastructure/evidence.py +99 -0
- dockerls-1.0.0/dockerls/infrastructure/hashing.py +165 -0
- dockerls-1.0.0/dockerls/infrastructure/logging/__init__.py +0 -0
- dockerls-1.0.0/dockerls/infrastructure/logging/setup.py +98 -0
- dockerls-1.0.0/dockerls/infrastructure/network/__init__.py +0 -0
- dockerls-1.0.0/dockerls/infrastructure/network/guarded_client.py +107 -0
- dockerls-1.0.0/dockerls/infrastructure/network/host_guard.py +117 -0
- dockerls-1.0.0/dockerls/infrastructure/redaction.py +135 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/alpine.dockerfile +44 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/debian.dockerfile +45 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/distroless.dockerfile +34 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/go-alpine.dockerfile +52 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/go-debian.dockerfile +54 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/go-distroless.dockerfile +43 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/go-scratch.dockerfile +48 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/go.dockerfile +50 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/gradle-alpine.dockerfile +51 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/gradle.dockerfile +52 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/java-alpine.dockerfile +50 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/java-debian.dockerfile +50 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/java-distroless.dockerfile +39 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/java-ubuntu.dockerfile +54 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/java.dockerfile +60 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/maven-alpine.dockerfile +56 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/maven.dockerfile +57 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/node-alpine.dockerfile +47 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/node-debian.dockerfile +54 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/node-distroless.dockerfile +46 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/node-ubuntu.dockerfile +63 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/node.dockerfile +61 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/php-alpine.dockerfile +45 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/php-debian.dockerfile +45 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/php-ubuntu.dockerfile +49 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/php.dockerfile +44 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/python-alpine.dockerfile +51 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/python-debian.dockerfile +54 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/python-distroless.dockerfile +51 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/python-ubuntu.dockerfile +60 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/python.dockerfile +58 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/ruby-alpine.dockerfile +48 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/ruby-debian.dockerfile +50 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/rust-alpine.dockerfile +50 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/rust-debian.dockerfile +48 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/rust-scratch.dockerfile +44 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/rust.dockerfile +54 -0
- dockerls-1.0.0/dockerls/infrastructure/templates/hardening/ubuntu.dockerfile +49 -0
- dockerls-1.0.0/dockerls/infrastructure/toolchain/__init__.py +0 -0
- dockerls-1.0.0/dockerls/infrastructure/toolchain/db_metadata.py +115 -0
- dockerls-1.0.0/dockerls/infrastructure/toolchain/installer.py +435 -0
- dockerls-1.0.0/dockerls/integrations/__init__.py +0 -0
- dockerls-1.0.0/dockerls/integrations/dhi/__init__.py +0 -0
- dockerls-1.0.0/dockerls/integrations/dhi/catalog.py +457 -0
- dockerls-1.0.0/dockerls/integrations/dhi/definition.py +151 -0
- dockerls-1.0.0/dockerls/integrations/dhi/repository.py +238 -0
- dockerls-1.0.0/dockerls/integrations/dockerhub/__init__.py +0 -0
- dockerls-1.0.0/dockerls/integrations/dockerhub/client.py +318 -0
- dockerls-1.0.0/dockerls/integrations/dockerhub/urls.py +75 -0
- dockerls-1.0.0/dockerls/integrations/endoflife/__init__.py +0 -0
- dockerls-1.0.0/dockerls/integrations/endoflife/checker.py +216 -0
- dockerls-1.0.0/dockerls/integrations/engine/__init__.py +0 -0
- dockerls-1.0.0/dockerls/integrations/engine/batch.py +197 -0
- dockerls-1.0.0/dockerls/integrations/engine/client.py +330 -0
- dockerls-1.0.0/dockerls/integrations/engine/locator.py +96 -0
- dockerls-1.0.0/dockerls/integrations/exploitdb/__init__.py +0 -0
- dockerls-1.0.0/dockerls/integrations/exploitdb/client.py +271 -0
- dockerls-1.0.0/dockerls/integrations/grype/__init__.py +0 -0
- dockerls-1.0.0/dockerls/integrations/grype/scanner.py +336 -0
- dockerls-1.0.0/dockerls/integrations/registry/__init__.py +0 -0
- dockerls-1.0.0/dockerls/integrations/registry/hardened.py +284 -0
- dockerls-1.0.0/dockerls/integrations/registry/inspector.py +420 -0
- dockerls-1.0.0/dockerls/integrations/registry/oci.py +259 -0
- dockerls-1.0.0/dockerls/integrations/registry/private.py +79 -0
- dockerls-1.0.0/dockerls/integrations/registry/urls.py +36 -0
- dockerls-1.0.0/dockerls/integrations/scan_errors.py +67 -0
- dockerls-1.0.0/dockerls/integrations/scan_target.py +57 -0
- dockerls-1.0.0/dockerls/integrations/signing/__init__.py +0 -0
- dockerls-1.0.0/dockerls/integrations/signing/cosign.py +484 -0
- dockerls-1.0.0/dockerls/integrations/threat_intel/__init__.py +0 -0
- dockerls-1.0.0/dockerls/integrations/threat_intel/client.py +290 -0
- dockerls-1.0.0/dockerls/integrations/trivy/__init__.py +0 -0
- dockerls-1.0.0/dockerls/integrations/trivy/cache_pool.py +176 -0
- dockerls-1.0.0/dockerls/integrations/trivy/scanner.py +447 -0
- dockerls-1.0.0/dockerls/utils/__init__.py +0 -0
- dockerls-1.0.0/dockerls/utils/auth.py +108 -0
- dockerls-1.0.0/dockerls/utils/executables.py +39 -0
- dockerls-1.0.0/dockerls/utils/ignore_file.py +130 -0
- dockerls-1.0.0/dockerls/utils/rate_limit.py +130 -0
- dockerls-1.0.0/dockerls/utils/resources.py +183 -0
- dockerls-1.0.0/dockerls/utils/retry.py +31 -0
- dockerls-1.0.0/dockerls/utils/safe_yaml.py +166 -0
- dockerls-1.0.0/dockerls/utils/subprocess_runner.py +216 -0
- dockerls-1.0.0/dockerls/utils/validation.py +72 -0
- dockerls-1.0.0/dockerls.egg-info/PKG-INFO +563 -0
- dockerls-1.0.0/dockerls.egg-info/SOURCES.txt +233 -0
- dockerls-1.0.0/dockerls.egg-info/dependency_links.txt +1 -0
- dockerls-1.0.0/dockerls.egg-info/entry_points.txt +2 -0
- dockerls-1.0.0/dockerls.egg-info/requires.txt +25 -0
- dockerls-1.0.0/dockerls.egg-info/top_level.txt +1 -0
- dockerls-1.0.0/pyproject.toml +126 -0
- 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.
|
dockerls-1.0.0/PKG-INFO
ADDED
|
@@ -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
|
+
[](https://github.com/Ivomsantiago/DockerLs/actions/workflows/ci.yml)
|
|
55
|
+
[](https://github.com/Ivomsantiago/DockerLs/actions/workflows/codeql.yml)
|
|
56
|
+
[](https://www.python.org/)
|
|
57
|
+
[](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).
|