Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ inputs:
required: false
default: ''
framework:
description: 'Framework (auto, terraform, kubernetes, cloudformation, helm)'
description: 'Framework (auto, terraform, kubernetes, cloudformation, helm, all)'
required: false
default: 'auto'
download-external-modules:
Expand Down
2 changes: 1 addition & 1 deletion cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def setup_args():
parser.add_argument(
"--framework",
default="auto",
choices=["auto", "terraform", "kubernetes", "cloudformation", "helm"],
choices=["auto", "terraform", "kubernetes", "cloudformation", "helm", "all"],
help="IaC framework type (default: auto-detect)"
)

Expand Down
14 changes: 11 additions & 3 deletions scanner/image_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ def find_compose_files(directory_path: str) -> List[str]:

for root, dirs, files in os.walk(directory_path):
for file in files:
if file in compose_patterns or file.startswith('docker-compose'):
compose_files.append(os.path.join(root, file))
if file.endswith(('.yml', '.yaml')):
if file in compose_patterns or file.startswith('docker-compose') or file.startswith('compose'):
compose_files.append(os.path.join(root, file))

return compose_files

Expand All @@ -38,7 +39,14 @@ def find_kubernetes_files(directory_path: str) -> List[str]:
def filter_container_files(files: List[str]) -> tuple[List[str], List[str]]:
"""Filter a list of files into Docker Compose and Kubernetes files."""
compose_patterns = ['docker-compose.yml', 'docker-compose.yaml', 'compose.yml', 'compose.yaml']
compose_files = [f for f in files if os.path.basename(f) in compose_patterns or os.path.basename(f).startswith('docker-compose')]
compose_files = [
f for f in files
if f.endswith(('.yml', '.yaml')) and (
os.path.basename(f) in compose_patterns
or os.path.basename(f).startswith('docker-compose')
or os.path.basename(f).startswith('compose')
)
]

potential_k8s = [f for f in files if f.endswith(('.yml', '.yaml')) and f not in compose_files]
k8s_files = []
Expand Down
52 changes: 46 additions & 6 deletions scanner/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ def detect_framework(path: str = None, files: list = None) -> str:
- 'kubernetes'
- 'cloudformation'
- 'helm'
- 'all' (fallback for Docker/secrets/actions/etc.)
"""
tf_files = 0
k8s_files = 0
cfn_files = 0
helm_files = 0

scan_files = []
if files:
Expand All @@ -44,6 +46,8 @@ def detect_framework(path: str = None, files: list = None) -> str:
file = os.path.basename(full_path)
if file.endswith('.tf'):
tf_files += 1
elif file == 'Chart.yaml' or file == 'Chart.yml':
helm_files += 1
elif file.endswith(('.yml', '.yaml')):
# Check file content for better detection
try:
Expand All @@ -56,12 +60,16 @@ def detect_framework(path: str = None, files: list = None) -> str:
except Exception:
continue

if k8s_files > tf_files and k8s_files > cfn_files:
if k8s_files > tf_files and k8s_files > cfn_files and k8s_files > helm_files:
return 'kubernetes'
if cfn_files > tf_files:
if cfn_files > tf_files and cfn_files > helm_files:
return 'cloudformation'
if helm_files > tf_files:
return 'helm'
if tf_files > 0:
return 'terraform'

return 'terraform'
return 'all'

def count_resources(path=None, framework='terraform', files=None):
"""
Expand All @@ -85,7 +93,7 @@ def count_resources(path=None, framework='terraform', files=None):
for file in f_list:
scan_files.append(os.path.join(root, file))

if framework == 'terraform':
if framework in ('terraform', 'all'):
for full_path in scan_files:
if full_path.endswith('.tf'):
try:
Expand All @@ -97,7 +105,8 @@ def count_resources(path=None, framework='terraform', files=None):
resource_count += len(matches)
except Exception:
continue
elif framework == 'kubernetes':

if framework in ('kubernetes', 'all'):
from scanner.image_utils import find_kubernetes_files
if files:
k8s_files = [f for f in files if f.endswith(('.yml', '.yaml'))]
Expand All @@ -115,6 +124,26 @@ def count_resources(path=None, framework='terraform', files=None):
resource_count += 1
except Exception:
continue

if framework in ('containers', 'all'):
from scanner.image_utils import find_compose_files
if files:
from scanner.image_utils import filter_container_files
compose_files, _ = filter_container_files(files)
else:
compose_files = find_compose_files(path)

for compose_file in compose_files:
try:
import yaml
with open(compose_file, 'r', encoding='utf-8') as f:
compose_data = yaml.safe_load(f)
if compose_data and isinstance(compose_data, dict) and 'services' in compose_data:
services = compose_data['services']
if isinstance(services, dict):
resource_count += len(services)
except Exception:
continue

return resource_count

Expand Down Expand Up @@ -143,7 +172,7 @@ def resolve_included_paths(base_path, included_paths):
elif os.path.isdir(full_path):
for root, dirs, files in os.walk(full_path):
for file in files:
if file.endswith(valid_extensions) or file.startswith('docker-compose'):
if file.endswith(valid_extensions) or file.startswith('docker-compose') or file.startswith('compose'):
resolved_files.append(os.path.join(root, file))

return list(set(resolved_files))
Expand Down Expand Up @@ -290,6 +319,17 @@ def scan_directory(path, scanner_type='regex', framework='terraform', download_e
extra_recommendations.extend(scout_recommendations)
except Exception as e:
print(f"Warning: Docker Scout scan failed: {e}")
elif is_grype_available():
print("\n[i] Docker Scout is not installed, falling back to Grype scanner...")
try:
from scanner.grype_scanner import run_grype_scan
grype_results = run_grype_scan(path, files=resolved_files)
for result in grype_results:
result['scanner'] = 'grype'
results.extend(grype_results)
print(f" Grype scan completed with {len(grype_results)} findings.")
except Exception as grype_e:
print(f" Grype fallback failed: {grype_e}")
else:
print("Warning: Docker Scout is not installed. See https://docs.docker.com/scout/ for installation")

Expand Down
Loading