struct-audit 0.2.1

Analyze binary memory layouts to detect padding inefficiencies
Documentation
name: 'struct-audit'
description: 'Analyze binary memory layouts to detect padding inefficiencies'
author: 'avifen'

branding:
  icon: 'cpu'
  color: 'orange'

inputs:
  binary:
    description: 'Path to the binary file to analyze'
    required: true
  command:
    description: 'Command to run: inspect, diff, or check'
    required: false
    default: 'inspect'
  baseline:
    description: 'Path to baseline binary (for diff command)'
    required: false
  config:
    description: 'Path to config file (for check command)'
    required: false
    default: '.struct-audit.yaml'
  filter:
    description: 'Filter structs by name (substring match)'
    required: false
  output:
    description: 'Output format: table or json'
    required: false
    default: 'table'
  sort-by:
    description: 'Sort by: name, size, padding, or padding-pct'
    required: false
    default: 'padding'
  top:
    description: 'Show only top N structs'
    required: false
  min-padding:
    description: 'Show only structs with at least N bytes of padding'
    required: false
  fail-on-regression:
    description: 'Fail if size or padding increased (for diff command)'
    required: false
    default: 'false'
  version:
    description: 'Version of struct-audit to use'
    required: false
    default: 'latest'

outputs:
  report:
    description: 'The struct-audit output'
    value: ${{ steps.run.outputs.report }}

runs:
  using: 'composite'
  steps:
    - name: Install struct-audit
      shell: bash
      run: |
        if [ "${{ inputs.version }}" = "latest" ]; then
          cargo install struct-audit
        else
          cargo install struct-audit --version ${{ inputs.version }}
        fi

    - name: Run struct-audit
      id: run
      shell: bash
      env:
        INPUT_COMMAND: ${{ inputs.command }}
        INPUT_BINARY: ${{ inputs.binary }}
        INPUT_BASELINE: ${{ inputs.baseline }}
        INPUT_CONFIG: ${{ inputs.config }}
        INPUT_FILTER: ${{ inputs.filter }}
        INPUT_OUTPUT: ${{ inputs.output }}
        INPUT_SORT_BY: ${{ inputs.sort-by }}
        INPUT_TOP: ${{ inputs.top }}
        INPUT_MIN_PADDING: ${{ inputs.min-padding }}
        INPUT_FAIL_ON_REGRESSION: ${{ inputs.fail-on-regression }}
      run: |
        set +e

        args=()

        case "$INPUT_COMMAND" in
          inspect)
            args+=(inspect "$INPUT_BINARY")
            if [ -n "$INPUT_FILTER" ]; then
              args+=(--filter "$INPUT_FILTER")
            fi
            args+=(--output "$INPUT_OUTPUT")
            args+=(--sort-by "$INPUT_SORT_BY")
            if [ -n "$INPUT_TOP" ]; then
              args+=(--top "$INPUT_TOP")
            fi
            if [ -n "$INPUT_MIN_PADDING" ]; then
              args+=(--min-padding "$INPUT_MIN_PADDING")
            fi
            ;;
          diff)
            if [ -z "$INPUT_BASELINE" ]; then
              echo "Error: baseline input is required for diff command"
              exit 1
            fi
            args+=(diff "$INPUT_BASELINE" "$INPUT_BINARY")
            if [ -n "$INPUT_FILTER" ]; then
              args+=(--filter "$INPUT_FILTER")
            fi
            args+=(--output "$INPUT_OUTPUT")
            if [ "$INPUT_FAIL_ON_REGRESSION" = "true" ]; then
              args+=(--fail-on-regression)
            fi
            ;;
          check)
            args+=(check "$INPUT_BINARY" --config "$INPUT_CONFIG")
            ;;
          *)
            echo "Error: unknown command '$INPUT_COMMAND'"
            exit 1
            ;;
        esac

        echo "Running: struct-audit ${args[*]}"
        OUTPUT=$(struct-audit "${args[@]}" 2>&1)
        EXIT_CODE=$?

        echo "$OUTPUT"

        # Set output for use in subsequent steps
        {
          echo "report<<EOF"
          echo "$OUTPUT"
          echo "EOF"
        } >> "$GITHUB_OUTPUT"

        exit $EXIT_CODE