diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 000000000..6e006423a --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,12 @@ +{ + "permissions": { + "allow": [ + "Bash(chmod:*)", + "Bash(mkdir:*)", + "Bash(./gradlew:*)", + "Bash(grep:*)", + "Bash(cat:*)" + ], + "deny": [] + } +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index ca0238887..d45455a7a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,7 @@ root = true [*] +charset = utf-8 indent_style = space indent_size = 4 end_of_line = lf @@ -26,6 +27,26 @@ trim_trailing_whitespace = false [*.js] indent_size = 2 +[*.css] +# CSS files typically use an indent size of 2 spaces for better readability and alignment with community standards. +indent_size = 2 + [*.yaml] +# YAML files use an indent size of 2 spaces to maintain consistency with common YAML formatting practices. +indent_size = 2 insert_final_newline = false trim_trailing_whitespace = false + +[*.yml] +# YML files follow the same conventions as YAML files, using an indent size of 2 spaces. +indent_size = 2 +insert_final_newline = false +trim_trailing_whitespace = false + +[*.json] +# JSON files use an indent size of 2 spaces, which is the standard for JSON formatting. +indent_size = 2 + +[*.jsonc] +# JSONC (JSON with comments) files also follow the standard JSON formatting with an indent size of 2 spaces. +indent_size = 2 diff --git a/.gitattributes b/.gitattributes index c498408ab..f72c204bd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,10 +1,10 @@ * text=auto eol=lf # Ignore all JavaScript files in a directory -src/main/resources/static/pdfjs/* linguist-vendored -src/main/resources/static/pdfjs/** linguist-vendored -src/main/resources/static/pdfjs-legacy/* linguist-vendored -src/main/resources/static/pdfjs-legacy/** linguist-vendored -src/main/resources/static/css/bootstrap-icons.css linguist-vendored -src/main/resources/static/css/bootstrap.min.css linguist-vendored -src/main/resources/static/css/fonts/* linguist-vendored +stirling-pdf/src/main/resources/static/pdfjs/* linguist-vendored +stirling-pdf/src/main/resources/static/pdfjs/** linguist-vendored +stirling-pdf/src/main/resources/static/pdfjs-legacy/* linguist-vendored +stirling-pdf/src/main/resources/static/pdfjs-legacy/** linguist-vendored +stirling-pdf/src/main/resources/static/css/bootstrap-icons.css linguist-vendored +stirling-pdf/src/main/resources/static/css/bootstrap.min.css linguist-vendored +stirling-pdf/src/main/resources/static/css/fonts/* linguist-vendored 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/config/repo_devs.json b/.github/config/repo_devs.json new file mode 100644 index 000000000..6f8b9f90c --- /dev/null +++ b/.github/config/repo_devs.json @@ -0,0 +1,12 @@ +{ + "repo_devs": [ + "Frooodle", + "sf298", + "Ludy87", + "LaserKaspar", + "sbplat", + "reecebrowne", + "DarioGii", + "ConnorYoh" + ] +} diff --git a/.github/config/system-prompt.txt b/.github/config/system-prompt.txt new file mode 100644 index 000000000..f3842878f --- /dev/null +++ b/.github/config/system-prompt.txt @@ -0,0 +1,13 @@ +You are a professional software engineer specializing in reviewing pull request titles. + +Your job is to analyze a git diff and an existing PR title, then evaluate and improve the PR title. + +You must: +- Always return valid JSON +- Only return the JSON response (no Markdown, no formatting) +- Use one of these conventional commit types at the beginning of the title: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test +- Use lowercase only, no emojis, no trailing period +- Ensure the title is between 5 and 72 printable ASCII characters +- Never let spelling or grammar errors affect the rating +- If the PR title is rated 6 or higher and only contains spelling or grammar mistakes, correct it - do not rephrase it +- If the PR title is rated below 6, generate a new, better title based on the diff diff --git a/.github/labeler-config-srvaroa.yml b/.github/labeler-config-srvaroa.yml new file mode 100644 index 000000000..f8e66fab4 --- /dev/null +++ b/.github/labeler-config-srvaroa.yml @@ -0,0 +1,142 @@ +version: 1 +labels: + + - label: "Bugfix" + title: '^fix:.*' + + - label: "enhancement" + title: '^feat:.*' + + - label: "build" + title: '^build:.*' + + - label: "chore" + title: '^chore:.*' + + - label: "ci" + title: '^ci:.*' + + - label: "perf" + title: '^perf:.*' + + - label: "refactor" + title: '^refactor:.*' + + - label: "revert" + title: '^revert:.*' + + - label: "style" + title: '^style:.*' + + - label: "Documentation" + title: '^docs:.*' + + - label: 'API' + title: '.*openapi.*' + + - label: 'Translation' + files: + - 'stirling-pdf/src/main/resources/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}.properties' + - 'scripts/ignore_translation.toml' + - 'stirling-pdf/src/main/resources/templates/fragments/languages.html' + - '.github/scripts/check_language_properties.py' + + - label: 'Front End' + files: + - 'stirling-pdf/src/main/resources/templates/.*' + - 'proprietary/src/main/resources/templates/.*' + - 'stirling-pdf/src/main/resources/static/.*' + - 'proprietary/src/main/resources/static/.*' + - 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/web/.*' + - 'stirling-pdf/src/main/java/stirling/software/SPDF/UI/.*' + - 'proprietary/src/main/java/stirling/software/proprietary/security/controller/web/.*' + + - label: 'Java' + files: + - 'common/src/main/java/.*.java' + - 'proprietary/src/main/java/.*.java' + - 'stirling-pdf/src/main/java/.*.java' + + - label: 'Back End' + files: + - 'stirling-pdf/src/main/java/stirling/software/SPDF/config/.*' + - 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/.*' + - 'stirling-pdf/src/main/resources/settings.yml.template' + - 'stirling-pdf/src/main/resources/application.properties' + - 'stirling-pdf/src/main/resources/banner.txt' + - 'scripts/png_to_webp.py' + - 'split_photos.py' + - 'application.properties' + + - label: 'Security' + files: + - 'proprietary/src/main/java/stirling/software/proprietary/security/.*' + - 'scripts/download-security-jar.sh' + - '.github/workflows/dependency-review.yml' + - '.github/workflows/scorecards.yml' + + - label: 'API' + files: + - 'stirling-pdf/src/main/java/stirling/software/SPDF/config/OpenApiConfig.java' + - 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java' + - 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/api/.*' + - 'stirling-pdf/src/main/java/stirling/software/SPDF/model/api/.*' + - 'proprietary/src/main/java/stirling/software/proprietary/security/controller/api/.*' + - 'scripts/png_to_webp.py' + - 'split_photos.py' + - '.github/workflows/swagger.yml' + + - label: 'Documentation' + files: + - '.*.md' + - 'scripts/counter_translation.py' + - 'scripts/ignore_translation.toml' + + - label: 'Docker' + files: + - '.github/workflows/build.yml' + - '.github/workflows/push-docker.yml' + - 'Dockerfile' + - 'Dockerfile.fat' + - 'Dockerfile.ultra-lite' + - 'exampleYmlFiles/.*.yml' + - 'scripts/download-security-jar.sh' + - 'scripts/init.sh' + - 'scripts/init-without-ocr.sh' + - 'scripts/installFonts.sh' + - 'test.sh' + - 'test2.sh' + + - label: 'Devtools' + files: + - '.devcontainer/.*' + - 'Dockerfile.dev' + - '.vscode/.*' + - '.editorconfig' + - '.pre-commit-config' + - '.github/workflows/pre_commit.yml' + - 'HowToAddNewLanguage.md' + + - label: 'Test' + files: + - 'common/src/test/.*' + - 'proprietary/src/test/.*' + - 'stirling-pdf/src/test/.*' + - 'testing/.*' + - '.github/workflows/scorecards.yml' + - 'exampleYmlFiles/test_cicd.yml' + + - label: 'Github' + files: + - '.github/.*' + + - label: 'Gradle' + files: + - 'gradle/.*' + - 'gradlew' + - 'gradlew.bat' + - 'settings.gradle' + - 'build.gradle' + - 'common/build.gradle' + - 'proprietary/build.gradle' + - 'stirling-pdf/build.gradle' diff --git a/.github/labeler-config.yml b/.github/labeler-config.yml index bb52c7b85..d1a340065 100644 --- a/.github/labeler-config.yml +++ b/.github/labeler-config.yml @@ -1,60 +1,45 @@ Translation: - changed-files: - - any-glob-to-any-file: 'src/main/resources/messages_*_*.properties' + - any-glob-to-any-file: 'stirling-pdf/src/main/resources/messages_*_*.properties' - any-glob-to-any-file: 'scripts/ignore_translation.toml' - - any-glob-to-any-file: 'src/main/resources/templates/fragments/languages.html' + - any-glob-to-any-file: 'stirling-pdf/src/main/resources/templates/fragments/languages.html' Front End: - changed-files: - - any-glob-to-any-file: 'src/main/resources/templates/**/*' - - any-glob-to-any-file: 'src/main/resources/static/**/*' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/**' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/UI/**/*' + - any-glob-to-any-file: 'stirling-pdf/src/main/resources/templates/**/*' + - any-glob-to-any-file: 'stirling-pdf/src/main/resources/static/**/*' + - any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/web/**' + - any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/UI/**/*' Java: - changed-files: - - any-glob-to-any-file: 'src/main/java/**/*.java' + - any-glob-to-any-file: 'common/src/main/java/**/*.java' + - any-glob-to-any-file: 'proprietary/src/main/java/**/*.java' + - any-glob-to-any-file: 'stirling-pdf/src/main/java/**/*.java' Back End: - changed-files: - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/**/*' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/**/*' - - any-glob-to-any-file: 'src/main/resources/settings.yml.template' - - any-glob-to-any-file: 'src/main/resources/application.properties' - - any-glob-to-any-file: 'src/main/resources/banner.txt' + - any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/config/**/*' + - any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/**/*' + - any-glob-to-any-file: 'stirling-pdf/src/main/resources/settings.yml.template' + - any-glob-to-any-file: 'stirling-pdf/src/main/resources/application.properties' + - any-glob-to-any-file: 'stirling-pdf/src/main/resources/banner.txt' - any-glob-to-any-file: 'scripts/png_to_webp.py' - any-glob-to-any-file: 'split_photos.py' Security: - changed-files: - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/interfaces/DatabaseInterface.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/security/**/*' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/DatabaseController.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/EmailController.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/H2SQLController.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/AccountWebController.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/DatabaseWebController.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/UserController.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/api/Email.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/exception/BackupNotFoundException.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/exception/NoProviderFoundExceptionjava' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/provider/**/*' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/AuthenticationType.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/ApiKeyAuthenticationToken.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/AttemptCounter.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/Authority.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/PersistentLogin.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/SessionEntity.java' + - any-glob-to-any-file: 'proprietary/src/main/java/stirling/software/proprietary/security/**/*' - any-glob-to-any-file: 'scripts/download-security-jar.sh' - any-glob-to-any-file: '.github/workflows/dependency-review.yml' - any-glob-to-any-file: '.github/workflows/scorecards.yml' API: - changed-files: - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/OpenApiConfig.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/MetricsController.java' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/api/**/*' - - any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/api/**/*' + - any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/config/OpenApiConfig.java' + - any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/web/MetricsController.java' + - any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/controller/api/**/*' + - any-glob-to-any-file: 'stirling-pdf/src/main/java/stirling/software/SPDF/model/api/**/*' - any-glob-to-any-file: 'scripts/png_to_webp.py' - any-glob-to-any-file: 'split_photos.py' - any-glob-to-any-file: '.github/workflows/swagger.yml' @@ -88,7 +73,9 @@ Devtools: Test: - changed-files: - any-glob-to-any-file: 'cucumber/**/*' - - any-glob-to-any-file: 'src/test/**/*' + - any-glob-to-any-file: 'common/src/test/**/*' + - any-glob-to-any-file: 'proprietary/src/test/**/*' + - any-glob-to-any-file: 'stirling-pdf/src/test/**/*' - any-glob-to-any-file: 'src/testing/**/*' - any-glob-to-any-file: '.pre-commit-config' - any-glob-to-any-file: '.github/workflows/pre_commit.yml' diff --git a/.github/labels.yml b/.github/labels.yml index f4e077f0a..b7f5642e7 100644 --- a/.github/labels.yml +++ b/.github/labels.yml @@ -111,3 +111,67 @@ - name: "Devtools" color: "FF9E1F" description: "Development tools" +- name: "Bugfix" + color: "FF9E1F" + description: "Pull requests that fix bugs" +- name: "Gradle" + color: "FF9E1F" + description: "Pull requests that update Gradle code" +- name: "build" + color: "1E90FF" + description: "Changes that affect the build system or external dependencies" +- name: "chore" + color: "FFD700" + description: "Routine tasks or maintenance that don't modify src or test files" +- name: "ci" + color: "4682B4" + description: "Changes to CI configuration files and scripts" +- name: "perf" + color: "FF69B4" + description: "Changes that improve performance" +- name: "refactor" + color: "9932CC" + description: "Code changes that neither fix a bug nor add a feature" +- name: "revert" + color: "DC143C" + description: "Reverts a previous commit" +- name: "style" + color: "FFA500" + description: "Changes that do not affect the meaning of the code (formatting, etc.)" +- name: "admin" + color: "195055" +- name: "codex" + color: "ededed" + description: null +- name: "Github" + color: "0052CC" +- name: "github_actions" + color: "000000" + description: "Pull requests that update GitHub Actions code" +- name: "needs-changes" + color: "A65A86" +- name: "on-hold" + color: "2526F9" +- name: "python" + color: "2b67c6" + description: "Pull requests that update Python code" +- name: "size:L" + color: "eb9500" + description: "This PR changes 100-499 lines ignoring generated files." +- name: "size:M" + color: "ebb800" + description: "This PR changes 30-99 lines ignoring generated files." +- name: "size:S" + color: "77b800" + description: "This PR changes 10-29 lines ignoring generated files." +- name: "size:XL" + color: "ff823f" + description: "This PR changes 500-999 lines ignoring generated files." +- name: "size:XS" + color: "00ff00" + description: "This PR changes 0-9 lines ignoring generated files." +- name: "size:XXL" + color: "ffb8b8" + description: "This PR changes 1000+ lines ignoring generated files." +- name: "to research" + color: "FBCA04" diff --git a/.github/scripts/check_language_properties.py b/.github/scripts/check_language_properties.py index 10e6fb650..659ff7027 100644 --- a/.github/scripts/check_language_properties.py +++ b/.github/scripts/check_language_properties.py @@ -196,7 +196,9 @@ def check_for_differences(reference_file, file_list, branch, actor): if len(file_list) == 1: file_arr = file_list[0].split() - base_dir = os.path.abspath(os.path.join(os.getcwd(), "src", "main", "resources")) + base_dir = os.path.abspath( + os.path.join(os.getcwd(), "stirling-pdf", "src", "main", "resources") + ) for file_path in file_arr: file_normpath = os.path.normpath(file_path) @@ -216,10 +218,19 @@ def check_for_differences(reference_file, file_list, branch, actor): or ( # only local windows command not file_normpath.startswith( - os.path.join("", "src", "main", "resources", "messages_") + os.path.join( + "", "stirling-pdf", "src", "main", "resources", "messages_" + ) ) and not file_normpath.startswith( - os.path.join(os.getcwd(), "src", "main", "resources", "messages_") + os.path.join( + os.getcwd(), + "stirling-pdf", + "src", + "main", + "resources", + "messages_", + ) ) ) or not file_normpath.endswith(".properties") @@ -317,7 +328,7 @@ def check_for_differences(reference_file, file_list, branch, actor): report.append("## āŒ Overall Check Status: **_Failed_**") report.append("") report.append( - f"@{actor} please check your translation if it conforms to the standard. Follow the format of [messages_en_GB.properties](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/messages_en_GB.properties)" + f"@{actor} please check your translation if it conforms to the standard. Follow the format of [messages_en_GB.properties](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/stirling-pdf/src/main/resources/messages_en_GB.properties)" ) else: report.append("## āœ… Overall Check Status: **_Success_**") @@ -377,7 +388,12 @@ if __name__ == "__main__": else: file_list = glob.glob( os.path.join( - os.getcwd(), "src", "main", "resources", "messages_*.properties" + os.getcwd(), + "stirling-pdf", + "src", + "main", + "resources", + "messages_*.properties", ) ) update_missing_keys(args.reference_file, file_list) diff --git a/.github/workflows/PR-Demo-Comment-with-react.yml b/.github/workflows/PR-Demo-Comment-with-react.yml index adb3e33cf..874081068 100644 --- a/.github/workflows/PR-Demo-Comment-with-react.yml +++ b/.github/workflows/PR-Demo-Comment-with-react.yml @@ -37,11 +37,12 @@ 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 }} + enable_pro: ${{ steps.check-pro-flag.outputs.enable_pro }} + enable_enterprise: ${{ steps.check-pro-flag.outputs.enable_enterprise }} steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -84,7 +85,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 +93,29 @@ 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: Check for pro flag + id: check-pro-flag + env: + COMMENT_BODY: ${{ github.event.comment.body }} + run: | + if [[ "$COMMENT_BODY" == *"pro"* ]] || [[ "$COMMENT_BODY" == *"premium"* ]]; then + echo "pro flags detected in comment" + echo "enable_pro=true" >> $GITHUB_OUTPUT + echo "enable_enterprise=false" >> $GITHUB_OUTPUT + elif [[ "$COMMENT_BODY" == *"enterprise"* ]]; then + echo "enterprise flags detected in comment" + echo "enable_enterprise=true" >> $GITHUB_OUTPUT + echo "enable_pro=true" >> $GITHUB_OUTPUT + else + echo "No pro or enterprise flags detected in comment" + echo "enable_pro=false" >> $GITHUB_OUTPUT + echo "enable_enterprise=false" >> $GITHUB_OUTPUT fi - name: Add 'in_progress' reaction to comment @@ -129,7 +149,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -155,17 +175,17 @@ 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: STIRLING_PDF_DESKTOP_UI: false - name: Set up Docker Buildx - uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Get version number id: versionNumber @@ -180,7 +200,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,16 +219,31 @@ jobs: id: deploy run: | # Set security settings based on flags - if [ "${{ needs.check-comment.outputs.enable_security }}" == "true" ]; then - DOCKER_SECURITY="true" + if [ "${{ needs.check-comment.outputs.disable_security }}" == "false" ]; then + DISABLE_ADDITIONAL_FEATURES="false" LOGIN_SECURITY="true" SECURITY_STATUS="šŸ”’ Security Enabled" else - DOCKER_SECURITY="false" + DISABLE_ADDITIONAL_FEATURES="true" LOGIN_SECURITY="false" SECURITY_STATUS="Security Disabled" fi + # Set pro/enterprise settings (enterprise implies pro) + if [ "${{ needs.check-comment.outputs.enable_enterprise }}" == "true" ]; then + PREMIUM_ENABLED="true" + PREMIUM_KEY="${{ secrets.ENTERPRISE_KEY }}" + PREMIUM_PROFEATURES_AUDIT_ENABLED="true" + elif [ "${{ needs.check-comment.outputs.enable_pro }}" == "true" ]; then + PREMIUM_ENABLED="true" + PREMIUM_KEY="${{ secrets.PREMIUM_KEY }}" + PREMIUM_PROFEATURES_AUDIT_ENABLED="true" + else + PREMIUM_ENABLED="false" + PREMIUM_KEY="" + PREMIUM_PROFEATURES_AUDIT_ENABLED="false" + fi + # First create the docker-compose content locally cat > docker-compose.yml << EOF version: '3.3' @@ -223,7 +258,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: "${DISABLE_ADDITIONAL_FEATURES}" SECURITY_ENABLELOGIN: "${LOGIN_SECURITY}" SYSTEM_DEFAULTLOCALE: en-GB UI_APPNAME: "Stirling-PDF PR#${{ needs.check-comment.outputs.pr_number }}" @@ -232,6 +267,9 @@ jobs: SYSTEM_MAXFILESIZE: "100" METRICS_ENABLED: "true" SYSTEM_GOOGLEVISIBILITY: "false" + PREMIUM_KEY: "${PREMIUM_KEY}" + PREMIUM_ENABLED: "${PREMIUM_ENABLED}" + PREMIUM_PROFEATURES_AUDIT_ENABLED: "${PREMIUM_PROFEATURES_AUDIT_ENABLED}" restart: on-failure:5 EOF @@ -250,7 +288,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/PR-Demo-cleanup.yml b/.github/workflows/PR-Demo-cleanup.yml index 1962bb83d..ae17ee7c8 100644 --- a/.github/workflows/PR-Demo-cleanup.yml +++ b/.github/workflows/PR-Demo-cleanup.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit diff --git a/.github/workflows/ai_pr_title_review.yml b/.github/workflows/ai_pr_title_review.yml new file mode 100644 index 000000000..0447a9b62 --- /dev/null +++ b/.github/workflows/ai_pr_title_review.yml @@ -0,0 +1,228 @@ +name: AI - PR Title Review + +on: + pull_request: + types: [opened, edited] + branches: [main] + +permissions: # required for secure-repo hardening + contents: read + +jobs: + ai-title-review: + permissions: + contents: read + pull-requests: write + models: read + + runs-on: ubuntu-latest + + steps: + - name: Harden Runner + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 + with: + egress-policy: audit + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Configure Git to suppress detached HEAD warning + run: git config --global advice.detachedHead false + + - name: Setup GitHub App Bot + if: github.actor != 'dependabot[bot]' + id: setup-bot + uses: ./.github/actions/setup-bot + continue-on-error: true + with: + app-id: ${{ secrets.GH_APP_ID }} + private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} + + - name: Check if actor is repo developer + id: actor + run: | + if [[ "${{ github.actor }}" == *"[bot]" ]]; then + echo "PR opened by a bot – skipping AI title review." + echo "is_repo_dev=false" >> $GITHUB_OUTPUT + exit 0 + fi + if [ ! -f .github/config/repo_devs.json ]; then + echo "Error: .github/config/repo_devs.json not found" >&2 + exit 1 + fi + # Validate JSON and extract repo_devs + REPO_DEVS=$(jq -r '.repo_devs[]' .github/config/repo_devs.json 2>/dev/null || { echo "Error: Invalid JSON in repo_devs.json" >&2; exit 1; }) + # Convert developer list into Bash array + mapfile -t DEVS_ARRAY <<< "$REPO_DEVS" + if [[ " ${DEVS_ARRAY[*]} " == *" ${{ github.actor }} "* ]]; then + echo "is_repo_dev=true" >> $GITHUB_OUTPUT + else + echo "is_repo_dev=false" >> $GITHUB_OUTPUT + fi + + - name: Get PR diff + if: steps.actor.outputs.is_repo_dev == 'true' + id: get_diff + run: | + git fetch origin ${{ github.base_ref }} + git diff origin/${{ github.base_ref }}...HEAD | head -n 10000 | grep -vP '[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x{202E}\x{200B}]' > pr.diff + echo "diff<> $GITHUB_OUTPUT + cat pr.diff >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Check and sanitize PR title + if: steps.actor.outputs.is_repo_dev == 'true' + id: sanitize_pr_title + env: + PR_TITLE_RAW: ${{ github.event.pull_request.title }} + run: | + # Sanitize PR title: max 72 characters, only printable characters + PR_TITLE=$(echo "$PR_TITLE_RAW" | tr -d '\n\r' | head -c 72 | sed 's/[^[:print:]]//g') + if [[ ${#PR_TITLE} -lt 5 ]]; then + echo "PR title is too short. Must be at least 5 characters." >&2 + fi + echo "pr_title=$PR_TITLE" >> $GITHUB_OUTPUT + + - name: AI PR Title Analysis + if: steps.actor.outputs.is_repo_dev == 'true' + id: ai-title-analysis + uses: actions/ai-inference@d645f067d89ee1d5d736a5990e327e504d1c5a4a # v1.1.0 + with: + model: openai/gpt-4o + system-prompt-file: ".github/config/system-prompt.txt" + prompt: | + Based on the following input data: + + { + "diff": "${{ steps.get_diff.outputs.diff }}", + "pr_title": "${{ steps.sanitize_pr_title.outputs.pr_title }}" + } + + Respond ONLY with valid JSON in the format: + { + "improved_rating": <0-10>, + "improved_ai_title_rating": <0-10>, + "improved_title": "" + } + + - name: Validate and set SCRIPT_OUTPUT + if: steps.actor.outputs.is_repo_dev == 'true' + run: | + cat < ai_response.json + ${{ steps.ai-title-analysis.outputs.response }} + EOF + + # Validate JSON structure + jq -e ' + (keys | sort) == ["improved_ai_title_rating", "improved_rating", "improved_title"] and + (.improved_rating | type == "number" and . >= 0 and . <= 10) and + (.improved_ai_title_rating | type == "number" and . >= 0 and . <= 10) and + (.improved_title | type == "string") + ' ai_response.json + if [ $? -ne 0 ]; then + echo "Invalid AI response format" >&2 + cat ai_response.json >&2 + exit 1 + fi + # Parse JSON fields + IMPROVED_RATING=$(jq -r '.improved_rating' ai_response.json) + IMPROVED_TITLE=$(jq -r '.improved_title' ai_response.json) + # Limit comment length to 1000 characters + COMMENT=$(cat < /tmp/ai-title-comment.md + # Log input and output to the GitHub Step Summary + echo "### šŸ¤– AI PR Title Analysis" >> $GITHUB_STEP_SUMMARY + echo "### Input PR Title" >> $GITHUB_STEP_SUMMARY + echo '```bash' >> $GITHUB_STEP_SUMMARY + echo "${{ steps.sanitize_pr_title.outputs.pr_title }}" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo '### AI Response (raw JSON)' >> $GITHUB_STEP_SUMMARY + echo '```json' >> $GITHUB_STEP_SUMMARY + cat ai_response.json >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + + - name: Post comment on PR if needed + if: steps.actor.outputs.is_repo_dev == 'true' + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + continue-on-error: true + with: + github-token: ${{ steps.setup-bot.outputs.token }} + script: | + const fs = require('fs'); + const body = fs.readFileSync('/tmp/ai-title-comment.md', 'utf8'); + const { GITHUB_REPOSITORY } = process.env; + const [owner, repo] = GITHUB_REPOSITORY.split('/'); + const issue_number = context.issue.number; + + const ratingMatch = body.match(/\*\*PR-Title Rating\*\*: (\d+)\/10/); + const rating = ratingMatch ? parseInt(ratingMatch[1], 10) : null; + + const expectedActor = "${{ steps.setup-bot.outputs.app-slug }}[bot]"; + const comments = await github.rest.issues.listComments({ owner, repo, issue_number }); + + const existing = comments.data.find(c => + c.user?.login === expectedActor && + c.body.includes("## šŸ¤– AI PR Title Suggestion") + ); + + if (rating === null) { + console.log("No rating found in AI response – skipping."); + return; + } + + if (rating <= 5) { + if (existing) { + await github.rest.issues.updateComment({ + owner, repo, + comment_id: existing.id, + body + }); + console.log("Updated existing suggestion comment."); + } else { + await github.rest.issues.createComment({ + owner, repo, issue_number, + body + }); + console.log("Created new suggestion comment."); + } + } else { + const praise = `## šŸ¤– AI PR Title Suggestion\n\nGreat job! The current PR title is clear and well-structured.\n\nāœ… No suggestions needed.\n\n---\n*Generated by GitHub Models AI*`; + + if (existing) { + await github.rest.issues.updateComment({ + owner, repo, + comment_id: existing.id, + body: praise + }); + console.log("Replaced suggestion with praise."); + } else { + console.log("Rating > 5 and no existing comment – skipping comment."); + } + } + + - name: is not repo dev + if: steps.actor.outputs.is_repo_dev != 'true' + run: | + exit 0 # Skip the AI title review for non-repo developers + + - name: Clean up + if: always() + run: | + rm -f pr.diff ai_response.json /tmp/ai-title-comment.md + echo "Cleaned up temporary files." + continue-on-error: true # Ensure cleanup runs even if previous steps fail diff --git a/.github/workflows/auto-labeler.yml b/.github/workflows/auto-labeler.yml index 5f350d2d4..5828a2556 100644 --- a/.github/workflows/auto-labeler.yml +++ b/.github/workflows/auto-labeler.yml @@ -13,7 +13,7 @@ jobs: pull-requests: write steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit diff --git a/.github/workflows/auto-labelerV2.yml b/.github/workflows/auto-labelerV2.yml new file mode 100644 index 000000000..dec73ddac --- /dev/null +++ b/.github/workflows/auto-labelerV2.yml @@ -0,0 +1,35 @@ +name: "Auto Pull Request Labeler V2" +on: + pull_request_target: + types: [opened, synchronize] + +permissions: + contents: read + +jobs: + labeler: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Harden Runner + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 + with: + egress-policy: audit + + - 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 }} + + - uses: srvaroa/labeler@0a20eccb8c94a1ee0bed5f16859aece1c45c3e55 # v1.13.0 + with: + config_path: .github/labeler-config-srvaroa.yml + use_local_config: false + fail_on_error: true + env: + GITHUB_TOKEN: "${{ steps.setup-bot.outputs.token }}" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1d5016ca8..9a4666956 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,10 +21,11 @@ jobs: fail-fast: false matrix: jdk-version: [17, 21] + spring-security: [true, false] steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -37,32 +38,60 @@ jobs: java-version: ${{ matrix.jdk-version }} distribution: "temurin" - - name: Build with Gradle and no spring security + - name: Build with Gradle and spring security ${{ matrix.spring-security }} run: ./gradlew clean build env: - DOCKER_ENABLE_SECURITY: false + DISABLE_ADDITIONAL_FEATURES: ${{ matrix.spring-security }} - - name: Build with Gradle and with spring security - run: ./gradlew clean build - env: - DOCKER_ENABLE_SECURITY: true + - name: Check Test Reports Exist + id: check-reports + if: always() + run: | + declare -a dirs=( + "stirling-pdf/build/reports/tests/" + "stirling-pdf/build/test-results/" + "common/build/reports/tests/" + "common/build/test-results/" + "proprietary/build/reports/tests/" + "proprietary/build/test-results/" + ) + missing_reports=() + for dir in "${dirs[@]}"; do + if [ ! -d "$dir" ]; then + missing_reports+=("$dir") + fi + done + if [ ${#missing_reports[@]} -gt 0 ]; then + echo "ERROR: The following required test report directories are missing:" + printf '%s\n' "${missing_reports[@]}" + exit 1 + fi + echo "All required test report directories are present" - name: Upload Test Reports if: always() uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - name: test-reports-jdk-${{ matrix.jdk-version }} + name: test-reports-jdk-${{ matrix.jdk-version }}-spring-security-${{ matrix.spring-security }} path: | - build/reports/tests/ - build/test-results/ + stirling-pdf/build/reports/tests/ + stirling-pdf/build/test-results/ + stirling-pdf/build/reports/problems/ + common/build/reports/tests/ + common/build/test-results/ + common/build/reports/problems/ + proprietary/build/reports/tests/ + proprietary/build/test-results/ + proprietary/build/reports/problems/ build/reports/problems/ retention-days: 3 + if-no-files-found: warn check-licence: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -106,7 +135,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -120,11 +149,11 @@ jobs: distribution: "adopt" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Install Docker Compose run: | - sudo curl -SL "https://github.com/docker/compose/releases/download/v2.32.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + sudo curl -SL "https://github.com/docker/compose/releases/download/v2.37.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose - name: Set up Python diff --git a/.github/workflows/check_properties.yml b/.github/workflows/check_properties.yml index 6825f59f9..7c2c075b3 100644 --- a/.github/workflows/check_properties.yml +++ b/.github/workflows/check_properties.yml @@ -4,7 +4,7 @@ on: pull_request_target: types: [opened, synchronize, reopened] paths: - - "src/main/resources/messages_*.properties" + - "stirling-pdf/src/main/resources/messages_*.properties" permissions: contents: read # Allow read access to repository content @@ -15,25 +15,28 @@ 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 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit - 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,16 +57,30 @@ 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..." - gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^src/main/resources/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$' > changed_files.txt # Filter only matching property files + # Check if PR number exists + if [ -z "${{ steps.get-pr-data.outputs.pr_number }}" ]; then + echo "Error: PR number is empty" + exit 1 + fi + # Get changed files and filter for properties files, handle case where no matches are found + gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^stirling-pdf/src/main/resources/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$' > changed_files.txt || echo "No matching properties files found in PR" + # Check if any files were found + if [ ! -s changed_files.txt ]; then + echo "No properties files changed in this PR" + echo "Workflow will exit early as no relevant files to check" + exit 0 + fi + echo "Found $(wc -l < changed_files.txt) matching properties files" - name: Determine reference file test 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"); @@ -98,8 +115,11 @@ jobs: // Filter for relevant files based on the PR changes const changedFiles = files - .map(file => file.filename) - .filter(file => /^src\/main\/resources\/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$/.test(file)); + .filter(file => + file.status !== "removed" && + /^stirling-pdf\/src\/main\/resources\/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$/.test(file.filename) + ) + .map(file => file.filename); console.log("Changed files:", changedFiles); @@ -137,12 +157,12 @@ jobs: // Determine reference file let referenceFilePath; - if (changedFiles.includes("src/main/resources/messages_en_GB.properties")) { + if (changedFiles.includes("stirling-pdf/src/main/resources/messages_en_GB.properties")) { console.log("Using PR branch reference file."); const { data: fileContent } = await github.rest.repos.getContent({ owner: prRepoOwner, repo: prRepoName, - path: "src/main/resources/messages_en_GB.properties", + path: "stirling-pdf/src/main/resources/messages_en_GB.properties", ref: branch, }); @@ -154,7 +174,7 @@ jobs: const { data: fileContent } = await github.rest.repos.getContent({ owner: repoOwner, repo: repoName, - path: "src/main/resources/messages_en_GB.properties", + path: "stirling-pdf/src/main/resources/messages_en_GB.properties", ref: "main", }); @@ -204,6 +224,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 +240,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 @@ -248,3 +269,12 @@ jobs: run: | echo "Failing the job because errors were detected." exit 1 + + - name: Cleanup temporary files + if: always() + run: | + echo "Cleaning up temporary files..." + rm -rf pr-branch + rm -f pr-branch-messages_en_GB.properties main-branch-messages_en_GB.properties changed_files.txt result.txt + echo "Cleanup complete." + continue-on-error: true # Ensure cleanup runs even if previous steps fail \ No newline at end of file diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 304267160..4f44295f7 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -17,11 +17,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit - 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..227948288 100644 --- a/.github/workflows/licenses-update.yml +++ b/.github/workflows/licenses-update.yml @@ -16,54 +16,52 @@ 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 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 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@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - - 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 + mv build/reports/dependency-license/index.json stirling-pdf/src/main/resources/static/3rdPartyLicenses.json - - name: Set up git config + - name: Commit changes run: | - git config --global user.name "stirlingbot[bot]" - git config --global user.email "1113334+stirlingbot[bot]@users.noreply.github.com" - - - name: Run git add - run: | - git add src/main/resources/static/3rdPartyLicenses.json + git add stirling-pdf/src/main/resources/static/3rdPartyLicenses.json git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV - name: Create Pull Request @@ -71,16 +69,16 @@ 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 - labels: licenses,github-actions + Auto-generated by ${{ steps.setup-bot.outputs.app-slug }}[bot] + labels: Licenses,github-actions draft: false delete-branch: true sign-commits: 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/manage-label.yml b/.github/workflows/manage-label.yml index 73ece41ae..3f123afbd 100644 --- a/.github/workflows/manage-label.yml +++ b/.github/workflows/manage-label.yml @@ -15,7 +15,7 @@ jobs: issues: write steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit diff --git a/.github/workflows/multiOSReleases.yml b/.github/workflows/multiOSReleases.yml index b078e4015..e2f33fae0 100644 --- a/.github/workflows/multiOSReleases.yml +++ b/.github/workflows/multiOSReleases.yml @@ -21,7 +21,7 @@ jobs: versionMac: ${{ steps.versionNumberMac.outputs.versionNumberMac }} steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -48,15 +48,15 @@ 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 - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -68,14 +68,14 @@ jobs: java-version: "21" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 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,15 +98,15 @@ 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 - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -144,7 +144,7 @@ jobs: contents: write steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -156,7 +156,7 @@ jobs: java-version: "21" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 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 @@ -234,7 +234,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -248,7 +248,7 @@ jobs: - name: Install Cosign if: matrix.os == 'windows-latest' - uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2 + uses: sigstore/cosign-installer@fb28c2b6339dcd94da6e4cbcbc5e888961f6f8c3 # v3.9.0 - name: Generate key pair if: matrix.os == 'windows-latest' @@ -297,7 +297,7 @@ jobs: contents: write steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -306,7 +306,7 @@ jobs: - name: Display structure of downloaded files run: ls -R - name: Upload binaries, attestations and signatures to Release and create GitHub Release - uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0 + uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2 with: tag_name: v${{ needs.read_versions.outputs.version }} generate_release_notes: true diff --git a/.github/workflows/pre_commit.yml b/.github/workflows/pre_commit.yml index ce10a6c3e..1190c49cd 100644 --- a/.github/workflows/pre_commit.yml +++ b/.github/workflows/pre_commit.yml @@ -16,62 +16,53 @@ jobs: pull-requests: write steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 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..39f022586 100644 --- a/.github/workflows/push-docker.yml +++ b/.github/workflows/push-docker.yml @@ -18,7 +18,7 @@ jobs: id-token: write steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -30,25 +30,25 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 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 if: github.ref == 'refs/heads/master' - uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2 + uses: sigstore/cosign-installer@fb28c2b6339dcd94da6e4cbcbc5e888961f6f8c3 # v3.9.0 with: cosign-release: "v2.4.1" - name: Set up Docker Buildx id: buildx - uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Get version number id: versionNumber @@ -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..76c711734 100644 --- a/.github/workflows/releaseArtifacts.yml +++ b/.github/workflows/releaseArtifacts.yml @@ -13,17 +13,17 @@ 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 }} steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -35,14 +35,14 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 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,15 +75,15 @@ 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 - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -95,7 +95,7 @@ jobs: run: ls -R - name: Install Cosign - uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2 + uses: sigstore/cosign-installer@fb28c2b6339dcd94da6e4cbcbc5e888961f6f8c3 # v3.9.0 - name: Generate key pair run: cosign generate-key-pair @@ -153,15 +153,15 @@ 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 - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -171,7 +171,7 @@ jobs: name: signed${{ matrix.file_suffix }} - name: Upload binaries, attestations and signatures to Release and create GitHub Release - uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0 + uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2 with: tag_name: v${{ needs.build.outputs.version }} generate_release_notes: true diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 3c2d59e3e..a79dc0ec2 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -34,7 +34,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -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@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0 with: sarif_file: results.sarif diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml index ddf0980ab..187e823ae 100644 --- a/.github/workflows/sonarqube.yml +++ b/.github/workflows/sonarqube.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -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@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - 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/stale.yml b/.github/workflows/stale.yml index 4000f0e6f..17d81412a 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -16,7 +16,7 @@ jobs: pull-requests: write steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit diff --git a/.github/workflows/swagger.yml b/.github/workflows/swagger.yml index 19c0aaa89..6b9307887 100644 --- a/.github/workflows/swagger.yml +++ b/.github/workflows/swagger.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -26,7 +26,7 @@ jobs: java-version: "17" distribution: "temurin" - - uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - name: Generate Swagger documentation run: ./gradlew generateOpenApiDocs diff --git a/.github/workflows/sync_files.yml b/.github/workflows/sync_files.yml index fe790c65b..f89f36b2a 100644 --- a/.github/workflows/sync_files.yml +++ b/.github/workflows/sync_files.yml @@ -8,87 +8,45 @@ on: paths: - "build.gradle" - "README.md" - - "src/main/resources/messages_*.properties" - - "src/main/resources/static/3rdPartyLicenses.json" + - "stirling-pdf/src/main/resources/messages_*.properties" + - "stirling-pdf/src/main/resources/static/3rdPartyLicenses.json" - "scripts/ignore_translation.toml" 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 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 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 + python .github/scripts/check_language_properties.py --reference-file "stirling-pdf/src/main/resources/messages_en_GB.properties" --branch main - - name: Set up git config + - name: Commit translation files 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 - run: | - git add src/main/resources/messages_*.properties - git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "no changes" + git add stirling-pdf/src/main/resources/messages_*.properties + 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" @@ -142,4 +101,4 @@ jobs: sign-commits: true add-paths: | README.md - src/main/resources/messages_*.properties + stirling-pdf/src/main/resources/messages_*.properties diff --git a/.github/workflows/testdriver.yml b/.github/workflows/testdriver.yml index 68c4fabb2..d0244619d 100644 --- a/.github/workflows/testdriver.yml +++ b/.github/workflows/testdriver.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -28,10 +28,10 @@ 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 + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Get version number id: versionNumber @@ -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" @@ -105,7 +105,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit @@ -134,7 +134,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit diff --git a/.gitignore b/.gitignore index 519c28f4a..52e57d719 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ local.properties .recommenders .classpath .project +*.local.json version.properties #### Stirling-PDF Files ### @@ -124,6 +125,9 @@ SwaggerDoc.json *.rar *.db /build +/stirling-pdf/build +/common/build +/proprietary/build # Byte-compiled / optimized / DLL files __pycache__/ @@ -189,11 +193,9 @@ id_ed25519.pub .pytest_cache .ipynb_checkpoints -# Claude.ai assistant files -CLAUDE.md + **/jcef-bundle/ # node_modules node_modules/ -*.mjs diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c792e50a0..5418deaea 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.12.0 hooks: - id: ruff args: @@ -16,13 +16,13 @@ repos: hooks: - id: codespell args: - - --ignore-words-list= + - --ignore-words-list=thirdParty,tabEl,tabEls - --skip="./.*,*.csv,*.json,*.ambr" - --quiet-level=2 files: \.(html|css|js|py|md)$ - exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js) + exclude: (.vscode|.devcontainer|stirling-pdf/src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js) - repo: https://github.com/gitleaks/gitleaks - rev: v8.24.3 + rev: v8.27.2 hooks: - id: gitleaks - repo: https://github.com/pre-commit/pre-commit-hooks diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 432bd0248..128af83ba 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -15,6 +15,7 @@ "ms-azuretools.vscode-docker", // Docker extension for Visual Studio Code "GitHub.copilot", // GitHub Copilot AI pair programmer for Visual Studio Code "GitHub.vscode-pull-request-github", // GitHub Pull Requests extension for Visual Studio Code - "charliermarsh.ruff" // Ruff code formatter for Python to follow the Ruff Style Guide + "charliermarsh.ruff", // Ruff code formatter for Python to follow the Ruff Style Guide + "yzhang.markdown-all-in-one", // Markdown All-in-One extension for enhanced Markdown editing ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index a4be4d0cd..3f272e18a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,11 +6,32 @@ "[java]": { "editor.defaultFormatter": "josevseb.google-java-format-for-vs-code" }, + "[jsonc]": { + "editor.defaultFormatter": "vscode.json-language-features" + }, + "[json]": { + "editor.defaultFormatter": "vscode.json-language-features" + }, + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter" + }, + "[gradle-kotlin-dsl]": { + "editor.defaultFormatter": "vscjava.vscode-gradle" + }, + "[markdown]": { + "editor.defaultFormatter": "yzhang.markdown-all-in-one" + }, + "[gradle-build]": { + "editor.defaultFormatter": "vscjava.vscode-gradle" + }, + "[gradle]": { + "editor.defaultFormatter": "vscjava.vscode-gradle" + }, "java.compile.nullAnalysis.mode": "automatic", "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 +70,11 @@ ".venv*/", ".vscode/", "bin/", + "common/bin/", + "proprietary/bin/", "build/", + "common/build/", + "proprietary/build/", "configs/", "customFiles/", "docs/", @@ -63,6 +88,8 @@ ".git-blame-ignore-revs", ".gitattributes", ".gitignore", + "common/.gitignore", + "proprietary/.gitignore", ".pre-commit-config.yaml", ], // Enables signature help in Java. @@ -80,4 +107,21 @@ "spring.initializr.defaultLanguage": "Java", "spring.initializr.defaultGroupId": "stirling.software.SPDF", "spring.initializr.defaultArtifactId": "SPDF", + "java.jdt.ls.lombokSupport.enabled": true, + "html.format.wrapLineLength": 127, + "html.format.enable": true, + "html.format.indentInnerHtml": true, + "html.format.unformatted": "script,style,textarea", + "html.format.contentUnformatted": "pre,code", + "html.format.extraLiners": "head,body,/html", + "html.format.wrapAttributes": "force", + "html.format.wrapAttributesIndentSize": 2, + "html.format.indentHandlebars": true, + "html.format.preserveNewLines": true, + "html.format.maxPreserveNewLines": 2, + "java.project.sourcePaths": [ + "stirling-pdf/src/main/java", + "common/src/main/java", + "proprietary/src/main/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/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..05bfb5254 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,124 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Common Development Commands + +### Build and Test +- **Build project**: `./gradlew clean build` +- **Run locally**: `./gradlew bootRun` +- **Full test suite**: `./test.sh` (builds all Docker variants and runs comprehensive tests) +- **Code formatting**: `./gradlew spotlessApply` (runs automatically before compilation) + +### Docker Development +- **Build ultra-lite**: `docker build -t stirlingtools/stirling-pdf:latest-ultra-lite -f ./Dockerfile.ultra-lite .` +- **Build standard**: `docker build -t stirlingtools/stirling-pdf:latest -f ./Dockerfile .` +- **Build fat version**: `docker build -t stirlingtools/stirling-pdf:latest-fat -f ./Dockerfile.fat .` +- **Example compose files**: Located in `exampleYmlFiles/` directory + +### Security Mode Development +Set `DOCKER_ENABLE_SECURITY=true` environment variable to enable security features during development. This is required for testing the full version locally. + +### Frontend Development +- **Frontend dev server**: `cd frontend && npm run dev` (requires backend on localhost:8080) +- **Tech Stack**: Vite + React + TypeScript + Mantine UI + TailwindCSS +- **Proxy Configuration**: Vite proxies `/api/*` calls to backend (localhost:8080) +- **Build Process**: DO NOT run build scripts manually - builds are handled by CI/CD pipelines +- **Package Installation**: DO NOT run npm install commands - package management handled separately + +#### Tailwind CSS Setup (if not already installed) +```bash +cd frontend +npm install -D tailwindcss postcss autoprefixer +npx tailwindcss init -p +``` + +## Architecture Overview + +### Project Structure +- **Backend**: Spring Boot application with Thymeleaf templating +- **Frontend**: React-based SPA in `/frontend` directory (replacing legacy Thymeleaf templates) + - **Current Status**: Active development to replace Thymeleaf UI with modern React SPA + - **File Storage**: IndexedDB for client-side file persistence and thumbnails + - **Internationalization**: JSON-based translations (converted from backend .properties) + - **URL Parameters**: Deep linking support for tool states and configurations +- **PDF Processing**: PDFBox for core PDF operations, LibreOffice for conversions, PDF.js for client-side rendering +- **Security**: Spring Security with optional authentication (controlled by `DOCKER_ENABLE_SECURITY`) +- **Configuration**: YAML-based configuration with environment variable overrides + +### Controller Architecture +- **API Controllers** (`src/main/java/.../controller/api/`): REST endpoints for PDF operations + - Organized by function: converters, security, misc, pipeline + - Follow pattern: `@RestController` + `@RequestMapping("/api/v1/...")` +- **Web Controllers** (`src/main/java/.../controller/web/`): Serve Thymeleaf templates + - Pattern: `@Controller` + return template names + +### Key Components +- **SPDFApplication.java**: Main application class with desktop UI and browser launching logic +- **ConfigInitializer**: Handles runtime configuration and settings files +- **Pipeline System**: Automated PDF processing workflows via `PipelineController` +- **Security Layer**: Authentication, authorization, and user management (when enabled) + +### Template System (Legacy + Modern) +- **Legacy Thymeleaf Templates**: Located in `src/main/resources/templates/` (being phased out) +- **Modern React Components**: Located in `frontend/src/components/` and `frontend/src/tools/` +- **Static Assets**: CSS, JS, and resources in `src/main/resources/static/` (legacy) + `frontend/public/` (modern) +- **Internationalization**: + - Backend: `messages_*.properties` files + - Frontend: JSON files in `frontend/public/locales/` (converted from .properties) + - Conversion Script: `scripts/convert_properties_to_json.py` + +### Configuration Modes +- **Ultra-lite**: Basic PDF operations only +- **Standard**: Full feature set +- **Fat**: Pre-downloaded dependencies for air-gapped environments +- **Security Mode**: Adds authentication, user management, and enterprise features + +### Testing Strategy +- **Integration Tests**: Cucumber tests in `testing/cucumber/` +- **Docker Testing**: `test.sh` validates all Docker variants +- **Manual Testing**: No unit tests currently - relies on UI and API testing + +## Development Workflow + +1. **Local Development**: + - Backend: `./gradlew bootRun` (runs on localhost:8080) + - Frontend: `cd frontend && npm run dev` (runs on localhost:5173, proxies to backend) +2. **Docker Testing**: Use `./test.sh` before submitting PRs +3. **Code Style**: Spotless enforces Google Java Format automatically +4. **Translations**: + - Backend: Use helper scripts in `/scripts` for multi-language updates + - Frontend: Update JSON files in `frontend/public/locales/` or use conversion script +5. **Documentation**: API docs auto-generated and available at `/swagger-ui/index.html` + +## Frontend Migration Notes + +- **Current Branch**: `feature/react-overhaul` - Active React SPA development +- **Migration Status**: Core tools (Split, Merge, Compress) converted to React with URL parameter support +- **File Management**: Implemented IndexedDB storage with thumbnail generation using PDF.js +- **Tools Architecture**: Each tool receives `params` and `updateParams` for URL state synchronization +- **Remaining Work**: Convert remaining Thymeleaf templates to React components + +## Important Notes + +- **Java Version**: Minimum JDK 17, supports and recommends JDK 21 +- **Lombok**: Used extensively - ensure IDE plugin is installed +- **Desktop Mode**: Set `STIRLING_PDF_DESKTOP_UI=true` for desktop application mode +- **File Persistence**: + - **Backend**: Designed to be stateless - files are processed in memory/temp locations only + - **Frontend**: Uses IndexedDB for client-side file storage and caching (with thumbnails) +- **Security**: When `DOCKER_ENABLE_SECURITY=false`, security-related classes are excluded from compilation + +## Communication Style +- Be direct and to the point +- No apologies or conversational filler +- Answer questions directly without preamble +- Explain reasoning concisely when asked +- Avoid unnecessary elaboration + +## Decision Making +- Ask clarifying questions before making assumptions +- Stop and ask when uncertain about project-specific details +- Confirm approach before making structural changes +- Request guidance on preferences (cross-platform vs specific tools, etc.) +- Verify understanding of requirements before proceeding diff --git a/DeveloperGuide.md b/DeveloperGuide.md index 32d480f5c..0728a1cdc 100644 --- a/DeveloperGuide.md +++ b/DeveloperGuide.md @@ -2,21 +2,38 @@ ## 1. Introduction -Stirling-PDF is a robust, locally hosted, web-based PDF manipulation tool. This guide focuses on Docker-based development and testing, which is the recommended approach for working with the full version of Stirling-PDF. +Stirling-PDF is a robust, locally hosted, web-based PDF manipulation tool. **Stirling 2.0** represents a complete frontend rewrite, replacing the legacy Thymeleaf-based UI with a modern React SPA (Single Page Application). + +This guide focuses on developing for Stirling 2.0, including both the React frontend and Spring Boot backend development workflows. ## 2. Project Overview -Stirling-PDF is built using: +**Stirling 2.0** is built using: -- Spring Boot + Thymeleaf -- PDFBox -- LibreOffice -- qpdf -- HTML, CSS, JavaScript -- Docker -- PDF.js -- PDF-LIB.js -- Lombok +**Backend:** +- Spring Boot (Java 17+, JDK 21 recommended) +- PDFBox for core PDF operations +- LibreOffice for document conversions +- qpdf for PDF optimization +- Spring Security (optional, controlled by `DOCKER_ENABLE_SECURITY`) +- Lombok for reducing boilerplate code + +**Frontend (React SPA):** +- React + TypeScript +- Vite for build tooling and development server +- Mantine UI component library +- TailwindCSS for styling +- PDF.js for client-side PDF rendering +- PDF-LIB.js for client-side PDF manipulation +- IndexedDB for client-side file storage and thumbnails +- i18next for internationalization + +**Infrastructure:** +- Docker for containerization +- Gradle for build management + +**Legacy (reference only during development):** +- Thymeleaf templates (being completely replaced in 2.0) ## 3. Development Environment Setup @@ -24,7 +41,8 @@ Stirling-PDF is built using: - Docker - Git -- Java JDK 17 or later +- Java JDK 17 or later (JDK 21 recommended) +- Node.js 18+ and npm (required for frontend development) - Gradle 7.0 or later (Included within the repo) ### Setup Steps @@ -55,16 +73,46 @@ 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. +5. **Frontend Setup (Required for Stirling 2.0)** + Navigate to the frontend directory and install dependencies using npm. -## 4. Project Structure +## 4. Stirling 2.0 Development Workflow + +### Frontend Development (React) +The frontend is a React SPA that runs independently during development: + +1. **Start the backend**: Run the Spring Boot application (serves API endpoints on localhost:8080) +2. **Start the frontend dev server**: Navigate to the frontend directory and run the development server (serves UI on localhost:5173) +3. **Development flow**: The Vite dev server automatically proxies API calls to the backend + +### File Storage Architecture +Stirling 2.0 uses client-side file storage: +- **IndexedDB**: Stores files locally in the browser with automatic thumbnail generation +- **PDF.js**: Handles client-side PDF rendering and processing +- **URL Parameters**: Support for deep linking and tool state persistence + +### Legacy Code Reference +The existing Thymeleaf templates remain in the codebase during development as reference material but will be completely removed for the 2.0 release. + +## 5. Project Structure ```bash Stirling-PDF/ ā”œā”€ā”€ .github/ # GitHub-specific files (workflows, issue templates) ā”œā”€ā”€ configs/ # Configuration files used by stirling at runtime (generated at runtime) -ā”œā”€ā”€ cucumber/ # Cucumber test files -│ ā”œā”€ā”€ features/ +ā”œā”€ā”€ frontend/ # React SPA frontend (Stirling 2.0) +│ ā”œā”€ā”€ src/ +│ │ ā”œā”€ā”€ components/ # React components +│ │ ā”œā”€ā”€ tools/ # Tool-specific React components +│ │ ā”œā”€ā”€ hooks/ # Custom React hooks +│ │ ā”œā”€ā”€ services/ # API and utility services +│ │ ā”œā”€ā”€ types/ # TypeScript type definitions +│ │ └── utils/ # Utility functions +│ ā”œā”€ā”€ public/ +│ │ └── locales/ # Internationalization files (JSON) +│ ā”œā”€ā”€ package.json # Frontend dependencies +│ └── vite.config.ts # Vite configuration ā”œā”€ā”€ customFiles/ # Custom static files and templates (generated at runtime used to replace existing files) ā”œā”€ā”€ docs/ # Documentation files ā”œā”€ā”€ exampleYmlFiles/ # Example YAML configuration files @@ -84,16 +132,14 @@ Stirling-PDF/ │ │ │ ā”œā”€ā”€ service/ │ │ │ └── utils/ │ │ └── resources/ -│ │ ā”œā”€ā”€ static/ +│ │ ā”œā”€ā”€ static/ # Legacy static assets (reference only) │ │ │ ā”œā”€ā”€ css/ │ │ │ ā”œā”€ā”€ js/ │ │ │ └── pdfjs/ -│ │ └── templates/ +│ │ └── templates/ # Legacy Thymeleaf templates (reference only) │ └── test/ -│ └── java/ -│ └── stirling/ -│ └── software/ -│ └── SPDF/ +ā”œā”€ā”€ testing/ # Cucumber and integration tests +│ └── cucumber/ # Cucumber test files ā”œā”€ā”€ build.gradle # Gradle build configuration ā”œā”€ā”€ Dockerfile # Main Dockerfile ā”œā”€ā”€ Dockerfile.ultra-lite # Dockerfile for ultra-lite version @@ -102,7 +148,7 @@ Stirling-PDF/ └── test.sh # Test script to deploy all docker versions and run cuke tests ``` -## 5. Docker-based Development +## 6. Docker-based Development Stirling-PDF offers several Docker versions: @@ -114,9 +160,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`: @@ -137,11 +183,11 @@ services: ports: - "8080:8080" volumes: - - /stirling/latest/data:/usr/share/tessdata:rw - - /stirling/latest/config:/configs:rw - - /stirling/latest/logs:/logs:rw + - ./stirling/latest/data:/usr/share/tessdata:rw + - ./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 +216,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,16 +239,16 @@ 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 . ``` Note: The `--no-cache` and `--pull` flags ensure that the build process uses the latest base images and doesn't use cached layers, which is useful for testing and ensuring reproducible builds. however to improve build times these can often be removed depending on your usecase -## 6. Testing +## 7. Testing ### Comprehensive Testing Script @@ -228,6 +274,15 @@ Note: The `test.sh` script will run automatically when you raise a PR. However, 2. Access the application at `http://localhost:8080` and manually test all features developed. +### Frontend Development Testing (Stirling 2.0) + +For React frontend development: + +1. Start the backend: Run the Spring Boot application to serve API endpoints on localhost:8080 +2. Start the frontend dev server: Navigate to the frontend directory and run the development server on localhost:5173 +3. The Vite dev server automatically proxies API calls to the backend +4. Test React components, UI interactions, and IndexedDB file operations using browser developer tools + ### Local Testing (Java and UI Components) For quick iterations and development of Java backend, JavaScript, and UI components, you can run and test Stirling-PDF locally without Docker. This approach allows you to work on and verify changes to: @@ -258,7 +313,7 @@ Important notes: - There are currently no automated unit tests. All testing is done manually through the UI or API calls. (You are welcome to add JUnits!) - Always verify your changes in the full Docker environment before submitting pull requests, as some integrations and features will only work in the complete setup. -## 7. Contributing +## 8. Contributing 1. Fork the repository on GitHub. 2. Create a new branch for your feature or bug fix. @@ -283,11 +338,11 @@ When you raise a PR: Address any issues that arise from these checks before finalizing your pull request. -## 8. API Documentation +## 9. API Documentation API documentation is available at `/swagger-ui/index.html` when running the application. You can also view the latest API documentation [here](https://app.swaggerhub.com/apis-docs/Stirling-Tools/Stirling-PDF/). -## 9. Customization +## 10. Customization Stirling-PDF can be customized through environment variables or a `settings.yml` file. Key customization options include: @@ -306,7 +361,7 @@ docker run -p 8080:8080 -e APP_NAME="My PDF Tool" stirling-pdf:full Refer to the main README for a full list of customization options. -## 10. Language Translations +## 11. Language Translations For managing language translations that affect multiple files, Stirling-PDF provides a helper script: @@ -326,13 +381,62 @@ Remember to test your changes thoroughly to ensure they don't break any existing ## Code examples -### Overview of Thymeleaf +### React Component Development (Stirling 2.0) + +For Stirling 2.0, new features are built as React components instead of Thymeleaf templates: + +#### Creating a New Tool Component + +1. **Create the React Component:** + ```typescript + // frontend/src/tools/NewTool.tsx + import { useState } from 'react'; + import { Button, FileInput, Container } from '@mantine/core'; + + interface NewToolProps { + params: Record; + updateParams: (updates: Record) => void; + } + + export default function NewTool({ params, updateParams }: NewToolProps) { + const [files, setFiles] = useState([]); + + const handleProcess = async () => { + // Process files using API or client-side logic + }; + + return ( + + + + + ); + } + ``` + +2. **Add API Integration:** + ```typescript + // Use existing API endpoints or create new ones + const response = await fetch('/api/v1/new-tool', { + method: 'POST', + body: formData + }); + ``` + +3. **Register in Tool Picker:** + Update the tool picker component to include the new tool with proper routing and URL parameter support. + +### Legacy Reference: Overview of Thymeleaf Thymeleaf is a server-side Java HTML template engine. It is used in Stirling-PDF to render dynamic web pages. Thymeleaf integrates heavily with Spring Boot. ### Thymeleaf overview -In Stirling-PDF, Thymeleaf is used to create HTML templates that are rendered on the server side. These templates are located in the `src/main/resources/templates` directory. Thymeleaf templates use a combination of HTML and special Thymeleaf attributes to dynamically generate content. +In Stirling-PDF, Thymeleaf is used to create HTML templates that are rendered on the server side. These templates are located in the `stirling-pdf/src/main/resources/templates` directory. Thymeleaf templates use a combination of HTML and special Thymeleaf attributes to dynamically generate content. Some examples of this are: @@ -384,7 +488,7 @@ This would generate n entries of tr for each person in exampleData ### Adding a New Feature to the Backend (API) 1. **Create a New Controller:** - - Create a new Java class in the `src/main/java/stirling/software/SPDF/controller/api` directory. + - Create a new Java class in the `stirling-pdf/src/main/java/stirling/software/SPDF/controller/api` directory. - Annotate the class with `@RestController` and `@RequestMapping` to define the API endpoint. - Ensure to add API documentation annotations like `@Tag(name = "General", description = "General APIs")` and `@Operation(summary = "Crops a PDF document", description = "This operation takes an input PDF file and crops it according to the given coordinates. Input:PDF Output:PDF Type:SISO")`. @@ -411,7 +515,7 @@ This would generate n entries of tr for each person in exampleData ``` 2. **Define the Service Layer:** (Not required but often useful) - - Create a new service class in the `src/main/java/stirling/software/SPDF/service` directory. + - Create a new service class in the `stirling-pdf/src/main/java/stirling/software/SPDF/service` directory. - Implement the business logic for the new feature. ```java @@ -463,7 +567,7 @@ This would generate n entries of tr for each person in exampleData ### Adding a New Feature to the Frontend (UI) 1. **Create a New Thymeleaf Template:** - - Create a new HTML file in the `src/main/resources/templates` directory. + - Create a new HTML file in the `stirling-pdf/src/main/resources/templates` directory. - Use Thymeleaf attributes to dynamically generate content. - Use `extract-page.html` as a base example for the HTML template, which is useful to ensure importing of the general layout, navbar, and footer. @@ -507,7 +611,7 @@ This would generate n entries of tr for each person in exampleData ``` 2. **Create a New Controller for the UI:** - - Create a new Java class in the `src/main/java/stirling/software/SPDF/controller/ui` directory. + - Create a new Java class in the `stirling-pdf/src/main/java/stirling/software/SPDF/controller/ui` directory. - Annotate the class with `@Controller` and `@RequestMapping` to define the UI endpoint. ```java @@ -537,7 +641,7 @@ This would generate n entries of tr for each person in exampleData 3. **Update the Navigation Bar:** - Add a link to the new feature page in the navigation bar. - - Update the `src/main/resources/templates/fragments/navbar.html` file. + - Update the `stirling-pdf/src/main/resources/templates/fragments/navbar.html` file. ```html