Skip to content

sec-default: a managed option, allowManagedModsOnly, keeps the mods a person installs from loading - #98083

Merged
poteat merged 1 commit into
mainfrom
poteat/sec-default-managed-mods-only
Sep 29, 2026
Merged

poteat merged 1 commit into
mainfrom
poteat/sec-default-managed-mods-only

Conversation

@poteat

@poteat poteat commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

TLDR: an organization can allow its own mods while refusing the ones a person installs, with one managed option.

We add allowManagedModsOnly, read from managed settings under sec-default's own pluginConfigs entry; while set, it refuses every user-tier hooks module at plugin.register.

Notes

  • re why: disableAllHooks, and turning hooks modules off, also stop the organization's own mods, and allowManagedHooksOnly also stops a person's settings hooks and status line. This option touches a person's mods alone.
  • It decides by the tier the CLI pins on the module, never a name or path the module supplies, and reads the policy source only: a person's, a project's or a --settings file neither sets nor loosens it. On unless absent or false; a value the settings schema rejects (null) makes the CLI drop the whole pluginConfigs key with a settings warning, and the option reads as unset.
  • Refused means nothing of the module joins: no hook, tool or command. Its top-level code has run once by then, in the closed context every hooks module is evaluated in, with no call on $ served; the loader admits after it evaluates today and we leave that as it is.
  • Failure: when the policy read is refused or the hook errors, its .catch refuses the module and names the error in the debug log. If sec-default does not answer at all (not seated, e.g. managed prependPlugins leaves it out), mods load as they do today; accepted. Set mid-session, a running mod runs on until its next reload.
  • The hook reads policy once per person's mod at load, so the existing tests that load a person's plugin now answer settings.read.
  • This PR's test check is expected red for now: it needs a published CLI whose claude plugin test loads a test's own hooks before the plugins it judges, and is re-run once that release is out.
  • Out of scope: the integrity of a managed mod's files on disk; claude plugin test (it loads nothing into a session).
  • Follow-ups, not here: a stderr line for a refused --plugin-dir mod under -p; a refusal shown on screen for an installed mod (today: where the session hot-reloads the folder, else the debug log).
  • A sibling PR reads a second option through the same reader (hooks/policy/own-option); the second to land merges identical files.

Test Plan

  • Set the option in managed settings and start claude --plugin-dir on a small mod: its hooks never run, and one line names the mod and the option.
  • Remove the option: the same mod loads.
  • Set the option only in your own ~/.claude/settings.json: the mod still loads.
  • claude plugin test mods/sec-default is green.

Revert-proof: 4 new tests fail on base with the fix reverted (claude plugin test mods/sec-default with the plugin.register row removed; with only its .catch removed the unreadable-policy test alone fails; with a merged read in place of the policy source the two scope tests fail)

Changelog

@poteat
poteat enabled auto-merge (squash) September 29, 2026 07:38
@poteat
poteat disabled auto-merge September 29, 2026 07:47
@poteat
poteat enabled auto-merge (squash) September 29, 2026 15:33
@poteat
poteat merged commit 0d7f14d into main Sep 29, 2026
1 of 2 checks passed
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