Commit Graph

11 Commits

Author SHA1 Message Date
Teknium d041ed7ab2 fix(skills-hub): reconcile salvaged install fixes with full-directory fetch
Follow-up reconciling the four cherry-picked contributor fixes with the
full-dir GitHubSource.fetch() that landed in #98246:

- Missing SKILL.md-linked support paths now warn and install without the
  file at all three sources (GitHub full-dir, GitHub fallback, UrlSource) —
  dangling links are prose over-matches or repo-only dev tools, not install
  blockers (#66760/#90081). A referenced path present in the tree as a
  SYMLINK stays a hard rejection.
- Extension requirement dropped from the glob/placeholder filter:
  references/LICENSE is a legitimate support file (82236's tests pin this).
  Truncated prose placeholders (references/type-<name>.md -> 'type-') are
  still rejected via the trailing-separator shape.
- percent-quoted Contents-API path (82236) merged with revision pinning
  (96336) in _fetch_file_bytes.
- Fixture typo fix: four cherry-picked test strings used '\---' where
  '\n---' was meant (DeprecationWarning + frontmatter never parsed).

Validation: 167/167 across tests/tools/{skills_hub,skills_guard,
skill_bundle_provenance} + tests/hermes_cli/test_skills_hub.py; live GitHub
fetches (impeccable 163 files rev-pinned; anthropics frontend-design).
2026-08-29 20:39:09 -07:00
liuhao1024 7e95b67ad8 fix(skills): review follow-up — revision pinning, canonicalization, case-fold guards
Addresses the review on #96336:

- Every GitHub byte fetch in an install (SKILL.md included) now carries
  the resolved tree's SHA as ?ref=, closing the pre-existing TOCTOU
  where /contents floated to the default-branch HEAD and bytes could
  come from a newer revision than the tree the paths were validated
  against. The tree is resolved first (idempotent + cached) so the pin
  covers the whole install.
- Same-dir link targets are canonicalized before validation: query/
  fragment stripped via urlsplit, percent-decoded, leading ./ removed —
  the same normalization the support-dir branch applies.
- A case-variant link to skill.md never ships as a bundle entry, and a
  case-folded collision among accepted siblings (A.md + a.md) drops the
  pair — both would overwrite/collide on case-insensitive filesystems.
2026-08-29 20:39:09 -07:00
liuhao1024 86dda3cd36 fix(skills): fetch explicitly linked same-directory siblings on install (#96310)
_referenced_support_paths only kept links whose first path segment was
one of the five support directories (references/templates/scripts/
assets/examples), so a SKILL.md linking same-directory siblings —
mattpocock/skills' domain-modeling links ./CONTEXT-FORMAT.md and
ADR-FORMAT.md — installed 'successfully' with those files silently
omitted: the bundle came out semantically incomplete with unresolved
links.

A second pass now collects same-directory markdown-link targets
(](./FILE.ext) or ](FILE.ext)) that name an extension-bearing file,
carry no internal slash, and are not SKILL.md itself; a leading '..'
is rejected fail-closed exactly like the support-dir traversal branch,
external URLs/anchors/mailto/site-absolute targets are left to their own
resolution, and every accepted name still runs the bundle path
validator. Unlinked siblings remain excluded — the fetch-minimization
contract is unchanged; only files the document explicitly links ship.
2026-08-29 20:39:09 -07:00
Fidias Feliciano 972d812429 [verified] fix: ignore glob-shaped skill support paths 2026-08-29 20:39:09 -07:00
PRATHAMESH75 9d813c7352 test(cli): add install-flow E2E for skipped unreachable URL support file (#66760)
Covers the reviewer-requested end-to-end path: a referenced support file
that 404s is skipped, and the URL skill still installs through quarantine,
scan, install, and lock provenance with only the reachable files on disk
and in the lock file.
2026-08-29 20:39:09 -07:00
Teknium 45d9c33d85 feat(skills-hub): impeccable joins the optional-skills catalog, content pulled live from upstream
hermes skills install impeccable (and the docs-page install button) now
installs the impeccable frontend-design skill as an official optional-skills
entry. The local optional-skills/creative/impeccable/ dir is a catalog STUB:
its frontmatter declares metadata.hermes.upstream (repo + path), and
OptionalSkillSource.fetch() pulls the real 163-file bundle live from
pbakaus/impeccable:.hermes/skills/impeccable — the Hermes-native bundle
upstream maintains and verifies. Nothing vendored, never stale.

New mechanism (generic, not impeccable-specific):
- OptionalSkillSource._upstream_pointer(): parses/validates the upstream
  pointer (owner/name repo, clean relative path, traversal rejected).
- _fetch_from_upstream(): delegates to GitHubSource.fetch(), relabels the
  bundle official/<rel> at trust 'trusted' (curated endorsement, but
  third-party content — dangerous scan verdicts still block).
- The live-repo fallback path redirects stubs the same way, so stale local
  checkouts behave identically.

Three real gaps this surfaced, all fixed:
- GitHubSource.fetch() only downloaded SKILL.md plus paths linked from a
  canonical support dir (references/, scripts/, ...). Impeccable keeps its
  playbooks under reference/ (singular) and links scripts only from
  reference files, so fetch shipped 1 of 163 files. fetch() now downloads
  the full skill directory via the git tree (same approach as the
  optional-skills live fetch), still rejecting symlinks/hidden/unsafe paths
  and still failing on a missing SKILL.md-linked references/ path.
- The five env_exfil_* scanner patterns flagged loopback requests as
  critical exfiltration: impeccable's live mode polls
  http://localhost:PORT/status?token=TOKEN and scored two CRITICALs.
  Scheme-anchored loopback exemption added; evil.com/?u=localhost decoys
  still fire (10-case regex matrix in tests).
- unified_search() truncated to limit before ranking, so official catalog
  entries got crowded out by skills.sh mirrors and bare-name installs
  stalled on an ambiguity table. Results now stable-sort by trust rank
  before the cut, and _resolve_short_name prefers a sole official exact
  match over community mirrors.

Also fixes pre-existing test pollution: TestInstallPathSafety's fixture
monkeypatched the PEP 562 dynamic SKILLS_DIR, permanently shadowing dynamic
resolution and breaking the served_repo E2E tests in any combined run
(reproducible on main).

Validation: live E2E do_install("impeccable") against real GitHub —
resolves to official/creative/impeccable, verdict SAFE, 163 files on disk,
skill loads, /impeccable slash command registers. 128/128 targeted tests;
full-dir fetch test sabotage-verified. Docs: optional-skills catalog row,
generated skill page, sidebar.
2026-08-29 19:15:32 -07:00
Chen Jin ed0a8a480e fix(skills): resolve skills dir before relative_to so junction installs work (#86971) 2026-08-16 02:02:34 -07:00
Teknium 39975613b1 test: prune wave 2 + speed fixes — 28,106 → 19,757 test functions, suite wall 315s → 294s
Second, deeper pass over tools/gateway/hermes_cli plus first pass over
the trees wave 1 missed (acp, acp_adapter, skills, computer_use, docker,
dashboard, conformance, monitoring, secret_sources, hermes_state,
providers). Same rubric as wave 1 (AGENTS.md test policy); security,
alternation/caching invariants, issue-number regressions, and E2E kept.

Real test-quality fixes found and rooted out along the way:
- tests/tools/test_command_guards.py made real auxiliary-LLM HTTPS calls
  (DEFAULT_CONFIG smart-approval leaked in) — pinned approval
  mode=manual via autouse fixture: 17.4s → 0.4s.
- test_model_switch_custom_providers.py / test_user_providers_model_switch.py
  silently probed live provider catalogs (~2s/test) — stubbed
  cached_provider_model_ids/provider_model_ids/fetch_api_models.
- test_telegram_noise_filter.py: 15-platform copy-paste matrix over
  shared gateway.run logic → 3 representative platforms (55s → 3.9s).
- test_gateway_shutdown.py: stop()'s 5s interrupt-deadline loop spun on
  MagicMock agents — interrupt.side_effect now clears _running_agents
  (22s → 1.0s).
- test_gateway_inactivity_timeout.py poll-harness timings shrunk 3-5x
  (24s → 1.1s); test_mcp_stability.py backoff/SIGTERM-grace sleeps
  patched (15.4s → 2.5s); test_async_delegation.py negative-drain wait
  5s → 0.5s.
- test_telegram_init_deadline.py: loop-block margin restored to 1.0s
  with rationale comment — the watchdog-dump assertion needs the loop
  blocked well past deadline+grace under parallel load (flaked once in
  the 40-worker verification run at a 0.2s margin).

Verification: full hermetic suite via scripts/run_tests.sh —
2,438 files, 21,718 tests passed, 0 failed, 293.9s wall.
Suite totals vs original baseline: 46,820 → 19,757 test functions
(−57.8%), wall 583.5s → 293.9s (−50%), subprocess CPU 13,564s → 11,623s.
2026-07-29 13:39:40 -07:00
Eugeniusz Gilewski 0cd4afeafd fix(security): guard remaining preflighted HTTP fetches
Several platform fetch paths called is_safe_url before constructing ordinary httpx clients, leaving a second DNS lookup at connection time. This preserved the rebinding window for Slack batch images, Feishu documents, Telegram URL-photo fallback, and WeCom remote media.

Route each path through create_ssrf_safe_async_client and the shared redirect guard so direct connections validate and dial vetted IPs while configured proxies remain an explicit trusted egress boundary. Add per-path regressions that change DNS from public at preflight to metadata at connect time.

The Skills Hub provenance fixture intentionally serves content over loopback. Opt that test-scoped server into private-address access so it keeps exercising the real HTTP transport without weakening production blocking.

Related #8033

Co-authored-by: teknium1 <127238744+teknium1@users.noreply.github.com>
2026-07-23 11:44:43 -07:00
teknium1 51382ac244 fix(skills): bind bundles to exact files and origins 2026-07-12 02:59:27 -07:00
teknium1 c36f6b7259 fix(skills): install referenced bundle files with scan provenance 2026-07-12 02:59:27 -07:00