Skip to content

[hardening] Constrain TaskSchema.status with a typed enum (deferred from FORGE-100 security review) #163

@firatcand

Description

@firatcand

Follow-up to #135 (P2.5-T09) — security-auditor LOW finding deferred to a fast-follow per the auditor's own verdict.

Issue

src/schemas/phases.ts:43 (post-firatcand/forge#135 patch) introduced status: z.string().optional() on TaskSchema with no enum constraint. The current live plans/phases.yaml uses values like 'deferred-v0.5', 'dropped', 'paused', and 'active' — none of which are validated. Garbage values will pass through unnoticed and surprise any future caller that switches on task.status.

Per [[widening-shared-regex-is-security-audit-trigger]]: unconstrained shared schemas are a class of latent bug we explicitly call out.

Scope

Define a typed enum that covers the values forge actually emits, and migrate TaskSchema.status to it:

export const TASK_STATUSES = [
  'active',
  'deferred-v0.5',
  'dropped',
  'paused',
] as const;

export const TaskSchema = z.object({
  ...
  status: z.enum(TASK_STATUSES).optional(),
});

If the team adds new status values in the future (e.g. 'cancelled'), the enum must be extended in the same PR that introduces the value.

Acceptance

  • TASK_STATUSES const + matching TaskStatus type exported from src/schemas/phases.ts
  • TaskSchema.status uses z.enum(TASK_STATUSES).optional()
  • live-snapshot.yaml fixture still validates (i.e. every status value present in plans/phases.yaml is in the enum)
  • Unit test: TaskSchema rejects garbage status like 'foo'
  • No production callers regress (none currently read task.status — confirmed via grep before this ticket was filed)

Source

docs/learnings/2026-Q2/widening-shared-regex-is-security-audit-trigger.md and the #135 security audit report from 2026-05-17 PM.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions