diff --git a/plugins/jfrog/skills/jfrog-ai-catalog-skills/SKILL.md b/plugins/jfrog/skills/jfrog-ai-catalog/SKILL.md similarity index 53% rename from plugins/jfrog/skills/jfrog-ai-catalog-skills/SKILL.md rename to plugins/jfrog/skills/jfrog-ai-catalog/SKILL.md index f129918..9ee1ae8 100644 --- a/plugins/jfrog/skills/jfrog-ai-catalog-skills/SKILL.md +++ b/plugins/jfrog/skills/jfrog-ai-catalog/SKILL.md @@ -1,26 +1,28 @@ --- -name: jfrog-ai-catalog-skills +name: jfrog-ai-catalog description: >- - Discover, install, manage, and publish agent skills hosted in the JFrog AI - Catalog (Artifactory skills repositories) using the JFrog CLI (`jf skills`) - and the JFrog Agent Guard. Lists and searches available skills (catalog-wide - or scoped to a project), shows a skill's versions and which repos host it, - installs the latest or a pinned version, verifies the install, lists - installed skills, updates and removes them, and publishes (uploads) a local - skill bundle and releases new versions. - Use when the user asks what skills are available or installed, to - search/browse the catalog, to install/update/uninstall a skill, to see a - skill's versions, or to publish/upload/release a skill to JFrog / - Artifactory / the AI Catalog. + Discover, install, manage, and publish agent skills and agent plugins hosted + in the JFrog AI Catalog (Artifactory skills and plugins repositories) using + the JFrog CLI (`jf skills`, `jf agent plugins`) and the JFrog Agent Guard. + Lists and searches available skills and plugins (catalog-wide or scoped to a + project), shows versions and which repos host them, installs the latest or a + pinned version, verifies the install, lists installed skills and plugins, + updates and removes them, and publishes a local skill or plugin bundle and + releases new versions. Use when the user asks what skills or plugins are + available or installed, to search/browse the catalog, to + install/update/uninstall/delete a skill or plugin, to see versions, or to + publish/upload/release a skill or plugin to JFrog / Artifactory / the AI + Catalog. metadata: role: workflow --- -# JFrog AI Catalog Skills +# JFrog AI Catalog -Discover, install, and manage agent skills from the JFrog AI Catalog -(Artifactory skills repositories), and publish your own skills back to it, all -through the JFrog CLI (`jf skills`) and the JFrog Agent Guard. +Discover, install, and manage agent skills and agent plugins from the JFrog AI +Catalog (Artifactory skills/plugins repositories), and publish your own back to +it, all through the JFrog CLI (`jf skills`, `jf agent plugins`) and the JFrog +Agent Guard. ## Choose a reference file @@ -32,6 +34,10 @@ Pick the row matching the user's intent and read that reference file. | Install or update a skill (latest or a pinned version), or a download is blocked | [references/installing-skills.md](references/installing-skills.md) | | "What's installed?" / remove an installed skill | [references/managing-installed-skills.md](references/managing-installed-skills.md) | | Publish / upload / release a skill to the catalog | [references/publishing-skills.md](references/publishing-skills.md) | +| "What plugins are available?" / browse the plugin catalog / list plugin versions / search plugins | [references/discovering-plugins.md](references/discovering-plugins.md) | +| Install or update a plugin (latest or a pinned version) | [references/installing-plugins.md](references/installing-plugins.md) | +| "What plugins are installed?" / remove an installed plugin | [references/managing-installed-plugins.md](references/managing-installed-plugins.md) | +| Publish / upload / release a plugin to the catalog | [references/publishing-plugins.md](references/publishing-plugins.md) | ## Prerequisites @@ -43,6 +49,12 @@ Pick the row matching the user's intent and read that reference file. - The [server selection rules](../jfrog/SKILL.md#server-selection-rules-mandatory) — resolve the default `` once and reuse it, pass `--server-id ` after the subcommand on every `jf` call, and use one server per request. + **Resolve it now, before any `jf` call:** + ```bash + jf config show 2>/dev/null \ + | awk '/^Server ID:/{id=$NF} /^Default:[[:space:]]*true/{print id; exit}' + # stdout: the default server-id; if empty, stop and ask which server to use + ``` - The stop-on-error rule — on any `jf` failure, stop and never switch servers. One addition specific to this skill: never `cat` or parse @@ -57,16 +69,21 @@ Pick the row matching the user's intent and read that reference file. as your `jf` calls. Agent Guard also reads `JFROG_URL` / `JF_URL` directly when set, so make sure the `` you resolved points at that same host. - **Resolve the project (``) only when needed.** - It is required for `--list-skills`, `--list-skill-versions`, and - `--provision-skills-repository`. Take it from `JF_PROJECT` or the user. + It is required for `--list-skills`, `--list-skill-versions`, + `--provision-skills-repository`, `--list-agent-plugins`, + `--list-agent-plugin-versions`, and `--provision-agent-plugins-repository`. + Take it from `JF_PROJECT` or the user. There is no non-admin way to look up or validate project keys (the `/access/api/v1/projects` list endpoint needs admin), so you cannot silently correct a display name to a key. If the value looks like a display name (spaces, mixed case) rather than a short slug, ask the user to confirm the project **key** specifically. Never assume `default`, never invent one. Install, update, remove, and publishing to - an explicit `--repo` are keyed by skill **name** and/or **repo**, not a - project. + an explicit `--repo` are keyed by skill/plugin **name** and/or **repo**, + not a project. +- **Bundle manifests differ by type.** Skill bundles require `SKILL.md` + in the bundle root; plugin bundles require `plugin.json`. Validate the + correct file before installing or publishing. ## Workflow overview @@ -76,10 +93,14 @@ flowchart TD B -->|No| C[Ask user to install jf CLI, then continue] B -->|Yes| D{Intent} C --> D - D -->|List all / versions| E[npx @jfrog/agent-guard --list-skills] - D -->|Install / update| F[Resolve slug + version, then jf skills install/update] - D -->|List installed / remove| G[jf skills list / rm -rf install dir] - D -->|Publish| H[Resolve/provision repo, validate bundle, jf skills publish] + D -->|List all skills / versions| E[npx @jfrog/agent-guard --list-skills] + D -->|Install / update skill| F[Resolve slug + version, then jf skills install/update] + D -->|List installed skills / remove| G[jf skills list / rm -rf install dir] + D -->|Publish skill| H[Resolve/provision repo, validate bundle, jf skills publish] + D -->|List all plugins / versions| I[npx @jfrog/agent-guard --list-agent-plugins] + D -->|Install / update plugin| J[Resolve slug + version, then jf agent plugins install/update] + D -->|List installed plugins / remove| K[jf agent plugins list / rm -rf install dir] + D -->|Publish plugin| L[Resolve/provision repo, validate bundle, jf agent plugins publish] ``` ## Gotchas @@ -100,3 +121,6 @@ the reference files above. - **Use the response templates verbatim**: where a reference file gives a "reply using this exact template" block, fill the placeholders and send exactly that, with the same wording every time and no extra preamble or commentary. +- **Plugins have no Xray support**: skip all Xray-related handling (no 403 + gating on download, no inline scan on publish, no `--skip-scan` flag) when + performing any `jf agent plugins` operation. diff --git a/plugins/jfrog/skills/jfrog-ai-catalog/references/discovering-plugins.md b/plugins/jfrog/skills/jfrog-ai-catalog/references/discovering-plugins.md new file mode 100644 index 0000000..8aed8a3 --- /dev/null +++ b/plugins/jfrog/skills/jfrog-ai-catalog/references/discovering-plugins.md @@ -0,0 +1,83 @@ +# Discovering plugins + +List-all and versions go through the **Agent Guard**. + +## List plugins (page through the catalog) + +```bash +npx --yes --registry @jfrog/agent-guard \ + --list-agent-plugins --project "" [--name ] [--server ""] [--page-size ] [--cursor ] [--format json] +``` + +| Flag | Required | Purpose | +|------|----------|---------| +| `--project ` | **Yes** | AI Catalog project to list. | +| `--name ` | No | Find plugins by name: server-side, case-insensitive substring, scoped to the project. | +| `--server ` | No | jf CLI config entry to authenticate with (defaults to the resolved single server). | +| `--page-size ` | No | Results per page. Pass `50` to stay bounded. The Agent Guard defaults to 500 if omitted. | +| `--cursor ` | No | Continuation cursor from a previous page's JSON, to fetch the next page. | +| `--format json` | No | Raw page JSON instead of the default compact TSV (name + last-updated). | + +Request a bounded page with `--page-size 50 --format json`, present those plugins, +then read `exhausted` and `cursor` from the response. If `exhausted` is `false` +there are more. Tell the user and offer to fetch the next page with +`--cursor `. Do not silently page through the whole catalog. + +**Presenting results (use this exact format).** Render the plugins as this table, +sorted by name, and nothing else (no commands, URLs, flags, or cursors): + +| Plugin | Last updated | +|--------|-------------| +| `` | `` | + +For a `--name` search with no matches, reply with one line instead: + +> No plugins match "``". + +To offer a follow-up (a plugin's versions or repos), ask in plain language +("want the versions for one of these?") and run the command yourself. + +## List a repo's plugins + +To see what is published in one specific plugins repository (for example, to check +a repo before or after publishing to it), list it directly with the CLI. This is +repo-scoped (Artifactory registry contents), unlike `--list-agent-plugins`, which is +project-scoped: + +```bash +jf agent plugins list --repo "" --server-id "" --format json +``` + +Never run a bare `jf agent plugins list` (it errors): always pass `--repo ` here, or +`--harness ` for installed plugins (see `managing-installed-plugins.md`). + +**Presenting results (use this exact format).** Render the plugins as this table, +sorted by name, and nothing else (no commands, URLs, or flags): + +Plugins in ``: + +| Plugin | Version | Description | +|--------|---------|-------------| +| `` | `` | `` | + +Include the **Description** column only when the listing provides one (drop it if +every plugin's description is empty). If the repo holds no plugins, reply with one +line instead: + +> No plugins published in ``. + +## A plugin's versions and hosting repos + +```bash +npx --yes --registry @jfrog/agent-guard \ + --list-agent-plugin-versions --project "" --agent-plugin "" [--server ""] [--page-size ] [--cursor ] [--format json] +# JSON: versions[].version, versions[].locations[].repoKey (page through with cursor like above) +``` + +**Presenting versions (use this exact format).** Newest version first: + +Versions of ``: + +| Version | Hosted in | +|---------|-----------| +| `` | ``[, ``…] | diff --git a/plugins/jfrog/skills/jfrog-ai-catalog-skills/references/discovering-skills.md b/plugins/jfrog/skills/jfrog-ai-catalog/references/discovering-skills.md similarity index 100% rename from plugins/jfrog/skills/jfrog-ai-catalog-skills/references/discovering-skills.md rename to plugins/jfrog/skills/jfrog-ai-catalog/references/discovering-skills.md diff --git a/plugins/jfrog/skills/jfrog-ai-catalog/references/installing-plugins.md b/plugins/jfrog/skills/jfrog-ai-catalog/references/installing-plugins.md new file mode 100644 index 0000000..fd1dc6f --- /dev/null +++ b/plugins/jfrog/skills/jfrog-ai-catalog/references/installing-plugins.md @@ -0,0 +1,138 @@ +# Installing and updating plugins + +Install and update both download from the registry, so they share the same +`--repo`/`--quiet` rules and verify-landed check. + +## Contents + +- When evidence verification fails +- Verify the install landed +- Update an installed plugin + +Install by **slug** (the registry `slug`/`name`, never a display name). Latest +version is used by default, and the user may pass an explicit version. +**The `jf agent plugins install` command takes no project.** Resolving which repo hosts +the slug uses `--list-agent-plugin-versions` (below), which does require `--project`, so +resolve it (from `JF_PROJECT`, else ask the user) before that lookup. + +```bash +jf agent plugins install "" \ + --server-id "" \ + --version "latest" \ + --repo "" \ + --harness "" \ + --quiet +``` + +**Always pass `--quiet`.** `jf agent plugins install`/`update` opens an interactive +prompt by default, and an agent's shell has no TTY, so without `--quiet` the +prompt fails. `--quiet` also defaults to `$CI`, so exporting `CI=true` has the +same effect if the flag is ever unavailable. Run non-interactively and resolve +every choice (`--repo`, target) up front. + +**Resolve `` from the environment check script — never from your model +name.** If `` is not already known from this session, run +`bash /scripts/check-environment.sh ` now and capture +its stdout as ``. Parse the `tool=` field from `` and map it to a +`jf` harness name: + +| `tool=` value in `` | `--harness` for `jf agent plugins` | +|-------------------------|------------------------------------| +| `claude` | `claude-code` | +| `cursor` | `cursor` | +| `unknown`, empty, or any other | Ask the user | + +If `tool` is `unknown`, empty, or not in the table — do **not** guess. Ask +the user for the desired install path and use `--path ` instead. VS Code +and similar hosts that lack a recognised `tool=` value are not in the supported +agents table for plugins; passing a guessed harness will cause the CLI to error +with `unknown agent`. + +Choose exactly one install target (these are mutually exclusive): + +| Flag | Installs into | +|------|---------------| +| `--harness ` | The current agent's resolved plugins dir (resolve per above, e.g. `cursor`, `claude-code`). | +| `--global` | Each agent's global directory from config. | +| `--project-dir ` | Project root combined with the agent's project path. | +| `--path ` | Direct: files go under `/`. | + +**Always resolve and pass `--repo`.** When the platform has more than one plugins +repository (the common case), `jf agent plugins install` errors with +`multiple plugins repositories found … specify --repo` if you omit it, even when +the plugin lives in only one repo. So **the first install step is always** to look +up where the slug is hosted with the Agent Guard: + +```bash +npx --yes --registry @jfrog/agent-guard \ + --list-agent-plugin-versions --project "" --agent-plugin "" [--server ""] --format json +# read versions[].version and versions[].locations[].repoKey +``` + +**Resolve the repo and version only via `--list-agent-plugin-versions`.** The catalog +listing (`--list-agent-plugins`, even with `--name`) returns just names, not repos or +versions, so use the versions call above to pick the repo, never a name listing. + +- **One repo hosts the slug.** Use it as `--repo ` directly. Don't ask. +- **Multiple repos host the slug.** Do not pick silently. List the repos (and + the version each holds), ask the user which to install from, then pass + `--repo `. The newest version may only exist in one of them, so + surface that to avoid giving the user a stale version. + +## When evidence verification fails + +If install fails with `evidence verification failed … no evidence found`, the +plugin has **no signed evidence/attestation** (proof it's genuine and scanned). +This is a security control. **Do not silently bypass it.** Stop and ask using +**this exact template**: + +> `@` has no signed evidence (proof it is genuine and scanned). +> Installing it skips that security check. Do you want to install it anyway? + +Only if the user explicitly agrees, re-run with +`JFROG_SKILLS_DISABLE_QUIET_FAILURE=true`. Never set that flag on your own. + +## Verify the install landed + +After install, confirm the `plugin.json` exists at the resolved install location +before reporting success: + +```bash +test -f "///plugin.json" && echo "installed" || echo "MISSING plugin.json" +``` + +If the file is missing, report the failure. Do not claim success. + +On success, reply using **this exact template**: + +> Installed `@` from `` into ``. +> Restart your agent session to load it. + +## Update an installed plugin + +To upgrade an installed plugin to a newer version, use the CLI (it re-downloads +and reinstalls in place): + +```bash +jf agent plugins update --slug "" --server-id "" --harness "" --version "latest" --quiet +# Preview without touching Artifactory: +jf agent plugins update --slug "" --server-id "" --harness "" --dry-run +# Reinstall even if already at the target version: +jf agent plugins update --slug "" --server-id "" --harness "" --force --quiet +# Update all installed plugins at once: +jf agent plugins update --all --server-id "" --harness "" --quiet +``` + +Note: unlike `jf skills update`, the slug is passed as `--slug ` (a named +flag), not as a positional argument. Use the same install-target flag +(`--harness`/`--global`/`--project-dir`/`--path`) the plugin was installed with. +After updating, re-verify the `plugin.json` (see *Verify the install landed* above). + +On success, reply using **this exact template**: + +> Updated `` to `` (``). +> Restart your agent session to load it. + +If the plugin was already current: + +> `` is already at the latest version (``). Nothing to update. diff --git a/plugins/jfrog/skills/jfrog-ai-catalog-skills/references/installing-skills.md b/plugins/jfrog/skills/jfrog-ai-catalog/references/installing-skills.md similarity index 91% rename from plugins/jfrog/skills/jfrog-ai-catalog-skills/references/installing-skills.md rename to plugins/jfrog/skills/jfrog-ai-catalog/references/installing-skills.md index d591aee..eec381b 100644 --- a/plugins/jfrog/skills/jfrog-ai-catalog-skills/references/installing-skills.md +++ b/plugins/jfrog/skills/jfrog-ai-catalog/references/installing-skills.md @@ -37,13 +37,21 @@ defaults to `$CI`, so exporting `CI=true` has the same effect if the flag is eve unavailable. Run non-interactively and resolve every choice (`--repo`, target) up front. -**Resolve `` from the host you are running in. Never take it from your -model name, and never hardcode it.** Get the valid names from the CLI: run -`jf skills list --harness '?'` to print the -`Supported agents:` table, then install into the row for your host. Identify the -host from its environment. For example, `CURSOR_*` → `cursor`, -`CLAUDECODE` → `claude-code`, VS Code / GitHub Copilot → `github-copilot`. If -nothing identifies the host, ask the user. Never assume. +**Resolve `` from the environment check script — never from your model +name.** If `` is not already known from this session, run +`bash /scripts/check-environment.sh ` now and capture +its stdout as ``. Parse the `tool=` field from `` and map it to a +`jf` harness name: + +| `tool=` value in `` | `--harness` for `jf skills` | +|-------------------------|------------------------------| +| `claude` | `claude-code` | +| `cursor` | `cursor` | +| `copilot` | `github-copilot` | +| `unknown`, empty, or any other | Ask the user | + +If `tool` is `unknown`, empty, or not in the table — do **not** guess. Ask +the user for the desired install path and use `--path ` instead. Choose exactly one install target (these are mutually exclusive): diff --git a/plugins/jfrog/skills/jfrog-ai-catalog/references/managing-installed-plugins.md b/plugins/jfrog/skills/jfrog-ai-catalog/references/managing-installed-plugins.md new file mode 100644 index 0000000..5a507e1 --- /dev/null +++ b/plugins/jfrog/skills/jfrog-ai-catalog/references/managing-installed-plugins.md @@ -0,0 +1,99 @@ +# Managing installed plugins + +## List currently installed plugins + +A plugin can be installed in two separate places: the **project/harness** location +and the **global** location. For a full inventory, always run **both** lists and +present the union, not just the first: + +```bash +# Project/harness install (the default target) +jf agent plugins list --server-id "" --harness "" --format json +# Global install (a separate location, always check it too) +jf agent plugins list --server-id "" --harness "" --global --format json +# Add --check-updates to compare installed versions against the registry +jf agent plugins list --server-id "" --harness "" --check-updates +``` + +Resolve `` to the current agent (see `installing-plugins.md`). +**Never run a bare `jf agent plugins list`** because it errors. Always pass +`--harness ` (installed plugins) or `--repo ` (registry contents). +`--check-updates` is only supported with `--harness` (not with `--repo`). Merge +the project and global results and drop duplicates before presenting. This lists +only plugins installed from the AI Catalog with `jf agent plugins install`, not +plugin-bundled or built-in agent plugins. + +**Presenting installed plugins (use this exact format):** + +Installed plugins (``): + +| Plugin | Version | Description | +|--------|---------|-------------| +| `` | `` | `` | + +Include the **Description** column only when the listing provides one (drop it if +every plugin's description is empty). With `--check-updates`, add an **Update to** +column (``, or `-` when the plugin is already current). To upgrade a +plugin, see *Update an installed plugin* in `installing-plugins.md`. + +## Remove a plugin + +**Confirm before removing.** Show exactly what will be removed using **this exact +template** and wait for an explicit "yes": + +> Removing plugin `` deletes its local install from ``. Do you want to remove it? + +There is no `jf agent plugins uninstall`. Use a two-step approach: try the +harness-native CLI first, fall back to deleting the local files if unavailable. + +### Step 1: try harness-native uninstall + +Some harnesses register plugins in their own registry — deleting files alone leaves +a dangling entry. Before falling back to step 2, map the `--harness` value to the +actual CLI binary, then probe whether it exposes a native plugin CLI: + +| `--harness` value | CLI binary | +|-------------------|------------| +| `claude-code` | `claude` | +| `cursor` | `cursor` | +| any other | same as harness value | + +```bash + plugin --help 2>/dev/null || plugins --help 2>/dev/null +``` + +If a plugin management CLI is found, use it to look up and uninstall the slug. If +not (command not found or exits non-zero with no useful output), skip to step 2. + +**claude-code** (`claude` binary) is the currently known example. It tracks plugins with ID +`@`: + +```bash +# Look up the registered ID in claude's registry +ID=$(claude plugin list --json 2>/dev/null \ + | jq -r '.[] | select(.id | startswith("@")) | .id') + +# Uninstall (-y required: no TTY in agent context) +claude plugin uninstall "$ID" --prune -y +``` + +### Step 2: fallback — delete local files + +If native uninstall is unavailable or returned no match for the slug. + +Plugins are installed under `///`. Delete the plugin +folder, then remove the parent repo directory if it is now empty: + +```bash +if [ -d "//" ]; then + rm -rf "//" + rmdir "/" 2>/dev/null || true +else + echo "Not installed, nothing to remove" +fi +``` + +On success, reply using **this exact template**: + +> Removed `` from ``. +> Restart your agent session for the removal to take effect. diff --git a/plugins/jfrog/skills/jfrog-ai-catalog-skills/references/managing-installed-skills.md b/plugins/jfrog/skills/jfrog-ai-catalog/references/managing-installed-skills.md similarity index 100% rename from plugins/jfrog/skills/jfrog-ai-catalog-skills/references/managing-installed-skills.md rename to plugins/jfrog/skills/jfrog-ai-catalog/references/managing-installed-skills.md diff --git a/plugins/jfrog/skills/jfrog-ai-catalog/references/publishing-plugins.md b/plugins/jfrog/skills/jfrog-ai-catalog/references/publishing-plugins.md new file mode 100644 index 0000000..b886827 --- /dev/null +++ b/plugins/jfrog/skills/jfrog-ai-catalog/references/publishing-plugins.md @@ -0,0 +1,205 @@ +# Publishing a plugin + +Publishing is mutating, so **always confirm the target repository and the plugin +name with the user before publishing**. Resolve the repo and read the name from +the bundle, then show both and wait for an explicit "yes". Never publish on the +initial request alone, and never auto-pick a repo without surfacing it first. + +## Contents + +- Resolve the target repository +- Validate the bundle +- Sign the plugin (evidence) +- Publish +- Report the publish result + +## Resolve the target repository + +Publish targets an Artifactory **repository** (`--repo`), not a JFrog project, +and there is no `--project` flag on `jf agent plugins publish`. Resolve `` +in this order: + +1. **User named a repo up front.** Use it directly as `` and skip + provisioning. An explicit user-named repo always wins. + +2. **No repo given. Provision the project's plugins repository.** Use Agent + Guard to create (or resolve, if it already exists) the project's local plugins + repo, then publish to the returned key. This needs `` (resolve it per + *Prerequisites* in `../SKILL.md`, asking only if it is unknown): + +```bash +npx --yes --registry @jfrog/agent-guard \ + --provision-agent-plugins-repository --project "" [--server ""] [--format json] +``` + + It prints the bare repo key (or `{"repoKey":""}` with `--format json`). + Use that as ``, then **show the user the provisioned repo and the plugin + name and wait for confirmation** before publishing (see *Confirm before + publishing*). Do not publish to it silently. + +3. **Provisioning failed. Stop and ask the user which repo to use.** Do not + retry in a loop. Publishing is mutating, so you must get an explicit repo from + the user here. This is the one case where you do ask before publishing. + + First list the existing plugins repos: + +```bash +jf api '/artifactory/api/repositories?packageType=plugins&type=local' \ + --server-id "" 2>/dev/null | jq -r '.[].key' +``` + + Then **wait for the user to pick one** (by name). If the command printed one or + more repos, reply in **this exact format**, sorted by name, one row per key, and + nothing else: + + Provisioning a plugins repository for project `` on `` failed, so + pick an existing repository to publish `` to: + + | Repository | + |------------| + | `` | + + If the command printed nothing (no plugins repos on the server), reply with one + line instead, filling `` with the provisioning error: + + > No plugins repositories on `` to publish to (provisioning failed: ``). Tell me a repository to use, or ask me to retry. + + **Never auto-select a repo, even if one exists whose name matches the + project.** A name match is not consent. Do not publish to any repo the user did + not explicitly choose. Never guess a repo. + +## Validate the bundle + +The publish argument is the **path to the folder containing `plugin.json`** (not +the `plugin.json` file itself). Before publishing: + +```bash +test -f "/plugin.json" || echo "No plugin.json at , not a plugin bundle" +``` + +Parse `plugin.json` and confirm it contains at least a `name` field with a +non-empty value. If the bundle is missing `plugin.json` or the required fields are +absent or malformed, do not publish and reply using **this exact template** (no +extra prose), filling `` with the specific issue found: + + > `` is not a publishable plugin bundle: ``. Point me at the + > folder that contains `plugin.json` and I'll retry. + +## Sign the plugin (evidence) + +Signing attaches a cryptographic attestation so the plugin **installs without an +evidence-verification warning** (see *When evidence verification fails* in +`installing-plugins.md`). It is **opt-in**. Never generate keys or sign silently, +and never echo, print, or hardcode the key path or its contents. + +**Ask the user how to sign before doing anything else.** Do **not** inspect, echo, +or probe the signing environment variables up front. Only look at them if the user +picks the environment option below. Use the table below as your own reference. Do +not paste it into the chat. Ask the user to pick one option, **prefer signing**, +and keep **publish unsigned** last: + +| Option | What it needs | When to use | +|--------|---------------|-------------| +| **Provide an existing key** | a **PEM private key path** + **key alias** (its public key already trusted), passed as `--signing-key`/`--key-alias` | the user already has a key | +| **Read from the environment** | `EVD_SIGNING_KEY_PATH` (PEM private key path) + `EVD_KEY_ALIAS` (trusted alias) already exported, picked up with no flags | a signer is already configured in the shell/CI | +| **Generate one now** | run `jf evd gen-keys` (needs **admin** to upload the public key) | no signer exists yet, user runs it or asks you to | +| **Publish unsigned** | nothing | installers hit the evidence warning, least preferred | + +**Ask for the key in the same prompt.** Let the user give the PEM private key path +and key alias in that answer, so **Provide an existing key** needs no follow-up. +Ask again only if they picked it but left the path or alias blank. + +For **Read from the environment**, check both vars are set. If either is missing, +ask the user to export both and retry instead of failing the publish. + +Precedence: an explicit `--signing-key`/`--key-alias` wins. Without it, +`jf agent plugins publish` falls back to `EVD_SIGNING_KEY_PATH`/`EVD_KEY_ALIAS`. +With neither, the publish is unsigned. + +To generate a key pair and register its public key in one step: + +```bash +jf evd gen-keys --key-alias "" \ + --key-file-path "" --server-id "" +# writes /evidence.key (private) + /evidence.pub, uploads the +# public key as a trusted key under +``` + +The key must be a **PEM private key**. Despite `--help` saying "PGP", an armored +PGP key fails with `failed to decode the data as PEM block`. `jf evd gen-keys` +produces the right format. + +## Confirm before publishing + +Once `` is resolved and the bundle validated, **show the user what will be +published and wait for an explicit confirmation**. Reply using this exact template +and do not run `jf agent plugins publish` until the user agrees: + + > Publishing plugin `` uploads it to repository `` on server ``. Do you want to publish it? + +Never combine this final confirmation step with the previous signing step into one prompt. + +If the user says no or names a different repo/name, use that instead and confirm +again. Only proceed to *Publish* after an explicit "yes". + +## Publish + +Publish to the resolved ``. When `--version` is omitted, the CLI uses the +version from `plugin.json`. Only pass `--version` to override with an explicit +semver the user provides; `latest` is not valid. Do not ask the user for a version. +Pass `--signing-key`/`--key-alias` only when signing with an explicit key the +user provided or generated. Omit them when relying on +`EVD_SIGNING_KEY_PATH`/`EVD_KEY_ALIAS` from the environment, or when publishing +unsigned. + +```bash +jf agent plugins publish "" \ + --server-id "" \ + --repo "" \ + --quiet \ + [--version ""] \ + [--signing-key "" --key-alias ""] \ + [--build-name "" --build-number ""] +``` + +Useful flags (verify with `jf agent plugins publish --help`): + +| Flag | Purpose | +|------|---------| +| `--repo` | Target Artifactory repository key. **Required.** | +| `--version` | Explicit semver override (e.g. `1.2.0`). Omit to use the version in `plugin.json`. | +| `--signing-key` | Path to the PEM private key for evidence signing (overrides `EVD_SIGNING_KEY_PATH`). | +| `--key-alias` | Alias of the signer's trusted public key (overrides `EVD_KEY_ALIAS`). | +| `--build-name` / `--build-number` | Optional: record build info for this publish. Both must be provided together. | +| `--module` | Optional module name for the build-info (requires `--build-name`/`--build-number`). | +| `--quiet` | Skip interactive prompts (also defaults to `$CI`). | + +To release a new version, bump the version in `plugin.json` and publish again. Each +publish adds a new version. + +**On a version conflict** (publish fails with `version ... already exists`): +the CLI's `[o] Overwrite` prompt is interactive-only (`--quiet`/CI aborts), so it +cannot be answered from here. Use the table below as your own reference. Do not +paste it into the chat. Ask the user to pick one option, filling `` with the +existing version and `` with the next patch (for example `3.0.0` to `3.0.1`): + +| Option | Action | +|--------|--------| +| **Overwrite** | Run `jf agent plugins delete "" --version "" --repo "" --server-id ""`, then re-run the publish unchanged. | +| **Publish as a new version** | Re-run the publish with `--version ` (the user's semver, or ``). | +| **Abort** | Stop and report that nothing was published. | + +## Report the publish result + +- **Success.** Reply using **this exact template**: + + > Published `@` to `` on ``. + +- **Other failure.** Reply using **this exact template**, quoting the CLI error + verbatim in ``: + + > Publishing `` to `` on `` failed: ``. + + On 401/403/404, follow the stop-on-error rule from the base `jfrog` skill + (see *Prerequisites* in `../SKILL.md`): stop and do not retry against a + different configured server. diff --git a/plugins/jfrog/skills/jfrog-ai-catalog-skills/references/publishing-skills.md b/plugins/jfrog/skills/jfrog-ai-catalog/references/publishing-skills.md similarity index 99% rename from plugins/jfrog/skills/jfrog-ai-catalog-skills/references/publishing-skills.md rename to plugins/jfrog/skills/jfrog-ai-catalog/references/publishing-skills.md index 970d44c..e19bcf8 100644 --- a/plugins/jfrog/skills/jfrog-ai-catalog-skills/references/publishing-skills.md +++ b/plugins/jfrog/skills/jfrog-ai-catalog/references/publishing-skills.md @@ -87,7 +87,7 @@ prose), filling `` with the specific issue found: ## Sign the skill (evidence) -Signing attaches a cryptographic attestation so the skill **installs without an +Signing attaches a cryptographic attestation so the skill **installs without a evidence-verification warning** (see *When evidence verification fails* in `installing-skills.md`). It is **opt-in**. Never generate keys or sign silently, and never echo, print, or hardcode the key path or its contents.