diff --git a/.github/workflows/test_multi_arch_images.yml b/.github/workflows/test_multi_arch_images.yml new file mode 100644 index 0000000..888cbf4 --- /dev/null +++ b/.github/workflows/test_multi_arch_images.yml @@ -0,0 +1,63 @@ +name: Test Multi-arch images + +on: + schedule: + - cron: '0 */6 * * *' # runs every 6 hours + push: + branches: # + - '*' + +permissions: + contents: read + id-token: write + +jobs: + test_multi_arch: + runs-on: ubuntu-latest + environment: + name: plugin-development + strategy: + matrix: + platform: + - "linux/386" + - "linux/amd64" + - "linux/arm/v5" + - "linux/arm/v7" + - "linux/arm64/v8" + - "linux/ppc64le" + - "linux/riscv64" + - "linux/s390x" + + steps: + + - name: Checkout this repository + uses: actions/checkout@v4 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ${{ secrets.AWS_REGION }} + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + + - name: Test multi-arch image - ${{ matrix.platform }} + id: inspector + uses: aws-actions/vulnerability-scan-github-action-for-amazon-inspector@investigate_multi_arch + with: + artifact_type: 'container' + artifact_path: 'debian:trixie' + platform: ${{ matrix.platform }} + display_vulnerability_findings: "enabled" + sbomgen_version: "latest" + + - name: Demonstrate SBOM Output (JSON) + run: cat ${{ steps.inspector.outputs.artifact_sbom }} + + - name: Display scan results + run: cat ${{ steps.inspector.outputs.inspector_scan_results }} + + - name: Validate multi-arch - ${{ matrix.platform }} + run: python3 validator/validate_multi_platform_image_support.py --platform "${{ matrix.platform }}" --sbom "${{ steps.inspector.outputs.artifact_sbom }}" + + diff --git a/action.yml b/action.yml index cc9a20f..af79fd8 100644 --- a/action.yml +++ b/action.yml @@ -162,6 +162,7 @@ runs: - --thresholds - ${{ inputs.threshold_fixable_only == 'true' && '--threshold-fixable-only' || '--no-op' }} - ${{ inputs.show_only_fixable_vulns == 'true' && '--show-only-fixable-vulns'|| '--no-op' }} + - --platform=${{ inputs.platform || '' }} - --critical=${{ inputs.critical_threshold }} - --high=${{ inputs.high_threshold }} - --medium=${{ inputs.medium_threshold }} diff --git a/validator/validate_multi_platform_image_support.py b/validator/validate_multi_platform_image_support.py new file mode 100644 index 0000000..0b933bb --- /dev/null +++ b/validator/validate_multi_platform_image_support.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 + +import argparse +import json +import sys + + +def get_expected_arch(platform): + """Map platform string to expected architecture value in SBOM""" + platform_to_arch = { + "linux/386": "386", + "linux/amd64": "amd64", + "linux/arm/v5": "arm", + "linux/arm/v7": "arm", + "linux/arm64/v8": "arm64", + "linux/ppc64le": "ppc64le", + "linux/riscv64": "riscv64", + "linux/s390x": "s390x" + } + + if platform not in platform_to_arch: + raise ValueError(f"Unknown platform: {platform}") + + return platform_to_arch[platform] + + +def extract_arch_from_sbom(sbom_file): + """Extract architecture from SBOM metadata""" + try: + with open(sbom_file, 'r') as f: + sbom = json.load(f) + + properties = sbom.get('metadata', {}).get('component', {}).get('properties', []) + + for prop in properties: + if prop.get('name') == 'amazon:inspector:sbom_generator:image_arch': + return prop.get('value') + + raise ValueError("Architecture property not found in SBOM") + + except Exception as e: + raise ValueError(f"Failed to parse SBOM: {e}") + + +def main(): + parser = argparse.ArgumentParser(description='Validate SBOM architecture matches expected platform') + parser.add_argument('--platform', required=True, help='Expected platform (e.g., linux/amd64)') + parser.add_argument('--sbom', required=True, help='Path to SBOM file') + + args = parser.parse_args() + + try: + expected_arch = get_expected_arch(args.platform) + actual_arch = extract_arch_from_sbom(args.sbom) + + print(f"Platform: {args.platform}") + print(f"Expected arch: {expected_arch}") + print(f"Actual arch: {actual_arch}") + + if actual_arch != expected_arch: + print(f" Architecture mismatch for platform {args.platform}") + print(f" Expected: {expected_arch}") + print(f" Found: {actual_arch}") + sys.exit(1) + + print(f"Architecture validation passed: {actual_arch} matches expected {expected_arch}") + + except Exception as e: + print(f"Validation failed: {e}") + sys.exit(1) + + +if __name__ == '__main__': + main()