Skip to content
Open
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
17 changes: 16 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,26 @@ GEMINI_GENERATE_MODEL=gemini-2.5-flash
AI_MAX_CONTENTS=12
AI_MAX_PARTS_PER_CONTENT=8
AI_MAX_SERIALIZED_CONTENT_BYTES=80000
API_RATE_LIMIT_PER_MINUTE=300
API_RATE_LIMIT_WINDOW_MS=60000
OAUTH_AUTHORIZE_IP_RATE_LIMIT_PER_MINUTE=30
OAUTH_AUTHORIZE_CLIENT_RATE_LIMIT_PER_MINUTE=80
OAUTH_TOKEN_IP_RATE_LIMIT_PER_MINUTE=20
OAUTH_TOKEN_CLIENT_RATE_LIMIT_PER_MINUTE=40
OAUTH_REVOKE_IP_RATE_LIMIT_PER_MINUTE=30
OAUTH_REVOKE_CLIENT_RATE_LIMIT_PER_MINUTE=60
OAUTH_USERINFO_IP_RATE_LIMIT_PER_MINUTE=60
OAUTH_USERINFO_TOKEN_RATE_LIMIT_PER_MINUTE=90
AUTH_SESSION_IP_RATE_LIMIT_PER_MINUTE=12
AUTH_SESSION_TOKEN_RATE_LIMIT_PER_MINUTE=20
QUANTUM_SYNC_IP_RATE_LIMIT_PER_MINUTE=80
QUANTUM_SYNC_TOKEN_RATE_LIMIT_PER_MINUTE=120
WHATSAPP_PHONE_NUMBER_ID=
WHATSAPP_SYSTEM_USER_TOKEN=
RESEND_API_KEY=
FLOW_API_KEY=
FLOW_ACCESS_SECRET=flow-local-development-secret
FLOW_ACCESS_SECRET=replace-with-a-long-random-flow-access-secret
ENFORCE_HTTPS=true
# Optional server-only bootstrap keys, e.g. "Ops:FLOW-OPS-2026,Sales:FLOW-SALES-2026".
# Prefer creating employee keys through POST /flow/admin/access-keys.
FLOW_REGISTERED_KEYS=
Expand Down
73 changes: 73 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Deploy Backend

on:
push:
branches:
- main
workflow_dispatch:

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

permissions:
attestations: write
contents: read
id-token: write

env:
NODE_ENV: production
NODE_VERSION: 22.13.x

jobs:
verify-and-package:
name: Security, Tests, Audit, and Build
runs-on: ubuntu-latest
timeout-minutes: 35
steps:
- name: Checkout repository
uses: actions/checkout@v4
Comment on lines +28 to +29

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 | ⚡ Quick win

Disable persisted checkout credentials.

actions/checkout should set persist-credentials: false to avoid leaving a writable token in git config for later steps.

Suggested patch
       - name: Checkout repository
         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 repository
uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.25.2)

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

(artipacked)


[error] 29-29: 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/deploy.yml around lines 28 - 29, The checkout step
"Checkout repository" is leaving a writable token; add the YAML key
persist-credentials: false to the actions/checkout@v4 step (the step named
"Checkout repository") so the action does not persist Git credentials into
subsequent steps; update that checkout step to include persist-credentials:
false under its uses entry.

Source: Linters/SAST tools


- name: Setup Node.js
uses: actions/setup-node@v4
Comment on lines +29 to +32

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the workflow and the specific area mentioned
echo "=== deploy.yml (lines 1-200) ==="
nl -ba .github/workflows/deploy.yml | sed -n '1,200p'

echo
echo "=== Uses lines (full file) ==="
rg -n "^\s*uses:\s*" .github/workflows/deploy.yml

echo
echo "=== Checkout persist-credentials config ==="
rg -n "persist-credentials" .github/workflows/deploy.yml || true

Repository: CheFu-code/chefu-inc-backend

Length of output: 166


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Listing workflow files ==="
ls -la .github/workflows || true

echo
echo "=== deploy.yml exists? ==="
test -f .github/workflows/deploy.yml && echo "Found: .github/workflows/deploy.yml" || echo "Missing: .github/workflows/deploy.yml"

echo
echo "=== deploy.yml first 220 lines (with line numbers via awk) ==="
awk '{printf "%d\t%s\n", NR, $0}' .github/workflows/deploy.yml | sed -n '1,220p'

echo
echo "=== All uses: entries ==="
rg -n "^\s*uses:\s*" .github/workflows/deploy.yml || true

echo
echo "=== Any persist-credentials ==="
rg -n "persist-credentials" .github/workflows/deploy.yml || true

echo
echo "=== Any attest-build-provenance upload-artifact uses ==="
rg -n "attest|provenance|upload-artifact" .github/workflows/deploy.yml || true

Repository: CheFu-code/chefu-inc-backend

Length of output: 2997


🌐 Web query:

actions/checkout@v4 persist-credentials default

💡 Result:

For actions/checkout@v4, persist-credentials defaults to true. The v4 action input persist-credentials is “Whether to configure the token or SSH key with the local git config” and its default is true [1]. The README also states that the auth token is persisted in the local git config by default, enabling scripts to run authenticated git commands, and that the token is removed during post-job cleanup; you can opt out by setting persist-credentials: false [2].

Citations:


Pin GitHub Actions to commit SHAs (and disable checkout credential persistence).

deploy.yml uses tag refs (actions/checkout@v4, actions/setup-node@v4, actions/upload-artifact@v4, actions/attest-build-provenance@v2), which leaves the pipeline exposed to tag-retarget/supply-chain risk—pin each uses: to an immutable commit SHA. Also, actions/checkout@v4 defaults persist-credentials: true, and this workflow doesn’t override it, so credentials remain available to later steps; set persist-credentials: false unless explicitly required.

Lines 29-32
Also applies to: 63-63, 71-71

🧰 Tools
🪛 zizmor (1.25.2)

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

(unpinned-uses)


[error] 32-32: 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/deploy.yml around lines 29 - 32, The workflow uses tag
refs for actions (actions/checkout@v4, actions/setup-node@v4,
actions/upload-artifact@v4, actions/attest-build-provenance@v2) and leaves
checkout credentials persisted; update each uses: entry to an immutable commit
SHA (replace the `@vX` tags with the corresponding full commit SHAs) and set
persist-credentials: false on the actions/checkout step (remove or set true only
if a later step explicitly needs repo credentials). Ensure you update every
occurrence (checkout at lines referenced and other uses of setup-node,
upload-artifact, attest-build-provenance) so all actions are pinned to SHAs and
checkout no longer persists credentials by default.

Source: Linters/SAST tools

with:
cache: npm
node-version: ${{ env.NODE_VERSION }}

- name: Install dependencies
run: npm ci --include=dev

- name: Lint
run: npm run lint

- name: Typecheck
run: npm run typecheck

- name: Run backend security integration tests
run: npm run test:security -- --silent

- name: Audit production dependency risk
run: npm audit --audit-level=high

- name: Build production API
run: npm run build

- name: Package backend artifact
run: |
set -euo pipefail
mkdir -p build-artifacts/backend
tar -czf build-artifacts/backend/chefu-api-dist-${{ github.sha }}.tgz dist package.json package-lock.json
(cd build-artifacts/backend && sha256sum *.tgz > SHA256SUMS)

- name: Upload backend artifact
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: chefu-api-production-${{ github.sha }}
path: build-artifacts/backend/*
retention-days: 30

- name: Attest backend artifact
uses: actions/attest-build-provenance@v2
with:
subject-path: build-artifacts/backend/*
15 changes: 15 additions & 0 deletions jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ["js", "json", "ts"],
roots: ["<rootDir>/test"],
testEnvironment: "node",
testRegex: ".*\\.spec\\.ts$",
transform: {
"^.+\\.(t|j)s$": [
"ts-jest",
{
tsconfig: "tsconfig.spec.json",
},
],
},
};
Loading
Loading