Skip to content

[BUG] Sandbox carve-out for ~/.infer/skills is conditional — move skills dirs into default Sandbox.Directories #577

@edenreich

Description

@edenreich

Summary

Follow-up to #569 / #571 (shipped in v0.117.0). The sandbox carve-out for ~/.infer/skills and ./.infer/skills is currently conditional on c.Agent.Skills.Enabled being true at ValidatePathInSandbox time (config/config.go:1041). When that flag isn't set — running with default config, before infer config agent skills enable has run, or when the INFER_AGENT_SKILLS_ENABLED override hasn't reached the validator — the carve-out silently does not fire and reads of SKILL.md are denied with outside configured sandbox directories.

Skills directories are a well-known, read-only allowlist under ~/.infer/. Gating their sandbox visibility on a runtime feature flag re-introduces the failure mode #569 was meant to remove.

Proposed fix

Move the skills directories into the default Sandbox.Directories in DefaultConfig() (config/config.go:619-625), unconditionally:

// resolve user-scope skills dir at config-build time
homeDir, _ := os.UserHomeDir()
dirs := []string{".", "/tmp", ConfigDirName + "/tmp", ConfigDirName + "/skills"}
if homeDir != "" {
    dirs = append(dirs, filepath.Join(homeDir, ConfigDirName, "skills"))
}

Sandbox: SandboxConfig{
    Directories:    dirs,
    ProtectedPaths: []string{ConfigDirName + "/", ".git/", "*.env"},
},

Then drop the isWithinSkillsDir-gated branch of the carveOut expression in ValidatePathInSandbox (lines 1041-1050). Keep isWithinConfigSubdir(absPath, "tmp", "plans") — that's an orthogonal carve-out for project .infer/{tmp,plans} and unrelated to skills.

Protected-paths interaction

protected_paths: [.infer/] will currently match ~/.infer/skills/foo/SKILL.md via the substring/prefix logic in checkProtectedPaths (config/config.go:1127-1149). Two options:

  1. Recognize an explicit, more-specific Sandbox.Directories entry (e.g. ~/.infer/skills) as an override of a broader protected_paths entry (.infer/). Generalizes today's carveOut-skip-.infer/ trick at line 1131 into something declarative.
  2. Add an isWithinSkillsDir(absPath) short-circuit in checkProtectedPaths (always allow, no flag) — narrower but simpler than option 1.

Either way, the agent's Read of SKILL.md and references/*.md succeeds with default config; ~/.infer/config.yaml, ~/.infer/conversations.db, etc. remain protected because they're outside skills/.

Why this is better than the v0.117.0 carve-out

  • One source of truth for what is readable: Sandbox.Directories. No second runtime predicate to keep in sync.
  • agent.skills.enabled goes back to meaning exactly "load skill metadata into the prompt and offer them to the agent" — purely about discovery/loading, no sandbox semantics.
  • No env-var plumbing required from infer-action or any other consumer: INFER_AGENT_SKILLS_ENABLED=true becomes optional for reading (still useful for enabling skill loading).
  • Behavior is identical across chat, infer agent, channels, and heartbeat — no per-mode flag drift.

Repro

Failed run that prompted this: @infer on inference-gateway/adl (2026-06-02), CLI v0.116.0 via inference-gateway/.github@v0.4.1's pin. v0.116.0 has no carve-out at all, so this exact failure is also resolved by the centralized workflow bumping its cli-version to v0.117.0+ — but the conditional design means even after that bump the failure can re-appear if agent.skills.enabled isn't true at validation time.

Tests

Update config/config_test.go:

  • New: ValidatePathInSandbox of ~/.infer/skills/foo/SKILL.md succeeds with DefaultConfig() and Agent.Skills.Enabled = false.
  • New: same for ./.infer/skills/foo/SKILL.md.
  • New: ~/.infer/config.yaml and ~/.infer/conversations.db still rejected (protected-paths still applies).
  • Remove or rewrite the existing isWithinSkillsDir / agent.skills.enabled-gated cases.

Follow-up

Once this lands and a new CLI is cut:

  • inference-gateway/infer-action — bump inputs.version.default in action.yml to the new CLI release.
  • inference-gateway/.github — bump cli-version default in the centralized infer workflow (currently v0.116.0) so existing consumers like adl pick up the fix.

[DOCS] ticket: a one-line update to the skills/sandbox doc explaining that skills dirs are read-allowed by default (no flag required).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingreleased

    Type

    No fields configured for Bug.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions