From aea3738ba097588fe45b1f09dc1a2ca10983f90f Mon Sep 17 00:00:00 2001 From: yanivt Date: Tue, 2 Jun 2026 09:33:09 +0300 Subject: [PATCH 1/5] get skills from public repo --- .cursor-plugin/marketplace.json | 2 +- .github/scripts/sync-skills.mjs | 139 ++++ .github/workflows/release.yml | 111 +++ .github/workflows/validate-template.yml | 6 + .gitignore | 5 + README.md | 2 +- plugins/jfrog/.cursor-plugin/plugin.json | 2 +- plugins/jfrog/.vendor.json | 5 + plugins/jfrog/skills/VENDOR.md | 13 - .../SKILL.md | 286 ------- plugins/jfrog/skills/jfrog/SKILL.md | 529 ------------ .../jfrog/references/apptrust-entities.md | 154 ---- .../jfrog/references/artifactory-api-gaps.md | 206 ----- .../references/artifactory-aql-syntax.md | 656 --------------- .../jfrog/references/artifactory-entities.md | 236 ------ .../references/artifactory-operations.md | 178 ----- .../jfrog/references/catalog-entities.md | 219 ----- ...eral-bulk-operations-and-agent-patterns.md | 93 --- .../references/general-parallel-execution.md | 131 --- .../references/general-use-case-hints.md | 27 - .../references/jfrog-brand-html-report.md | 98 --- .../references/jfrog-cli-install-upgrade.md | 30 - .../jfrog/references/jfrog-entity-index.md | 112 --- .../jfrog/references/jfrog-login-flow.md | 132 --- .../jfrog/references/jfrog-url-references.md | 51 -- .../references/onemodel-common-patterns.md | 323 -------- .../jfrog/references/onemodel-graphql.md | 446 ----------- .../references/onemodel-query-examples.md | 753 ------------------ .../references/platform-access-entities.md | 200 ----- .../references/platform-admin-api-gaps.md | 164 ---- .../references/platform-admin-operations.md | 58 -- .../skills/jfrog/references/projects-api.md | 241 ------ .../references/release-lifecycle-entities.md | 180 ----- .../references/stored-packages-entities.md | 165 ---- .../skills/jfrog/references/xray-entities.md | 740 ----------------- .../skills/jfrog/scripts/check-environment.sh | 224 ------ .../scripts/jfrog-login-register-session.sh | 84 -- .../scripts/jfrog-login-save-credentials.sh | 128 --- 38 files changed, 269 insertions(+), 6860 deletions(-) create mode 100755 .github/scripts/sync-skills.mjs create mode 100644 .github/workflows/release.yml create mode 100644 plugins/jfrog/.vendor.json delete mode 100644 plugins/jfrog/skills/VENDOR.md delete mode 100644 plugins/jfrog/skills/jfrog-package-safety-and-download/SKILL.md delete mode 100644 plugins/jfrog/skills/jfrog/SKILL.md delete mode 100644 plugins/jfrog/skills/jfrog/references/apptrust-entities.md delete mode 100644 plugins/jfrog/skills/jfrog/references/artifactory-api-gaps.md delete mode 100644 plugins/jfrog/skills/jfrog/references/artifactory-aql-syntax.md delete mode 100644 plugins/jfrog/skills/jfrog/references/artifactory-entities.md delete mode 100644 plugins/jfrog/skills/jfrog/references/artifactory-operations.md delete mode 100644 plugins/jfrog/skills/jfrog/references/catalog-entities.md delete mode 100644 plugins/jfrog/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md delete mode 100644 plugins/jfrog/skills/jfrog/references/general-parallel-execution.md delete mode 100644 plugins/jfrog/skills/jfrog/references/general-use-case-hints.md delete mode 100644 plugins/jfrog/skills/jfrog/references/jfrog-brand-html-report.md delete mode 100644 plugins/jfrog/skills/jfrog/references/jfrog-cli-install-upgrade.md delete mode 100644 plugins/jfrog/skills/jfrog/references/jfrog-entity-index.md delete mode 100644 plugins/jfrog/skills/jfrog/references/jfrog-login-flow.md delete mode 100644 plugins/jfrog/skills/jfrog/references/jfrog-url-references.md delete mode 100644 plugins/jfrog/skills/jfrog/references/onemodel-common-patterns.md delete mode 100644 plugins/jfrog/skills/jfrog/references/onemodel-graphql.md delete mode 100644 plugins/jfrog/skills/jfrog/references/onemodel-query-examples.md delete mode 100644 plugins/jfrog/skills/jfrog/references/platform-access-entities.md delete mode 100644 plugins/jfrog/skills/jfrog/references/platform-admin-api-gaps.md delete mode 100644 plugins/jfrog/skills/jfrog/references/platform-admin-operations.md delete mode 100644 plugins/jfrog/skills/jfrog/references/projects-api.md delete mode 100644 plugins/jfrog/skills/jfrog/references/release-lifecycle-entities.md delete mode 100644 plugins/jfrog/skills/jfrog/references/stored-packages-entities.md delete mode 100644 plugins/jfrog/skills/jfrog/references/xray-entities.md delete mode 100755 plugins/jfrog/skills/jfrog/scripts/check-environment.sh delete mode 100755 plugins/jfrog/skills/jfrog/scripts/jfrog-login-register-session.sh delete mode 100755 plugins/jfrog/skills/jfrog/scripts/jfrog-login-save-credentials.sh diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json index 6947c05..499cffb 100644 --- a/.cursor-plugin/marketplace.json +++ b/.cursor-plugin/marketplace.json @@ -6,7 +6,7 @@ }, "metadata": { "description": "JFrog Platform plugins for Cursor", - "version": "0.5.0", + "version": "0.5.1", "pluginRoot": "plugins" }, "plugins": [ diff --git a/.github/scripts/sync-skills.mjs b/.github/scripts/sync-skills.mjs new file mode 100755 index 0000000..134e2e1 --- /dev/null +++ b/.github/scripts/sync-skills.mjs @@ -0,0 +1,139 @@ +#!/usr/bin/env node +// Vendors skill content from the upstream jfrog/jfrog-skills repository +// into this plugin at release time. `main` itself never contains the +// synced files — they live only on the release tag. +// +// Called by .github/workflows/release.yml. Also safe to run locally to +// preview what a pin bump will produce — plugins//skills/ is +// gitignored, so the result is invisible to git. +// +// For each plugin listed in .cursor-plugin/marketplace.json, this script: +// 1. Reads /.vendor.json to learn which repo + ref to pull. +// 2. Downloads that tarball from codeload.github.com (public, no auth). +// 3. Extracts it into a temp directory. +// 4. Copies the requested paths (e.g. "skills") into the plugin folder. +// +// Set SKILLS_REF to override the pin for one run (e.g. SKILLS_REF=v0.12.0). + +import { promises as fs, createWriteStream } from "node:fs"; +import { Readable } from "node:stream"; +import { pipeline } from "node:stream/promises"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; +import { tmpdir } from "node:os"; + +// filesystem helpers +async function readJson(filePath) { + return JSON.parse(await fs.readFile(filePath, "utf8")); +} + +async function fileExists(filePath) { + try { await fs.access(filePath); return true; } catch { return false; } +} + +// download the upstream tarball + +// codeload.github.com serves any public repo's archive over HTTPS +// without auth, accepting a tag, branch, or commit SHA as the ref. +async function downloadTarball(repo, ref, destPath) { + const url = `https://codeload.github.com/${repo}/tar.gz/${encodeURIComponent(ref)}`; + const res = await fetch(url, { redirect: "follow" }); + if (!res.ok) throw new Error(`Could not download ${repo}@${ref} (HTTP ${res.status})`); + await pipeline(Readable.fromWeb(res.body), createWriteStream(destPath)); + console.log(` fetched ${url}`); +} + +// extract the tarball + +// Shells out to the system `tar` instead of pulling in an npm tar library — +// keeps the script zero-dependency. +// +// GitHub tarballs always have exactly one top-level directory whose +// name encodes the repo + commit. We return that path so the caller +// knows where to find the extracted tree. +async function extractTarball(tarballPath, intoDir) { + await fs.mkdir(intoDir, { recursive: true }); + const result = spawnSync("tar", ["-xzf", tarballPath, "-C", intoDir], { stdio: "inherit" }); + if (result.status !== 0) throw new Error(`tar exited with status ${result.status}`); + const [topLevel] = await fs.readdir(intoDir); + return path.join(intoDir, topLevel); +} + +// copy one path from the extracted tree into the plugin + +// Removes the destination first so we never end up with stale leftovers +// from a previous sync, then creates the destination's parent directory then copies. +async function copyPath(fromDir, toDir, relativePath) { + const from = path.join(fromDir, relativePath); + const to = path.join(toDir, relativePath); + if (!(await fileExists(from))) { + throw new Error(`path missing in upstream tarball: ${relativePath}`); + } + await fs.rm(to, { recursive: true, force: true }); + await fs.mkdir(path.dirname(to), { recursive: true }); + await fs.cp(from, to, { recursive: true }); + console.log(` ${relativePath} -> ${path.relative(process.cwd(), to)}`); +} + +// Resolve a marketplace plugin entry to its on-disk directory. +// +// The Cursor marketplace manifest can declare a shared `metadata.pluginRoot` +// (e.g. "plugins") that is prepended to each plugin's `source` (e.g. "jfrog"), +// so the real plugin folder is `plugins/jfrog`. If `pluginRoot` is absent or +// already a prefix of `source`, the source is used as-is. +function resolvePluginDir(plugin, pluginRoot) { + const source = plugin.source ?? ""; + if (!source) throw new Error(`plugin "${plugin.name}" is missing a "source"`); + if (!pluginRoot) return path.resolve(source); + const normalizedRoot = pluginRoot.replace(/\/+$/, ""); + if (source === normalizedRoot || source.startsWith(`${normalizedRoot}/`)) { + return path.resolve(source); + } + return path.resolve(normalizedRoot, source); +} + +// Sync one plugin: read its .vendor.json, download + extract + copy. +// Plugins without a .vendor.json are silently skipped. +// +// SKILLS_REF env var (set by the release workflow's `skills_version` +// input) overrides the pin for ad-hoc releases; falls back to the +// pin in .vendor.json when unset or empty. +async function syncPlugin(plugin, pluginRoot, workDir) { + const pluginDir = resolvePluginDir(plugin, pluginRoot); + const vendorPath = path.join(pluginDir, ".vendor.json"); + if (!(await fileExists(vendorPath))) return; + + const { repo, pin, paths } = await readJson(vendorPath); + if (!repo || !pin || !Array.isArray(paths) || paths.length === 0) { + throw new Error(`${vendorPath} must define 'repo', 'pin' and a non-empty 'paths' array`); + } + + const ref = process.env.SKILLS_REF?.trim() || pin; + const overridden = ref !== pin; + console.log(`--- ${plugin.name} (ref: ${ref}${overridden ? " [override]" : ""}) ---`); + + // `slug` is just a unique filename for this plugin's tarball + extract. + const slug = `${repo.replace("/", "-")}-${ref.replace(/[^A-Za-z0-9._-]/g, "_")}`; + const tarball = path.join(workDir, `${slug}.tar.gz`); + await downloadTarball(repo, ref, tarball); + const extracted = await extractTarball(tarball, path.join(workDir, slug)); + for (const rel of paths) await copyPath(extracted, pluginDir, rel); +} + +// Entry point: walk .cursor-plugin/marketplace.json, sync each plugin +// sequentially, always clean up the temp work directory. +async function main() { + const marketplace = await readJson(".cursor-plugin/marketplace.json"); + const pluginRoot = marketplace.metadata?.pluginRoot ?? ""; + const workDir = await fs.mkdtemp(path.join(tmpdir(), "sync-skills-")); + try { + for (const plugin of marketplace.plugins ?? []) { + await syncPlugin(plugin, pluginRoot, workDir); + } + } finally { + await fs.rm(workDir, { recursive: true, force: true }); + } + console.log("done."); +} + +await main(); diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1550b53 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,111 @@ +# Copyright (c) JFrog Ltd. 2026 +# Licensed under the Apache License, Version 2.0 +# https://www.apache.org/licenses/LICENSE-2.0 + +# Tags a release for the Cursor marketplace. +# +# What this workflow does, in order: +# 1. Clones the current `main` (which is skill-free — see .gitignore). +# 2. Pulls skill content from jfrog/jfrog-skills@ into +# plugins//skills/. +# 3. Reads the version from .cursor-plugin/marketplace.json (already +# bumped in a PR). +# 4. Creates a detached commit, tags it v, and pushes only the +# tag. `main` itself is never modified by CI. +# 5. Publishes a GitHub Release pointing at the tag. +# +# To trigger: Actions → "Release plugin" → Run workflow. +# Access is gated by the `release` Environment — configure required +# reviewers in Settings → Environments → release. + +name: Release plugin + +on: + workflow_dispatch: + inputs: + skills_version: + description: "Optional override for the upstream skill ref (tag/branch/SHA). Leave empty to use the pin in plugins//.vendor.json." + required: false + default: "" + +permissions: + # Needed so the workflow can push the new tag and create the release. + contents: write + +jobs: + release: + runs-on: ubuntu-latest + # Access control lives in the `release` environment (Settings → + # Environments → release → Required reviewers). The job pauses + # until a listed reviewer approves the run; non-reviewers cannot + # move it forward. + environment: release + steps: + # Check out main + # Shallow clone is enough: we never look at past commits, we only + # add a new one on a detached HEAD further down. + - name: Check out main + uses: actions/checkout@v6 + with: + ref: main + + # Install Node + # Needed for the sync script and for reading marketplace.json in + # the "Resolve release tag" step. + - name: Install Node.js + uses: actions/setup-node@v6 + with: + node-version: "20" + + # Vendor the skills from upstream + # Downloads the upstream tarball at the pin declared in each + # plugin's .vendor.json (e.g. jfrog/jfrog-skills@v0.11.0) and + # copies its skill folders into the plugin. If the operator + # supplied a `skills_version` input, it overrides the pin for this + # run. + - name: Sync skills from upstream + env: + SKILLS_REF: ${{ inputs.skills_version }} + run: node .github/scripts/sync-skills.mjs + + # Read the release version from .cursor-plugin/marketplace.json + # The version is bumped in a normal PR before triggering this + # workflow; the workflow itself never edits files. Fails if the + # marketplace metadata is missing a non-empty version. + - name: Resolve release tag + run: | + VERSION=$(node -e ' + const meta = require("./.cursor-plugin/marketplace.json").metadata ?? {}; + if (!meta.version) process.exit(1); + console.log(meta.version); + ') + if [ -z "$VERSION" ]; then + echo "::error::.cursor-plugin/marketplace.json must define a non-empty metadata.version" + exit 1 + fi + echo "TAG=v${VERSION}" >> "$GITHUB_ENV" + + # Create a detached commit, tag, and push the tag + # `git checkout --detach` lets us commit without moving `main`. + # We push only the tag (`origin `), so the synced skills + # live exclusively on the release tag. + # + # If the version on main was never bumped, `git push` rejects the + # tag as "already exists" — clean failure, no force push. + - name: Tag the release + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git checkout --detach + git add -A + git commit -m "Release ${TAG}" + git tag "${TAG}" + git push origin "${TAG}" + + # Publish a GitHub Release + # `--generate-notes` asks GitHub to auto-write release notes from + # the PRs merged since the previous tag. + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release create "${TAG}" --title "${TAG}" --generate-notes diff --git a/.github/workflows/validate-template.yml b/.github/workflows/validate-template.yml index c82c73e..abe1b78 100644 --- a/.github/workflows/validate-template.yml +++ b/.github/workflows/validate-template.yml @@ -25,5 +25,11 @@ jobs: with: node-version: "20" + # Skills are vendored from jfrog/jfrog-skills only at release time + # (see .gitignore + plugins//.vendor.json). Sync them + # before validation so plugin.json's skill paths resolve. + - name: Sync skills from upstream + run: node .github/scripts/sync-skills.mjs + - name: Run template validation run: node scripts/validate-template.mjs diff --git a/.gitignore b/.gitignore index 466f0c8..ee764ae 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,8 @@ tmp/ temp/ .fly/ + +# Skills are vendored from jfrog/jfrog-skills only at release time (see +# plugins//.vendor.json and .github/scripts/sync-skills.mjs). +# main is skill-free. +plugins/*/skills/ diff --git a/README.md b/README.md index 627aeb1..d430279 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ JFrog plugin for [Cursor](https://cursor.com): artifact management, security scanning, supply-chain best practices, and Agent Guard. -## What's new in v0.5.0 +## What's new in v0.5.1 - **Official skills.** The plugin now uses the official [jfrog-skills](https://github.com/jfrog/jfrog-skills) v0.11.0, replacing the previously bundled skill content. This brings structured reference files, automation scripts, and a three-tier tool selection strategy (MCP, CLI, REST/GraphQL). - **Package safety skill.** New `jfrog-package-safety-and-download` skill for checking whether packages are safe, curated, or allowed before downloading them through Artifactory. diff --git a/plugins/jfrog/.cursor-plugin/plugin.json b/plugins/jfrog/.cursor-plugin/plugin.json index 71ccb48..070de6d 100644 --- a/plugins/jfrog/.cursor-plugin/plugin.json +++ b/plugins/jfrog/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "jfrog", "displayName": "JFrog Platform", - "version": "0.5.0", + "version": "0.5.1", "description": "JFrog Platform integration with MCP, security skills, supply-chain best practices, and JFrog Agent Guard governance for adding, removing, and listing MCP servers.", "author": { "name": "JFrog", diff --git a/plugins/jfrog/.vendor.json b/plugins/jfrog/.vendor.json new file mode 100644 index 0000000..b4c4d06 --- /dev/null +++ b/plugins/jfrog/.vendor.json @@ -0,0 +1,5 @@ +{ + "repo": "jfrog/jfrog-skills", + "pin": "v0.11.0", + "paths": ["skills"] +} diff --git a/plugins/jfrog/skills/VENDOR.md b/plugins/jfrog/skills/VENDOR.md deleted file mode 100644 index c72b69e..0000000 --- a/plugins/jfrog/skills/VENDOR.md +++ /dev/null @@ -1,13 +0,0 @@ -# Vendored skills - -The skill packages in this directory are vendored from **[jfrog/jfrog-skills](https://github.com/jfrog/jfrog-skills)**. - -| | | -| --- | --- | -| **Repository** | https://github.com/jfrog/jfrog-skills | -| **Release** | [v0.11.0](https://github.com/jfrog/jfrog-skills/releases/tag/v0.11.0) | -| **Source commit** | `66e7d1d1e7b762bbf9e356d680511c4fb4ce231c` | - -Included directories: `jfrog/`, `jfrog-package-safety-and-download/`. - -To refresh: take the [latest release tarball](https://github.com/jfrog/jfrog-skills/releases/latest), replace those skill trees under `skills/`, and update this file with the new tag and commit SHA. diff --git a/plugins/jfrog/skills/jfrog-package-safety-and-download/SKILL.md b/plugins/jfrog/skills/jfrog-package-safety-and-download/SKILL.md deleted file mode 100644 index 598318a..0000000 --- a/plugins/jfrog/skills/jfrog-package-safety-and-download/SKILL.md +++ /dev/null @@ -1,286 +0,0 @@ ---- -name: jfrog-package-safety-and-download -description: >- - Check JFrog Public Catalog and stored packages for a version, interpret - catalog security signals, and download through Artifactory (JFrog Platform - locations, remote cache, curation-aware package managers, or repo proxy). - Use when the user asks whether a package is safe, allowed, curated, or - wants to download npm, Maven, PyPI, Go, or similar packages via JFrog. - Do NOT use for pure CVE or vulnerability lookups (e.g. "details on - CVE-2021-23337") — those are handled by the jfrog skill's Public security - domain queries without this workflow. -metadata: - role: workflow ---- - -# JFrog Package Safety and Download - -## Prerequisites - -- Read `../jfrog/SKILL.md` for JFrog Platform concepts, domain model, CLI setup, and API patterns. -- **OneModel shapes drift by server version.** Before inventing GraphQL fields or `where` filters, read `../jfrog/references/onemodel-graphql.md` (schema fetch workflow) and `../jfrog/references/onemodel-query-examples.md` (**Public packages**, **Stored packages**). Regenerate or verify queries against `GET "$JFROG_URL/onemodel/api/v1/supergraph/schema"` when examples fail validation. - -## Workflow - -# Package safety check and download workflow - -When to read this file: - -- User asks to **check if a package is safe** and/or **download** it. -- User asks to **download a package** from Artifactory. -- User mentions checking a package for **curation** approval. -- User wants to know if a package is **allowed** or **approved** for use. - -## Workflow overview - -```mermaid -flowchart TD - A[User requests package check / download] --> B{Package in Public Catalog?} - B -->|Yes| C[Get latest version from Catalog] - B -->|No| D{Package in JFrog Platform Stored Packages?} - D -->|Yes| E[Get latest version from Stored Packages] - D -->|No| F[Package not found — stop] - C --> G{Latest version in JFrog Platform?} - E --> G - G -->|Yes| H[Safe — download from JFrog Platform] - G -->|No| I{Curation entitled?} - I -->|Yes| J[Check curation policy via API] - I -->|No| K[Download via remote repo] - J -->|200 Allowed| K - J -->|403 Blocked| M[Report curation blocked — stop] -``` - -### Parallelization opportunities - -Several steps in this workflow are independent and can run in parallel to -reduce total latency: - -- **Step 1 + Step 1 fallback**: When package type is known, query both the - Public Catalog (`getPackage`) and Stored Packages (`getPackage`) in - parallel. Use whichever returns data; if the Public Catalog returns a hit, - prefer its `latestVersion` for Step 2. -- **Step 3 + Step 5**: After determining the version, query stored package - versions (JFrog Platform check) and curation entitlement - (`/api/system/version`) in parallel. Both are independent reads — the - curation result is needed immediately if the JFrog Platform check returns - empty. - -When issuing parallel Shell calls, each `jf api` call authenticates -independently against the active `jf config` server; no shell state needs -to be passed between calls. - -## Step 1: Find the package - -Search the **Public Catalog** first via OneModel GraphQL, then fall back to -**Stored Packages** if not found. - -Execute the query through `jf api` as described in -`../jfrog/references/onemodel-graphql.md`; refer to -`../jfrog/references/onemodel-query-examples.md` for concrete query shapes. - -**When package type is known** (e.g. `npm`, `maven`, `pypi`), use -`publicPackages.getPackage(type:, name:)` (see *Get a public package*). -Include the `latestVersion { version }` selection set — `latestVersion` is -an object, not a scalar. - -**When type is unknown**, use `publicPackages.searchPackages` with -`nameContains` (see *Search public packages*). Add `type:` when the user -narrows the ecosystem. - -- **Found** → note `type` and `latestVersion.version`. Proceed to Step 2. -- **Not found** → the package may be 1st/2nd party. Search **Stored Packages** - using `storedPackages.searchPackages` or `storedPackages.getPackage` (see - *Stored packages domain* in `onemodel-query-examples.md`). Prefer - filtering by `type` when known; if not, use `nameContains` alone. - - **Found** → note `type` and `latestVersionName` (or derive a version from - `versionsConnection`). Proceed to Step 2. - - **Not found in either** → report "package not found" and stop. - -If multiple results with different `type` values, ask the user which package -type they mean. - -## Step 2: Determine latest version - -| Source | Version field | -|--------|--------------| -| Public Catalog | `latestVersion.version` (object selection required) | -| JFrog Platform Stored Packages | `latestVersionName` on `StoredPackage`, or highest entry from `versionsConnection` | - -## Step 3: Check if package + latest version exists in JFrog Platform - -Query stored package versions using `storedPackages.searchPackageVersions` -with a `hasPackageWith` filter (see `../jfrog/references/onemodel-query-examples.md` -→ *Search stored package versions*). Add a `version` filter for the specific -version from Step 2, and request `locationsConnection` to get repository -details (`repositoryKey`, `repositoryType`, `leadArtifactPath`). - -Execute the query through `jf api` (see -`../jfrog/references/onemodel-graphql.md` for the invocation pattern). - -- **Found with locations** → package is in the JFrog Platform. Report as **safe to - download**. Proceed to Step 4. -- **Not found** → proceed to Step 5. - -## Step 4: Download from JFrog Platform - -Use the location info from Step 3. Binary artifact downloads go through -`jf rt dl` — **not** `jf api`. `jf api` is the unified entry point for the -JFrog REST APIs (metadata, admin, curation, etc.) and does not expose the -`-L` / `-o` flags needed to stream binary content through a redirect chain. - -**`` must be a full file path** (e.g. -`./downloads/lodash-4.18.1.tgz`), not a bare directory. `jf rt dl --flat` -treats the target as a file name; passing a directory causes a misleading -"open path: is a directory" error. - -| `repositoryType` | Strategy | -|-------------------|----------| -| `local` or `federated` | `jf rt dl "/" --flat` | -| `remote` | `jf rt dl` against the **base** remote repo (strip any trailing `-cache`) — it transparently triggers the remote fetch when the artifact is not yet cached | - -**local / federated / remote download:** - -```bash -jf rt dl "/" --flat -``` - -**Resolving the remote repo key:** The `repositoryKey` returned by OneModel -for remote locations often already ends in `-cache` (e.g. -`devNPM-remote-cache`). `jf rt dl` needs the **base remote repo name** -(without `-cache`). Strip the `-cache` suffix when present (e.g. -`devNPM-remote-cache` → `devNPM-remote`). If the key does not end in -`-cache`, use it as-is. - -See the **Protocol endpoints** table below for the package-type-specific -path format inside the repo. - -## Step 5: Check curation entitlement - -```bash -jf api /artifactory/api/system/version \ - | jq '.addons | index("curation") != null' -``` - -- `true` → curation is entitled. Proceed to Step 6a. -- `false` → curation not available. Proceed to Step 6b. - -## Step 6a: Check curation policy and download - -When curation is entitled, use the Xray curation API to check whether the -package version is allowed across all repositories before downloading. - -```bash -RESPONSE_FILE="/tmp/curation-status-$$.json" -PAYLOAD_FILE="/tmp/curation-payload-$$.json" -STDERR_FILE="/tmp/curation-err-$$.log" - -jq -n \ - --arg type "" \ - --arg name "" \ - --arg version "" \ - '{packageType:$type, packageName:$name, packageVersion:$version}' \ - > "$PAYLOAD_FILE" - -set +e -jf api /xray/api/v1/curation/package_status/all_repos \ - -X POST -H "Content-Type: application/json" \ - --input "$PAYLOAD_FILE" \ - > "$RESPONSE_FILE" 2> "$STDERR_FILE" -RC=$? -set -e -echo "RC=$RC"; echo "$RESPONSE_FILE" -``` - -Supported `packageType` values: `npm`, `pypi`, `maven`, `go`, `nuget`, -`docker`, `gradle`. - -**Interpreting the result with `jf api`**: unlike plain `curl`, `jf api` -surfaces the HTTP result through its **exit code** and a -`" [Warn] ... returned 4xx/5xx"` line on **stderr** (not a -`%{http_code}` suffix in stdout). The response body is always written to -stdout. Parse both: - -```bash -if [ "$RC" -eq 0 ]; then - echo "Package is allowed by curation." -elif grep -q 'returned 403' "$STDERR_FILE"; then - echo "Blocked by curation policy:" - cat "$RESPONSE_FILE" -else - echo "Curation check failed (rc=$RC):" - cat "$STDERR_FILE" -fi -``` - -**Evaluate the outcome:** - -- **exit 0** → package is **allowed** by curation policy. Proceed to - download via a remote repo (same as Step 6b). -- **`returned 403` on stderr** → package is **blocked** by a curation - policy. The response body explains which policy rule blocked it. Report - the block reason to the user and stop — do not attempt to download. -- **Any other non-zero exit** → treat as an operational failure (auth, DNS, - endpoint disabled) and report. - -## Step 6b: Download without curation - -When curation is not entitled and the package is not in the JFrog Platform, -download directly through a remote repo. - -1. **Find a remote repo** of the right package type: - - ```bash - jf api \ - "/artifactory/api/repositories?type=remote&packageType=" \ - | jq '.[].key' - ``` - -2. **Download** — use `jf rt dl` against the base remote repo (without - `-cache`); it handles both cached and uncached artifacts: - - ```bash - jf rt dl "/" --flat - ``` - -## Artifact paths by package type - -Use these path patterns when `leadArtifactPath` is not available from -OneModel. The leading `/` is the base repo key you pass to `jf rt dl`. - -| Type | `jf rt dl` target pattern | -|--------|-------------------------------------------------------------------------| -| `npm` | `//-/-.tgz` | -| `pypi` | `///-.tar.gz` | -| `maven`| `////-.jar` | -| `go` | `//@v/.zip` | - -## Gotchas - -- **Binary downloads vs. `jf api`**: `jf api` is for REST APIs, not binary - content. It does not follow redirects transparently into a binary payload - and does not expose `-L` / `-o`. Always use `jf rt dl` (against the base - remote repo, not the `-cache` one) for the actual artifact download. -- **`jf rt dl` and uncached remotes**: `jf rt dl "/"` — - targeting the **base** remote repo rather than `-cache/` — - transparently triggers the remote fetch and caches the artifact. Do not - try to pre-query the proxy via `jf api`. -- **`jf rt dl --flat` target must be a file path**: When downloading a - single artifact, pass a full output **file** path (e.g. - `./downloads/lodash-4.18.1.tgz`), not a directory. The CLI opens the target - path as a file; a directory causes a cryptic "open path: is a directory" - error that retries four times before failing. Derive the filename from - `leadArtifactPath` (take the segment after the last `/`). -- **Package type detection**: If the user doesn't specify the package type, - the Public Catalog search by name alone may return multiple types. Ask the - user to disambiguate before proceeding. -- **Curation endpoint lives under Xray**: use - `/xray/api/v1/curation/package_status/all_repos` (via `jf api`). Do not - prefix it with `/artifactory`. -- **Curation result discrimination with `jf api`**: the 200/403 signal comes - from `jf api`'s **exit code** plus a `returned NNN` line on **stderr**, - not from a `%{http_code}` appended to stdout. Capture stderr to a file - (`2> "$STDERR_FILE"`) and branch on `RC` + `grep 'returned 403'` as shown - in Step 6a. -- **Curation API package type values**: Must be lowercase and match one of - `npm`, `pypi`, `maven`, `go`, `nuget`, `docker`, `gradle`. Other values - will return an error. diff --git a/plugins/jfrog/skills/jfrog/SKILL.md b/plugins/jfrog/skills/jfrog/SKILL.md deleted file mode 100644 index 67e0391..0000000 --- a/plugins/jfrog/skills/jfrog/SKILL.md +++ /dev/null @@ -1,529 +0,0 @@ ---- -name: jfrog -description: >- - Interact with the JFrog Platform via the JFrog CLI, JFrog MCP server and REST/GraphQL APIs. - Use this skill when the user wants to manage Artifactory repositories, - upload or download artifacts, manage builds, configure permissions, - manage users and groups, work with access tokens, configure JFrog CLI - servers, search artifacts, manage properties, set up replication, - manage JFrog Projects, run security audits or scans, look up CVE details, - query exposures scan results from JFrog Advanced Security, manage - release bundles and lifecycle operations, aggregate or export platform - data, or perform any JFrog Platform administration task. - Also use when the user mentions jf, jfrog, artifactory, xray, distribution, - evidence, apptrust, onemodel, graphql, workers, mission control, curation, - advanced security, exposures, or any JFrog product name. -compatibility: >- - Requires jq on PATH. -metadata: - role: base - version: "0.11.0" ---- - -# JFrog Skill - -The foundational skill for all JFrog agent interactions. Covers JFrog Platform concepts, `jf` CLI setup and authentication, and intent routing to workflow skills. - -Interact with the JFrog Platform through three tool tiers — see -[Tool selection strategy](#tool-selection-strategy). In code examples below, -`` refers to this skill's directory and is resolved automatically -by the agent. If the agent does not resolve it, determine the path by locating -this SKILL.md file and using its parent directory. - -## Tool selection strategy - -Try the tiers in order; move to the next only when the current does not -cover the operation or fails: - -1. **JFrog MCP tools** (preferred): `CallMcpTool` against the JFrog MCP - server. Discover available tools from the server's tool list; never - guess tool names. -2. **`jf` CLI subcommands** (fallback): dedicated commands such as - `jf rt upload`, `jf rt dl`, `jf build-publish`. -3. **`jf api`** (last resort): REST/GraphQL endpoints with no dedicated - subcommand. Validate the path first — see rule 6 in - [Cautious execution](#cautious-execution). - -MCP and the CLI may use different token scopes. If one tier returns 403, -try the alternate tier before reporting the operation blocked. - -## Prerequisites - -The following tools must be available on `PATH`: - -| Tool | Purpose | -|------|---------| -| `jq` | JSON parsing of CLI and API output | - -All JFrog HTTP traffic from Tiers 2 and 3 goes through the `jf` CLI itself -(`jf api`, see [Invoking platform APIs with `jf api`](#invoking-platform-apis-with-jf-api) below) — -no standalone `curl` is required for any JFrog interaction. - -**Runtime permission for JFrog calls.** All `jf` calls that touch the network -need an outbound-HTTPS escalation from the agent runtime. The `~/.jfrog/` -credential save (`jf config add` during login) additionally needs a -filesystem-write escalation. - -| Runtime | Network | Network + `~/.jfrog/` write | -| ----------- | --------------------------------------------- | ------------------------------- | -| Cursor | `required_permissions: ["full_network"]` | `required_permissions: ["all"]` | -| Claude Code | `allowed-tools: Bash(jf:*)` + host allowlist | same + filesystem allowlist | -| Other | Configure at the runtime/sandbox layer | same | - -If `jf` exits 1 with empty output, the runtime's network gate is the first -thing to check — re-run with the appropriate escalation above. - -## Environment check - -MCP (Tier 1) operations do not require this check and can proceed immediately. -Before your first Tier 2 or Tier 3 (`jf`) operation in a session, run the -environment check and **remember its stdout** as `` for the rest of the -session: - -```bash -bash /scripts/check-environment.sh -# stdout (one line): jfrog-skills/ [(tool=; model=)] jfrog-cli-go/ -# stderr: JSON state (cached 24h at ${JFROG_CLI_HOME_DIR:-$HOME/.jfrog}/skills-cache/jfrog-skill-state.json) -``` - -Pass the precise underlying-model slug with version: `opus-4.7`, -`sonnet-4.5`, `gpt-5-codex`, `gemini-2.5-pro`, `composer-2-fast`. Cursor's -Composer product slug **is** the canonical id — use it as-is. Do **not** -pass harness/role names (`subagent`, `agent`, `assistant`) or bare family -names (`claude`, `gpt`); subagents inherit the parent's slug. If genuinely -unknown, pass `unknown`. - -### Export `JFROG_CLI_USER_AGENT` once per bash invocation - -At the top of every bash invocation that runs `jf`, export `` once; -all `jf` calls in that invocation pick it up: - -```bash -export JFROG_CLI_USER_AGENT='' -jf config show -jf api /artifactory/api/system/version -``` - -Do **not** repeat the assignment per `jf` call (`JFROG_CLI_USER_AGENT='' jf …` -on every line). Examples elsewhere in this skill and in `references/*.md` -omit the export for readability — the rule is global. When launching a -subagent, pass `` in its prompt; subagents do not re-run the script. - -| Exit | Meaning | -|------|---------| -| 0 | Cache fresh — CLI ready (Tiers 2 and 3 available), proceed | -| 1 | Cache refreshed — CLI ready (Tiers 2 and 3 available), proceed | -| 2 | `jf` not installed — Tiers 2 and 3 unavailable; only MCP (Tier 1) remains | -| 3 | `jf` below minimum version — Tiers 2 and 3 unavailable; only MCP (Tier 1) remains | - -Exit 2 or 3 is not a fatal error. Attempt to install or upgrade the CLI -(see `references/jfrog-cli-install-upgrade.md`). If installation succeeds, -re-run the environment check. If installation is not possible (no permissions, -restricted environment), proceed with MCP (Tier 1) only. Both `jf` CLI commands -(Tier 2) and `jf api` (Tier 3) require a working `jf` installation. - -### JSON parsing (`jq`) - -Use **`jq`** for all JSON parsing of CLI and API output (pipes, `-r`, filters). - -## `~/.jfrog/skills-cache/` — allowed files only - -`${JFROG_CLI_HOME_DIR:-$HOME/.jfrog}/skills-cache/` is **not** a general scratch -or temp directory. Use it **only** for these two artifacts: - -1. **`jfrog-skill-state.json`** — written by `scripts/check-environment.sh` - (24-hour CLI check cache). -2. **`onemodel-schema-${JFROG_SERVER_ID}.graphql`** — cached OneModel supergraph - schema (see `references/onemodel-graphql.md`). - -**Do not** save HTTP response bodies, GraphQL query results, ad-hoc JSON, reports, -or any other temporary files under `skills-cache/`. Write those to a host temp -path instead (for example `/tmp/-$$.json` or `mktemp -d`), echo the path -when a follow-up Shell step must read the file — same pattern as *Preserving -command output* below. - -## Cautious execution - -Do not run commands speculatively. Before executing any JFrog CLI command, -MCP tool call, or API call: - -1. Confirm the operation is needed to fulfill the user's request. - If the request is ambiguous or could refer to multiple systems (e.g. - "builds" could mean Artifactory build-info or CI/CD pipeline runs), - **ask the user for clarification** instead of guessing. Never fetch data - from the wrong system — a wrong answer is worse than asking a question. -2. Resolve the target server using the **Server selection rules** below — - there must be no ambiguity about which server is used -3. For mutating operations (create, update, delete, upload), confirm with the - user unless the intent is clearly implied. This applies to all tiers - (MCP tools, CLI commands, and `jf api` with POST/PUT/DELETE). -4. Prefer read operations first to understand current state before making changes -5. **Never invent preparatory mutations.** If the requested operation fails - because a precondition is not met (artifact missing from the specified repo, - repository does not exist, package not at the expected location, build not - found), **stop and report the gap to the user**. Do not perform copy, move, - upload, create-repo, or any other mutating operation to satisfy the - precondition unless the user explicitly asks for it. These "helper" mutations - can have cascading effects the user has not considered — virtual repository - resolution changes, storage quota consumption, replication triggers, Xray - re-indexing, or permission propagation. -6. **Never guess tool names or API paths.** For MCP tools, confirm the tool - exists in the server's tool list. For `jf api` paths, validate against - `/references/` (or - [JFrog OpenAPI specifications](https://docs.jfrog.com/integrations/docs/openapi-specifications) - if you have web access). On a 404, stop and report — never retry with a guessed - alternative path. - -## Server selection rules (mandatory) - -**Single-server invariant.** Every `jf` call MUST pass `--server-id ` -(default resolved below); for one user request, all `jf` calls use **exactly -one** server-id. A wrong answer from the wrong server is worse than a stop-and-ask. - -**JFrog MCP and CLI use independent auth.** MCP tools authenticate through -the MCP server session (not `jf config`); CLI commands authenticate through -`jf config`. If you switch the CLI target server via `jf config use`, the -MCP connection still points to its original server. Do not mix MCP and CLI -calls targeting different servers in the same session. If the user asks to -switch servers, warn that MCP tools will continue to target the original -server until the MCP connection is re-established. - -**MUST NOT** retry on a second configured server after 401/403/404, empty, or -partial results; **MUST NOT** infer multi-server intent from "my"/"our" or -from seeing extra entries in `jf config show`. **Override:** only when the user -**explicitly** names another id ("on ``, …", "use ``", "compare `` -and ``") — inferred intent is not an override. - -### Resolve the default once per session - -Before your first `jf` call, resolve the default server-id and **remember it** -as `` for the rest of the session, same pattern as ``: - -```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 to use -``` - -Pass `--server-id ` to every subsequent `jf` call. The flag goes -**after** the subcommand name, not after `jf` itself: - -- ✅ `jf api --server-id /artifactory/api/system/version` -- ✅ `jf rt ping --server-id ` -- ❌ `jf --server-id api /…` — fails with `flag provided but not defined` - -When launching a subagent, pass `` in its prompt — subagents do not -re-resolve. Examples elsewhere in this skill and in `references/*.md` omit -`--server-id` for readability; the rule is global, same as -`JFROG_CLI_USER_AGENT`. To add a new server, read -`references/jfrog-login-flow.md`. - -### On any error, stop — never switch - -If a `jf` call returns 401/403, 404, network error, timeout, or any other -failure, **stop with no further `jf` calls** and respond: - -> `` returned `` for ``: ``. Other -> configured server(s): `` — I won't query them without your explicit -> instruction. How would you like to proceed? - -## When to read reference files - -Load the most specific file for the task at hand. Avoid loading more than 2-3 -reference files for a single operation — start with the most relevant one and -only load additional files if the first doesn't cover the need. File sizes -vary (~25–640 lines); larger files are noted with approximate line counts -below. - -### Cross-domain - -- **Disambiguating a JFrog entity, understanding entity types, or planning operations that span multiple products**: read `references/jfrog-entity-index.md`, then follow pointers to the relevant domain file -- **Looking up documentation URLs**: read `references/jfrog-url-references.md` - -### Artifactory - -- **Repository types, artifacts, builds, properties, or permission targets (concepts)**: read `references/artifactory-entities.md` (~220 lines) -- **Stored packages, package versions, version locations, or the metadata layer over Artifactory (concepts)**: read `references/stored-packages-entities.md` (~165 lines) -- **Repo, file, build, permission, user/group, or replication operations**: if the JFrog MCP server exposes a tool for the operation, prefer it. For CLI/API fallback, read `references/artifactory-operations.md` (for **listing builds** use AQL with `limit`/`offset` — see § *Listing build names*; for **full build detail** use `GET /api/build//?project=` — see § *Retrieving full build info*) -- **AQL queries**: read `references/artifactory-aql-syntax.md` (~585 lines) -- **Artifactory REST beyond the CLI, structured JSON templates (replacing interactive wizards), or any Artifactory API gap**: read `references/artifactory-api-gaps.md` (~220 lines) - -### Xray & security - -- **Watches, policies, violations, components, or vulnerability scanning (concepts)**: read `references/xray-entities.md` (~290 lines) -- **Exposures scanning results (secrets, IaC, service misconfigurations, application security risks)**: read `references/xray-entities.md` § Exposures (Advanced Security) -- **Curation audit events (approved/blocked packages, dry-run policy evaluations, curation export)**: read `references/xray-entities.md` § Curation audit events - -### Release lifecycle & distribution - -- **Release bundles, lifecycle stages, distribution, or evidence (concepts)**: read `references/release-lifecycle-entities.md` (~180 lines) -- **Applications, application versions, releasables, promotions, or AppTrust (concepts)**: read `references/apptrust-entities.md` (~155 lines) - -### Catalog - -- **Public or custom catalog, package metadata, vulnerability advisories, licenses, OpenSSF, or MCP services (concepts)**: if the JFrog MCP server exposes a catalog tool, prefer it for single-package lookups. For deeper queries, read `references/catalog-entities.md` (~190 lines) -- **CVE details, vulnerability lookup by CVE ID, or severity/affected-packages/fix-versions for a specific CVE**: prefer an MCP vulnerability-lookup tool if the JFrog MCP server exposes one. Otherwise read `references/onemodel-query-examples.md` § *Public security domain* for the `searchVulnerabilities` query shape — this is self-contained; do not load the `jfrog-package-safety-and-download` skill for pure CVE lookups - -### OneModel (GraphQL) - -- **GraphQL queries** (applications, packages, evidence, release bundles, catalog, cross-domain, or "list/search my" platform entities): read `references/onemodel-graphql.md` (~325 lines) -- **Query templates and domain-specific examples**: read `references/onemodel-query-examples.md` (~555 lines) -- **Pagination, filtering, GraphQL variables, or date formatting**: read `references/onemodel-common-patterns.md` (~280 lines) - -### Platform administration - -- **Platform structure, project/repo membership, or project roles vs environments (concepts)**: read `references/platform-access-entities.md` -- **Access tokens, stats, projects, or system health**: read `references/platform-admin-operations.md` -- **Managing JFrog Projects, members, or environments**: read `references/projects-api.md` (~260 lines) -- **Platform REST beyond the CLI, or any platform-level API gap**: read `references/platform-admin-api-gaps.md` (~180 lines) - -### CLI setup & authentication - -- **Adding a server or logging in**: read `references/jfrog-login-flow.md` (~130 lines) -- **CLI not installed, upgrade needed, or `jq` unavailable**: read `references/jfrog-cli-install-upgrade.md` - -### General patterns - -- **Batching, parallel Shell calls, or launching subagents**: read `references/general-parallel-execution.md` (~135 lines) -- **Large or parallel data gathering, list-vs-detail APIs, cache hygiene**: read `references/general-bulk-operations-and-agent-patterns.md` -- **Standalone HTML report with JFrog-aligned styling**: read `references/jfrog-brand-html-report.md` -- **Reusable gotchas from past tasks**: read or extend `references/general-use-case-hints.md` - -## Command discovery - -Use the commands listed below as your primary reference. Run `--help` to -verify options you are unsure about or to discover commands not listed here — -do not rely on memorized commands outside this skill, as they may be outdated. - -1. `jf --help` — list all namespaces and top-level commands -2. `jf --help` — list subcommands in a namespace -3. `jf --help` — show usage, arguments, and options - -### CLI namespaces - -| Namespace | Alias | Product | -|-----------|-------|---------| -| `rt` | | Artifactory | -| `xr` | | Xray | -| `ds` | | Distribution V1 | -| `at` | `apptrust` | AppTrust | -| `evd` | | Evidence | -| `mc` | | Mission Control | -| `worker` | | Workers | -| `config` | `c` | CLI server configuration | -| `plugin` | | CLI plugin management | -| `ide` | | IDE integration | - -> **Sunset notice:** JFrog Pipelines has been sunset and is no longer supported. -> Do not use the `pl` CLI namespace or the Pipelines REST API -> (`/pipelines/api/...`). If a user asks about Pipelines, inform them the -> product has been sunset. - -Top-level lifecycle commands (no namespace): `rbc`, `rbp`, `rbd`, `rba`, -`rbf`, `rbe`, `rbi`, `rbs`, `rbu`, `rbdell`, `rbdelr`. - -Top-level security commands: `audit`, `scan`, `build-scan`, `curation-audit`, -`sbom-enrich`. - -Top-level other: `access-token-create` (`atc`), `login`, `how`, `stats`, -`generate-summary-markdown`, `exchange-oidc-token`, `completion`. - -## Invoking platform APIs with `jf api` - -`jf api` is the Tier 3 entry point for JFrog Platform REST and GraphQL -endpoints, auto-authenticated against the resolved server. **Do not use -`jf rt curl` or `jf xr curl`**; they are superseded by `jf api`. - -### Product-prefix table - -`jf api` requires the **full** path including the product prefix; omitting it -returns 404. - -| Product | Path prefix | -|---------|-------------| -| Artifactory | `/artifactory/api/...` | -| Xray | `/xray/api/...` | -| Access (users, groups, tokens, permissions, projects) | `/access/api/...` | -| Evidence | `/evidence/api/...` | -| Release Lifecycle | `/lifecycle/api/...` | -| AppTrust | `/apptrust/api/...` | -| Distribution | `/distribution/api/...` | -| OneModel (GraphQL) | `/onemodel/api/v1/graphql`, `/onemodel/api/v1/supergraph/schema` | -| Mission Control | `/mc/api/...` | -| Curation | `/xray/api/v1/curation/...` (lives under Xray) | - -### Examples - -```bash -jf api /artifactory/api/repositories -jf api --server-id /artifactory/api/system/version - -# AQL (POST with text/plain body) -jf api /artifactory/api/search/aql \ - -X POST -H "Content-Type: text/plain" -d '' -``` - -Common flags: `-X/--method`, `-H/--header`, `-d/--data`, `--input `, -`--server-id`, `--timeout`. Body on stdout, status on stderr — see -[Gotchas](#gotchas). - -### GraphQL (OneModel) - -OneModel is the unified GraphQL API. **Do not** embed the query inside a JSON -literal (`-d '{"query":"..."}'`) — escaping breaks requests. Build the payload -with `jq -n --arg`, pass it via `--input`, and save the response to a file -before running `jq` on it. - -```bash -QUERY='{ evidence { searchEvidence(first: 5, where: { hasSubjectWith: { repositoryKey: "my-repo-local" } }) { totalCount } } }' -PAYLOAD=/tmp/onemodel-payload-$$.json RESPONSE=/tmp/onemodel-$$.json -jq -n --arg q "$QUERY" '{query:$q}' > "$PAYLOAD" -jf api /onemodel/api/v1/graphql -X POST \ - -H "Content-Type: application/json" --input "$PAYLOAD" > "$RESPONSE" -jq . "$RESPONSE" -``` - -Schema discovery: `jf api /onemodel/api/v1/supergraph/schema > "$SCHEMA_FILE"` -(store only under `~/.jfrog/skills-cache/`, never query responses). Read -`references/onemodel-graphql.md` for the full workflow (schema fetch, -validation, pagination, errors), plus `references/onemodel-query-examples.md` -and `references/onemodel-common-patterns.md` for query shapes, pagination, -variables, and dates. - -## Structured inputs - -Several CLI commands require JSON template files. The templates are normally -created by interactive wizard commands (`jf rt rpt`, `jf rt ptt`, `jf rt rplt`) -which agents cannot use. Instead, retrieve an existing config via REST API as a -starting point and modify it: - -```bash -jf api /artifactory/api/repositories/ -``` - -For other Artifactory or platform REST patterns, or when you need more than -this repo GET, see **Any API gap** under [When to read reference files](#when-to-read-reference-files). - -## Gotchas - -### MCP tools - -- MCP tools return structured data in the tool result. Read response fields - directly; do not pipe MCP output through shell commands or `jq`. - -### CLI and `jf api` - -- `jf api` requires the **product prefix** in the path. Omitting it returns - 404. See the [product-prefix table](#product-prefix-table) for the full list. -- `jf api` writes the body (success or error JSON) to **stdout** and - `[Info] Http Status: NNN` to **stderr** on every call; non-2xx also exits - 1 and adds `[Warn] jf api: returned NNN`. Pipe stdout to - `jq` directly; **never `2>&1 | jq`** — stderr corrupts the JSON. To keep - diagnostics: `jf api 2>/tmp/err-$$.log | jq .`. -- `jf api` has **no `-L`** (follow redirects) and **no `-o`** (output file). - Save bodies with shell redirection - (`jf api ... > /tmp/out-$$.json`); for - binary downloads through the Artifactory remote proxy prefer `jf rt dl`, - which handles the cache and redirect semantics natively. -- Remote repository content is stored in a `-cache` suffixed repo. Properties - and AQL queries for remote repo artifacts must target the cache repo. - Conversely, `/api/repositories/` only accepts the parent remote key - (without `-cache`) — strip the suffix for configuration lookups. -- **Do not use `jf rt search`** — always use a direct AQL query via - `jf api /artifactory/api/search/aql -X POST -H "Content-Type: text/plain" -d ''`. - See `references/artifactory-aql-syntax.md`. -- Use `--quiet` flag for non-interactive execution (suppresses confirmation - prompts). **Caution:** `--quiet` is not a global flag — commands that do not - support it (e.g. `jf rt s`, `jf rt ping`) will fail with misleading errors - like "Wrong number of arguments" or "flag provided but not defined". Check - `--help` for a command before adding `--quiet`. -- Use `--server-id` when targeting a non-default server. If a command fails - with `--server-id`, do not retry without it — that silently targets the - default server instead. See [Server selection rules](#server-selection-rules-mandatory). -- Never use interactive commands. All JFrog CLI operations must be performed - non-interactively. Known interactive commands to avoid: `jf config add`, - `jf login`, `jf rt repo-template`, `jf rt permission-target-template`, and - `jf rt replication-template`. For server setup, follow `references/jfrog-login-flow.md`. - For templates, use JSON schemas or REST API. If a command prompts for input - unexpectedly, find the non-interactive alternative via `--help` or REST API. -- `jf config export` output is base64-encoded JSON. Decode with - `base64 -d | jq` to extract fields. -- Build info lookups require a scope (`?buildRepo=` or `?project=`) — - resolve it before calling the API. See `references/artifactory-operations.md` - §Retrieving build info for the full workflow. -- If a `jf api` call returns 401, the configured token may have expired or - been rotated — ask the user to re-run the login flow (see - `references/jfrog-login-flow.md`) for the **same** server. If 403, the - token lacks required permissions. If 404, verify the endpoint path - (especially the product prefix) and target server version. On any of - these errors, do not try a different configured server as a workaround — - that targets a different environment. Report the error and ask the user. -- **Xray contextual analysis:** the summary artifact response has two - applicability fields — `applicability` (top-level, often null) and - `applicability_details` (always present with a `result` string). **Use - `applicability_details[].result` for counts and summaries.** Using the - top-level `applicability` field for aggregation produces wrong counts because - it is null when no scanner exists. See `references/xray-entities.md` - §Contextual analysis for the eight possible result values and jq snippets. -- **OneModel GraphQL:** always fetch the supergraph schema from the **same** - server you query before building operations (schemas differ by deployment); - cache, validate, and execute per `references/onemodel-graphql.md`. -- Never duplicate a network-fetching command to retry `jq` parsing — save the - response to a temp file first (see [Preserving command output](#preserving-command-output)). -- When collecting detail responses in a loop (e.g. per-repo GETs), validate - each body with `jq -e .` before appending to a results file. One non-JSON - or empty response corrupts a downstream `jq -s` slurp. Write validated - lines to an NDJSON file, then `jq -s '.' file.ndjson` to produce the final - array. See `references/general-bulk-operations-and-agent-patterns.md`. -- Accumulated edge cases from real tasks live in `references/general-use-case-hints.md` - — read when debugging odd failures; **append** a short entry when you confirm - a new, reusable gotcha. - -## Batch and parallel execution - -When a task requires multiple independent operations, use the lightest -parallelism mechanism that fits. Three tiers: (1) batch commands in a single -Shell call using loops or `&`, (2) issue parallel Shell tool calls, (3) launch -parallel subagents for large fan-out. Read `references/general-parallel-execution.md` -(~135 lines) for tier selection, examples, and subagent prompt structuring. - -## Preserving command output - -When a CLI command or API call returns data, redirect the output to a temporary -file so you can re-read it without re-executing the call: - -```bash -OUT=/tmp/jf-repos-$$.json -jf api /artifactory/api/repositories > "$OUT" -echo "$OUT" -``` - -Use `$$` (the shell PID) in the filename to prevent collisions across -concurrent sessions or processes. - -**Cross-call gotcha:** each Shell tool invocation runs in a new process with a -different PID, so `$$` expands to a different value in each call. Always -**echo the expanded filename** so the agent can read it from the output and -reuse the literal path in subsequent calls. Three patterns, in priority order: - -1. **`$$` + echo** (preferred): use `$$` for collision safety, echo the path - as shown above. The agent reads `/tmp/jf-repos-12345.json` from the output - and passes that literal value to the next Shell call. -2. **Session ID**: when many files share a prefix across calls, generate an ID - once (`SID=$(date +%s)-$$`), echo it, and reuse in later calls. -3. **Hardcoded names**: last resort — risks collisions when parallel calls or - subagents write to the same path. - -This protects against wasted round-trips when you need to retry parsing — for -example, if a `jq` filter fails or you extract the wrong field on the first -attempt. Re-read the file instead of hitting the server again. - -Do **not** duplicate the same **network** request in a shell pipeline (e.g. with -`||`) only to re-run `jq` or to reveal jq diagnostics—the duplicate call -adds load on JFrog without fetching new data. Run -`jq '' /tmp/jf-*-$$.json` (or redirect stdin from the file) instead -of re-running the same `jf api` or other identical network-backed command. - -Do **not** reuse saved output across unrelated steps or changed contexts (different -server, user, or intent). The file is only valid for the immediate sequence of -operations that motivated the original call. diff --git a/plugins/jfrog/skills/jfrog/references/apptrust-entities.md b/plugins/jfrog/skills/jfrog/references/apptrust-entities.md deleted file mode 100644 index 6ca5088..0000000 --- a/plugins/jfrog/skills/jfrog/references/apptrust-entities.md +++ /dev/null @@ -1,154 +0,0 @@ -# AppTrust entities - -When to read this file: - -- Working with **applications**, **application versions**, or **releasables**. -- Querying or managing **application version promotions** through stages. -- Understanding what **sources** (builds, release bundles, other app versions) feed into an application version. -- Using the OneModel GraphQL API with the `applications` query root. - -AppTrust entities are accessed exclusively via the **OneModel GraphQL API** -(`/onemodel/api/v1/graphql`). There are no CLI commands for this domain. - -For the OneModel query workflow (credentials, schema fetch, validation, -execution), read `references/onemodel-graphql.md`. - -## Entity relationship overview - -```mermaid -erDiagram - Application ||--o{ ApplicationVersion : "has versions" - ApplicationVersion ||--o{ Releasable : "contains" - ApplicationVersion ||--o{ Promotion : "promoted through" - ApplicationVersion }o--o{ Source : "assembled from" - Releasable }o--o{ Source : "contributed by" - Releasable ||--o{ Artifact : "contains" - Releasable }o--o| StoredPackageVersionLocation : "located at" - Application }o--o{ Owner : "owned by" - Application }o--o{ Label : "tagged with" - ApplicationVersion }o--o| EvidenceSubject : "attested by" -``` - -## Application - -The top-level entity representing a software application registered in -AppTrust. Applications belong to a JFrog Project and serve as the -organizational container for tracking versions, ownership, and criticality. - -| Field | Description | -|-------|-------------| -| `key` | Unique identifier (referenced as `applicationKey` or `appKey` elsewhere) | -| `projectKey` | JFrog Project this application belongs to | -| `displayName` | Human-readable name | -| `criticality` | `unspecified`, `low`, `medium`, `high`, `critical` | -| `maturityLevel` | `unspecified`, `experimental`, `production`, `end_of_life` | -| `owners` | List of users or groups that own the application | -| `labels` | Key-value pairs for custom categorization | - -Query: `applications.getApplication(key: "...")` or -`applications.searchApplications(where: {...})`. - -## Application version - -A versioned instance of an application. Each version captures a specific set -of releasable artifacts, their sources, and a promotion history through -lifecycle stages. - -| Field | Description | -|-------|-------------| -| `application` | Parent application | -| `version` | Version identifier (semantic or custom) | -| `tag` | Optional tag | -| `status` | Processing status: `STARTED`, `FAILED`, `COMPLETED`, `DELETING` | -| `releaseStatus` | Release maturity: `PRE_RELEASE`, `RELEASED`, `TRUSTED_RELEASE` | -| `currentStageName` | Most recent stage the version has been promoted to (null if never promoted) | -| `createdBy`, `createdAt` | Audit fields | -| `evidenceSubject` | Evidence attestation anchor (shared across domains) | - -The `releaseStatus` field is distinct from `status`: `status` tracks the -version creation process, while `releaseStatus` tracks its release maturity. - -Query: `applications.getApplicationVersion(applicationKey: "...", version: "...")` -or `applications.searchApplicationVersions(where: {...})`. - -## Releasable - -A deployable unit within an application version — either a **package version** -or an individual **artifact**. - -| Field | Description | -|-------|-------------| -| `name` | Package name or artifact file name | -| `version` | Package version (empty for non-package artifacts) | -| `packageType` | Repository package type (docker, maven, generic, etc.) | -| `releasableType` | `artifact` or `package_version` | -| `sha256` | Leading file checksum (e.g. manifest for Docker images) | -| `totalSize` | Sum of all artifact sizes in bytes | -| `sources` | Sources that contributed to this releasable | -| `artifacts` | Individual files that make up the releasable | -| `packageVersionLocation` | Link to `StoredPackageVersionLocation` for package releasables | -| `vcsCommit` | VCS commit details (for AppTrust-bound package versions) | - -Releasables bridge the application model to the underlying Artifactory -storage. The `packageVersionLocation` field connects to the Stored Packages -domain (see `stored-packages-entities.md`). - -## Application version promotion - -Records the promotion of an application version from one stage to another. -All promotions are recorded including failed attempts. - -| Field | Description | -|-------|-------------| -| `sourceStageName` | Stage being promoted from (empty for first promotion) | -| `targetStageName` | Stage being promoted to | -| `status` | `SUBMITTED`, `STARTED`, `PENDING`, `COMPLETED`, `FAILED`, `REJECTED` | -| `createdBy`, `createdAt` | Who initiated and when | -| `artifacts` | Artifacts included in this promotion (repo + path) | -| `messages` | Error messages if the promotion failed | - -Promotions use the same environment/stage model as Release Bundle promotions -(see `release-lifecycle-entities.md`) but at the application level. - -## Sources - -Sources describe how releasables were assembled into an application version. -Four types exist: - -| Source type | Fields | Description | -|-------------|--------|-------------| -| **Build** | `name`, `number`, `startedAt`, `repositoryKey` | A CI/CD build that produced releasables | -| **ReleaseBundle** | `name`, `version` | A release bundle whose artifacts were included | -| **ApplicationVersion** | `applicationKey`, `version` | Another application version (composition) | -| **Direct** | (none) | Directly included without an associated build or bundle | - -Sources appear at both the application version level (all sources) and the -individual releasable level (sources for that specific releasable). - -## Artifacts (within application versions) - -Individual files within releasables. - -| Field | Description | -|-------|-------------| -| `filePath` | Path in the repository (excluding repo key) | -| `downloadPath` | Full path for downloading from a Release Bundle repository | -| `sha256` | Checksum | -| `size` | Size in bytes | -| `evidenceSubject` | Evidence attestation anchor | - -## Cross-domain connections - -AppTrust entities connect to other domains via the OneModel GraphQL API: - -- **Evidence** — `ApplicationVersion.evidenceSubject` and - `ApplicationVersionArtifact.evidenceSubject` link to the Evidence domain - via `EvidenceSubject.fullPath`. This allows querying evidence attached to - app versions and their artifacts. -- **Stored Packages** — `Releasable.packageVersionLocation` links to - `StoredPackageVersionLocation`, connecting the application model to where - packages physically reside in Artifactory. -- **Release Bundles** — source type `ReleaseBundle` references release bundle - name/version from the Release Lifecycle domain. -- **Builds** — source type `Build` references build-info records from - Artifactory. diff --git a/plugins/jfrog/skills/jfrog/references/artifactory-api-gaps.md b/plugins/jfrog/skills/jfrog/references/artifactory-api-gaps.md deleted file mode 100644 index 1533d8a..0000000 --- a/plugins/jfrog/skills/jfrog/references/artifactory-api-gaps.md +++ /dev/null @@ -1,206 +0,0 @@ -# Artifactory API Gaps - -Operations available through REST API but not through CLI commands. -Invoke them via `jf api [flags]` (authentication is handled -automatically against the active `jf config` server; see the base skill's -*Invoking platform APIs with `jf api`* section). - -## Repository management - -### Get repository configuration -```bash -jf api /artifactory/api/repositories/ -``` -Returns the full JSON configuration of a repository. Useful as a template -for creating similar repos. - -### List all repositories -```bash -jf api /artifactory/api/repositories -``` -Optional query params (combinable): `type` (one of `local`, `remote`, -`virtual`, `federated`), `packageType` (e.g. `docker`, `maven`, `npm`, -`pypi`, `generic`), `project`. Examples: -```bash -jf api "/artifactory/api/repositories?type=local" -jf api "/artifactory/api/repositories?packageType=docker" -jf api "/artifactory/api/repositories?type=remote&packageType=maven&project=my-project" -``` - -### Get repositories (v2) -```bash -jf api /artifactory/api/repositories/configurations -``` -Optional query params (combinable, comma-separated values allowed): -`repoType` (case-insensitive; one of `local`, `remote`, `virtual`, -`federated`) and `packageType` (e.g. `maven`, `docker`, `npm`). Note: -`repo_type` is silently ignored — the correct name is `repoType`. -Examples: -```bash -jf api "/artifactory/api/repositories/configurations?repoType=local" -jf api "/artifactory/api/repositories/configurations?packageType=maven" -jf api "/artifactory/api/repositories/configurations?repoType=local,remote&packageType=docker" -``` - -### Check if repository exists -```bash -jf api /artifactory/api/repositories/ -X HEAD -# 200 = exists, 400 = does not exist -``` - -## Storage and system - -### Get storage summary -```bash -jf api /artifactory/api/storageinfo -``` - -### Refresh storage summary -```bash -jf api /artifactory/api/storageinfo/calculate -X POST -``` - -### Get storage item info -```bash -jf api "/artifactory/api/storage//" -``` - -### System ping -```bash -jf api /artifactory/api/system/ping -``` - -### System version -```bash -jf api /artifactory/api/system/version -``` - -### System configuration -```bash -jf api /artifactory/api/system/configuration -``` - -## Search (beyond CLI) - -### AQL queries -```bash -jf api /artifactory/api/search/aql \ - -X POST -H "Content-Type: text/plain" \ - -d 'items.find({"repo":"my-repo","name":{"$match":"*.jar"}})' -``` - -For remote repository content, query the `-cache` suffixed repo: -```bash -jf api /artifactory/api/search/aql \ - -X POST -H "Content-Type: text/plain" \ - -d 'items.find({"repo":"my-remote-cache"})' -``` - -### Property search -```bash -jf api "/artifactory/api/search/prop?key=value&repos=my-repo" -``` - -### Checksum search -```bash -jf api "/artifactory/api/search/checksum?sha256=" -``` - -### GAVC search (Maven) -```bash -jf api "/artifactory/api/search/gavc?g=com.example&a=mylib&v=1.0" -``` - -## User and group management - -User and group operations are handled by the Access service. See -`platform-admin-api-gaps.md` (Users / Groups sections) for the full set. - -## Metadata calculation - -Trigger metadata recalculation for various package types: -```bash -# Maven -jf api /artifactory/api/maven/calculateMetaData/ -X POST - -# npm -jf api /artifactory/api/npm//reindex -X POST - -# Docker -# (automatic, no manual trigger) - -# PyPI -jf api /artifactory/api/pypi//reindex -X POST - -# Helm -jf api /artifactory/api/helm//reindex -X POST - -# Debian -jf api /artifactory/api/deb/reindex/ -X POST -``` - -## Trash can and garbage collection - -### Empty trash -```bash -jf api /artifactory/api/trash/empty -X POST -``` - -### Restore from trash -```bash -jf api "/artifactory/api/trash/restore//" -X POST -``` - -### Run garbage collection -```bash -jf api /artifactory/api/system/storage/gc -X POST -``` - -## Federated repositories (beyond basic CRUD) - -### Get federation status -```bash -jf api /artifactory/api/federation/status/ -``` - -### Trigger full sync -```bash -jf api "/artifactory/api/federation/fullSyncAll/" -X POST -``` - -## Build info (beyond CLI) - -### List builds (prefer scoped queries) - -**Unscoped** `GET /artifactory/api/build` (no query parameters) can **time -out** on busy instances. Prefer **project-scoped** or **repo-scoped** -listing, then detail GETs. Full flow: read `artifactory-operations.md` -§ *Listing builds when the project key is known*. - -```bash -# Project scope — build names (latest per name) -jf api "/artifactory/api/build?project=" - -# Project scope — all run numbers for one build name (response: buildsNumbers) -jf api "/artifactory/api/build/?project=" - -# Build-info repo scope — alternative when you know the repo key -jf api "/artifactory/api/build?buildRepo=" -``` - -### Get build info -```bash -# Default build-info repo only (no project / non-default repo) -jf api "/artifactory/api/build//" - -# Project or custom build-info repo -jf api "/artifactory/api/build//?project=" -jf api "/artifactory/api/build//?buildRepo=" -``` - -### Delete builds -```bash -jf api /artifactory/api/build/delete \ - -X POST -H "Content-Type: application/json" \ - -d '{"buildName":"my-build","buildNumbers":["1","2"]}' -``` diff --git a/plugins/jfrog/skills/jfrog/references/artifactory-aql-syntax.md b/plugins/jfrog/skills/jfrog/references/artifactory-aql-syntax.md deleted file mode 100644 index b120275..0000000 --- a/plugins/jfrog/skills/jfrog/references/artifactory-aql-syntax.md +++ /dev/null @@ -1,656 +0,0 @@ -# AQL (Artifactory Query Language) - -AQL queries are sent as POST requests with `Content-Type: text/plain`: - -```bash -jf api /artifactory/api/search/aql \ - -X POST -H "Content-Type: text/plain" -d '' -``` - -## Query structure - -``` -.find() - .include() - .sort() - .offset() - .limit() - .distinct() -``` - -Only `.find()` is required. The others are optional and chainable. -**The chain order above is enforced by the server.** `.include()` must come -before `.sort()`, `.sort()` before `.offset()`, etc. Putting them out of -order (e.g. `.sort()` before `.include()`) produces a parse error. - -**Mandatory include fields:** `items` requires `"repo","path","name"`; -`builds` requires `"name","number","repo"`. Always include these even when -you only need a subset — narrow results with `jq` post-query instead: - -``` -items.find({"name":"commons-lang3-3.12.0.jar"}) - .include("repo","path","name") - .distinct(true) -``` - -## Domains - -AQL has 13 queryable domains. Each domain represents a different entity type -and has its own set of fields. - - -| Domain | Query name | Description | -| -------------------- | ------------------- | ---------------------------------------------- | -| Items | `items` | Artifacts stored in repositories (most common) | -| Properties | `properties` | Key-value properties on items | -| Item infos | `item.infos` | Property modification metadata | -| Statistics | `stats` | Download statistics (local and remote) | -| Builds | `builds` | Build info records | -| Build modules | `modules` | Modules within a build | -| Build artifacts | `artifacts` | Artifacts produced by a build module | -| Build dependencies | `dependencies` | Dependencies consumed by a build module | -| Build properties | `build.properties` | Key-value properties on builds | -| Build promotions | `build.promotions` | Build promotion records | -| Module properties | `module.properties` | Key-value properties on build modules | -| Release bundles | `releases` | Release bundle records | -| Release bundle files | `release_artifacts` | Files within a release bundle | - - -## Domain relationships - -Domains connect through the following join paths. Cross-domain queries -traverse these links — fields from related domains can appear in criteria -and include clauses by prefixing the domain path. - -```mermaid -erDiagram - items ||--o{ properties : "has" - items ||--o| item_infos : "has" - items ||--o{ stats : "has" - items ||--o{ artifacts : "via checksum" - items ||--o{ dependencies : "via checksum" - items ||--o{ release_artifacts : "has" - artifacts }o--|| modules : "belongs to" - dependencies }o--|| modules : "belongs to" - modules }o--|| builds : "belongs to" - modules ||--o{ module_properties : "has" - builds ||--o{ build_properties : "has" - builds ||--o{ build_promotions : "has" - release_artifacts }o--|| releases : "belongs to" -``` - - - -**Key:** Items connect to build artifacts and dependencies through SHA-1 -checksum matching, not a direct key. This means a cross-domain query from -items to builds traverses: items → artifacts → modules → builds. - -### Cross-domain field paths - -To reference a field from a related domain, use dot-separated domain paths: - -``` -items.find({"artifact.module.build.name":"my-build"}) - .include("name","repo","path","artifact.module.build.number") -``` - -Common cross-domain paths from items: - -- `stat.downloads`, `stat.downloaded` — download statistics -- `property.key`, `property.value` — item properties -- `artifact.module.build.name` — build that produced the item -- `artifact.module.build.number` — build number - -From builds: - -- `module.artifact.name` — artifacts in build modules -- `module.dependency.name` — dependencies of build modules - -## Fields by domain - -Field types: `string`, `date`, `int`, `long`, `itemType` (`file`, `folder`, -or `any`). Fields marked "default" are returned without explicit `.include()`. - -### items - - -| Field | Type | Default | -| --------------- | -------- | ------- | -| `repo` | string | yes | -| `path` | string | yes | -| `name` | string | yes | -| `type` | itemType | yes | -| `size` | long | yes | -| `depth` | int | yes | -| `created` | date | yes | -| `created_by` | string | yes | -| `modified` | date | yes | -| `modified_by` | string | yes | -| `updated` | date | yes | -| `actual_md5` | string | no | -| `actual_sha1` | string | no | -| `sha256` | string | no | -| `original_md5` | string | no | -| `original_sha1` | string | no | - - -Computed field: `virtual_repos` — returns virtual repositories that include -the item's actual repository. Must use `.include("virtual_repos")` explicitly; -requires `repo`, `path`, `name` in the result set. - -### properties - - -| Field | Type | Default | -| ------- | ------ | ------- | -| `key` | string | yes | -| `value` | string | yes | - - -### stats - - -| Field | Type | Default | -| ---------------------- | ------ | ------- | -| `downloads` | int | yes | -| `downloaded` | date | yes | -| `downloaded_by` | string | yes | -| `remote_downloads` | int | yes | -| `remote_downloaded` | date | yes | -| `remote_downloaded_by` | string | yes | -| `remote_origin` | string | yes | -| `remote_path` | string | yes | - - -### item.infos - - -| Field | Type | Default | -| ------------------- | ------ | ------- | -| `props_modified` | date | yes | -| `props_modified_by` | string | yes | -| `props_md5` | string | yes | - - -### builds - - -| Field | Type | Default | -| ------------- | ------ | ------- | -| `url` | string | yes | -| `name` | string | yes | -| `number` | string | yes | -| `started` | date | yes | -| `created` | date | yes | -| `created_by` | string | yes | -| `modified` | date | yes | -| `modified_by` | string | yes | -| `repo` | string | no | - - -### modules - - -| Field | Type | Default | -| ------ | ------ | ------- | -| `name` | string | yes | - - -### artifacts - - -| Field | Type | Default | -| ------ | ------ | ------- | -| `name` | string | yes | -| `type` | string | yes | -| `sha1` | string | yes | -| `md5` | string | yes | - - -### dependencies - - -| Field | Type | Default | -| ------- | ------ | ------- | -| `name` | string | yes | -| `scope` | string | yes | -| `type` | string | yes | -| `sha1` | string | yes | -| `md5` | string | yes | - - -### build.properties - - -| Field | Type | Default | -| ------- | ------ | ------- | -| `key` | string | yes | -| `value` | string | yes | - - -### build.promotions - - -| Field | Type | Default | -| ------------ | ------ | ------- | -| `created` | date | yes | -| `created_by` | string | yes | -| `status` | string | yes | -| `repo` | string | yes | -| `comment` | string | yes | -| `user` | string | yes | - - -### module.properties - - -| Field | Type | Default | -| ------- | ------ | ------- | -| `key` | string | yes | -| `value` | string | yes | - - -### releases - - -| Field | Type | Default | -| -------------- | --------------------------- | ------- | -| `name` | string | yes | -| `version` | string | yes | -| `status` | string | yes | -| `created` | date | yes | -| `signature` | string | yes | -| `type` | string (`SOURCE`, `TARGET`) | yes | -| `storing_repo` | string | yes | - - -### release_artifacts - - -| Field | Type | Default | -| ------ | ------ | ------- | -| `path` | string | yes | - - -## Comparators - - -| Operator | Meaning | Example | -| ---------- | -------------------------------- | ------------------------------------ | -| `$eq` | Equals (default if omitted) | `{"type":"file"}` | -| `$ne` | Not equals | `{"type":{"$ne":"folder"}}` | -| `$eqic` | Equals, case-insensitive | `{"name":{"$eqic":"README.md"}}` | -| `$match` | Wildcard match (`*`, `?`) | `{"name":{"$match":"*.jar"}}` | -| `$matchic` | Wildcard match, case-insensitive | `{"name":{"$matchic":"*.JAR"}}` | -| `$nmatch` | Wildcard not-match | `{"name":{"$nmatch":"*-SNAPSHOT*"}}` | -| `$gt` | Greater than | `{"size":{"$gt":"1000000"}}` | -| `$gte` | Greater than or equal | `{"stat.downloads":{"$gte":"10"}}` | -| `$lt` | Less than | `{"size":{"$lt":"5000"}}` | -| `$lte` | Less than or equal | `{"modified":{"$lte":"2025-01-01"}}` | - - -### Boolean operators - - -| Operator | Description | -| -------- | ---------------------------------------------------------------------- | -| `$and` | All conditions must match (implicit when fields are at the same level) | -| `$or` | Any condition must match | - - -``` -items.find({"$and":[ - {"repo":"my-repo"}, - {"$or":[ - {"name":{"$match":"*.jar"}}, - {"name":{"$match":"*.war"}} - ]} -]}) -``` - -### Relative date comparators - -AQL supports relative date queries with `$last` and `$before`: - - -| Operator | Meaning | Example | -| --------- | ------------------------------------------------------- | ------------------------------- | -| `$last` | Within the last N period (equivalent to `$gt` from now) | `{"modified":{"$last":"7d"}}` | -| `$before` | Before the last N period (equivalent to `$lt` from now) | `{"created":{"$before":"3mo"}}` | - - -Supported units: `d` (days), `w` (weeks), `mo` (months), `y` (years), -`s` (seconds), `mi` (minutes), `ms` (milliseconds). - -### Multi-property AND - -To match items that have property A=1 **and** property B=2 (different -property rows), use `$and` with `@` shorthand: - -``` -items.find({"$and":[ - {"@build.name":"my-build"}, - {"@build.number":"42"} -]}) -``` - -AQL also documents a `$msp` (multi-set property) operator for this purpose, -but `$msp` is **unreliable in practice** — it returns 0 results on many -server versions even when matching items exist. Prefer `$and` with `@` -shorthand, which is verified to work correctly. - -## Date queries - -Dates use ISO 8601 format for absolute dates: - -``` -items.find({"modified":{"$gt":"2025-06-01T00:00:00.000Z"}}) -``` - -Or use relative dates (preferred — avoids hardcoding timestamps): - -``` -items.find({"modified":{"$last":"30d"}}) -items.find({"created":{"$before":"6mo"}}) -``` - -## Property queries - -Two equivalent syntaxes for property filtering: - -**`@key` shorthand** — concise, works for single property conditions: - -``` -items.find({"repo":"my-repo","@build.name":"my-build","type":"file"}) -``` - -**Explicit form** — `property.key`/`property.value` pairs: - -``` -items.find({ - "repo":"my-repo", - "property.key":"build.name", - "property.value":"my-build" -}) -``` - -**Multi-property AND** — use `$and` with `@` shorthand to match across -different property rows: - -``` -items.find({"$and":[ - {"@build.name":"my-build"}, - {"@build.number":"42"} -]}) -``` - -> **Note:** The `@key` shorthand works inside `$and`. For `$or`, use the -> explicit `property.key`/`property.value` form if the shorthand does not -> return expected results. - -## Include - -Select which fields to return. Without `.include()`, AQL returns each -domain's default field set. - -**When you use `.include()`, you replace the defaults — so you must -explicitly list any required fields:** - -- `items` domain: always include `"repo","path","name"` (server rejects -the query otherwise) -- `builds` domain: always include `"name","number","repo"` - -``` -items.find({"repo":"my-repo"}) - .include("name","repo","path","size","sha256","stat.downloads") -``` - -Cross-domain includes use dot-separated paths: - -``` -items.find({"repo":"my-repo"}) - .include("name","repo","path","property.key","property.value") -``` - -## Sort and pagination - -``` -items.find({"repo":"my-repo"}) - .sort({"$desc":["modified"]}) - .offset(0) - .limit(50) -``` - -Sort directions: `$asc`, `$desc`. Sort fields must also appear in the result -set (explicit `.include()` or default fields). See -[Before constructing a query](#before-constructing-a-query) for sort -performance rules. - -## Distinct - -Deduplicate result rows: - -``` -items.find({"repo":"my-repo"}).distinct(true) -``` - -## Validation rules - -The server enforces these constraints — violating them produces an error: - -**Non-admin users:** - -- `items` domain queries must include `repo`, `path`, `name` in results -(needed for permission filtering) -- `builds` domain queries must include `name`, `number`, `repo` in results - -**Transitive mode** (`.transitive()` for querying through virtual repos): - -- Only works with `items` domain -- Include subdomains limited to `items` and `properties` -- Repo criteria must use `$eq` (exact match) with a single repository -- No `offset` or `sort` allowed - -## Before constructing a query - -Run through these checks before writing any AQL query: - -1. **Never `.sort()` without a `repo` filter** — forces a full table scan - across all repositories. Sort client-side with `jq` instead. Also, - `.sort()` on cross-domain fields (e.g. `stat.downloads` in `items.find()`) - is silently ignored — fetch all rows and sort client-side. -2. **Always set `.limit()`** — no built-in default limit; unbounded queries - can time out or OOM. Broad queries without a `repo` filter are especially - expensive. -3. **`range.total` = returned count, not total matching** — AQL has no - count-only mode. To find the true total, paginate with `.offset()` until - a page returns fewer results than the limit. -4. **AQL has no repo-type field** — to restrict to local repos, either - pre-query `GET /api/repositories?type=local` and add repo names to - criteria (practical when count is small), or query without a repo filter - and exclude `-cache` / `-virtual` suffixed repos client-side with `jq`. -5. **Narrow server-side first** — add every applicable filter (`created_by`, - `created`, `type`, `name`) before relying on client-side `jq` filtering. - -## Common query patterns - -### Find all JARs in a repo - -``` -items.find({"repo":"libs-release","name":{"$match":"*.jar"}}) -``` - -### Find large files (> 100 MB) - -``` -items.find({"repo":"my-repo","size":{"$gt":"104857600"},"type":"file"}) -``` - -### Find Maven SNAPSHOT JARs - -Use `*-SNAPSHOT*.jar` (not `*-SNAPSHOT.jar`) to also match classifier -artifacts like `-sources.jar` and `-javadoc.jar`: - -``` -items.find({"repo":"libs-snapshot","name":{"$match":"*-SNAPSHOT*.jar"},"type":"file"}) -``` - -### Find artifacts modified in the last 7 days - -``` -items.find({"repo":"my-repo","modified":{"$last":"7d"},"type":"file"}) - .sort({"$desc":["modified"]}) - .limit(100) -``` - -### Docker queries - -Use `"name":"manifest.json"` to **list tags** (one per tag). Use -`"name":{"$match":"*manifest.json"}` to **query all manifests** (includes -`list.manifest.json` for multi-arch tags — see [Gotchas](#gotchas)). - -``` -items.find({"repo":"docker-local","path":{"$match":"my-image/*"},"name":"manifest.json"}) -``` - -### Docker image size - -**Do not use AQL** — layer blobs live at `/sha256:/`, not -under `//`. Use the V2 manifest API (returns `layers[].size`): - -```bash -jf api "/artifactory/api/docker//v2//manifests/" \ - -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -``` - -For multi-arch images the response is an image index; fetch each platform -manifest by digest to get its layers. - -### Find artifacts with a specific property - -``` -items.find({"repo":"my-repo","@build.name":"my-build","type":"file"}) -``` - -### Find never-downloaded files (zero download count) - -Zero-download items lack a stats row — filter client-side instead -(see [Gotchas](#gotchas)): - -```bash -jf api /artifactory/api/search/aql \ - -X POST -H "Content-Type: text/plain" -d ' -items.find({"repo":"my-repo","type":"file"}) - .include("repo","path","name","size","stat.downloads") -' | jq '[.results[] | select((.stats[0].downloads // 0) == 0) | {repo, path, name, size}]' -``` - -### Find artifacts not downloaded in 90 days - -Only matches previously-downloaded items (see [Gotchas](#gotchas)). -Combine with the never-downloaded pattern above for full coverage. - -``` -items.find({ - "repo":"my-repo", - "type":"file", - "stat.downloaded":{"$before":"90d"} -}).include("name","repo","path","stat.downloaded","size") -``` - -### Find items by build name (cross-domain) - -``` -items.find({"artifact.module.build.name":"my-service"}) - .include("name","repo","path","artifact.module.build.number") - .sort({"$desc":["modified"]}) - .limit(50) -``` - -### Find builds by name - -Non-admin users must include `name`, `number`, `repo` — omitting any -produces an error. - -``` -builds.find({"name":{"$match":"*my-service*"}}) - .include("name","number","repo","started") - .sort({"$desc":["started"]}) - .limit(10) -``` - -### Find build artifacts - -``` -artifacts.find({"module.build.name":"my-service","module.build.number":"42"}) - .include("name","type","sha1","md5") -``` - -### Find build dependencies - -``` -dependencies.find({"module.build.name":"my-service","module.build.number":"42"}) - .include("name","scope","type","sha1") -``` - -### Remote repository content - -Remote repo artifacts are stored in a `-cache` suffixed repo. Always query -the cache repo, not the remote repo itself: - -``` -items.find({"repo":"npm-remote-cache","name":{"$match":"*.tgz"}}) -``` - -## Gotchas - -- The request body is **plain text**, not JSON — use -`Content-Type: text/plain`. -- String values in criteria must be quoted, including numeric comparisons -(`"size":{"$gt":"1000"}` not `"size":{"$gt":1000}`). -- Remote repo content lives in `-cache`, not ``. -- Sort fields must appear in the result set (included explicitly or by -default). -- Non-admin `items` queries must return `repo`, `path`, `name`. -- Non-admin `builds` queries must return `name`, `number`, `repo`. -- Items connect to builds through checksum matching (SHA-1), so cross-domain -queries between items and builds are valid but traverse multiple joins. -- The `path` value for items at the **root** of a repository is `"."`, not -`""` or `"/"`. Use `"path":"."` to match root-level files. -- **Docker `list.manifest.json`** — multi-arch images store two manifest files per - tag: `manifest.json` (platform-specific manifest) and `list.manifest.json` (OCI - image index). Filtering by `"name":"manifest.json"` is correct for tag listing - (one result per tag), but silently excludes `list.manifest.json` entries. Use - `"name":{"$match":"*manifest.json"}` when querying by uploader, date range, or - any context where all manifest pushes should be counted. -- **`stat.downloads` filters do not match zero-download items** — never-downloaded - items lack a stats row so the join finds nothing. Use the client-side `jq` - approach in "Find never-downloaded files" above. -- `$match` uses SQL-style wildcards: `*` matches any characters, `?` matches -exactly one character. It is **not** regex. Literal `_` and `%` in patterns -are escaped automatically. -- The `builds.number` field is a **string**, not an integer. Build numbers -like `"42"`, `"1.0.3"`, and `"SNAPSHOT-1"` are all valid. -- Release bundle `type` values are uppercase strings: `"SOURCE"` or -`"TARGET"`. -- Dates accept both ISO 8601 format (`"2025-06-01T00:00:00.000Z"`) and -epoch milliseconds as a string (`"1719792000000"`). -- The server silently excludes trash, support-bundle, and in-transit -repository content from AQL results. If an item exists but doesn't appear -in results, it may be in one of these hidden repos. -- Virtual repo queries are rewritten to search the underlying physical repos. -The `repo` field in results shows the physical repo name, not the virtual -repo name you queried. - -## Official documentation - -- [Artifactory Query Language](https://docs.jfrog.com/artifactory/docs/artifactory-query-language) — overview and architecture -- [Query Structure and Syntax](https://docs.jfrog.com/artifactory/docs/aql-syntax) — domain queries, field references, JSON-like syntax rules -- [Search Criteria and Operators](https://docs.jfrog.com/artifactory/docs/aql-search-criteria) — comparators, wildcards, `$msp`, relative time -- [AQL Entities and Fields Reference](https://docs.jfrog.com/artifactory/docs/aql-entities-fields-reference) — complete field list for all domains -- [Query Output and Modifiers](https://docs.jfrog.com/artifactory/docs/aql-query-output) — `.include()`, `.sort()`, `.offset()`, `.limit()`, `.distinct()` -- [Query Execution and Permissions](https://docs.jfrog.com/artifactory/docs/aql-query-execution) — authentication, scoped tokens, HTTP errors, streaming -- [AQL Examples and Common Patterns](https://docs.jfrog.com/artifactory/docs/aql-examples) — ready-to-use queries by use case -- [Repository-Specific Queries](https://docs.jfrog.com/artifactory/docs/aql-repository-queries) — `.transitive()`, virtual repos, remote search -- [Performance and Operational Controls](https://docs.jfrog.com/artifactory/docs/aql-performance) — result limits, timeouts, rate limiting, optimization - diff --git a/plugins/jfrog/skills/jfrog/references/artifactory-entities.md b/plugins/jfrog/skills/jfrog/references/artifactory-entities.md deleted file mode 100644 index 1e4d950..0000000 --- a/plugins/jfrog/skills/jfrog/references/artifactory-entities.md +++ /dev/null @@ -1,236 +0,0 @@ -# Artifactory entities - -When to read this file: - -- Working with **repositories** and you need to understand the difference between local, remote, virtual, and federated types. -- Managing **artifacts**, **properties**, or **package types**. -- Working with **builds**, **build promotion**, or **permission targets**. -- Debugging unexpected behavior related to repo types (e.g. upload failures, missing search results). - -For CLI commands see `artifactory-operations.md`. For API gaps see -`artifactory-api-gaps.md`. For AQL syntax see `artifactory-aql-syntax.md`. - -## Repositories - -A repository is the primary storage and resolution unit in Artifactory. Every -repo has a **key** (unique identifier), a **package type** (immutable after -creation), and a **repository class** (`rclass`) that determines its behavior. - -### Repository types - -| Type | `rclass` | Behavior | Stores artifacts? | -|------|----------|----------|-------------------| -| **Local** | `local` | Hosts artifacts deployed directly (upload, promote, copy, move) | Yes | -| **Remote** | `remote` | Proxies an external URL; downloads are cached in a companion `-cache` repo | Only in the `-cache` repo | -| **Virtual** | `virtual` | Aggregates multiple local and remote repos under a single URL for resolution | No (resolves from underlying repos) | -| **Federated** | `federated` | Local repo that bi-directionally synchronizes across Platform Deployments | Yes (replicated across sites) | - -### Key relationships and fields - -- `key` — unique repo identifier (e.g. `libs-release-local`) -- `packageType` — determines layout and protocol (see Package types below) -- `rclass` — `local`, `remote`, `virtual`, or `federated` -- `url` — (remote only) the external source URL being proxied -- `repositories` — (virtual only) ordered list of local/remote repos to aggregate -- `projectKey` — links repo to a JFrog Project (see `platform-access-entities.md`) -- `environments` — environments the repo is assigned to (used in RBAC and lifecycle) - -### System repositories - -Artifactory and Xray maintain several **system repositories** for internal -platform metadata. These are not user-created and should be excluded when -iterating over repositories for reporting, scanning, or auditing: - -| Pattern | Purpose | -|---------|---------| -| `release-bundles` | Release Bundles V1 metadata | -| `release-bundles-v2` | Release Bundles V2 metadata | -| `artifactory-build-info` | Default build info storage | -| `*-release-bundles` | Project-scoped Release Bundles V1 | -| `*-release-bundles-v2` | Project-scoped Release Bundles V2 | -| `*-build-info` | Project-scoped build info storage | -| `*-application-versions` | AppTrust application version metadata | - -Including these in aggregate queries (violation counts, storage reports, etc.) -produces misleading results because they contain platform metadata rather than -user artifacts. - -### Remote repository cache - -When Artifactory downloads an artifact through a remote repo, it stores the -cached copy in a **separate local repo** named `-cache`. This is -critical for: - -- **AQL queries** — search the `-cache` repo, not the remote repo key -- **Properties** — properties on cached artifacts live on the `-cache` repo -- **Storage calculations** — cached artifacts consume storage under the `-cache` repo - -The remote repo key itself is used for **configuration** (URL, credentials, -inclusion/exclusion patterns) but does not directly contain artifacts. - -### Virtual repository resolution - -A virtual repo aggregates **both local and remote repos** under a single URL. -It resolves artifacts by searching its underlying repos in the configured -**order** — when the same artifact exists in multiple underlying repos, the -first match wins. - -A virtual repo may designate one of its underlying **local** repos as the -**default deployment repository**. Uploads through the virtual URL are routed -to that local repo. Without a default deployment repo, the virtual repo is -read-only. - -```mermaid -erDiagram - VirtualRepo ||--o{ LocalRepo : "aggregates" - VirtualRepo ||--o{ RemoteRepo : "aggregates" - VirtualRepo ||--o| LocalRepo : "defaultDeploymentRepo" - RemoteRepo ||--|| CacheRepo : "has -cache" -``` - -## Artifacts - -An artifact is a file stored in a repository. Each artifact is uniquely -identified by the triple **repo + path + name**. - -Key attributes: -- `repo`, `path`, `name` — location identifier -- `size` — bytes -- `sha256`, `sha1`, `md5` — checksums (sha256 is the primary identifier for cross-referencing with builds and Xray) -- `created`, `modified`, `created_by`, `modified_by` — audit fields - -Artifacts are **content-addressable** — build info and Xray reference them by -checksum, not by path. Moving or copying an artifact changes its path but not -its checksum, so build associations follow the artifact. - -## Properties - -Key-value metadata pairs attached to artifacts or folders. - -- Keys are strings; values are strings or arrays of strings -- Set via `jf rt set-props`, queried via AQL or the properties API -- Commonly used for: build metadata, maturity labels, promotion tracking, cleanup policies -- Properties on remote-cached artifacts live on the `-cache` repo - -## Package types - -The `packageType` field on a repository determines how Artifactory interprets -its contents. It controls directory structure conventions, metadata extraction, -and which client protocols are supported (e.g. Docker registry API, npm -registry, Maven layout). - -Common types: `maven`, `gradle`, `npm`, `docker`, `pypi`, `nuget`, `go`, -`helm`, `rpm`, `debian`, `generic`. - -Package type is **immutable** — it cannot be changed after repo creation. Use -`generic` when no specific package type applies. - -## Build info - -A build info record captures CI/CD metadata: which artifacts were produced, -which dependencies were consumed, and the build environment. - -| Field | Description | -|-------|-------------| -| `name` + `number` | Unique identifier for a build run | -| `modules` | List of modules, each with its own artifacts and dependencies | -| `vcs` | Version control metadata (revision, URL, branch) | -| `buildAgent`, `agent` | CI tool info | -| `properties` | Custom build-level properties | - -Build info references artifacts **by checksum** (sha256). This means: -- A build can reference artifacts across multiple repositories -- Moving an artifact does not break the build association -- Xray scans build info by resolving checksums to components - -Lifecycle: collect → publish → (optionally) promote → (optionally) scan. - -## Build promotion - -Promotion changes a build's **status** and can copy or move its artifacts -from a source repo to a target repo. - -| Field | Description | -|-------|-------------| -| `status` | Target status label (e.g. `staged`, `released`) | -| `sourceRepo` | Where artifacts currently reside | -| `targetRepo` | Where artifacts should be moved/copied | -| `copy` | If `true`, copy instead of move | - -Promotion records are queryable via AQL (`build.promotions` domain) and the -build promotion API. - -## Permissions - -Permissions define RBAC policies mapping **resources** and **principals** -(users and groups) to **actions**. Two models exist: - -### Permissions V2 (Access Permissions) — current model - -Managed by the **Access service** (since Artifactory 7.72.0, recommended from -7.77.2). Supports all resource types. - -| Component | Description | -|-----------|-------------| -| `name` | Permission name | -| `resources` | Map of resource type → targets + actions | - -Resource types: `artifact` (repositories), `build`, `release_bundle`, -`destination` (Edge nodes), `pipeline_source`. - -Each resource contains: -- `targets` — map of target names/patterns to include/exclude patterns -- `actions.users` — map of username → list of actions -- `actions.groups` — map of group name → list of actions - -Actions use uppercase: `READ`, `ANNOTATE`, `DEPLOY/CACHE`, `DELETE/OVERWRITE`, -`MANAGE_XRAY_METADATA`, `MANAGE`. - -API: `POST/PUT/GET/DELETE /access/api/v2/permissions/{permissionName}`. - -Documentation: [Permissions](https://docs.jfrog.com/administration/docs/permissions). - -### Permission targets (V1) — legacy model - -Managed by **Artifactory**. Still functional and backwards compatible, but -V2 is recommended for new implementations. The CLI `jf rt permission-target-*` -commands use this API. - -| Component | Description | -|-----------|-------------| -| `repositories` | List of repo keys or patterns | -| `actions.users` | Map of username → list of actions | -| `actions.groups` | Map of group name → list of actions | - -Actions use lowercase: `read`, `write`, `annotate`, `delete`, `manage`. - -Does **not** support `destination` or `pipeline_source` resource types. - -API: `PUT /artifactory/api/security/permissions/{permissionName}`. - -### Key differences - -| Aspect | V1 (Permission Targets) | V2 (Access Permissions) | -|--------|------------------------|------------------------| -| Managed by | Artifactory | Access service | -| API base | `/artifactory/api/security/permissions/` | `/access/api/v2/permissions/` | -| Actions | lowercase (`read`, `write`) | uppercase (`READ`, `WRITE`) | -| Resource types | repos, builds, release bundles | + destinations, pipeline sources | -| Pattern fields | `includes_pattern` / `excludes_pattern` | `include_patterns` / `exclude_patterns` | -| CLI support | `jf rt permission-target-*` | No direct CLI commands (use REST) | - -For project-scoped RBAC, see Project roles in `platform-access-entities.md`. - -## Replication - -Replication synchronizes artifacts and properties between repositories, either -within the same instance or across Platform Deployments. - -| Type | Direction | Trigger | -|------|-----------|---------| -| **Push** | Source pushes to target | Scheduled or event-based | -| **Pull** | Target pulls from source | Scheduled | - -Replication configs are JSON templates applied per repository. Both artifact -content and properties are replicated. For federated repos, replication is -automatic and bi-directional across all member nodes. diff --git a/plugins/jfrog/skills/jfrog/references/artifactory-operations.md b/plugins/jfrog/skills/jfrog/references/artifactory-operations.md deleted file mode 100644 index bab2b65..0000000 --- a/plugins/jfrog/skills/jfrog/references/artifactory-operations.md +++ /dev/null @@ -1,178 +0,0 @@ -# Artifactory Operations - -CLI commands for managing Artifactory resources. All commands use the `jf rt` -namespace. Run `jf rt --help` to discover subcommands not listed here. - -## Repository management - -Repositories are created from JSON templates. The workflow is: - -1. Get a template: retrieve an existing repo config via - `jf api /artifactory/api/repositories/` - and modify it, or craft JSON manually. - Note: `jf rt repo-template` is interactive and cannot be used by agents. -2. Create: `jf rt repo-create ` -3. Update: `jf rt repo-update ` -4. Delete: `jf rt repo-delete --quiet` - -To list repositories, use: -`jf api /artifactory/api/repositories` - -## File operations - -- Upload: `jf rt upload ` -- Download: `jf rt download [target]` -- Search: `jf rt search ` -- Move: `jf rt move ` -- Copy: `jf rt copy ` -- Delete: `jf rt delete ` -- Set properties: `jf rt set-props "key=value"` -- Delete properties: `jf rt delete-props "key"` - -### Searching across repositories - -`jf rt search` expects a `/` argument. When the repo is unknown, -agents tend to use a leading wildcard (`jf rt search "*/path/..."`), which -generates an unscoped AQL internally and can time out on large instances. - -Use a direct AQL query with `name` and `path` criteria instead — omitting the -`repo` field searches all accessible repos via indexed columns: - -```bash -jf api /artifactory/api/search/aql \ - -X POST -H "Content-Type: text/plain" \ - -d 'items.find({ - "name":"", - "path":"" - }).include("repo","path","name","size","sha256")' -``` - -Add `"repo":""` to the criteria when the target repo is known, to -narrow the search further. - -## Build info - -**Project scoping rule:** Append `?project=` to **every** build detail -API call. When the user provides a project key, use it. When no project key -is provided, use `?project=default` (the built-in default project that covers -the `artifactory-build-info` repo). For AQL queries, scope by -`"repo":"-build-info"` (or `"repo":"artifactory-build-info"` for -the default project). - -**Server rule:** A 404 from a `?project=` build call is **not** a signal -to try a different server. Use only the resolved server; on any failure, -report and stop. See `SKILL.md` § *Server selection rules*. - -### Publishing builds - -- Collect env: `jf rt build-collect-env ` -- Add git info: `jf rt build-add-git ` -- Publish: `jf rt build-publish ` -- Promote: `jf rt build-promote ` -- Discard: `jf rt build-discard ` - -### Listing build names - -**Do not use `GET /api/build`** — it has no pagination and times out on large -instances. Always use AQL with `limit` and `offset`. - -**All builds** (no project scope): - -```bash -jf api /artifactory/api/search/aql \ - -X POST -H "Content-Type: text/plain" \ - -d 'builds.find().include("name","number","repo","created").sort({"$desc":["created"]}).offset(0).limit(100)' -``` - -**Project-scoped** — filter by the project's build-info repository -(`-build-info`, or `artifactory-build-info` for the default -project): - -```bash -jf api /artifactory/api/search/aql \ - -X POST -H "Content-Type: text/plain" \ - -d 'builds.find({"repo":"-build-info"}).include("name","number","repo","created").sort({"$desc":["created"]}).offset(0).limit(100)' -``` - -**Pagination:** The response includes a `range` object with `total` (total -matching records). If `total` exceeds the `limit`, tell the user: *"Showing -first 100 of N results (paginated). Ask for the next batch if needed."* -For subsequent pages, increment `offset` by 100. - -**Output rule (mandatory):** AQL returns one row per name+number pair. -Extract **unique build names** client-side (e.g. -`jq '[.[].builds.name] | unique'`). Present **only the deduplicated list of -build names** to the user. **Do not** include build numbers, timestamps, run -counts, or any per-run details in the response — not even as a "bonus" or -"most recent" table. The user is asking "what builds exist", not "what runs -happened". Only show run-level details if the user explicitly asks for them -in a follow-up. - -### Listing runs of a specific build - -```bash -jf api /artifactory/api/search/aql \ - -X POST -H "Content-Type: text/plain" \ - -d 'builds.find({"name":""}).include("name","number","repo","created").sort({"$desc":["created"]}).offset(0).limit(100)' -``` - -Add `"repo":"-build-info"` to the criteria when a project key -is known. Apply the same pagination rules as above. - -### Retrieving full build info - -Use the REST detail endpoint for a **single** build run. Always include -`?project=` (or `?project=default` when no key is provided): - -```bash -jf api "/artifactory/api/build//?project=" -``` - -This is the only `/api/build` endpoint that should be used — it returns a -single record and does not need pagination. - -### When a build is not found - -If the detail call returns 404, the build likely belongs to a different -project. **Ask the user for the project key** rather than searching across -repos or servers. - -### Repository listing vs build-info - -`GET /artifactory/api/repositories?project=&type=buildinfo` may return -an empty list even when project-scoped build info exists (for example under -a `*-build-info` repository). Prefer AQL to -discover builds; do not treat an empty repository -list as proof that no -builds exist. - -## Permissions - -Permission targets use JSON templates. -Note: `jf rt permission-target-template` is interactive. - -- Create: `jf rt permission-target-create ` -- Update: `jf rt permission-target-update ` -- Delete: `jf rt permission-target-delete ` - -## Users and groups - -- Create users: `jf rt users-create --csv ` -- Create single user: `jf rt user-create` (check `--help` for options) -- Delete users: `jf rt users-delete ` -- Create group: `jf rt group-create ` -- Delete group: `jf rt group-delete ` -- Add users to group: `jf rt group-add-users ` - -To get user details or update users, use `jf api`: -``` -jf api /access/api/v2/users/ -``` - -## Replication - -Replication configs use JSON templates. -Note: `jf rt replication-template` is interactive. - -- Create: `jf rt replication-create ` -- Delete: `jf rt replication-delete ` diff --git a/plugins/jfrog/skills/jfrog/references/catalog-entities.md b/plugins/jfrog/skills/jfrog/references/catalog-entities.md deleted file mode 100644 index 085bea0..0000000 --- a/plugins/jfrog/skills/jfrog/references/catalog-entities.md +++ /dev/null @@ -1,219 +0,0 @@ -# Catalog entities - -When to read this file: - -- Querying **public package metadata** (descriptions, vulnerabilities, licenses, operational info). -- Working with the **Custom Catalog** (org-specific labels, package views, federation). -- Looking up **vulnerability details** beyond what Xray provides (advisories, EPSS, CWE, known exploits). -- Querying **OpenSSF scorecards**, **ML model metadata**, or **MCP service** registries. -- Using the OneModel GraphQL API with `publicPackages`, `customPackages`, - `publicSecurityInfo`, `publicLegalInfo`, `publicOperationalInfo`, - `publicCatalogLabels`, or `publicRemoteServices` query roots. - -Catalog entities are accessed via the **OneModel GraphQL API** -(`/onemodel/api/v1/graphql`). - -For the OneModel query workflow (credentials, schema fetch, validation, -execution), read `references/onemodel-graphql.md`. - -## Two catalog layers - -| Layer | Scope | Description | -|-------|-------|-------------| -| **Public Catalog** | Global | JFrog's curated package database — security, legal, and operational metadata for public packages across ecosystems | -| **Custom Catalog** | Organization | Org-specific overlay — custom labels, per-org package views, federation config | - -The Custom Catalog builds on top of the Public Catalog. A public package -can be enriched with org-specific labels and metadata through the Custom -Catalog without altering the underlying public data. - -## Public Catalog entities - -### PublicPackage - -A package as known to JFrog's global package database. - -| Field | Description | -|-------|-------------| -| `name` | Package name (e.g. `lodash`, `spring-boot-starter-web`) | -| `type` | Package type (e.g. `npm`, `maven`, `pypi`) | -| `ecosystem` | Ecosystem identifier | -| `description` | Rich-text description | -| `homepage`, `vcsUrl` | Package URLs | -| `vendor` | Maintainer or organization | -| `latestVersion` | Most recent version | -| `trendingScore` | Popularity score | -| `publishedAt`, `modifiedAt` | Timestamps | -| `mlModel` | ML model metadata (for HuggingFace etc.) | - -Connections: `versionsConnection`, `publicLabelsConnection`, `legalInfo`, -`operationalInfo`, `securityInfo`. - -Query: `publicPackages.searchPackages(where: {...})`. - -### PublicPackageVersion - -A specific version with security, legal, and operational analysis. - -| Field | Description | -|-------|-------------| -| `version` | Version string | -| `isLatest` | Whether this is the latest version | -| `isListedVersion` | Whether visible in Catalog UI | -| `publishedAt`, `modifiedAt` | Timestamps | -| `trendingScore` | Version-level popularity | -| `dependencies` | Dependency information | -| `mlModelMetadata`, `mlInfo` | ML/AI-related metadata | - -Each version carries three info blocks: -- `securityInfo` — vulnerability data, maliciousness, contextual analysis -- `legalInfo` — licenses, copyrights -- `operationalInfo` — end-of-life, OpenSSF scores, popularity metrics - -### PublicVulnerability - -Vulnerability data richer than what Xray violations expose. Useful for -deep-dive security analysis and advisory lookups. - -| Field | Description | -|-------|-------------| -| `name` | CVE identifier (e.g. `CVE-2021-44228`) | -| `ecosystem` | Affected ecosystem | -| `severity` | `CRITICAL`, `HIGH`, `MEDIUM`, `LOW` | -| `description` | Detailed impact description | -| `cvss` | CVSS scores — v2, v3, **and v4** | -| `epss` | EPSS (Exploit Prediction Scoring System) — exploit likelihood | -| `knownExploit` | Known exploit information | -| `withdrawn` | Whether the CVE has been retracted | -| `aliases` | Alternative identifiers | -| `references` | Advisory URLs | -| `publishedAt`, `modifiedAt` | Timestamps | - -Advisory sources (via `advisories` connection): -- **NVD** — NIST National Vulnerability Database -- **GHSA** — GitHub Security Advisory -- **JFrog Advisory** — JFrog's own research (includes impact reasons) -- **Debian Security Tracker** -- **RedHat OVAL** - -Additional connections: `cwesConnection` (CWE entries), `cpesConnection` -(CPE entries), `publicPackageInfo` (affected packages and versions). - -Query: `publicSecurityInfo.searchVulnerabilities(where: {...})`. - -#### Filtering limitations - -`searchVulnerabilities` can filter by CVE name, ecosystem, severity, CVSS, -EPSS, known exploit status, and publication date — but **not** by affected -package name. There is no `hasPublicPackageInfoWith` or similar filter on -`PublicVulnerabilityWhereInput`. To find vulnerabilities affecting a specific -package, use one of these alternatives: - -- **Version-level security info** (GraphQL): query - `publicPackages.getPackage(type, name)` and navigate to - `versionsConnection → securityInfo → vulnerabilitiesConnection` to get - CVEs affecting specific versions. -- **Individual CVE lookup**: use `searchVulnerabilities(where: { name: "" })` - and inspect `publicPackageInfo.vulnerablePublicPackagesConnection` on the - `generic` ecosystem entry. - -#### Ecosystem multiplicity - -A single CVE appears as multiple `PublicVulnerability` entries — one per -ecosystem. The `ecosystem` field determines which entry you see: - -| Ecosystem | Contains | -|-----------|----------| -| `generic` | Non-OS package-level data (npm, maven, pypi, go, etc.) — includes `publicPackageInfo` with vulnerable versions and fix versions | -| `debian`, `redhat`, `ubuntu`, etc. | OS-specific advisory data — severity may differ from NVD; `publicPackageInfo` is typically empty (OS packages are tracked separately) | - -When looking up a CVE by name, `searchVulnerabilities(where: { name: "" })` -returns all ecosystem entries. To get affected packages and fix versions for -libraries like npm or maven, filter for or focus on the `generic` ecosystem -entry. `getVulnerability` requires both `name` and `ecosystem` — use -`searchVulnerabilities` when the ecosystem is unknown. - -### PublicLicense - -License metadata with permission, condition, and limitation details. - -| Field | Description | -|-------|-------------| -| `name` | License name (e.g. `Apache-2.0`, `MIT`) | -| `spdxId` | SPDX identifier | -| `permissions` | What the license permits | -| `limitations` | Restrictions imposed | -| `patentConditions` | Patent grant conditions | -| `noticeFiles` | Required notices | - -Query: `publicLegalInfo.searchLicenses(where: {...})`. - -### PublicPackageOperationalInfo - -Operational risk assessment for packages and versions. - -| Entity | Key data | -|--------|----------| -| **OpenSSF scorecard** | Overall score, individual checks with scores and pass/fail | -| **End-of-life** | Whether the package or version is EOL, justification | -| **Popularity** | JFrog popularity by segment and subscription tier, download counts | - -### MCP services and tools - -The Public Catalog also indexes MCP (Model Context Protocol) services: - -| Entity | Description | -|--------|-------------| -| `PublicMcpService` | An MCP service with name, description, version | -| `PublicMcpTool` | A tool exposed by an MCP service with arguments | -| `PublicMcpRemote` | Remote MCP server configuration | - -Query: `publicRemoteServices.searchMcpServices(where: {...})`. - -## Custom Catalog entities - -### CustomPackage - -A package in the organization's private catalog view. - -| Field | Description | -|-------|-------------| -| `customCatalogId` | Org-scoped identifier | -| `name`, `type`, `ecosystem`, `namespace` | Package identity | -| `isListedPackage` | Whether visible in Catalog UI | -| `customCatalogAddedAt`, `customCatalogModifiedAt` | Org-specific timestamps | - -Connections: `versionsConnection`, `legalInfo`, -`customCatalogLabelsConnection`. - -### CustomCatalogLabel - -Organization-defined labels for categorizing packages. - -| Field | Description | -|-------|-------------| -| `name` | Label name | -| `description` | What the label represents | -| `color` | Display color | -| `labelType` | `MANUAL` or `AUTOMATIC` | -| `assignmentInfo` | How and when the label was assigned | - -Labels can be assigned to both custom packages and public packages/versions -within the org's catalog scope. The Custom Catalog mutations allow -creating, updating, and deleting labels. - -### CustomCatalogFederation - -Configuration for federating catalog data across JFrog deployments. - -## Catalog vs. Xray vs. Stored Packages - -These three domains provide different views of package and security data: - -| Aspect | Catalog | Xray | Stored Packages | -|--------|---------|------|-----------------| -| **Scope** | Global knowledge base + org overlay | Instance-scoped scanning | Instance-scoped storage | -| **Security** | CVE advisories, EPSS, CVSS v2/v3/v4, known exploits | Watches, policies, violations | Vulnerability summary (deprecated) | -| **Packages** | Public metadata (description, homepage, OpenSSF) | Components identified during scanning | Packages/versions stored in Artifactory | -| **Access** | GraphQL only | REST + CLI (`jf api /xray/...`) | GraphQL only | -| **Use case** | Research, compliance reporting, package evaluation | Runtime enforcement, CI/CD gating | Inventory, location queries | diff --git a/plugins/jfrog/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md b/plugins/jfrog/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md deleted file mode 100644 index 2b44979..0000000 --- a/plugins/jfrog/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md +++ /dev/null @@ -1,93 +0,0 @@ -# Bulk operations and agent execution patterns - -Platform-wide guidance for agents that gather data from multiple JFrog products -(Artifactory, Xray, Access, Distribution, etc.), run long shell -sequences, or parallelize work. Product-specific field names and endpoints live -in the other `references/*` files; this document describes **patterns**, not -one workflow. - -## List vs detail responses - -Many REST surfaces expose a **light list** (keys, names, minimal fields) and a -**richer GET by id or key**. Fields needed for audits, reporting, joins, or -permission checks may appear **only** on the detail response. Before building a -multi-step flow on a single list call, confirm in API docs or with a sample GET -whether the fields you need are present. - -## Volume, batching, and timeouts - -- Estimate **N** round-trips (list + per-item GETs, paginated APIs, etc.) before - starting so execution time and tool timeouts stay predictable. -- Prefer batching independent reads in one Shell invocation when credentials and - tier match (see SKILL.md **Batch and parallel execution**). -- Split very large work across chunks, parallel Shell calls, or subagents when - the skill's tiering guidance says so. -- Before starting an N+1 loop (list + per-item detail), **estimate wall time** - as roughly `N * 1.5s` for sequential calls. Set `block_until_ms` to at - least that estimate plus a 30-second buffer. -- For loops exceeding ~60 items, prefer a single Shell invocation that writes - progress to a log file (`>> /tmp/jf-progress-$$.log`) so partial results - are visible even if the job is interrupted. -- If the task is read-only and items are independent, consider Tier 2 or - Tier 3 parallelism (see `general-parallel-execution.md`) to reduce total time — - but respect rate limits and keep concurrency modest (4-8 parallel calls). - -## Parallelism and shared files - -**Unsafe:** Multiple concurrent processes appending lines to the **same** file -(JSONL, logs, ndjson) without synchronization. Output can interleave on one -line and break parsers (e.g. JSON "Extra data" errors). - -**Safer:** - -- Write sequentially to one file; or -- One temp file per worker or chunk, then concatenate; or -- Use advisory locking (`flock`) if one file must be shared. - -For bulk API or CLI output files, use `/tmp` or `mktemp`; do not use -`~/.jfrog/skills-cache/` except for `jfrog-skill-state.json` and the OneModel -schema file (see main SKILL.md). - -## Shell hygiene - -- Use `set -euo pipefail` in non-trivial scripts so failures are not silent. -- Use unique temp paths (e.g. `$$` in the filename) and **echo the expanded - path** so it can be reused across Shell calls (see SKILL.md **Preserving - command output** for the `$$` + echo, session ID, and hardcoded patterns). -- Parse CLI and API JSON with **`jq`**. - -## Safe multi-response collection - -When looping over items (repos, builds, users) and fetching detail for each: - -1. Save each response to a variable or per-item file. -2. Validate with `jq -e . >/dev/null 2>&1` before appending. -3. On validation failure, write a structured error line so the caller can - report partial results instead of crashing. -4. After the loop, `jq -s '.' results.ndjson` to produce a single array. - -```bash -: >results.ndjson -while read -r key; do - body=$(jf api "/artifactory/api/repositories/$key" || true) - if echo "$body" | jq -e . >/dev/null 2>&1; then - echo "$body" | jq -c . >>results.ndjson - else - printf '{"key":"%s","_error":"invalid_response"}\n' "$key" >>results.ndjson - fi -done < <(jq -r '.[].key' list.json) -jq -s '.' results.ndjson > details.json -``` - -Never pipe a loop of `jf api` calls directly into `jq -s` without -per-body validation. - -## Where to find product specifics - -- Artifactory REST nuances: `references/artifactory-api-gaps.md` -- Platform admin / Access: `references/platform-admin-api-gaps.md` -- JFrog Projects (endpoints): `references/projects-api.md` -- Joining Artifactory repos to Projects (`projectKey`, roles, environments): - `references/platform-access-entities.md` -- Platform API invocation (all products through `jf api`): see - `SKILL.md` § *Invoking platform APIs with `jf api`* diff --git a/plugins/jfrog/skills/jfrog/references/general-parallel-execution.md b/plugins/jfrog/skills/jfrog/references/general-parallel-execution.md deleted file mode 100644 index a0bb9ba..0000000 --- a/plugins/jfrog/skills/jfrog/references/general-parallel-execution.md +++ /dev/null @@ -1,131 +0,0 @@ -# Batch and Parallel Execution - -When a task requires multiple independent operations, use the lightest -parallelism mechanism that fits. Three tiers are available, from lightest to -heaviest: - -| Tier | Mechanism | Best for | -|------|-----------|----------| -| 1 | Single Shell call with `&&` | Few commands, same credentials | -| 2 | Parallel Shell tool calls | Independent commands that can run concurrently | -| 3 | Parallel subagents (Task tool) | Large multi-step jobs where each branch needs its own reasoning | - -## Tier 1: Batch within a single Shell call - -Combine independent commands with `&&`. All JFrog API calls go through the -same `jf api` command and the same `jf config` server, so batching them -together is both safe and efficient: - -```bash -jf api /artifactory/api/repositories > /tmp/jf-repos-$$.json && \ -jf api /artifactory/api/system/ping > /tmp/jf-ping-$$.json && \ -jf api /artifactory/api/storageinfo > /tmp/jf-storage-$$.json -``` - -Cross-product reads batch the same way: - -```bash -jf api /access/api/v2/users/ > /tmp/jf-users-$$.json && \ -jf api /access/api/v2/groups/ > /tmp/jf-groups-$$.json && \ -jf api /access/api/v2/permissions/ > /tmp/jf-perms-$$.json -``` - -## Tier 2: Parallel Shell tool calls - -Use multiple Shell tool calls in the same message when the commands are -independent and the total runtime benefits from concurrency: - -```bash -# Shell call 1 — echo the expanded path so the agent can reference it later -OUT=/tmp/jf-repos-$$.json -jf api /artifactory/api/repositories > "$OUT" && echo "$OUT" - -# Shell call 2 (parallel) — same pattern, different PID -OUT=/tmp/jf-users-$$.json -jf api /access/api/v2/users/ > "$OUT" && echo "$OUT" -``` - -Each parallel Shell call gets a different PID, so `$$` expands to different -values. Echo the path so the agent knows the literal filename for cross-call -use (see SKILL.md **Preserving command output**). - -## Tier 3: Parallel subagents - -For tasks with multiple independent branches that each require several steps -or their own reasoning — such as generating a platform health report with -separate sections, auditing both repository config and security policies, or -comparing configurations across servers the user explicitly named — launch -parallel subagents using the Task tool. - -Each subagent runs autonomously, executes its own CLI/API calls, and returns -a structured result. The parent agent assembles the final answer. - -### Example — platform audit with three parallel subagents - -``` -Subagent 1 (shell): "Collect repository data" - → jf api /artifactory/api/repositories - → jf api /artifactory/api/storageinfo - → Return repo count, types, total size - -Subagent 2 (shell): "Collect security configuration" - → jf api /xray/api/v2/policies - → jf api /xray/api/v2/watches - → Return policy count, watch count, coverage gaps - -Subagent 3 (shell): "Collect user and permission data" - → jf api /access/api/v2/users/ - → jf api /access/api/v2/groups/ - → jf api /access/api/v2/permissions/ - → Return user count, group count, admin users -``` - -All three subagents run concurrently. Once all complete, the parent agent -merges their results into a unified report. - -### How to structure a subagent prompt - -1. State the goal clearly (e.g. "Collect all Xray policies and watches"). -2. Provide the exact commands to run, or name the API tier and let the - subagent discover via `--help`. -3. Tell the subagent to save output to `/tmp/jf-