diff --git a/.github/actions/sca/fossa-scan/README.md b/.github/actions/sca/fossa-scan/README.md new file mode 100644 index 0000000..798b374 --- /dev/null +++ b/.github/actions/sca/fossa-scan/README.md @@ -0,0 +1,220 @@ +# FOSSA Scan Action + +A GitHub Action that runs FOSSA security and license compliance scanning with configurable parameters. + +## Overview + +This action uses a JSON-based configuration system (`fossa-params.json`) to dynamically map environment variables to FOSSA CLI flags, making it easy to add new parameters without modifying the action logic. + +## Configuration + +### Parameter Mapping (`fossa-params.json`) + +The action reads parameter definitions from `fossa-params.json`: + +```json +{ + "parameters": [ + { + "env": "SCA_FOSSA_CONFIG", + "flag": "--config", + "type": "value", + "description": "Path to custom .fossa.yml configuration file", + "example": "fossa.config=packages/my-package/.fossa.yml" + } + ] +} +``` + +**Field Definitions:** +- `env`: Environment variable name (automatically set by `sca-scan` action) +- `flag`: FOSSA CLI flag to use +- `type`: Either `"flag"` (boolean) or `"value"` (requires a value) +- `description`: Human-readable description +- `example`: Example usage via `additional_scan_params` + +### Parameter Types + +#### Type: `flag` (Boolean) +Only added to CLI if environment variable equals `"true"`. + +**Example:** +```yaml +additional_scan_params: | + fossa.analyze_debug=true +``` +Generates: `fossa analyze --debug` + +#### Type: `value` (String) +Added to CLI with the provided value if non-empty. + +**Example:** +```yaml +additional_scan_params: | + fossa.config=sam-mongodb/.fossa.yml + fossa.path=sam-mongodb +``` +Generates: `fossa analyze --config sam-mongodb/.fossa.yml --path sam-mongodb` + +## Usage + +### Basic Usage + +```yaml +- name: FOSSA Scan + uses: SolaceDev/solace-public-workflows/.github/actions/sca/sca-scan@main + with: + scanners: "fossa" + fossa_api_key: ${{ secrets.FOSSA_API_KEY }} +``` + +### With Custom Parameters + +```yaml +- name: FOSSA Scan (Monorepo Plugin) + uses: SolaceDev/solace-public-workflows/.github/actions/sca/sca-scan@main + with: + scanners: "fossa" + additional_scan_params: | + fossa.path=sam-mongodb + fossa.config=sam-mongodb/.fossa.yml + fossa.project=my-plugin + fossa.branch=PR + fossa.revision=${{ github.sha }} + fossa_api_key: ${{ secrets.FOSSA_API_KEY }} +``` + +## Available Parameters + +| Parameter | Type | FOSSA Flag | Commands | Description | +|-----------|------|------------|----------|-------------| +| `fossa.analyze_debug` | flag | `--debug` | `analyze` | Enable debug logging | +| `fossa.branch` | value | `--branch` | `analyze` | Branch name for tracking | +| `fossa.revision` | value | `--revision` | `analyze`, `test` | Git commit SHA | +| `fossa.project` | value | `--project` | `analyze`, `test` | Override project name/ID | +| `fossa.path` | value | N/A (working directory) | `analyze`, `test` | Base directory to scan from | +| `fossa.config` | value | `--config` | `analyze`, `test` | Path to `.fossa.yml` (optional if using fossa.path) | +| `fossa.unpack_archives` | flag | `--unpack-archives` | `analyze` | Unpack and scan archives | +| `fossa.without_default_filters` | flag | `--without-default-filters` | `analyze` | Disable default filters | +| `fossa.force_vendored_dependency_rescans` | flag | `--force-vendored-dependency-rescans` | `analyze` | Force rescan vendored deps | + +**Commands Column:** +- `analyze` - Used for the `fossa analyze` command (scans code and uploads results) +- `test` - Used for the `fossa test` command (checks scan results against policies) +- Both commands - Parameter is used by both commands + +**Special Parameters:** +- `fossa.path` - Sets the working directory for FOSSA commands. This is not a CLI flag but uses GitHub Actions' `working-directory` to change into the specified directory before running `fossa analyze` and `fossa test`. + - **Important:** If you specify `fossa.path`, FOSSA will automatically look for `.fossa.yml` in that directory. You only need `fossa.config` if your config file is in a different location or has a non-standard name. + - **Example:** `fossa.path=sam-bedrock-agent` will automatically use `sam-bedrock-agent/.fossa.yml` if it exists. + +See [fossa-params.json](./fossa-params.json) for the complete list with examples. + +## Adding New Parameters + +To add a new FOSSA CLI parameter, follow these steps: + +### 1. Update the JSON Configuration + +Add an entry to [`fossa-params.json`](./fossa-params.json): + +```json +{ + "env": "SCA_FOSSA_NEW_PARAM", + "flag": "--new-param", + "type": "value", + "commands": ["analyze", "test"], + "description": "Description of what this parameter does", + "example": "fossa.new_param=value" +} +``` + +**Field Guide:** +- `env`: Environment variable name (must start with `SCA_FOSSA_`) +- `flag`: FOSSA CLI flag (e.g., `--config`, `--path`) +- `type`: Either `"flag"` (boolean) or `"value"` (requires a value) +- `commands`: Array of FOSSA commands that support this parameter + - `["analyze"]` - Only used for `fossa analyze` + - `["test"]` - Only used for `fossa test` + - `["analyze", "test"]` - Used for both commands +- `description`: Human-readable description of the parameter +- `example`: Usage example via `additional_scan_params` + +### 2. Run the Test Suite + +Before committing, verify your changes work correctly: + +```bash +cd .github/actions/sca/fossa-scan +./test-parse-fossa-params.sh +``` + +Expected output: +``` +๐Ÿงช FOSSA Parameter Parser Test Suite +... +โœ… All tests passed! +``` + +### 3. (Optional) Add a Test Case + +For complex parameters, add a test case to [`test-parse-fossa-params.sh`](./test-parse-fossa-params.sh): + +```bash +test_your_new_parameter() { + echo "" + echo "Test: Your new parameter" + + export SCA_FOSSA_NEW_PARAM="test-value" + export FOSSA_PARAMS_CONFIG="$SCRIPT_DIR/fossa-params.json" + + source "$SCRIPT_DIR/parse-fossa-params.sh" + build_fossa_args > /dev/null + + assert_contains "$FOSSA_CLI_ARGS" "--new-param test-value" \ + "Should include --new-param with value" + + unset SCA_FOSSA_NEW_PARAM FOSSA_CLI_ARGS +} +``` + +Then add `test_your_new_parameter` to the test execution section. + +### 4. Update Documentation + +Add your parameter to the "Available Parameters" table in this README. + +### 5. Commit and Create PR + +```bash +git add fossa-params.json README.md +git commit -m "feat: Add support for --new-param FOSSA flag" +``` + +**That's it!** No code changes to `action.yaml` or `parse-fossa-params.sh` are needed - the JSON configuration is declarative and self-contained. + +## Architecture + +### Flow Diagram + +``` +User Workflow (sca-scan) + โ†“ + additional_scan_params: "fossa.config=path/.fossa.yml" + โ†“ + Converted to: SCA_FOSSA_CONFIG=path/.fossa.yml + โ†“ +fossa-scan Action + โ†“ + Reads: fossa-params.json + โ†“ + Maps: SCA_FOSSA_CONFIG โ†’ --config path/.fossa.yml + โ†“ + Executes: fossa analyze --config path/.fossa.yml +``` + +## Related Documentation + +- [FOSSA CLI Documentation](https://github.com/fossas/fossa-cli) +- [Parent SCA Scan Action](../sca-scan/) +- [FOSSA Parameter Config](./fossa-params.json) diff --git a/.github/actions/sca/fossa-scan/action.yaml b/.github/actions/sca/fossa-scan/action.yaml index a098892..9932264 100644 --- a/.github/actions/sca/fossa-scan/action.yaml +++ b/.github/actions/sca/fossa-scan/action.yaml @@ -12,53 +12,29 @@ runs: echo "Installing FOSSA CLI..." curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install-latest.sh | bash - SCA_FOSSA_ADDITIONAL_ARGS="" + # Use the parameter parser script for analyze command + export FOSSA_PARAMS_CONFIG="${GITHUB_ACTION_PATH}/fossa-params.json" + source "${GITHUB_ACTION_PATH}/parse-fossa-params.sh" - #if SCA_FOSSA_ANALYZE_DEBUG is set to true, add --debug to analyze args - if [ "${{ env.SCA_FOSSA_ANALYZE_DEBUG }}" == "true" ]; then - SCA_FOSSA_ADDITIONAL_ARGS="$SCA_FOSSA_ADDITIONAL_ARGS --debug" - fi - - # Set branch parameter if SCA_FOSSA_BRANCH environment variable is provided - if [ -n "${{ env.SCA_FOSSA_BRANCH }}" ]; then - SCA_FOSSA_ADDITIONAL_ARGS="$SCA_FOSSA_ADDITIONAL_ARGS --branch ${{ env.SCA_FOSSA_BRANCH }}" - fi - - # Set revision parameter if SCA_FOSSA_REVISION environment variable is provided - if [ -n "${{ env.SCA_FOSSA_REVISION }}" ]; then - SCA_FOSSA_ADDITIONAL_ARGS="$SCA_FOSSA_ADDITIONAL_ARGS --revision ${{ env.SCA_FOSSA_REVISION }}" - fi - - # Add --unpack-archives if SCA_FOSSA_UNPACK_ARCHIVES is set to true - if [ "${{ env.SCA_FOSSA_UNPACK_ARCHIVES }}" == "true" ]; then - SCA_FOSSA_ADDITIONAL_ARGS="$SCA_FOSSA_ADDITIONAL_ARGS --unpack-archives" - fi + # Build analyze args + build_fossa_args "analyze" + echo "SCA_FOSSA_ADDITIONAL_ARGS=${FOSSA_CLI_ARGS}" >> "$GITHUB_ENV" - # Add --without-default-filters if SCA_FOSSA_WITHOUT_DEFAULT_FILTERS is set to true - if [ "${{ env.SCA_FOSSA_WITHOUT_DEFAULT_FILTERS }}" == "true" ]; then - SCA_FOSSA_ADDITIONAL_ARGS="$SCA_FOSSA_ADDITIONAL_ARGS --without-default-filters" - fi - - # Add --force-vendored-dependency-rescans if SCA_FOSSA_FORCE_VENDORED_DEPENDENCY_RESCANS is set to true - if [ "${{ env.SCA_FOSSA_FORCE_VENDORED_DEPENDENCY_RESCANS }}" == "true" ]; then - SCA_FOSSA_ADDITIONAL_ARGS="$SCA_FOSSA_ADDITIONAL_ARGS --force-vendored-dependency-rescans" - fi - - echo "SCA_FOSSA_ADDITIONAL_ARGS=${SCA_FOSSA_ADDITIONAL_ARGS}" >> "$GITHUB_ENV" - - # Set up test args with only revision parameter - SCA_FOSSA_TEST_ARGS="" - if [ -n "${{ env.SCA_FOSSA_REVISION }}" ]; then - SCA_FOSSA_TEST_ARGS="--revision ${{ env.SCA_FOSSA_REVISION }}" - fi - echo "SCA_FOSSA_TEST_ARGS=${SCA_FOSSA_TEST_ARGS}" >> "$GITHUB_ENV" + # Build test args + build_fossa_args "test" + echo "SCA_FOSSA_TEST_ARGS=${FOSSA_CLI_ARGS}" >> "$GITHUB_ENV" echo "::endgroup::" - name: Fossa - Scan shell: bash + working-directory: ${{ env.SCA_FOSSA_PATH || '.' }} run: | echo "::group::๐Ÿ” Fossa Scan" + if [ -n "${{ env.SCA_FOSSA_PATH }}" ]; then + echo "Scanning from directory: ${{ env.SCA_FOSSA_PATH }}" + fi + FOSSA_CMD="fossa analyze" echo "Running: $FOSSA_CMD $SCA_FOSSA_ADDITIONAL_ARGS" @@ -68,6 +44,7 @@ runs: - name: FOSSA - Scan Wait For Results continue-on-error: true shell: bash + working-directory: ${{ env.SCA_FOSSA_PATH || '.' }} run: | echo "::group::โณ Fossa Wait For Results" echo "Running: fossa test $SCA_FOSSA_TEST_ARGS" diff --git a/.github/actions/sca/fossa-scan/fossa-params.json b/.github/actions/sca/fossa-scan/fossa-params.json new file mode 100644 index 0000000..f042860 --- /dev/null +++ b/.github/actions/sca/fossa-scan/fossa-params.json @@ -0,0 +1,81 @@ +{ + "$schema": "fossa-params-schema", + "description": "FOSSA CLI parameter mappings for the fossa-scan GitHub Action", + "version": "2.0.0", + "parameters": [ + { + "env": "SCA_FOSSA_ANALYZE_DEBUG", + "flag": "--debug", + "type": "flag", + "commands": ["analyze"], + "description": "Enable debug logging during FOSSA analysis", + "example": "fossa.analyze_debug=true" + }, + { + "env": "SCA_FOSSA_BRANCH", + "flag": "--branch", + "type": "value", + "commands": ["analyze"], + "description": "Branch name for FOSSA project tracking", + "example": "fossa.branch=main" + }, + { + "env": "SCA_FOSSA_REVISION", + "flag": "--revision", + "type": "value", + "commands": ["analyze", "test"], + "description": "Git revision/commit SHA for FOSSA tracking", + "example": "fossa.revision=abc123" + }, + { + "env": "SCA_FOSSA_PROJECT", + "flag": "--project", + "type": "value", + "commands": ["analyze", "test"], + "description": "Override project name/ID for FOSSA tracking", + "example": "fossa.project=MyOrg_my-project" + }, + { + "env": "SCA_FOSSA_CONFIG", + "flag": "--config", + "type": "value", + "commands": ["analyze", "test"], + "description": "Path to custom .fossa.yml configuration file", + "example": "fossa.config=packages/my-package/.fossa.yml" + }, + { + "env": "SCA_FOSSA_UNPACK_ARCHIVES", + "flag": "--unpack-archives", + "type": "flag", + "commands": ["analyze"], + "description": "Unpack and scan archive files", + "example": "fossa.unpack_archives=true" + }, + { + "env": "SCA_FOSSA_WITHOUT_DEFAULT_FILTERS", + "flag": "--without-default-filters", + "type": "flag", + "commands": ["analyze"], + "description": "Disable default file filters", + "example": "fossa.without_default_filters=true" + }, + { + "env": "SCA_FOSSA_FORCE_VENDORED_DEPENDENCY_RESCANS", + "flag": "--force-vendored-dependency-rescans", + "type": "flag", + "commands": ["analyze"], + "description": "Force rescanning of vendored dependencies", + "example": "fossa.force_vendored_dependency_rescans=true" + } + ], + "notes": [ + "Parameters are mapped from additional_scan_params (e.g., 'fossa.branch=main') to environment variables (e.g., 'SCA_FOSSA_BRANCH')", + "Type 'flag' means boolean - only added if set to 'true'", + "Type 'value' means the parameter requires a value and is added if non-empty", + "The 'commands' field specifies which FOSSA commands support this parameter: 'analyze' and/or 'test'", + "Special parameter: 'fossa.path' sets the working directory for FOSSA commands (not a CLI flag, uses GitHub Actions working-directory)", + "If you specify 'fossa.path', FOSSA will automatically look for .fossa.yml in that directory - you only need 'fossa.config' if the config is elsewhere", + "Example: fossa.path=sam-bedrock-agent will cd into sam-bedrock-agent and use sam-bedrock-agent/.fossa.yml automatically", + "To add a new parameter: add an entry to this file and it will automatically be processed" + ] +} diff --git a/.github/actions/sca/fossa-scan/parse-fossa-params.sh b/.github/actions/sca/fossa-scan/parse-fossa-params.sh new file mode 100755 index 0000000..00f4572 --- /dev/null +++ b/.github/actions/sca/fossa-scan/parse-fossa-params.sh @@ -0,0 +1,147 @@ +#!/bin/bash +set -euo pipefail + +############################################################################### +# FOSSA Parameter Parser +# +# Reads fossa-params.json and builds CLI arguments from environment variables. +# +# Usage: +# source parse-fossa-params.sh +# build_fossa_args +# echo "$FOSSA_CLI_ARGS" +# +# Environment: +# FOSSA_PARAMS_CONFIG - Path to fossa-params.json (default: ./fossa-params.json) +# SCA_FOSSA_* - Various FOSSA configuration variables +# +# Output: +# FOSSA_CLI_ARGS - Space-separated CLI arguments for FOSSA +############################################################################### + +# Default configuration file path +FOSSA_PARAMS_CONFIG="${FOSSA_PARAMS_CONFIG:-$(dirname "${BASH_SOURCE[0]}")/fossa-params.json}" + +############################################################################### +# build_fossa_args [command] +# +# Reads JSON configuration and builds FOSSA CLI arguments from environment +# variables. Sets the FOSSA_CLI_ARGS variable with the result. +# +# Parameters: +# command - Optional FOSSA command to filter parameters by (e.g., "analyze", "test") +# If not provided, uses all parameters regardless of command. +# +# Returns: +# 0 on success, 1 on error +############################################################################### +build_fossa_args() { + local filter_command="${1:-}" + local config_file="$FOSSA_PARAMS_CONFIG" + + # Validate config file exists + if [ ! -f "$config_file" ]; then + echo "โŒ Error: FOSSA parameters config not found: $config_file" >&2 + return 1 + fi + + # Validate JSON syntax + if ! jq empty "$config_file" 2>/dev/null; then + echo "โŒ Error: Invalid JSON in $config_file" >&2 + return 1 + fi + + if [ -n "$filter_command" ]; then + echo "๐Ÿ“‹ Loading FOSSA '$filter_command' parameter mappings from: $config_file" + else + echo "๐Ÿ“‹ Loading FOSSA parameter mappings from: $config_file" + fi + + # Initialize output variable + FOSSA_CLI_ARGS="" + + # Parse JSON and process each parameter + # Use jq to iterate and output shell-safe commands + local param_count + param_count=$(jq -r '.parameters | length' "$config_file") + + for ((i=0; i&2 + ;; + esac + done + + # Trim leading whitespace + FOSSA_CLI_ARGS="${FOSSA_CLI_ARGS# }" + + echo "โœ… Built FOSSA CLI args: $FOSSA_CLI_ARGS" + + # Export for use in calling scripts + export FOSSA_CLI_ARGS + + return 0 +} + +############################################################################### +# print_fossa_config +# +# Pretty-prints the FOSSA parameter configuration for debugging. +############################################################################### +print_fossa_config() { + local config_file="$FOSSA_PARAMS_CONFIG" + + if [ ! -f "$config_file" ]; then + echo "โŒ Error: Config file not found: $config_file" >&2 + return 1 + fi + + echo "๐Ÿ“‹ FOSSA Parameter Configuration" + echo "================================" + echo "" + + jq -r '.parameters[] | " \(.env)\n Flag: \(.flag)\n Type: \(.type)\n Desc: \(.description)\n Example: \(.example)\n"' "$config_file" +} + +############################################################################### +# If script is executed directly (not sourced), run build_fossa_args +############################################################################### +if [ "${BASH_SOURCE[0]}" == "${0}" ]; then + build_fossa_args "$@" +fi diff --git a/.github/actions/sca/fossa-scan/test-parse-fossa-params.sh b/.github/actions/sca/fossa-scan/test-parse-fossa-params.sh new file mode 100755 index 0000000..309b9c9 --- /dev/null +++ b/.github/actions/sca/fossa-scan/test-parse-fossa-params.sh @@ -0,0 +1,292 @@ +#!/bin/bash +set -euo pipefail + +############################################################################### +# Test Suite for parse-fossa-params.sh +# +# Usage: +# ./test-parse-fossa-params.sh +############################################################################### + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TEST_PASSED=0 +TEST_FAILED=0 + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +############################################################################### +# Test Helper Functions +############################################################################### + +assert_equals() { + local expected="$1" + local actual="$2" + local test_name="$3" + + if [ "$expected" == "$actual" ]; then + echo -e "${GREEN}โœ“${NC} $test_name" + ((TEST_PASSED++)) + return 0 + else + echo -e "${RED}โœ—${NC} $test_name" + echo " Expected: $expected" + echo " Actual: $actual" + ((TEST_FAILED++)) + return 1 + fi +} + +assert_contains() { + local haystack="$1" + local needle="$2" + local test_name="$3" + + if [[ "$haystack" == *"$needle"* ]]; then + echo -e "${GREEN}โœ“${NC} $test_name" + ((TEST_PASSED++)) + return 0 + else + echo -e "${RED}โœ—${NC} $test_name" + echo " Expected to contain: $needle" + echo " Actual: $haystack" + ((TEST_FAILED++)) + return 1 + fi +} + +############################################################################### +# Test Cases +############################################################################### + +test_basic_flag_parameter() { + echo "" + echo "Test: Basic flag parameter" + + export SCA_FOSSA_ANALYZE_DEBUG="true" + export FOSSA_PARAMS_CONFIG="$SCRIPT_DIR/fossa-params.json" + + source "$SCRIPT_DIR/parse-fossa-params.sh" + build_fossa_args > /dev/null + + assert_contains "$FOSSA_CLI_ARGS" "--debug" "Should include --debug flag" + + unset SCA_FOSSA_ANALYZE_DEBUG + unset FOSSA_CLI_ARGS +} + +test_value_parameter() { + echo "" + echo "Test: Value parameter" + + export SCA_FOSSA_BRANCH="main" + export FOSSA_PARAMS_CONFIG="$SCRIPT_DIR/fossa-params.json" + + source "$SCRIPT_DIR/parse-fossa-params.sh" + build_fossa_args > /dev/null + + assert_contains "$FOSSA_CLI_ARGS" "--branch main" "Should include --branch with value" + + unset SCA_FOSSA_BRANCH + unset FOSSA_CLI_ARGS +} + +test_multiple_parameters() { + echo "" + echo "Test: Multiple parameters" + + export SCA_FOSSA_ANALYZE_DEBUG="true" + export SCA_FOSSA_BRANCH="PR" + export SCA_FOSSA_REVISION="abc123" + export SCA_FOSSA_PATH="sam-mongodb" + export SCA_FOSSA_CONFIG="sam-mongodb/.fossa.yml" + export FOSSA_PARAMS_CONFIG="$SCRIPT_DIR/fossa-params.json" + + source "$SCRIPT_DIR/parse-fossa-params.sh" + build_fossa_args > /dev/null + + assert_contains "$FOSSA_CLI_ARGS" "--debug" "Should include --debug" + assert_contains "$FOSSA_CLI_ARGS" "--branch PR" "Should include --branch PR" + assert_contains "$FOSSA_CLI_ARGS" "--revision abc123" "Should include --revision" + assert_contains "$FOSSA_CLI_ARGS" "--config sam-mongodb/.fossa.yml" "Should include --config" + + unset SCA_FOSSA_ANALYZE_DEBUG SCA_FOSSA_BRANCH SCA_FOSSA_REVISION SCA_FOSSA_PATH SCA_FOSSA_CONFIG + unset FOSSA_CLI_ARGS +} + +test_empty_value_not_included() { + echo "" + echo "Test: Empty value parameter not included" + + export SCA_FOSSA_BRANCH="" + export FOSSA_PARAMS_CONFIG="$SCRIPT_DIR/fossa-params.json" + + source "$SCRIPT_DIR/parse-fossa-params.sh" + build_fossa_args > /dev/null + + if [[ "$FOSSA_CLI_ARGS" == *"--branch"* ]]; then + echo -e "${RED}โœ—${NC} Should not include --branch when value is empty" + echo " Actual: $FOSSA_CLI_ARGS" + ((TEST_FAILED++)) + else + echo -e "${GREEN}โœ“${NC} Should not include --branch when value is empty" + ((TEST_PASSED++)) + fi + + unset SCA_FOSSA_BRANCH + unset FOSSA_CLI_ARGS +} + +test_false_flag_not_included() { + echo "" + echo "Test: False flag parameter not included" + + export SCA_FOSSA_ANALYZE_DEBUG="false" + export FOSSA_PARAMS_CONFIG="$SCRIPT_DIR/fossa-params.json" + + source "$SCRIPT_DIR/parse-fossa-params.sh" + build_fossa_args > /dev/null + + if [[ "$FOSSA_CLI_ARGS" == *"--debug"* ]]; then + echo -e "${RED}โœ—${NC} Should not include --debug when set to false" + echo " Actual: $FOSSA_CLI_ARGS" + ((TEST_FAILED++)) + else + echo -e "${GREEN}โœ“${NC} Should not include --debug when set to false" + ((TEST_PASSED++)) + fi + + unset SCA_FOSSA_ANALYZE_DEBUG + unset FOSSA_CLI_ARGS +} + +test_project_parameter() { + echo "" + echo "Test: Project parameter" + + export SCA_FOSSA_PROJECT="MyOrg_my-project" + export FOSSA_PARAMS_CONFIG="$SCRIPT_DIR/fossa-params.json" + + source "$SCRIPT_DIR/parse-fossa-params.sh" + build_fossa_args > /dev/null + + assert_contains "$FOSSA_CLI_ARGS" "--project MyOrg_my-project" "Should include project override" + + unset SCA_FOSSA_PROJECT + unset FOSSA_CLI_ARGS +} + +test_command_filtering_analyze() { + echo "" + echo "Test: Command filtering - analyze" + + export SCA_FOSSA_ANALYZE_DEBUG="true" + export SCA_FOSSA_CONFIG="sam-mongodb/.fossa.yml" + export FOSSA_PARAMS_CONFIG="$SCRIPT_DIR/fossa-params.json" + + source "$SCRIPT_DIR/parse-fossa-params.sh" + build_fossa_args "analyze" > /dev/null + + assert_contains "$FOSSA_CLI_ARGS" "--debug" "Analyze should include --debug" + assert_contains "$FOSSA_CLI_ARGS" "--config sam-mongodb/.fossa.yml" "Analyze should include --config" + + unset SCA_FOSSA_ANALYZE_DEBUG SCA_FOSSA_CONFIG + unset FOSSA_CLI_ARGS +} + +test_command_filtering_test() { + echo "" + echo "Test: Command filtering - test" + + export SCA_FOSSA_ANALYZE_DEBUG="true" + export SCA_FOSSA_CONFIG="sam-mongodb/.fossa.yml" + export SCA_FOSSA_BRANCH="PR" + export SCA_FOSSA_REVISION="abc123" + export SCA_FOSSA_PROJECT="MyOrg_project" + export FOSSA_PARAMS_CONFIG="$SCRIPT_DIR/fossa-params.json" + + source "$SCRIPT_DIR/parse-fossa-params.sh" + build_fossa_args "test" > /dev/null + + # Test command should include these + assert_contains "$FOSSA_CLI_ARGS" "--revision abc123" "Test should include --revision" + assert_contains "$FOSSA_CLI_ARGS" "--project MyOrg_project" "Test should include --project" + assert_contains "$FOSSA_CLI_ARGS" "--config sam-mongodb/.fossa.yml" "Test should include --config" + + # Test command should NOT include these (analyze-only) + if [[ "$FOSSA_CLI_ARGS" == *"--debug"* ]]; then + echo -e "${RED}โœ—${NC} Test should NOT include --debug (analyze-only)" + ((TEST_FAILED++)) + else + echo -e "${GREEN}โœ“${NC} Test should NOT include --debug (analyze-only)" + ((TEST_PASSED++)) + fi + + if [[ "$FOSSA_CLI_ARGS" == *"--branch"* ]]; then + echo -e "${RED}โœ—${NC} Test should NOT include --branch (analyze-only)" + ((TEST_FAILED++)) + else + echo -e "${GREEN}โœ“${NC} Test should NOT include --branch (analyze-only)" + ((TEST_PASSED++)) + fi + + unset SCA_FOSSA_ANALYZE_DEBUG SCA_FOSSA_CONFIG SCA_FOSSA_BRANCH SCA_FOSSA_REVISION SCA_FOSSA_PROJECT + unset FOSSA_CLI_ARGS +} + +test_monorepo_use_case() { + echo "" + echo "Test: Monorepo use case (real-world scenario)" + + export SCA_FOSSA_CONFIG="sam-mongodb/.fossa.yml" + export SCA_FOSSA_PROJECT="SolaceLabs_sam-mongodb" + export SCA_FOSSA_BRANCH="PR" + export SCA_FOSSA_REVISION="feature-branch" + export FOSSA_PARAMS_CONFIG="$SCRIPT_DIR/fossa-params.json" + + source "$SCRIPT_DIR/parse-fossa-params.sh" + build_fossa_args > /dev/null + + assert_contains "$FOSSA_CLI_ARGS" "--project SolaceLabs_sam-mongodb" "Should include project name" + assert_contains "$FOSSA_CLI_ARGS" "--config sam-mongodb/.fossa.yml" "Should include plugin config" + + unset SCA_FOSSA_CONFIG SCA_FOSSA_PROJECT SCA_FOSSA_BRANCH SCA_FOSSA_REVISION + unset FOSSA_CLI_ARGS +} + +############################################################################### +# Run All Tests +############################################################################### + +echo "=================================================" +echo "๐Ÿงช FOSSA Parameter Parser Test Suite" +echo "=================================================" + +test_basic_flag_parameter +test_value_parameter +test_multiple_parameters +test_empty_value_not_included +test_false_flag_not_included +test_project_parameter +test_command_filtering_analyze +test_command_filtering_test +test_monorepo_use_case + +echo "" +echo "=================================================" +echo "๐Ÿ“Š Test Results" +echo "=================================================" +echo -e "${GREEN}Passed:${NC} $TEST_PASSED" +echo -e "${RED}Failed:${NC} $TEST_FAILED" +echo "=================================================" + +if [ $TEST_FAILED -eq 0 ]; then + echo -e "${GREEN}โœ… All tests passed!${NC}" + exit 0 +else + echo -e "${RED}โŒ Some tests failed${NC}" + exit 1 +fi diff --git a/.github/actions/sca/sca-scan/README.md b/.github/actions/sca/sca-scan/README.md new file mode 100644 index 0000000..eada7c0 --- /dev/null +++ b/.github/actions/sca/sca-scan/README.md @@ -0,0 +1,256 @@ +# SCA Scan Action + +A generic Software Composition Analysis (SCA) scan entrypoint that orchestrates multiple security scanning tools. + +## Overview + +This action serves as a unified interface for running various SCA scanners (currently supporting FOSSA). It handles parameter conversion and routing to specific scanner implementations. + +## Features + +- **Multi-scanner support**: Run one or more SCA scanners (currently: FOSSA) +- **Unified parameter system**: Configure scanner-specific options through `additional_scan_params` +- **Automatic parameter conversion**: Converts `scanner.param_name` โ†’ `SCA_SCANNER_PARAM_NAME` environment variables +- **Extensible architecture**: Easy to add new scanners without changing caller workflows + +## Usage + +### Basic Usage + +```yaml +- name: Run SCA Scan + uses: SolaceDev/solace-public-workflows/.github/actions/sca/sca-scan@main + with: + scanners: "fossa" + fossa_api_key: ${{ secrets.FOSSA_API_KEY }} +``` + +### With Custom Parameters + +```yaml +- name: Run SCA Scan with Custom Config + uses: SolaceDev/solace-public-workflows/.github/actions/sca/sca-scan@main + with: + scanners: "fossa" + additional_scan_params: | + fossa.path=packages/my-package + fossa.config=packages/my-package/.fossa.yml + fossa.branch=main + fossa.revision=${{ github.sha }} + fossa_api_key: ${{ secrets.FOSSA_API_KEY }} +``` + +### Monorepo Use Case + +```yaml +- name: Scan Specific Plugin + uses: SolaceDev/solace-public-workflows/.github/actions/sca/sca-scan@main + with: + scanners: "fossa" + additional_scan_params: | + fossa.path=sam-mongodb + fossa.config=sam-mongodb/.fossa.yml + fossa.project=SolaceLabs_sam-mongodb + fossa.branch=PR + fossa_api_key: ${{ secrets.FOSSA_API_KEY }} +``` + +## Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|---------| +| `scanners` | Comma-separated list of scanners to run | No | `"fossa"` | +| `additional_scan_params` | Scanner-specific parameters (see below) | No | `""` | +| `fossa_api_key` | API key for FOSSA scanner | No (required if using FOSSA) | `""` | + +## Additional Scan Parameters + +The `additional_scan_params` input accepts scanner-specific configuration in `scanner.param_name=value` format. + +### Format + +```yaml +additional_scan_params: | + scanner.parameter_name=value + scanner.another_param=another_value +``` + +### Parameter Conversion + +Parameters are automatically converted to environment variables: + +| Input Format | Environment Variable | Example | +|--------------|---------------------|---------| +| `fossa.config` | `SCA_FOSSA_CONFIG` | `fossa.config=.fossa.yml` โ†’ `SCA_FOSSA_CONFIG=.fossa.yml` | +| `fossa.branch` | `SCA_FOSSA_BRANCH` | `fossa.branch=main` โ†’ `SCA_FOSSA_BRANCH=main` | +| `fossa.analyze_debug` | `SCA_FOSSA_ANALYZE_DEBUG` | `fossa.analyze_debug=true` โ†’ `SCA_FOSSA_ANALYZE_DEBUG=true` | + +**Conversion Rules:** +1. Prefix with `SCA_` +2. Replace `.` with `_` +3. Convert to UPPERCASE + +### Comments and Empty Lines + +```yaml +additional_scan_params: | + # This is a comment - will be ignored + fossa.branch=main + + # Empty lines are also ignored + fossa.config=.fossa.yml +``` + +### Available Parameters by Scanner + +#### FOSSA + +See the [FOSSA Scan Action README](../fossa-scan/README.md) for a complete list of available parameters. + +**Common FOSSA Parameters:** +- `fossa.path` - Base directory to scan +- `fossa.config` - Path to `.fossa.yml` configuration file +- `fossa.branch` - Branch name for tracking +- `fossa.revision` - Git commit SHA +- `fossa.project` - Custom project name +- `fossa.analyze_debug` - Enable debug logging (`true`/`false`) + +## How It Works + +### Architecture Flow + +``` +User Workflow + โ†“ + sca-scan Action + โ†“ + Parse additional_scan_params + โ†“ + Convert to Environment Variables + (fossa.config โ†’ SCA_FOSSA_CONFIG) + โ†“ + Route to Scanner Action (fossa-scan) + โ†“ + Scanner reads SCA_* environment variables + โ†“ + Execute Scanner CLI +``` + +### Parameter Parsing + +1. **Input**: Multi-line string with `key=value` pairs +2. **Parsing**: Split on `=`, trim whitespace +3. **Conversion**: Apply naming convention (`SCA_SCANNER_PARAM`) +4. **Export**: Set as environment variable in `$GITHUB_ENV` +5. **Propagation**: Available to all child actions + +### Example Transformation + +**Input:** +```yaml +additional_scan_params: | + fossa.path=sam-mongodb + fossa.config=sam-mongodb/.fossa.yml +``` + +**Exported Variables:** +```bash +SCA_FOSSA_PATH=sam-mongodb +SCA_FOSSA_CONFIG=sam-mongodb/.fossa.yml +``` + +**FOSSA Command:** +```bash +fossa analyze --path sam-mongodb --config sam-mongodb/.fossa.yml +``` + +## Error Handling + +### Invalid Parameter Format + +```yaml +additional_scan_params: | + invalid_line_without_equals +``` + +**Result:** +``` +โŒ Invalid additional_scan_params line (missing '='): invalid_line_without_equals +``` + +The action will fail fast to prevent incorrect configuration. + +## Extending with New Scanners + +To add a new scanner: + +1. **Create scanner action**: `.github/actions/sca/new-scanner/action.yaml` +2. **Add input**: Add `new_scanner_api_key` input to this action +3. **Add step**: Add routing step to call your scanner action +4. **Update docs**: Document scanner-specific parameters + +**Example:** +```yaml +- name: SCA - Run NewScanner scan + if: contains(inputs.scanners, 'newscanner') + uses: SolaceDev/solace-public-workflows/.github/actions/sca/new-scanner@main + env: + NEWSCANNER_API_KEY: ${{ inputs.newscanner_api_key }} +``` + +## Related Documentation + +- [FOSSA Scan Action](../fossa-scan/README.md) - FOSSA scanner implementation +- [FOSSA Parameters](../fossa-scan/fossa-params.json) - Complete FOSSA parameter list +- [FOSSA CLI Docs](https://github.com/fossas/fossa-cli) - Official FOSSA documentation + +## Troubleshooting + + + +### Matrix Build (Multiple Packages) + +```yaml +jobs: + sca-scan: + strategy: + matrix: + package: [sam-mongodb, sam-slack, sam-jira] + steps: + - name: Scan ${{ matrix.package }} + uses: SolaceDev/solace-public-workflows/.github/actions/sca/sca-scan@main + with: + scanners: "fossa" + additional_scan_params: | + fossa.path=${{ matrix.package }} + fossa.config=${{ matrix.package }}/.fossa.yml + fossa.project=MyOrg_${{ matrix.package }} + fossa_api_key: ${{ secrets.FOSSA_API_KEY }} +``` + +### PR Scanning + +```yaml +- name: Scan PR Changes + uses: SolaceDev/solace-public-workflows/.github/actions/sca/sca-scan@main + with: + scanners: "fossa" + additional_scan_params: | + fossa.branch=PR + fossa.revision=${{ github.event.pull_request.head.sha }} + fossa_api_key: ${{ secrets.FOSSA_API_KEY }} +``` + +### Main Branch Scanning + +```yaml +- name: Scan Main Branch + if: github.ref == 'refs/heads/main' + uses: SolaceDev/solace-public-workflows/.github/actions/sca/sca-scan@main + with: + scanners: "fossa" + additional_scan_params: | + fossa.branch=${{ github.ref_name }} + fossa.revision=${{ github.sha }} + fossa_api_key: ${{ secrets.FOSSA_API_KEY }} +```