Skip to content

feat(cli): add auth verification + password policy to insforge.toml#127

Merged
tonychang04 merged 6 commits into
mainfrom
feat/insforge-toml-auth-policy
May 14, 2026
Merged

feat(cli): add auth verification + password policy to insforge.toml#127
tonychang04 merged 6 commits into
mainfrom
feat/insforge-toml-auth-policy

Conversation

@tonychang04
Copy link
Copy Markdown
Contributor

@tonychang04 tonychang04 commented May 14, 2026

Summary

Extends config-as-code to cover the rest of the auth.config row that the SMTP work depends on — declaratively configure verification flows + password policy.

Stacked on top of #123 (the SMTP / deployments PR). Merge that first; this is a clean fast-forward after.

New TOML surface

```toml
[auth]
require_email_verification = true
verify_email_method = "link" # "code" | "link"
reset_password_method = "code"

[auth.password]
min_length = 12
require_number = true
require_lowercase = true
require_uppercase = true
require_special_char = true
```

Design notes

  • Per-key DiffChange variants (not whole-object like SMTP) — a partial `[auth.password]` block only touches the fields it names, preserving the rest of live state. True default-keep semantics.
  • Per-field capability gating — each field probes its own `/api/metadata` key, so a backend that exposes the policy piecemeal still applies the supported subset rather than failing the whole batch.
  • Single endpoint, per-key PUTs — all eight new fields route through `PUT /api/auth/config`. Idempotent and fast; keeps each change independently capability-gated.
  • No OSS backend work needed — `authConfigAdminResponseSchema` already spreads every field on `/api/metadata`, and `updateAuthConfigRequestSchema = authConfigSchema.omit(...).partial()` already accepts them on the PUT side.

Drive-by fix

Extracted `liveFromMetadata` into `src/lib/config-metadata.ts` so apply/plan/export agree on the live shape. Fixes a latent bug where `plan.ts` only read `allowedRedirectUrls` from metadata — SMTP/deployments/new-field diffs in the plan output would have shown false positives.

Test plan

  • `vitest run` — 343/343 pass (~30 new tests across config-diff, config-toml, config-capabilities, export)
  • `tsc --noEmit` — clean on every touched file (one pre-existing prompts.ts error remains, unrelated)
  • `eslint src/lib/config-.ts src/commands/config/.ts src/lib/config-metadata.ts` — clean
  • `tsup` build — clean
  • Manual: `insforge config export` against a real backend, hand-edit `[auth.password]`, `insforge config plan`, `apply` — verify per-key apply semantics

🤖 Generated with Claude Code


Summary by cubic

Adds auth verification flags and password policy to insforge.toml with per-field diffs and applies. Centralizes metadata handling and hardens parsing to prevent crashes, bogus diffs, and false skips.

  • New Features

    • [auth]: require_email_verification, verify_email_method ("code" | "link"), reset_password_method ("code" | "link").
    • [auth.password]: min_length, require_number, require_lowercase, require_uppercase, require_special_char; per-key diffs and idempotent per-field PUT /api/auth/config using a centralized wire-key map; capability-gated via flat /api/metadata keys.
    • Export uses shared config-metadata to emit only supported fields; unknown enum values are dropped.
  • Bug Fixes

    • Shared liveFromMetadata + configFromMetadata keep plan/export/apply in sync and fix plan false positives.
    • Defensive parsing: coerce wrong-shaped allowedRedirectUrls to []; treat smtpConfig: null as supported-but-empty; shape-guard deployments.customSlug (non-strings → null) to avoid bogus diffs.
    • Explicit key-existence checks for verify_email_method and reset_password_method avoid silent mismatches when live is missing.

Written for commit c4e086e. Summary will update on new commits.

Note

Add auth verification flags and password policy support to insforge.toml

  • Extends the insforge.toml schema with require_email_verification, verify_email_method, reset_password_method, and an [auth.password] sub-table (with min_length and require_* boolean fields).
  • Updates config plan, config apply, and config export to diff, apply, and emit these new fields by issuing PUT /api/auth/config with the relevant fields.
  • Centralizes live-state projection and export logic into new liveFromMetadata and configFromMetadata helpers in config-metadata.ts, removing duplicated inline implementations from each command.
  • Adds capability probing in config-capabilities.ts so unsupported fields are skipped when the backend lacks them.
  • Behavioral Change: config plan now diffs additional live fields; backends missing these fields default to false (verification flag) or 'code' (method fields) rather than being ignored.

Changes since #127 opened

  • Added asStringArray utility function and updated liveFromMetadata and configFromMetadata functions to coerce wrong-shaped allowedRedirectUrls values to empty arrays [78325f8]
  • Updated liveFromMetadata and configFromMetadata functions to only populate SMTP configuration blocks when smtpConfig is a plain object, treating null values as absent [78325f8]
  • Added test coverage for allowedRedirectUrls coercion and smtpConfig null-handling in both liveFromMetadata and configFromMetadata functions [78325f8]
  • Modified liveFromMetadata function in config-metadata to validate deployments.customSlug type and value, ensuring deployments.subdomain is set to null unless customSlug is a non-empty string, and added corresponding test coverage for non-string input scenarios [c4e086e]

Macroscope summarized 8b22aa2.

Summary by CodeRabbit

  • New Features

    • Email verification controls (require flag, selection of verification/reset method)
    • Password policy customization (min length and per-character requirements) and dedicated password subtable in exports
    • Exports/plans/applies now use richer backend metadata to show supported/unsupported fields and emit deterministic TOML (SMTP password exported as env placeholder)
  • Tests

    • Expanded coverage for auth fields, password-policy diffs, metadata projections, capability probing, and TOML parse/stringify

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

Walkthrough

Adds a new metadata mapping module that projects raw /api/metadata into CLI LiveConfig and InsforgeConfig shapes, expands auth config (verification flags, reset/verify methods, password policy), wires those projections into config plan/export/apply flows, and updates diffs, TOML parsing/stringifying, capability probing, and tests accordingly.

Changes

Auth + Metadata projection and CLI config flow

Layer / File(s) Summary
Metadata projection layer
src/lib/config-metadata.ts, src/lib/config-metadata.test.ts
New RawAuthMetadata / RawMetadataResponse types and exported liveFromMetadata(raw) / configFromMetadata(raw) that safely map raw /api/metadata into LiveConfig and InsforgeConfig (TOML-ready) and return skipped fields; comprehensive tests for full/partial/malformed inputs, enum filtering, password defaults, SMTP and deployments customSlug handling.
Capability probing & wire-key mapping
src/lib/config-capabilities.ts, src/lib/config-capabilities.test.ts
Refactors metadataSupports to runtime key-presence checks via hasAuthKey; adds AUTH_PASSWORD_WIRE_KEY mapping and exported authPasswordWireKey() used to translate [auth.password] TOML keys to backend wire keys; tests for presence-based probes and auth.password per-field support.
Diffing and live model updates
src/lib/config-diff.ts, src/lib/config-diff.test.ts
Extends DiffChange and LiveConfig with require_email_verification, verify_email_method, reset_password_method, and per-field auth.password.*; adds diffPassword and EMPTY_PASSWORD_POLICY for deterministic per-field password diffs; tests for verification flags and granular password diff behaviors.
TOML schema & parsing/validation
src/lib/config-schema.ts, src/lib/config-toml.ts, src/lib/config-toml.test.ts
Adds VerificationMethod and PasswordConfig to schema; extends validateAuth and adds validateVerificationMethod/validatePassword; stringifyConfigToml now renders flat auth fields and a conditional [auth.password] subtable; tests added/updated for parsing and stringify round-trip.
CLI command wiring (apply/export/plan)
src/commands/config/apply.ts, src/commands/config/export.ts, src/commands/config/plan.ts, src/commands/config/export.test.ts
apply/plan now use liveFromMetadata(raw: RawMetadataResponse) from config-metadata; export uses configFromMetadata(raw) returning {config, skipped}; applyChange gains handlers for require_email_verification, verify_email_method, reset_password_method, and auth.password (uses authPasswordWireKey to build PUT body); tests updated to expect expanded skipped lists.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • InsForge/CLI#123: Related changes extending the config apply/capability plumbing and auth.* handling.
  • InsForge/CLI#109: Earlier PR wiring config export/plan/apply; this PR builds on that metadata-driven approach.

Suggested reviewers

  • jwfing

Poem

🐰 I hopped through metadata, sniffed each key,
Found passwords, SMTP, and flags for me,
I map the raw, skip what's not shown,
Emit neat TOML, defaults well-known,
A tiny rabbit, tidy configs — whee!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately summarizes the main changes: adding auth verification and password policy configuration to insforge.toml.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/insforge-toml-auth-policy

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 12 files

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 14, 2026

Greptile Summary

This PR extends insforge.toml with email verification flags (require_email_verification, verify_email_method, reset_password_method) and a new [auth.password] sub-table, and centralizes all /api/metadata → live-state projection into a single new config-metadata.ts module so that apply, plan, and export agree on field presence.

  • New TOML surface: three flat [auth] verification fields and five [auth.password] policy fields, each independently capability-gated and applied via individual PUT /api/auth/config payloads to support partial backend rollouts.
  • Centralized metadata projection: liveFromMetadata and configFromMetadata in config-metadata.ts replace three divergent inline implementations, fixing the latent false-positive bug in plan.ts that was only reading allowedRedirectUrls from metadata.
  • Defensive parsing hardened: non-object auth slices, wrong-typed allowedRedirectUrls, smtpConfig: null (supported-but-empty), and non-string customSlug values are all coerced gracefully rather than crashing commands.

Confidence Score: 5/5

Safe to merge; all new auth/password fields route through well-tested, capability-gated code paths with correct wire-key mappings and defensive null handling.

The centralization of metadata projection into config-metadata.ts is clean and the new per-field diff/apply/export logic is thorough and well-tested (343 passing tests). The only finding is a type-level inaccuracy in RawAuthMetadata.smtpConfig — the runtime handling via isPlainObject() is correct everywhere the field is read.

src/lib/config-metadata.ts — the smtpConfig nullable type gap is worth fixing before this module grows further.

Important Files Changed

Filename Overview
src/lib/config-metadata.ts New file — single source of truth for /api/metadata projection; logic is correct but RawAuthMetadata.smtpConfig is typed as non-nullable while the API and tests both show it can be null
src/lib/config-diff.ts Adds DiffChange variants for verification flags and per-key password policy; diffPassword correctly implements default-keep semantics with EMPTY_PASSWORD_POLICY fallback
src/lib/config-capabilities.ts Refactored to use hasAuthKey helper; adds per-field capability probing for all new auth/password fields using centralized AUTH_PASSWORD_WIRE_KEY map
src/lib/config-schema.ts Adds VerificationMethod union, PasswordConfig interface, and validators; min_length bounds (4–128) and boolean presence-checks look correct
src/commands/config/apply.ts Adds applyChange branches for three new auth fields and auth.password using centralized authPasswordWireKey; each dispatches a separate PUT /api/auth/config with correct wire-key bodies
src/commands/config/plan.ts Minimal change: swaps the inline metadata cast for liveFromMetadata, fixing the false-positive plan output that previously only diffed allowedRedirectUrls
src/commands/config/export.ts Replaces 60 lines of inline field-detection logic with a single configFromMetadata call, resolving the previously-noted duplication concern
src/lib/config-toml.ts Adds renderAuthFlatFields and renderPasswordFields helpers; TOML section ordering updated to auth → auth.password → auth.smtp → deployments

Sequence Diagram

sequenceDiagram
    participant CLI
    participant apply.ts
    participant plan.ts
    participant export.ts
    participant config-metadata.ts
    participant Backend

    CLI->>Backend: GET /api/metadata
    Backend-->>CLI: RawMetadataResponse

    alt config apply
        CLI->>apply.ts: applyCommand()
        apply.ts->>config-metadata.ts: liveFromMetadata(raw)
        config-metadata.ts-->>apply.ts: LiveConfig
        apply.ts->>apply.ts: "diffConfig({live, file})"
        loop each DiffChange (capability-gated)
            apply.ts->>Backend: "PUT /api/auth/config {field: value}"
        end
    else config plan
        CLI->>plan.ts: planCommand()
        plan.ts->>config-metadata.ts: liveFromMetadata(raw)
        config-metadata.ts-->>plan.ts: LiveConfig
        plan.ts->>plan.ts: "diffConfig({live, file})"
        plan.ts-->>CLI: formatted plan output
    else config export
        CLI->>export.ts: exportCommand()
        export.ts->>config-metadata.ts: configFromMetadata(raw)
        config-metadata.ts-->>export.ts: "{config, skipped[]}"
        export.ts-->>CLI: insforge.toml written
    end
Loading

Reviews (5): Last reviewed commit: "fix(config-metadata): shape-guard custom..." | Re-trigger Greptile

Comment thread src/lib/config-diff.ts Outdated
Comment thread src/commands/config/export.ts Outdated
jwfing
jwfing previously approved these changes May 14, 2026
Copy link
Copy Markdown
Member

@jwfing jwfing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, approved.

Copy link
Copy Markdown
Member

@jwfing jwfing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — feat(cli): add auth verification + password policy to insforge.toml

Summary: Well-structured extension of the config-as-code surface — per-key gating, default-keep semantics, and the liveFromMetadata centralisation are all solid design calls. No blocking issues found.


Requirements context

No /docs/superpowers/ directory exists in this repo. Review assessed against the PR description, stacked-on PR #123, and the inline design notes.


Findings

Critical

(none)


Suggestion

[Software Engineering] config-metadata.ts has no dedicated unit tests

liveFromMetadata (src/lib/config-metadata.ts:52-113) is the new single source of truth that both apply.ts and plan.ts route through — and the PR description correctly calls out that the old plan.ts had a latent bug that this fixes. Yet the 30 new tests are spread across config-diff, config-toml, config-capabilities, and export; none target liveFromMetadata directly.

The function has non-trivial edge cases:

  • Presence-based detection of the password block ('passwordMinLength' in a || 'requireNumber' in a || …)
  • Type-narrowing guards on verifyEmailMethod/resetPasswordMethod that silently fall back when the value is not 'code' | 'link'
  • The per-field ?? default fallback for partial backend exposure

A dedicated config-metadata.test.ts covering at least: full payload, partial auth (password only), legacy backend (no auth fields), and an unexpected verifyEmailMethod value would lock in the correctness guarantee the PR claims.


[Functionality] export.ts does not call liveFromMetadata — the centralisation is incomplete for export

apply.ts and plan.ts both now route through liveFromMetadata. export.ts (src/commands/config/export.ts:56-134) has its own parallel projection. This is semantically defensible (export builds a TOML file rather than a diff baseline), but the PR description says "apply/plan/export agree on the live shape" — which is only two-thirds true.

The practical risk: if a field mapping is corrected in liveFromMetadata, the export path won't benefit automatically. The field-presence semantics between the two paths are consistent right now, but they could silently diverge as new fields are added. Worth at least a comment in export.ts noting the intentional divergence, or a future consolidation task.


[Functionality] Unknown enum values from a future backend are silently skipped and misreported

In both export.ts:69-80 and liveFromMetadata (config-metadata.ts:66-77), a verifyEmailMethod or resetPasswordMethod value that is not 'code' or 'link' causes the field to be treated as absent:

// export.ts
if (authObj && 'verifyEmailMethod' in authObj &&
    (authObj.verifyEmailMethod === 'code' || authObj.verifyEmailMethod === 'link')) {
  config.auth.verify_email_method = authObj.verifyEmailMethod;
} else {
  skipped.push('auth.verify_email_method');  // ← also fires for unexpected values
}

If a future backend ships a new method value (e.g. 'otp'), export would list the field as skipped (misleading — the backend does support it), and liveFromMetadata would leave verify_email_method as undefined, causing diffConfig to default the live value to 'code'. A user with verify_email_method = 'link' in their TOML would then see a false diff and apply would overwrite the backend's actual value.

Low probability today, but it's worth an inline comment explaining why unknown values fall back rather than being passed through, so a future maintainer adding a new enum value knows to update the CLI first.


Information

[Software Engineering] Exhaustiveness check is only in applyChange, not in metadataSupports

applyChange correctly ends with const _exhaustive: never = change (apply.ts:215). metadataSupports (config-capabilities.ts:42-83) ends with return false for unrecognised changes. Both are correct given their contracts (false-safe fallback for capabilities, hard error for apply). Just noting for visibility — the asymmetry is intentional and fine.


[Performance] Sequential PUTs for multi-field password policy

A TOML block that changes all five [auth.password] fields issues five sequential PUT /api/auth/config requests. These are administrative, low-frequency operations, so this is not a problem in practice. If latency ever becomes noticeable, the backend's partial-body PUT already supports sending multiple fields in one call — the CLI could batch them. Not worth changing now.


Verdict

approved (informational — no Critical findings). The implementation is correct, the capability-gating model is coherent, and the test coverage for the new TOML surface is solid. The two Suggestion items (missing config-metadata.ts unit tests and the incomplete centralisation in export) are the most actionable follow-ups before this pattern scales to more fields.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/commands/config/export.ts">

<violation number="1" location="src/commands/config/export.ts:52">
P2: `configFromMetadata(raw)` can crash on malformed metadata because it assumes `raw.auth` is an object before using `'in'` checks. This makes `config export` less robust against unexpected API payloads.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread src/commands/config/export.ts
@tonychang04 tonychang04 changed the base branch from feat/insforge-toml-smtp to main May 14, 2026 20:38
@tonychang04 tonychang04 dismissed jwfing’s stale review May 14, 2026 20:38

The base branch was changed.

tonychang04 and others added 4 commits May 14, 2026 13:38
Extends config-as-code to cover the auth.config row beyond redirect URLs:

- [auth] adds require_email_verification + verify_email_method +
  reset_password_method as direct keys
- [auth.password] block: min_length + require_number / require_lowercase /
  require_uppercase / require_special_char

Per-key DiffChange variants give true default-keep semantics — a partial
[auth.password] block only touches the fields it names. All eight new
fields route through the existing PUT /api/auth/config endpoint with
per-key idempotent PUTs and per-field capability gating, so a backend
that exposes them piecemeal still applies the supported subset.

Also extracts liveFromMetadata into a shared lib/config-metadata.ts so
apply / plan / export agree on the live shape — fixes a latent plan.ts
bug that only read allowedRedirectUrls.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Use 'key' in fileAuth presence-check for verify_email_method and
  reset_password_method, matching the established pattern (truthy check
  happens to work today but would silently misbehave on a hypothetical
  future enum value)
- Extract configFromMetadata into config-metadata.ts so export.ts shares
  the same field-presence detection as liveFromMetadata — adding a new
  field now touches one place rather than risking silent drift
- Add config-metadata.test.ts covering full / partial / legacy / unknown-
  enum response shapes for both functions
- Add inline comment explaining why unknown enum values fall back to
  "skipped" (parser would reject them on next apply, so we can't
  round-trip them)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ents

cubic flagged that configFromMetadata could crash on a malformed
metadata response — `'key' in primitive` throws TypeError, so a
backend bug returning auth: "string" would take down `config export`.
Guard both slices through isPlainObject() before reading any key,
treating wrong-shaped input as "field not exposed" so the command
degrades gracefully.

Same guard applied to liveFromMetadata for symmetry; both paths now
have test coverage for string/number/null/array auth slices.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bind raw.deployments to a local before the predicate check so TS can
narrow it past `... | undefined`. Constrain the helper's type
parameter to `extends object` so callers without an explicit type
context still get a useful narrowing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@tonychang04 tonychang04 force-pushed the feat/insforge-toml-auth-policy branch from 0663ddf to 8b22aa2 Compare May 14, 2026 20:39
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/lib/config-metadata.test.ts (1)

95-103: ⚡ Quick win

Add malformed inner-field regression cases for metadata projection.

Current malformed tests only cover non-object auth. Add cases like allowedRedirectUrls: 123 (and similar wrong inner types) to lock defensive behavior and prevent crash regressions.

Also applies to: 187-194

🤖 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 `@src/lib/config-metadata.test.ts` around lines 95 - 103, Add additional
malformed-inner-field cases to the metadata projection tests so non-object inner
fields don't crash; in the test that calls liveFromMetadata (the 'treats a
malformed auth slice as absent...' case) include examples where object fields
contain wrong primitive types (e.g., { auth: { allowedRedirectUrls: 123 } }, {
auth: { clientIds: "bad" } } etc.) and assert the function returns the safe
projected form (e.g., auth: { allowedRedirectUrls: [], clientIds: [] } or an
empty object as appropriate). Repeat the same pattern for the other test block
that uses liveFromMetadata referenced later (the similar test around lines
187-194) so both slices and inner fields are guarded against malformed types.
Ensure assertions reflect the expected defensive defaults from the projection
logic.
🤖 Prompt for all review comments with 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.

Inline comments:
In `@src/lib/config-metadata.ts`:
- Around line 65-67: The assignment to live.auth!.allowed_redirect_urls in
src/lib/config-metadata.ts trusts a.allowedRedirectUrls shape and can crash
later; update the logic (both where allowedRedirectUrls is set at the shown
block and the similar block at lines 149-152) to validate that
a.allowedRedirectUrls is an array of strings before assigning it to
live.auth!.allowed_redirect_urls (e.g., check Array.isArray and typeof elements
=== 'string'), and otherwise assign a safe fallback (empty array or undefined)
so downstream calls like normalizeUrlList/TOML rendering won't throw.

---

Nitpick comments:
In `@src/lib/config-metadata.test.ts`:
- Around line 95-103: Add additional malformed-inner-field cases to the metadata
projection tests so non-object inner fields don't crash; in the test that calls
liveFromMetadata (the 'treats a malformed auth slice as absent...' case) include
examples where object fields contain wrong primitive types (e.g., { auth: {
allowedRedirectUrls: 123 } }, { auth: { clientIds: "bad" } } etc.) and assert
the function returns the safe projected form (e.g., auth: { allowedRedirectUrls:
[], clientIds: [] } or an empty object as appropriate). Repeat the same pattern
for the other test block that uses liveFromMetadata referenced later (the
similar test around lines 187-194) so both slices and inner fields are guarded
against malformed types. Ensure assertions reflect the expected defensive
defaults from the projection logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 054afdfb-5de8-4333-8766-94fce0c655d7

📥 Commits

Reviewing files that changed from the base of the PR and between 601f8d6 and 8b22aa2.

📒 Files selected for processing (13)
  • src/commands/config/apply.ts
  • src/commands/config/export.test.ts
  • src/commands/config/export.ts
  • src/commands/config/plan.ts
  • src/lib/config-capabilities.test.ts
  • src/lib/config-capabilities.ts
  • src/lib/config-diff.test.ts
  • src/lib/config-diff.ts
  • src/lib/config-metadata.test.ts
  • src/lib/config-metadata.ts
  • src/lib/config-schema.ts
  • src/lib/config-toml.test.ts
  • src/lib/config-toml.ts

Comment thread src/lib/config-metadata.ts Outdated
@tonychang04
Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai please re-review after rebase onto main + minor narrowing fix

@cubic-dev-ai
Copy link
Copy Markdown

cubic-dev-ai Bot commented May 14, 2026

@cubic-dev-ai please re-review after rebase onto main + minor narrowing fix

@tonychang04 I have started the AI code review. It will take a few minutes to complete.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 13 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/lib/config-metadata.ts">

<violation number="1" location="src/lib/config-metadata.ts:214">
P2: `configFromMetadata` incorrectly marks `auth.smtp` as unsupported when `smtpConfig` is present but null; this diverges from the repository’s presence-based capability checks and can produce incorrect export/skipped output.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread src/lib/config-metadata.ts Outdated
CodeRabbit (Major) flagged that allowedRedirectUrls was assigned without
shape validation — a backend returning a string instead of an array
would crash normalizeUrlList on the diff path. Coerce non-array values
to [] in both projections via a new asStringArray helper; wrong-shaped
values still count as "supported" since the key was present.

cubic (P2) flagged that configFromMetadata used a truthy check on
smtpConfig, so smtpConfig: null (legitimate "supported but blank"
signal) was incorrectly reported as unsupported. Switch to a presence-
based check matching metadataSupports() in config-capabilities.ts: emit
the [auth.smtp] block only when there's real data, but keep the field
out of the skipped[] list when the key exists with a null value.

liveFromMetadata gets the same isPlainObject guard on smtpConfig for
symmetry — the diff layer's empty-state defaults already cover the
no-row case.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@src/lib/config-metadata.ts`:
- Around line 126-128: liveFromMetadata() currently assigns
live.deployments.subdomain directly from raw.deployments.customSlug which can be
a non-string; validate that raw.deployments (d) has a string and non-empty
customSlug before assigning. Change the assignment in liveFromMetadata so it
sets live.deployments = { subdomain: typeof d.customSlug === 'string' &&
d.customSlug.trim() ? d.customSlug : null } (mirroring the guard used in
configFromMetadata()), ensuring malformed numeric or empty values degrade to
null.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 485532ee-eb3d-4701-90c4-1be945604d2a

📥 Commits

Reviewing files that changed from the base of the PR and between 8b22aa2 and 78325f8.

📒 Files selected for processing (2)
  • src/lib/config-metadata.test.ts
  • src/lib/config-metadata.ts

Comment thread src/lib/config-metadata.ts Outdated
CodeRabbit (Major): liveFromMetadata trusted deployments.customSlug
without a type check. A malformed payload like { customSlug: 123 }
would leak a number into live.deployments.subdomain, producing
nonsense diffs against the file's string-typed subdomain. Mirror the
string-shape guard already in configFromMetadata: non-string or empty
values degrade to null.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@jwfing jwfing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Well-scoped extension of the config-as-code surface: adds auth verification flags and password policy to insforge.toml, centralises the metadata projection that was previously duplicated across apply/plan/export, and ships with solid test coverage across all the new library layers.

Requirements context

No matching spec/plan found under /docs/superpowers/ — that directory does not exist in this repo. Assessment is against the PR description and linked design notes alone.


Findings

Critical

(none)


Suggestion

[Software Engineering] apply.test.ts not updated for the new dispatch branchessrc/commands/config/apply.ts:135-173

The existing apply.test.ts tests allowedRedirectUrls, auth.smtp, and deployments.subdomain by asserting the exact PUT endpoint and body. The four new branches added in this PR (require_email_verification, verify_email_method, reset_password_method, and the auth.password dispatch via authPasswordWireKey) have no equivalent coverage.

The risk: a wire-key typo (e.g. requireEmailVerifcation) or wrong endpoint would pass all existing tests undetected. The authPasswordWireKey path is indirectly validated by config-capabilities.test.ts, but the applyChange call-site that wraps it is not. The test harness is already in place and the pattern is clear — each new branch deserves a test that asserts the PUT body matches the expected camelCase key.


[Software Engineering] Truthy guard after in-check on verify_email_method / reset_password_methodsrc/lib/config-diff.ts:211,227

if (fileAuth && 'verify_email_method' in fileAuth && fileAuth.verify_email_method) {

After 'verify_email_method' in fileAuth, TypeScript narrows fileAuth.verify_email_method to VerificationMethod (non-optional 'code' | 'link'), so the trailing truthy guard is always true — the validator rejects empty strings at parse time. The inline comment acknowledges this awkwardness. Using !== undefined instead would be consistent with the require_email_verification branch immediately above and removes the "happens to work" fragility if VerificationMethod is ever extended.


Information

[Process] PR is stacked on #123 — merge order dependency

The PR description explicitly notes "Merge [#123] first; this is a clean fast-forward after." The base branch is main. Confirm #123 is merged before merging this one, or rebase and update the description.


[Software Engineering] EMPTY_PASSWORD_POLICY defaults must stay in sync with backend authConfigSchemasrc/lib/config-diff.ts:418-425

const EMPTY_PASSWORD_POLICY: LivePasswordPolicy = {
  min_length: 8,
  require_number: false,
  ...
};

The comment already calls this out. A drift between this constant and the backend's actual defaults would cause a spurious diff on every first config plan against a fresh project. Consider adding a pointer to the shared-schemas package version (or a TODO with the issue number) so a future maintainer knows where to look if the backend defaults ever change.


Verdict

approved (informational — explicit GitHub approval is a separate human action)

No critical findings. The two Suggestions are worth addressing before this lands, particularly the apply.test.ts gap, but neither blocks the correctness of the feature as shipped. The centralization of liveFromMetadata / configFromMetadata is a clear win — it closes a real plan false-positive bug and makes future field additions a single-file change.

Copy link
Copy Markdown
Member

@jwfing jwfing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, approved.

@tonychang04 tonychang04 merged commit 699d0ed into main May 14, 2026
4 checks passed
@tonychang04 tonychang04 deleted the feat/insforge-toml-auth-policy branch May 14, 2026 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants