diff --git a/.github/workflows/PR-Auto-Deploy-V2.yml b/.github/workflows/PR-Auto-Deploy-V2.yml index d8df89585..a8f971d53 100644 --- a/.github/workflows/PR-Auto-Deploy-V2.yml +++ b/.github/workflows/PR-Auto-Deploy-V2.yml @@ -2,7 +2,7 @@ name: Auto PR V2 Deployment on: pull_request: - types: [opened, synchronize, reopened] + types: [opened, synchronize, reopened, closed] permissions: @@ -12,6 +12,7 @@ permissions: jobs: check-pr: + if: github.event.action != 'closed' runs-on: ubuntu-latest outputs: should_deploy: ${{ steps.check-conditions.outputs.should_deploy }} @@ -46,6 +47,7 @@ jobs: "reecebrowne" "DarioGii" "ConnorYoh" + "EthanHealy01" ) # Check if author is in the authorized list @@ -57,10 +59,10 @@ jobs: fi done - # If PR is targeting feature/react-overhaul and user is authorized, deploy unconditionally + # If PR is targeting V2 and user is authorized, deploy unconditionally PR_BASE_BRANCH="${{ github.event.pull_request.base.ref }}" - if [[ "$PR_BASE_BRANCH" == "feature/react-overhaul" && "$is_authorized" == "true" ]]; then - echo "āœ… Deployment forced: PR targets feature/react-overhaul and author is authorized." + if [[ "$PR_BASE_BRANCH" == "V2" && "$is_authorized" == "true" ]]; then + echo "āœ… Deployment forced: PR targets V2 and author is authorized." echo "should_deploy=true" >> $GITHUB_OUTPUT exit 0 fi @@ -183,19 +185,8 @@ jobs: repository: ${{ needs.check-pr.outputs.pr_repository }} ref: ${{ needs.check-pr.outputs.pr_ref }} token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 # Fetch full history for commit hash detection - - name: Set up JDK - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 - with: - java-version: "17" - distribution: "temurin" - - - name: Build backend - run: | - export DISABLE_ADDITIONAL_FEATURES=true - ./gradlew clean build - env: - STIRLING_PDF_DESKTOP_UI: false - name: Set up Docker Buildx uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 @@ -212,13 +203,81 @@ jobs: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_API }} - - name: Build and push V2 monolith image + - name: Get commit hashes for frontend and backend + id: commit-hashes + run: | + # Get last commit that touched the frontend folder, docker/frontend, or docker/compose + FRONTEND_HASH=$(git log -1 --format="%H" -- frontend/ docker/frontend/ docker/compose/ 2>/dev/null || echo "") + if [ -z "$FRONTEND_HASH" ]; then + FRONTEND_HASH="no-frontend-changes" + fi + + # Get last commit that touched backend code, docker/backend, or docker/compose + BACKEND_HASH=$(git log -1 --format="%H" -- app/ docker/backend/ docker/compose/ 2>/dev/null || echo "") + if [ -z "$BACKEND_HASH" ]; then + BACKEND_HASH="no-backend-changes" + fi + + echo "Frontend hash: $FRONTEND_HASH" + echo "Backend hash: $BACKEND_HASH" + + echo "frontend_hash=$FRONTEND_HASH" >> $GITHUB_OUTPUT + echo "backend_hash=$BACKEND_HASH" >> $GITHUB_OUTPUT + + # Short hashes for tags + if [ "$FRONTEND_HASH" = "no-frontend-changes" ]; then + echo "frontend_short=no-frontend" >> $GITHUB_OUTPUT + else + echo "frontend_short=${FRONTEND_HASH:0:8}" >> $GITHUB_OUTPUT + fi + + if [ "$BACKEND_HASH" = "no-backend-changes" ]; then + echo "backend_short=no-backend" >> $GITHUB_OUTPUT + else + echo "backend_short=${BACKEND_HASH:0:8}" >> $GITHUB_OUTPUT + fi + + - name: Check if frontend image exists + id: check-frontend + run: | + if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} >/dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Frontend image already exists, skipping build" + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "Frontend image needs to be built" + fi + + - name: Check if backend image exists + id: check-backend + run: | + if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} >/dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Backend image already exists, skipping build" + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "Backend image needs to be built" + fi + + - name: Build and push V2 frontend image + if: steps.check-frontend.outputs.exists == 'false' uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: context: . - file: ./docker/monolith/Dockerfile + file: ./docker/frontend/Dockerfile push: true - tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-pr-${{ needs.check-pr.outputs.pr_number }} + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} + build-args: VERSION_TAG=v2-alpha + platforms: linux/amd64 + + - name: Build and push V2 backend image + if: steps.check-backend.outputs.exists == 'false' + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + with: + context: . + file: ./docker/backend/Dockerfile + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} build-args: VERSION_TAG=v2-alpha platforms: linux/amd64 @@ -233,16 +292,17 @@ jobs: run: | # Use same port strategy as regular PRs - just the PR number V2_PORT=${{ needs.check-pr.outputs.pr_number }} + BACKEND_PORT=$((V2_PORT + 10000)) # Backend on higher port to avoid conflicts - # Create docker-compose for V2 monolith + # Create docker-compose for V2 with separate frontend and backend cat > docker-compose.yml << EOF version: '3.3' services: - stirling-pdf-v2: - container_name: stirling-pdf-v2-pr-${{ needs.check-pr.outputs.pr_number }} - image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-pr-${{ needs.check-pr.outputs.pr_number }} + stirling-pdf-v2-backend: + container_name: stirling-pdf-v2-backend-pr-${{ needs.check-pr.outputs.pr_number }} + image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} ports: - - "${V2_PORT}:80" # Frontend port (same as regular PRs) + - "${BACKEND_PORT}:8080" # Backend API port volumes: - /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/data:/usr/share/tessdata:rw - /stirling/V2-PR-${{ needs.check-pr.outputs.pr_number }}/config:/configs:rw @@ -258,6 +318,17 @@ jobs: METRICS_ENABLED: "true" SYSTEM_GOOGLEVISIBILITY: "false" restart: on-failure:5 + + stirling-pdf-v2-frontend: + container_name: stirling-pdf-v2-frontend-pr-${{ needs.check-pr.outputs.pr_number }} + image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} + ports: + - "${V2_PORT}:80" # Frontend port (same as regular PRs) + environment: + VITE_API_BASE_URL: "http://${{ secrets.VPS_HOST }}:${BACKEND_PORT}" + depends_on: + - stirling-pdf-v2-backend + restart: on-failure:5 EOF # Deploy to VPS @@ -280,6 +351,9 @@ jobs: # Clean up unused Docker resources to save space docker system prune -af --volumes + + # Clean up old backend/frontend images (older than 2 weeks) + docker image prune -af --filter "until=336h" --filter "label!=keep=true" ENDSSH # Set port for output @@ -325,3 +399,102 @@ jobs: body: commentBody }); + cleanup-v2-deployment: + if: github.event.action == 'closed' + runs-on: ubuntu-latest + permissions: + contents: read + issues: write + pull-requests: write + + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - 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: Clean up V2 deployment comments + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + github-token: ${{ steps.setup-bot.outputs.token }} + script: | + const { owner, repo } = context.repo; + const prNumber = ${{ github.event.pull_request.number }}; + + // Find and delete V2 deployment comments + const { data: comments } = await github.rest.issues.listComments({ + owner, + repo, + issue_number: prNumber + }); + + const v2Comments = comments.filter(c => + c.body?.includes("## šŸš€ V2 Auto-Deployment Complete!") && + c.user?.type === "Bot" + ); + + for (const comment of v2Comments) { + await github.rest.issues.deleteComment({ + owner, + repo, + comment_id: comment.id + }); + console.log(`Deleted V2 deployment comment (ID: ${comment.id})`); + } + + - name: Set up SSH + run: | + mkdir -p ~/.ssh/ + echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key + sudo chmod 600 ../private.key + + - name: Cleanup V2 deployment + run: | + ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH' + if [ -d "/stirling/V2-PR-${{ github.event.pull_request.number }}" ]; then + echo "Found V2 PR directory, proceeding with cleanup..." + + # Stop and remove V2 containers + cd /stirling/V2-PR-${{ github.event.pull_request.number }} + docker-compose down || true + + # Go back to root before removal + cd / + + # Remove V2 PR-specific directories + rm -rf /stirling/V2-PR-${{ github.event.pull_request.number }} + + # Clean up V2 containers by name (in case compose cleanup missed them) + docker rm -f stirling-pdf-v2-frontend-pr-${{ github.event.pull_request.number }} || true + docker rm -f stirling-pdf-v2-backend-pr-${{ github.event.pull_request.number }} || true + + echo "V2 cleanup completed" + else + echo "V2 PR directory not found, nothing to clean up" + fi + + # Clean up old unused images (older than 2 weeks) but keep recent ones for reuse + docker image prune -af --filter "until=336h" --filter "label!=keep=true" + + # Note: We don't remove the commit-based images since they can be reused across PRs + # Only remove PR-specific containers and directories + ENDSSH + + - name: Cleanup temporary files + if: always() + run: | + rm -f ../private.key + continue-on-error: true + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aa98d2a1e..3c8a85782 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,9 @@ name: Build repo on: push: - branches: ["main"] + branches: ["main", "V2", "V2-gha"] pull_request: - branches: ["main"] + branches: ["main", "V2", "V2-gha"] permissions: contents: read @@ -114,6 +114,46 @@ jobs: name: openapi-docs path: ./SwaggerDoc.json + frontend-validation: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Set up Node.js + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + - name: Install frontend dependencies + run: | + cd frontend + npm ci + + - name: Build frontend + run: | + cd frontend + npm run build + + - name: Run frontend tests (if available) + run: | + cd frontend + npm test --passWithNoTests --watchAll=false || true + + - name: Upload frontend build artifacts + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: frontend-build + path: frontend/dist/ + retention-days: 3 + check-licence: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/frontend-licenses-update.yml b/.github/workflows/frontend-licenses-update.yml new file mode 100644 index 000000000..b6f37ce3a --- /dev/null +++ b/.github/workflows/frontend-licenses-update.yml @@ -0,0 +1,217 @@ +name: Frontend License Report Workflow + +on: + push: + branches: + - V2 + paths: + - "frontend/package.json" + - "frontend/package-lock.json" + - "frontend/scripts/generate-licenses.js" + pull_request: + branches: + - V2 + paths: + - "frontend/package.json" + - "frontend/package-lock.json" + - "frontend/scripts/generate-licenses.js" + +permissions: + contents: read + +jobs: + generate-frontend-license-report: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + repository-projects: write # Required for enabling automerge + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2 + with: + egress-policy: audit + + - 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: Set up Node.js + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: '18' + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + - name: Install frontend dependencies + working-directory: frontend + run: npm ci + + - name: Generate frontend license report + working-directory: frontend + run: npm run generate-licenses + + - name: Check for license warnings + run: | + if [ -f "frontend/src/assets/license-warnings.json" ]; then + echo "LICENSE_WARNINGS_EXIST=true" >> $GITHUB_ENV + else + echo "LICENSE_WARNINGS_EXIST=false" >> $GITHUB_ENV + fi + + # PR Event: Check licenses and comment on PR + - name: Delete previous license check comments + if: github.event_name == 'pull_request' + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + github-token: ${{ steps.setup-bot.outputs.token }} + script: | + const { owner, repo } = context.repo; + const prNumber = context.issue.number; + + // Get all comments on the PR + const { data: comments } = await github.rest.issues.listComments({ + owner, + repo, + issue_number: prNumber, + per_page: 100 + }); + + // Filter for license check comments + const licenseComments = comments.filter(comment => + comment.body.includes('## āœ… Frontend License Check Passed') || + comment.body.includes('## āŒ Frontend License Check Failed') + ); + + // Delete old license check comments + for (const comment of licenseComments) { + console.log(`Deleting old license check comment: ${comment.id}`); + await github.rest.issues.deleteComment({ + owner, + repo, + comment_id: comment.id + }); + } + + - name: Comment on PR - License Check Results + if: github.event_name == 'pull_request' + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + github-token: ${{ steps.setup-bot.outputs.token }} + script: | + const { owner, repo } = context.repo; + const prNumber = context.issue.number; + const hasWarnings = process.env.LICENSE_WARNINGS_EXIST === 'true'; + + let commentBody; + + if (hasWarnings) { + // Read warnings file to get specific issues + const fs = require('fs'); + let warningDetails = ''; + try { + const warnings = JSON.parse(fs.readFileSync('frontend/src/assets/license-warnings.json', 'utf8')); + warningDetails = warnings.warnings.map(w => `- ${w.message}`).join('\n'); + } catch (e) { + warningDetails = 'Unable to read warning details'; + } + + commentBody = `## āŒ Frontend License Check Failed + +The frontend license check has detected compatibility warnings that require review: + +${warningDetails} + +**Action Required:** Please review these licenses to ensure they are acceptable for your use case before merging. + +_This check will fail the PR until license issues are resolved._`; + } else { + commentBody = `## āœ… Frontend License Check Passed + +All frontend licenses have been validated and no compatibility warnings were detected. + +The frontend license report has been updated successfully.`; + } + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: commentBody + }); + + - name: Fail workflow if license warnings exist (PR only) + if: github.event_name == 'pull_request' && env.LICENSE_WARNINGS_EXIST == 'true' + run: | + echo "āŒ License warnings detected. Failing the workflow." + exit 1 + + # Push Event: Commit license files and create PR + - name: Commit changes (Push only) + if: github.event_name == 'push' + run: | + git add frontend/src/assets/3rdPartyLicenses.json + # Note: Do NOT commit license-warnings.json - it's only for PR review + git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV + + - name: Prepare PR body (Push only) + if: github.event_name == 'push' + run: | + PR_BODY="Auto-generated by ${{ steps.setup-bot.outputs.app-slug }}[bot] + + This PR updates the frontend license report based on changes to package.json dependencies." + + if [ "${{ env.LICENSE_WARNINGS_EXIST }}" = "true" ]; then + PR_BODY="$PR_BODY + + ## āš ļø License Compatibility Warnings + + The following licenses may require review for corporate compatibility: + + $(cat frontend/src/assets/license-warnings.json | jq -r '.warnings[].message') + + Please review these licenses to ensure they are acceptable for your use case." + fi + + echo "PR_BODY<> $GITHUB_ENV + echo "$PR_BODY" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: Create Pull Request (Push only) + id: cpr + if: github.event_name == 'push' && env.CHANGES_DETECTED == 'true' + uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + with: + token: ${{ steps.setup-bot.outputs.token }} + commit-message: "Update Frontend 3rd Party Licenses" + committer: ${{ steps.setup-bot.outputs.committer }} + author: ${{ steps.setup-bot.outputs.committer }} + signoff: true + branch: update-frontend-3rd-party-licenses + base: V2 + title: "Update Frontend 3rd Party Licenses" + body: ${{ env.PR_BODY }} + labels: Licenses,github-actions,frontend + draft: false + delete-branch: true + sign-commits: true + + - name: Enable Pull Request Automerge (Push only) + if: github.event_name == 'push' && steps.cpr.outputs.pull-request-operation == 'created' && env.LICENSE_WARNINGS_EXIST == 'false' + run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}" + env: + GH_TOKEN: ${{ steps.setup-bot.outputs.token }} + + - name: Add review required label (Push only) + if: github.event_name == 'push' && steps.cpr.outputs.pull-request-operation == 'created' && env.LICENSE_WARNINGS_EXIST == 'true' + run: gh pr edit "${{ steps.cpr.outputs.pull-request-number }}" --add-label "license-review-required" + env: + GH_TOKEN: ${{ steps.setup-bot.outputs.token }} diff --git a/docker/README.md b/docker/README.md index e73a82072..df07e6b9e 100644 --- a/docker/README.md +++ b/docker/README.md @@ -14,15 +14,10 @@ docker/ │ ā”œā”€ā”€ Dockerfile # React/Vite frontend with nginx │ ā”œā”€ā”€ nginx.conf # Nginx configuration │ └── entrypoint.sh # Dynamic backend URL setup -ā”œā”€ā”€ monolith/ # Single container setup -│ ā”œā”€ā”€ Dockerfile # Combined frontend + backend -│ ā”œā”€ā”€ nginx-monolith.conf # Nginx config for monolith -│ └── start-monolith.sh # Startup script └── compose/ # Docker Compose files ā”œā”€ā”€ docker-compose.yml # Standard setup ā”œā”€ā”€ docker-compose.ultra-lite.yml # Ultra-lite setup - ā”œā”€ā”€ docker-compose.fat.yml # Full-featured setup - └── docker-compose.monolith.yml # Single container setup + └── docker-compose.fat.yml # Full-featured setup ``` ## Usage @@ -42,12 +37,6 @@ docker-compose -f docker/compose/docker-compose.ultra-lite.yml up --build docker-compose -f docker/compose/docker-compose.fat.yml up --build ``` -### Single Container (Monolith) - -```bash -# Single container with both frontend and backend -docker-compose -f docker/compose/docker-compose.monolith.yml up --build -``` ## Access Points @@ -57,7 +46,7 @@ docker-compose -f docker/compose/docker-compose.monolith.yml up --build ## Configuration -- **Backend URL**: Set `BACKEND_URL` environment variable for custom backend locations +- **Backend URL**: Set `VITE_API_BASE_URL` environment variable for custom backend locations - **Custom Ports**: Modify port mappings in docker-compose files - **Memory Limits**: Adjust memory limits per variant (2G ultra-lite, 4G standard, 6G fat) diff --git a/docker/backend/Dockerfile b/docker/backend/Dockerfile index 68dba6108..d3e64a843 100644 --- a/docker/backend/Dockerfile +++ b/docker/backend/Dockerfile @@ -1,11 +1,36 @@ -# Backend Dockerfile - Java Spring Boot with all dependencies +# Backend Dockerfile - Java Spring Boot with all dependencies and build stage +# Build the application +FROM gradle:8.14-jdk21 AS build + +COPY build.gradle . +COPY settings.gradle . +COPY gradlew . +COPY gradle gradle/ +COPY app/core/build.gradle core/. +COPY app/common/build.gradle common/. +COPY app/proprietary/build.gradle proprietary/. +RUN ./gradlew build -x spotlessApply -x spotlessCheck -x test -x sonarqube || return 0 + +# Set the working directory +WORKDIR /app + +# Copy the entire project to the working directory +COPY . . + +# Build the application with DISABLE_ADDITIONAL_FEATURES=false +RUN DISABLE_ADDITIONAL_FEATURES=false \ + STIRLING_PDF_DESKTOP_UI=false \ + ./gradlew clean build -x spotlessApply -x spotlessCheck -x test -x sonarqube + +# Main stage FROM alpine:3.22.0@sha256:8a1f59ffb675680d47db6337b49d22281a139e9d709335b492be023728e11715 # Copy necessary files COPY scripts /scripts COPY pipeline /pipeline COPY app/core/src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/ -COPY app/core/build/libs/*.jar app.jar +# first /app directory is for the build stage, second is for the final image +COPY --from=build /app/app/core/build/libs/*.jar app.jar ARG VERSION_TAG @@ -22,7 +47,7 @@ LABEL org.opencontainers.image.version="${VERSION_TAG}" LABEL org.opencontainers.image.keywords="PDF, manipulation, backend, API, Spring Boot" # Set Environment Variables -ENV DISABLE_ADDITIONAL_FEATURES=true \ +ENV DISABLE_ADDITIONAL_FEATURES=false \ VERSION_TAG=$VERSION_TAG \ JAVA_BASE_OPTS="-XX:+UnlockExperimentalVMOptions -XX:MaxRAMPercentage=75 -XX:InitiatingHeapOccupancyPercent=20 -XX:+G1PeriodicGCInvokesConcurrent -XX:G1PeriodicGCInterval=10000 -XX:+UseStringDeduplication -XX:G1PeriodicGCSystemLoadThreshold=70" \ JAVA_CUSTOM_OPTS="" \ @@ -50,7 +75,6 @@ RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/a tini \ bash \ curl \ - qpdf \ shadow \ su-exec \ openssl \ @@ -63,11 +87,13 @@ RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/a # pdftohtml poppler-utils \ # OCR MY PDF (unpaper for descew and other advanced features) + unpaper \ tesseract-ocr-data-eng \ tesseract-ocr-data-chi_sim \ tesseract-ocr-data-deu \ tesseract-ocr-data-fra \ tesseract-ocr-data-por \ + ocrmypdf \ # CV py3-opencv \ python3 \ diff --git a/docker/backend/Dockerfile.fat b/docker/backend/Dockerfile.fat index 5d4b73385..0fc2acc77 100644 --- a/docker/backend/Dockerfile.fat +++ b/docker/backend/Dockerfile.fat @@ -77,12 +77,13 @@ RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/a # pdftohtml poppler-utils \ # OCR MY PDF (unpaper for descew and other advanced featues) - qpdf \ + unpaper \ tesseract-ocr-data-eng \ tesseract-ocr-data-chi_sim \ tesseract-ocr-data-deu \ tesseract-ocr-data-fra \ tesseract-ocr-data-por \ + ocrmypdf \ font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra font-liberation font-linux-libertine \ # CV py3-opencv \ diff --git a/docker/backend/Dockerfile.ultra-lite b/docker/backend/Dockerfile.ultra-lite index 6291736e2..8c5e41cc5 100644 --- a/docker/backend/Dockerfile.ultra-lite +++ b/docker/backend/Dockerfile.ultra-lite @@ -1,4 +1,28 @@ -# Backend ultra-lite Dockerfile - Java Spring Boot with minimal dependencies +# Backend ultra-lite Dockerfile - Java Spring Boot with minimal dependencies and build stage +# Build the application +FROM gradle:8.14-jdk21 AS build + +COPY build.gradle . +COPY settings.gradle . +COPY gradlew . +COPY gradle gradle/ +COPY app/core/build.gradle core/. +COPY app/common/build.gradle common/. +COPY app/proprietary/build.gradle proprietary/. +RUN ./gradlew build -x spotlessApply -x spotlessCheck -x test -x sonarqube || return 0 + +# Set the working directory +WORKDIR /app + +# Copy the entire project to the working directory +COPY . . + +# Build the application with DISABLE_ADDITIONAL_FEATURES=true +RUN DISABLE_ADDITIONAL_FEATURES=true \ + STIRLING_PDF_DESKTOP_UI=false \ + ./gradlew clean build -x spotlessApply -x spotlessCheck -x test -x sonarqube + +# Main stage FROM alpine:3.22.0@sha256:8a1f59ffb675680d47db6337b49d22281a139e9d709335b492be023728e11715 ARG VERSION_TAG @@ -18,11 +42,10 @@ ENV DISABLE_ADDITIONAL_FEATURES=true \ TMP=/tmp/stirling-pdf # Copy necessary files -COPY scripts/download-security-jar.sh /scripts/download-security-jar.sh COPY scripts/init-without-ocr.sh /scripts/init-without-ocr.sh COPY scripts/installFonts.sh /scripts/installFonts.sh COPY pipeline /pipeline -COPY app/core/build/libs/*.jar app.jar +COPY --from=build /app/app/core/build/libs/*.jar app.jar # Set up necessary directories and permissions RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \ diff --git a/docker/compose/docker-compose.fat.yml b/docker/compose/docker-compose.fat.yml index 764c9604c..8399c4080 100644 --- a/docker/compose/docker-compose.fat.yml +++ b/docker/compose/docker-compose.fat.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: backend: build: @@ -43,8 +41,8 @@ services: frontend: build: - context: ../../frontend - dockerfile: ../docker/frontend/Dockerfile + context: ../.. + dockerfile: docker/frontend/Dockerfile container_name: stirling-pdf-frontend-fat restart: on-failure:5 ports: diff --git a/docker/compose/docker-compose.monolith.yml b/docker/compose/docker-compose.monolith.yml deleted file mode 100644 index 06064cdf7..000000000 --- a/docker/compose/docker-compose.monolith.yml +++ /dev/null @@ -1,42 +0,0 @@ -version: '3.8' - -services: - stirling-pdf-monolith: - build: - context: ../.. - dockerfile: docker/monolith/Dockerfile - container_name: stirling-pdf-monolith - restart: on-failure:5 - deploy: - resources: - limits: - memory: 4G - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:80/ && curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP'"] - interval: 10s - timeout: 15s - retries: 16 - ports: - - "3000:80" # Frontend access - - "8080:8080" # Direct backend access (for debugging) - volumes: - - ../../stirling/latest/data:/usr/share/tessdata:rw - - ../../stirling/latest/config:/configs:rw - - ../../stirling/latest/logs:/logs:rw - environment: - DISABLE_ADDITIONAL_FEATURES: "true" - SECURITY_ENABLELOGIN: "false" - LANGS: "en_GB,en_US,ar_AR,de_DE,fr_FR,es_ES,zh_CN,zh_TW,ca_CA,it_IT,sv_SE,pl_PL,ro_RO,ko_KR,pt_BR,ru_RU,el_GR,hi_IN,hu_HU,tr_TR,id_ID" - SYSTEM_DEFAULTLOCALE: en-US - UI_APPNAME: Stirling-PDF - UI_HOMEDESCRIPTION: Single container Stirling-PDF - UI_APPNAMENAVBAR: Stirling-PDF Monolith - SYSTEM_MAXFILESIZE: "100" - METRICS_ENABLED: "true" - SYSTEM_GOOGLEVISIBILITY: "true" - SHOW_SURVEY: "true" - -volumes: - stirling-data: - stirling-config: - stirling-logs: \ No newline at end of file diff --git a/docker/compose/docker-compose.ultra-lite.yml b/docker/compose/docker-compose.ultra-lite.yml index a16484262..bfbf55861 100644 --- a/docker/compose/docker-compose.ultra-lite.yml +++ b/docker/compose/docker-compose.ultra-lite.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: backend: build: @@ -38,8 +36,8 @@ services: frontend: build: - context: ../../frontend - dockerfile: ../docker/frontend/Dockerfile + context: ../.. + dockerfile: docker/frontend/Dockerfile container_name: stirling-pdf-frontend-ultra-lite restart: on-failure:5 ports: diff --git a/docker/compose/docker-compose.yml b/docker/compose/docker-compose.yml index 3bcdca423..4defef872 100644 --- a/docker/compose/docker-compose.yml +++ b/docker/compose/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: backend: build: @@ -41,8 +39,8 @@ services: frontend: build: - context: ../../frontend - dockerfile: ../docker/frontend/Dockerfile + context: ../.. + dockerfile: docker/frontend/Dockerfile container_name: stirling-pdf-frontend restart: on-failure:5 ports: diff --git a/docker/frontend/Dockerfile b/docker/frontend/Dockerfile index af570b6bb..a220782b0 100644 --- a/docker/frontend/Dockerfile +++ b/docker/frontend/Dockerfile @@ -4,13 +4,13 @@ FROM node:20-alpine AS build WORKDIR /app # Copy package files -COPY package*.json ./ +COPY frontend/package*.json ./ # Install dependencies RUN npm ci # Copy source code -COPY . . +COPY frontend . # Build the application RUN npm run build @@ -22,8 +22,8 @@ FROM nginx:alpine COPY --from=build /app/dist /usr/share/nginx/html # Copy nginx configuration and entrypoint -COPY nginx.conf /etc/nginx/nginx.conf -COPY entrypoint.sh /entrypoint.sh +COPY docker/frontend/nginx.conf /etc/nginx/nginx.conf +COPY docker/frontend/entrypoint.sh /entrypoint.sh # Make entrypoint executable RUN chmod +x /entrypoint.sh @@ -32,7 +32,7 @@ RUN chmod +x /entrypoint.sh EXPOSE 80 # Environment variables for flexibility -ENV BACKEND_URL=http://backend:8080 +ENV VITE_API_BASE_URL=http://backend:8080 # Use custom entrypoint ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/docker/frontend/entrypoint.sh b/docker/frontend/entrypoint.sh index ca1d6cba7..a81272969 100644 --- a/docker/frontend/entrypoint.sh +++ b/docker/frontend/entrypoint.sh @@ -1,10 +1,10 @@ #!/bin/sh # Set default backend URL if not provided -BACKEND_URL=${BACKEND_URL:-"http://backend:8080"} +VITE_API_BASE_URL=${VITE_API_BASE_URL:-"http://backend:8080"} # Replace the placeholder in nginx.conf with the actual backend URL -sed -i "s|\${BACKEND_URL}|${BACKEND_URL}|g" /etc/nginx/nginx.conf +sed -i "s|\${VITE_API_BASE_URL}|${VITE_API_BASE_URL}|g" /etc/nginx/nginx.conf # Start nginx exec nginx -g "daemon off;" \ No newline at end of file diff --git a/docker/frontend/nginx.conf b/docker/frontend/nginx.conf index f45f5784b..456d70140 100644 --- a/docker/frontend/nginx.conf +++ b/docker/frontend/nginx.conf @@ -17,6 +17,9 @@ http { server_name _; root /usr/share/nginx/html; index index.html index.htm; + + # Global settings for file uploads + client_max_body_size 100m; # Handle client-side routing - support subpaths location / { @@ -25,13 +28,28 @@ http { # Proxy API calls to backend location /api/ { - proxy_pass ${BACKEND_URL}/api/; + proxy_pass ${VITE_API_BASE_URL}/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; + + # Additional headers for proper API proxying + proxy_set_header Connection ''; + proxy_http_version 1.1; + proxy_buffering off; + proxy_cache off; + + # Timeout settings for large file uploads + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # Request size limits for file uploads + client_max_body_size 100m; + proxy_request_buffering off; } # Cache static assets diff --git a/docker/monolith/Dockerfile b/docker/monolith/Dockerfile deleted file mode 100644 index 1957fb8f5..000000000 --- a/docker/monolith/Dockerfile +++ /dev/null @@ -1,128 +0,0 @@ -# Monolith Dockerfile - Frontend + Backend in same container -# Build frontend -FROM node:20-alpine AS frontend-build - -WORKDIR /app/frontend - -# Copy frontend package files -COPY frontend/package*.json ./ - -# Install frontend dependencies -RUN npm ci - -# Copy frontend source -COPY frontend/ ./ - -# Build frontend -RUN npm run build - -# Main stage - Backend with frontend files -FROM alpine:3.22.0@sha256:8a1f59ffb675680d47db6337b49d22281a139e9d709335b492be023728e11715 - -# Copy necessary files -COPY scripts /scripts -COPY pipeline /pipeline -COPY stirling-pdf/src/main/resources/static/fonts/*.ttf /usr/share/fonts/opentype/noto/ -COPY stirling-pdf/build/libs/*.jar app.jar - -# Copy built frontend files -COPY --from=frontend-build /app/frontend/dist /usr/share/nginx/html - -ARG VERSION_TAG - -LABEL org.opencontainers.image.title="Stirling-PDF Monolith" -LABEL org.opencontainers.image.description="Single container with both frontend and backend for Stirling-PDF" -LABEL org.opencontainers.image.source="https://github.com/Stirling-Tools/Stirling-PDF" -LABEL org.opencontainers.image.licenses="MIT" -LABEL org.opencontainers.image.vendor="Stirling-Tools" -LABEL org.opencontainers.image.url="https://www.stirlingpdf.com" -LABEL org.opencontainers.image.documentation="https://docs.stirlingpdf.com" -LABEL maintainer="Stirling-Tools" -LABEL org.opencontainers.image.authors="Stirling-Tools" -LABEL org.opencontainers.image.version="${VERSION_TAG}" -LABEL org.opencontainers.image.keywords="PDF, manipulation, monolith, single-container" - -# Set Environment Variables -ENV DISABLE_ADDITIONAL_FEATURES=true \ - VERSION_TAG=$VERSION_TAG \ - JAVA_BASE_OPTS="-XX:+UnlockExperimentalVMOptions -XX:MaxRAMPercentage=75 -XX:InitiatingHeapOccupancyPercent=20 -XX:+G1PeriodicGCInvokesConcurrent -XX:G1PeriodicGCInterval=10000 -XX:+UseStringDeduplication -XX:G1PeriodicGCSystemLoadThreshold=70" \ - JAVA_CUSTOM_OPTS="" \ - HOME=/home/stirlingpdfuser \ - PUID=1000 \ - PGID=1000 \ - UMASK=022 \ - PYTHONPATH=/usr/lib/libreoffice/program:/opt/venv/lib/python3.12/site-packages \ - UNO_PATH=/usr/lib/libreoffice/program \ - URE_BOOTSTRAP=file:///usr/lib/libreoffice/program/fundamentalrc \ - PATH=$PATH:/opt/venv/bin \ - STIRLING_TEMPFILES_DIRECTORY=/tmp/stirling-pdf \ - TMPDIR=/tmp/stirling-pdf \ - TEMP=/tmp/stirling-pdf \ - TMP=/tmp/stirling-pdf - -# Install nginx and all dependencies -RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \ - echo "@community https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \ - echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \ - apk upgrade --no-cache -a && \ - apk add --no-cache \ - ca-certificates \ - tzdata \ - tini \ - bash \ - curl \ - qpdf \ - shadow \ - su-exec \ - openssl \ - openssl-dev \ - openjdk21-jre \ - nginx \ - # Doc conversion - gcompat \ - libc6-compat \ - libreoffice \ - # pdftohtml - poppler-utils \ - # OCR MY PDF (unpaper for descew and other advanced features) - tesseract-ocr-data-eng \ - tesseract-ocr-data-chi_sim \ - tesseract-ocr-data-deu \ - tesseract-ocr-data-fra \ - tesseract-ocr-data-por \ - # CV - py3-opencv \ - python3 \ - py3-pip \ - py3-pillow@testing \ - py3-pdf2image@testing && \ - python3 -m venv /opt/venv && \ - /opt/venv/bin/pip install --upgrade pip setuptools && \ - /opt/venv/bin/pip install --no-cache-dir --upgrade unoserver weasyprint && \ - ln -s /usr/lib/libreoffice/program/uno.py /opt/venv/lib/python3.12/site-packages/ && \ - ln -s /usr/lib/libreoffice/program/unohelper.py /opt/venv/lib/python3.12/site-packages/ && \ - ln -s /usr/lib/libreoffice/program /opt/venv/lib/python3.12/site-packages/LibreOffice && \ - mv /usr/share/tessdata /usr/share/tessdata-original && \ - mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /tmp/stirling-pdf && \ - fc-cache -f -v && \ - chmod +x /scripts/* && \ - chmod +x /scripts/init.sh && \ - # User permissions - addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \ - chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline /tmp/stirling-pdf && \ - chown stirlingpdfuser:stirlingpdfgroup /app.jar && \ - chown -R stirlingpdfuser:stirlingpdfgroup /usr/share/nginx/html - -# Copy nginx configuration for monolith -COPY docker/monolith/nginx-monolith.conf /etc/nginx/nginx.conf - -# Copy startup script -COPY docker/monolith/start-monolith.sh /start-monolith.sh -RUN chmod +x /start-monolith.sh - -# Expose both ports -EXPOSE 80 8080 - -# Set user and run command -ENTRYPOINT ["tini", "--"] -CMD ["/start-monolith.sh"] \ No newline at end of file diff --git a/docker/monolith/nginx-monolith.conf b/docker/monolith/nginx-monolith.conf deleted file mode 100644 index 05fa72b7d..000000000 --- a/docker/monolith/nginx-monolith.conf +++ /dev/null @@ -1,49 +0,0 @@ -events { - worker_connections 1024; -} - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - # Gzip compression - gzip on; - gzip_vary on; - gzip_min_length 1024; - gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json; - - server { - listen 80; - server_name _; - root /usr/share/nginx/html; - index index.html index.htm; - - # Handle client-side routing - support subpaths - location / { - try_files $uri $uri/ /index.html; - } - - # Proxy API calls to backend running on same container - location /api/ { - proxy_pass http://localhost:8080/api/; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Port $server_port; - } - - # Cache static assets - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { - expires 1y; - add_header Cache-Control "public, immutable"; - } - - # Security headers - add_header X-Frame-Options "SAMEORIGIN" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-XSS-Protection "1; mode=block" always; - add_header Referrer-Policy "strict-origin-when-cross-origin" always; - } -} \ No newline at end of file diff --git a/docker/monolith/start-monolith.sh b/docker/monolith/start-monolith.sh deleted file mode 100644 index b75f15d2d..000000000 --- a/docker/monolith/start-monolith.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -# Start the Java backend in the background -echo "Starting Java backend..." -su-exec stirlingpdfuser:stirlingpdfgroup bash -c " - cd /home/stirlingpdfuser && \ - java -Dfile.encoding=UTF-8 -Djava.io.tmpdir=/tmp/stirling-pdf -jar /app.jar & - /opt/venv/bin/unoserver --port 2003 --interface 127.0.0.1 & -" - -# Wait for backend to start -echo "Waiting for backend to start..." -until curl -f http://localhost:8080/api/v1/info/status >/dev/null 2>&1; do - sleep 2 -done - -echo "Backend started, starting nginx..." - -# Start nginx in the foreground -nginx -g "daemon off;" \ No newline at end of file diff --git a/exampleYmlFiles/docker-compose-latest-fat-endpoints-disabled.yml b/exampleYmlFiles/docker-compose-latest-fat-endpoints-disabled.yml deleted file mode 100644 index 827de1e19..000000000 --- a/exampleYmlFiles/docker-compose-latest-fat-endpoints-disabled.yml +++ /dev/null @@ -1,36 +0,0 @@ - -services: - stirling-pdf: - container_name: Stirling-PDF-Fat-Disable-Endpoints - image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest-fat - deploy: - resources: - limits: - memory: 4G - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP'"] - interval: 5s - timeout: 10s - retries: 16 - ports: - - 8080:8080 - volumes: - - ./stirling/latest/data:/usr/share/tessdata:rw - - ./stirling/latest/config:/configs:rw - - ./stirling/latest/logs:/logs:rw - - ../testing/allEndpointsRemovedSettings.yml:/configs/settings.yml:rw - environment: - DISABLE_ADDITIONAL_FEATURES: "false" - SECURITY_ENABLELOGIN: "false" - PUID: 1002 - PGID: 1002 - UMASK: "022" - SYSTEM_DEFAULTLOCALE: en-US - UI_APPNAME: Stirling-PDF - UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest-fat with all Endpoints Disabled - UI_APPNAMENAVBAR: Stirling-PDF Latest-fat - SYSTEM_MAXFILESIZE: "100" - METRICS_ENABLED: "true" - SYSTEM_GOOGLEVISIBILITY: "true" - SHOW_SURVEY: "true" - restart: on-failure:5 diff --git a/exampleYmlFiles/docker-compose-latest-fat-security-postgres.yml b/exampleYmlFiles/docker-compose-latest-fat-security-postgres.yml deleted file mode 100644 index bbf8a2115..000000000 --- a/exampleYmlFiles/docker-compose-latest-fat-security-postgres.yml +++ /dev/null @@ -1,64 +0,0 @@ -services: - stirling-pdf: - container_name: Stirling-PDF-Security-Fat-Postgres - image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest-fat-postgres - deploy: - resources: - limits: - memory: 4G - depends_on: - - db - healthcheck: - test: [ "CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP'" ] - interval: 5s - timeout: 10s - retries: 16 - ports: - - 8080:8080 - volumes: - - ./stirling/latest/data:/usr/share/tessdata:rw - - ./stirling/latest/config:/configs:rw - - ./stirling/latest/logs:/logs:rw - environment: - DISABLE_ADDITIONAL_FEATURES: "false" - SECURITY_ENABLELOGIN: "false" - PUID: 1002 - PGID: 1002 - UMASK: "022" - SYSTEM_DEFAULTLOCALE: en-US - UI_APPNAME: Stirling-PDF - UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest-fat with Security and PostgreSQL - UI_APPNAMENAVBAR: Stirling-PDF Latest-fat-PostgreSQL - SYSTEM_MAXFILESIZE: "100" - METRICS_ENABLED: "true" - SYSTEM_GOOGLEVISIBILITY: "true" - SYSTEM_DATASOURCE_ENABLECUSTOMDATABASE: "true" - SYSTEM_DATASOURCE_CUSTOMDATABASEURL: "jdbc:postgresql://db:5432/stirling_pdf" - SYSTEM_DATASOURCE_USERNAME: "admin" - SYSTEM_DATASOURCE_PASSWORD: "stirling" - SHOW_SURVEY: "true" - restart: on-failure:5 - - db: - image: 'postgres:17.2-alpine' - restart: on-failure:5 - container_name: db - ports: - - "5432:5432" - environment: - POSTGRES_DB: "stirling_pdf" - POSTGRES_USER: "admin" - POSTGRES_PASSWORD: "stirling" - shm_size: "512mb" - deploy: - resources: - limits: - memory: 512m - cpus: "0.5" - healthcheck: - test: [ "CMD-SHELL", "pg_isready -U admin stirling_pdf" ] - interval: 1s - timeout: 5s - retries: 10 - volumes: - - ./stirling/latest/data:/pgdata diff --git a/exampleYmlFiles/docker-compose-latest-fat-security.yml b/exampleYmlFiles/docker-compose-latest-fat-security.yml deleted file mode 100644 index 5b07420ff..000000000 --- a/exampleYmlFiles/docker-compose-latest-fat-security.yml +++ /dev/null @@ -1,34 +0,0 @@ -services: - stirling-pdf: - container_name: Stirling-PDF-Security-Fat - image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest-fat - deploy: - resources: - limits: - memory: 4G - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP'"] - interval: 5s - timeout: 10s - retries: 16 - ports: - - 8080:8080 - volumes: - - ./stirling/latest/data:/usr/share/tessdata:rw - - ./stirling/latest/config:/configs:rw - - ./stirling/latest/logs:/logs:rw - environment: - DISABLE_ADDITIONAL_FEATURES: "false" - SECURITY_ENABLELOGIN: "false" - PUID: 1002 - PGID: 1002 - UMASK: "022" - SYSTEM_DEFAULTLOCALE: en-US - UI_APPNAME: Stirling-PDF - UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest-fat with Security - UI_APPNAMENAVBAR: Stirling-PDF Latest-fat - SYSTEM_MAXFILESIZE: "100" - METRICS_ENABLED: "true" - SYSTEM_GOOGLEVISIBILITY: "true" - SHOW_SURVEY: "true" - restart: on-failure:5 diff --git a/exampleYmlFiles/docker-compose-latest-security-with-sso.yml b/exampleYmlFiles/docker-compose-latest-security-with-sso.yml deleted file mode 100644 index 55ea0893d..000000000 --- a/exampleYmlFiles/docker-compose-latest-security-with-sso.yml +++ /dev/null @@ -1,42 +0,0 @@ -services: - stirling-pdf: - container_name: Stirling-PDF-Security - image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest - deploy: - resources: - limits: - memory: 4G - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"] - interval: 5s - timeout: 10s - retries: 16 - ports: - - "8080:8080" - volumes: - - ./stirling/latest/data:/usr/share/tessdata:rw - - ./stirling/latest/config:/configs:rw - - ./stirling/latest/logs:/logs:rw - environment: - DISABLE_ADDITIONAL_FEATURES: "false" - SECURITY_ENABLELOGIN: "true" - SECURITY_OAUTH2_ENABLED: "true" - SECURITY_OAUTH2_AUTOCREATEUSER: "true" # This is set to true to allow auto-creation of non-existing users in Stirling-PDF - SECURITY_OAUTH2_ISSUER: "https://accounts.google.com" # Change with any other provider that supports OpenID Connect Discovery (/.well-known/openid-configuration) end-point - SECURITY_OAUTH2_CLIENTID: ".apps.googleusercontent.com" # Client ID from your provider - SECURITY_OAUTH2_CLIENTSECRET: "" # Client Secret from your provider - SECURITY_OAUTH2_SCOPES: "openid,profile,email" # Expected OAuth2 Scope - SECURITY_OAUTH2_USEASUSERNAME: "email" # Default is 'email'; custom fields can be used as the username - SECURITY_OAUTH2_PROVIDER: "google" # Set this to your OAuth provider's name, e.g., 'google' or 'keycloak' - PUID: 1002 - PGID: 1002 - UMASK: "022" - SYSTEM_DEFAULTLOCALE: en-US - UI_APPNAME: Stirling-PDF - UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security - UI_APPNAMENAVBAR: Stirling-PDF Latest - SYSTEM_MAXFILESIZE: "100" - METRICS_ENABLED: "true" - SYSTEM_GOOGLEVISIBILITY: "true" - SHOW_SURVEY: "true" - restart: on-failure:5 diff --git a/exampleYmlFiles/docker-compose-latest-security.yml b/exampleYmlFiles/docker-compose-latest-security.yml deleted file mode 100644 index c6589ab9c..000000000 --- a/exampleYmlFiles/docker-compose-latest-security.yml +++ /dev/null @@ -1,34 +0,0 @@ -services: - stirling-pdf: - container_name: Stirling-PDF-Security - image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest - deploy: - resources: - limits: - memory: 4G - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"] - interval: 5s - timeout: 10s - retries: 16 - ports: - - "8080:8080" - volumes: - - ./stirling/latest/data:/usr/share/tessdata:rw - - ./stirling/latest/config:/configs:rw - - ./stirling/latest/logs:/logs:rw - environment: - DISABLE_ADDITIONAL_FEATURES: "false" - SECURITY_ENABLELOGIN: "true" - PUID: 1002 - PGID: 1002 - UMASK: "022" - SYSTEM_DEFAULTLOCALE: en-US - UI_APPNAME: Stirling-PDF - UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security - UI_APPNAMENAVBAR: Stirling-PDF Latest - SYSTEM_MAXFILESIZE: "100" - METRICS_ENABLED: "true" - SYSTEM_GOOGLEVISIBILITY: "true" - SHOW_SURVEY: "true" - restart: on-failure:5 diff --git a/exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml b/exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml deleted file mode 100644 index fe839d941..000000000 --- a/exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml +++ /dev/null @@ -1,31 +0,0 @@ -services: - stirling-pdf: - container_name: Stirling-PDF-Ultra-Lite-Security - image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest-ultra-lite - deploy: - resources: - limits: - memory: 1G - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"] - interval: 5s - timeout: 10s - retries: 16 - ports: - - "8080:8080" - volumes: - - ./stirling/latest/data:/usr/share/tessdata:rw - - ./stirling/latest/config:/configs:rw - - ./stirling/latest/logs:/logs:rw - environment: - DISABLE_ADDITIONAL_FEATURES: "false" - SECURITY_ENABLELOGIN: "true" - SYSTEM_DEFAULTLOCALE: en-US - UI_APPNAME: Stirling-PDF-Lite - UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Lite Latest with Security - UI_APPNAMENAVBAR: Stirling-PDF-Lite Latest - SYSTEM_MAXFILESIZE: "100" - METRICS_ENABLED: "true" - SYSTEM_GOOGLEVISIBILITY: "true" - SHOW_SURVEY: "true" - restart: on-failure:5 diff --git a/exampleYmlFiles/docker-compose-latest.yml b/exampleYmlFiles/docker-compose-latest.yml deleted file mode 100644 index a68da538a..000000000 --- a/exampleYmlFiles/docker-compose-latest.yml +++ /dev/null @@ -1,31 +0,0 @@ -services: - stirling-pdf: - container_name: Stirling-PDF - image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest - deploy: - resources: - limits: - memory: 4G - healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -qv 'Please sign in'"] - interval: 5s - timeout: 10s - retries: 16 - ports: - - "8080:8080" - volumes: - - ./stirling/latest/data:/usr/share/tessdata:rw - - ./stirling/latest/config:/configs:rw - - ./stirling/latest/logs:/logs:rw - environment: - SECURITY_ENABLELOGIN: "false" - LANGS: "en_GB,en_US,ar_AR,de_DE,fr_FR,es_ES,zh_CN,zh_TW,ca_CA,it_IT,sv_SE,pl_PL,ro_RO,ko_KR,pt_BR,ru_RU,el_GR,hi_IN,hu_HU,tr_TR,id_ID" - SYSTEM_DEFAULTLOCALE: en-US - UI_APPNAME: Stirling-PDF - UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest - UI_APPNAMENAVBAR: Stirling-PDF Latest - SYSTEM_MAXFILESIZE: "100" - METRICS_ENABLED: "true" - SYSTEM_GOOGLEVISIBILITY: "true" - SHOW_SURVEY: "true" - restart: on-failure:5 diff --git a/exampleYmlFiles/test_cicd.yml b/exampleYmlFiles/test_cicd.yml deleted file mode 100644 index 31e24da48..000000000 --- a/exampleYmlFiles/test_cicd.yml +++ /dev/null @@ -1,34 +0,0 @@ -services: - stirling-pdf: - container_name: Stirling-PDF-Security-Fat-with-login - image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest-fat - deploy: - resources: - limits: - memory: 4G - healthcheck: - test: ["CMD-SHELL", "curl -f -H 'X-API-KEY: 123456789' http://localhost:8080/api/v1/info/status | grep -q 'UP'"] - interval: 5s - timeout: 10s - retries: 16 - ports: - - 8080:8080 - volumes: - - ./stirling/latest/data:/usr/share/tessdata:rw - - ./stirling/latest/config:/configs:rw - - ./stirling/latest/logs:/logs:rw - environment: - DISABLE_ADDITIONAL_FEATURES: "false" - SECURITY_ENABLELOGIN: "true" - PUID: 1002 - PGID: 1002 - UMASK: "022" - SYSTEM_DEFAULTLOCALE: en-US - UI_APPNAME: Stirling-PDF - UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest-fat with Security - UI_APPNAMENAVBAR: Stirling-PDF Latest-fat - SYSTEM_MAXFILESIZE: "100" - METRICS_ENABLED: "true" - SYSTEM_GOOGLEVISIBILITY: "true" - SECURITY_CUSTOMGLOBALAPIKEY: "123456789" - restart: on-failure:5 diff --git a/frontend/README.md b/frontend/README.md index 52be84b38..1640a506e 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -2,6 +2,10 @@ This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). +## Docker Setup + +For Docker deployments and configuration, see the [Docker README](../docker/README.md). + ## Available Scripts In the project directory, you can run: diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 3af784b5d..629409568 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "frontend", "version": "0.1.0", + "license": "SEE LICENSE IN https://raw.githubusercontent.com/Stirling-Tools/Stirling-PDF/refs/heads/main/proprietary/LICENSE", "dependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", @@ -42,6 +43,7 @@ "@types/react": "^19.1.4", "@types/react-dom": "^19.1.5", "@vitejs/plugin-react": "^4.5.0", + "license-checker": "^25.0.1", "postcss": "^8.5.3", "postcss-cli": "^11.0.1", "postcss-preset-mantine": "^1.17.0", @@ -2480,8 +2482,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "license": "ISC", - "optional": true + "devOptional": true, + "license": "ISC" }, "node_modules/agent-base": { "version": "6.0.2", @@ -2565,6 +2567,21 @@ "dequal": "^2.0.3" } }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2647,8 +2664,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT", - "optional": true + "devOptional": true, + "license": "MIT" }, "node_modules/binary-extensions": { "version": "2.3.0", @@ -2667,8 +2684,8 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "devOptional": true, "license": "MIT", - "optional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2919,8 +2936,8 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT", - "optional": true + "devOptional": true, + "license": "MIT" }, "node_modules/console-control-strings": { "version": "1.1.0", @@ -3024,6 +3041,16 @@ } } }, + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/decompress-response": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", @@ -3087,6 +3114,16 @@ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", "license": "MIT" }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "node_modules/dom-accessibility-api": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", @@ -3408,8 +3445,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC", - "optional": true + "devOptional": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -3528,8 +3565,8 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", + "devOptional": true, "license": "ISC", - "optional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3642,6 +3679,12 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, "node_modules/html-parse-stringify": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", @@ -3745,8 +3788,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "devOptional": true, "license": "ISC", - "optional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -3937,6 +3980,141 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/license-checker": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", + "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "debug": "^3.1.0", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "read-installed": "~4.0.3", + "semver": "^5.5.0", + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0", + "spdx-satisfies": "^4.0.0", + "treeify": "^1.1.0" + }, + "bin": { + "license-checker": "bin/license-checker" + } + }, + "node_modules/license-checker/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/license-checker/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/license-checker/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/license-checker/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/license-checker/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/license-checker/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/license-checker/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/license-checker/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/license-checker/node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/license-checker/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/license-checker/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/lie": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", @@ -4331,8 +4509,8 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "devOptional": true, "license": "ISC", - "optional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4340,6 +4518,15 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -4493,6 +4680,27 @@ "node": ">=6" } }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4512,6 +4720,12 @@ "node": ">=0.10.0" } }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, "node_modules/npmlog": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", @@ -4539,12 +4753,41 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "devOptional": true, "license": "ISC", - "optional": true, "dependencies": { "wrappy": "1" } }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "deprecated": "This package is no longer supported.", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -4584,8 +4827,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "devOptional": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -5288,6 +5531,46 @@ "pify": "^2.3.0" } }, + "node_modules/read-installed": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", + "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", + "deprecated": "This package is no longer supported.", + "dev": true, + "dependencies": { + "debuglog": "^1.0.1", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.2" + } + }, + "node_modules/read-installed/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-package-json": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", + "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", + "dev": true, + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -5303,6 +5586,19 @@ "node": ">= 6" } }, + "node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -5558,6 +5854,15 @@ "simple-concat": "^1.0.0" } }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -5576,6 +5881,66 @@ "node": ">=0.10.0" } }, + "node_modules/spdx-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", + "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", + "dev": true, + "dependencies": { + "array-find-index": "^1.0.2", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true + }, + "node_modules/spdx-ranges": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", + "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", + "dev": true + }, + "node_modules/spdx-satisfies": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz", + "integrity": "sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==", + "dev": true, + "dependencies": { + "spdx-compare": "^1.0.0", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -5814,6 +6179,15 @@ "node": ">=8.0" } }, + "node_modules/treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -5980,6 +6354,22 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/util-extend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "node_modules/vite": { "version": "6.3.5", "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", @@ -6129,8 +6519,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC", - "optional": true + "devOptional": true, + "license": "ISC" }, "node_modules/y18n": { "version": "5.0.8", diff --git a/frontend/package.json b/frontend/package.json index 0f982313c..b30f38553 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -2,6 +2,7 @@ "name": "frontend", "version": "0.1.0", "private": true, + "license": "SEE LICENSE IN https://raw.githubusercontent.com/Stirling-Tools/Stirling-PDF/refs/heads/main/proprietary/LICENSE", "proxy": "http://localhost:8080", "dependencies": { "@emotion/react": "^11.14.0", @@ -38,7 +39,8 @@ "build": "vite build", "preview": "vite preview", "tauri-dev": "tauri dev --no-watch", - "tauri-build": "tauri build" + "tauri-build": "tauri build", + "generate-licenses": "node scripts/generate-licenses.js" }, "eslintConfig": { "extends": [ @@ -63,6 +65,7 @@ "@types/react": "^19.1.4", "@types/react-dom": "^19.1.5", "@vitejs/plugin-react": "^4.5.0", + "license-checker": "^25.0.1", "postcss": "^8.5.3", "postcss-cli": "^11.0.1", "postcss-preset-mantine": "^1.17.0", diff --git a/frontend/scripts/generate-licenses.js b/frontend/scripts/generate-licenses.js new file mode 100644 index 000000000..cfd5f675a --- /dev/null +++ b/frontend/scripts/generate-licenses.js @@ -0,0 +1,415 @@ +#!/usr/bin/env node + +const { execSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +/** + * Generate 3rd party licenses for frontend dependencies + * This script creates a JSON file similar to the Java backend's 3rdPartyLicenses.json + */ + +const OUTPUT_FILE = path.join(__dirname, '..', 'src', 'assets', '3rdPartyLicenses.json'); +const PACKAGE_JSON = path.join(__dirname, '..', 'package.json'); + +// Ensure the output directory exists +const outputDir = path.dirname(OUTPUT_FILE); +if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); +} + +console.log('šŸ” Generating frontend license report...'); + +try { + // Install license-checker if not present + try { + require.resolve('license-checker'); + } catch (e) { + console.log('šŸ“¦ Installing license-checker...'); + execSync('npm install --save-dev license-checker', { stdio: 'inherit' }); + } + + // Generate license report using license-checker (more reliable) + const licenseReport = execSync('npx license-checker --production --json', { + encoding: 'utf8', + cwd: path.dirname(PACKAGE_JSON) + }); + + let licenseData; + try { + licenseData = JSON.parse(licenseReport); + } catch (parseError) { + console.error('āŒ Failed to parse license data:', parseError.message); + console.error('Raw output:', licenseReport.substring(0, 500) + '...'); + process.exit(1); + } + + if (!licenseData || typeof licenseData !== 'object') { + console.error('āŒ Invalid license data structure'); + process.exit(1); + } + + // Convert license-checker format to array + const licenseArray = Object.entries(licenseData).map(([key, value]) => { + let name, version; + + // Handle scoped packages like @mantine/core@1.0.0 + if (key.startsWith('@')) { + const parts = key.split('@'); + name = `@${parts[1]}`; + version = parts[2]; + } else { + // Handle regular packages like react@18.0.0 + const lastAtIndex = key.lastIndexOf('@'); + name = key.substring(0, lastAtIndex); + version = key.substring(lastAtIndex + 1); + } + + // Normalize license types for edge cases + let licenseType = value.licenses; + + // Handle missing or null licenses + if (!licenseType || licenseType === null || licenseType === undefined) { + licenseType = 'Unknown'; + } + + // Handle empty string licenses + if (licenseType === '') { + licenseType = 'Unknown'; + } + + // Handle array licenses (rare but possible) + if (Array.isArray(licenseType)) { + licenseType = licenseType.join(' AND '); + } + + // Handle object licenses (fallback) + if (typeof licenseType === 'object' && licenseType !== null) { + licenseType = 'Unknown'; + } + + return { + name: name, + version: version || value.version || 'unknown', + licenseType: licenseType, + repository: value.repository, + url: value.url, + link: value.licenseUrl + }; + }); + + // Transform to match Java backend format + const transformedData = { + dependencies: licenseArray.map(dep => { + const licenseType = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : (dep.licenseType || 'Unknown'); + const licenseUrl = dep.link || getLicenseUrl(licenseType); + + return { + moduleName: dep.name, + moduleUrl: dep.repository || dep.url || `https://www.npmjs.com/package/${dep.name}`, + moduleVersion: dep.version, + moduleLicense: licenseType, + moduleLicenseUrl: licenseUrl + }; + }) + }; + + // Log summary of license types found + const licenseSummary = licenseArray.reduce((acc, dep) => { + const license = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : (dep.licenseType || 'Unknown'); + acc[license] = (acc[license] || 0) + 1; + return acc; + }, {}); + + console.log('šŸ“Š License types found:'); + Object.entries(licenseSummary).forEach(([license, count]) => { + console.log(` ${license}: ${count} packages`); + }); + + // Log any complex or unusual license formats for debugging + const complexLicenses = licenseArray.filter(dep => + dep.licenseType && ( + dep.licenseType.includes('AND') || + dep.licenseType.includes('OR') || + dep.licenseType === 'Unknown' || + dep.licenseType.includes('SEE LICENSE') + ) + ); + + if (complexLicenses.length > 0) { + console.log('\nšŸ” Complex/Edge case licenses detected:'); + complexLicenses.forEach(dep => { + console.log(` ${dep.name}@${dep.version}: "${dep.licenseType}"`); + }); + } + + // Check for potentially problematic licenses + const problematicLicenses = checkLicenseCompatibility(licenseSummary, licenseArray); + if (problematicLicenses.length > 0) { + console.log('\nāš ļø License compatibility warnings:'); + problematicLicenses.forEach(warning => { + console.log(` ${warning.message}`); + }); + + // Write license warnings to a separate file for CI/CD + const warningsFile = path.join(__dirname, '..', 'src', 'assets', 'license-warnings.json'); + fs.writeFileSync(warningsFile, JSON.stringify({ + warnings: problematicLicenses, + generated: new Date().toISOString() + }, null, 2)); + console.log(`āš ļø License warnings saved to: ${warningsFile}`); + } else { + console.log('\nāœ… All licenses appear to be corporate-friendly'); + } + + // Write to file + fs.writeFileSync(OUTPUT_FILE, JSON.stringify(transformedData, null, 4)); + + console.log(`āœ… License report generated successfully!`); + console.log(`šŸ“„ Found ${transformedData.dependencies.length} dependencies`); + console.log(`šŸ’¾ Saved to: ${OUTPUT_FILE}`); + +} catch (error) { + console.error('āŒ Error generating license report:', error.message); + process.exit(1); +} + +/** + * Get standard license URLs for common licenses + */ +function getLicenseUrl(licenseType) { + if (!licenseType || licenseType === 'Unknown') return ''; + + const licenseUrls = { + 'MIT': 'https://opensource.org/licenses/MIT', + 'Apache-2.0': 'https://www.apache.org/licenses/LICENSE-2.0', + 'Apache License 2.0': 'https://www.apache.org/licenses/LICENSE-2.0', + 'BSD-3-Clause': 'https://opensource.org/licenses/BSD-3-Clause', + 'BSD-2-Clause': 'https://opensource.org/licenses/BSD-2-Clause', + 'BSD': 'https://opensource.org/licenses/BSD-3-Clause', + 'GPL-3.0': 'https://www.gnu.org/licenses/gpl-3.0.html', + 'GPL-2.0': 'https://www.gnu.org/licenses/gpl-2.0.html', + 'LGPL-2.1': 'https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html', + 'LGPL-3.0': 'https://www.gnu.org/licenses/lgpl-3.0.html', + 'ISC': 'https://opensource.org/licenses/ISC', + 'CC0-1.0': 'https://creativecommons.org/publicdomain/zero/1.0/', + 'Unlicense': 'https://unlicense.org/', + 'MPL-2.0': 'https://www.mozilla.org/en-US/MPL/2.0/', + 'WTFPL': 'http://www.wtfpl.net/', + 'Zlib': 'https://opensource.org/licenses/Zlib', + 'Artistic-2.0': 'https://opensource.org/licenses/Artistic-2.0', + 'EPL-1.0': 'https://www.eclipse.org/legal/epl-v10.html', + 'EPL-2.0': 'https://www.eclipse.org/legal/epl-2.0/', + 'CDDL-1.0': 'https://opensource.org/licenses/CDDL-1.0', + 'Ruby': 'https://www.ruby-lang.org/en/about/license.txt', + 'Python-2.0': 'https://www.python.org/download/releases/2.0/license/', + 'Public Domain': 'https://creativecommons.org/publicdomain/zero/1.0/', + 'UNLICENSED': '' + }; + + // Try exact match first + if (licenseUrls[licenseType]) { + return licenseUrls[licenseType]; + } + + // Try case-insensitive match + const lowerType = licenseType.toLowerCase(); + for (const [key, url] of Object.entries(licenseUrls)) { + if (key.toLowerCase() === lowerType) { + return url; + } + } + + // Handle complex SPDX expressions like "(MIT AND Zlib)" or "(MIT OR CC0-1.0)" + if (licenseType.includes('AND') || licenseType.includes('OR')) { + // Extract the first license from compound expressions for URL + const match = licenseType.match(/\(?\s*([A-Za-z0-9\-\.]+)/); + if (match && licenseUrls[match[1]]) { + return licenseUrls[match[1]]; + } + } + + // For non-standard licenses, return empty string (will use package link if available) + return ''; +} + +/** + * Check for potentially problematic licenses that may not be MIT/corporate compatible + */ +function checkLicenseCompatibility(licenseSummary, licenseArray) { + const warnings = []; + + // Define problematic license patterns + const problematicLicenses = { + // Copyleft licenses + 'GPL-2.0': 'Strong copyleft license - requires derivative works to be GPL', + 'GPL-3.0': 'Strong copyleft license - requires derivative works to be GPL', + 'LGPL-2.1': 'Weak copyleft license - may require source disclosure for modifications', + 'LGPL-3.0': 'Weak copyleft license - may require source disclosure for modifications', + 'AGPL-3.0': 'Network copyleft license - requires source disclosure for network use', + 'AGPL-1.0': 'Network copyleft license - requires source disclosure for network use', + + // Other potentially problematic licenses + 'WTFPL': 'Potentially problematic license - legal uncertainty', + 'CC-BY-SA-4.0': 'ShareAlike license - requires derivative works to use same license', + 'CC-BY-SA-3.0': 'ShareAlike license - requires derivative works to use same license', + 'CC-BY-NC-4.0': 'Non-commercial license - prohibits commercial use', + 'CC-BY-NC-3.0': 'Non-commercial license - prohibits commercial use', + 'OSL-3.0': 'Copyleft license - requires derivative works to be OSL', + 'EPL-1.0': 'Weak copyleft license - may require source disclosure', + 'EPL-2.0': 'Weak copyleft license - may require source disclosure', + 'CDDL-1.0': 'Weak copyleft license - may require source disclosure', + 'CDDL-1.1': 'Weak copyleft license - may require source disclosure', + 'CPL-1.0': 'Weak copyleft license - may require source disclosure', + 'MPL-1.1': 'Weak copyleft license - may require source disclosure', + 'EUPL-1.1': 'Copyleft license - requires derivative works to be EUPL', + 'EUPL-1.2': 'Copyleft license - requires derivative works to be EUPL', + 'UNLICENSED': 'No license specified - usage rights unclear', + 'Unknown': 'License not detected - manual review required' + }; + + // Known good licenses (no warnings needed) + const goodLicenses = new Set([ + 'MIT', 'Apache-2.0', 'Apache License 2.0', 'BSD-2-Clause', 'BSD-3-Clause', 'BSD', + 'ISC', 'CC0-1.0', 'Public Domain', 'Unlicense', '0BSD', 'BlueOak-1.0.0', + 'Zlib', 'Artistic-2.0', 'Python-2.0', 'Ruby', 'MPL-2.0', 'CC-BY-4.0', + 'SEE LICENSE IN https://raw.githubusercontent.com/Stirling-Tools/Stirling-PDF/refs/heads/main/proprietary/LICENSE' + ]); + + // Helper function to normalize license names for comparison + function normalizeLicense(license) { + return license + .replace(/-or-later$/, '') // Remove -or-later suffix + .replace(/\+$/, '') // Remove + suffix + .trim(); + } + + // Check each license type + Object.entries(licenseSummary).forEach(([license, count]) => { + // Skip known good licenses + if (goodLicenses.has(license)) { + return; + } + + // Check if this license only affects our own packages + const affectedPackages = licenseArray.filter(dep => { + const depLicense = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : dep.licenseType; + return depLicense === license; + }); + + const isOnlyOurPackages = affectedPackages.every(dep => + dep.name === 'frontend' || + dep.name.toLowerCase().includes('stirling-pdf') || + dep.name.toLowerCase().includes('stirling_pdf') || + dep.name.toLowerCase().includes('stirlingpdf') + ); + + if (isOnlyOurPackages && (license === 'UNLICENSED' || license.startsWith('SEE LICENSE IN'))) { + return; // Skip warnings for our own Stirling-PDF packages + } + + // Check for compound licenses like "(MIT AND Zlib)" or "(MIT OR CC0-1.0)" + if (license.includes('AND') || license.includes('OR')) { + // For OR licenses, check if there's at least one acceptable license option + if (license.includes('OR')) { + // Extract license components from OR expression + const orComponents = license + .replace(/[()]/g, '') // Remove parentheses + .split(' OR ') + .map(component => component.trim()); + + // Check if any component is in the goodLicenses set (with normalization) + const hasGoodLicense = orComponents.some(component => { + const normalized = normalizeLicense(component); + return goodLicenses.has(component) || goodLicenses.has(normalized); + }); + + if (hasGoodLicense) { + return; // Skip warning - can use the good license option + } + } + + // For AND licenses or OR licenses with no good options, check for problematic components + const hasProblematicComponent = Object.keys(problematicLicenses).some(problematic => + license.includes(problematic) + ); + + if (hasProblematicComponent) { + const affectedPackages = licenseArray + .filter(dep => { + const depLicense = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : dep.licenseType; + return depLicense === license; + }) + .map(dep => ({ + name: dep.name, + version: dep.version, + url: dep.repository || dep.url || `https://www.npmjs.com/package/${dep.name}` + })); + + const licenseType = license.includes('AND') ? 'AND' : 'OR'; + const reason = licenseType === 'AND' + ? 'Compound license with AND requirement - all components must be compatible' + : 'Compound license with potentially problematic components and no good fallback options'; + + warnings.push({ + message: `šŸ“‹ This PR contains ${count} package${count > 1 ? 's' : ''} with compound license "${license}" - manual review recommended`, + licenseType: license, + licenseUrl: '', + reason: reason, + packageCount: count, + affectedDependencies: affectedPackages + }); + } + return; + } + + // Check for exact matches with problematic licenses + if (problematicLicenses[license]) { + const affectedPackages = licenseArray + .filter(dep => { + const depLicense = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : dep.licenseType; + return depLicense === license; + }) + .map(dep => ({ + name: dep.name, + version: dep.version, + url: dep.repository || dep.url || `https://www.npmjs.com/package/${dep.name}` + })); + + const packageList = affectedPackages.map(pkg => pkg.name).slice(0, 5).join(', ') + (affectedPackages.length > 5 ? `, and ${affectedPackages.length - 5} more` : ''); + const licenseUrl = getLicenseUrl(license) || 'https://opensource.org/licenses'; + + warnings.push({ + message: `āš ļø This PR contains ${count} package${count > 1 ? 's' : ''} with license type [${license}](${licenseUrl}) - ${problematicLicenses[license]}. Affected packages: ${packageList}`, + licenseType: license, + licenseUrl: licenseUrl, + reason: problematicLicenses[license], + packageCount: count, + affectedDependencies: affectedPackages + }); + } else { + // Unknown license type - flag for manual review + const affectedPackages = licenseArray + .filter(dep => { + const depLicense = Array.isArray(dep.licenseType) ? dep.licenseType.join(', ') : dep.licenseType; + return depLicense === license; + }) + .map(dep => ({ + name: dep.name, + version: dep.version, + url: dep.repository || dep.url || `https://www.npmjs.com/package/${dep.name}` + })); + + warnings.push({ + message: `ā“ This PR contains ${count} package${count > 1 ? 's' : ''} with unknown license type "${license}" - manual review required`, + licenseType: license, + licenseUrl: '', + reason: 'Unknown license type', + packageCount: count, + affectedDependencies: affectedPackages + }); + } + }); + + return warnings; +} \ No newline at end of file diff --git a/frontend/src/components/pageEditor/PageEditor.tsx b/frontend/src/components/pageEditor/PageEditor.tsx index f1a5dfd3c..4ba56a291 100644 --- a/frontend/src/components/pageEditor/PageEditor.tsx +++ b/frontend/src/components/pageEditor/PageEditor.tsx @@ -21,7 +21,7 @@ import { pdfExportService } from "../../services/pdfExportService"; import { useThumbnailGeneration } from "../../hooks/useThumbnailGeneration"; import { calculateScaleFromFileSize } from "../../utils/thumbnailUtils"; import { fileStorage } from "../../services/fileStorage"; -import './pageEditor.module.css'; +import './PageEditor.module.css'; import PageThumbnail from './PageThumbnail'; import BulkSelectionPanel from './BulkSelectionPanel'; import DragDropGrid from './DragDropGrid'; diff --git a/scripts/init-without-ocr.sh b/scripts/init-without-ocr.sh index 73d9feb4a..bbc1a32ec 100644 --- a/scripts/init-without-ocr.sh +++ b/scripts/init-without-ocr.sh @@ -19,9 +19,8 @@ if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" && "$FAT_DOCKER" != "true" #apk add --no-cache calibre@testing fi -if [[ "$FAT_DOCKER" != "true" ]]; then - /scripts/download-security-jar.sh -fi +# Security jar is now built into the application jar during Docker build +# No need to download it separately if [[ -n "$LANGS" ]]; then /scripts/installFonts.sh $LANGS diff --git a/testing/compose/docker-compose-security-with-login.yml b/testing/compose/docker-compose-security-with-login.yml new file mode 100644 index 000000000..feb91b080 --- /dev/null +++ b/testing/compose/docker-compose-security-with-login.yml @@ -0,0 +1,63 @@ +services: + backend: + build: + context: ../.. + dockerfile: docker/backend/Dockerfile + container_name: Stirling-PDF-Security-with-login + restart: on-failure:5 + deploy: + resources: + limits: + memory: 4G + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP'"] + interval: 5s + timeout: 10s + retries: 16 + ports: + - "8080:8080" + volumes: + - ../../stirling/latest/data:/usr/share/tessdata:rw + - ../../stirling/latest/config:/configs:rw + - ../../stirling/latest/logs:/logs:rw + environment: + DISABLE_ADDITIONAL_FEATURES: "false" + DOCKER_ENABLE_SECURITY: "true" + SECURITY_ENABLELOGIN: "true" + SECURITY_INITIALLOGIN_USERNAME: "admin" + SECURITY_INITIALLOGIN_PASSWORD: "stirling" + SYSTEM_DEFAULTLOCALE: en-US + UI_APPNAME: Stirling-PDF + UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security and Login + UI_APPNAMENAVBAR: Stirling-PDF Latest + SYSTEM_MAXFILESIZE: "100" + METRICS_ENABLED: "true" + SYSTEM_GOOGLEVISIBILITY: "true" + SECURITY_CUSTOMGLOBALAPIKEY: "123456789" + SHOW_SURVEY: "true" + networks: + - stirling-network + + frontend: + build: + context: ../.. + dockerfile: docker/frontend/Dockerfile + container_name: stirling-pdf-frontend-security-login + restart: on-failure:5 + ports: + - "3000:80" + environment: + BACKEND_URL: http://backend:8080 + depends_on: + - backend + networks: + - stirling-network + +networks: + stirling-network: + driver: bridge + +volumes: + stirling-data: + stirling-config: + stirling-logs: \ No newline at end of file diff --git a/testing/compose/docker-compose-security.yml b/testing/compose/docker-compose-security.yml new file mode 100644 index 000000000..14aedb697 --- /dev/null +++ b/testing/compose/docker-compose-security.yml @@ -0,0 +1,59 @@ +services: + backend: + build: + context: ../.. + dockerfile: docker/backend/Dockerfile + container_name: Stirling-PDF-Security + restart: on-failure:5 + deploy: + resources: + limits: + memory: 4G + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP'"] + interval: 5s + timeout: 10s + retries: 16 + ports: + - "8080:8080" + volumes: + - ../../stirling/latest/data:/usr/share/tessdata:rw + - ../../stirling/latest/config:/configs:rw + - ../../stirling/latest/logs:/logs:rw + environment: + DISABLE_ADDITIONAL_FEATURES: "false" + SECURITY_ENABLELOGIN: "false" + SYSTEM_DEFAULTLOCALE: en-US + UI_APPNAME: Stirling-PDF + UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security + UI_APPNAMENAVBAR: Stirling-PDF Latest + SYSTEM_MAXFILESIZE: "100" + METRICS_ENABLED: "true" + SYSTEM_GOOGLEVISIBILITY: "true" + SHOW_SURVEY: "true" + networks: + - stirling-network + + frontend: + build: + context: ../.. + dockerfile: docker/frontend/Dockerfile + container_name: stirling-pdf-frontend-security + restart: on-failure:5 + ports: + - "3000:80" + environment: + BACKEND_URL: http://backend:8080 + depends_on: + - backend + networks: + - stirling-network + +networks: + stirling-network: + driver: bridge + +volumes: + stirling-data: + stirling-config: + stirling-logs: \ No newline at end of file diff --git a/exampleYmlFiles/docker-compose-latest-ultra-lite.yml b/testing/compose/docker-compose-ultra-lite.yml similarity index 50% rename from exampleYmlFiles/docker-compose-latest-ultra-lite.yml rename to testing/compose/docker-compose-ultra-lite.yml index a3710ad82..2ea9464a6 100644 --- a/exampleYmlFiles/docker-compose-latest-ultra-lite.yml +++ b/testing/compose/docker-compose-ultra-lite.yml @@ -1,11 +1,14 @@ services: - stirling-pdf: + backend: + build: + context: ../.. + dockerfile: docker/backend/Dockerfile.ultra-lite container_name: Stirling-PDF-Ultra-Lite - image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest-ultra-lite + restart: on-failure:5 deploy: resources: limits: - memory: 1G + memory: 2G healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -qv 'Please sign in'"] interval: 5s @@ -14,10 +17,12 @@ services: ports: - "8080:8080" volumes: - - ./stirling/latest/config:/configs:rw - - ./stirling/latest/logs:/logs:rw + - ../../stirling/latest/config:/configs:rw + - ../../stirling/latest/logs:/logs:rw environment: + DISABLE_ADDITIONAL_FEATURES: "true" SECURITY_ENABLELOGIN: "false" + ENDPOINTS_GROUPS_TO_REMOVE: "CLI" SYSTEM_DEFAULTLOCALE: en-US UI_APPNAME: Stirling-PDF-Ultra-lite UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Ultra-lite Latest @@ -26,4 +31,29 @@ services: METRICS_ENABLED: "true" SYSTEM_GOOGLEVISIBILITY: "true" SHOW_SURVEY: "true" + networks: + - stirling-network + + frontend: + build: + context: ../.. + dockerfile: docker/frontend/Dockerfile + container_name: stirling-pdf-frontend-ultra-lite restart: on-failure:5 + ports: + - "3000:80" + environment: + BACKEND_URL: http://backend:8080 + depends_on: + - backend + networks: + - stirling-network + +networks: + stirling-network: + driver: bridge + +volumes: + stirling-data: + stirling-config: + stirling-logs: \ No newline at end of file diff --git a/testing/test.sh b/testing/test.sh index d4adce375..0876893de 100644 --- a/testing/test.sh +++ b/testing/test.sh @@ -225,8 +225,8 @@ test_compose() { echo "Testing $compose_file configuration..." - # Start up the Docker Compose service - docker-compose -f "$compose_file" up -d + # Start up the Docker Compose service with forced rebuild + docker-compose -f "$compose_file" up -d --build # Wait for the service to become healthy if check_health "$service_name" "$compose_file"; then @@ -276,22 +276,27 @@ main() { EXPECTED_VERSION=$(get_expected_version) echo "Expected version: $EXPECTED_VERSION" - # Building Docker images - # docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest -f ./Dockerfile . - docker build --build-arg VERSION_TAG=alpha -t docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest-ultra-lite -f ./Dockerfile.ultra-lite . - # Test each configuration - run_tests "Stirling-PDF-Ultra-Lite" "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml" + run_tests "Stirling-PDF-Ultra-Lite" "./testing/compose/docker-compose-ultra-lite.yml" - echo "Testing webpage accessibility..." - cd "testing" - if ./test_webpages.sh -f webpage_urls.txt -b http://localhost:8080; then - passed_tests+=("Webpage-Accessibility-lite") + echo "Testing basic frontend homepage accessibility..." + if curl -f http://localhost:3000 > /dev/null 2>&1; then + passed_tests+=("Frontend-Homepage-Accessibility-lite") + echo "Frontend homepage accessibility check passed" else - failed_tests+=("Webpage-Accessibility-lite") - echo "Webpage accessibility lite tests failed" + failed_tests+=("Frontend-Homepage-Accessibility-lite") + echo "Frontend homepage accessibility check failed" fi - cd "$PROJECT_ROOT" + + # echo "Testing webpage accessibility..." + # cd "testing" + # if ./test_webpages.sh -f webpage_urls.txt -b http://localhost:8080; then + # passed_tests+=("Webpage-Accessibility-lite") + # else + # failed_tests+=("Webpage-Accessibility-lite") + # echo "Webpage accessibility lite tests failed" + # fi + # cd "$PROJECT_ROOT" echo "Testing version verification..." if verify_app_version "Stirling-PDF-Ultra-Lite" "http://localhost:8080"; then @@ -302,10 +307,11 @@ main() { echo "Version verification failed for Stirling-PDF-Ultra-Lite" fi - docker-compose -f "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml" down - - # run_tests "Stirling-PDF" "./exampleYmlFiles/docker-compose-latest.yml" - # docker-compose -f "./exampleYmlFiles/docker-compose-latest.yml" down + docker-compose -f "./testing/compose/docker-compose-ultra-lite.yml" down + + # Clean up any generated config files + echo "Cleaning up generated config files..." + rm -rf "$PROJECT_ROOT/stirling/" 2>/dev/null || true export DISABLE_ADDITIONAL_FEATURES=false # Run the gradlew build command and check if it fails @@ -319,43 +325,44 @@ main() { EXPECTED_VERSION=$(get_expected_version) echo "Expected version with security enabled: $EXPECTED_VERSION" - # Building Docker images with security enabled - # docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest -f ./Dockerfile . - # docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t stirlingtools/stirling-pdf:latest-ultra-lite -f ./Dockerfile.ultra-lite . - docker build --no-cache --pull --build-arg VERSION_TAG=alpha -t docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest-fat -f ./Dockerfile.fat . - - # Test each configuration with security - # run_tests "Stirling-PDF-Ultra-Lite-Security" "./exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml" - # docker-compose -f "./exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml" down - # run_tests "Stirling-PDF-Security" "./exampleYmlFiles/docker-compose-latest-security.yml" - # docker-compose -f "./exampleYmlFiles/docker-compose-latest-security.yml" down + run_tests "Stirling-PDF-Security" "./testing/compose/docker-compose-security.yml" - - run_tests "Stirling-PDF-Security-Fat" "./exampleYmlFiles/docker-compose-latest-fat-security.yml" - - echo "Testing webpage accessibility..." - cd "testing" - if ./test_webpages.sh -f webpage_urls_full.txt -b http://localhost:8080; then - passed_tests+=("Webpage-Accessibility-full") + echo "Testing basic frontend homepage accessibility..." + if curl -f http://localhost:3000 > /dev/null 2>&1; then + passed_tests+=("Frontend-Homepage-Accessibility-full") + echo "Frontend homepage accessibility check passed" else - failed_tests+=("Webpage-Accessibility-full") - echo "Webpage accessibility full tests failed" + failed_tests+=("Frontend-Homepage-Accessibility-full") + echo "Frontend homepage accessibility check failed" fi - cd "$PROJECT_ROOT" + + # echo "Testing webpage accessibility..." + # cd "testing" + # if ./test_webpages.sh -f webpage_urls_full.txt -b http://localhost:8080; then + # passed_tests+=("Webpage-Accessibility-full") + # else + # failed_tests+=("Webpage-Accessibility-full") + # echo "Webpage accessibility full tests failed" + # fi + # cd "$PROJECT_ROOT" echo "Testing version verification..." - if verify_app_version "Stirling-PDF-Security-Fat" "http://localhost:8080"; then - passed_tests+=("Stirling-PDF-Security-Fat-Version-Check") - echo "Version verification passed for Stirling-PDF-Security-Fat" + if verify_app_version "Stirling-PDF-Security" "http://localhost:8080"; then + passed_tests+=("Stirling-PDF-Security-Version-Check") + echo "Version verification passed for Stirling-PDF-Security" else - failed_tests+=("Stirling-PDF-Security-Fat-Version-Check") - echo "Version verification failed for Stirling-PDF-Security-Fat" + failed_tests+=("Stirling-PDF-Security-Version-Check") + echo "Version verification failed for Stirling-PDF-Security" fi - docker-compose -f "./exampleYmlFiles/docker-compose-latest-fat-security.yml" down + docker-compose -f "./testing/compose/docker-compose-security.yml" down + + # Clean up any generated config files + echo "Cleaning up generated config files..." + rm -rf "$PROJECT_ROOT/stirling/" 2>/dev/null || true - run_tests "Stirling-PDF-Security-Fat-with-login" "./exampleYmlFiles/test_cicd.yml" + run_tests "Stirling-PDF-Security-with-login" "./testing/compose/docker-compose-security-with-login.yml" if [ $? -eq 0 ]; then # Create directory for file snapshots if it doesn't exist @@ -368,7 +375,7 @@ main() { DIFF_FILE="$SNAPSHOT_DIR/files_diff.txt" # Define container name variable for consistency - CONTAINER_NAME="Stirling-PDF-Security-Fat-with-login" + CONTAINER_NAME="Stirling-PDF-Security-with-login" capture_file_list "$CONTAINER_NAME" "$BEFORE_FILE" @@ -409,28 +416,12 @@ main() { fi fi - docker-compose -f "./exampleYmlFiles/test_cicd.yml" down + docker-compose -f "./testing/compose/docker-compose-security-with-login.yml" down + + # Clean up any generated config files + echo "Cleaning up generated config files..." + rm -rf "$PROJECT_ROOT/stirling/" 2>/dev/null || true - run_tests "Stirling-PDF-Fat-Disable-Endpoints" "./exampleYmlFiles/docker-compose-latest-fat-endpoints-disabled.yml" - - echo "Testing disabled endpoints..." - if ./testing/test_disabledEndpoints.sh -f ./testing/endpoints.txt -b http://localhost:8080; then - passed_tests+=("Disabled-Endpoints") - else - failed_tests+=("Disabled-Endpoints") - echo "Disabled Endpoints tests failed" - fi - - echo "Testing version verification..." - if verify_app_version "Stirling-PDF-Fat-Disable-Endpoints" "http://localhost:8080"; then - passed_tests+=("Stirling-PDF-Fat-Disable-Endpoints-Version-Check") - echo "Version verification passed for Stirling-PDF-Fat-Disable-Endpoints" - else - failed_tests+=("Stirling-PDF-Fat-Disable-Endpoints-Version-Check") - echo "Version verification failed for Stirling-PDF-Fat-Disable-Endpoints" - fi - - docker-compose -f "./exampleYmlFiles/docker-compose-latest-fat-endpoints-disabled.yml" down # Report results echo "All tests completed in $SECONDS seconds." diff --git a/testing/test2.sh b/testing/test2.sh index b33d2df8c..c8376d288 100644 --- a/testing/test2.sh +++ b/testing/test2.sh @@ -51,29 +51,33 @@ build_and_test() { local dockerfile_name="./Dockerfile" local image_base="stirlingtools/stirling-pdf" local security_suffix="" - local docker_compose_base="./exampleYmlFiles/docker-compose-latest" + local docker_compose_base="./testing/compose/docker-compose" local compose_suffix=".yml" local service_name_base="Stirling-PDF" - if [ "$enable_security" == "true" ]; then - security_suffix="-Security" - docker_compose_base+="-security" # Append to base name for Docker Compose files with security - fi - case "$build_type" in full) - dockerfile_name="./Dockerfile" + dockerfile_name="./docker/backend/Dockerfile" + if [ "$enable_security" == "true" ]; then + compose_file="${docker_compose_base}-fat-security${compose_suffix}" + service_name="Stirling-PDF-Security-Fat" + else + compose_file="${docker_compose_base}-fat${compose_suffix}" + service_name="stirling-pdf-backend-fat" + fi ;; ultra-lite) - dockerfile_name="./Dockerfile.ultra-lite" + dockerfile_name="./docker/backend/Dockerfile.ultra-lite" + if [ "$enable_security" == "true" ]; then + compose_file="${docker_compose_base}-ultra-lite-security${compose_suffix}" + service_name="stirling-pdf-backend-ultra-lite-security" + else + compose_file="${docker_compose_base}-ultra-lite${compose_suffix}" + service_name="Stirling-PDF-Ultra-Lite" + fi ;; esac - # Dynamic image tag and service name based on build type and security - local image_tag="${image_base}:latest${build_type}${security_suffix}" - local service_name="${service_name_base}${build_type^}${security_suffix}" - local compose_file="${docker_compose_base}${build_type}${compose_suffix}" - # Gradle build with or without security echo "Running ./gradlew clean build with security=$enable_security..." ./gradlew clean build @@ -83,10 +87,6 @@ build_and_test() { exit 1 fi - # Building Docker image - echo "Building Docker image $image_tag with Dockerfile $dockerfile_name..." - docker build --build-arg VERSION_TAG=$version_tag -t $image_tag -f $dockerfile_name . - if [ "$run_compose" == "true" ]; then echo "Running Docker Compose for $build_type with security=$enable_security..." docker-compose -f "$compose_file" up -d