empty commit #21
Workflow file for this run
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: Deploy Preview | |
on: | |
pull_request: | |
branches: [ master ] | |
types: [opened, synchronize, reopened] | |
permissions: | |
contents: read | |
packages: read | |
pull-requests: write | |
deployments: write | |
id-token: write | |
concurrency: | |
group: preview-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.ref }} | |
cancel-in-progress: true | |
env: | |
NODE_ENV: development | |
HUSKY: 0 | |
jobs: | |
security-check: | |
name: Security Check | |
runs-on: ubuntu-latest | |
timeout-minutes: 5 | |
permissions: | |
pull-requests: read | |
outputs: | |
is-fork: ${{ steps.check.outputs.is-fork }} | |
is-authorized: ${{ steps.check.outputs.is-authorized }} | |
steps: | |
- name: Check PR source and permissions | |
id: check | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const pr = context.payload.pull_request; | |
const isFork = pr.head.repo.full_name !== pr.base.repo.full_name; | |
let isAuthorized = false; | |
try { | |
const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
username: pr.user.login | |
}); | |
isAuthorized = ['admin', 'write'].includes(permission.permission); | |
} catch (e) { | |
console.error('Error checking permissions:', e); | |
isAuthorized = false; | |
} | |
core.setOutput('is-fork', isFork.toString()); | |
core.setOutput('is-authorized', isAuthorized.toString()); | |
if (isFork && !isAuthorized) { | |
core.notice('⚠️ This PR is from a fork and requires approval from maintainers'); | |
} | |
preview: | |
name: Deploy Preview | |
needs: security-check | |
runs-on: ubuntu-latest | |
if: | | |
github.event.workflow_run.conclusion != 'action_required' || | |
github.event.workflow_run.conclusion == 'approved' | |
environment: | |
name: preview | |
url: ${{ steps.deploy.outputs.deployment-url }} | |
permissions: | |
deployments: write | |
issues: write | |
pull-requests: write | |
contents: read | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
with: | |
ref: ${{ github.event.pull_request.head.sha }} | |
fetch-depth: 0 | |
- name: Additional security checks for forks | |
id: security_checks | |
if: needs.security-check.outputs.is-fork == 'true' | |
run: | | |
# Function to check file patterns | |
check_patterns() { | |
local file="$1" | |
local patterns=( | |
"crypto\." | |
"eval[\s]*\(" | |
"child_process" | |
"exec[A-Z][a-z]*\(" | |
"http[s]?\." | |
"net\." | |
"process\.env" | |
"require\(['\"]child_process" | |
"fs\." | |
"new\s+Function" | |
"__proto__" | |
"Function\(" | |
"require\(['\"]\.\." | |
"require\(['\"]~" | |
"process\.binding" | |
"v8\." | |
"vm\." | |
"\.constructor\." | |
"Object\.prototype" | |
"Object\.defineProperty" | |
"Object\.setPrototypeOf" | |
) | |
for pattern in "${patterns[@]}"; do | |
if grep -q "$pattern" "$file"; then | |
echo "⚠️ Suspicious pattern found in $file: $pattern" | |
return 1 | |
fi | |
done | |
return 0 | |
} | |
exit_code=0 | |
while IFS= read -r file; do | |
if [ -f "$file" ]; then | |
if file "$file" | grep -q "binary"; then | |
echo "❌ Binary file detected: $file" | |
exit_code=1 | |
fi | |
if ! file "$file" | grep -q "binary"; then | |
if ! check_patterns "$file"; then | |
exit_code=1 | |
fi | |
fi | |
fi | |
done < <(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}) | |
if [ $exit_code -eq 0 ]; then | |
echo "SECURITY_CHECK_RESULT=✅ All security checks passed" >> $GITHUB_ENV | |
else | |
echo "SECURITY_CHECK_RESULT=⚠️ Security review required - See above for details" >> $GITHUB_ENV | |
exit 1 | |
fi | |
- name: Setup environment | |
uses: ./.github/actions/setup-environment | |
- name: Deploy to Vercel | |
id: deploy | |
timeout-minutes: 10 | |
uses: ./.github/actions/deploy/vercel/development | |
env: | |
# Pass all repository secrets to the action | |
REACT_APP_WS_PORT: ${{ secrets.REACT_APP_WS_PORT }} | |
REACT_APP_WS_URL: ${{ secrets.REACT_APP_WS_URL }} | |
REACT_OAUTH_URL: ${{ secrets.REACT_OAUTH_URL }} | |
REACT_CURRENT_ENVIRONMENT: preview | |
with: | |
vercel-token: ${{ secrets.VERCEL_TOKEN }} | |
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} | |
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} | |
pr-number: ${{ github.event.pull_request.number }} | |
- name: Add preview URL to pull request | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const isFork = '${{ needs.security-check.outputs.is-fork }}' === 'true'; | |
const isAuthorized = '${{ needs.security-check.outputs.is-authorized }}' === 'true'; | |
let securityStatus = ''; | |
if (isFork) { | |
securityStatus = `\n\n🔒 Security Status: | |
- PR is from a fork repository | |
- Author permission level: ${isAuthorized ? '✅ Authorized' : '⚠️ Requires Approval'} | |
- Security checks: ${process.env.SECURITY_CHECK_RESULT || '✅ Passed'} | |
Note: First-time contributors require maintainer approval for workflow runs.`; | |
} | |
const deploymentUrl = '${{ steps.deploy.outputs.deployment-url }}'; | |
const comment = `✨ Preview deployment is ready! | |
🔗 Preview URL: ${deploymentUrl} | |
📝 Commit: ${context.sha.substring(0, 7)} | |
🕒 Deployed at: ${new Date().toISOString()}${securityStatus}`; | |
await github.rest.issues.createComment({ | |
issue_number: context.issue.number, | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
body: comment | |
}); | |
- name: Update deployment status | |
uses: ./.github/actions/deployment-status | |
if: success() | |
with: | |
environment: 'preview' | |
deployment-url: ${{ steps.deploy.outputs.deployment-url }} | |
sha: ${{ github.event.pull_request.head.sha }} | |
status: 'success' | |
description: '✨ Preview deployment completed' | |
- name: Handle deployment failure | |
if: failure() | |
uses: ./.github/actions/deployment-status | |
with: | |
environment: 'preview' | |
deployment-url: ${{ steps.deploy.outputs.deployment-url }} | |
sha: ${{ github.event.pull_request.head.sha }} | |
status: 'failure' | |
description: '❌ Preview deployment failed' |