Files
nhost/.github/workflows/ci.yaml
David Barroso 34ede5cf2c fix (dashboard): enable csp again (#3439)
### **PR Type**
Enhancement, Security


___

### **Description**
- Re-enable Content Security Policy (CSP) for production

- Disable CSP headers in development environment

- Improve security configuration in Next.js


___

### Diagram Walkthrough


```mermaid
flowchart LR
  A["Environment Check"] --> B{"Is Production?"}
  B -->|Yes| C["Apply CSP"]
  B -->|No| D["Skip CSP"]
  C --> E["Apply Other Security Headers"]
  D --> E
```



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Security</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>next.config.js</strong><dd><code>Conditional CSP
application based on environment</code>&nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

dashboard/next.config.js

<ul><li>Added environment check for CSP application<br> <li> Re-enabled
Content-Security-Policy header<br> <li> Removed commented-out CSP
code</ul>


</details>


  </td>
<td><a
href="https://github.com/nhost/nhost/pull/3439/files#diff-398ac9b04404f14166a89845539399764fecd520ad3e6f0119f8730c0eefa94a">+8/-4</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></td></tr></tr></tbody></table>

</details>

___
2025-08-25 09:50:45 +02:00

215 lines
9.3 KiB
YAML

name: Continuous Integration
on:
push:
branches: [main]
paths-ignore:
- 'assets/**'
- '**.md'
- 'LICENSE'
- 'docs/**'
pull_request:
types: [opened, synchronize]
paths-ignore:
- 'assets/**'
- '**.md'
- 'LICENSE'
- 'docs/**'
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: nhost
NEXT_PUBLIC_ENV: dev
NEXT_TELEMETRY_DISABLED: 1
NHOST_TEST_DASHBOARD_URL: ${{ vars.NHOST_TEST_DASHBOARD_URL }}
NHOST_TEST_PROJECT_NAME: ${{ vars.NHOST_TEST_PROJECT_NAME }}
NHOST_TEST_ORGANIZATION_NAME: ${{ vars.NHOST_TEST_ORGANIZATION_NAME }}
NHOST_TEST_ORGANIZATION_SLUG: ${{ vars.NHOST_TEST_ORGANIZATION_SLUG }}
NHOST_TEST_PERSONAL_ORG_SLUG: ${{ vars.NHOST_TEST_PERSONAL_ORG_SLUG }}
NHOST_TEST_PROJECT_SUBDOMAIN: ${{ vars.NHOST_TEST_PROJECT_SUBDOMAIN }}
NHOST_PRO_TEST_PROJECT_NAME: ${{ vars.NHOST_PRO_TEST_PROJECT_NAME }}
NHOST_TEST_USER_EMAIL: ${{ secrets.NHOST_TEST_USER_EMAIL }}
NHOST_TEST_USER_PASSWORD: ${{ secrets.NHOST_TEST_USER_PASSWORD }}
NHOST_TEST_PROJECT_ADMIN_SECRET: '${{ secrets.NHOST_TEST_PROJECT_ADMIN_SECRET }}'
NHOST_TEST_FREE_USER_EMAILS: ${{ secrets.NHOST_TEST_FREE_USER_EMAILS }}
jobs:
build:
name: Build @nhost packages
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
# * Install Node and dependencies. Package downloads will be cached for the next jobs.
- name: Install Node and dependencies
uses: ./.github/actions/install-dependencies
with:
TURBO_TOKEN: ${{ env.TURBO_TOKEN }}
TURBO_TEAM: ${{ env.TURBO_TEAM }}
BUILD: 'all'
- name: Check if the pnpm lockfile changed
id: changed-lockfile
uses: tj-actions/changed-files@v37
with:
files: pnpm-lock.yaml
# * Determine a pnpm filter argument for packages that have been modified.
# * If the lockfile has changed, we don't filter anything in order to run all the e2e tests.
- name: filter packages
id: filter-packages
if: steps.changed-lockfile.outputs.any_changed != 'true' && github.event_name == 'pull_request'
run: echo "filter=${{ format('--filter=...[origin/{0}]', github.base_ref) }}" >> $GITHUB_OUTPUT
# * List packagesthat has an `e2e` script, except the root, and return an array of their name and path
# * In a PR, only include packages that have been modified, and their dependencies
- name: List examples with an e2e script
id: set-matrix
run: |
PACKAGES=$(pnpm recursive list --depth -1 --parseable --filter='!nhost-root' ${{ steps.filter-packages.outputs.filter }} \
| xargs -I@ realpath --relative-to=$PWD @ \
| xargs -I@ jq "if (.scripts.e2e | length) != 0 then {name: .name, path: \"@\"} else null end" @/package.json \
| awk "!/null/" \
| jq -c --slurp 'map(select(length > 0))')
echo "matrix=$PACKAGES" >> $GITHUB_OUTPUT
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
unit:
name: Unit tests
needs: build
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v3
# * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job.
- name: Install Node and dependencies
uses: ./.github/actions/install-dependencies
with:
TURBO_TOKEN: ${{ env.TURBO_TOKEN }}
TURBO_TEAM: ${{ env.TURBO_TEAM }}
# * Run every `test` script in the workspace . Dependencies build is cached by Turborepo
- name: Run unit tests
run: pnpm run test:all
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: '**/coverage/coverage-final.json'
name: codecov-umbrella
- name: Create summary
run: |
echo '### Code coverage' >> $GITHUB_STEP_SUMMARY
echo 'Visit [codecov](https://app.codecov.io/gh/nhost/nhost/) to see the code coverage reports' >> $GITHUB_STEP_SUMMARY
lint:
name: Lint
needs: build
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v3
# * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job.
- name: Install Node and dependencies
uses: ./.github/actions/install-dependencies
with:
TURBO_TOKEN: ${{ env.TURBO_TOKEN }}
TURBO_TEAM: ${{ env.TURBO_TEAM }}
- name: Enforce Prettier formatting in dashboard
working-directory: ./dashboard
run: pnpm prettier --check "./**/*.tsx" --config prettier.config.js
# * Run every `lint` script in the workspace . Dependencies build is cached by Turborepo
- name: Lint
run: pnpm run lint:all
- name: Audit for vulnerabilities
run: pnpx audit-ci --config ./audit-ci.jsonc
e2e:
name: 'E2E (Package: ${{ matrix.package.path }})'
needs: build
if: ${{ needs.build.outputs.matrix != '[]' && needs.build.outputs.matrix != '' }}
strategy:
# * Don't cancel other matrices when one fails
fail-fast: false
matrix:
package: ${{ fromJson(needs.build.outputs.matrix) }}
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- uses: actions/checkout@v3
# * Install Node and dependencies. Package dependencies won't be downloaded again as they have been cached by the `build` job.
- name: Install Node and dependencies
uses: ./.github/actions/install-dependencies
with:
TURBO_TOKEN: ${{ env.TURBO_TOKEN }}
TURBO_TEAM: ${{ env.TURBO_TEAM }}
# * Build Dashboard image to test it locally
- name: Build Dashboard local image
if: matrix.package.path == 'dashboard'
run: |
docker build -t nhost/dashboard:0.0.0-dev -f ${{ matrix.package.path }}/Dockerfile .
mkdir -p nhost-test-project
# * Install Nhost CLI if a `nhost/config.yaml` file is found
- name: Install Nhost CLI
if: hashFiles(format('{0}/nhost/config.yaml', matrix.package.path)) != '' && matrix.package.path != 'dashboard'
uses: ./.github/actions/nhost-cli
# * Install Nhost CLI to test Dashboard locally
- name: Install Nhost CLI (Local Dashboard tests)
timeout-minutes: 5
if: matrix.package.path == 'dashboard'
uses: ./.github/actions/nhost-cli
with:
init: 'true' # Initialize the application
start: 'true' # Start the application
path: ./nhost-test-project
wait: 'true' # Wait until the application is ready
dashboard-image: 'nhost/dashboard:0.0.0-dev'
- name: Fetch Dashboard Preview URL
id: fetch-dashboard-preview-url
uses: zentered/vercel-preview-url@v1.1.9
if: github.ref_name != 'main'
env:
VERCEL_TOKEN: ${{ secrets.DASHBOARD_VERCEL_DEPLOY_TOKEN }}
GITHUB_REF: ${{ github.ref_name }}
GITHUB_REPOSITORY: ${{ github.repository }}
with:
vercel_team_id: ${{ secrets.DASHBOARD_VERCEL_TEAM_ID }}
vercel_project_id: ${{ secrets.DASHBOARD_STAGING_VERCEL_PROJECT_ID }}
vercel_state: BUILDING,READY,INITIALIZING
- name: Set Dashboard Preview URL
if: steps.fetch-dashboard-preview-url.outputs.preview_url != ''
run: echo "NHOST_TEST_DASHBOARD_URL=https://${{ steps.fetch-dashboard-preview-url.outputs.preview_url }}" >> $GITHUB_ENV
- name: Run Onboarding Dashboard e2e tests
if: matrix.package.path == 'dashboard'
timeout-minutes: 10
run: pnpm --filter="${{ matrix.package.name }}" run e2e:onboarding
# * Run the `ci` script of the current package of the matrix. Dependencies build is cached by Turborepo
- name: Run e2e tests
timeout-minutes: 20
run: pnpm --filter="${{ matrix.package.name }}" run e2e
# * Run the `e2e-local` script of the dashboard
- name: Run Local Dashboard e2e tests
if: matrix.package.path == 'dashboard'
timeout-minutes: 5
run: pnpm --filter="${{ matrix.package.name }}" run e2e:local
- name: Stop Nhost CLI
if: matrix.package.path == 'dashboard'
working-directory: ./nhost-test-project
run: nhost down
- name: Stop Nhost CLI for packages
if: always() && (matrix.package.path == 'packages/hasura-auth-js' || matrix.package.path == 'packages/hasura-storage-js')
working-directory: ./${{ matrix.package.path }}
run: nhost down
- name: Encrypt Playwright report
if: ${{ failure() && hashFiles('dashboard/playwright-report/**') != ''}}
run: |
tar -czf dashboard/playwright-report.tar.gz dashboard/playwright-report/
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 100000 \
-in dashboard/playwright-report.tar.gz \
-out playwright-report.tar.gz.enc \
-k "${{ secrets.PLAYWRIGHT_REPORT_ENCRYPTION_KEY }}"
rm dashboard/playwright-report.tar.gz
- name: Upload encrypted Playwright report
uses: actions/upload-artifact@v4
if: ${{ failure() && hashFiles('dashboard/playwright-report/**') != ''}}
with:
name: encrypted-playwright-report-${{ github.run_id }}
path: playwright-report.tar.gz.enc
retention-days: 1