Conversation
274f6b0 to
5a90185
Compare
5a90185 to
a6fbd13
Compare
| overwriting a skill already on disk (naming the source by ``ref.fqn``), so a | ||
| declined skill is never fetched. Dedup keys on the bundle name, since that is | ||
| the directory an agent would load. Name validity is the server's job -- | ||
| FinalizeSkill enforces the Agent Skills naming rules on ``bundle_name`` before |
There was a problem hiding this comment.
P1 (defense-in-depth): bundle_name flows straight into filesystem paths — write_skill does root / ref.bundle_name, and _skill_installs records those same dirs, which ug skill remove later shutil.rmtrees. Today that's safe because, as this docstring says, FinalizeSkill enforces Agent Skills naming rules server-side (no .//), so a legit bundle_name can't traverse. But it's a remote-provided value feeding a write and delete sink with zero client-side check — if the server guarantee ever regresses or is bypassed, we write/delete outside the skill dir. A one-line guard where the ref is built (reject .., /, or absolute paths, skip+warn) is cheap insurance for a delete sink. Not exploitable as-is — flagging for hardening.
a6fbd13 to
eda0255
Compare
eda0255 to
0571612
Compare
0571612 to
1d7543c
Compare
1d7543c to
69292f2
Compare
69292f2 to
202fd05
Compare
202fd05 to
3f6aa4e
Compare
3f6aa4e to
21a7d8d
Compare
Refactor skills_download.py so the download mechanics (collision dedup, overwrite prompt, parallel fetch, write) become one reusable core, ahead of the interactive picker (PR D) which selects individual skills across schemas. - SkillRef now carries catalog/schema and exposes fqn, so a ref is fully self-contained; _skill_ref parses all three from the API name. - Extract _download_refs(refs, roots) -> (written, total), the shared core. should_download_skill and _reject_bundle_name_collisions read the source off the ref (ref.fqn), yielding identical messages, so the core is location-agnostic and handles a cross-schema set. - _fetch_bundles keys results by fqn (a securable is unique only within its schema) and takes its progress-bar label from the caller. - Rename download_skills to download_skills_from_schema_locations; it calls _download_refs per location and keeps the per-location summary. - download_managed_skills_on_launch (the other _fetch_bundles caller) moves to the new keying; behavior unchanged. - Add get_skill(fqn) (GetSkill, NOT_FOUND to None) and download_selected_skills(fqns, path); both unwired this PR. No behavior change on any existing path. New unit tests cover _download_refs (including cross-schema dedup), get_skill, and download_selected_skills. Co-authored-by: Isaac <no-reply@databricks.com>
21a7d8d to
aaa780b
Compare
What
PR C of the
ug skill addinteractive-picker stack. It reshapesskills_download.pyso the download mechanics become one reusable core, and adds the (still unwired) functions the picker will call in PR D. No behavior changes on any existing path.Design doc:
ug_skill_add_download_interactive_picker_design.md(PR table, row C).Changes
SkillRefcarries its full location. Newcatalog/schemafields plus anfqnproperty, parsed once from the APInamein_skill_ref, so a ref is self-contained and can be downloaded on its own._download_refs(refs, roots) -> (written, total), the shared core: collision dedup, overwrite prompt, parallel fetch, write.should_download_skilland_reject_bundle_name_collisionsnow read the source off the ref (ref.fqn) instead of an explicitlocationarg, which produces byte-identical messages and lets the core serve a flat, cross-schema set._fetch_bundleskeys results by FQN (a securable name is unique only within its schema) and takes its progress-bar label from the caller.download_skillstodownload_skills_from_schema_locations, now calling_download_refsper location and keeping the exact per-locationDownloaded k/n from <location>summary.get_skill(fqn)(GetSkill at/2.1/unity-catalog/skills/<fqn>, reusing_skill_ref; NOT_FOUND toNone) anddownload_selected_skills(fqns, path)(one_download_refspass over the flat selection). Both are dead code until PR D wires the picker.Deviations from the design doc
download_managed_skills_on_launchis a second caller of_fetch_bundlesthe doc did not mention; it is updated to the new keying (behavior-preserving).should_download_skill/_reject_bundle_name_collisionsas reused unchanged, but making the core location-agnostic means they read the source off the ref. The emitted messages are identical (<catalog>.<schema>.<securable>equalsref.fqn).Testing
uv run ruff check .,ruff format --check src tests, anduv run pytestall pass (the 2 pre-existing e2e failures intest_e2e_user_agentandtest_claude_smart_routing_v2are unrelated and also fail on the base branch). New unit tests cover_download_refs(including cross-schema dedup),get_skill(NOT_FOUND toNone, unfinalized toNone), anddownload_selected_skills.Stacked on #574 (
skills-picker-walk).This pull request and its description were written by Isaac.