struct-audit 0.2.0

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
      run: |
        set +e

        ARGS=""

        case "${{ inputs.command }}" in
          inspect)
            ARGS="inspect ${{ inputs.binary }}"
            if [ -n "${{ inputs.filter }}" ]; then
              ARGS="$ARGS --filter '${{ inputs.filter }}'"
            fi
            ARGS="$ARGS --output ${{ inputs.output }}"
            ARGS="$ARGS --sort-by ${{ inputs.sort-by }}"
            if [ -n "${{ inputs.top }}" ]; then
              ARGS="$ARGS --top ${{ inputs.top }}"
            fi
            if [ -n "${{ inputs.min-padding }}" ]; then
              ARGS="$ARGS --min-padding ${{ inputs.min-padding }}"
            fi
            ;;
          diff)
            if [ -z "${{ inputs.baseline }}" ]; then
              echo "Error: baseline input is required for diff command"
              exit 1
            fi
            ARGS="diff ${{ inputs.baseline }} ${{ inputs.binary }}"
            if [ -n "${{ inputs.filter }}" ]; then
              ARGS="$ARGS --filter '${{ inputs.filter }}'"
            fi
            ARGS="$ARGS --output ${{ inputs.output }}"
            if [ "${{ inputs.fail-on-regression }}" = "true" ]; then
              ARGS="$ARGS --fail-on-regression"
            fi
            ;;
          check)
            ARGS="check ${{ inputs.binary }} --config ${{ inputs.config }}"
            ;;
          *)
            echo "Error: unknown command '${{ inputs.command }}'"
            exit 1
            ;;
        esac

        echo "Running: struct-audit $ARGS"
        OUTPUT=$(eval "struct-audit $ARGS" 2>&1)
        EXIT_CODE=$?

        echo "$OUTPUT"

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

        exit $EXIT_CODE