Skip to content

fix(cli): fail closed when permissions.yaml is unreadable - #13467

Open
gokay-ai wants to merge 3 commits into
continuedev:mainfrom
gokay-ai:fix/permissions-yaml-fail-closed-13461
Open

gokay-ai wants to merge 3 commits into
continuedev:mainfrom
gokay-ai:fix/permissions-yaml-fail-closed-13461

Conversation

@gokay-ai

@gokay-ai gokay-ai commented Nov 6, 2026

Copy link
Copy Markdown

Description

~/.continue/permissions.yaml is how users mark tools as ask / exclude. When that file exists but cannot be parsed (syntax error, wrong value type, unknown key), the loader previously returned the same null as for a missing file. In headless / CI (cn -p) the remaining defaults then allow Bash and *, so a typo silently unlocks tools the user had put behind confirmation.

This change makes loading tri-state (absent / valid / unreadable):

  • unreadable → resolvePermissionPrecedence inserts a fail-closed { tool: "*", permission: "ask" } ahead of defaults (first match wins, so headless Bash/*: allow cannot unlock execution).
  • addPolicyToYaml refuses to rewrite the file from an empty config when unreadable, so a later "always allow" choice cannot permanently drop the remaining rules.

Fixes #13461

Testing

cd extensions/cli
npx vitest run src/permissions/permissionsYamlFailClosed.test.ts \
  src/permissions/permissionsYamlLoader.test.ts \
  src/permissions/precedenceResolver.test.ts \
  src/permissions/policyWriter.test.ts

36 tests passed (7 new fail-closed cases covering absent / valid / invalid structure / YAML parse error / headless unlock prevention / valid ask still applied / writer refusal).

Checklist

  • Concise title / description
  • Linked issue
  • Tests added / updated

When ~/.continue/permissions.yaml exists but cannot be parsed, the CLI
previously treated that the same as a missing file and fell through to
the permissive headless defaults (Bash/*: allow). A typo or truncated
write therefore silently unlocked tools the user had put behind ask.

Make the loader tri-state (absent / valid / unreadable). On unreadable,
resolvePermissionPrecedence inserts a fail-closed "*": ask policy ahead
of defaults, and addPolicyToYaml refuses to rewrite the file from an
empty config so remaining rules are not permanently dropped.

Fixes continuedev#13461

Signed-off-by: GokayAI <60583610+gokay-ai@users.noreply.github.com>
@gokay-ai
gokay-ai requested a review from a team as a code owner November 6, 2026 10:30
@gokay-ai
gokay-ai requested review from sestinj and a balanced review from Copilot and removed request for a team November 6, 2026 10:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

Signed-off-by: GokayAI <60583610+gokay-ai@users.noreply.github.com>
eslint import/order requires newlines-between builtin and external.

Signed-off-by: GokayAI <60583610+gokay-ai@users.noreply.github.com>

This branch has not been deployed

No deployments
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.

Security: an invalid permissions.yaml is treated as "no policy file", so a command set to ask runs without confirmation in headless/CI

2 participants