fix build image error
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
# Security Hardening Application Report
|
||||
|
||||
Generated: 2026-06-09
|
||||
Project: RentalDriveGo / Car Management System
|
||||
Input archive: `/mnt/data/car_management_system_plan_applied(1).zip`
|
||||
Plan applied: `/mnt/data/SECURITY_HARDENING_IMPLEMENTATION_PLAN(1).md`
|
||||
|
||||
## Executive result
|
||||
|
||||
The uploaded project was inspected and the security hardening plan was applied as far as safely possible inside the source archive. The archive already contained a broad previous hardening pass. I did not blindly trust that state, because that is how software becomes an expensive apology letter. I re-audited the implementation against the plan and applied additional corrections where the code still contradicted the target security model.
|
||||
|
||||
The final output includes a patched project archive, this report, a changed-file list, and an incremental diff for the additional changes made during this pass.
|
||||
|
||||
## What was already present in the uploaded project
|
||||
|
||||
The project already contained many of the plan-aligned building blocks:
|
||||
|
||||
- Centralized JWT helpers for actor tokens.
|
||||
- HttpOnly session cookie helpers for admin, employee, and renter sessions.
|
||||
- Company authorization policy helpers.
|
||||
- Admin 2FA and fresh-2FA enforcement middleware.
|
||||
- Public booking access-token helpers.
|
||||
- Webhook idempotency helpers.
|
||||
- Hashed `CompanyApiKey` model and migration.
|
||||
- `ReservationPublicAccess` model and migration.
|
||||
- `WebhookEvent` model and migration.
|
||||
- Upload validation helpers and public/private storage separation.
|
||||
- Request ID and sanitized error response middleware.
|
||||
- Production Docker/Traefik hardening, including Redis authentication and `x-middleware-subrequest` blocking.
|
||||
- Static security scan script and CI security gates.
|
||||
|
||||
That base work was useful, but it had a few security and test-consistency gaps.
|
||||
|
||||
## Additional changes applied in this pass
|
||||
|
||||
### 1. Removed legacy plaintext company API key storage
|
||||
|
||||
The plan requires company API keys to be hash-only. The code had introduced `CompanyApiKey`, but the legacy `Company.apiKey` field still existed in the Prisma schema and middleware still allowed a fallback lookup against that plaintext field when `ALLOW_LEGACY_COMPANY_API_KEYS=true`.
|
||||
|
||||
Changes applied:
|
||||
|
||||
- Removed `Company.apiKey` from `packages/database/prisma/schema.prisma`.
|
||||
- Removed `apiKey` from the local `Company` TypeScript interface in `packages/database/src/index.ts` and `packages/database/src/index.d.ts`.
|
||||
- Removed the legacy plaintext fallback path from `apps/api/src/middleware/requireApiKey.ts`.
|
||||
- Added migration `20260609233000_drop_legacy_company_api_key` to drop the old column and unique index.
|
||||
- Rewrote `requireApiKey` tests around prefix lookup, hash comparison, revocation, and `lastUsedAt` updates.
|
||||
|
||||
Security effect: raw company API keys are no longer accepted through the legacy company column and are no longer represented in the current Prisma schema.
|
||||
|
||||
### 2. Centralized Socket.io token verification
|
||||
|
||||
The main API process still verified Socket.io auth tokens directly with `jwt.verify(token, JWT_SECRET)` and did not enforce issuer, audience, actor type, or allowed algorithm. This contradicted the session-authentication phase of the plan.
|
||||
|
||||
Changes applied:
|
||||
|
||||
- Added `verifyAnyActorToken()` to `apps/api/src/security/tokens.ts`.
|
||||
- Updated `apps/api/src/index.ts` to use centralized actor-token verification for Socket.io authentication.
|
||||
- Removed the direct `jsonwebtoken` import from the main API entrypoint.
|
||||
|
||||
Security effect: Socket.io no longer accepts tokens that bypass the centralized actor-token constraints.
|
||||
|
||||
### 3. Hardened employee password-reset JWT verification
|
||||
|
||||
Employee password-reset tokens were signed and verified directly with the JWT secret and no issuer, audience, or algorithm constraints.
|
||||
|
||||
Changes applied:
|
||||
|
||||
- Added explicit `HS256` signing for employee password-reset tokens.
|
||||
- Added issuer `rentaldrivego-api`.
|
||||
- Added audience `employee_password_reset`.
|
||||
- Added matching verification constraints.
|
||||
|
||||
Security effect: reset tokens now reject wrong issuer, wrong audience, or wrong algorithm instead of relying on a bare shared-secret verification.
|
||||
|
||||
### 4. Repaired test fixtures and middleware tests
|
||||
|
||||
Some tests still expected pre-hardening behavior. That is a bad smell: tests defending old weaknesses are basically tiny lobbyists for future incidents.
|
||||
|
||||
Changes applied:
|
||||
|
||||
- Updated API-key middleware tests to validate hashed-key behavior instead of plaintext `Company.apiKey` lookup.
|
||||
- Updated auth middleware tests to match the centralized token verifier behavior.
|
||||
- Updated integration test helper token generation to use `signActorToken()` so generated test tokens include issuer and audience.
|
||||
|
||||
Security effect: future test runs are less likely to push developers back toward weaker auth behavior.
|
||||
|
||||
## Verification performed in this sandbox
|
||||
|
||||
| Check | Result | Notes |
|
||||
|---|---:|---|
|
||||
| Static security scan | PASS | `npm run security:static` completed successfully. |
|
||||
| Critical production dependency audit | PASS | `npm audit --package-lock-only --omit=dev --audit-level=critical` exited successfully. |
|
||||
| JSON syntax check | PASS | Root and app `package.json` files and lockfile parsed successfully. |
|
||||
| Shell syntax check | PASS | Shell scripts and production entrypoint parsed with `bash -n`. |
|
||||
| YAML parse check | PASS | `docker-compose.production.yml` and `.gitlab-ci.yml` parsed successfully. |
|
||||
| Node script syntax | PASS | `scripts/security-static-check.mjs` passed `node --check`. |
|
||||
| Full dependency install | NOT COMPLETED | `npm ci --ignore-scripts --prefer-offline` could not complete in this sandbox. |
|
||||
| Full type-check/test/build | NOT RUN | Requires dependencies to be installed. Run in CI or a normal development environment. |
|
||||
| Docker compose config/render | NOT RUN | Docker is unavailable in this sandbox. |
|
||||
| Prisma generate/migrate | NOT RUN | Requires dependency installation and a normal Prisma/DB environment. |
|
||||
|
||||
## Dependency audit note
|
||||
|
||||
The critical audit gate passes. The audit still reports moderate findings involving `postcss` through Next.js and `uuid` through Firebase/cron-related dependency chains. The lockfile’s suggested fixes require forced or breaking upgrades, so I did not casually smash the dependency graph with a hammer and call the mess “security.” Those should be handled in a controlled dependency-upgrade ticket with full frontend and notification regression testing.
|
||||
|
||||
## Files changed by this pass
|
||||
|
||||
- `apps/api/src/index.ts`
|
||||
- `apps/api/src/middleware/requireApiKey.ts`
|
||||
- `apps/api/src/middleware/requireApiKey.test.ts`
|
||||
- `apps/api/src/middleware/requireCompanyAuth.test.ts`
|
||||
- `apps/api/src/middleware/requireRenterAuth.test.ts`
|
||||
- `apps/api/src/modules/auth/auth.employee.service.ts`
|
||||
- `apps/api/src/security/tokens.ts`
|
||||
- `apps/api/src/tests/helpers/fixtures.ts`
|
||||
- `packages/database/prisma/schema.prisma`
|
||||
- `packages/database/prisma/migrations/20260609233000_drop_legacy_company_api_key/migration.sql`
|
||||
- `packages/database/src/index.ts`
|
||||
- `packages/database/src/index.d.ts`
|
||||
|
||||
See also:
|
||||
|
||||
- `security_hardening_incremental.diff`
|
||||
- `security_hardening_changed_files.txt`
|
||||
|
||||
## Phase status against the hardening plan
|
||||
|
||||
| Phase | Status | Evidence / caveat |
|
||||
|---|---:|---|
|
||||
| Phase 0: Emergency stabilization | Partial / needs operator action | Static scan passes, placeholders are present, but real production secret rotation cannot be performed inside the archive. |
|
||||
| Phase 1: Sessions and authentication | Substantially applied | HttpOnly session helpers and centralized actor JWT verification exist; Socket.io and reset-token gaps were corrected in this pass. |
|
||||
| Phase 2: Authorization and tenant isolation | Substantially applied | Company policy middleware exists; tenant-safe patterns are present in many modules. Full proof requires test suite and code review across all repository methods. |
|
||||
| Phase 3: Public booking privacy | Applied at source level | Public access token model/helper and safe public booking flow are present. Must be verified with integration tests. |
|
||||
| Phase 4: Admin hardening | Applied at source level | Mandatory 2FA and fresh-2FA middleware are present. Enrollment and recovery-code workflows still need production validation. |
|
||||
| Phase 5: API key hardening | Strengthened in this pass | Legacy plaintext company API key storage/fallback removed; hash-only `CompanyApiKey` path remains. |
|
||||
| Phase 6: Payments and webhooks | Applied at source level | Raw-body webhook handling and idempotency helpers are present. Must be verified against provider test events. |
|
||||
| Phase 7: Upload and storage hardening | Applied at source level | Magic-byte validation and public/private storage split are present. Must be verified with upload abuse tests. |
|
||||
| Phase 8: Rate limiting, errors, browser security | Applied at source level | Request IDs, sanitized errors, rate limit middleware, and security headers are present. Must be verified in deployed environment. |
|
||||
| Phase 9: Deployment hardening | Applied at config level | Redis auth, non-public DB tooling, private networks, and Traefik header blocking are present. Must be verified on the real host. |
|
||||
| Phase 10: Observability, auditability, jobs | Partial | Logging/audit hooks exist, but queue migration and operational observability need dedicated validation. |
|
||||
| CI/CD security gates | Applied at config level | Security scan and critical audit gates exist; full CI must run outside this sandbox. |
|
||||
|
||||
## Required follow-up before launch
|
||||
|
||||
1. Rotate all real production secrets and invalidate old sessions/API keys where appropriate.
|
||||
2. Run `npm ci` in CI or a normal development environment.
|
||||
3. Run `npm run db:generate` and apply the new migration after backup.
|
||||
4. Run full type-check, unit tests, integration tests, e2e tests, and builds.
|
||||
5. Run payment-provider webhook test events using real sandbox provider signatures.
|
||||
6. Verify public/private storage behavior with real uploaded files.
|
||||
7. Verify Redis and PostgreSQL are not externally reachable from the production host.
|
||||
8. Run container image build and Trivy scan.
|
||||
9. Confirm admin 2FA enrollment and fresh-2FA gates before enabling privileged admin actions in production.
|
||||
10. Document any deferrals with owner, risk acceptance, compensating control, deadline, and ticket number.
|
||||
|
||||
## Launch recommendation
|
||||
|
||||
Do not launch publicly yet based only on the patched archive. The source now better matches the plan, and the critical static/audit checks pass, but the hard launch gate still depends on full CI, Prisma migration validation, deployment verification, and production secret rotation.
|
||||
|
||||
The patched archive is suitable for the next CI/staging pass. Treat it as implementation-ready source, not production clearance. Production clearance comes from reproducible evidence, not vibes in a ZIP file.
|
||||
@@ -0,0 +1,255 @@
|
||||
# Security Hardening Leftover Application Report
|
||||
|
||||
Project: RentalDriveGo / Car Management System
|
||||
Input archive: `car_management_system_hardened_applied.zip`
|
||||
Output archive: `car_management_system_leftover_applied.zip`
|
||||
Date: 2026-06-09
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This pass applied the remaining source-level hardening gaps that were still practical to implement directly in the repository after the first hardening pass. The focus was on eliminating browser-readable authentication assumptions, enforcing app-layer blocking for the `x-middleware-subrequest` bypass class, improving actor-aware rate limiting, adding an admin 2FA recovery-code workflow, and bringing documentation/static checks into line with the hardened authentication model.
|
||||
|
||||
This does not replace production operator work such as real secret rotation, live infrastructure verification, container scanning, applying migrations to a real database, or running the complete CI/test pipeline. Those items remain launch-gate evidence requirements.
|
||||
|
||||
## Applied Changes
|
||||
|
||||
### 1. Removed remaining browser-side employee token assumptions
|
||||
|
||||
Changed files:
|
||||
|
||||
- `apps/dashboard/src/lib/api.ts`
|
||||
- `apps/dashboard/src/components/layout/TopBar.tsx`
|
||||
- `apps/dashboard/src/components/layout/Sidebar.tsx`
|
||||
- `apps/dashboard/src/app/(dashboard)/team/page.tsx`
|
||||
- `apps/dashboard/src/app/sign-in/[[...sign-in]]/SignInPageClient.tsx`
|
||||
|
||||
What changed:
|
||||
|
||||
- Removed dashboard use of employee auth tokens from `localStorage`.
|
||||
- Dashboard API calls now use `credentials: 'include'` and depend on HttpOnly cookies.
|
||||
- Dashboard Socket.io connection now uses cookie credentials instead of script-provided auth tokens.
|
||||
- Team page no longer decodes employee identity from a localStorage JWT. It resolves the current actor through `/auth/employee/me`.
|
||||
- Admin 2FA sign-in form now accepts either a six-digit TOTP code or a recovery code value.
|
||||
|
||||
Security effect:
|
||||
|
||||
- Reduces script-readable authentication exposure.
|
||||
- Aligns the dashboard with the intended HttpOnly session-cookie model.
|
||||
- Prevents UI code from treating a readable JWT as the authority for employee identity.
|
||||
|
||||
### 2. Added Socket.io HttpOnly-cookie session support
|
||||
|
||||
Changed file:
|
||||
|
||||
- `apps/api/src/index.ts`
|
||||
|
||||
What changed:
|
||||
|
||||
- Added Socket.io session-token extraction from HttpOnly cookies.
|
||||
- Preserved explicit token verification for trusted non-browser/server contexts, while browser clients can now authenticate through cookies.
|
||||
- Reused centralized actor-token verification.
|
||||
|
||||
Security effect:
|
||||
|
||||
- Real-time dashboard connections no longer require JavaScript-readable employee tokens.
|
||||
- Socket authentication now follows the same actor-token validation path used elsewhere.
|
||||
|
||||
### 3. Added app-layer `x-middleware-subrequest` blocking
|
||||
|
||||
Changed files:
|
||||
|
||||
- `apps/api/src/app.ts`
|
||||
- `apps/dashboard/src/middleware.ts`
|
||||
- `apps/marketplace/src/middleware.ts`
|
||||
- `apps/admin/src/middleware.ts`
|
||||
- `apps/dashboard/src/middleware.test.ts`
|
||||
- `apps/marketplace/src/middleware.test.ts`
|
||||
|
||||
What changed:
|
||||
|
||||
- API now rejects requests containing `x-middleware-subrequest` before route handling.
|
||||
- Dashboard, marketplace, and admin Next middleware now reject the same header at the app layer.
|
||||
- Added/updated middleware tests for the rejection path.
|
||||
|
||||
Security effect:
|
||||
|
||||
- Adds defense in depth beyond reverse-proxy filtering.
|
||||
- Prevents the project from depending on a single infrastructure control for this bypass class.
|
||||
|
||||
### 4. Hardened admin/browser fetch behavior
|
||||
|
||||
Changed files include:
|
||||
|
||||
- `apps/admin/src/lib/api.ts`
|
||||
- `apps/admin/src/app/dashboard/admin-users/page.tsx`
|
||||
- `apps/admin/src/app/dashboard/renters/page.tsx`
|
||||
- `apps/admin/src/app/dashboard/companies/[id]/page.tsx`
|
||||
- `apps/admin/src/app/dashboard/containers/page.tsx`
|
||||
- `apps/admin/src/app/dashboard/pricing/page.tsx`
|
||||
- `apps/admin/src/app/forgot-password/page.tsx`
|
||||
- `apps/admin/src/app/reset-password/page.tsx`
|
||||
|
||||
What changed:
|
||||
|
||||
- Admin API wrapper uses `credentials: 'include'`.
|
||||
- Manual admin fetch calls now include credentials where they directly call the admin API.
|
||||
- Removed dead placeholder `getToken()` helpers that returned empty strings and created meaningless `Authorization: Bearer ` headers.
|
||||
|
||||
Security effect:
|
||||
|
||||
- Admin browser requests now consistently rely on the HttpOnly admin session cookie.
|
||||
- Removes misleading bearer-token scaffolding from the admin UI.
|
||||
|
||||
### 5. Improved actor-aware rate limiting
|
||||
|
||||
Changed files:
|
||||
|
||||
- `apps/api/src/middleware/rateLimiter.ts`
|
||||
- `apps/api/src/app.ts`
|
||||
|
||||
What changed:
|
||||
|
||||
- API rate-limit keys now prefer a verified actor identity from session cookies or valid Bearer tokens.
|
||||
- Actor-aware rate limiting falls back safely to existing request actor fields or anonymous IP keys.
|
||||
- Admin authentication routes now receive the stricter authentication limiter before the broader admin limiter.
|
||||
|
||||
Security effect:
|
||||
|
||||
- Authenticated traffic is limited by actor identity instead of only coarse IP data.
|
||||
- Login and admin-auth abuse get stricter protection.
|
||||
- Multi-container correctness still depends on Redis availability/configuration in production, which must be verified during deployment.
|
||||
|
||||
### 6. Added admin 2FA recovery-code backend workflow
|
||||
|
||||
Changed files:
|
||||
|
||||
- `packages/database/prisma/schema.prisma`
|
||||
- `packages/database/prisma/migrations/20260610001500_add_admin_recovery_codes/migration.sql`
|
||||
- `apps/api/src/modules/admin/admin.repo.ts`
|
||||
- `apps/api/src/modules/admin/admin.service.ts`
|
||||
- `apps/api/src/modules/admin/admin.schemas.ts`
|
||||
- `apps/api/src/modules/admin/admin.routes.ts`
|
||||
|
||||
What changed:
|
||||
|
||||
- Added `AdminRecoveryCode` model.
|
||||
- Recovery codes are stored as bcrypt hashes, not plaintext.
|
||||
- TOTP enrollment now issues one-time recovery codes.
|
||||
- Recovery-code regeneration is protected by authenticated admin access and fresh 2FA.
|
||||
- Login can consume a valid unused recovery code when TOTP is enabled.
|
||||
- Recovery-code issuance and use are audited.
|
||||
|
||||
Security effect:
|
||||
|
||||
- Adds a recovery path for mandatory admin 2FA without storing backup codes in plaintext.
|
||||
- Preserves one-time-use semantics.
|
||||
- Adds auditability for recovery-code lifecycle events.
|
||||
|
||||
Limitation:
|
||||
|
||||
- The backend returns recovery codes after enrollment/regeneration. A production-ready admin UI still needs to display them once with clear save instructions and must not persist them client-side.
|
||||
|
||||
### 7. Strengthened static scanning for auth-token regressions
|
||||
|
||||
Changed file:
|
||||
|
||||
- `scripts/security-static-check.mjs`
|
||||
|
||||
What changed:
|
||||
|
||||
- Static scan now catches common regressions involving auth/session token names in `localStorage` and `document.cookie`.
|
||||
- Scan specifically targets auth token/session names such as employee/admin/renter tokens and sessions.
|
||||
|
||||
Security effect:
|
||||
|
||||
- Makes it harder for future code changes to quietly reintroduce script-readable authentication tokens.
|
||||
|
||||
### 8. Updated documentation to match the hardened model
|
||||
|
||||
Changed files:
|
||||
|
||||
- `apps/dashboard/README.md`
|
||||
- `memory/project_auth_architecture.md`
|
||||
- `docs/project-design/COOKIE_POLICY.md`
|
||||
- `apps/api/src/swagger/openapi.ts`
|
||||
|
||||
What changed:
|
||||
|
||||
- Replaced stale localStorage/JWT handoff claims with HttpOnly session-cookie wording.
|
||||
- Clarified that browser clients use HttpOnly sessions and that Bearer tokens are only for documented trusted server/mobile contexts.
|
||||
- Updated cookie policy references from legacy `employee_token` wording to `employee_session`.
|
||||
|
||||
Security effect:
|
||||
|
||||
- Reduces the odds that a future developer follows stale documentation and reintroduces the old pattern.
|
||||
|
||||
## Validation Performed
|
||||
|
||||
The following checks were run successfully in the available environment:
|
||||
|
||||
```bash
|
||||
npm run security:static
|
||||
node --check scripts/security-static-check.mjs
|
||||
# JSON parse validation for package.json and package-lock.json files
|
||||
# YAML parse validation for docker-compose.production.yml and .gitlab-ci.yml
|
||||
bash -n docker/entrypoint.production.sh scripts/docker-prod-*.sh scripts/docker-registry-local-up.sh scripts/setup-clerk-keys.sh
|
||||
# TypeScript/TSX syntax transpile check over 507 source files
|
||||
npm audit --package-lock-only --omit=dev --audit-level=critical
|
||||
```
|
||||
|
||||
Results:
|
||||
|
||||
- Security static check: passed.
|
||||
- Static-check script syntax: passed.
|
||||
- Package JSON validation: passed.
|
||||
- YAML validation: passed.
|
||||
- Shell syntax validation: passed.
|
||||
- TypeScript/TSX syntax transpile validation: passed.
|
||||
- Critical production dependency audit: passed.
|
||||
|
||||
Audit note:
|
||||
|
||||
- `npm audit --audit-level=critical` exited successfully.
|
||||
- Moderate advisories remain for transitive `postcss` and `uuid` paths. The available automatic fixes require breaking/force dependency changes, so they were not applied blindly in this source pass.
|
||||
|
||||
## Not Fully Verified in This Environment
|
||||
|
||||
The following items require a real development/CI/deployment environment:
|
||||
|
||||
- `npm ci` from a clean checkout.
|
||||
- Full workspace typecheck.
|
||||
- Full unit, integration, security, and e2e test suites.
|
||||
- Prisma client generation.
|
||||
- Applying the new database migration to a real database.
|
||||
- Database backup/restore verification.
|
||||
- Docker image build and runtime validation.
|
||||
- Container scanning with Trivy or equivalent.
|
||||
- Live reverse-proxy validation for `x-middleware-subrequest` blocking.
|
||||
- Redis-backed distributed rate-limit validation across multiple API containers.
|
||||
- Provider webhook sandbox tests.
|
||||
- Live admin 2FA recovery-code UX verification.
|
||||
|
||||
## Remaining Launch-Gate Work
|
||||
|
||||
These are still not things source edits can prove by themselves:
|
||||
|
||||
1. Rotate all real production secrets.
|
||||
2. Confirm no real secrets exist in repository history or image layers.
|
||||
3. Apply and verify the new `admin_recovery_codes` migration.
|
||||
4. Run the full CI gate: lint, typecheck, unit tests, integration tests, security tests, build, dependency audit, secret scan, and container scan.
|
||||
5. Confirm Redis and PostgreSQL are private in production.
|
||||
6. Confirm DB management tools are not publicly reachable.
|
||||
7. Confirm production containers run non-root with reduced capabilities and resource limits.
|
||||
8. Confirm webhook signature/idempotency behavior against real provider sandbox payloads.
|
||||
9. Confirm private files are inaccessible through static routes in the deployed environment.
|
||||
10. Confirm the admin UI displays recovery codes once and instructs admins to save them securely.
|
||||
|
||||
## Changed Files
|
||||
|
||||
See `security_hardening_leftover_changed_files.txt` for the complete file list and `security_hardening_leftover.diff` for the unified diff.
|
||||
|
||||
## Final Assessment
|
||||
|
||||
This pass closes a meaningful set of leftover source-level gaps from the security-hardening plan. The project is closer to the intended model: API-enforced security, HttpOnly browser sessions, stronger admin 2FA recovery, app-layer bypass blocking, and less stale documentation.
|
||||
|
||||
However, this still should not be treated as production-ready until the remaining launch-gate evidence is collected from CI and the live deployment environment. Security that has not been tested in the actual runtime is mostly optimism with a lanyard.
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
'use client'
|
||||
|
||||
import React from "react";
|
||||
|
||||
import PublicFooter from '@/components/PublicFooter'
|
||||
import PublicHeader from '@/components/PublicHeader'
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user