diff --git a/README.md b/README.md index 9f4d82c..50906c1 100644 --- a/README.md +++ b/README.md @@ -2,29 +2,92 @@ Run [SpotBugs](https://spotbugs.readthedocs.io/en/latest/) as a Github action. +## Inputs + +### outputType + +Output type for the report. It can be 'xml', 'html', 'sarif', 'emacs' +or 'xdocs'. Default value is 'sarif' as it is the used by GitHub Advanced +Security. + +> default: 'sarif'
+> required: true + +### packages + +Comma separated list of packages to scan. It will fill the +-onlyAnalyze parameter in spotbugs. It can contain the wildcards '\*' and +'-': com.example.\* for single package or com.example.- for all +subpackages. + +> If not specified, it will scan all packages. + +See more at https://spotbugs.readthedocs.io/en/stable/running.html#text-ui-options + +### arguments + +A string with any additional command arguments to be sent to [spotbugs](https://spotbugs.readthedocs.io/en/stable/running.html#text-ui-options) + +### output + +The output filename. If not specified, it will use the default name 'results.[EXTENSION]' + +### target + +It can be a file or a directory, it is usually the ./target folder where you compiled your project. + +### dependenciesPath + +Path to the dependencies folder. For example, for Maven it is usually stored +in the `~/.m2` folder. + +### basePath + +The basePath is used as a prefix in the sarif file to help GitHub find the +right file of the issue. It is tipically something like 'src/main/java'. + +## Example usage + +This workflow would analyze a Java application that builds a set of +packages under the com.example package name and outputs the results in +sarif format to upload it to the GitHub Security tab: + ```yaml name: SpotBugs on: [push, pull_request] jobs: - spotbugs-analyze: + spotbugs-analyze: name: Analyze runs-on: ubuntu-latest - steps: + steps: + + # checkout and build the project - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 + + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + cache: maven + - name: Build with Maven + run: mvn clean package -B -Dmaven.test.skip - - name: Run SpotBugs - uses: spotbugs/spotbugs-github-action@v1 + # Run SpotBugs and upload the SARIF file + - name: Run SpotBugs action + if: always() + uses: abirismyname/spotbugs-github-action@v2 with: - arguments: '-sarif' - target: './HelloWorld.jar' - output: 'results.sarif' - spotbugs-version: 'latest' + packages: com.example.- + target: ./target + dependenciesPath: ~/.m2 + basePath: src/main/java - name: Upload analysis results to GitHub Security tab - uses: github/codeql-action/upload-sarif@v1 + uses: github/codeql-action/upload-sarif@v2 with: sarif_file: ${{github.workspace}}/results.sarif ``` diff --git a/action.yml b/action.yml index e679362..fafa285 100644 --- a/action.yml +++ b/action.yml @@ -8,16 +8,47 @@ inputs: description: 'SpotBugs version to use.' default: 'latest' required: false + packages: + description: > + Comma separated list of packages to scan. It will fill the + -onlyAnalyze parameter in spotbugs. It can contain the wildcards '*' and + '-': com.example.* for single package or com.example.- for all + subpackages. + + If not specified, it will scan all packages. + See more: https://spotbugs.readthedocs.io/en/stable/running.html#text-ui-options + required: false arguments: - description: 'Command arguments to be sent to SpotBugs' - required: true - default: '' + description: > + A string with any additional command arguments to be sent to spotbugs. + See more: https://spotbugs.readthedocs.io/en/stable/running.html#text-ui-options + required: false output: - description: 'Output file name' - required: true + description: > + The output filename. If not specified, it will use the default name + 'results.EXTENSION' target: - description: 'Target of what you want to analyze' - required: true + description: > + Target of what you want to analyze. It can be a file or a directory, it + is usually the ./target folder where you compiled your project. + required: false + outputType: + description: > + Output type for the report. It can be 'xml', 'html', 'sarif', 'emacs' + or 'xdocs'. Default value is 'sarif' as it is the used by GitHub Advanced + Security. + default: 'sarif' + required: true + dependenciesPath: + description: > + Path to the dependencies folder. For Maven it is usually stored in the + '~/.m2' folder. + required: false + basePath: + description: > + The basePath is used as a prefix in the sarif file to help GitHub find the + right file of the issue. It is tipically something like 'src/main/java'. + required: false runs: using: "composite" steps: @@ -26,6 +57,10 @@ runs: shell: bash env: SPOTBUGS_VERSION: ${{ inputs.spotbugs-version }} + PACKAGES: ${{ inputs.packages }} OUTPUT: ${{ inputs.output }} + OUTPUT_TYPE: ${{ inputs.outputType }} ARGUMENTS: ${{ inputs.arguments }} - TARGET: ${{ inputs.target }} \ No newline at end of file + TARGET: ${{ inputs.target }} + DEPENDENCIES_PATH: ${{ inputs.dependenciesPath }} + BASE_PATH: ${{ inputs.basePath }} \ No newline at end of file diff --git a/analyze.sh b/analyze.sh index ae70a41..e650610 100755 --- a/analyze.sh +++ b/analyze.sh @@ -1,16 +1,106 @@ #!/bin/bash +# set com.example.demo and all chid packages (.- means all children, .* this package only) +# PACKAGES="com.example.demo.-" +# source path to prepend to the class path +# BASEPATH="src/main/java" +# DEPENDENCIES_PATH="~/.m2" +# OUTPUT_TYPE="sarif" + # Check whether to use latest version of PMD -if [ "$SPOTBUGS_VERSION" == 'latest' ]; then +if [ "$SPOTBUGS_VERSION" == 'latest' ] || [ "$SPOTBUGS_VERSION" == "" ]; then LATEST_TAG="$(curl -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/spotbugs/spotbugs/releases/latest | jq --raw-output '.tag_name')" SPOTBUGS_VERSION=$LATEST_TAG fi # Download SpotBugs -wget https://github.com/spotbugs/spotbugs/releases/download/"${SPOTBUGS_VERSION}"/spotbugs-"${SPOTBUGS_VERSION}".zip -unzip spotbugs-"${SPOTBUGS_VERSION}".zip +wget -q -N https://github.com/spotbugs/spotbugs/releases/download/"${SPOTBUGS_VERSION}"/spotbugs-"${SPOTBUGS_VERSION}".zip +unzip -q -o spotbugs-"${SPOTBUGS_VERSION}".zip # Run SpotBugs SPOTBUGS_HOME=spotbugs-"${SPOTBUGS_VERSION}" SPOTBUGS=${SPOTBUGS_HOME}/bin/spotbugs -sh $SPOTBUGS -textui -output "${OUTPUT}" "${ARGUMENTS}" "${TARGET}" + +#sh $SPOTBUGS -textui -output "${OUTPUT}" "${ARGUMENTS}" "${TARGET}" + +# Take care of parameter order, sometimes does not work if you change it + +CMD="java -Xmx1900M -Dlog4j2.formatMsgNoLookups=true \ + -jar ${SPOTBUGS_HOME}/lib/spotbugs.jar -textui " + +if [ "$PACKAGES" != "" ]; then + CMD="$CMD -onlyAnalyze ${PACKAGES}" +fi + +CMD="$CMD -quiet -effort:max -low -noClassOk" + +case $OUTPUT_TYPE in + "xml") + if [ "$OUTPUT" == "" ]; then + OUTPUT="results.xml" + fi + CMD="$CMD -xml:withMessages=./$OUTPUT" + ;; + "html") + if [ "$OUTPUT" == "" ]; then + OUTPUT="results.html" + fi + CMD="$CMD -html:withMessages=./$OUTPUT" + ;; + "emacs") + if [ "$OUTPUT" == "" ]; then + OUTPUT="results.emacs" + fi + CMD="$CMD -emacs:withMessages=./$OUTPUT" + ;; + "xdocs") + if [ "$OUTPUT" == "" ]; then + OUTPUT="results.xdocs" + fi + CMD="$CMD -xdoc:withMessages=./$OUTPUT" + ;; + *) + OUTPUT_TYPE="sarif" + if [ "$OUTPUT" == "" ]; then + OUTPUT="results.sarif" + fi + CMD="$CMD -sarif:withMessages=./resultspre.sarif" + ;; +esac + +if [ "$DEPENDENCIES_PATH" != "" ]; then + DEP_CMD="find ${DEPENDENCIES_PATH} -name \"*.jar\" -type f > /tmp/jardependencies.txt" + echo "Scanning jars with: ${DEP_CMD}" + eval ${DEP_CMD} + CMD="$CMD -auxclasspathFromFile /tmp/jardependencies.txt" +fi + +if [ "$BASE_PATH" != "" ]; then + if [[ "$BASE_PATH" != */ ]]; then + BASE_PATH="$BASE_PATH/" + fi + # using sourcepath does not work for GitHub's sarif parser + # but keeping there just in case + CMD="$CMD -sourcepath ${BASE_PATH}" +fi + +if [ "$ARGUMENTS" != "" ]; then + CMD="$CMD ${ARGUMENTS}" +fi + +if [ "$TARGET" != "" ]; then + CMD="$CMD ${TARGET}" +else + CMD="$CMD ." +fi + +echo "Running SpotBugs with command: $CMD" + +eval ${CMD} + +if [ "$OUTPUT_TYPE" == "sarif" ] && [ "$BASE_PATH" != "" ]; then + # prepend the pyhsical path + echo "Transform sarif file to include the physical path" + jq -c "(.runs[].results[].locations[].physicalLocation.artifactLocation.uri) |=\"$BASE_PATH\"+." resultspre.sarif > "$OUTPUT" +fi +