From 1a48130d590024e38174e6d4dcd5d79caa1dc4cc Mon Sep 17 00:00:00 2001 From: yanivt Date: Tue, 2 Jun 2026 09:51:24 +0300 Subject: [PATCH 1/8] get skills from public repo --- .claude-plugin/plugin.json | 2 +- .github/scripts/sync-skills.mjs | 115 +++ .github/workflows/release.yml | 64 ++ .github/workflows/validate.yml | 3 + .gitignore | 8 +- .vendor.json | 5 + CONTRIBUTING.md | 26 +- VENDOR.md | 40 + skills/VENDOR.md | 13 - .../SKILL.md | 262 ------ skills/jfrog/.gitignore | 1 - skills/jfrog/SKILL.md | 484 ----------- skills/jfrog/assets/.gitkeep | 0 skills/jfrog/references/apptrust-entities.md | 154 ---- .../jfrog/references/artifactory-api-gaps.md | 216 ----- .../references/artifactory-aql-syntax.md | 654 --------------- .../jfrog/references/artifactory-entities.md | 236 ------ .../references/artifactory-operations.md | 170 ---- skills/jfrog/references/catalog-entities.md | 219 ----- ...eral-bulk-operations-and-agent-patterns.md | 102 --- .../references/general-parallel-execution.md | 133 ---- .../references/general-use-case-hints.md | 28 - .../references/jfrog-brand-html-report.md | 98 --- .../references/jfrog-cli-install-upgrade.md | 30 - .../references/jfrog-credential-patterns.md | 168 ---- skills/jfrog/references/jfrog-entity-index.md | 112 --- skills/jfrog/references/jfrog-login-flow.md | 127 --- .../jfrog/references/jfrog-url-references.md | 51 -- .../references/onemodel-common-patterns.md | 320 -------- skills/jfrog/references/onemodel-graphql.md | 423 ---------- .../references/onemodel-query-examples.md | 753 ------------------ .../references/platform-access-entities.md | 200 ----- .../references/platform-admin-api-gaps.md | 181 ----- .../references/platform-admin-operations.md | 60 -- skills/jfrog/references/projects-api.md | 257 ------ .../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 | 139 ---- .../jfrog/scripts/get-platform-credentials.sh | 77 -- .../scripts/jfrog-login-register-session.sh | 64 -- .../scripts/jfrog-login-save-credentials.sh | 97 --- 42 files changed, 252 insertions(+), 6925 deletions(-) create mode 100644 .github/scripts/sync-skills.mjs create mode 100644 .github/workflows/release.yml create mode 100644 .vendor.json create mode 100644 VENDOR.md delete mode 100644 skills/VENDOR.md delete mode 100644 skills/jfrog-package-safety-and-download/SKILL.md delete mode 100644 skills/jfrog/.gitignore delete mode 100644 skills/jfrog/SKILL.md delete mode 100644 skills/jfrog/assets/.gitkeep delete mode 100644 skills/jfrog/references/apptrust-entities.md delete mode 100644 skills/jfrog/references/artifactory-api-gaps.md delete mode 100644 skills/jfrog/references/artifactory-aql-syntax.md delete mode 100644 skills/jfrog/references/artifactory-entities.md delete mode 100644 skills/jfrog/references/artifactory-operations.md delete mode 100644 skills/jfrog/references/catalog-entities.md delete mode 100644 skills/jfrog/references/general-bulk-operations-and-agent-patterns.md delete mode 100644 skills/jfrog/references/general-parallel-execution.md delete mode 100644 skills/jfrog/references/general-use-case-hints.md delete mode 100644 skills/jfrog/references/jfrog-brand-html-report.md delete mode 100644 skills/jfrog/references/jfrog-cli-install-upgrade.md delete mode 100644 skills/jfrog/references/jfrog-credential-patterns.md delete mode 100644 skills/jfrog/references/jfrog-entity-index.md delete mode 100644 skills/jfrog/references/jfrog-login-flow.md delete mode 100644 skills/jfrog/references/jfrog-url-references.md delete mode 100644 skills/jfrog/references/onemodel-common-patterns.md delete mode 100644 skills/jfrog/references/onemodel-graphql.md delete mode 100644 skills/jfrog/references/onemodel-query-examples.md delete mode 100644 skills/jfrog/references/platform-access-entities.md delete mode 100644 skills/jfrog/references/platform-admin-api-gaps.md delete mode 100644 skills/jfrog/references/platform-admin-operations.md delete mode 100644 skills/jfrog/references/projects-api.md delete mode 100644 skills/jfrog/references/release-lifecycle-entities.md delete mode 100644 skills/jfrog/references/stored-packages-entities.md delete mode 100644 skills/jfrog/references/xray-entities.md delete mode 100755 skills/jfrog/scripts/check-environment.sh delete mode 100755 skills/jfrog/scripts/get-platform-credentials.sh delete mode 100755 skills/jfrog/scripts/jfrog-login-register-session.sh delete mode 100755 skills/jfrog/scripts/jfrog-login-save-credentials.sh diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index e7d9ae4..0488a96 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "name": "jfrog", "displayName": "JFrog", "description": "Official JFrog plugin. Connect Claude Code to JFrog to manage, secure, and govern your software supply chain. Give agents the context to build secure, compliant software.", - "version": "0.2.1", + "version": "0.2.2", "author": { "name": "JFrog Ltd.", "email": "devrel@jfrog.com", diff --git a/.github/scripts/sync-skills.mjs b/.github/scripts/sync-skills.mjs new file mode 100644 index 0000000..a837810 --- /dev/null +++ b/.github/scripts/sync-skills.mjs @@ -0,0 +1,115 @@ +#!/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 — skills/ is gitignored, so the +// result is invisible to git. +// +// This repo IS a single Claude Code plugin (the repo root is the plugin +// root), so unlike multi-plugin marketplaces this script reads a single +// .vendor.json at the repo root. It then: +// 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 repo root. +// +// 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)}`); +} + +// Sync this plugin: read .vendor.json, download + extract + copy. +// +// 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 main() { + const repoRoot = process.cwd(); + const vendorPath = path.join(repoRoot, ".vendor.json"); + if (!(await fileExists(vendorPath))) { + throw new Error(`missing .vendor.json at ${vendorPath}`); + } + + 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(`--- ${repo} (ref: ${ref}${overridden ? " [override]" : ""}) ---`); + + const workDir = await fs.mkdtemp(path.join(tmpdir(), "sync-skills-")); + try { + // `slug` is just a unique filename for this tarball + extract dir. + 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, repoRoot, rel); + } 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..290ce60 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,64 @@ +# Copyright (c) JFrog Ltd. 2026 +# Licensed under the Apache License, Version 2.0 +# https://www.apache.org/licenses/LICENSE-2.0 + +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 .vendor.json." + required: false + default: "" + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + environment: release + steps: + - name: Check out main + uses: actions/checkout@v6 + with: + ref: main + + - name: Install Node.js + uses: actions/setup-node@v6 + with: + node-version: "20" + + - name: Sync skills from upstream + env: + SKILLS_REF: ${{ inputs.skills_version }} + run: node .github/scripts/sync-skills.mjs + + - name: Resolve release tag + run: | + VERSION=$(node -e ' + const manifest = require("./.claude-plugin/plugin.json"); + if (!manifest?.version) process.exit(1); + console.log(manifest.version); + ') + if [ -z "$VERSION" ]; then + echo "::error::.claude-plugin/plugin.json must define a non-empty version" + exit 1 + fi + echo "TAG=v${VERSION}" >> "$GITHUB_ENV" + + - 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}" + + - 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.yml b/.github/workflows/validate.yml index 9fe59bb..2183ada 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -20,5 +20,8 @@ jobs: with: node-version: "24" + - name: Sync skills from upstream + run: node .github/scripts/sync-skills.mjs + - name: Validate plugin layout run: node scripts/validate-claude-plugin.mjs diff --git a/.gitignore b/.gitignore index 603ad37..f73c5a0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ .env.* !.env.example +# IDE settings +.idea/ + # OS and editor .DS_Store *.swp @@ -13,8 +16,9 @@ tmp/ temp/ -# Local extract when refreshing vendored skills -.tmp-jfrog-skills/ +# Skills are vendored from jfrog/jfrog-skills only at release time (see +# .vendor.json and .github/scripts/sync-skills.mjs). main is skill-free. +skills/ # Skill runtime caches (never commit) **/local-cache/ diff --git a/.vendor.json b/.vendor.json new file mode 100644 index 0000000..b4c4d06 --- /dev/null +++ b/.vendor.json @@ -0,0 +1,5 @@ +{ + "repo": "jfrog/jfrog-skills", + "pin": "v0.11.0", + "paths": ["skills"] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 26020fd..6fbc815 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,15 +10,23 @@ All contributors must sign the [JFrog CLA](https://jfrog.com/cla/) before contri 1. **Fork** the repository and create a feature branch from `main`. 2. Make your changes, ensuring they follow the existing code style and project conventions. -3. **Validate** locally: +3. **Vendor the skills locally** before testing — `main` does not contain `skills/`; they are pulled from [jfrog/jfrog-skills](https://github.com/jfrog/jfrog-skills) at release time. See [`VENDOR.md`](VENDOR.md) for the full picture. + +```bash +node .github/scripts/sync-skills.mjs +``` + +The pin lives in [`.vendor.json`](.vendor.json). Override for a one-off local run with `SKILLS_REF=v0.12.0 node .github/scripts/sync-skills.mjs`. The synced `skills/` tree is gitignored. + +4. **Validate** locally: ```bash node scripts/validate-claude-plugin.mjs ``` -Before a release or directory submission, also run **`claude plugin validate`** (requires [Claude Code](https://code.claude.com/docs) CLI). +This checks `.claude-plugin/plugin.json` and walks every `skills/*/SKILL.md` for required YAML frontmatter. Run it after `sync-skills.mjs` so it sees a real skill tree. Before a release or directory submission, also run **`claude plugin validate`** (requires [Claude Code](https://code.claude.com/docs) CLI). -4. **Test** by loading the repository as the plugin (the repo root is the plugin root): +5. **Test** by loading the repository as the plugin (the repo root is the plugin root): ```bash claude --plugin-dir . @@ -26,20 +34,22 @@ claude --plugin-dir . Exercise the skills you changed (for example `/jfrog:`). Run `/reload-plugins` after editing plugin files. -5. **Commit** with a clear, descriptive message. -6. Open a **pull request** against `main` with a summary of what changed and why. +6. **Commit** with a clear, descriptive message. Do not commit anything under `skills/` — that tree is regenerated at release time. +7. Open a **pull request** against `main` with a summary of what changed and why. ## Pre-release checklist -- [ ] `node scripts/validate-claude-plugin.mjs` passes. +- [ ] `node .github/scripts/sync-skills.mjs` succeeds against the pin in `.vendor.json`. +- [ ] `node scripts/validate-claude-plugin.mjs` passes against the synced tree. - [ ] `claude plugin validate` passes (before directory submission or major releases). - [ ] Version bumped in [`.claude-plugin/plugin.json`](.claude-plugin/plugin.json) when the plugin changes. - [ ] No secrets, credentials, or files under `**/local-cache/` committed. -- [ ] Smoke-test: `claude --plugin-dir .` from the repo root. +- [ ] No vendored skills committed under `skills/`. +- [ ] Smoke-test: `claude --plugin-dir .` from the repo root (after running the sync script). ### Submitting to the Claude plugin directory -Use [Submitting your plugin](https://claude.com/docs/plugins/submit). Submit the **public GitHub URL** of this repository — the **repository root** is the plugin root (manifest in `.claude-plugin/`, skills in `skills/`). +Use [Submitting your plugin](https://claude.com/docs/plugins/submit). Submit the **public GitHub URL** of this repository — the **repository root** is the plugin root (manifest in `.claude-plugin/`, skills vendored into `skills/` at release time from [jfrog/jfrog-skills](https://github.com/jfrog/jfrog-skills)). Compliance: [Anthropic Software Directory Terms](https://support.claude.com/en/articles/13145338-anthropic-software-directory-terms), [Anthropic Software Directory Policy](https://support.claude.com/en/articles/13145358-anthropic-software-directory-policy). diff --git a/VENDOR.md b/VENDOR.md new file mode 100644 index 0000000..fb1fab6 --- /dev/null +++ b/VENDOR.md @@ -0,0 +1,40 @@ +# Vendored skills + +The skill packages under `skills/` are vendored from **[jfrog/jfrog-skills](https://github.com/jfrog/jfrog-skills)** at release time. They are **not** committed to `main` — `skills/` is gitignored, and the synced tree lives only on the release tag. + +## Source of truth + +The upstream repository, the pinned ref, and the directories to copy are declared in [`.vendor.json`](.vendor.json): + +```json +{ + "repo": "jfrog/jfrog-skills", + "pin": "v0.11.0", + "paths": ["skills"] +} +``` + +Whatever ref is pinned there is what end users get when they install the plugin from the corresponding release tag. + +## How sync works + +[`.github/scripts/sync-skills.mjs`](.github/scripts/sync-skills.mjs) downloads the upstream tarball from `codeload.github.com`, extracts it, and copies each path listed in `paths` into the repo root. It runs: + +- **In CI**, on every pull request and push to `main` (see [`.github/workflows/validate.yml`](.github/workflows/validate.yml)) — exercises the synced tree against `scripts/validate-claude-plugin.mjs`. +- **In CI**, at release time (see [`.github/workflows/release.yml`](.github/workflows/release.yml)) — produces the actual content shipped on the release tag. +- **Locally**, when contributors want to test the plugin against the real skill content. The synced `skills/` tree is gitignored. + +## Refreshing the pin + +1. Edit `pin` in `.vendor.json` to the new tag (e.g. `v0.12.0`). +2. (Optional) Run `node .github/scripts/sync-skills.mjs` locally to preview. +3. Open a PR with the bump. CI will sync against the new pin and validate. +4. Merge, then trigger the **Release plugin** workflow in GitHub Actions. + +To override the pin for a one-off local run without editing the file, set `SKILLS_REF`: + +```bash +SKILLS_REF=v0.12.0 node .github/scripts/sync-skills.mjs +``` + +The release workflow exposes the same override as a `skills_version` workflow input. diff --git a/skills/VENDOR.md b/skills/VENDOR.md deleted file mode 100644 index 6b107b7..0000000 --- a/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.3.0](https://github.com/jfrog/jfrog-skills/releases/tag/v0.3.0) | -| **Source commit** | `af1fb9d98d8b7230cc179a41c12d606aca3aac7e` | - -Included directories: `jfrog/`, `jfrog-package-safety-and-download/` (as of that release). - -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 (`git rev-parse vX.Y.Z` in a clone, or the GitHub tag object). diff --git a/skills/jfrog-package-safety-and-download/SKILL.md b/skills/jfrog-package-safety-and-download/SKILL.md deleted file mode 100644 index 3762550..0000000 --- a/skills/jfrog-package-safety-and-download/SKILL.md +++ /dev/null @@ -1,262 +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, remember that credentials don't persist -across calls — use the jfrog skill to obtain the platform URL and credentials -in each parallel call. - -## Step 1: Find the package - -Search the **Public Catalog** first via OneModel GraphQL, then fall back to -**Stored Packages** if not found. - -Use the jfrog skill for credentials (Tier 3) and the GraphQL execution -pattern. Refer to `../jfrog/references/onemodel-query-examples.md` for 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`). - -Use the jfrog skill for credentials and GraphQL execution. - -- **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. Download command depends on repository -type. **`` 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` | Use `jf rt dl` — the artifact is stored locally and will always be found | -| `remote` | Use the proxy endpoint directly — `jf rt dl` only finds already-cached artifacts and returns 0 for uncached packages, wasting an API call | - -**local / federated download:** - -```bash -jf rt dl "/" --flat -``` - -**remote download — go straight to the proxy endpoint:** - -```bash -jf rt curl -s -L -XGET "/api///" \ - -o -``` - -**Resolving the remote repo key for the proxy endpoint:** The `repositoryKey` -returned by OneModel for remote locations often already ends in `-cache` (e.g. -`devNPM-remote-cache`). The proxy endpoint 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 `` and path format. - -## Step 5: Check curation entitlement - -```bash -jf rt curl -s -XGET /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" -jf xr curl -s -XPOST "/api/v1/curation/package_status/all_repos" \ - -H "Content-Type: application/json" \ - -d "{\"packageType\":\"\",\"packageName\":\"\",\"packageVersion\":\"\"}" \ - -o "$RESPONSE_FILE" -w "\n%{http_code}" -echo "$RESPONSE_FILE" -``` - -Supported `packageType` values: `npm`, `pypi`, `maven`, `go`, `nuget`, -`docker`, `gradle`. - -To capture both the response body and the HTTP status code in one call, use -`-w "\n%{http_code}"` and parse the last line as the status code: - -```bash -HTTP_CODE=$(tail -1 "$RESPONSE_FILE") -BODY=$(sed '$d' "$RESPONSE_FILE") -if [ "$HTTP_CODE" = "403" ]; then - echo "Blocked by curation policy:" - echo "$BODY" -elif [ "$HTTP_CODE" = "200" ]; then - echo "Package is allowed by curation." -fi -``` - -**Evaluate the HTTP status code:** - -- **200** → package is **allowed** by curation policy. Proceed to download - via a remote repo (same as Step 6b). -- **403** → 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. - -## 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 rt curl -s -XGET "/api/repositories?type=remote&packageType=" \ - | jq '.[].key' - ``` - -2. **Download:** - - ```bash - jf rt dl "-cache/" --flat - ``` - - If 0 results (not cached), fetch through the remote proxy: - - ```bash - jf rt curl -s -L -XGET "/api///" \ - -o - ``` - -## Protocol endpoints by package type - -| Type | Protocol prefix | Artifact path pattern | -|------|----------------|----------------------| -| `npm` | `/api/npm/` | `/-/-.tgz` | -| `pypi` | `/api/pypi//packages` | `//-.tar.gz` | -| `maven` | `/` | `///-.jar` | -| `go` | `/api/go/` | `/@v/.zip` | - -## Gotchas - -- **`jf rt dl` and remote repos**: `jf rt dl` only finds artifacts already - present in the `-cache` repo. For `remote` repository types, Step 4 - instructs to skip `jf rt dl` entirely and use the proxy endpoint directly, - avoiding a wasted round-trip for uncached packages. -- **Redirects**: `jf rt curl` does not follow HTTP redirects by default. - Always pass `-L` when downloading binary artifacts through remote repo - proxy endpoints. -- **`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 API uses `jf xr curl`**: The curation package status endpoint - is under Xray, not Artifactory. Use `jf xr curl`, not `jf rt curl`. -- **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/skills/jfrog/.gitignore b/skills/jfrog/.gitignore deleted file mode 100644 index 3215b96..0000000 --- a/skills/jfrog/.gitignore +++ /dev/null @@ -1 +0,0 @@ -local-cache/ diff --git a/skills/jfrog/SKILL.md b/skills/jfrog/SKILL.md deleted file mode 100644 index 71b3bc6..0000000 --- a/skills/jfrog/SKILL.md +++ /dev/null @@ -1,484 +0,0 @@ ---- -name: jfrog -version: "0.3.0" -description: >- - Interact with the JFrog Platform via the JFrog CLI 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 curl and jq on PATH. -metadata: - role: base ---- - -# 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 the JFrog CLI (`jf`) and, where the -CLI falls short, through REST APIs and GraphQL. 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. - -## Prerequisites - -The following tools must be available on `PATH`: - -| Tool | Purpose | -|------|---------| -| `curl` | HTTP requests to JFrog REST and GraphQL APIs | -| `jq` | JSON parsing of CLI and API output | - -## Environment check - -Before your first JFrog operation in a session, run the environment check. -It verifies the CLI is installed, checks for updates, and exports -`JFROG_CLI_USER_AGENT` so every outbound request is identifiable: - -```bash -eval "$(JFROG_SKILL_MODEL="" bash /scripts/check-environment.sh)" -``` - -Set `JFROG_SKILL_MODEL` to the model slug you are running as (e.g. -`opus-4.6`, `sonnet-4`). The script appends it to the user agent string. - -The `eval` is required — the script outputs -`export JFROG_CLI_USER_AGENT='model/ jfrog-skills/ jfrog-cli-go/'` -on stdout. The JFrog CLI picks this up natively and injects it as the -`User-Agent` header on every HTTP request. JSON state is printed to stderr -for informational purposes (also written to the cache file). - -The script uses a 24-hour cache at `/local-cache/jfrog-skill-state.json`. If the -cache is fresh, it returns immediately. If stale or missing, it checks whether -`jf` is installed, its version, and whether a newer version is available. - -- Exit 0: cache is fresh, CLI is ready -- Exit 1: cache was stale and has been refreshed, CLI is ready -- Exit 2: `jf` is not installed - -Bypass the cache only when the user explicitly asks to install, upgrade, or -reconfigure the CLI. - -If the CLI is missing (exit 2) or an upgrade is needed, read -`references/jfrog-cli-install-upgrade.md` for install and upgrade instructions. - -### JSON parsing (`jq`) - -Use **`jq`** for all JSON parsing of CLI and API output (pipes, `-r`, filters). -Examples: `base64 -d | jq -r '.url'`, `jf rt curl ... | jq '.[] | .key'`. - -## Network permissions - -JFrog servers are not on the default sandbox network allowlist. Every Shell -call that contacts a JFrog server — whether via `jf` CLI, `jf rt curl`, -`jf xr curl`, or plain `curl` — requires `required_permissions: ["full_network"]`. - -Without this permission, commands fail silently: `jf` exits with code 1 and -empty output, `curl` returns an empty response, and downstream JSON parsing -crashes. All JFrog operations that touch the network need this permission. - -### Agent execution environments - -`check-environment.sh` does **not** call your JFrog server, but it may make an -outbound request to `releases.jfrog.io` for version checking and may **write** -`/local-cache/jfrog-skill-state.json` when the cache is stale. In a **sandboxed** -agent environment, **`full_network` alone may not suffice**: if the workspace -cannot be written, the check can fail before any JFrog call. Request -permissions that allow writing `/local-cache` (or run -outside a restrictive sandbox) when you see filesystem errors from the -environment check. - -### `local-cache/` — allowed files only - -`/local-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 `local-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. - -Apply `full_network` on the **first** Shell call that hits JFrog. Once -granted for a session, the agent environment typically retains it for -subsequent calls, but always include it explicitly to avoid silent failures. - -## Server management - -Server configuration is always read live from `jf config` (never cached). - -- **List servers**: `jf config show` (local operation, no network needed) -- **Use a specific server**: pass `--server-id ` to any command -- **Switch default**: `jf config use ` -- **Add a new server**: read `references/jfrog-login-flow.md` for the full - login procedure (web login or manual token setup) - -### Server selection rules (mandatory) - -Exactly one server (or an explicit set of servers) must be resolved before any -operation. The rules are strict and apply to every CLI command, API call, and -subagent prompt: - -1. **User named specific server(s)** — use those and only those. Pass - `--server-id ` (CLI) or the matching server-id to - `get-platform-credentials.sh` (REST). Do not touch any other configured - server. -2. **User did not name a server** — use the current default server and only - it. Determine the default via `jf config show` (the entry marked as - default). If no default is set, stop and ask the user which server to use. -3. **Verify before executing** — after resolving the server, confirm it - exists in `jf config show` output before running any command against it. - If the server-id is not listed, stop and tell the user. - -Do not fall back to a different server. Silently switching servers is -dangerous because different servers hold different data, permissions, and -configurations — an operation that succeeds on the wrong server can corrupt -state, leak data across environments, or produce results the user cannot -reproduce. If the resolved server produces any error — does not exist in -`jf config`, authentication failure (401/403), network error, connection -refused, or any other failure — stop immediately and report the error to the -user. Do not try other configured servers, do not iterate through the server -list, and do not silently switch servers. Ask the user how to proceed. - -## 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`. - -## Artifactory operations - -Artifactory resources are managed through the `jf rt` namespace — repos, files, -builds, permissions, users/groups, and replication. Read -`references/artifactory-operations.md` when performing any of these operations. - -## Platform administration - -Access tokens, login, stats, projects, and system health. Read -`references/platform-admin-operations.md` when performing any of these -operations. - -## Falling back to REST APIs - -When the CLI does not support an operation, use REST APIs. All commands in this -section require `required_permissions: ["full_network"]` (see Network -permissions above). Read `references/jfrog-credential-patterns.md` for detailed -patterns. - -### Tier 1: Artifactory (`jf rt curl`) - -Handles authentication automatically: -```bash -jf rt curl -XGET /api/repositories -jf rt curl -XGET "/api/storage//?properties" -jf rt curl -XPOST /api/search/aql -H "Content-Type: text/plain" -d '' -``` - -### Tier 2: Xray (`jf xr curl`) - -Handles authentication automatically: -```bash -jf xr curl -XGET /api/v2/watches -jf xr curl -XGET /api/v2/policies -``` - -### Tier 3: Other products (plain curl) - -Extract credentials using the helper script: -```bash -eval "$(bash /scripts/get-platform-credentials.sh [server-id])" -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/access/api/v2/users/" -``` - -### GraphQL (OneModel) - -OneModel is the unified GraphQL API on the platform base URL. **Do not** embed -the query string inside a JSON literal (`-d '{"query":"..."}'`) — GraphQL uses -many double quotes and manual escaping breaks requests. Use **`jq -n --arg`** -to build the payload, and **save the HTTP response to a file** with `curl -o` -before running `jq` (same principle as *Preserving command output* below). - -```bash -eval "$(bash /scripts/get-platform-credentials.sh [server-id])" -QUERY='{ evidence { searchEvidence(first: 5, where: { hasSubjectWith: { repositoryKey: "my-repo-local" } } }) { totalCount } } }' -PAYLOAD=$(jq -n --arg q "$QUERY" '{"query": $q}') -RESPONSE_FILE="/tmp/onemodel-$$.json" -curl -s -X POST "$JFROG_URL/onemodel/api/v1/graphql" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d "$PAYLOAD" \ - -o "$RESPONSE_FILE" -jq . "$RESPONSE_FILE" -echo "$RESPONSE_FILE" -``` - -Schema discovery: `GET $JFROG_URL/onemodel/api/v1/supergraph/schema` (schema file -only under `/local-cache/` per `references/onemodel-graphql.md` and -**`local-cache/` — allowed files only** above — not for query responses). - -Read **`references/onemodel-graphql.md`** for the full workflow (mandatory schema -fetch, validation, pagination, errors, playground). Read -**`references/onemodel-query-examples.md`** for domain-specific query shapes and -**`references/onemodel-common-patterns.md`** for 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 rt curl -XGET /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 - -- JFrog network calls require `required_permissions: ["full_network"]` in the - Shell tool. Without it, commands fail silently with empty output. The - environment check does **not** call your JFrog server (it may contact - `releases.jfrog.io` for version checking), but it may need **workspace - write** access for its cache file (see [Agent execution environments](#agent-execution-environments)). -- `jf rt curl` only works for Artifactory. `jf xr curl` only works for Xray. - For other products, use plain curl with extracted credentials. -- 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 rt curl -XPOST /api/search/aql`. 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 curl`, `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. -- Always use `jf rt curl -s` (silent flag) when piping output to `jq` or - redirecting to a file. Without `-s`, curl's progress meter is mixed into - stdout and breaks JSON parsing. -- 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 REST API call returns 401, the access token may have expired — - re-extract credentials with `get-platform-credentials.sh` for the **same** - server. If 403, the token lacks required permissions. If 404, verify the - endpoint path 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. - -## Cautious execution - -Do not run commands speculatively. Before executing any JFrog CLI command or -API call: - -1. Confirm the operation is needed to fulfill the user's request -2. Resolve the target server using the **Server selection rules** above — - 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 -4. Prefer read operations first to understand current state before making changes -5. If any command fails with a server-level error (not found, auth, network), - stop and ask the user — never retry against a different server -6. **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. - -## 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 rt curl -XGET /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 rt curl`, `jf xr curl`, Tier 3 `curl`, 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. - -## 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**: read `references/artifactory-operations.md` (for **listing builds** with a known project key: REST `GET /api/build?project=`, then `GET /api/build/?project=` — see § *Listing builds when the project key is known*) -- **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)**: read `references/catalog-entities.md` (~190 lines) -- **CVE details, vulnerability lookup by CVE ID, or severity/affected-packages/fix-versions for a specific CVE**: go directly to `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) -- **Credential extraction for products beyond Artifactory and Xray**: read `references/jfrog-credential-patterns.md` (~155 lines; includes **Response handling** for any network-backed response body: fetch once to a temp file, then `jq` the file — plain `curl` or `jf rt curl` / `jf xr curl` alike) - -### 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, sandbox/cache issues**: 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` diff --git a/skills/jfrog/assets/.gitkeep b/skills/jfrog/assets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/skills/jfrog/references/apptrust-entities.md b/skills/jfrog/references/apptrust-entities.md deleted file mode 100644 index 6ca5088..0000000 --- a/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/skills/jfrog/references/artifactory-api-gaps.md b/skills/jfrog/references/artifactory-api-gaps.md deleted file mode 100644 index 02e4c12..0000000 --- a/skills/jfrog/references/artifactory-api-gaps.md +++ /dev/null @@ -1,216 +0,0 @@ -# Artifactory API Gaps - -Operations available through REST API but not through CLI commands. -Use `jf rt curl` for all of these (handles authentication automatically). - -## Repository management - -### Get repository configuration -```bash -jf rt curl -XGET /api/repositories/ -``` -Returns the full JSON configuration of a repository. Useful as a template -for creating similar repos. - -### List all repositories -```bash -jf rt curl -XGET /api/repositories -# Filter by type, package type, and/or project (all combinable) -jf rt curl -XGET "/api/repositories?type=local" -jf rt curl -XGET "/api/repositories?type=remote" -jf rt curl -XGET "/api/repositories?type=virtual" -jf rt curl -XGET "/api/repositories?packageType=docker" -jf rt curl -XGET "/api/repositories?project=myproj" -jf rt curl -XGET "/api/repositories?project=myproj&type=local&packageType=docker" -``` - -### Get repositories (v2) -```bash -jf rt curl -XGET "/api/repositories/configurations?repo_type=LOCAL&package_type=maven" -``` - -### Check if repository exists -```bash -jf rt curl -XHEAD /api/repositories/ -# 200 = exists, 400 = does not exist -``` - -## Storage and system - -### Get storage summary -```bash -jf rt curl -XGET /api/storageinfo -``` - -### Refresh storage summary -```bash -jf rt curl -XPOST /api/storageinfo/calculate -``` - -### Get storage item info -```bash -jf rt curl -XGET "/api/storage//" -``` - -### System ping -```bash -jf rt curl -XGET /api/system/ping -``` - -### System version -```bash -jf rt curl -XGET /api/system/version -``` - -### System configuration -```bash -jf rt curl -XGET /api/system/configuration -``` - -## Search (beyond CLI) - -### AQL queries -```bash -jf rt curl -XPOST /api/search/aql \ - -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 rt curl -XPOST /api/search/aql \ - -H "Content-Type: text/plain" \ - -d 'items.find({"repo":"my-remote-cache"})' -``` - -### Property search -```bash -jf rt curl -XGET "/api/search/prop?key=value&repos=my-repo" -``` - -### Checksum search -```bash -jf rt curl -XGET "/api/search/checksum?sha256=" -``` - -### GAVC search (Maven) -```bash -jf rt curl -XGET "/api/search/gavc?g=com.example&a=mylib&v=1.0" -``` - -## User management (beyond CLI) - -These Access API endpoints are routed through Artifactory's auth proxy via -`jf rt curl`. The same endpoints can also be reached with plain `curl` and -extracted credentials — see `platform-admin-api-gaps.md` (Users section). - -### Get user details -```bash -jf rt curl -XGET /access/api/v2/users/ -``` - -### Update user -```bash -jf rt curl -XPATCH /access/api/v2/users/ \ - -H "Content-Type: application/json" \ - -d '{"email": "new@example.com"}' -``` - -### List all users -```bash -jf rt curl -XGET /access/api/v2/users/ -``` - -### Get group details -```bash -jf rt curl -XGET /access/api/v2/groups/ -``` - -## Metadata calculation - -Trigger metadata recalculation for various package types: -```bash -# Maven -jf rt curl -XPOST /api/maven/calculateMetaData/ - -# npm -jf rt curl -XPOST /api/npm//reindex - -# Docker -# (automatic, no manual trigger) - -# PyPI -jf rt curl -XPOST /api/pypi//reindex - -# Helm -jf rt curl -XPOST /api/helm//reindex - -# Debian -jf rt curl -XPOST /api/deb/reindex/ -``` - -## Trash can and garbage collection - -### Empty trash -```bash -jf rt curl -XPOST /api/trash/empty -``` - -### Restore from trash -```bash -jf rt curl -XPOST "/api/trash/restore//" -``` - -### Run garbage collection -```bash -jf rt curl -XPOST /api/system/storage/gc -``` - -## Federated repositories (beyond basic CRUD) - -### Get federation status -```bash -jf rt curl -XGET /api/federation/status/ -``` - -### Trigger full sync -```bash -jf rt curl -XPOST "/api/federation/fullSyncAll/" -``` - -## Build info (beyond CLI) - -### List builds (prefer scoped queries) - -**Unscoped** `GET /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 rt curl -XGET "/api/build?project=" - -# Project scope — all run numbers for one build name (response: buildsNumbers) -jf rt curl -XGET "/api/build/?project=" - -# Build-info repo scope — alternative when you know the repo key -jf rt curl -XGET "/api/build?buildRepo=" -``` - -### Get build info -```bash -# Default build-info repo only (no project / non-default repo) -jf rt curl -XGET "/api/build//" - -# Project or custom build-info repo -jf rt curl -XGET "/api/build//?project=" -jf rt curl -XGET "/api/build//?buildRepo=" -``` - -### Delete builds -```bash -jf rt curl -XPOST /api/build/delete \ - -H "Content-Type: application/json" \ - -d '{"buildName":"my-build","buildNumbers":["1","2"]}' -``` diff --git a/skills/jfrog/references/artifactory-aql-syntax.md b/skills/jfrog/references/artifactory-aql-syntax.md deleted file mode 100644 index 937f83c..0000000 --- a/skills/jfrog/references/artifactory-aql-syntax.md +++ /dev/null @@ -1,654 +0,0 @@ -# AQL (Artifactory Query Language) - -AQL queries are sent as POST requests with `Content-Type: text/plain`: - -```bash -jf rt curl -XPOST /api/search/aql -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 rt curl -s -XGET "/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 rt curl -s -XPOST /api/search/aql -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/skills/jfrog/references/artifactory-entities.md b/skills/jfrog/references/artifactory-entities.md deleted file mode 100644 index 1e4d950..0000000 --- a/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/skills/jfrog/references/artifactory-operations.md b/skills/jfrog/references/artifactory-operations.md deleted file mode 100644 index 84a39e6..0000000 --- a/skills/jfrog/references/artifactory-operations.md +++ /dev/null @@ -1,170 +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 rt curl -XGET /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 rt curl -XGET /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 rt curl -s -XPOST /api/search/aql \ - -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 - -### 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 ` - -### Retrieving build info - -The build detail API (`GET /api/build/{name}/{number}`) returns 404 when the -build is stored in a non-default build-info repo or belongs to a JFrog -Project. **Always resolve the scope before calling the build API:** - -1. If the user provided a project key or build-info repo, use it directly. -2. If you need to **list** build names or run numbers and you have a **project - key**, follow [Listing builds when the project key is known](#listing-builds-when-the-project-key-is-known) (REST first — do not jump to AQL). -3. If the project key and build-info repo are still unknown, discover scope - via AQL (see [Discovering build scope without a project key](#discovering-build-scope-without-a-project-key) below). -4. For **detail**, use a scoped detail GET — never call `GET /api/build//` without `?project=` or `?buildRepo=` when the build requires it. - -```bash -jf rt curl -s -XGET "/api/build//?buildRepo=" -jf rt curl -s -XGET "/api/build//?project=" -``` - -Scope parameters: - -- `?buildRepo=` — when the build info is stored in a - non-default build-info repository (anything other than - `artifactory-build-info`) -- `?project=` — when the build belongs to a JFrog Project - -### Listing builds when the project key is known - -When you have a **project key**, use this REST sequence before AQL. It scopes -the server’s work and avoids **unscoped** listing pitfalls (see below). - -1. **Build names** (one row per logical build): - `GET /api/build?project=` - Response includes `builds[]` with `uri` (path suffix per name) and - `lastStarted` (latest run for that name). - -2. **Run numbers for one name**: - `GET /api/build/?project=` - Response uses the field **`buildsNumbers`** (exact spelling from the API); - each entry has `uri` (e.g. `/33`) and `started`. The same number may appear - more than once with different `started` values — do not assume uniqueness - by number alone. - -3. **Full build info** (unchanged): - `GET /api/build//?project=` - -```bash -jf rt curl -s -XGET "/api/build?project=" -jf rt curl -s -XGET "/api/build/?project=" -jf rt curl -s -XGET "/api/build//?project=" -``` - -### Discovering build scope without a project key - -When the user has not provided the project key or build-info repo, discover -it via AQL. **Do not** use **unscoped** `GET /api/build` (no `?project=` or -`?buildRepo=`) to list all builds — it can time out on large instances with -thousands of builds. - -Use AQL `builds.find()` instead. The builds domain **requires** `name`, -`number`, and `repo` in `.include()` for permission reasons — omitting `repo` -produces an error. - -```bash -jf rt curl -s -XPOST /api/search/aql \ - -H "Content-Type: text/plain" \ - -d 'builds.find({"name":""}).include("name","number","repo").sort({"$desc":["number"]}).limit(10)' -``` - -The `build.repo` field in the response tells you which build-info repository -the build resides in. Use that value as the `buildRepo` parameter in the -detail GET. - -### Repository listing vs build-info - -`GET /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 the **build** endpoints above or 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 rt curl`: -``` -jf rt curl -XGET /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/skills/jfrog/references/catalog-entities.md b/skills/jfrog/references/catalog-entities.md deleted file mode 100644 index f4f1ee2..0000000 --- a/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 xr curl`) | GraphQL only | -| **Use case** | Research, compliance reporting, package evaluation | Runtime enforcement, CI/CD gating | Inventory, location queries | diff --git a/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md b/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md deleted file mode 100644 index aeac970..0000000 --- a/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md +++ /dev/null @@ -1,102 +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. - -## Agent sandboxes and the environment check - -`scripts/check-environment.sh` does **not** call your JFrog server, but it may -make an outbound request to `releases.jfrog.io` for version checking and may -**write** -`/local-cache/jfrog-skill-state.json` when the cache is stale or missing. In a -restricted agent sandbox, **workspace write** access can fail even when -`full_network` is granted. Request permissions that allow writing `/local-cache` -when the check fails with a filesystem error. - -For bulk API or CLI output files, use `/tmp` or `mktemp`; do not use -`local-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 rt curl -sS -XGET "/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 rt curl` 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` -- Credential tiers: `references/jfrog-credential-patterns.md` diff --git a/skills/jfrog/references/general-parallel-execution.md b/skills/jfrog/references/general-parallel-execution.md deleted file mode 100644 index 340dd2e..0000000 --- a/skills/jfrog/references/general-parallel-execution.md +++ /dev/null @@ -1,133 +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 tier, same credentials | -| 2 | Parallel Shell tool calls | Commands across different tiers or credential scopes | -| 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 `&&` when they share the same credential -scope. This reduces approval prompts. - -```bash -jf rt curl -XGET /api/repositories > /tmp/jf-repos-$$.json && \ -jf rt curl -XGET /api/system/ping > /tmp/jf-ping-$$.json && \ -jf rt curl -XGET /api/storageinfo > /tmp/jf-storage-$$.json -``` - -For REST calls that share extracted credentials: - -```bash -eval "$(bash /scripts/get-platform-credentials.sh)" && \ -curl -s -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/access/api/v2/users/" > /tmp/jf-users-$$.json && \ -curl -s -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/access/api/v2/groups/" > /tmp/jf-groups-$$.json && \ -curl -s -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/access/api/v2/permissions/" > /tmp/jf-perms-$$.json -``` - -## Tier 2: Parallel Shell tool calls - -Use multiple Shell tool calls in the same message when commands target -different tiers or do not share state (e.g. one `jf rt curl` call alongside -one plain `curl` call): - -```bash -# Shell call 1 — echo the expanded path so the agent can reference it later -OUT=/tmp/jf-repos-$$.json -jf rt curl -XGET /api/repositories > "$OUT" && echo "$OUT" - -# Shell call 2 (parallel) — same pattern, different PID -OUT=/tmp/jf-users-$$.json -eval "$(bash /scripts/get-platform-credentials.sh)" && \ -curl -s -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/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 rt curl -XGET /api/repositories - → jf rt curl -XGET /api/storageinfo - → Return repo count, types, total size - -Subagent 2 (shell): "Collect security configuration" - → jf xr curl -XGET /api/v2/policies - → jf xr curl -XGET /api/v2/watches - → Return policy count, watch count, coverage gaps - -Subagent 3 (shell): "Collect user and permission data" - → eval credentials, then curl Access API for users, groups, 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-