Commit Graph

10 Commits

Author SHA1 Message Date
teknium1
dad0057271 fix(plugin-guard): v8 — four intake false-positive classes step down where inert
Real catalog pins from the 2026-09-20 intake batch scored on text that cannot run on
the installing host:

1. `.github/workflows/*.yml` — a CI step's own `os.environ['RUNNER_TEMP']` read scored
   `python_os_environ/high` and made a clean plugin `caution` (remarkable). A workflow
   runs on the forge's runner; it now takes the README prose cap (one step down,
   agent-facing shapes like `curl | sh` keep full severity).
2. "pip install" inside a user-facing message literal (`"... no pip install is needed"`,
   image-utils) scored `unpinned_pip_install/medium`; mid-literal, non-command position,
   no exec verb on the line → low. `"pip install x"`, `python -m pip install`, `uv pip`,
   `subprocess.run("pip install …")` keep medium.
3. `desktop_surface_findings()` was being run by batch tooling over every `*.js`/`*.mjs`
   in a repo and flagged a Node sidecar's lazy `import('jszip')` (remarkable). The
   product check was already scoped to `desktop/`; expose that scope as
   `is_desktop_surface()` / `desktop_surface_hits()` so tooling shares it.
4. `127.0.0.1:<port>` (README, .mcp.json, client defaults) scored `hardcoded_ip_port` as
   network egress; a line whose every IP:port is loopback → low. A routable address on
   the line keeps medium.

Every finding stays in the report. PLUGIN_SCANNER_VERSION → plugin-guard-v8 so cached
verdicts on quarantined pins are re-evaluated.
2026-09-20 11:49:00 -07:00
teknium1
50e9cd7bd5 fix(plugin-guard): two intake false positives — regex literal <script, allowlist "printenv"
Desktop lint: /<script[\s\S]*?<\/script>/gi in a feed sanitiser scored as
'script injection' and failed pinned-source-validate for rss-reader. Mask
JS regex literals for the markup-shaped rule only; <script in a string
literal (an innerHTML payload) and createElement('script') still fail.

Install scanner: "printenv" as a whole-string entry of a read-only
allowlist (frozenset({..., "printenv"})) fired dump_all_env high →
caution on hermes-jev. Extend the literal-token demotion: a token that is
the ENTIRE quoted literal on a line that executes nothing steps down like
an alternation member; "sudo" inside subprocess.run([...]) and
os.system("printenv") keep high.

A/B vs origin/main: attack probes identical (23 rows), in-tree sweep 319
entries 0 worse/0 changed; both new tests red on base. Bumps
PLUGIN_SCANNER_VERSION to v6 so cached caution verdicts refresh.

Signed-off-by: teknium1 <teknium1@users.noreply.github.com>
2026-09-19 14:30:36 -07:00
teknium1
72f55062d2 feat(plugin-catalog): refuse desktop plugins that step outside the SDK surface
A desktop/plugin.js is evaluated in the Electron renderer with the app's
full authority; the runtime loader documents itself as error isolation
only and says a remote source must not reuse it without a boundary. The
catalog is that remote source, so admission now fails a plugin whose
desktop code patches prototypes, uses eval/new Function, dynamically
imports anything but the SDK (app chunks, blob/http URLs), or injects
script tags. Against the 18 desktop plugins in the current sweep the lint
passes 17 and fails the one the security review flagged for exactly these
moves. Policy written down in plugin-catalog/README.md rule 8 and the
user-facing catalog doc.
2026-09-19 03:19:18 -07:00
teknium1
260da4ef62 fix: catalog installs no longer block on caution; admission runs the same scanner
Symptom: a third of catalog entries (23 of 71 pinned trees scanned today) could not be
installed from the Desktop. The install path runs plugin_guard on every clone and a
caution verdict needs a confirmation; the CLI prompts, the Desktop/dashboard path
passes no decision callback, so caution became "Security scan blocked".

Root cause: admission (hermes plugins validate + catalog CI) never ran the scanner, so a
pin could be approved by a human and still trip the installer.

Fix, both halves:
- validate_plugin_dir gains a "security scan" check: dangerous fails the entry, caution
  is reported as warnings so the reviewer reads the findings before merging the pin.
  pinned-source-validate in plugin-catalog-ci.yml therefore runs the identical scanner.
- _install_plugin_core accepts reviewed_pin=<catalog sha>; when the checked-out revision
  equals it, caution is accepted without a prompt. dangerous still blocks (a signature
  added after review is what the backstop is for). Raw-URL installs, --ref overrides
  and a checkout at any other revision keep the current behaviour.

Live: dashboard_install_plugin('weather') on origin/main -> BLOCKED caution; after -> ok.
2026-09-16 15:47:44 -07:00
teknium1
5f9042bec6 fix(plugins): validate accepts model-provider plugins and mirrors the real PluginContext surface
Two false positives in `hermes plugins validate` that block catalog admission
for plugins that are correct at runtime:

- `kind: model-provider` plugins register at import via
  providers.register_provider(ProviderProfile); the PluginManager never calls a
  register(ctx) on them (plugins_discovery skips the kind). The probe demanded
  register() anyway, so every provider plugin -- including the in-tree
  plugins/model-providers/* -- failed with "no register() function". The probe
  now records register_provider calls for that kind and fails only when the
  import registers nothing.
- RecordingContext returned a no-op callable for ANY attribute, so
  `getattr(ctx, "profile_path", None)` was truthy under validation alone and
  register() crashed with an error the real PluginContext never produces. The
  parent now passes the real PluginContext method names into the probe; other
  names raise AttributeError exactly like the real object.

Surfaced by the 2026-09-15 catalog sweep (Gondola provider, hermes-persona).
2026-09-15 18:39:54 -07:00
teddychenfeiyang-png
a8ac7899b5 test(plugins): typo'd requires_hermes clause fails plugins validate admission
Companion to the import fix: a clause whose version segment does not parse
(`>=0.21.1,<0.x`) must fail admission rather than silently gate nothing.

Salvage note: the source hunk (same import fix) and the duplicate positive
test from PR #108842 were dropped in favour of the earlier #107553; only the
negative test is carried here.
2026-09-12 07:57:13 -07:00
jinli.yl
c4c508579d fix(plugins): validate requires_hermes from manifest module 2026-09-12 07:57:13 -07:00
Teknium
f4af457679 test(plugins): trim catalog tests to invariants against the new shapes
538+570+296+216 lines of change-detectors → 4 files of contract tests:
seed catalog valid, bad entries skipped, kill list name-or-repo, live
fallback+union; real-git pinned install + sidecar + re-pin; kill list
blocks CLI/dashboard/TUI with only the CLI bypass; dashboard merge via
sidecar; probe get_config default; extractor live document.
2026-09-09 04:38:01 -07:00
Teknium
ce6d9e62cd fix(catalog): reconcile catalog layer with landed index/manifest-v2/portable tracks
- cmd_install: curated catalog resolution first, community-index fallback with unreviewed warning
- _install_plugin_core: removed-blocklist gate on top of main pinned-metadata installer
- cmd_update: catalog sidecar re-pins to catalog SHA (never git pull)
- validator: config_schema (v2) shape check; portable Agent Plugins v1 plugin.json admission
- admission CI: accept plugin.json-only packages at the pinned SHA
- cmd_list: catalog:<tier>@<sha> provenance + removed annotations (table + JSON)
2026-08-27 21:37:16 -07:00
Teknium
373ad70f4c test(plugins): cover catalog CLI surface and plugin validation
Behavior contracts for catalog-name install resolution (ref pin +
sidecar), custom-URL banner, --allow-removed wiring, catalog-pin
updates, list annotations, live-index fetch/fallback/TTL cache,
search/browse/info rendering, doctor, argparse dispatch, and the
validate checks incl. undeclared-capability diffs, crash containment,
and built-in tool collisions.
2026-07-22 08:14:51 -07:00