diff --git a/.github/actions/setup-bot/action.yml b/.github/actions/setup-bot/action.yml new file mode 100644 index 000000000..0be2f43bf --- /dev/null +++ b/.github/actions/setup-bot/action.yml @@ -0,0 +1,33 @@ +name: 'Setup GitHub App Bot' +description: 'Generates a GitHub App Token and configures Git for a bot' +inputs: + app-id: + description: 'GitHub App ID' + required: True + private-key: + description: 'GitHub App Private Key' + required: True +outputs: + token: + description: 'Generated GitHub App Token' + value: ${{ steps.generate-token.outputs.token }} + committer: + description: 'Committer string for Git' + value: "${{ steps.generate-token.outputs.app-slug }}[bot] <${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com>" + app-slug: + description: 'GitHub App slug' + value: ${{ steps.generate-token.outputs.app-slug }} +runs: + using: 'composite' + steps: + - name: Generate a GitHub App Token + id: generate-token + uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + with: + app-id: ${{ inputs.app-id }} + private-key: ${{ inputs.private-key }} + - name: Configure Git + run: | + git config --global user.name "${{ steps.generate-token.outputs.app-slug }}[bot]" + git config --global user.email "${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com" + shell: bash diff --git a/.github/workflows/PR-Demo-Comment-with-react.yml b/.github/workflows/PR-Demo-Comment-with-react.yml index adb3e33cf..e9dcc3d8b 100644 --- a/.github/workflows/PR-Demo-Comment-with-react.yml +++ b/.github/workflows/PR-Demo-Comment-with-react.yml @@ -37,7 +37,7 @@ jobs: pr_repository: ${{ steps.get-pr-info.outputs.repository }} pr_ref: ${{ steps.get-pr-info.outputs.ref }} comment_id: ${{ github.event.comment.id }} - enable_security: ${{ steps.check-security-flag.outputs.enable_security }} + disable_security: ${{ steps.check-security-flag.outputs.disable_security }} steps: - name: Harden Runner @@ -84,7 +84,7 @@ jobs: core.setOutput('repository', repository); core.setOutput('ref', pr.head.ref); - + - name: Check for security/login flag id: check-security-flag env: @@ -92,10 +92,10 @@ jobs: run: | if [[ "$COMMENT_BODY" == *"security"* ]] || [[ "$COMMENT_BODY" == *"login"* ]]; then echo "Security flags detected in comment" - echo "enable_security=true" >> $GITHUB_OUTPUT + echo "disable_security=false" >> $GITHUB_OUTPUT else echo "No security flags detected in comment" - echo "enable_security=false" >> $GITHUB_OUTPUT + echo "disable_security=true" >> $GITHUB_OUTPUT fi - name: Add 'in_progress' reaction to comment @@ -155,10 +155,10 @@ jobs: - name: Run Gradle Command run: | - if [ "${{ needs.check-comment.outputs.enable_security }}" == "true" ]; then - export DOCKER_ENABLE_SECURITY=true + if [ "${{ needs.check-comment.outputs.disable_security }}" == "true" ]; then + export DISABLE_ADDITIONAL_FEATURES=true else - export DOCKER_ENABLE_SECURITY=false + export DISABLE_ADDITIONAL_FEATURES=false fi ./gradlew clean build env: @@ -180,7 +180,7 @@ jobs: password: ${{ secrets.DOCKER_HUB_API }} - name: Build and push PR-specific image - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: context: . file: ./Dockerfile @@ -199,7 +199,7 @@ jobs: id: deploy run: | # Set security settings based on flags - if [ "${{ needs.check-comment.outputs.enable_security }}" == "true" ]; then + if [ "${{ needs.check-comment.outputs.disable_security }}" == "false" ]; then DOCKER_SECURITY="true" LOGIN_SECURITY="true" SECURITY_STATUS="🔒 Security Enabled" @@ -223,7 +223,7 @@ jobs: - /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/config:/configs:rw - /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "${DOCKER_SECURITY}" + DISABLE_ADDITIONAL_FEATURES: "${DOCKER_SECURITY}" SECURITY_ENABLELOGIN: "${LOGIN_SECURITY}" SYSTEM_DEFAULTLOCALE: en-GB UI_APPNAME: "Stirling-PDF PR#${{ needs.check-comment.outputs.pr_number }}" @@ -250,7 +250,7 @@ jobs: docker-compose pull docker-compose up -d ENDSSH - + # Set output for use in PR comment echo "security_status=${SECURITY_STATUS}" >> $GITHUB_ENV diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1d5016ca8..7274c568b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,12 +40,12 @@ jobs: - name: Build with Gradle and no spring security run: ./gradlew clean build env: - DOCKER_ENABLE_SECURITY: false + DISABLE_ADDITIONAL_FEATURES: true - name: Build with Gradle and with spring security run: ./gradlew clean build env: - DOCKER_ENABLE_SECURITY: true + DISABLE_ADDITIONAL_FEATURES: false - name: Upload Test Reports if: always() @@ -56,6 +56,9 @@ jobs: build/reports/tests/ build/test-results/ build/reports/problems/ + /common/build/reports/tests/ + /common/build/test-results/ + /common/build/reports/problems/ retention-days: 3 check-licence: diff --git a/.github/workflows/check_properties.yml b/.github/workflows/check_properties.yml index 6825f59f9..d74e3084a 100644 --- a/.github/workflows/check_properties.yml +++ b/.github/workflows/check_properties.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest permissions: issues: write # Allow posting comments on issues/PRs - pull-requests: write + pull-requests: write # Allow writing to pull requests steps: - name: Harden Runner uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 @@ -25,15 +25,18 @@ jobs: - name: Checkout main branch first uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Set up Python - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + - name: Setup GitHub App Bot + id: setup-bot + uses: ./.github/actions/setup-bot with: - python-version: "3.12" + app-id: ${{ secrets.GH_APP_ID }} + private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} - name: Get PR data id: get-pr-data uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: + github-token: ${{ steps.setup-bot.outputs.token }} script: | const prNumber = context.payload.pull_request.number; const repoOwner = context.payload.repository.owner.login; @@ -54,7 +57,7 @@ jobs: - name: Fetch PR changed files id: fetch-pr-changes env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.setup-bot.outputs.token }} run: | echo "Fetching PR changed files..." echo "Getting list of changed files from PR..." @@ -64,6 +67,7 @@ jobs: id: determine-file uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: + github-token: ${{ steps.setup-bot.outputs.token }} script: | const fs = require("fs"); const path = require("path"); @@ -204,6 +208,7 @@ jobs: if: env.SCRIPT_OUTPUT != '' uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: + github-token: ${{ steps.setup-bot.outputs.token }} script: | const { GITHUB_REPOSITORY, SCRIPT_OUTPUT } = process.env; const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/'); @@ -219,7 +224,7 @@ jobs: const comment = comments.data.find(c => c.body.includes("## 🚀 Translation Verification Summary")); // Only update or create comments by the action user - const expectedActor = "github-actions[bot]"; + const expectedActor = "${{ steps.setup-bot.outputs.app-slug }}[bot]"; if (comment && comment.user.login === expectedActor) { // Update existing comment diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 304267160..5a662f423 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -24,4 +24,4 @@ jobs: - name: "Checkout Repository" uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: "Dependency Review" - uses: actions/dependency-review-action@ce3cf9537a52e8119d91fd484ab5b8a807627bf8 # v4.6.0 + uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1 diff --git a/.github/workflows/licenses-update.yml b/.github/workflows/licenses-update.yml index f2ab49f88..e040e5436 100644 --- a/.github/workflows/licenses-update.yml +++ b/.github/workflows/licenses-update.yml @@ -16,52 +16,50 @@ jobs: permissions: contents: write pull-requests: write + repository-projects: write # Required for enabling automerge steps: - name: Harden Runner uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 with: egress-policy: audit - - name: Generate GitHub App Token - id: generate-token - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + - name: Check out code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Setup GitHub App Bot + id: setup-bot + uses: ./.github/actions/setup-bot with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} - - name: Check out code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Set up JDK 17 uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: java-version: "17" distribution: "adopt" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - name: Setup Gradle + uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 - - name: check the licenses for compatibility + - name: Check licenses for compatibility run: ./gradlew clean checkLicense - - name: FAILED - check the licenses for compatibility + - name: Upload artifact on failure if: failure() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: dependencies-without-allowed-license.json - path: | - build/reports/dependency-license/dependencies-without-allowed-license.json + path: build/reports/dependency-license/dependencies-without-allowed-license.json retention-days: 3 - - name: Move and Rename License File + - name: Move and rename license file run: | mv build/reports/dependency-license/index.json src/main/resources/static/3rdPartyLicenses.json - - name: Set up git config - run: | - git config --global user.name "stirlingbot[bot]" - git config --global user.email "1113334+stirlingbot[bot]@users.noreply.github.com" - - - name: Run git add + - name: Commit changes run: | git add src/main/resources/static/3rdPartyLicenses.json git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV @@ -71,15 +69,15 @@ jobs: if: env.CHANGES_DETECTED == 'true' uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 with: - token: ${{ steps.generate-token.outputs.token }} + token: ${{ steps.setup-bot.outputs.token }} commit-message: "Update 3rd Party Licenses" - committer: "stirlingbot[bot] <1113334+stirlingbot[bot]@users.noreply.github.com>" - author: "stirlingbot[bot] <1113334+stirlingbot[bot]@users.noreply.github.com>" + committer: ${{ steps.setup-bot.outputs.committer }} + author: ${{ steps.setup-bot.outputs.committer }} signoff: true branch: update-3rd-party-licenses title: "Update 3rd Party Licenses" body: | - Auto-generated by StirlingBot + Auto-generated by ${{ steps.setup-bot.outputs.app-slug }}[bot] labels: licenses,github-actions draft: false delete-branch: true @@ -89,4 +87,4 @@ jobs: if: steps.cpr.outputs.pull-request-operation == 'created' run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}" env: - GH_TOKEN: ${{ steps.generate-token.outputs.token }} + GH_TOKEN: ${{ steps.setup-bot.outputs.token }} diff --git a/.github/workflows/multiOSReleases.yml b/.github/workflows/multiOSReleases.yml index b078e4015..c934b7129 100644 --- a/.github/workflows/multiOSReleases.yml +++ b/.github/workflows/multiOSReleases.yml @@ -48,11 +48,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - enable_security: [true, false] + disable_security: [true, false] include: - - enable_security: true + - disable_security: false file_suffix: "-with-login" - - enable_security: false + - disable_security: true file_suffix: "" steps: - name: Harden Runner @@ -68,14 +68,14 @@ jobs: java-version: "21" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 with: gradle-version: 8.14 - - name: Generate jar (With Security=${{ matrix.enable_security }}) + - name: Generate jar (Disable Security=${{ matrix.disable_security }}) run: ./gradlew clean createExe env: - DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }} + DISABLE_ADDITIONAL_FEATURES: ${{ matrix.disable_security }} STIRLING_PDF_DESKTOP_UI: false - name: Rename binaries @@ -98,11 +98,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - enable_security: [true, false] + disable_security: [true, false] include: - - enable_security: true + - disable_security: false file_suffix: "with-login-" - - enable_security: false + - disable_security: true file_suffix: "" steps: - name: Harden Runner @@ -156,7 +156,7 @@ jobs: java-version: "21" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 with: gradle-version: 8.14 @@ -171,7 +171,7 @@ jobs: - name: Build Installer run: ./gradlew build jpackage -x test --info env: - DOCKER_ENABLE_SECURITY: false + DISABLE_ADDITIONAL_FEATURES: true STIRLING_PDF_DESKTOP_UI: true BROWSER_OPEN: true diff --git a/.github/workflows/pre_commit.yml b/.github/workflows/pre_commit.yml index ce10a6c3e..5cca4e76e 100644 --- a/.github/workflows/pre_commit.yml +++ b/.github/workflows/pre_commit.yml @@ -20,58 +20,49 @@ jobs: with: egress-policy: audit - - name: Generate GitHub App Token - id: generate-token - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 - with: - app-id: ${{ secrets.GH_APP_ID }} - private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} - - - name: Get GitHub App User ID - id: get-user-id - run: echo "user-id=$(gh api "/users/${{ steps.generate-token.outputs.app-slug }}[bot]" --jq .id)" >> $GITHUB_OUTPUT - env: - GH_TOKEN: ${{ steps.generate-token.outputs.token }} - - - id: committer - run: | - echo "string=${{ steps.generate-token.outputs.app-slug }}[bot] <${{ steps.get-user-id.outputs.user-id }}+${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com>" >> "$GITHUB_OUTPUT" - - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 + + - name: Setup GitHub App Bot + id: setup-bot + uses: ./.github/actions/setup-bot + with: + app-id: ${{ secrets.GH_APP_ID }} + private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} + - name: Set up Python uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: 3.12 cache: 'pip' # caching pip dependencies + - name: Run Pre-Commit Hooks run: | pip install --require-hashes -r ./.github/scripts/requirements_pre_commit.txt + - run: pre-commit run --all-files -c .pre-commit-config.yaml continue-on-error: true - - name: Set up git config - run: | - git config --global user.name ${{ steps.generate-token.outputs.app-slug }}[bot] - git config --global user.email "${{ steps.get-user-id.outputs.user-id }}+${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com" + - name: git add run: | git add . git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV + - name: Create Pull Request if: env.CHANGES_DETECTED == 'true' uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 with: - token: ${{ steps.generate-token.outputs.token }} + token: ${{ steps.setup-bot.outputs.token }} commit-message: ":file_folder: pre-commit" - committer: ${{ steps.committer.outputs.string }} - author: ${{ steps.committer.outputs.string }} + committer: ${{ steps.setup-bot.outputs.committer }} + author: ${{ steps.setup-bot.outputs.committer }} signoff: true branch: pre-commit - title: "🤖 format everything with pre-commit by <${{ steps.generate-token.outputs.app-slug }}>" + title: "🤖 format everything with pre-commit by ${{ steps.setup-bot.outputs.app-slug }}" body: | - Auto-generated by [create-pull-request][1] with **${{ steps.generate-token.outputs.app-slug }}** + Auto-generated by [create-pull-request][1] with **${{ steps.setup-bot.outputs.app-slug }}** [1]: https://github.com/peter-evans/create-pull-request draft: false diff --git a/.github/workflows/push-docker.yml b/.github/workflows/push-docker.yml index e4532ff59..03ea3464d 100644 --- a/.github/workflows/push-docker.yml +++ b/.github/workflows/push-docker.yml @@ -30,14 +30,14 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 with: gradle-version: 8.14 - name: Run Gradle Command run: ./gradlew clean build env: - DOCKER_ENABLE_SECURITY: false + DISABLE_ADDITIONAL_FEATURES: true STIRLING_PDF_DESKTOP_UI: false - name: Install cosign @@ -90,7 +90,7 @@ jobs: - name: Build and push main Dockerfile id: build-push-regular - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: builder: ${{ steps.buildx.outputs.name }} context: . @@ -135,7 +135,7 @@ jobs: - name: Build and push Dockerfile-ultra-lite id: build-push-lite - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 if: github.ref != 'refs/heads/main' with: context: . @@ -166,7 +166,7 @@ jobs: - name: Build and push main Dockerfile fat id: build-push-fat - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 if: github.ref != 'refs/heads/main' with: builder: ${{ steps.buildx.outputs.name }} diff --git a/.github/workflows/releaseArtifacts.yml b/.github/workflows/releaseArtifacts.yml index c0d23ce19..5434eec96 100644 --- a/.github/workflows/releaseArtifacts.yml +++ b/.github/workflows/releaseArtifacts.yml @@ -13,11 +13,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - enable_security: [true, false] + disable_security: [true, false] include: - - enable_security: true + - disable_security: false file_suffix: "-with-login" - - enable_security: false + - disable_security: true file_suffix: "" outputs: version: ${{ steps.versionNumber.outputs.versionNumber }} @@ -35,14 +35,14 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 with: gradle-version: 8.14 - - name: Generate jar (With Security=${{ matrix.enable_security }}) + - name: Generate jar (Disable Security=${{ matrix.disable_security }}) run: ./gradlew clean createExe env: - DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }} + DISABLE_ADDITIONAL_FEATURES: ${{ matrix.disable_security }} STIRLING_PDF_DESKTOP_UI: false - name: Get version number @@ -75,11 +75,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - enable_security: [true, false] + disable_security: [true, false] include: - - enable_security: true + - disable_security: false file_suffix: "-with-login" - - enable_security: false + - disable_security: true file_suffix: "" steps: - name: Harden Runner @@ -153,11 +153,11 @@ jobs: contents: write strategy: matrix: - enable_security: [true, false] + disable_security: [true, false] include: - - enable_security: true + - disable_security: false file_suffix: "-with-login" - - enable_security: false + - disable_security: true file_suffix: "" steps: - name: Harden Runner diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 3c2d59e3e..1e531075a 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -44,7 +44,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 + uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 with: results_file: results.sarif results_format: sarif @@ -74,6 +74,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17 + uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 with: sarif_file: results.sarif diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml index ddf0980ab..16d004dd9 100644 --- a/.github/workflows/sonarqube.yml +++ b/.github/workflows/sonarqube.yml @@ -27,13 +27,13 @@ jobs: fetch-depth: 0 - name: Setup Gradle - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 - name: Build and analyze with Gradle env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - DOCKER_ENABLE_SECURITY: true + DISABLE_ADDITIONAL_FEATURES: false STIRLING_PDF_DESKTOP_UI: true run: | ./gradlew clean build sonar \ diff --git a/.github/workflows/swagger.yml b/.github/workflows/swagger.yml index 19c0aaa89..0e06cb1ee 100644 --- a/.github/workflows/swagger.yml +++ b/.github/workflows/swagger.yml @@ -26,7 +26,7 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 - name: Generate Swagger documentation run: ./gradlew generateOpenApiDocs diff --git a/.github/workflows/sync_files.yml b/.github/workflows/sync_files.yml index fe790c65b..92b4f3c87 100644 --- a/.github/workflows/sync_files.yml +++ b/.github/workflows/sync_files.yml @@ -16,79 +16,37 @@ permissions: contents: read jobs: - read_bot_entries: + sync-files: runs-on: ubuntu-latest - outputs: - userName: ${{ steps.get-user-id.outputs.user_name }} - userEmail: ${{ steps.get-user-id.outputs.user_email }} - committer: ${{ steps.committer.outputs.committer }} steps: - name: Harden Runner uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 with: egress-policy: audit - - name: Generate GitHub App Token - id: generate-token - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Setup GitHub App Bot + id: setup-bot + uses: ./.github/actions/setup-bot with: app-id: ${{ secrets.GH_APP_ID }} private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} - - name: Get GitHub App User ID - id: get-user-id - run: | - USER_NAME="${{ steps.generate-token.outputs.app-slug }}[bot]" - USER_ID=$(gh api "/users/$USER_NAME" --jq .id) - USER_EMAIL="$USER_ID+$USER_NAME@users.noreply.github.com" - echo "user_name=$USER_NAME" >> "$GITHUB_OUTPUT" - echo "user_email=$USER_EMAIL" >> "$GITHUB_OUTPUT" - echo "user-id=$USER_ID" >> "$GITHUB_OUTPUT" - env: - GH_TOKEN: ${{ steps.generate-token.outputs.token }} - - - id: committer - run: | - COMMITTER="${{ steps.get-user-id.outputs.user_name }} <${{ steps.get-user-id.outputs.user_email }}>" - echo "committer=$COMMITTER" >> "$GITHUB_OUTPUT" - - sync-files: - needs: ["read_bot_entries"] - runs-on: ubuntu-latest - steps: - - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 - with: - egress-policy: audit - - - name: Generate GitHub App Token - id: generate-token - uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 - with: - app-id: ${{ vars.GH_APP_ID }} - private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} - - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Set up Python uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.12" - cache: 'pip' # caching pip dependencies + cache: "pip" # caching pip dependencies - name: Sync translation property files run: | python .github/scripts/check_language_properties.py --reference-file "src/main/resources/messages_en_GB.properties" --branch main - - name: Set up git config - run: | - git config --global user.name ${{ needs.read_bot_entries.outputs.userName }} - git config --global user.email ${{ needs.read_bot_entries.outputs.userEmail }} - - - name: Run git add + - name: Commit translation files run: | git add src/main/resources/messages_*.properties - git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "no changes" + git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "No changes detected" - name: Install dependencies run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt @@ -100,15 +58,16 @@ jobs: - name: Run git add run: | git add README.md - git diff --staged --quiet || git commit -m ":memo: Sync README.md" || echo "no changes" + git diff --staged --quiet || git commit -m ":memo: Sync README.md" || echo "No changes detected" - name: Create Pull Request + if: always() uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 with: - token: ${{ steps.generate-token.outputs.token }} + token: ${{ steps.setup-bot.outputs.token }} commit-message: Update files - committer: ${{ needs.read_bot_entries.outputs.committer }} - author: ${{ needs.read_bot_entries.outputs.committer }} + committer: ${{ steps.setup-bot.outputs.committer }} + author: ${{ steps.setup-bot.outputs.committer }} signoff: true branch: sync_readme title: ":globe_with_meridians: Sync Translations + Update README Progress Table" diff --git a/.github/workflows/testdriver.yml b/.github/workflows/testdriver.yml index 68c4fabb2..e4ef4138f 100644 --- a/.github/workflows/testdriver.yml +++ b/.github/workflows/testdriver.yml @@ -28,7 +28,7 @@ jobs: - name: Build with Gradle run: ./gradlew clean build env: - DOCKER_ENABLE_SECURITY: false + DISABLE_ADDITIONAL_FEATURES: true - name: Set up Docker Buildx uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 @@ -46,7 +46,7 @@ jobs: password: ${{ secrets.DOCKER_HUB_API }} - name: Build and push test image - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: context: . file: ./Dockerfile @@ -76,7 +76,7 @@ jobs: - /stirling/test-${{ github.sha }}/config:/configs:rw - /stirling/test-${{ github.sha }}/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "false" + DISABLE_ADDITIONAL_FEATURES: "true" SECURITY_ENABLELOGIN: "false" SYSTEM_DEFAULTLOCALE: en-GB UI_APPNAME: "Stirling-PDF Test" diff --git a/.gitignore b/.gitignore index 90d48ccea..06602d03b 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ local.properties .recommenders .classpath .project +*.local.json version.properties #### Stirling-PDF Files ### diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c792e50a0..beec5eb99 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.6 + rev: v0.11.11 hooks: - id: ruff args: @@ -22,7 +22,7 @@ repos: files: \.(html|css|js|py|md)$ exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js) - repo: https://github.com/gitleaks/gitleaks - rev: v8.24.3 + rev: v8.26.0 hooks: - id: gitleaks - repo: https://github.com/pre-commit/pre-commit-hooks diff --git a/.vscode/settings.json b/.vscode/settings.json index a4be4d0cd..f759730f2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,7 +10,7 @@ "java.configuration.updateBuildConfiguration": "interactive", "java.format.enabled": true, "java.format.settings.profile": "GoogleStyle", - "java.format.settings.google.version": "1.26.0", + "java.format.settings.google.version": "1.27.0", "java.format.settings.google.extra": "--aosp --skip-sorting-imports --skip-javadoc-formatting", // (DE) Aktiviert Kommentare im Java-Format. // (EN) Enables comments in Java formatting. @@ -49,7 +49,11 @@ ".venv*/", ".vscode/", "bin/", + "common/bin/", + "proprietary/bin/", "build/", + "common/build/", + "proprietary/build/", "configs/", "customFiles/", "docs/", @@ -63,6 +67,8 @@ ".git-blame-ignore-revs", ".gitattributes", ".gitignore", + "common/.gitignore", + "proprietary/.gitignore", ".pre-commit-config.yaml", ], // Enables signature help in Java. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..461d26c07 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,24 @@ +# Codex Contribution Guidelines for Stirling-PDF + +This file provides high-level instructions for Codex when modifying any files within this repository. Follow these rules to ensure changes remain consistent with the existing project structure. + +## 1. Code Style and Formatting +- Respect the `.editorconfig` settings located in the repository root. Java files use 4 spaces; HTML, JS, and Python generally use 2 spaces. Lines should end with `LF`. +- Format Java code with `./gradlew spotlessApply` before committing. +- Review `DeveloperGuide.md` for project structure and design details before making significant changes. + +## 2. Testing +- Run `./gradlew build` before committing changes to ensure the project compiles. +- If the build cannot complete due to environment restrictions, DO NOT COMMIT THE CHANGE + +## 3. Commits +- Keep commits focused. Group related changes together and provide concise commit messages. +- Ensure the working tree is clean (`git status`) before concluding your work. + +## 4. Pull Requests +- Summarize what was changed and why. Include build results from `./gradlew build` in the PR description. +- Note that the code was generated with the assistance of AI. + +## 5. Translations +- Only modify `messages_en_GB.properties` when adding or updating translations. + diff --git a/DeveloperGuide.md b/DeveloperGuide.md index bbf8b8677..d484838e0 100644 --- a/DeveloperGuide.md +++ b/DeveloperGuide.md @@ -55,7 +55,7 @@ Stirling-PDF uses Lombok to reduce boilerplate code. Some IDEs, like Eclipse, do Visit the [Lombok website](https://projectlombok.org/setup/) for installation instructions specific to your IDE. 5. Add environment variable -For local testing, you should generally be testing the full 'Security' version of Stirling-PDF. To do this, you must add the environment flag DOCKER_ENABLE_SECURITY=true to your system and/or IDE build/run step. +For local testing, you should generally be testing the full 'Security' version of Stirling PDF. To do this, you must add the environment flag DISABLE_ADDITIONAL_FEATURES=false to your system and/or IDE build/run step. ## 4. Project Structure @@ -114,9 +114,9 @@ Stirling-PDF offers several Docker versions: Stirling-PDF provides several example Docker Compose files in the `exampleYmlFiles` directory, such as: -- `docker-compose-latest.yml`: Latest version without security features -- `docker-compose-latest-security.yml`: Latest version with security features enabled -- `docker-compose-latest-fat-security.yml`: Fat version with security features enabled +- `docker-compose-latest.yml`: Latest version without login and security features +- `docker-compose-latest-security.yml`: Latest version with login and security features enabled +- `docker-compose-latest-fat-security.yml`: Fat version with login and security features enabled These files provide pre-configured setups for different scenarios. For example, here's a snippet from `docker-compose-latest-security.yml`: @@ -141,7 +141,7 @@ services: - /stirling/latest/config:/configs:rw - /stirling/latest/logs:/logs:rw environment: - DOCKER_ENABLE_SECURITY: "true" + DISABLE_ADDITIONAL_FEATURES: "false" SECURITY_ENABLELOGIN: "true" PUID: 1002 PGID: 1002 @@ -170,7 +170,7 @@ Stirling-PDF uses different Docker images for various configurations. The build 1. Set the security environment variable: ```bash - export DOCKER_ENABLE_SECURITY=false # or true for security-enabled builds + export DISABLE_ADDITIONAL_FEATURES=true # or false for to enable login and security features for builds ``` 2. Build the project with Gradle: @@ -193,10 +193,10 @@ Stirling-PDF uses different Docker images for various configurations. The build docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-ultra-lite -f ./Dockerfile.ultra-lite . ``` - For the fat version (with security enabled): + For the fat version (with login and security features enabled): ```bash - export DOCKER_ENABLE_SECURITY=true + export DISABLE_ADDITIONAL_FEATURES=false docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-fat -f ./Dockerfile.fat . ``` @@ -541,7 +541,7 @@ This would generate n entries of tr for each person in exampleData ```html
This is valid HTML with formatting.
", + new String[] {"", "", ""}),
+ Arguments.of(
+ " Text with bold, italic, underline, "
+ + "emphasis, strong, Styled text Example Link";
+
+ // Act
+ String sanitizedHtml = CustomHtmlSanitizer.sanitize(htmlWithLink);
+
+ // Assert
+ // The most important aspect is that the link content is preserved
+ assertTrue(sanitizedHtml.contains("Example Link"), "Link text should be preserved");
+
+ // Check that the href is present in some form
+ assertTrue(sanitizedHtml.contains("href="), "Link href attribute should be present");
+
+ // Check that the URL is present in some form
+ assertTrue(sanitizedHtml.contains("example.com"), "Link URL should be preserved");
+
+ // OWASP sanitizer may handle title attributes differently depending on version
+ // So we won't make strict assertions about the title attribute
+ }
+
+ @Test
+ void testSanitizeDisallowsJavaScriptLinks() {
+ // Arrange
+ String htmlWithJsLink = "Malicious Link";
+
+ // Act
+ String sanitizedHtml = CustomHtmlSanitizer.sanitize(htmlWithJsLink);
+
+ // Assert
+ assertFalse(sanitizedHtml.contains("javascript:"), "JavaScript URLs should be removed");
+ // The link tag might still be there, but the href should be sanitized
+ assertTrue(sanitizedHtml.contains("Malicious Link"), "Link text should be preserved");
+ }
+
+ @Test
+ void testSanitizeAllowsTables() {
+ // Arrange - Testing Sanitizers.TABLES
+ String htmlWithTable =
+ " Safe contentstrikethrough, "
+ + "strike, subscript, superscript, "
+ + "teletype, code
, big, small.Heading 1
Heading 2
Heading 3
"
+ + "Heading 4
Heading 5
Heading 6
"
+ + "Blockquote
"
+ + "
",
+ new String[] {
+ "", "
", "
", "
", "
", "
"
+ + "
";
+
+ // Act
+ String sanitizedHtml = CustomHtmlSanitizer.sanitize(htmlWithTable);
+
+ // Assert
+ assertTrue(sanitizedHtml.contains(" "
+ + "Header 1 Header 2 "
+ + "Cell 1 Cell 2 "
+ + "Footer "), "Table rows should be preserved");
+ assertTrue(sanitizedHtml.contains("
"), "Table headers should be preserved");
+ assertTrue(sanitizedHtml.contains(" "), "Table cells should be preserved");
+ // Note: border attribute might be removed as it's deprecated in HTML5
+
+ // Check for content values instead of exact tag formats because
+ // the sanitizer may normalize tags and attributes
+ assertTrue(sanitizedHtml.contains("Header 1"), "Table header content should be preserved");
+ assertTrue(sanitizedHtml.contains("Cell 1"), "Table cell content should be preserved");
+ assertTrue(sanitizedHtml.contains("Footer"), "Table footer content should be preserved");
+
+ // OWASP sanitizer may not preserve these structural elements or attributes in the same
+ // format
+ // So we check for the content rather than the exact structure
+ }
+
+ @Test
+ void testSanitizeAllowsImages() {
+ // Arrange - Testing Sanitizers.IMAGES
+ String htmlWithImage =
+ " ";
+
+ // Act
+ String sanitizedHtml = CustomHtmlSanitizer.sanitize(htmlWithImage);
+
+ // Assert
+ assertTrue(sanitizedHtml.contains("
";
+
+ // Act
+ String sanitizedHtml = CustomHtmlSanitizer.sanitize(htmlWithDataUrlImage);
+
+ // Assert
+ assertFalse(
+ sanitizedHtml.contains("data:image/svg"),
+ "Data URLs with potentially malicious content should be removed");
+ }
+
+ @Test
+ void testSanitizeRemovesJavaScriptInAttributes() {
+ // Arrange
+ String htmlWithJsEvent =
+ "Click me";
+
+ // Act
+ String sanitizedHtml = CustomHtmlSanitizer.sanitize(htmlWithJsEvent);
+
+ // Assert
+ assertFalse(
+ sanitizedHtml.contains("onclick"), "JavaScript event handlers should be removed");
+ assertFalse(
+ sanitizedHtml.contains("onmouseover"),
+ "JavaScript event handlers should be removed");
+ assertTrue(sanitizedHtml.contains("Click me"), "Link text should be preserved");
+ }
+
+ @Test
+ void testSanitizeRemovesScriptTags() {
+ // Arrange
+ String htmlWithScript = "