Security fix: Server-Side Request Forgery #497
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: PR Deployment via Comment | |
on: | |
issue_comment: | |
types: [created] | |
jobs: | |
check-comment: | |
runs-on: ubuntu-latest | |
if: | | |
github.event.issue.pull_request && | |
( | |
contains(github.event.comment.body, 'prdeploy') || | |
contains(github.event.comment.body, 'deploypr') | |
) | |
&& | |
( | |
github.event.comment.user.login == 'frooodle' || | |
github.event.comment.user.login == 'sf298' || | |
github.event.comment.user.login == 'Ludy87' || | |
github.event.comment.user.login == 'LaserKaspar' || | |
github.event.comment.user.login == 'sbplat' || | |
github.event.comment.user.login == 'reecebrowne' | |
) | |
outputs: | |
pr_number: ${{ steps.get-pr.outputs.pr_number }} | |
pr_repository: ${{ steps.get-pr-info.outputs.repository }} | |
pr_ref: ${{ steps.get-pr-info.outputs.ref }} | |
steps: | |
- name: Harden Runner | |
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 | |
with: | |
egress-policy: audit | |
- name: Get PR data | |
id: get-pr | |
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
with: | |
script: | | |
const prNumber = context.payload.issue.number; | |
console.log(`PR Number: ${prNumber}`); | |
core.setOutput('pr_number', prNumber); | |
- name: Get PR repository and ref | |
id: get-pr-info | |
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
with: | |
script: | | |
const { owner, repo } = context.repo; | |
const prNumber = context.payload.issue.number; | |
const { data: pr } = await github.rest.pulls.get({ | |
owner, | |
repo, | |
pull_number: prNumber, | |
}); | |
// For forks, use the full repository name, for internal PRs use the current repo | |
const repository = pr.head.repo.fork ? pr.head.repo.full_name : `${owner}/${repo}`; | |
console.log(`PR Repository: ${repository}`); | |
console.log(`PR Branch: ${pr.head.ref}`); | |
core.setOutput('repository', repository); | |
core.setOutput('ref', pr.head.ref); | |
deploy-pr: | |
needs: check-comment | |
runs-on: ubuntu-latest | |
steps: | |
- name: Harden Runner | |
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 | |
with: | |
egress-policy: audit | |
- name: Checkout PR | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
with: | |
repository: ${{ needs.check-comment.outputs.pr_repository }} | |
ref: ${{ needs.check-comment.outputs.pr_ref }} | |
token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Set up JDK | |
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0 | |
with: | |
java-version: '17' | |
distribution: 'temurin' | |
- name: Run Gradle Command | |
run: ./gradlew clean build | |
env: | |
DOCKER_ENABLE_SECURITY: false | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0 | |
- name: Get version number | |
id: versionNumber | |
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT | |
- name: Login to Docker Hub | |
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 | |
with: | |
username: ${{ secrets.DOCKER_HUB_USERNAME }} | |
password: ${{ secrets.DOCKER_HUB_API }} | |
- name: Build and push PR-specific image | |
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0 | |
with: | |
context: . | |
file: ./Dockerfile | |
push: true | |
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ needs.check-comment.outputs.pr_number }} | |
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }} | |
platforms: linux/amd64 | |
- name: Set up SSH | |
run: | | |
mkdir -p ~/.ssh/ | |
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key | |
sudo chmod 600 ../private.key | |
- name: Deploy to VPS | |
run: | | |
# First create the docker-compose content locally | |
cat > docker-compose.yml << 'EOF' | |
version: '3.3' | |
services: | |
stirling-pdf: | |
container_name: stirling-pdf-pr-${{ needs.check-comment.outputs.pr_number }} | |
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ needs.check-comment.outputs.pr_number }} | |
ports: | |
- "${{ needs.check-comment.outputs.pr_number }}:8080" | |
volumes: | |
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/data:/usr/share/tessdata:rw | |
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/config:/configs:rw | |
- /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/logs:/logs:rw | |
environment: | |
DOCKER_ENABLE_SECURITY: "false" | |
SECURITY_ENABLELOGIN: "false" | |
SYSTEM_DEFAULTLOCALE: en-GB | |
UI_APPNAME: "Stirling-PDF PR#${{ needs.check-comment.outputs.pr_number }}" | |
UI_HOMEDESCRIPTION: "PR#${{ needs.check-comment.outputs.pr_number }} for Stirling-PDF Latest" | |
UI_APPNAMENAVBAR: "PR#${{ needs.check-comment.outputs.pr_number }}" | |
SYSTEM_MAXFILESIZE: "100" | |
METRICS_ENABLED: "true" | |
SYSTEM_GOOGLEVISIBILITY: "false" | |
restart: on-failure:5 | |
EOF | |
# Then copy the file and execute commands | |
scp -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null docker-compose.yml ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }}:/tmp/docker-compose.yml | |
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH' | |
# Create PR-specific directories | |
mkdir -p /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/{data,config,logs} | |
# Move docker-compose file to correct location | |
mv /tmp/docker-compose.yml /stirling/PR-${{ needs.check-comment.outputs.pr_number }}/docker-compose.yml | |
# Start or restart the container | |
cd /stirling/PR-${{ needs.check-comment.outputs.pr_number }} | |
docker-compose pull | |
docker-compose up -d | |
ENDSSH | |
- name: Post deployment URL to PR | |
if: success() | |
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
with: | |
script: | | |
const { GITHUB_REPOSITORY } = process.env; | |
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/'); | |
const prNumber = ${{ needs.check-comment.outputs.pr_number }}; | |
const deploymentUrl = `http://${{ secrets.VPS_HOST }}:${prNumber}`; | |
const commentBody = `## 🚀 PR Test Deployment\n\n` + | |
`Your PR has been deployed for testing!\n\n` + | |
`🔗 **Test URL:** [${deploymentUrl}](${deploymentUrl})\n\n` + | |
`This deployment will be automatically cleaned up when the PR is closed.\n\n`; | |
await github.rest.issues.createComment({ | |
owner: repoOwner, | |
repo: repoName, | |
issue_number: prNumber, | |
body: commentBody | |
}); |