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
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
# This workflow runs on Pull Requests opened against MAIN.
# It will scan the incoming HEAD branch with Workbench.
# If Pending IDs or Policy Violations are found, the PR will be blocked.
# This workflow can be triggered to scan a branch and evaluate gates.
# The workflow will fail if Pending IDs or Policy Violations are found.

name: Scan Incoming PRs and Check Gates
name: Scan Branch and Evaluate Gates

on:
pull_request:
branches: main
on: workflow_dispatch

jobs:
workbench-scan:
Expand All @@ -24,9 +21,9 @@ jobs:
--api-token ${{ env.WORKBENCH_TOKEN }} \
scan-git \
--project-name $GITHUB_REPOSITORY \
--scan-name $GITHUB_HEAD_REF \
--scan-name $GITHUB_REF_NAME \
--git-url $GITHUB_SERVER_URL/$GITHUB_REPOSITORY \
--git-branch $GITHUB_HEAD_REF \
--git-branch $GITHUB_REF_NAME \
--git-depth 1 \
--id-reuse \
--id-reuse-type project \
Expand All @@ -52,6 +49,6 @@ jobs:
--api-token ${{ env.WORKBENCH_TOKEN }} \
evaluate-gates \
--project-name $GITHUB_REPOSITORY \
--scan-name $GITHUB_HEAD_REF \
--scan-name $GITHUB_REF_NAME \
--fail-on-pending \
--fail-on-policy
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# Alternative workflow using container approach with pre-built archive
# This workflow runs on Pull Requests opened against MAIN.
# It will scan only those files touched by the incoming HEAD branch using containers.
# It will scan only those files touched by the incoming HEAD branch.
# If Pending IDs or Policy Violations are found, the PR will be blocked.

name: Scan Diff of Incoming PRs
name: Scan Diff of PR Head

on:
pull_request:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This workflow runs if code is pushed to the MAIN branch.
# It will tell Workbench to clone the latest state of the branch and scan it.

name: Update Main Branch Scan on Push
name: Update Main Branch Scan

on:
push:
Expand Down
148 changes: 148 additions & 0 deletions tests/unit/cli/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import pytest
from unittest.mock import MagicMock, patch
import argparse
import os
import sys

# Add src to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..', 'src'))

from workbench_cli.cli import parse_cmdline_args


@pytest.fixture
def mock_path_exists():
"""Mock os.path.exists to return True by default."""
with patch('os.path.exists', return_value=True) as mock:
yield mock


@pytest.fixture
def base_args():
"""Base argument list with required credentials."""
return [
'workbench-cli',
'--api-url', 'https://test.com',
'--api-user', 'testuser',
'--api-token', 'testtoken'
]


@pytest.fixture
def arg_parser():
"""Create a fresh argument parser for each test."""
def _create_parser_with_args(args_list):
"""Parse arguments without affecting sys.argv."""
# Import inside function to avoid import order issues
from workbench_cli.cli import parse_cmdline_args
with patch('sys.argv', args_list):
return parse_cmdline_args()
return _create_parser_with_args


@pytest.fixture
def mock_main_dependencies():
"""Mock all main() function dependencies."""
mocks = {}

# Mock WorkbenchAPI
with patch("workbench_cli.main.WorkbenchAPI") as mock_wb:
mocks['workbench_api'] = mock_wb
mocks['workbench_instance'] = MagicMock()
mock_wb.return_value = mocks['workbench_instance']

# Mock all handlers
with patch("workbench_cli.main.handle_scan") as mock_scan:
mocks['handle_scan'] = mock_scan

with patch("workbench_cli.main.handle_scan_git") as mock_scan_git:
mocks['handle_scan_git'] = mock_scan_git

with patch("workbench_cli.main.handle_import_da") as mock_import:
mocks['handle_import_da'] = mock_import

with patch("workbench_cli.main.handle_show_results") as mock_show:
mocks['handle_show_results'] = mock_show

with patch("workbench_cli.main.handle_download_reports") as mock_download:
mocks['handle_download_reports'] = mock_download

with patch("workbench_cli.main.handle_evaluate_gates") as mock_gates:
mocks['handle_evaluate_gates'] = mock_gates

yield mocks


class ArgBuilder:
"""Builder pattern for constructing test arguments."""

def __init__(self):
self.args = [
'workbench-cli',
'--api-url', 'https://test.com',
'--api-user', 'testuser',
'--api-token', 'testtoken'
]

def scan(self, project='TestProject', scan='TestScan', path='.'):
self.args.extend(['scan', '--project-name', project, '--scan-name', scan, '--path', path])
return self

def scan_git(self, project='TestProject', scan='TestScan', git_url='https://git.com/repo.git'):
self.args.extend(['scan-git', '--project-name', project, '--scan-name', scan, '--git-url', git_url])
return self

def git_branch(self, branch='main'):
self.args.extend(['--git-branch', branch])
return self

def git_tag(self, tag='v1.0'):
self.args.extend(['--git-tag', tag])
return self

def git_commit(self, commit='abc123'):
self.args.extend(['--git-commit', commit])
return self

def import_da(self, project='TestProject', scan='TestScan', path='results.json'):
self.args.extend(['import-da', '--project-name', project, '--scan-name', scan, '--path', path])
return self

def download_reports(self, scope='scan'):
self.args.extend(['download-reports', '--report-scope', scope])
return self

def project_name(self, name):
self.args.extend(['--project-name', name])
return self

def scan_name(self, name):
self.args.extend(['--scan-name', name])
return self

def show_results(self, project='TestProject', scan='TestScan'):
self.args.extend(['show-results', '--project-name', project, '--scan-name', scan])
return self

def show_licenses(self):
self.args.append('--show-licenses')
return self

def id_reuse(self, reuse_type='any', source=None):
self.args.extend(['--id-reuse', '--id-reuse-type', reuse_type])
if source:
self.args.extend(['--id-reuse-source', source])
return self

def log_level(self, level='INFO'):
self.args.extend(['--log', level])
return self

def build(self):
return self.args.copy()


@pytest.fixture
def args():
"""Fixture providing the ArgBuilder for constructing test arguments."""
return ArgBuilder
Loading
Loading