dev_arc_aws/.kiro/specs/code-audit-fixes/tasks.md
Samuel James 3172104d29
All checks were successful
CI / validate (push) Successful in 3m33s
Add code-audit-fixes spec (#5)
2026-06-24 19:20:18 +00:00

153 lines
7.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Implementation Plan: Code Audit Fixes
## Overview
Surgical fixes for 13 Critical + High audit issues across the ArchNest backend (Fastify 5 + TypeScript) and frontend (React 19 + TypeScript), plus a CloudFormation test deploy template. Each task targets a specific file with a minimal, correct patch. No new dependencies introduced.
## Tasks
- [ ] 1. Backend security hardening — input validation and auth
- [ ] 1.1 Add path traversal prevention to `backend/src/routes/files.ts`
- Add `validatePath()` function using `posix.normalize()` to reject absolute paths and `..` traversal
- Apply validation at the top of every handler that accepts a user-supplied path (list, content read, content write, mkdir, rename, delete, chmod, download, upload)
- Return HTTP 400 with descriptive error on rejection
- _Requirements: 6.1, 6.2, 6.3, 6.4_
- [ ] 1.2 Fix agent token timing-safe comparison in `backend/src/routes/agents.ts`
- Replace early-return on length mismatch with padded constant-time comparison
- Pad both buffers to `Math.max(a.length, b.length)` before `timingSafeEqual`
- Ensure `ok: true` only when both length AND content match
- Same 401 response for all rejection cases
- _Requirements: 7.1, 7.2, 7.3_
- [ ] 1.3 Add session log integrationId validation in `backend/src/routes/terminal.ts`
- Update `sessionLogPath()` to return `null` when integrationId is not a positive integer
- Callers skip logging on `null` return
- _Requirements: 13.1, 13.2_
- [ ] 1.4 Add body size limit to data import in `backend/src/routes/data.ts`
- Add `bodyLimit: 10 * 1024 * 1024` to the POST `/api/data/import` route registration
- Fastify returns 413 automatically when exceeded
- _Requirements: 8.1, 8.2_
- [ ] 1.5 Set CORS origin to fail-closed default in `backend/src/server.ts`
- Change fallback from `true` to `false` when `ARCHNEST_CORS_ORIGIN` is not set
- Log a warning at startup when env var is missing
- _Requirements: 10.1, 10.2, 10.3_
- [ ]* 1.6 Write property tests for path traversal, agent token, and integrationId validation
- **Property 3: Path Traversal Prevention** — verify `validatePath` rejects all `..` escape patterns and accepts valid relative paths
- **Property 4: Agent Token Comparison Correctness** — verify `ok: true` iff `presented === expected`, never throws
- **Property 8: Integration ID Numeric Validation** — verify `sessionLogPath` returns null for non-positive-integer values
- **Validates: Requirements 6.1, 6.2, 7.1, 7.2, 7.3, 13.1, 13.2**
- [ ] 2. Checkpoint — Backend security
- Ensure all tests pass, ask the user if questions arise.
- [ ] 3. WebSocket authentication refactor
- [ ] 3.1 Implement first-message auth gate in `backend/src/routes/terminal.ts`
- Add `authenticated` flag per connection
- Require `{ type: 'auth', token }` as first message; verify JWT
- Reject all other message types before auth with error frame + close
- Remove `req.query.token` usage from connect/list_tmux handlers
- _Requirements: 5.3, 5.4_
- [ ] 3.2 Implement first-message auth gate in `backend/src/routes/docker.ts`
- Same pattern as terminal: auth-first protocol for Docker exec WebSocket
- Verify existing JSON parse error handling remains intact (already correct per design)
- _Requirements: 5.3, 5.4, 12.1, 12.2_
- [ ] 3.3 Update frontend WebSocket connections in `src/lib/TerminalSessionContext.tsx`
- Remove `?token=` from WebSocket URL query string
- Send `{ type: 'auth', token }` as first message on `ws.onopen`
- Apply same change to `fetchTmuxSessions()` WebSocket
- _Requirements: 5.1, 5.2_
- [ ] 3.4 Fix WebSocket session leak in `src/lib/TerminalSessionContext.tsx`
- Guard `ws.close()` with readyState check (OPEN or CONNECTING)
- Capture `thisWs` reference; in `onclose`, bail if `s.ws !== thisWs`
- _Requirements: 1.1, 1.2, 1.3_
- [ ]* 3.5 Write property test for WebSocket auth gate
- **Property 5: WebSocket Auth Gate Rejects Unauthenticated Messages**
- Verify no message type other than `auth` is processed before authentication
- **Validates: Requirements 5.3, 5.4**
- [ ] 4. Checkpoint — WebSocket auth
- Ensure all tests pass, ask the user if questions arise.
- [ ] 5. Backend — tmux validation and SSH cleanup verification
- [ ] 5.1 Harden tmux session name usage in `backend/src/routes/terminal.ts`
- Ensure validated name is single-quoted in shell command construction
- Defense-in-depth: strip any `'` (impossible given regex, but belt+suspenders)
- _Requirements: 2.1, 2.2, 2.3_
- [ ] 5.2 Verify container ref validation in `backend/src/ssh/docker.ts`
- Confirm `CONTAINER_REF_RE` regex is `^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$`
- Confirm `shQuote()` is applied to all container ref interpolations
- Confirm SSH cleanup in `withSshClient` finally block is present
- If already correct (per design), add a code comment noting audit verification
- _Requirements: 3.1, 3.2, 3.3, 9.1, 9.2_
- [ ]* 5.3 Write property tests for tmux name validation and container ref validation
- **Property 1: tmux Session Name Validation Prevents Injection** — verify only `[A-Za-z0-9_-]{1,64}` passes
- **Property 2: Container Reference Validation and Safe Escaping** — verify regex and `shQuote` safety
- **Property 6: SSH Connection Cleanup Guarantee** — verify `withSshClient` always calls `.end()`
- **Validates: Requirements 2.1, 2.3, 3.1, 3.3, 9.1, 9.2**
- [ ] 6. Frontend stability fixes
- [ ] 6.1 Add `.catch()` to Sidebar promise in `src/components/Sidebar.tsx`
- Append `.catch(() => {})` to the `api.listIntegrations()` call
- Ensure integrations state remains null on failure (shows "Checking…")
- _Requirements: 4.1, 4.2_
- [ ] 6.2 Create Error Boundary component at `src/components/ErrorBoundary.tsx`
- React class component with `getDerivedStateFromError` + `componentDidCatch`
- Fallback UI: centered message + gold "Reload Page" button on dark background
- Log error to console
- _Requirements: 11.2, 11.3, 11.4_
- [ ] 6.3 Wrap Dashboard in ErrorBoundary in `src/App.tsx`
- Import and wrap the top-level Dashboard component tree
- _Requirements: 11.1_
- [ ]* 6.4 Write unit tests for ErrorBoundary and Sidebar error handling
- Verify ErrorBoundary renders fallback on child throw
- Verify Sidebar swallows rejected promise without crashing
- **Validates: Requirements 4.1, 4.2, 11.1, 11.2, 11.3, 11.4**
- [ ] 7. CloudFormation test deploy template
- [ ] 7.1 Create `infra/test-deploy.yml` CloudFormation template
- Parameters: KeyPairName (KeyPair type), NotificationEmail (String)
- Resources: SecurityGroup (SSH + HTTP/HTTPS), EC2 Instance (t4g.small, AL2023 ARM64, Docker + Compose via UserData), Budget alarm ($30/month, 80% threshold)
- Outputs: PublicIP, InstanceId
- _Requirements: 14.1, 14.2, 14.3, 14.4, 14.5, 14.6_
- [ ]* 7.2 Write smoke test validating CloudFormation template structure
- Verify required resource types, parameters, and outputs exist
- Validate YAML parses correctly
- **Validates: Requirements 14.114.6**
- [ ] 8. Final checkpoint
- Ensure all tests pass, ask the user if questions arise.
## Notes
- Tasks marked with `*` are optional and can be skipped for faster MVP
- Each task references specific requirements for traceability
- Components 3 (container ref), 9 (SSH cleanup), and 12 (JSON parse) are verified-already-correct per design — task 5.2 confirms with a code comment
- The project uses TypeScript throughout (Fastify 5 backend, React 19 frontend)
- No new dependencies are introduced; all fixes use Node.js built-ins and existing patterns
## Task Dependency Graph
```json
{
"waves": [
{ "id": 0, "tasks": ["1.1", "1.2", "1.3", "1.4", "1.5", "6.1", "6.2", "7.1"] },
{ "id": 1, "tasks": ["1.6", "6.3", "6.4", "7.2"] },
{ "id": 2, "tasks": ["3.1", "3.2", "5.1", "5.2"] },
{ "id": 3, "tasks": ["3.3", "3.4", "3.5", "5.3"] }
]
}
```