Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .firebaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"projects": {
"default": "servio-app"
}
}
50 changes: 50 additions & 0 deletions .github/workflows/firebase-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Deploy to Firebase Hosting

on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: firebase-deploy-${{ github.ref }}
cancel-in-progress: true

jobs:
build-and-deploy:
name: Build & Deploy
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

Comment on lines +21 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚖️ Poor tradeoff

Pin GitHub Actions to specific commit hashes for supply-chain security.

Three actions are unpinned (@v4 and @v0 tags). Tags can be moved or compromised; pin to immutable commit hashes to ensure reproducible, auditable CI/CD.

🔒 Proposed fixes for pinned action hashes
       - name: Checkout
-        uses: actions/checkout@v4
+        uses: actions/checkout@a5ac7e51b41094c7f3ba2a8547355d5e79c575f7  # v4.1.6
       - name: Set up Node.js
-        uses: actions/setup-node@v4
+        uses: actions/setup-node@60edb5dd545a775178fac7f3e464e8ff4f5296be  # v4.0.2
       - name: Deploy to Firebase Hosting
-        uses: FirebaseExtended/action-hosting-deploy@v0
+        uses: FirebaseExtended/action-hosting-deploy@16cfa59e21b9e3a2e23a41e4f0420a42a1c6ef30  # v0.8.1

Note: Verify these are the latest compatible versions by checking the action repositories before merging. Use the @actions/ or Firebase release tags to find the exact commit hash for each version.

Also applies to: 25-28, 45-50

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 21-22: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 22-22: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/firebase-deploy.yml around lines 21 - 23, Pin the GitHub
Actions to specific commit hashes instead of version tags for supply-chain
security. Replace the version tags (such as `@v4` in actions/checkout and `@v0` in
other actions) with their corresponding full commit hashes throughout the
workflow file. Look up the exact commit hash for each action version from the
respective action repositories on GitHub, then update each uses statement to
reference the immutable commit hash instead of the mutable version tag to ensure
reproducible and auditable CI/CD deployments.

Source: Linters/SAST tools


⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add persist-credentials: false to prevent credential leakage.

The checkout action leaves Git credentials in the workflow's git config, which could be exposed in logs or artifacts if a later step is compromised.

🔐 Proposed fix
       - name: Checkout
         uses: actions/checkout@v4
+        with:
+          persist-credentials: false
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 21-22: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 22-22: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/firebase-deploy.yml around lines 21 - 23, The checkout
action using `actions/checkout@v4` is missing the `persist-credentials: false`
configuration which leaves Git credentials in the workflow's git config. Add
`persist-credentials: false` as a parameter to the checkout action to prevent
credentials from being persisted and potentially exposed in logs or artifacts if
a later workflow step is compromised.

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build
env:
VITE_FIREBASE_API_KEY: ${{ secrets.VITE_FIREBASE_API_KEY }}
VITE_FIREBASE_AUTH_DOMAIN: ${{ secrets.VITE_FIREBASE_AUTH_DOMAIN }}
VITE_FIREBASE_PROJECT_ID: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
VITE_FIREBASE_STORAGE_BUCKET: ${{ secrets.VITE_FIREBASE_STORAGE_BUCKET }}
VITE_FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.VITE_FIREBASE_MESSAGING_SENDER_ID }}
VITE_FIREBASE_APP_ID: ${{ secrets.VITE_FIREBASE_APP_ID }}
VITE_FIREBASE_MEASUREMENT_ID: ${{ secrets.VITE_FIREBASE_MEASUREMENT_ID }}

- name: Deploy to Firebase Hosting
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: ${{ secrets.GITHUB_TOKEN }}
firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
channelId: live
projectId: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
50 changes: 50 additions & 0 deletions .github/workflows/firebase-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Firebase Hosting Preview

on:
pull_request:

permissions:
contents: read
checks: write
pull-requests: write

concurrency:
group: firebase-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
preview:
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
name: Build & Preview
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
Comment on lines +22 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚖️ Poor tradeoff

Pin GitHub Actions to specific commit hashes for supply-chain security.

Same unpinned action issue as the production workflow. Apply the same hashes to ensure consistency across workflows.

🔒 Proposed fixes for pinned action hashes
       - name: Checkout
-        uses: actions/checkout@v4
+        uses: actions/checkout@a5ac7e51b41094c7f3ba2a8547355d5e79c575f7  # v4.1.6
       - name: Set up Node.js
-        uses: actions/setup-node@v4
+        uses: actions/setup-node@60edb5dd545a775178fac7f3ba2a8547355d5e79c575f7  # v4.0.2
       - name: Deploy Preview to Firebase Hosting
-        uses: FirebaseExtended/action-hosting-deploy@v0
+        uses: FirebaseExtended/action-hosting-deploy@16cfa59e21b9e3a2e23a41e4f0420a42a1c6ef30  # v0.8.1

Note: Use the same pinned versions as the production workflow to keep CI/CD consistent.

Also applies to: 25-29, 46-50

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 22-23: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/firebase-preview.yml around lines 22 - 23, Pin the GitHub
Actions in the firebase-preview.yml workflow to specific commit hashes instead
of version tags for supply-chain security. Replace the unpinned action
references (actions/checkout@v4 and any other actions in the sections spanning
lines 25-29 and 46-50) with their corresponding full commit hash format (e.g.,
actions/checkout@<hash>). Use the same commit hashes that are already applied in
the production workflow to maintain consistency across all CI/CD workflows.

Source: Linters/SAST tools


⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add persist-credentials: false to prevent credential leakage.

Same security concern as production workflow: checkout leaves Git credentials in git config.

🔐 Proposed fix
       - name: Checkout
         uses: actions/checkout@v4
+        with:
+          persist-credentials: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Checkout
uses: actions/checkout@v4
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 22-23: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/firebase-preview.yml around lines 22 - 23, The Checkout
step using actions/checkout@v4 is missing the persist-credentials: false
parameter, which leaves Git credentials in the git config after checkout
completes. Add the persist-credentials: false input parameter to the checkout
action to prevent credentials from being persisted in the git configuration,
mitigating the security risk of credential leakage in the workflow.


- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build
env:
VITE_FIREBASE_API_KEY: ${{ secrets.VITE_FIREBASE_API_KEY }}
VITE_FIREBASE_AUTH_DOMAIN: ${{ secrets.VITE_FIREBASE_AUTH_DOMAIN }}
VITE_FIREBASE_PROJECT_ID: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
VITE_FIREBASE_STORAGE_BUCKET: ${{ secrets.VITE_FIREBASE_STORAGE_BUCKET }}
VITE_FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.VITE_FIREBASE_MESSAGING_SENDER_ID }}
VITE_FIREBASE_APP_ID: ${{ secrets.VITE_FIREBASE_APP_ID }}
VITE_FIREBASE_MEASUREMENT_ID: ${{ secrets.VITE_FIREBASE_MEASUREMENT_ID }}

- name: Deploy Preview to Firebase Hosting
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: ${{ secrets.GITHUB_TOKEN }}
firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
projectId: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,7 @@ Thumbs.db
.env.local
.env.development.local
.env.test.local
.env.production.local
.env.production.local

# Firebase
.firebase/
67 changes: 67 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,73 @@ A modern SaaS website built with React, Vite, and Tailwind CSS. This project is
npm run dev
```

## 🚀 Deployment

This project uses **Firebase Hosting** for production deployments.

### Prerequisites

- [Firebase CLI](https://firebase.google.com/docs/cli) installed globally:
```bash
npm install -g firebase-tools
```
- A Firebase project with Hosting enabled
- Firebase authentication via `firebase login`

### Environment Variables

Create a `.env` file at the project root with your Firebase configuration:

```env
VITE_FIREBASE_API_KEY=your_api_key
VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your_project_id
VITE_FIREBASE_STORAGE_BUCKET=your_project.firebasestorage.app
VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
VITE_FIREBASE_APP_ID=your_app_id
VITE_FIREBASE_MEASUREMENT_ID=your_measurement_id
```

### Manual Deployment

1. Build and deploy to production:
```bash
npm run deploy
```

2. Deploy a preview channel:
```bash
npm run deploy:preview
```

### Automated Deployment (CI/CD)

Deployments are automated via GitHub Actions:

- **Production:** Merges to `main` trigger a build and deploy to the live Firebase Hosting channel.
- **Preview:** Pull requests automatically deploy to a temporary preview URL (posted as a PR comment).

To enable automated deployments, add the following secrets to your GitHub repository (`Settings > Secrets and variables > Actions`):

| Secret | Description |
|--------|-------------|
| `FIREBASE_SERVICE_ACCOUNT` | Firebase service account JSON key (see [setup guide](https://github.com/FirebaseExtended/action-hosting-deploy/blob/main/docs/service-account.md)) |
| `VITE_FIREBASE_API_KEY` | Firebase API key |
| `VITE_FIREBASE_AUTH_DOMAIN` | Firebase auth domain |
| `VITE_FIREBASE_PROJECT_ID` | Firebase project ID |
| `VITE_FIREBASE_STORAGE_BUCKET` | Firebase storage bucket |
| `VITE_FIREBASE_MESSAGING_SENDER_ID` | Firebase messaging sender ID |
| `VITE_FIREBASE_APP_ID` | Firebase app ID |
| `VITE_FIREBASE_MEASUREMENT_ID` | Firebase measurement ID |

### Firebase Project Setup

1. Update the project ID in `.firebaserc` to match your Firebase project.
2. The `firebase.json` configures:
- `dist/` as the public directory (Vite build output)
- SPA rewrites (all routes serve `index.html`)
- Cache headers for static assets

## ✨ Key Features

- **Web Development Services:** Professional development of high-performance landing pages, corporate websites, and custom SaaS applications tailored for business growth.
Expand Down
36 changes: 36 additions & 0 deletions firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"hosting": {
"public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
],
"headers": [
{
"source": "/assets/**",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
},
{
"source": "**/*.@(js|css)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
}
]
}
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"dev": "vite --open",
"build": "vite build",
"typecheck": "tsc --noEmit",
"lint": "eslint ."
"lint": "eslint .",
"deploy": "npm run build && firebase deploy --only hosting",
"deploy:preview": "npm run build && firebase hosting:channel:deploy preview"
},
"dependencies": {
"@emotion/react": "11.14.0",
Expand Down
Loading