Files
twenty/.github/workflows/ci-test-docker-compose.yaml
Félix Malfait fc6b136c2f fix: resolve GitHub Actions security vulnerabilities (#16174)
## 🔒 Security Fixes

This PR addresses security vulnerabilities identified by GitHub CodeQL
security scanning.

### Changes

#### 1. Fix Shell Command Injection (High Severity)
**File:** `.github/workflows/docs-i18n-pull.yaml`

**Issue:** Direct interpolation of `${{ github.head_ref }}` in shell
command was susceptible to command injection attacks.

**Fix:** Assign GitHub context variable to environment variable first:
```yaml
run: |
  git push origin "HEAD:$HEAD_REF"
env:
  HEAD_REF: ${{ github.head_ref }}
```

This prevents malicious input from being executed as shell commands.

#### 2. Add Missing Workflow Permissions (Medium Severity)
**File:** `.github/workflows/ci-test-docker-compose.yaml`

**Issue:** Workflow did not explicitly define GITHUB_TOKEN permissions,
running with overly broad defaults.

**Fix:** Added explicit minimal permissions:
```yaml
permissions:
  contents: read
```

This applies to all 3 jobs in the workflow:
- `changed-files-check`
- `test`
- `ci-test-docker-compose-status-check`

### Security Impact

-  Prevents potential shell injection attacks via pull request branch
names
-  Follows principle of least privilege for GitHub Actions tokens
-  Aligns with GitHub Actions security best practices
-  Resolves all CodeQL security alerts for these workflows

### References

- [GitHub Actions: Security hardening for GitHub
Actions](https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions)
- [GitHub Actions: Permissions for the
GITHUB_TOKEN](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token)
- Related attacks: 2025 Nx supply chain attack, 2024 ultralytics/actions
attack
2025-11-28 13:15:33 +01:00

99 lines
3.4 KiB
YAML

name: 'Test Docker Compose'
permissions:
contents: read
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
changed-files-check:
uses: ./.github/workflows/changed-files.yaml
with:
files: |
packages/twenty-docker/**
docker-compose.yml
test:
needs: changed-files-check
if: needs.changed-files-check.outputs.any_changed == 'true'
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run compose
run: |
echo "Patching docker-compose.yml..."
# change image to localbuild using yq
yq eval 'del(.services.server.image)' -i docker-compose.yml
yq eval '.services.server.build.context = "../../"' -i docker-compose.yml
yq eval '.services.server.build.dockerfile = "./packages/twenty-docker/twenty/Dockerfile"' -i docker-compose.yml
yq eval '.services.server.restart = "no"' -i docker-compose.yml
echo "Setting up .env file..."
cp .env.example .env
echo "Generating secrets..."
echo "" >> .env
echo "# === Randomly generated secrets ===" >>.env
echo "APP_SECRET=$(openssl rand -base64 32)" >>.env
echo "PGPASSWORD_SUPERUSER=$(openssl rand -hex 16)" >>.env
echo "Docker compose up..."
docker compose up -d || {
echo "Docker compose failed to start"
docker compose logs
exit 1
}
docker compose logs db server -f &
pid=$!
echo "Waiting for database to start..."
count=0
while [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-db-1) = "healthy" ]; do
sleep 1;
count=$((count+1));
if [ $(docker inspect --format='{{.State.Status}}' twenty-db-1) = "exited" ]; then
echo "Database exited"
docker compose logs db
exit 1
fi
if [ $count -gt 300 ]; then
echo "Failed to start database after 5 minutes"
docker compose logs db
exit 1
fi
echo "Still waiting for database... (${count}/60)"
done
echo "Waiting for server to start..."
count=0
while [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-server-1) = "healthy" ]; do
sleep 1;
count=$((count+1));
if [ $(docker inspect --format='{{.State.Status}}' twenty-server-1) = "exited" ]; then
echo "Server exited"
docker compose logs server
exit 1
fi
if [ $count -gt 300 ]; then
echo "Failed to start server after 5 minutes"
docker compose logs server
exit 1
fi
echo "Still waiting for server... (${count}/300s)"
done
working-directory: ./packages/twenty-docker/
ci-test-docker-compose-status-check:
if: always() && !cancelled()
timeout-minutes: 5
runs-on: ubuntu-latest
needs: [changed-files-check, test]
steps:
- name: Fail job if any needs failed
if: contains(needs.*.result, 'failure')
run: exit 1