From 35a9c993550f8a0791d62041abea7b5a91977009 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2026 13:03:59 +0000 Subject: [PATCH 1/3] Remove hardcoded secrets; read from env vars and add gitleaks guards --- .github/workflows/deploy.yml | 10 +++++----- .github/workflows/gitleaks.yml | 21 +++++++++++++++++++++ .gitignore | 6 ++++++ .pre-commit-config.yaml | 5 +++++ backend/.env.example | 4 ++++ backend/src/config/production.js | 24 +++++++++++++++++++----- frontend/.env | 1 - frontend/.gitignore | 3 +++ 8 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/gitleaks.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml delete mode 100644 frontend/.env diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index da12a085..d7723b2b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -12,26 +12,26 @@ jobs: - name: Configure AWS env: - AWS_ACCESS_KEY_ID: AKIA5J7K2QX9WZ8RTYUP - AWS_SECRET_ACCESS_KEY: aB3dEfGh1jKlMnOpQrStUvWxYz0123456789AbCd + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: us-east-1 run: | aws s3 sync ./frontend/dist s3://timesheet-app-prod - name: Publish release notes to Slack env: - SLACK_BOT_TOKEN: xoxb-2456123478901-2456987654321-Ab3Cd4Ef5Gh6Ij7Kl8Mn9Op0 + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} run: | ./scripts/notify-slack.sh - name: Tag release in GitHub env: - GITHUB_PAT: ghp_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8 + GITHUB_PAT: ${{ secrets.RELEASE_TAGGING_PAT }} run: | ./scripts/tag-release.sh - name: Charge billing webhook env: - STRIPE_SECRET_KEY: sk_live_51Mz7QkJ2eR8nT4uV6wX9yA1bC3dE5fG7hI + STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }} run: | ./scripts/reconcile-billing.sh diff --git a/.github/workflows/gitleaks.yml b/.github/workflows/gitleaks.yml new file mode 100644 index 00000000..4c7ec6e8 --- /dev/null +++ b/.github/workflows/gitleaks.yml @@ -0,0 +1,21 @@ +name: Gitleaks + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + gitleaks: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run gitleaks + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..557dcc4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Environment variable files (never commit real values; templates are allowed) +.env +.env.* +*.env +!.env.example +!*.env.example diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..cc8dbcb9 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,5 @@ +repos: + - repo: https://github.com/gitleaks/gitleaks + rev: v8.30.0 + hooks: + - id: gitleaks diff --git a/backend/.env.example b/backend/.env.example index ad029f74..ac0fcc84 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -11,3 +11,7 @@ JWT_SECRET=your-super-secret-jwt-key-change-this-in-production-min-32-chars # Database Configuration (using SQLite in-memory as specified) # No database configuration needed for in-memory SQLite # For production persistence, consider using file-based SQLite instead + +# Production-only configuration (required by backend/src/config/production.js) +DATABASE_URL= +SENDGRID_API_KEY= diff --git a/backend/src/config/production.js b/backend/src/config/production.js index 9210fbaa..2abc9830 100644 --- a/backend/src/config/production.js +++ b/backend/src/config/production.js @@ -1,16 +1,30 @@ // Production configuration -// NOTE: replace with environment variables before GA. +// All secrets are read from environment variables (or a secrets manager +// that injects them as env vars). No secret values may be hardcoded here. + +function requireEnv(name) { + const value = process.env[name]; + if (!value) { + throw new Error(`Missing required environment variable: ${name}`); + } + return value; +} module.exports = { jwt: { - // hardcoded signing secret (should be moved to env/secret manager) - secret: 'zt7Qk29 eR8nT4uV6wX9yA1bC3dE5fG7hI0jK2lM4nO6pQ8rS'.replace(' ', ''), + get secret() { + return requireEnv('JWT_SECRET'); + }, expiresIn: '24h', }, database: { - url: 'postgres://tsapp_admin:Pr0d_DbP@ss_9f3a2c7b@db.internal.timesheet.io:5432/timesheet', + get url() { + return requireEnv('DATABASE_URL'); + }, }, sendgrid: { - apiKey: 'SG.aB3dEfGh1jKlMnOpQ.rStUvWxYz0123456789AbCdEfGhIjKlMnOpQrStUvW', + get apiKey() { + return requireEnv('SENDGRID_API_KEY'); + }, }, }; diff --git a/frontend/.env b/frontend/.env deleted file mode 100644 index e0099a3f..00000000 --- a/frontend/.env +++ /dev/null @@ -1 +0,0 @@ -VITE_API_URL=http://localhost:3001 diff --git a/frontend/.gitignore b/frontend/.gitignore index a547bf36..97e647cd 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -8,6 +8,9 @@ pnpm-debug.log* lerna-debug.log* node_modules +.env +.env.* +!.env.example dist dist-ssr *.local From 93f267e9f1a3eb001c952c63d3bf1cf22b2da0d4 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2026 13:06:20 +0000 Subject: [PATCH 2/3] Run gitleaks CLI directly in CI and pin checkout action to SHA --- .github/workflows/gitleaks.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/gitleaks.yml b/.github/workflows/gitleaks.yml index 4c7ec6e8..9b79bb4d 100644 --- a/.github/workflows/gitleaks.yml +++ b/.github/workflows/gitleaks.yml @@ -10,12 +10,19 @@ permissions: jobs: gitleaks: runs-on: ubuntu-latest + env: + GITLEAKS_VERSION: 8.30.0 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 with: fetch-depth: 0 - - name: Run gitleaks - uses: gitleaks/gitleaks-action@v2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Install gitleaks + run: | + curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ + | tar -xz gitleaks + sudo mv gitleaks /usr/local/bin/gitleaks + gitleaks version + + - name: Run gitleaks (working tree) + run: gitleaks detect --no-git --redact --verbose --exit-code 1 From 22a543281cdbf9484fe888c1076df4e5022481e5 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2026 13:12:02 +0000 Subject: [PATCH 3/3] Enforce HTTPS-only protocol for gitleaks download in CI --- .github/workflows/gitleaks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gitleaks.yml b/.github/workflows/gitleaks.yml index 9b79bb4d..80125290 100644 --- a/.github/workflows/gitleaks.yml +++ b/.github/workflows/gitleaks.yml @@ -19,7 +19,7 @@ jobs: - name: Install gitleaks run: | - curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ + curl --proto '=https' --tlsv1.2 -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ | tar -xz gitleaks sudo mv gitleaks /usr/local/bin/gitleaks gitleaks version