diff --git a/.github/workflows/cicd_1-pr.yml b/.github/workflows/cicd_1-pr.yml index 4c6c7e59b670..ad2fb8dbcedc 100644 --- a/.github/workflows/cicd_1-pr.yml +++ b/.github/workflows/cicd_1-pr.yml @@ -77,17 +77,33 @@ jobs: sonar: name: PR SonarQube needs: [ initialize,build ] - if: always() && !failure() && !cancelled() && needs.initialize.outputs.build == 'true' + if: always() && !failure() && !cancelled() && needs.initialize.outputs.build == 'true' && + ( + (github.event_name == 'workflow_dispatch' && !inputs.disable-sonar) || + (github.event_name != 'workflow_dispatch' && vars.DISABLE_SONAR != 'true') + ) uses: ./.github/workflows/cicd_comp_sonarqube-phase.yml secrets: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + semgrep: + name: PR Semgrep + needs: [ initialize,build ] + if: always() && !failure() && !cancelled() && needs.initialize.outputs.build == 'true' && + ( + (github.event_name == 'workflow_dispatch' && !inputs.disable-semgrep) || + (github.event_name != 'workflow_dispatch' && vars.DISABLE_SEMGREP != 'true') + ) + uses: ./.github/workflows/cicd_comp_semgrep-phase.yml + secrets: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} + # Finalize job - aggregates results from previous jobs finalize: name: Finalize if: always() - needs: [ sonar,test ] + needs: [ sonar,semgrep,test ] uses: ./.github/workflows/cicd_comp_finalize-phase.yml with: needsData: ${{ toJson(needs) }} diff --git a/.github/workflows/cicd_3-trunk.yml b/.github/workflows/cicd_3-trunk.yml index 309bdbc8344d..08653f7dfe62 100644 --- a/.github/workflows/cicd_3-trunk.yml +++ b/.github/workflows/cicd_3-trunk.yml @@ -34,7 +34,15 @@ on: publish-npm-sdk-libs: description: 'Publish NPM SDKs' type: boolean - default: false + default: false + disable-sonar: + description: 'Disable SonarQube job' + type: boolean + default: false + disable-semgrep: + description: 'Disable Semgrep job' + type: boolean + default: false jobs: # Initialize the trunk check process @@ -75,8 +83,8 @@ jobs: # SonarQube analysis job sonar: name: Trunk SonarQube - needs: [ initialize,test ] - if: always() && !failure() && !cancelled() + needs: [ initialize, test ] + if: always() && !failure() && !cancelled() && vars.DISABLE_SONAR != 'true' uses: ./.github/workflows/cicd_comp_sonarqube-phase.yml with: artifact-run-id: ${{ needs.initialize.outputs.artifact-run-id }} @@ -84,6 +92,14 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + semgrep: + name: Trunk Semgrep + needs: [ initialize, test ] + if: always() && !failure() && !cancelled() && vars.DISABLE_SEMGREP != 'true' + uses: ./.github/workflows/cicd_comp_semgrep-phase.yml + secrets: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} + # CLI Build job - builds CLI artifacts build-cli: name: CLI Build @@ -116,7 +132,7 @@ jobs: finalize: name: Finalize if: always() - needs: [ initialize, build, build-cli, test, sonar, deployment] + needs: [ initialize, build, build-cli, test, sonar, semgrep, deployment] uses: ./.github/workflows/cicd_comp_finalize-phase.yml with: artifact-run-id: ${{ needs.initialize.outputs.artifact-run-id }} diff --git a/.github/workflows/cicd_comp_semgrep-phase.yml b/.github/workflows/cicd_comp_semgrep-phase.yml new file mode 100644 index 000000000000..3b66b60f976a --- /dev/null +++ b/.github/workflows/cicd_comp_semgrep-phase.yml @@ -0,0 +1,77 @@ +# Semgrep Phase Workflow +# +# This reusable workflow is responsible for running Semgrep analysis on the codebase +# +# Key features: +# - Runs Semgrep analysis on the codebase +# - Configurable timeout for quality gate check +# - Outputs quality gate status for further use + +name: Semgrep Phase + +on: + workflow_call: + inputs: + artifact-run-id: + description: 'The run id of the build to download artifacts from.' + default: ${{ github.run_id }} + type: string + secrets: + SEMGREP_APP_TOKEN: + required: true + +jobs: + buildmavenDepTree: + name: Semgrep Dep Tree + runs-on: ubuntu-latest + # Only run on main branch or pull requests in the main repository + if: | + (github.ref == 'refs/heads/main' || github.event_name == 'pull_request') && github.repository == 'dotCMS/core' + steps: + # Checkout the repository with full history for accurate analysis + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Prepare Maven environment and run SonarQube analysis + - name: Build Dependency Tre + uses: ./.github/actions/core-cicd/maven-job + with: + stage-name: "Dependency Tree Scan" + artifacts-from: ${{ inputs.artifact-run-id }} + require-main: true + github-token: ${{ secrets.GITHUB_TOKEN }} + maven-args: dependency:tree -DoutputFile=maven_dep_tree.txt + - name: Create Zip File + run: find . -type f -name 'maven_dep_tree.txt' -exec zip -r dependency-tree.zip {} + + - name: Upload Dependency Zip + uses: actions/upload-artifact@v4 + with: + name: dependency-tree + path: dependency-tree.zip + + semgrep: + needs: buildmavenDepTree + name: Scan + runs-on: ubuntu-20.04 + env: + SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} + NO_FAIL: ${{ vars.SEMGREP_NO_FAIL || 'false' }} + container: + image: semgrep/semgrep + # Skip any PR created by dependabot to avoid permission issues: + if: (github.actor != 'dependabot[bot]') + steps: + - uses: actions/checkout@v4 + - name: Download artifact from the previous job + uses: actions/download-artifact@v4 + with: + name: dependency-tree + - name: Semgrep Scan + run: | + unzip -o dependency-tree.zip + if [ "${NO_FAIL}" = "true" ]; then + semgrep ci || echo "Semgrep completed with errors, but continuing due to NO_FAIL=true" + else + semgrep ci + fi \ No newline at end of file