Skip to content

setup: writeGlobalConfig serializes provider fields with wrong YAML key names #20

@materemias

Description

@materemias

Bug

nightshift setup writes provider config fields using Go struct field names (lowercased) instead of the mapstructure tag names. This causes the config to silently break — the fields are written but never read back correctly on subsequent runs.

Root Cause

In cmd/nightshift/commands/setup.go line 1920:

v.Set("providers", cfg.Providers)

When viper serializes a Go struct, it lowercases Go field names rather than using mapstructure tags. So DangerouslySkipPermissions becomes dangerouslyskippermissions in YAML, but the struct expects dangerously_skip_permissions (from mapstructure:"dangerously_skip_permissions").

Affected Fields

Go field Written as (wrong) Expected (mapstructure tag)
DataPath datapath data_path
DangerouslySkipPermissions dangerouslyskippermissions dangerously_skip_permissions
DangerouslyBypassApprovalsAndSandbox dangerouslybypassapprovalsandsandbox dangerously_bypass_approvals_and_sandbox

Impact

After running nightshift setup:

  • dangerously_skip_permissions: true is silently lost — defaults to false
  • All tasks fail with permission denials across all iterations, then get abandoned
  • Projects are marked "processed today" despite zero work being done
  • The config passes nightshift config validate (validation doesn't check field name correctness)
  • nightshift config output doesn't display the permission flags at all, making it hard to diagnose

Suggested Fix

Replace the bulk struct set with individual key sets, matching the mapstructure tags:

// Instead of: v.Set("providers", cfg.Providers)
v.Set("providers.claude.enabled", cfg.Providers.Claude.Enabled)
v.Set("providers.claude.data_path", cfg.Providers.Claude.DataPath)
v.Set("providers.claude.dangerously_skip_permissions", cfg.Providers.Claude.DangerouslySkipPermissions)
v.Set("providers.claude.dangerously_bypass_approvals_and_sandbox", cfg.Providers.Claude.DangerouslyBypassApprovalsAndSandbox)
v.Set("providers.codex.enabled", cfg.Providers.Codex.Enabled)
v.Set("providers.codex.data_path", cfg.Providers.Codex.DataPath)
v.Set("providers.codex.dangerously_skip_permissions", cfg.Providers.Codex.DangerouslySkipPermissions)
v.Set("providers.codex.dangerously_bypass_approvals_and_sandbox", cfg.Providers.Codex.DangerouslyBypassApprovalsAndSandbox)
v.Set("providers.preference", cfg.Providers.Preference)

Alternatively, use yaml struct tags alongside mapstructure tags, or use mapstructure.Decode in reverse to produce correct keys.

Reproduction

  1. Set correct field names manually in ~/.config/nightshift/config.yaml
  2. Run nightshift setup, complete the wizard
  3. Inspect config — field names are now wrong
  4. Run nightshift run — all tasks fail with permission denials

Environment

  • nightshift v0.3.2
  • Go module: github.com/marcus/nightshift@v0.3.2
  • OS: Linux (Arch)

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