diff --git a/plugins/jfrog/.cursor-plugin/plugin.json b/plugins/jfrog/.cursor-plugin/plugin.json index e92f4df..6ab2d9f 100644 --- a/plugins/jfrog/.cursor-plugin/plugin.json +++ b/plugins/jfrog/.cursor-plugin/plugin.json @@ -22,6 +22,9 @@ "ai-catalog" ], "logo": "assets/logo.svg", - "skills": ["skills/jfrog/SKILL.md"], + "skills": [ + "skills/jfrog/SKILL.md", + "skills/jfrog-package-safety-and-download/SKILL.md" + ], "hooks": "hooks/hooks.json" } diff --git a/plugins/jfrog/skills/jfrog-package-safety-and-download/SKILL.md b/plugins/jfrog/skills/jfrog-package-safety-and-download/SKILL.md new file mode 100644 index 0000000..598318a --- /dev/null +++ b/plugins/jfrog/skills/jfrog-package-safety-and-download/SKILL.md @@ -0,0 +1,286 @@ +--- +name: jfrog-package-safety-and-download +description: >- + Check JFrog Public Catalog and stored packages for a version, interpret + catalog security signals, and download through Artifactory (JFrog Platform + locations, remote cache, curation-aware package managers, or repo proxy). + Use when the user asks whether a package is safe, allowed, curated, or + wants to download npm, Maven, PyPI, Go, or similar packages via JFrog. + Do NOT use for pure CVE or vulnerability lookups (e.g. "details on + CVE-2021-23337") — those are handled by the jfrog skill's Public security + domain queries without this workflow. +metadata: + role: workflow +--- + +# JFrog Package Safety and Download + +## Prerequisites + +- Read `../jfrog/SKILL.md` for JFrog Platform concepts, domain model, CLI setup, and API patterns. +- **OneModel shapes drift by server version.** Before inventing GraphQL fields or `where` filters, read `../jfrog/references/onemodel-graphql.md` (schema fetch workflow) and `../jfrog/references/onemodel-query-examples.md` (**Public packages**, **Stored packages**). Regenerate or verify queries against `GET "$JFROG_URL/onemodel/api/v1/supergraph/schema"` when examples fail validation. + +## Workflow + +# Package safety check and download workflow + +When to read this file: + +- User asks to **check if a package is safe** and/or **download** it. +- User asks to **download a package** from Artifactory. +- User mentions checking a package for **curation** approval. +- User wants to know if a package is **allowed** or **approved** for use. + +## Workflow overview + +```mermaid +flowchart TD + A[User requests package check / download] --> B{Package in Public Catalog?} + B -->|Yes| C[Get latest version from Catalog] + B -->|No| D{Package in JFrog Platform Stored Packages?} + D -->|Yes| E[Get latest version from Stored Packages] + D -->|No| F[Package not found — stop] + C --> G{Latest version in JFrog Platform?} + E --> G + G -->|Yes| H[Safe — download from JFrog Platform] + G -->|No| I{Curation entitled?} + I -->|Yes| J[Check curation policy via API] + I -->|No| K[Download via remote repo] + J -->|200 Allowed| K + J -->|403 Blocked| M[Report curation blocked — stop] +``` + +### Parallelization opportunities + +Several steps in this workflow are independent and can run in parallel to +reduce total latency: + +- **Step 1 + Step 1 fallback**: When package type is known, query both the + Public Catalog (`getPackage`) and Stored Packages (`getPackage`) in + parallel. Use whichever returns data; if the Public Catalog returns a hit, + prefer its `latestVersion` for Step 2. +- **Step 3 + Step 5**: After determining the version, query stored package + versions (JFrog Platform check) and curation entitlement + (`/api/system/version`) in parallel. Both are independent reads — the + curation result is needed immediately if the JFrog Platform check returns + empty. + +When issuing parallel Shell calls, each `jf api` call authenticates +independently against the active `jf config` server; no shell state needs +to be passed between calls. + +## Step 1: Find the package + +Search the **Public Catalog** first via OneModel GraphQL, then fall back to +**Stored Packages** if not found. + +Execute the query through `jf api` as described in +`../jfrog/references/onemodel-graphql.md`; refer to +`../jfrog/references/onemodel-query-examples.md` for concrete query shapes. + +**When package type is known** (e.g. `npm`, `maven`, `pypi`), use +`publicPackages.getPackage(type:, name:)` (see *Get a public package*). +Include the `latestVersion { version }` selection set — `latestVersion` is +an object, not a scalar. + +**When type is unknown**, use `publicPackages.searchPackages` with +`nameContains` (see *Search public packages*). Add `type:` when the user +narrows the ecosystem. + +- **Found** → note `type` and `latestVersion.version`. Proceed to Step 2. +- **Not found** → the package may be 1st/2nd party. Search **Stored Packages** + using `storedPackages.searchPackages` or `storedPackages.getPackage` (see + *Stored packages domain* in `onemodel-query-examples.md`). Prefer + filtering by `type` when known; if not, use `nameContains` alone. + - **Found** → note `type` and `latestVersionName` (or derive a version from + `versionsConnection`). Proceed to Step 2. + - **Not found in either** → report "package not found" and stop. + +If multiple results with different `type` values, ask the user which package +type they mean. + +## Step 2: Determine latest version + +| Source | Version field | +|--------|--------------| +| Public Catalog | `latestVersion.version` (object selection required) | +| JFrog Platform Stored Packages | `latestVersionName` on `StoredPackage`, or highest entry from `versionsConnection` | + +## Step 3: Check if package + latest version exists in JFrog Platform + +Query stored package versions using `storedPackages.searchPackageVersions` +with a `hasPackageWith` filter (see `../jfrog/references/onemodel-query-examples.md` +→ *Search stored package versions*). Add a `version` filter for the specific +version from Step 2, and request `locationsConnection` to get repository +details (`repositoryKey`, `repositoryType`, `leadArtifactPath`). + +Execute the query through `jf api` (see +`../jfrog/references/onemodel-graphql.md` for the invocation pattern). + +- **Found with locations** → package is in the JFrog Platform. Report as **safe to + download**. Proceed to Step 4. +- **Not found** → proceed to Step 5. + +## Step 4: Download from JFrog Platform + +Use the location info from Step 3. Binary artifact downloads go through +`jf rt dl` — **not** `jf api`. `jf api` is the unified entry point for the +JFrog REST APIs (metadata, admin, curation, etc.) and does not expose the +`-L` / `-o` flags needed to stream binary content through a redirect chain. + +**`` must be a full file path** (e.g. +`./downloads/lodash-4.18.1.tgz`), not a bare directory. `jf rt dl --flat` +treats the target as a file name; passing a directory causes a misleading +"open path: is a directory" error. + +| `repositoryType` | Strategy | +|-------------------|----------| +| `local` or `federated` | `jf rt dl "/" --flat` | +| `remote` | `jf rt dl` against the **base** remote repo (strip any trailing `-cache`) — it transparently triggers the remote fetch when the artifact is not yet cached | + +**local / federated / remote download:** + +```bash +jf rt dl "/" --flat +``` + +**Resolving the remote repo key:** The `repositoryKey` returned by OneModel +for remote locations often already ends in `-cache` (e.g. +`devNPM-remote-cache`). `jf rt dl` needs the **base remote repo name** +(without `-cache`). Strip the `-cache` suffix when present (e.g. +`devNPM-remote-cache` → `devNPM-remote`). If the key does not end in +`-cache`, use it as-is. + +See the **Protocol endpoints** table below for the package-type-specific +path format inside the repo. + +## Step 5: Check curation entitlement + +```bash +jf api /artifactory/api/system/version \ + | jq '.addons | index("curation") != null' +``` + +- `true` → curation is entitled. Proceed to Step 6a. +- `false` → curation not available. Proceed to Step 6b. + +## Step 6a: Check curation policy and download + +When curation is entitled, use the Xray curation API to check whether the +package version is allowed across all repositories before downloading. + +```bash +RESPONSE_FILE="/tmp/curation-status-$$.json" +PAYLOAD_FILE="/tmp/curation-payload-$$.json" +STDERR_FILE="/tmp/curation-err-$$.log" + +jq -n \ + --arg type "" \ + --arg name "" \ + --arg version "" \ + '{packageType:$type, packageName:$name, packageVersion:$version}' \ + > "$PAYLOAD_FILE" + +set +e +jf api /xray/api/v1/curation/package_status/all_repos \ + -X POST -H "Content-Type: application/json" \ + --input "$PAYLOAD_FILE" \ + > "$RESPONSE_FILE" 2> "$STDERR_FILE" +RC=$? +set -e +echo "RC=$RC"; echo "$RESPONSE_FILE" +``` + +Supported `packageType` values: `npm`, `pypi`, `maven`, `go`, `nuget`, +`docker`, `gradle`. + +**Interpreting the result with `jf api`**: unlike plain `curl`, `jf api` +surfaces the HTTP result through its **exit code** and a +`" [Warn] ... returned 4xx/5xx"` line on **stderr** (not a +`%{http_code}` suffix in stdout). The response body is always written to +stdout. Parse both: + +```bash +if [ "$RC" -eq 0 ]; then + echo "Package is allowed by curation." +elif grep -q 'returned 403' "$STDERR_FILE"; then + echo "Blocked by curation policy:" + cat "$RESPONSE_FILE" +else + echo "Curation check failed (rc=$RC):" + cat "$STDERR_FILE" +fi +``` + +**Evaluate the outcome:** + +- **exit 0** → package is **allowed** by curation policy. Proceed to + download via a remote repo (same as Step 6b). +- **`returned 403` on stderr** → package is **blocked** by a curation + policy. The response body explains which policy rule blocked it. Report + the block reason to the user and stop — do not attempt to download. +- **Any other non-zero exit** → treat as an operational failure (auth, DNS, + endpoint disabled) and report. + +## Step 6b: Download without curation + +When curation is not entitled and the package is not in the JFrog Platform, +download directly through a remote repo. + +1. **Find a remote repo** of the right package type: + + ```bash + jf api \ + "/artifactory/api/repositories?type=remote&packageType=" \ + | jq '.[].key' + ``` + +2. **Download** — use `jf rt dl` against the base remote repo (without + `-cache`); it handles both cached and uncached artifacts: + + ```bash + jf rt dl "/" --flat + ``` + +## Artifact paths by package type + +Use these path patterns when `leadArtifactPath` is not available from +OneModel. The leading `/` is the base repo key you pass to `jf rt dl`. + +| Type | `jf rt dl` target pattern | +|--------|-------------------------------------------------------------------------| +| `npm` | `//-/-.tgz` | +| `pypi` | `///-.tar.gz` | +| `maven`| `////-.jar` | +| `go` | `//@v/.zip` | + +## Gotchas + +- **Binary downloads vs. `jf api`**: `jf api` is for REST APIs, not binary + content. It does not follow redirects transparently into a binary payload + and does not expose `-L` / `-o`. Always use `jf rt dl` (against the base + remote repo, not the `-cache` one) for the actual artifact download. +- **`jf rt dl` and uncached remotes**: `jf rt dl "/"` — + targeting the **base** remote repo rather than `-cache/` — + transparently triggers the remote fetch and caches the artifact. Do not + try to pre-query the proxy via `jf api`. +- **`jf rt dl --flat` target must be a file path**: When downloading a + single artifact, pass a full output **file** path (e.g. + `./downloads/lodash-4.18.1.tgz`), not a directory. The CLI opens the target + path as a file; a directory causes a cryptic "open path: is a directory" + error that retries four times before failing. Derive the filename from + `leadArtifactPath` (take the segment after the last `/`). +- **Package type detection**: If the user doesn't specify the package type, + the Public Catalog search by name alone may return multiple types. Ask the + user to disambiguate before proceeding. +- **Curation endpoint lives under Xray**: use + `/xray/api/v1/curation/package_status/all_repos` (via `jf api`). Do not + prefix it with `/artifactory`. +- **Curation result discrimination with `jf api`**: the 200/403 signal comes + from `jf api`'s **exit code** plus a `returned NNN` line on **stderr**, + not from a `%{http_code}` appended to stdout. Capture stderr to a file + (`2> "$STDERR_FILE"`) and branch on `RC` + `grep 'returned 403'` as shown + in Step 6a. +- **Curation API package type values**: Must be lowercase and match one of + `npm`, `pypi`, `maven`, `go`, `nuget`, `docker`, `gradle`. Other values + will return an error. diff --git a/plugins/jfrog/skills/jfrog/SKILL.md b/plugins/jfrog/skills/jfrog/SKILL.md index e34a727..69ebcd6 100644 --- a/plugins/jfrog/skills/jfrog/SKILL.md +++ b/plugins/jfrog/skills/jfrog/SKILL.md @@ -1,543 +1,483 @@ --- -name: jfrog-platform -description: Use when working with the JFrog Platform -- Artifactory (repositories, artifacts, builds, AQL, replication, federation), Security/Xray (vulnerabilities, CVEs, policies, watches, SBOM, SAST, secrets detection), Access (tokens, users, groups, permissions, projects, RBAC), Distribution (release bundles, promotion, environments, edge nodes, evidence), Curation (package firewall, blocked packages, waivers), AppTrust (application entities, versions, trusted releases), Runtime (clusters, running images, sensors), Mission Control (JPDs, deployment health, licenses), Workers (serverless TypeScript, event hooks), CLI (jf command, jf rt, jf audit, jf scan), and architectural patterns/best practices. Triggers on mentions of any JFrog product, artifactory, xray, security, access token, curation, distribution, release bundle, apptrust, runtime, mission control, worker, jf command, pattern, or best practice. +name: jfrog +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 jq on PATH. metadata: - author: JFrog - version: 1.0.0 - mcp-server: jfrog - category: security - tags: [artifactory, xray, curation, supply-chain-security, devops] + role: base + version: "0.7.0" --- -# JFrog Platform Skill +# JFrog Skill -## MCP Server (Cursor) +The foundational skill for all JFrog agent interactions. Covers JFrog Platform concepts, `jf` CLI setup and authentication, and intent routing to workflow skills. -The JFrog MCP Server provides AI tools for Artifactory, Xray, Curation, and the JFrog Catalog directly inside Cursor. Auth is via **OAuth** — no API keys or tokens needed in Cursor. SaaS only. URL format: `https://.jfrog.io`. +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. -To enable: **Administration > General > Settings > MCP Server → ON** (admin required). +## Prerequisites -If MCP tools are unavailable: ask the user to enable the MCP Server. If unauthorized: restart Cursor to re-trigger OAuth. Fall back to REST API / CLI for operations not covered by MCP tools. +The following tools must be available on `PATH`: -## JFrog Catalog - -Global OSS intelligence database (12M+ packages). Provides vulnerability data, license info, and malicious package flags — independent of what your org stores in Artifactory. - -| | JFrog Catalog | Artifactory | -|---|---|---| -| **What** | Global OSS intelligence | Your org's private binary repos | -| **Answers** | "What's known about this package?" | "What do *we* use?" | - -**Query routing:** -- "Is X safe?" / "Vulnerabilities in X?" → Catalog (public intel) -- "Do we use X?" / "Versions in our repos?" → Artifactory (internal) -- "Are we exposed to CVE-X?" → Both: Catalog for vuln data, Artifactory for internal exposure -- Ambiguous ("check log4j") → full security assessment (see workflow below) - -Artifactory package tools are for **dependency analysis only**, not CI/CD build artifacts. - -## Supply Chain Flow - -``` -Public Registry (npm, PyPI, Maven Central...) - → JFrog Catalog (global OSS intelligence: vulns, licenses, malicious flags) - → JFrog Curation (gatekeeper: approved / blocked / inconclusive) - → Artifactory (your org's repos, used by your teams) - → JFrog Xray (continuous scanning of what's already inside) -``` - -Each layer serves a different purpose. When assessing risk, work top-down through this chain. - -## Security Assessment Workflows - -### Package Security Assessment - -**Trigger:** "is X safe?", "check package X", "should we use X?" - -Chain sequentially: -1. **Catalog metadata** — malicious flag? license type? If malicious, **STOP and warn**. -2. **Vulnerabilities** — severity breakdown for the target version (default: latest) -3. **Curation status** — approved / blocked / inconclusive -4. **Internal usage** — Artifactory query for versions and repos in use -5. **Synthesize** — risk summary: malicious status, license, vuln counts, curation decision, internal exposure - -### Vulnerability Investigation - -**Trigger:** "what is CVE-X?", "are we affected by CVE-X?" +| Tool | Purpose | +|------|---------| +| `jq` | JSON parsing of CLI and API output | -1. **CVE lookup** in Catalog — affected packages, versions, severity -2. **Internal exposure** — Artifactory query per affected package, cross-ref version ranges -3. **Report** — vulnerable repos + safe upgrade targets +All HTTP traffic to JFrog Platform APIs goes through the `jf` CLI itself +(`jf api`, see [Invoking platform APIs with `jf api`](#invoking-platform-apis-with-jf-api) below) — +no standalone `curl` is required for any JFrog interaction. -### DevSecOps Report +**Runtime permission for JFrog calls.** All `jf` calls that touch the network +need an outbound-HTTPS escalation from the agent runtime. The `~/.jfrog/` +credential save (`jf config add` during login) additionally needs a +filesystem-write escalation. -**Trigger:** "security report", "security posture", "how are we doing on security?" +| Runtime | Network | Network + `~/.jfrog/` write | +| ----------- | --------------------------------------------- | ------------------------------- | +| Cursor | `required_permissions: ["full_network"]` | `required_permissions: ["all"]` | +| Claude Code | `allowed-tools: Bash(jf:*)` + host allowlist | same + filesystem allowlist | +| Other | Configure at the runtime/sandbox layer | same | -1. Generate report via DevSecOps tools -2. Highlight critical/high CVEs, applicability status, trends -3. Summarize by severity with actionable next steps +If `jf` exits 1 with empty output, the runtime's network gate is the first +thing to check — re-run with the appropriate escalation above. -## Authentication +## Environment check -All JFrog REST API calls require authentication via the `Authorization` header: +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: -``` -Authorization: Bearer $JFROG_ACCESS_TOKEN +```bash +eval "$(JFROG_SKILL_MODEL="" bash /scripts/check-environment.sh)" ``` -When authentication is needed, follow the [login-flow.md](login-flow.md) procedure to resolve the active JFrog environment. The `jf` CLI is required and will be installed automatically if missing. The agent checks saved credentials via `jf config show` and asks which environment to use if multiple are saved. If none exist, the agent drives the web login flow and saves credentials via `jf config add`. +Set `JFROG_SKILL_MODEL` to the precise slug of the underlying LLM, with +version (e.g. `opus-4.7`, `sonnet-4.5`, `gpt-5-codex`, `gemini-2.5-pro`, +`composer-2-fast`, `composer-2.1-fast`). For Cursor's Composer family, the +product slug (`composer-2`, `composer-2-fast`, `composer-2.1-fast`, etc.) +IS the canonical identifier — use it as-is, do not fall back to `unknown` +just because there is no separate weights version. +**Do not** use harness/role names like `subagent`, `cursor-agent`, `agent`, +`assistant`, or a generic family name (`claude`, `gpt`). Subagents pass +through the parent's slug. If genuinely unknown, use `unknown`. + +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 `${JFROG_CLI_HOME_DIR:-$HOME/.jfrog}/skills-cache/jfrog-skill-state.json` +(co-located with `jf config`). 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 — proceed +- Exit 1: cache was stale and has been refreshed, CLI is ready — proceed +- Exit 2: `jf` is not installed — **STOP** (see below) +- Exit 3: `jf` is installed but below the minimum version required by this skill (the script prints the minimum and the detected version to stderr) — **STOP** (see below) + +Bypass the cache only when the user explicitly asks to install, upgrade, or +reconfigure the CLI. + +**On exit 2 or 3, stop and ask the user to install or upgrade.** Do not work +around it with `jf rt curl`, raw `curl`, or other fallbacks — see +`references/jfrog-cli-install-upgrade.md`. + +### JSON parsing (`jq`) + +Use **`jq`** for all JSON parsing of CLI and API output (pipes, `-r`, filters). + +## `~/.jfrog/skills-cache/` — allowed files only + +`${JFROG_CLI_HOME_DIR:-$HOME/.jfrog}/skills-cache/` is **not** a general scratch +or temp directory. Use it **only** for these two artifacts: + +1. **`jfrog-skill-state.json`** — written by `scripts/check-environment.sh` + (24-hour CLI check cache). +2. **`onemodel-schema-${JFROG_SERVER_ID}.graphql`** — cached OneModel supergraph + schema (see `references/onemodel-graphql.md`). + +**Do not** save HTTP response bodies, GraphQL query results, ad-hoc JSON, reports, +or any other temporary files under `skills-cache/`. Write those to a host temp +path instead (for example `/tmp/-$$.json` or `mktemp -d`), echo the path +when a follow-up Shell step must read the file — same pattern as *Preserving +command output* below. + +## Cautious execution + +Do not run commands speculatively. Before executing any JFrog CLI command or +API call: + +1. Confirm the operation is needed to fulfill the user's request. + If the request is ambiguous or could refer to multiple systems (e.g. + "builds" could mean Artifactory build-info or CI/CD pipeline runs), + **ask the user for clarification** instead of guessing. Never fetch data + from the wrong system — a wrong answer is worse than asking a question. +2. Resolve the target server using the **Server selection rules** below — + there must be no ambiguity about which server is used +3. For mutating operations (create, update, delete, upload), confirm with the + user unless the intent is clearly implied +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. -### Environment Variables +## Server selection rules (mandatory) -| Variable | Description | -|----------|-------------| -| `JFROG_URL` | JFrog instance hostname (no `https://`). Used in all REST API calls | -| `JFROG_ACCESS_TOKEN` | Access token for Bearer authentication | -| `JF_URL` | CLI-native alternative to `JFROG_URL` | -| `JF_ACCESS_TOKEN` | CLI-native alternative to `JFROG_ACCESS_TOKEN` | +Exactly one server must be resolved before any operation: -## Pre-flight Service Discovery +1. **User named specific server(s)** — use those only. Pass + `--server-id ` to every `jf` command. +2. **User did not name a server** — use the current default. `jf config show` + lists every server with a `Default: true/false` line; do **not** pre-filter + with `grep "Server ID"` — that drops the `Default` field and the first + listed server is not necessarily the default. One-liner: -Before calling a service other than Artifactory, verify it is available. See [preflight.md](preflight.md) for the full endpoint list. + ```bash + jf config show 2>/dev/null \ + | awk '/^Server ID:/{id=$NF} /^Default:[[:space:]]*true/{print id; exit}' + ``` -| Service | Ping Endpoint | Expected | -|---------|--------------|----------| -| Artifactory | `GET $JFROG_URL/artifactory/api/system/ping` | `OK` | -| Xray | `GET $JFROG_URL/xray/api/v1/system/ping` | HTTP 200 | -| Curation | `GET $JFROG_URL/curation/api/v1/system/ping` | HTTP 200 | -| Lifecycle | `GET $JFROG_URL/lifecycle/api/v2/promotion/records?limit=1` | HTTP 200 | -| AppTrust | `jf apptrust ping` | `OK` | + If nothing prints, stop and ask which server to use. +3. **Verify** the resolved server exists in `jf config show` before running. -If a service is unavailable, inform the user and stop -- do not attempt further calls to that service. +**Never fall back to a different server.** Different servers hold different +data and permissions — silent switches corrupt state and leak across +environments. On any error from the resolved server (401/403, network, +timeout, 404, missing server-id, etc.), stop with no further `jf` calls +and respond: + +> `` returned `` for ``: ``. +> Other configured server(s): ``. The rules forbid me from using +> them without your explicit instruction. How would you like to proceed? -## Platform Overview +## When to read reference files -| Service | Base URL | Purpose | -|---------|----------|---------| -| **Artifactory** | `$JFROG_URL/artifactory/api/...` | Repository and artifact management | -| **Xray** | `$JFROG_URL/xray/api/...` | Security scanning, policies, watches | -| **Access** | `$JFROG_URL/access/api/...` | Tokens, users, groups, permissions, projects | -| **Lifecycle** | `$JFROG_URL/lifecycle/api/...` | Release bundles, promotion | -| **Distribution** | `$JFROG_URL/distribution/api/...` | Distribute releases to edge nodes | -| **Evidence** | `$JFROG_URL/evidence/api/...` | Signed attestations (DSSE format) | -| **Curation** | `$JFROG_URL/curation/api/...` | Package firewall | -| **AppTrust** | `$JFROG_URL/apptrust/api/v1/...` | Application lifecycle management | -| **Runtime** | `$JFROG_URL/runtime/api/v1/...` | Kubernetes container monitoring | -| **Mission Control** | `$JFROG_URL/mc/api/v1/...` | Multi-JPD management | -| **Workers** | `$JFROG_URL/worker/api/...` | Serverless TypeScript functions | +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. -## Artifactory +### Cross-domain -Manages repositories, artifacts, builds, and search. For complete API coverage, see [artifactory-reference.md](artifactory-reference.md). +- **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` -### Repository Types +### Artifactory -| Type | Purpose | -|------|---------| -| **Local** | Store your own artifacts (1st-party binaries, builds) | -| **Remote** | Cache/proxy external registries (npm, Maven Central, Docker Hub) | -| **Virtual** | Single URL routing to multiple local & remote repos with priority order | -| **Federated** | Bi-directional mirror across JPDs | +- **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** use AQL with `limit`/`offset` — see § *Listing build names*; for **full build detail** use `GET /api/build//?project=` — see § *Retrieving full build info*) +- **AQL queries**: read `references/artifactory-aql-syntax.md` (~585 lines) +- **Artifactory REST beyond the CLI, structured JSON templates (replacing interactive wizards), or any Artifactory API gap**: read `references/artifactory-api-gaps.md` (~220 lines) -> **Virtual repo constraint:** `defaultDeploymentRepo` MUST be present in the `repositories` list before it can be set as the default. This is not enforced by the API schema — always validate before creation. +### Xray & security -### Quick Reference +- **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 -```bash -# List repos -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/artifactory/api/repositories" - -# Create local repo -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"my-docker-local","rclass":"local","packageType":"docker"}' \ - "$JFROG_URL/artifactory/api/repositories/my-docker-local" - -# Deploy artifact -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -T ./myapp-1.0.jar \ - "$JFROG_URL/artifactory/libs-release-local/com/example/myapp/1.0/myapp-1.0.jar" - -# Download artifact -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -O "$JFROG_URL/artifactory/libs-release-local/com/example/myapp/1.0/myapp-1.0.jar" - -# AQL search (see aql syntax in artifactory-reference.md) -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: text/plain" \ - -d 'items.find({"repo":"libs-release-local","name":{"$match":"*.jar"}})' \ - "$JFROG_URL/artifactory/api/search/aql" - -# Build info -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/artifactory/api/build/myapp/42" -``` +### Release lifecycle & distribution -For AQL syntax, package-type configs, replication, and federation, see [artifactory-reference.md](artifactory-reference.md) and [artifactory-packages-reference.md](artifactory-packages-reference.md). +- **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) -## Security (Xray) +### Platform administration -Scans artifacts for vulnerabilities, manages policies and watches. For complete API coverage, see [security-reference.md](security-reference.md). +- **Platform structure, project/repo membership, or project roles vs environments (concepts)**: read `references/platform-access-entities.md` +- **Access tokens, stats, projects, or system health**: read `references/platform-admin-operations.md` +- **Managing JFrog Projects, members, or environments**: read `references/projects-api.md` (~260 lines) +- **Platform REST beyond the CLI, or any platform-level API gap**: read `references/platform-admin-api-gaps.md` (~180 lines) + +### CLI setup & authentication -### Key Entities +- **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` -| Entity | Description | -|--------|-------------| -| **Policy** | Rules defining what constitutes a violation (security, license, or operational risk) | -| **Watch** | Links policies to resources (repos, builds, release bundles) to trigger scanning | -| **Violation** | A policy breach found during scanning | +### General patterns -### Quick Reference +- **Batching, parallel Shell calls, or launching subagents**: read `references/general-parallel-execution.md` (~135 lines) +- **Large or parallel data gathering, list-vs-detail APIs, cache hygiene**: read `references/general-bulk-operations-and-agent-patterns.md` +- **Standalone HTML report with JFrog-aligned styling**: read `references/jfrog-brand-html-report.md` +- **Reusable gotchas from past tasks**: read or extend `references/general-use-case-hints.md` -```bash -# Scan artifact for vulnerabilities -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"component_details": [{"component_id": "npm://lodash:4.17.20"}]}' \ - "$JFROG_URL/xray/api/v1/summary/component" - -# Create security policy -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "high-severity-block", - "type": "security", - "rules": [{"name": "block-critical", "criteria": {"min_severity": "Critical"}, "actions": {"block_download": {"active": true}, "fail_build": true}}] - }' \ - "$JFROG_URL/xray/api/v2/policies" - -# Create watch -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "general_data": {"name": "prod-watch", "active": true}, - "project_resources": {"resources": [{"type": "repository", "name": "libs-release-local"}]}, - "assigned_policies": [{"name": "high-severity-block", "type": "security"}] - }' \ - "$JFROG_URL/xray/api/v2/watches" -``` +## Server management -Advanced Security (JAS): Contextual Analysis, Secrets Detection, SAST, IaC Scanning. See [security-reference.md](security-reference.md). +Server configuration is always read live from `jf config` (never cached). -## Access +- **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) -Manages tokens, users, groups, permissions, and projects. For complete API coverage, see [access-reference.md](access-reference.md). +## Command discovery -### Quick Reference +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. -```bash -# Create scoped token -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"subject":"ci-bot","scope":"applied-permissions/groups:readers,deployers","expires_in":3600}' \ - "$JFROG_URL/access/api/v1/tokens" - -# Create user -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"username\":\"john\",\"email\":\"john@example.com\",\"password\":\"$USER_PASSWORD\",\"admin\":false}" \ - "$JFROG_URL/access/api/v2/users" - -# Create permission target -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "dev-repos-permission", - "resources": {"repository": {"include_patterns": ["**"], "actions": ["read","write","annotate"], "targets": [{"name": "libs-snapshot-local"}]}}, - "principals": {"groups": [{"name": "dev-team", "permissions": ["read","write","annotate"]}]} - }' \ - "$JFROG_URL/access/api/v2/permissions" - -# Create project -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"display_name":"My Application","project_key":"myapp"}' \ - "$JFROG_URL/access/api/v1/projects" -``` - -## Distribution & Release Lifecycle - -Manages release bundles, promotion through environments, distribution to edge nodes, and evidence. For complete API coverage, see [distribution-reference.md](distribution-reference.md). - -### Workflow - -``` -Build artifacts -> Create Release Bundle -> Promote DEV -> STAGING -> PROD -> Distribute to Edge -``` - -### Quick Reference - -```bash -# Create release bundle from build -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "release_bundle_name": "my-app-release", "release_bundle_version": "1.0.0", - "source_type": "builds", "source": {"builds": [{"build_name": "my-app", "build_number": "42"}]} - }' \ - "$JFROG_URL/lifecycle/api/v2/release_bundle" - -# Promote to staging -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"environment": "STAGING", "included_repository_keys": ["libs-release-local"]}' \ - "$JFROG_URL/lifecycle/api/v2/release_bundle/records/my-app-release/1.0.0/promote" - -# Distribute to edge nodes -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"distribution_rules": [{"site_name": "edge-us-east"}, {"site_name": "edge-eu-west"}]}' \ - "$JFROG_URL/distribution/api/v1/distribution/my-app-release/1.0.0" - -# Attach evidence (CLI recommended) -jf evd create --build-name=my-app --build-number=42 \ - --key "$PRIVATE_KEY" --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/signature/v1 -``` - -## Curation +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 -Package firewall that blocks risky OSS before it enters Artifactory. For complete API coverage, see [curation-reference.md](curation-reference.md). +### CLI namespaces -**Curation status values:** -- **approved** — safe to use -- **blocked** — rejected by policy; advise against use -- **inconclusive** — not yet evaluated; **do NOT treat as approved** +| 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 | -**License guidance:** Always surface the license type in package reports. Flag copyleft (GPL/AGPL) and unknown/missing licenses as risks. +> **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. -### Quick Reference +Top-level lifecycle commands (no namespace): `rbc`, `rbp`, `rbd`, `rba`, +`rbf`, `rbe`, `rbi`, `rbs`, `rbu`, `rbdell`, `rbdelr`. -```bash -# Create curation policy -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "block-malicious-and-critical", "enabled": true, - "conditions": [{"type": "malicious_package"}, {"type": "cvss_score", "min_severity": 9.0}], - "repositories": ["npm-remote", "pypi-remote"], "action": "block" - }' \ - "$JFROG_URL/curation/api/v1/policies" - -# Audit blocked packages -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/curation/api/v1/audit?repo=npm-remote&action=blocked&limit=50" - -# CLI: audit current project -jf curation-audit -``` +Top-level security commands: `audit`, `scan`, `build-scan`, `curation-audit`, +`sbom-enrich`. -## AppTrust +Top-level other: `access-token-create` (`atc`), `login`, `how`, `stats`, +`generate-summary-markdown`, `exchange-oidc-token`, `completion`. -Manages application entities, versions, lifecycle promotion, and package binding. For complete API coverage, see [apptrust-reference.md](apptrust-reference.md). +## Invoking platform APIs with `jf api` -### Quick Reference +When the CLI lacks a dedicated subcommand, use `jf api` — the unified entry +point for every JFrog Platform REST and GraphQL endpoint, auto-authenticated +against the resolved server. **Do not use `jf rt curl` or `jf xr curl`** — +they are superseded by `jf api`. -```bash -# Create application -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"application_key":"my-app","application_name":"My Application","project_key":"myproj","criticality":"high"}' | jq . - -# Create version from build -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"version":"1.0.0","sources":{"builds":[{"name":"my-app","number":"42"}]}}' | jq . - -# Promote version -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions/${VERSION}/promote" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"target_stage":"QA","promotion_type":"copy"}' | jq . - -# Release to production -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions/${VERSION}/release" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"promotion_type":"copy"}' | jq . -``` +### Product-prefix table -## Workers +`jf api` requires the **full** path including the product prefix; omitting it +returns 404. -Serverless TypeScript functions triggered by platform events or HTTP requests. For complete API coverage, see [workers-reference.md](workers-reference.md). +| Product | Path prefix | +|---------|-------------| +| Artifactory | `/artifactory/api/...` | +| Xray | `/xray/api/...` | +| Access (users, groups, tokens, permissions, projects) | `/access/api/...` | +| Evidence | `/evidence/api/...` | +| Release Lifecycle | `/lifecycle/api/...` | +| AppTrust | `/apptrust/api/...` | +| Distribution | `/distribution/api/...` | +| OneModel (GraphQL) | `/onemodel/api/v1/graphql`, `/onemodel/api/v1/supergraph/schema` | +| Mission Control | `/mc/api/...` | +| Curation | `/xray/api/v1/curation/...` (lives under Xray) | -### Quick Reference +### Examples ```bash -# Initialize worker scaffold -jf worker init my-worker --event BEFORE_DOWNLOAD +jf api /artifactory/api/repositories +jf api /artifactory/api/system/version --server-id -# Deploy worker -jf worker deploy my-worker - -# List workers -jf worker list - -# REST API: create worker -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d @manifest.json "$JFROG_URL/worker/api/v1/workers" +# AQL (POST with text/plain body) +jf api /artifactory/api/search/aql \ + -X POST -H "Content-Type: text/plain" -d '' ``` -For event types and TypeScript templates, see [workers-reference.md](workers-reference.md). - -## Runtime +Common flags: `-X/--method`, `-H/--header`, `-d/--data`, `--input `, +`--server-id`, `--timeout`. Body on stdout, status on stderr — see +[Gotchas](#gotchas). -Monitors running containers in Kubernetes clusters. For complete API coverage, see [runtime-reference.md](runtime-reference.md). +### GraphQL (OneModel) -### Quick Reference +OneModel is the unified GraphQL API. **Do not** embed the query inside a JSON +literal (`-d '{"query":"..."}'`) — escaping breaks requests. Build the payload +with `jq -n --arg`, pass it via `--input`, and save the response to a file +before running `jq` on it. ```bash -# List clusters -curl -s -X POST "$JFROG_URL/runtime/api/v1/clusters" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"limit": 50}' | jq . - -# List running images with vulnerability stats -curl -s -X GET "$JFROG_URL/runtime/api/v1/live/images?num_of_rows=100&statistics=true&timePeriod=now" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . +QUERY='{ evidence { searchEvidence(first: 5, where: { hasSubjectWith: { repositoryKey: "my-repo-local" } }) { totalCount } } }' +PAYLOAD=/tmp/onemodel-payload-$$.json RESPONSE=/tmp/onemodel-$$.json +jq -n --arg q "$QUERY" '{query:$q}' > "$PAYLOAD" +jf api /onemodel/api/v1/graphql -X POST \ + -H "Content-Type: application/json" --input "$PAYLOAD" > "$RESPONSE" +jq . "$RESPONSE" ``` -## Mission Control +Schema discovery: `jf api /onemodel/api/v1/supergraph/schema > "$SCHEMA_FILE"` +(store only under `~/.jfrog/skills-cache/`, never query responses). Read +`references/onemodel-graphql.md` for the full workflow (schema fetch, +validation, pagination, errors), plus `references/onemodel-query-examples.md` +and `references/onemodel-common-patterns.md` for query shapes, pagination, +variables, and dates. -Manages JFrog Platform Deployments (JPDs), licenses, and proxies. For complete API coverage, see [mission-control-reference.md](mission-control-reference.md). +## Structured inputs -### Quick Reference +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 -# List all JPDs -curl -s -X GET "$JFROG_URL/mc/api/v1/jpds" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . - -# Get JPD health -curl -s -X GET "$JFROG_URL/mc/api/v1/jpds/${JPD_ID}" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . +jf api /artifactory/api/repositories/ ``` -## CLI Quick Reference - -The JFrog CLI (`jf`) provides command-line access to all platform services. For complete command coverage, see [cli-reference.md](cli-reference.md). +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 + +- `jf api` requires the **product prefix** in the path (`/artifactory/...`, `/xray/...`, `/access/...`, `/evidence/...`, + `/lifecycle/...`, `/apptrust/...`, `/distribution/...`, `/onemodel/...`, + `/mc/...`). Omitting the prefix returns 404. See the + [product-prefix table](#product-prefix-table) above. +- `jf api` writes the body (success or error JSON) to **stdout** and + `[Info] Http Status: NNN` to **stderr** on every call; non-2xx also exits + 1 and adds `[Warn] jf api: returned NNN`. Pipe stdout to + `jq` directly; **never `2>&1 | jq`** — stderr corrupts the JSON. To keep + diagnostics: `jf api 2>/tmp/err-$$.log | jq .`. +- `jf api` has **no `-L`** (follow redirects) and **no `-o`** (output file). + Save bodies with shell redirection + (`jf api ... > /tmp/out-$$.json`); for + binary downloads through the Artifactory remote proxy prefer `jf rt dl`, + which handles the cache and redirect semantics natively. +- Remote repository content is stored in a `-cache` suffixed repo. Properties + and AQL queries for remote repo artifacts must target the cache repo. + Conversely, `/api/repositories/` only accepts the parent remote key + (without `-cache`) — strip the suffix for configuration lookups. +- **Do not use `jf rt search`** — always use a direct AQL query via + `jf api /artifactory/api/search/aql -X POST -H "Content-Type: text/plain" -d ''`. + See `references/artifactory-aql-syntax.md`. +- Use `--quiet` flag for non-interactive execution (suppresses confirmation + prompts). **Caution:** `--quiet` is not a global flag — commands that do not + support it (e.g. `jf rt s`, `jf rt ping`) will fail with misleading errors + like "Wrong number of arguments" or "flag provided but not defined". Check + `--help` for a command before adding `--quiet`. +- Use `--server-id` when targeting a non-default server. If a command fails + with `--server-id`, do not retry without it — that silently targets the + default server instead. See [Server selection rules](#server-selection-rules-mandatory). +- Never use interactive commands. All JFrog CLI operations must be performed + non-interactively. Known interactive commands to avoid: `jf config add`, + `jf login`, `jf rt repo-template`, `jf rt permission-target-template`, and + `jf rt replication-template`. For server setup, follow `references/jfrog-login-flow.md`. + For templates, use JSON schemas or REST API. If a command prompts for input + unexpectedly, find the non-interactive alternative via `--help` or REST API. +- `jf config export` output is base64-encoded JSON. Decode with + `base64 -d | jq` to extract fields. +- Build info lookups require a scope (`?buildRepo=` or `?project=`) — + resolve it before calling the API. See `references/artifactory-operations.md` + §Retrieving build info for the full workflow. +- If a `jf api` call returns 401, the configured token may have expired or + been rotated — ask the user to re-run the login flow (see + `references/jfrog-login-flow.md`) for the **same** server. If 403, the + token lacks required permissions. If 404, verify the endpoint path + (especially the product prefix) and target server version. On any of + these errors, do not try a different configured server as a workaround — + that targets a different environment. Report the error and ask the user. +- **Xray contextual analysis:** the summary artifact response has two + applicability fields — `applicability` (top-level, often null) and + `applicability_details` (always present with a `result` string). **Use + `applicability_details[].result` for counts and summaries.** Using the + top-level `applicability` field for aggregation produces wrong counts because + it is null when no scanner exists. See `references/xray-entities.md` + §Contextual analysis for the eight possible result values and jq snippets. +- **OneModel GraphQL:** always fetch the supergraph schema from the **same** + server you query before building operations (schemas differ by deployment); + cache, validate, and execute per `references/onemodel-graphql.md`. +- Never duplicate a network-fetching command to retry `jq` parsing — save the + response to a temp file first (see [Preserving command output](#preserving-command-output)). +- When collecting detail responses in a loop (e.g. per-repo GETs), validate + each body with `jq -e .` before appending to a results file. One non-JSON + or empty response corrupts a downstream `jq -s` slurp. Write validated + lines to an NDJSON file, then `jq -s '.' file.ndjson` to produce the final + array. See `references/general-bulk-operations-and-agent-patterns.md`. +- Accumulated edge cases from real tasks live in `references/general-use-case-hints.md` + — read when debugging odd failures; **append** a short entry when you confirm + a new, reusable gotcha. + +## Batch and parallel execution + +When a task requires multiple independent operations, use the lightest +parallelism mechanism that fits. Three tiers: (1) batch commands in a single +Shell call using loops or `&`, (2) issue parallel Shell tool calls, (3) launch +parallel subagents for large fan-out. Read `references/general-parallel-execution.md` +(~135 lines) for tier selection, examples, and subagent prompt structuring. + +## Preserving command output + +When a CLI command or API call returns data, redirect the output to a temporary +file so you can re-read it without re-executing the call: ```bash -# Install -brew install jfrog-cli # macOS -curl -fL https://install-cli.jfrog.io | sh # Linux - -# Artifact operations -jf rt upload "build/*.jar" libs-release-local/com/example/app/1.0/ -jf rt download "libs-release-local/com/example/app/1.0/*.jar" ./local/ -jf rt search "libs-release-local/com/example/**/*.jar" - -# Build integration -jf rt build-publish my-build 1 - -# Security scanning -jf audit # Scan project dependencies -jf scan ./myapp.jar # Scan a binary -jf docker scan myapp:1.0 # Scan Docker image - -# Release bundles -jf release-bundle-create my-bundle 1.0 --builds="my-build/1" --signing-key=mykey -jf release-bundle-promote my-bundle 1.0 --environment=PROD +OUT=/tmp/jf-repos-$$.json +jf api /artifactory/api/repositories > "$OUT" +echo "$OUT" ``` -## Patterns & Best Practices - -22 recommended architectural patterns across 6 categories. See [patterns-reference.md](patterns-reference.md) for the full catalog. - -| Category | Patterns | Reference | -|----------|----------|-----------| -| CI Integration | 4 patterns (SIMPLE to ADVANCED) | [patterns-ci-integration.md](patterns-ci-integration.md) | -| Repositories | 3 patterns (SIMPLE to ADVANCED) | [patterns-repositories.md](patterns-repositories.md) | -| Supply Chain Security | 4 patterns (INTERMEDIATE to ADVANCED) | [patterns-supply-chain-security.md](patterns-supply-chain-security.md) | -| Release Lifecycle | 4 patterns (SIMPLE to ADVANCED) | [patterns-release-lifecycle.md](patterns-release-lifecycle.md) | -| Multi-Site | 5 patterns (All ADVANCED) | [patterns-multi-site.md](patterns-multi-site.md) | -| AppTrust | 2 patterns (Both SIMPLE) | [patterns-apptrust.md](patterns-apptrust.md) | - -Use the 5 user journeys to pick the right patterns: [patterns-journeys.md](patterns-journeys.md). - -| If your goal is... | Start with... | -|---------------------|---------------| -| Centralize artifacts and automate CI/CD | CI Integration + Basic Repo Setup | -| Secure the software supply chain | Xray Security + Curation Security | -| Accelerate developer productivity | CI Integration + Curation + Contextual Analysis | -| Handle enterprise-scale multi-site | Multi-Site Active/Active or Active/Standby | -| Govern releases with compliance | Release Lifecycle + Evidence + AppTrust | - -## Flow Encouragement (Agent Behavior) - -Use [flow-suggestions.md](flow-suggestions.md) in **two situations**: - -### A. After completing an action - -Check whether the action is part of a larger pattern. If it is, **show progress and offer options** to continue: - -1. **Acknowledge first** -- confirm the action succeeded before suggesting anything. -2. **Always show the diagram** -- render the mermaid progress diagram so the user can see where they are in the pattern. Mark completed steps with `:::done` and the suggested next step with `:::next`. Prefer `flowchart LR` for simple sequential flows; use `flowchart TD` for branching architectures. -3. **Offer a selection** -- after the diagram, use the `AskQuestion` tool to present 2-3 options. The first option should be the natural next step. Include at least one alternative and always end with a "Something else" option. -4. **Never block** -- the suggestion goes at the end of your response, after the completed work. -5. **Context-aware** -- if the user already has the next piece in place, skip it and suggest the one after. - -### B. When the user is exploring - -If the user asks "what can I do?", "how do I get started?", or seems unsure -- use the **Getting Started** section of flow-suggestions.md. - -**Rules:** Respect the answer -- if the user declines, do not push the pattern again. Always show a mermaid diagram before offering options. - -## Parallelization - -Many JFrog operations are independent and can run concurrently: -- **Repository creation**: multiple repos can be created in parallel -- **User/group creation**: independent operations -- **Docker builds**: each `docker build` + `jf docker push` pair can run in parallel -- **Package binding** (AppTrust): bind calls are independent -- **Batch artifact uploads**: independent upload operations - -## Security Rules - -- **Never print, echo, or display tokens** in terminal output. Extract tokens silently into shell variables. -- **Never surface tokens in chat.** Use "authenticated successfully" -- never the token itself. -- **Quote all shell variables** (`"${VAR}"`, not `$VAR`). -- **Avoid shell interpolation for secrets.** Use quoted heredocs (`<< 'EOF'`). -- **`jf config` is the sole credential store.** Never store tokens in plaintext files. -- **Validate URLs** (ping endpoint) before authenticated API calls. -- **`JFROG_ACCESS_TOKEN` is sensitive** -- never use in echo/logging. - -## Response Guidelines - -- Include severity, affected versions, and upgrade targets for all vulnerability reports -- Always include license type in package reports; flag copyleft and unknown licenses as risks -- Chain tools sequentially without asking the user to wait between steps -- State clearly when results are empty or inconclusive — do not speculate -- Use tables for multi-item listings - -## Troubleshooting (MCP) - -- **Tools unavailable:** Admin must enable the MCP Server — Administration > General > Settings > MCP Server > ON. SaaS only. -- **Unauthorized:** Restart Cursor to re-trigger OAuth. Verify the JFrog URL and user permissions. -- **Empty results:** Verify package name and ecosystem. Check project/repo access. -- **Inconclusive curation:** Package not yet evaluated — advise checking later or escalating to a security admin. - -## Documentation - -- [JFrog Help Center](https://jfrog.com/help/home) -- [JFrog REST APIs](https://jfrog.com/help/r/jfrog-rest-apis) -- [Artifactory REST APIs](https://jfrog.com/help/r/jfrog-rest-apis/artifactory-rest-apis) -- [Xray REST APIs](https://jfrog.com/help/r/xray-rest-apis) -- [Distribution REST APIs](https://jfrog.com/help/r/jfrog-rest-apis/distribution-rest-apis) -- [AppTrust REST APIs](https://jfrog.com/help/r/jfrog-rest-apis/apptrust-rest-apis) -- [JFrog CLI](https://jfrog.com/help/r/jfrog-cli) -- [Repository Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/repository-management) -- [Release Lifecycle Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/release-lifecycle-management) -- [Xray User Guide](https://jfrog.com/help/r/jfrog-security-user-guide/products/xray) -- [Advanced Security](https://jfrog.com/help/r/jfrog-security-user-guide/products/advanced-security) -- [Curation](https://jfrog.com/help/r/jfrog-security-user-guide/products/curation) -- [Runtime Security](https://jfrog.com/help/r/jfrog-security-user-guide/products/runtime) -- [Workers](https://jfrog.com/help/r/jfrog-platform-administration-documentation/workers) -- [Mission Control](https://jfrog.com/help/r/jfrog-platform-administration-documentation/mission-control) -- [Projects](https://jfrog.com/help/r/jfrog-platform-administration-documentation/projects) -- [Access Federation](https://jfrog.com/help/r/jfrog-platform-administration-documentation/access-federation) -- [Evidence Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/evidence-management) -- [Build Integration](https://jfrog.com/help/r/jfrog-integrations-documentation/build-integration) +Use `$$` (the shell PID) in the filename to prevent collisions across +concurrent sessions or processes. + +**Cross-call gotcha:** each Shell tool invocation runs in a new process with a +different PID, so `$$` expands to a different value in each call. Always +**echo the expanded filename** so the agent can read it from the output and +reuse the literal path in subsequent calls. Three patterns, in priority order: + +1. **`$$` + echo** (preferred): use `$$` for collision safety, echo the path + as shown above. The agent reads `/tmp/jf-repos-12345.json` from the output + and passes that literal value to the next Shell call. +2. **Session ID**: when many files share a prefix across calls, generate an ID + once (`SID=$(date +%s)-$$`), echo it, and reuse in later calls. +3. **Hardcoded names**: last resort — risks collisions when parallel calls or + subagents write to the same path. + +This protects against wasted round-trips when you need to retry parsing — for +example, if a `jq` filter fails or you extract the wrong field on the first +attempt. Re-read the file instead of hitting the server again. + +Do **not** duplicate the same **network** request in a shell pipeline (e.g. with +`||`) only to re-run `jq` or to reveal jq diagnostics—the duplicate call +adds load on JFrog without fetching new data. Run +`jq '' /tmp/jf-*-$$.json` (or redirect stdin from the file) instead +of re-running the same `jf api` or other identical network-backed command. + +Do **not** reuse saved output across unrelated steps or changed contexts (different +server, user, or intent). The file is only valid for the immediate sequence of +operations that motivated the original call. diff --git a/plugins/jfrog/skills/jfrog/access-reference.md b/plugins/jfrog/skills/jfrog/access-reference.md deleted file mode 100644 index bf8a063..0000000 --- a/plugins/jfrog/skills/jfrog/access-reference.md +++ /dev/null @@ -1,321 +0,0 @@ -# Access Reference - -## Core Concepts - -| Concept | Description | -|---------|-------------| -| **Access Token** | JWT-based credential with optional scope, expiry, and subject. Preferred over API keys. | -| **Scoped Token** | Token limited to specific resources (repos, builds) and permissions | -| **User** | Individual identity with credentials | -| **Group** | Collection of users for bulk permission assignment | -| **Permission** | Maps actions (read, write, deploy, manage, etc.) to resources for users/groups | -| **Project** | Multi-tenant isolation unit grouping repos, builds, environments, and members | -| **Environment** | SDLC stage (DEV, STAGE, PROD) used for release lifecycle promotion | - -## Key API Operations - -### Tokens - -```bash -# Create short-lived, least-privilege token (preferred: scope to groups/perms, set expires_in) -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "subject": "ci-bot", - "scope": "applied-permissions/groups:readers,deployers", - "expires_in": 3600, - "refreshable": false, - "description": "CI pipeline token" - }' \ - "$JFROG_URL/access/api/v1/tokens" -# Avoid admin-scoped or non-expiring tokens (expires_in: 0) in production; use only when required and rotate. - -# List tokens -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/access/api/v1/tokens" - -# Revoke token -curl -X DELETE -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/access/api/v1/tokens/{token_id}" -``` - -### Users - -```bash -# Create user (set password via env or secret; never commit) -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"username\":\"john\",\"email\":\"john@example.com\",\"password\":\"$USER_PASSWORD\",\"admin\":false}" \ - "$JFROG_URL/access/api/v2/users" - -# Get user -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/access/api/v2/users/john" - -# List users -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/access/api/v2/users" - -# Delete user -curl -X DELETE -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/access/api/v2/users/john" -``` - -### Groups - -```bash -# Create group -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name":"dev-team","description":"Development team","members":["john","jane"]}' \ - "$JFROG_URL/access/api/v2/groups" - -# Add member to group -curl -X PATCH -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"add":["newuser"]}' \ - "$JFROG_URL/access/api/v2/groups/dev-team/members" -``` - -### Permissions - -```bash -# Create permission target -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "dev-repos-permission", - "resources": { - "repository": { - "include_patterns": ["**"], - "actions": ["read", "write", "annotate"], - "targets": [{"name": "libs-snapshot-local"}] - } - }, - "principals": { - "groups": [{"name": "dev-team", "permissions": ["read", "write", "annotate"]}] - } - }' \ - "$JFROG_URL/access/api/v2/permissions" -``` - -### Projects - -```bash -# Create project -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "display_name": "My Application", - "description": "Main application project", - "admin_privileges": {"manage_members": true, "manage_resources": true}, - "project_key": "myapp" - }' \ - "$JFROG_URL/access/api/v1/projects" - -# List projects -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/access/api/v1/projects" - -# Add member to project -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name":"john","roles":["Developer"]}' \ - "$JFROG_URL/access/api/v1/projects/myapp/users/john" - -# Get project environments -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/access/api/v1/projects/myapp/environments" -``` - -## Parallelization - -When creating multiple users, groups, or permission targets, run the calls in parallel. These are independent operations that do not depend on each other. For example, creating three team groups with their members can be done concurrently. - -## Access Federation - -Synchronize users, groups, permissions, and tokens across multiple JPDs. - -- Requires a **Circle of Trust** between JPDs -- Entities can be federated uni-directionally or bi-directionally -- Each JPD maintains its own Access service - -## Reference Files - -- [api-reference.md](api-reference.md) -- Complete Access REST API endpoint catalog - -# Access REST API Reference - -Base URL: `https://$JFROG_URL/access/api` - -Authentication: `Authorization: Bearer $JFROG_ACCESS_TOKEN` - -## Tokens - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/v1/tokens` | Create access token | -| GET | `/v1/tokens` | List tokens | -| GET | `/v1/tokens/{token_id}` | Get token details | -| DELETE | `/v1/tokens/{token_id}` | Revoke token | -| POST | `/v1/tokens/{token_id}/refresh` | Refresh token | - -### Create Token Body - -```json -{ - "subject": "ci-bot", - "scope": "applied-permissions/groups:readers,deployers", - "expires_in": 3600, - "refreshable": true, - "description": "CI pipeline token", - "audience": "*@*", - "include_reference_token": false -} -``` - -**Scope examples:** -- `applied-permissions/admin` -- full admin -- `applied-permissions/groups:readers` -- inherit readers group permissions -- `applied-permissions/groups:readers,deployers` -- multiple groups -- `applied-permissions/user` -- current user's permissions - -## Users - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/v2/users` | Create user | -| GET | `/v2/users` | List users | -| GET | `/v2/users/{username}` | Get user | -| PATCH | `/v2/users/{username}` | Update user | -| DELETE | `/v2/users/{username}` | Delete user | - -### Create User Body - -```json -{ - "username": "john", - "email": "john@example.com", - "password": "securePass123!", - "admin": false, - "profile_updatable": true, - "disable_ui_access": false, - "groups": ["dev-team"] -} -``` - -## Groups - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/v2/groups` | Create group | -| GET | `/v2/groups` | List groups | -| GET | `/v2/groups/{groupName}` | Get group | -| PATCH | `/v2/groups/{groupName}` | Update group | -| DELETE | `/v2/groups/{groupName}` | Delete group | -| GET | `/v2/groups/{groupName}/members` | List group members | -| PATCH | `/v2/groups/{groupName}/members` | Add/remove members | - -## Permissions - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/v2/permissions` | Create permission | -| GET | `/v2/permissions` | List permissions | -| GET | `/v2/permissions/{permissionName}` | Get permission | -| PUT | `/v2/permissions/{permissionName}` | Replace permission | -| PATCH | `/v2/permissions/{permissionName}` | Update permission | -| DELETE | `/v2/permissions/{permissionName}` | Delete permission | - -### Create Permission Body - -```json -{ - "name": "release-deployers", - "resources": { - "repository": { - "include_patterns": ["**"], - "exclude_patterns": [], - "actions": ["read", "write", "annotate", "delete"], - "targets": [ - {"name": "libs-release-local"}, - {"name": "docker-prod-local"} - ] - }, - "build": { - "include_patterns": ["**"], - "actions": ["read", "write", "manage"], - "targets": [ - {"name": "artifactory-build-info"} - ] - } - }, - "principals": { - "users": [ - {"name": "release-bot", "permissions": ["read", "write", "annotate"]} - ], - "groups": [ - {"name": "release-team", "permissions": ["read", "write", "annotate", "delete"]} - ] - } -} -``` - -**Available actions:** `read`, `write`, `annotate`, `delete`, `manage`, `managedXrayMeta`, `distribute` - -## Projects - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/v1/projects` | Create project | -| GET | `/v1/projects` | List projects | -| GET | `/v1/projects/{projectKey}` | Get project | -| PUT | `/v1/projects/{projectKey}` | Update project | -| DELETE | `/v1/projects/{projectKey}` | Delete project | -| PUT | `/v1/projects/{projectKey}/users/{username}` | Add/update project member | -| DELETE | `/v1/projects/{projectKey}/users/{username}` | Remove project member | -| PUT | `/v1/projects/{projectKey}/groups/{groupName}` | Add/update project group | -| GET | `/v1/projects/{projectKey}/roles` | List project roles | -| POST | `/v1/projects/{projectKey}/roles` | Create custom role | - -### Project Roles - -Built-in roles: `Project Admin`, `Developer`, `Release Manager`, `Viewer`, `Contributor` - -## Environments - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/v1/projects/{project_key}/environments` | List project environments (since 7.53.1) | - -**Response:** - -```json -[ - {"name": "DEV"}, - {"name": "STAGING"}, - {"name": "PROD"} -] -``` - -## Lifecycle Stages (via AppTrust) - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/v2/stages/` | Create lifecycle stage (since 7.125.4) | -| PUT | `/v2/stages/{stageId}` | Update stage | -| GET | `/v2/stages/` | List lifecycle stages | -| GET | `/v2/stages/{stageId}` | Get stage details | -| DELETE | `/v2/stages/{stageId}` | Delete stage | -| GET | `/v2/lifecycles/{lifecycleId}` | Get lifecycle | -| PUT | `/v2/lifecycles/{lifecycleId}` | Update lifecycle | - -## Federation - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/v1/federation/circle_of_trust` | Get circle of trust members | -| POST | `/v1/federation/circle_of_trust` | Add JPD to circle of trust | -| POST | `/v1/federation/full_sync` | Trigger full entity sync | - -## System - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/v1/system/ping` | Health check | -| GET | `/v1/system/version` | Access version | diff --git a/plugins/jfrog/skills/jfrog/apptrust-reference.md b/plugins/jfrog/skills/jfrog/apptrust-reference.md deleted file mode 100644 index 19e3a26..0000000 --- a/plugins/jfrog/skills/jfrog/apptrust-reference.md +++ /dev/null @@ -1,468 +0,0 @@ -# AppTrust Reference - -> **Pre-flight:** Before operations, verify AppTrust is available: `jf apptrust ping --server-id="$JFROG_SERVER_ID"` (expect `OK`). `JFROG_SERVER_ID` is extracted in Step 2 of [login-flow.md](login-flow.md). If unavailable, inform the user that AppTrust is not enabled on this instance and stop. - -> **Prerequisites:** Artifactory 7.125.0+, Xray 3.130.5+, Enterprise Plus license with AppTrust entitlement. - -## Core Concepts - -| Concept | Description | -|---------|-------------| -| **Application** | Logical entity representing a software product, with metadata like maturity, criticality, and ownership | -| **Application Version** | A specific release of an application, composed from artifacts, builds, or other versions | -| **Lifecycle Stage** | SDLC phase (DEV, QA, STAGING, PROD) that a version moves through | -| **Promotion** | Advancing a version from one stage to the next (copy, move, keep, or dry_run) | -| **Release** | Final promotion to the PROD stage | -| **Trusted Release** | Status earned when a version passes all policy gates across all stages | -| **Package Binding** | Linking a package version to an application for supply-chain traceability | - -## Application Operations - -### List Applications - -```bash -curl -s -X GET "$JFROG_URL/apptrust/api/v1/applications?project_key=$PROJECT_KEY" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -Query parameters: - -| Parameter | Description | -|-----------|-------------| -| `project_key` | Filter by project | -| `name` | Filter by application name | -| `maturity` | `unspecified`, `experimental`, `production`, `end_of_life` | -| `criticality` | `unspecified`, `low`, `medium`, `high`, `critical` | -| `owner` | Filter by owner (repeatable) | -| `label` | Filter by label as `key:value` (repeatable) | -| `order_by` | `name` or `created` (default: `created`) | -| `order_asc` | `true` or `false` (default: `false`) | -| `limit` | Max results (default: 100) | -| `offset` | Pagination offset (default: 0) | - -### Create Application - -```bash -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "application_key": "my-web-app", - "application_name": "My Web Application", - "project_key": "myproj", - "description": "Customer-facing web application", - "maturity_level": "production", - "criticality": "high", - "labels": {"environment": "production", "team": "platform"}, - "user_owners": ["admin", "devops-lead"], - "group_owners": ["platform-admins"] - }' | jq . -``` - -Required fields: `application_key`, `application_name`, `project_key`. - -### Get Application - -```bash -curl -s -X GET "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -### Update Application - -Uses `PATCH` — only send fields you want to change. Send empty arrays/objects to clear list fields. - -```bash -curl -s -X PATCH "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"maturity_level": "end_of_life", "criticality": "low"}' | jq . -``` - -### Delete Application - -```bash -curl -s -X DELETE "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" -``` - -## Application Version Operations - -### List Versions - -```bash -curl -s -X GET "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions?limit=25&offset=0" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -### Create Version - -At least one source (artifacts, builds, or existing versions) is required. - -**From builds:** - -```bash -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "version": "2.0.0", - "sources": { - "builds": [ - {"name": "my-app-build", "number": "42", "include_dependencies": true, "repository_key": "artifactory-build-info"} - ] - } - }' | jq . -``` - -**From artifacts:** - -```bash -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "version": "1.0.0", - "tag": "stable", - "sources": { - "artifacts": [ - {"path": "libs-release/com/example/app/1.0.0/app-1.0.0.jar", "sha256": "abc123..."} - ] - } - }' | jq . -``` - -**From existing application versions:** - -```bash -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "version": "3.0.0", - "sources": { - "versions": [ - {"application_key": "base-service", "version": "2.5.0"} - ] - } - }' | jq . -``` - -### Update Version - -```bash -curl -s -X PATCH "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions/${VERSION}" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"tag": "latest-stable", "properties": {"build.url": ["https://ci.example.com/42"]}}' | jq . -``` - -To remove properties, include `"delete_properties": ["key-to-remove"]`. - -### Delete Version - -```bash -curl -s -X DELETE "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions/${VERSION}" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" -``` - -## Version Lifecycle Operations - -### Promote Version - -Promote a version to a target lifecycle stage (e.g. QA, staging). - -```bash -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions/${VERSION}/promote" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "target_stage": "QA", - "promotion_type": "copy", - "included_repository_keys": ["libs-release-local"], - "excluded_repository_keys": [] - }' | jq . -``` - -`promotion_type` values: `move`, `copy` (default), `keep`, `dry_run`. - -### Release Version - -Release a version to the PROD stage (final promotion). - -```bash -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions/${VERSION}/release" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"promotion_type": "copy"}' | jq . -``` - -### Rollback Version - -Roll back a version from a lifecycle stage. - -```bash -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions/${VERSION}/rollback" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"from_stage": "QA"}' | jq . -``` - -### Get Version Status - -```bash -curl -s -X GET "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions/${VERSION}/status" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -Returns `release_status` (`pre_release`, `released`, `trusted_release`) and `current_stage`. - -### List Version Promotions - -```bash -curl -s -X GET "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/versions/${VERSION}/promotions?limit=25" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -## Package Binding Operations - -Bind package versions to applications for supply-chain traceability. A package version can only be bound to one application. - -### Bind Package - -```bash -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/packages" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"package_type": "maven", "package_name": "com.example:my-library", "package_version": "1.0.0"}' | jq . -``` - -### List Bound Packages - -```bash -curl -s -X GET "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/packages" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -### List Bound Package Versions - -```bash -curl -s -X GET "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/packages/${PKG_TYPE}/${PKG_NAME}" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -### Unbind Package Version - -```bash -curl -s -X DELETE "$JFROG_URL/apptrust/api/v1/applications/${APP_KEY}/packages/${PKG_TYPE}/${PKG_NAME}/${PKG_VERSION}" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" -``` - -## Parallelization - -When binding multiple packages to an application, the bind calls are independent and can run in parallel. When creating multiple applications (e.g., across different projects), those calls are also independent. Version creation depends on the application existing first, so sequence accordingly. - -## Common Workflows - -### Register and Release an Application - -```bash -# 1. Create app -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"application_key":"payments-svc","application_name":"Payments Service","project_key":"payments","criticality":"critical"}' | jq . - -# 2. Create version from build -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/payments-svc/versions" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"version":"1.0.0","sources":{"builds":[{"name":"payments-svc","number":"100"}]}}' | jq . - -# 3. Promote through stages -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/payments-svc/versions/1.0.0/promote" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"target_stage":"QA","promotion_type":"copy"}' | jq . - -# 4. Release to production -curl -s -X POST "$JFROG_URL/apptrust/api/v1/applications/payments-svc/versions/1.0.0/release" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"promotion_type":"copy"}' | jq . - -# 5. Verify status -curl -s -X GET "$JFROG_URL/apptrust/api/v1/applications/payments-svc/versions/1.0.0/status" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -### Audit Application Status - -```bash -curl -s -X GET "$JFROG_URL/apptrust/api/v1/applications/payments-svc/versions/1.0.0/promotions" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -For detailed field schemas, see [api-reference.md](api-reference.md). - -# AppTrust API Reference - -Base path: `/apptrust/api/v1/` - -## Applications - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/applications` | List applications (supports filtering & pagination) | -| POST | `/applications` | Create application | -| GET | `/applications/{key}` | Get application | -| PATCH | `/applications/{key}` | Update application (partial) | -| DELETE | `/applications/{key}` | Delete application | - -### Application Request Body - -```json -{ - "application_key": "string (required, unique)", - "application_name": "string (required)", - "project_key": "string (required)", - "description": "string", - "maturity_level": "unspecified | experimental | production | end_of_life", - "criticality": "unspecified | low | medium | high | critical", - "labels": {"key": "value"}, - "user_owners": ["username"], - "group_owners": ["group-name"] -} -``` - -### List Query Parameters - -| Parameter | Type | Description | -|-----------|------|-------------| -| `project_key` | string | Filter by project | -| `name` | string | Filter by name | -| `maturity` | string | Filter by maturity level | -| `criticality` | string | Filter by criticality | -| `owner` | string | Filter by owner (repeatable) | -| `label` | string | Filter by label as `key:value` (repeatable) | -| `order_by` | string | `name` or `created` (default: `created`) | -| `order_asc` | boolean | Sort ascending (default: false) | -| `limit` | integer | Max results (default: 100) | -| `offset` | integer | Pagination offset (default: 0) | - -## Application Versions - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/applications/{key}/versions` | List versions | -| POST | `/applications/{key}/versions` | Create version | -| PATCH | `/applications/{key}/versions/{version}` | Update version | -| DELETE | `/applications/{key}/versions/{version}` | Delete version | - -### Version Request Body - -```json -{ - "version": "string (required, semver)", - "tag": "string", - "sources": { - "artifacts": [ - {"path": "repo/path/to/file", "sha256": "checksum"} - ], - "builds": [ - { - "name": "build-name", - "number": "build-number", - "build_started": "ISO 8601 (optional)", - "build_repository": "artifactory-build-info (default)", - "include_dependencies": false - } - ], - "versions": [ - {"application_key": "other-app", "version": "1.0.0"} - ] - } -} -``` - -At least one source type (artifacts, builds, or versions) is required. - -### Version Response - -```json -{ - "version": "1.0.0", - "tag": "stable", - "release_status": "pre_release | released | trusted_release", - "current_stage": "QA", - "created_by": "admin", - "created": "2025-01-15T10:00:00Z" -} -``` - -## Lifecycle Operations - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/applications/{key}/versions/{version}/promote` | Promote version to stage | -| POST | `/applications/{key}/versions/{version}/release` | Release version to PROD | -| POST | `/applications/{key}/versions/{version}/rollback` | Rollback from stage | -| GET | `/applications/{key}/versions/{version}/status` | Get version status | -| GET | `/applications/{key}/versions/{version}/promotions` | List promotions | - -### Promote Request Body - -```json -{ - "target_stage": "string (required, e.g. QA, STAGING)", - "promotion_type": "copy | move | keep | dry_run (default: copy)", - "included_repository_keys": ["repo-key"], - "excluded_repository_keys": ["repo-key"] -} -``` - -### Release Request Body - -```json -{ - "promotion_type": "copy | move | keep | dry_run (default: copy)" -} -``` - -### Rollback Request Body - -```json -{ - "from_stage": "string (required, stage to roll back from)" -} -``` - -### Status Response - -```json -{ - "release_status": "pre_release | released | trusted_release", - "current_stage": "PROD" -} -``` - -## Package Bindings - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/applications/{key}/packages` | Bind package to application | -| GET | `/applications/{key}/packages` | List bound packages | -| GET | `/applications/{key}/packages/{type}/{name}` | List bound package versions | -| DELETE | `/applications/{key}/packages/{type}/{name}/{version}` | Unbind package version | - -### Bind Package Request Body - -```json -{ - "package_type": "maven | npm | docker | pypi | go | ...", - "package_name": "com.example:my-library", - "package_version": "1.0.0" -} -``` - -A package version can only be bound to one application at a time. diff --git a/plugins/jfrog/skills/jfrog/artifactory-packages-reference.md b/plugins/jfrog/skills/jfrog/artifactory-packages-reference.md deleted file mode 100644 index 0aa50ef..0000000 --- a/plugins/jfrog/skills/jfrog/artifactory-packages-reference.md +++ /dev/null @@ -1,260 +0,0 @@ -# Artifactory Package Types Reference - -Artifactory supports 40+ package types. Below are the most common with their repository configurations. - -## Docker - -```json -{ - "key": "docker-local", - "rclass": "local", - "packageType": "docker", - "dockerApiVersion": "V2", - "maxUniqueTags": 0 -} -``` - -Remote URL: `https://registry-1.docker.io/` - -CLI: `jf docker push/pull`, `jf rt build-docker-create` - -## Maven - -```json -{ - "key": "libs-release-local", - "rclass": "local", - "packageType": "maven", - "handleReleases": true, - "handleSnapshots": false, - "checksumPolicyType": "client-checksums", - "snapshotVersionBehavior": "unique", - "suppressPomConsistencyChecks": false -} -``` - -Remote URL: `https://repo.maven.apache.org/maven2` - -CLI: `jf mvn`, `jf mvnc` (config) - -## npm - -```json -{ - "key": "npm-local", - "rclass": "local", - "packageType": "npm" -} -``` - -Remote URL: `https://registry.npmjs.org` - -CLI: `jf npm install/publish/ci`, `jf npmc` (config) - -## PyPI - -```json -{ - "key": "pypi-local", - "rclass": "local", - "packageType": "pypi" -} -``` - -Remote URL: `https://files.pythonhosted.org` - -Registry URL: `https://pypi.org` - -CLI: `jf pip install`, `jf pipenv install`, `jf pipc` (config) - -## Go - -```json -{ - "key": "go-local", - "rclass": "local", - "packageType": "go", - "externalDependenciesEnabled": false -} -``` - -Remote URL: `https://proxy.golang.org/` - -CLI: `jf go build/publish`, `jf goc` (config) - -## Helm - -```json -{ - "key": "helm-local", - "rclass": "local", - "packageType": "helm" -} -``` - -Remote URL: `https://charts.helm.sh/stable` (or custom chart repo) - -CLI: `jf rt upload *.tgz helm-local/` - -## NuGet - -```json -{ - "key": "nuget-local", - "rclass": "local", - "packageType": "nuget", - "forceNugetAuthentication": true -} -``` - -Remote URL: `https://www.nuget.org/api/v2` (V2) or `https://api.nuget.org/v3/index.json` (V3) - -CLI: `jf nuget`, `jf nugetc` (config), `jf dotnet` - -## Gradle - -Uses Maven repo type with Gradle-specific layout. - -CLI: `jf gradle`, `jf gradlec` (config) - -## Generic - -```json -{ - "key": "generic-local", - "rclass": "local", - "packageType": "generic" -} -``` - -For any file type not covered by a specific package type. - -CLI: `jf rt upload/download` - -## Terraform - -```json -{ - "key": "terraform-local", - "rclass": "local", - "packageType": "terraform" -} -``` - -Remote URL: `https://registry.terraform.io/` - -CLI: `jf terraform publish/config` - -## Cargo (Rust) - -```json -{ - "key": "cargo-local", - "rclass": "local", - "packageType": "cargo", - "cargoInternalIndex": true -} -``` - -Remote URL: `https://github.com/rust-lang/crates.io-index` - -## OCI - -```json -{ - "key": "oci-local", - "rclass": "local", - "packageType": "oci" -} -``` - -For OCI-compliant container images and artifacts. - -## Debian - -```json -{ - "key": "debian-local", - "rclass": "local", - "packageType": "debian", - "debianTrivialLayout": false -} -``` - -Deploy with layout metadata: - -```bash -PUT /debian-local/pool/my-package.deb;deb.distribution=focal;deb.component=main;deb.architecture=amd64 -``` - -## RPM - -```json -{ - "key": "rpm-local", - "rclass": "local", - "packageType": "rpm", - "yumRootDepth": 0, - "calculateYumMetadata": true -} -``` - -## Alpine - -```json -{ - "key": "alpine-local", - "rclass": "local", - "packageType": "alpine" -} -``` - -## Conan (C/C++) - -```json -{ - "key": "conan-local", - "rclass": "local", - "packageType": "conan" -} -``` - -Remote URL: `https://center.conan.io` - -## Swift - -```json -{ - "key": "swift-local", - "rclass": "local", - "packageType": "swift" -} -``` - -## Pub (Dart/Flutter) - -```json -{ - "key": "pub-local", - "rclass": "local", - "packageType": "pub" -} -``` - -Remote URL: `https://pub.dev` - -## Virtual Repository Pattern - -For any package type, the virtual repo aggregates local + remote: - -```json -{ - "key": "{type}-virtual", - "rclass": "virtual", - "packageType": "{type}", - "repositories": ["{type}-local", "{type}-remote"], - "defaultDeploymentRepo": "{type}-local" -} -``` - -Resolution order: repos are tried in array order. First match wins. diff --git a/plugins/jfrog/skills/jfrog/artifactory-reference.md b/plugins/jfrog/skills/jfrog/artifactory-reference.md deleted file mode 100644 index 5cf0c32..0000000 --- a/plugins/jfrog/skills/jfrog/artifactory-reference.md +++ /dev/null @@ -1,520 +0,0 @@ -# Artifactory Reference - -## Core Concepts - -### Repository Types - -| Type | Purpose | Example | -|------|---------|---------| -| **Local** | Store your own artifacts (1st-party binaries, builds) | `libs-release-local` | -| **Remote** | Cache/proxy external registries (npm, Maven Central, Docker Hub) | `npm-remote` | -| **Virtual** | Single URL that routes to multiple local & remote repos with priority order | `npm` | -| **Federated** | Bi-directional mirror across JFrog Platform Deployments (JPDs) | `shared-docker-federated` | - -### Build Info - -Structured metadata collected by JFrog CLI during CI. Contains: build name/number, artifacts produced, dependencies consumed, environment variables, VCS info. Published with `jf rt build-publish`. Enables: Xray scanning of builds, promotion, release bundle creation. - -### Package Types - -Artifactory supports 40+ package types. See [package-types-reference.md](package-types-reference.md) for repo config per type. - -## Key API Operations - -### Repository Management - -```bash -# List all repos -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/artifactory/api/repositories" - -# Create a local repo -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"my-docker-local","rclass":"local","packageType":"docker"}' \ - "$JFROG_URL/artifactory/api/repositories/my-docker-local" - -# Create a remote repo (proxy Docker Hub) -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"docker-remote","rclass":"remote","packageType":"docker","url":"https://registry-1.docker.io/"}' \ - "$JFROG_URL/artifactory/api/repositories/docker-remote" - -# Create a virtual repo -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"docker","rclass":"virtual","packageType":"docker","repositories":["my-docker-local","docker-remote"],"defaultDeploymentRepo":"my-docker-local"}' \ - "$JFROG_URL/artifactory/api/repositories/docker" -``` - -### Artifact Operations - -```bash -# Deploy (upload) an artifact -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -T ./myapp-1.0.jar \ - "$JFROG_URL/artifactory/libs-release-local/com/example/myapp/1.0/myapp-1.0.jar" - -# Download an artifact -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -O "$JFROG_URL/artifactory/libs-release-local/com/example/myapp/1.0/myapp-1.0.jar" - -# Get file info -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/artifactory/api/storage/libs-release-local/com/example/myapp/1.0/myapp-1.0.jar" - -# Set properties on an artifact -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/artifactory/api/storage/libs-release-local/com/example/myapp/1.0/myapp-1.0.jar?properties=build.name=myapp;build.number=42" - -# Delete an artifact -curl -X DELETE -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/artifactory/libs-release-local/com/example/myapp/1.0/myapp-1.0.jar" -``` - -### Search - -```bash -# Quick search by name -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/artifactory/api/search/artifact?name=myapp&repos=libs-release-local" - -# GAVC search (Maven coordinates) -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/artifactory/api/search/gavc?g=com.example&a=myapp&v=1.0" - -# Property search -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/artifactory/api/search/prop?build.name=myapp&repos=libs-release-local" -``` - -For complex queries use **AQL** -- see the AQL Reference section below. - -### Build Info - -```bash -# Get build info -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/artifactory/api/build/myapp/42" - -# Delete build -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"buildName":"myapp","buildNumbers":["42"],"deleteAll":false}' \ - "$JFROG_URL/artifactory/api/build/delete" - -# Promote build (move artifacts between repos) -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"status":"released","targetRepo":"libs-release-local","copy":false}' \ - "$JFROG_URL/artifactory/api/build/promote/myapp/42" -``` - -### System - -```bash -# System health check -curl "$JFROG_URL/artifactory/api/system/ping" - -# Get version -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/artifactory/api/system/version" - -# Storage summary -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/artifactory/api/storageinfo" -``` - -## Parallelization - -When creating multiple repositories (e.g., per-environment or per-team), run the creation calls in parallel using concurrent subagents or background shell jobs. Repository creation calls are independent and do not depend on each other. The same applies to batch artifact uploads and property-setting operations. - -## Replication - -- **Push replication**: pushes artifacts from local repo to another Artifactory instance -- **Pull replication**: pulls artifacts from a remote Artifactory into a local repo -- **Event-based replication**: triggers on artifact deploy/delete (real-time sync) -- **Cron-based replication**: scheduled sync - -```bash -# Create push replication (use token or credentials for the target server) -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"url":"https:///artifactory/libs-release-local","username":"$TARGET_USER","password":"$TARGET_TOKEN","enabled":true,"cronExp":"0 0 * * * ?","enableEventReplication":true}' \ - "$JFROG_URL/artifactory/api/replications/libs-release-local" -``` - -## Federation - -Federated repositories are mirrored across multiple JPDs with full bi-directional sync. All members are equal peers. - -```bash -# Convert local repo to federated -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - "$JFROG_URL/artifactory/api/federation/migrate/libs-release-local" -``` - ---- - -# Artifactory REST API Reference - -Base URL: `https://$JFROG_URL/artifactory/api` - -Authentication: `Authorization: Bearer $JFROG_ACCESS_TOKEN` - -## System - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/system/ping` | Health check (no auth needed) | -| GET | `/system/version` | Artifactory version info | -| GET | `/system/configuration` | Full system YAML configuration | -| PATCH | `/system/configuration` | Update system configuration (YAML body) | -| GET | `/storageinfo` | Storage summary (binaries count, size, repos) | -| POST | `/system/storage/optimize` | Run storage garbage collection | - -## Repositories - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/repositories` | List all repositories (filter: `?type=local\|remote\|virtual\|federated&packageType=docker`) | -| GET | `/repositories/{repoKey}` | Get repo configuration | -| PUT | `/repositories/{repoKey}` | Create repository (JSON body with `key`, `rclass`, `packageType`) | -| POST | `/repositories/{repoKey}` | Update repository configuration | -| DELETE | `/repositories/{repoKey}` | Delete repository | -| POST | `/repositories/calculateYumMetadata` | Calculate YUM metadata | - -### Create Repository Body (key fields) - -```json -{ - "key": "my-repo", - "rclass": "local|remote|virtual|federated", - "packageType": "generic|docker|maven|npm|pypi|go|helm|...", - "description": "My repository", - "url": "https://registry-1.docker.io/", // remote only - "repositories": ["local-1", "remote-1"], // virtual only - "defaultDeploymentRepo": "local-1", // virtual only - "members": [{"url":"https://other.jfrog.io/artifactory/my-repo","enabled":true}] // federated only -} -``` - -## Artifacts -- Deploy & Download - -| Method | Endpoint | Description | -|--------|----------|-------------| -| PUT | `/{repoKey}/{path}` | Deploy artifact (file upload) | -| GET | `/{repoKey}/{path}` | Download artifact | -| HEAD | `/{repoKey}/{path}` | Check artifact exists | -| DELETE | `/{repoKey}/{path}` | Delete artifact | -| POST | `/copy/{srcRepoKey}/{srcPath}?to=/{dstRepoKey}/{dstPath}` | Copy artifact | -| POST | `/move/{srcRepoKey}/{srcPath}?to=/{dstRepoKey}/{dstPath}` | Move artifact | - -### Deploy with Properties - -```bash -PUT /{repoKey}/{path};prop1=value1;prop2=value2 -``` - -### Deploy with Checksum - -```bash -PUT /{repoKey}/{path} -X-Checksum-Sha1: -X-Checksum-Sha256: -X-Checksum-Deploy: true -``` - -## Artifacts -- File Info & Properties - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/storage/{repoKey}/{path}` | File/folder info (size, checksums, created/modified dates) | -| GET | `/storage/{repoKey}/{path}?properties` | Get item properties | -| PUT | `/storage/{repoKey}/{path}?properties=key1=val1;key2=val2` | Set item properties | -| PATCH | `/metadata/{repoKey}/{path}` | Update item properties (merge) | -| DELETE | `/storage/{repoKey}/{path}?properties=key1,key2` | Delete item properties | -| GET | `/storage/{repoKey}/{path}?list&deep=1` | List folder contents recursively | -| GET | `/storage/{repoKey}/{path}?stats` | Get download statistics | -| POST | `/checksum/sha256` | Calculate SHA-256 for deployed artifact | - -## Search - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/search/artifact?name={name}&repos={repos}` | Quick search by filename | -| GET | `/search/gavc?g={group}&a={artifact}&v={version}&c={classifier}` | Maven GAVC search | -| GET | `/search/prop?key1=val1&repos={repos}` | Property search | -| GET | `/search/checksum?sha1={sha1}` | Checksum search (sha1, sha256, md5) | -| GET | `/search/dates?from={timestamp}&to={timestamp}&repos={repos}` | Date range search (created/modified) | -| GET | `/search/usage?notUsedSince={timestamp}&repos={repos}` | Find artifacts not downloaded since date | -| GET | `/search/creation?from={timestamp}&to={timestamp}&repos={repos}` | Find artifacts created in date range | -| POST | `/search/aql` | AQL query (see AQL Reference section below) | - -## Builds - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/build` | List all builds | -| GET | `/build/{buildName}` | List build runs | -| GET | `/build/{buildName}/{buildNumber}` | Get build info | -| PUT | `/build` | Upload build info (JSON body) | -| POST | `/build/promote/{buildName}/{buildNumber}` | Promote build | -| POST | `/build/delete` | Delete builds | -| GET | `/build/{buildName}/{buildNumber}?diff={otherNumber}` | Diff two builds | -| POST | `/build/rename/{buildName}?to={newName}` | Rename build | - -### Promote Build Body - -```json -{ - "status": "released", - "comment": "Promoted to release", - "ciUser": "ci-bot", - "targetRepo": "libs-release-local", - "sourceRepo": "libs-snapshot-local", - "copy": false, - "artifacts": true, - "dependencies": false, - "failFast": true -} -``` - -## Replication - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/replications/{repoKey}` | Get replication config | -| PUT | `/replications/{repoKey}` | Create/replace replication | -| POST | `/replications/{repoKey}` | Update replication | -| DELETE | `/replications/{repoKey}` | Delete replication | -| POST | `/replication/execute/{repoKey}` | Trigger replication now | - -## Federation - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/federation/migrate/{repoKey}` | Convert local repo to federated | -| POST | `/federation/fullSync/{repoKey}` | Force full sync of federated repo | -| GET | `/federation/status/{repoKey}` | Get federation sync status | -| POST | `/federation/configSync` | Sync all federated repo configs | - -## Support Bundles - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/system/support/bundle` | Create support bundle | -| GET | `/system/support/bundle/{bundleId}` | Get support bundle status | -| GET | `/system/support/bundle/{bundleId}/archive` | Download support bundle | - -## Docker-Specific - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/docker/{repoKey}/v2/_catalog` | List Docker repositories | -| GET | `/docker/{repoKey}/v2/{image}/tags/list` | List image tags | -| POST | `/docker/{repoKey}/v2/promote` | Promote Docker image between repos | -| DELETE | `/docker/{repoKey}/v2/{image}/manifests/{tag}` | Delete Docker tag | - -## Tokens (Legacy -- prefer Access API) - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/security/token` | Create token | -| POST | `/security/token/revoke` | Revoke token | -| GET | `/security/apiKey` | Get API key | - ---- - -# Artifactory Query Language (AQL) Reference - -AQL is Artifactory's flexible search language for querying artifacts, builds, and properties. - -## Usage - -```bash -POST /artifactory/api/search/aql -Content-Type: text/plain - -items.find({"repo":"libs-release-local","name":{"$match":"*.jar"}}) -``` - -## Syntax - -``` -.find() - .include() - .sort() - .offset() - .limit() -``` - -## Domains - -| Domain | Description | -|--------|-------------| -| `items` | Artifacts (files and folders) | -| `builds` | Build records | -| `entries` | Archive entries (files inside zip/jar) | -| `properties` | Item properties | -| `statistics` | Download stats | -| `modules` | Build modules | -| `releases` | Release bundles | - -## Criteria Operators - -| Operator | Description | Example | -|----------|-------------|---------| -| `$eq` | Equals (default) | `{"name":"app.jar"}` | -| `$ne` | Not equals | `{"name":{"$ne":"test.jar"}}` | -| `$gt` | Greater than | `{"size":{"$gt":1000000}}` | -| `$gte` | Greater than or equal | `{"created":{"$gte":"2024-01-01"}}` | -| `$lt` | Less than | `{"size":{"$lt":5000}}` | -| `$lte` | Less than or equal | | -| `$match` | Wildcard match (`*` and `?`) | `{"name":{"$match":"*.jar"}}` | -| `$nmatch` | Wildcard not match | `{"name":{"$nmatch":"test*"}}` | - -## Logical Operators - -``` -// AND (default when multiple criteria) -items.find({"repo":"my-repo","name":{"$match":"*.jar"}}) - -// OR -items.find({"$or":[{"repo":"repo-a"},{"repo":"repo-b"}]}) - -// AND explicit -items.find({"$and":[{"size":{"$gt":1000}},{"size":{"$lt":100000}}]}) -``` - -## Fields - -### Item Fields - -| Field | Type | Description | -|-------|------|-------------| -| `repo` | string | Repository key | -| `path` | string | Path within repo | -| `name` | string | Filename | -| `type` | string | `file` or `folder` | -| `size` | long | File size in bytes | -| `created` | date | Creation timestamp | -| `created_by` | string | User who created | -| `modified` | date | Last modification | -| `modified_by` | string | User who modified | -| `updated` | date | Last DB update | -| `depth` | int | Path depth | -| `original_md5` | string | Original MD5 checksum | -| `actual_md5` | string | Actual MD5 checksum | -| `original_sha1` | string | Original SHA-1 | -| `actual_sha1` | string | Actual SHA-1 | -| `sha256` | string | SHA-256 checksum | - -### Cross-Domain Fields - -Access related domains using dot notation: - -``` -// Find items with specific property -items.find({"@build.name":"my-build"}) - -// Find items from a build -items.find({"artifact.module.build.name":"my-build","artifact.module.build.number":"42"}) - -// Find items with download stats -items.find({"stat.downloads":{"$gt":100}}) -``` - -## Include - -Specify which fields to return: - -``` -items.find({"repo":"my-repo"}) - .include("name","repo","path","size","sha256") -``` - -Include related domain data: - -``` -items.find({"repo":"my-repo"}) - .include("name","property.*","stat.*") -``` - -## Sort & Pagination - -``` -items.find({"repo":"my-repo"}) - .sort({"$desc":["size"]}) - .offset(0) - .limit(100) -``` - -## Common Examples - -### Find large artifacts - -``` -items.find({ - "repo":"libs-release-local", - "size":{"$gt":104857600} -}).include("name","path","size") - .sort({"$desc":["size"]}) - .limit(20) -``` - -### Find artifacts not downloaded in 90 days - -``` -items.find({ - "repo":"libs-release-local", - "stat.downloaded":{"$lt":"2024-01-01"} -}).include("name","path","size","stat.downloaded") -``` - -### Find artifacts by build - -``` -items.find({ - "artifact.module.build.name":"my-app", - "artifact.module.build.number":"42" -}).include("name","repo","path","sha256") -``` - -### Find Docker images by property - -``` -items.find({ - "repo":"docker-local", - "type":"file", - "name":"manifest.json", - "@docker.repoName":{"$match":"my-app*"} -}).include("name","path","@docker.repoName","@docker.manifest") -``` - -### Find artifacts created this week - -``` -items.find({ - "created":{"$gte":"2024-06-01"}, - "type":"file" -}).include("name","repo","path","created","size") - .sort({"$desc":["created"]}) - .limit(50) -``` - -### Find artifacts with specific properties - -``` -items.find({ - "repo":"libs-release-local", - "@release.status":"approved", - "@qa.passed":"true" -}).include("name","path","@release.status","@qa.passed") -``` - -## Performance Tips - -- Always specify `repo` in criteria to avoid full-table scans -- Use `limit` to cap results -- Use `include` to return only needed fields -- Index-backed fields: `repo`, `path`, `name`, `type`, `created`, `modified`, checksums -- Property queries (`@key`) are efficient when combined with repo filter diff --git a/plugins/jfrog/skills/jfrog/cli-reference.md b/plugins/jfrog/skills/jfrog/cli-reference.md deleted file mode 100644 index 4cbfd72..0000000 --- a/plugins/jfrog/skills/jfrog/cli-reference.md +++ /dev/null @@ -1,647 +0,0 @@ -# CLI Reference - -## Installation - -```bash -# macOS -brew install jfrog-cli - -# Linux (curl) — runs remote script; for production prefer package manager or verify script integrity -curl -fL https://install-cli.jfrog.io | sh - -# Docker -docker run releases-docker.jfrog.io/jfrog/jfrog-cli jf --version -``` - -Requires JFrog CLI v2+ (all commands use `jf` prefix). - -## Configuration - -```bash -# List configurations -jf config show - -# Set default server (if multiple configured) -jf config use my-server - -# Add server configuration (non-interactive, using env vars) -jf config add my-server \ - --url=https://$JFROG_URL \ - --access-token=$JFROG_ACCESS_TOKEN \ - --interactive=false - -# Export/import config (for CI). Never commit the export file; add it to .gitignore. -jf config export my-server > jf-config.export -jf config import jf-config.export -``` - -### Environment Variables - -| Variable | Description | -|----------|-------------| -| `JFROG_URL` | JFrog instance hostname (no `https://`). Used across all JFrog skills | -| `JFROG_ACCESS_TOKEN` | Access token. Used across all JFrog skills and for direct REST API calls | -| `JF_URL` | JFrog Platform URL (CLI-native alternative to `JFROG_URL`) | -| `JF_ACCESS_TOKEN` | Access token (CLI-native alternative to `JFROG_ACCESS_TOKEN`) | -| `JF_USER` / `JF_PASSWORD` | Basic auth credentials | -| `JFROG_CLI_BUILD_NAME` | Default build name | -| `JFROG_CLI_BUILD_NUMBER` | Default build number | -| `JFROG_CLI_BUILD_PROJECT` | Default project key | - -## File Specs - -JSON format for specifying upload/download/search patterns: - -```json -{ - "files": [ - { - "pattern": "libs-release-local/com/example/(*)/(*).jar", - "target": "downloads/{1}/{2}.jar", - "flat": false, - "recursive": true, - "regexp": false - } - ] -} -``` - -Use with: `jf rt upload --spec=filespec.json`, `jf rt download --spec=filespec.json` - -## Command Groups Overview - -| Group | Prefix | Description | -|-------|--------|-------------| -| Artifactory | `jf rt` | Artifact operations, repos, builds | -| Security | `jf audit`, `jf scan` | Vulnerability scanning, SBOM | -| Platform | `jf ds`, `jf worker`, `jf evd` | Distribution, workers, evidence | - -## Most Common Commands - -```bash -# Upload artifacts -jf rt upload "build/*.jar" libs-release-local/com/example/app/1.0/ - -# Download artifacts -jf rt download "libs-release-local/com/example/app/1.0/*.jar" ./local/ - -# Search artifacts -jf rt search "libs-release-local/com/example/**/*.jar" - -# Build integration -jf rt build-add-git my-build 1 -jf mvn install --build-name=my-build --build-number=1 -jf rt build-publish my-build 1 - -# Security scanning -jf audit # Scan project dependencies -jf scan ./myapp.jar # Scan a binary -jf docker scan myapp:1.0 # Scan Docker image - -# Release bundles -jf release-bundle-create my-bundle 1.0 --builds="my-build/1" --signing-key=mykey -jf release-bundle-promote my-bundle 1.0 --environment=PROD -jf release-bundle-distribute my-bundle 1.0 --site="edge-*" - -# Evidence -jf evd create --build-name=my-build --build-number=1 \ - --predicate=./sign.json --predicate-type=https://jfrog.com/evidence/signature/v1 \ - --key="$PRIVATE_KEY" -``` - -## Parallelization - -When building and pushing multiple Docker images, run the builds concurrently using parallel subagents or background processes. Docker builds are independent of each other and are typically the most time-consuming step in onboarding workflows. Each `docker build` + `jf docker push` pair can run in its own subagent. Publish build info (`jf rt build-publish`) only after all image pushes for that build are complete. - ---- - -# Artifactory Commands - -## Upload & Download - -```bash -# Upload files -jf rt upload "build/*.jar" libs-release-local/com/example/app/1.0/ \ - --flat=false --recursive --threads=5 - -# Upload with file spec -jf rt upload --spec=upload-spec.json - -# Upload with properties -jf rt upload "*.jar" libs-release-local/ --props="build.name=myapp;build.number=42" - -# Download files -jf rt download "libs-release-local/com/example/**/*.jar" ./local/ \ - --flat=false --threads=5 - -# Download with file spec -jf rt download --spec=download-spec.json - -# Download latest by property -jf rt download "libs-release-local/com/example/app/*" --props="release=latest" --sort-by=created --sort-order=desc --limit=1 -``` - -## Search & Delete - -```bash -# Search artifacts -jf rt search "libs-release-local/com/example/**/*.jar" - -# Search with properties -jf rt search "libs-release-local/**" --props="build.name=myapp" - -# Delete artifacts -jf rt delete "libs-release-local/com/example/app/1.0-SNAPSHOT/" - -# Delete with confirmation prompt -jf rt delete "libs-release-local/old/**" --quiet=false -``` - -## Properties - -```bash -# Set properties -jf rt set-props "libs-release-local/app.jar" "release.status=approved;qa.signed=true" - -# Delete properties -jf rt delete-props "libs-release-local/app.jar" "release.status" -``` - -## Copy & Move - -```bash -# Copy between repos -jf rt copy "libs-snapshot-local/app/(*)" "libs-release-local/app/{1}" --flat=false - -# Move between repos -jf rt move "libs-snapshot-local/app/(*)" "libs-release-local/app/{1}" -``` - -## Repository Management - -```bash -# Create repository (from template) -jf rt repo-create template.json - -# Delete repository -jf rt repo-delete my-repo - -# Generate repo template interactively -jf rt repo-template template.json -``` - -## Build Integration - -```bash -# Collect environment variables -jf rt build-collect-env my-build 42 - -# Add Git info to build -jf rt build-add-git my-build 42 - -# Add dependencies manually -jf rt build-add-dependencies my-build 42 "libs-release-local/deps/**" - -# Publish build info -jf rt build-publish my-build 42 - -# Promote build -jf rt build-promote my-build 42 libs-release-local --status=released - -# Scan build (Xray) -jf rt build-scan my-build 42 - -# Discard old builds -jf rt build-discard my-build --max-builds=10 - -# Build Docker and collect info -jf rt build-docker-create docker-local --image-file=build-metadata \ - --build-name=my-build --build-number=42 -``` - -## Package Manager Commands - -### Maven - -```bash -jf mvnc # Configure Maven for Artifactory -jf mvn clean install # Run Maven with Artifactory integration -jf mvn deploy -Drevision=1.0 # Deploy Maven artifacts -``` - -### Gradle - -```bash -jf gradlec # Configure Gradle -jf gradle clean build # Run Gradle build -jf gradle artifactoryPublish # Publish to Artifactory -``` - -### npm - -```bash -jf npmc # Configure npm -jf npm install # Install with Artifactory -jf npm publish # Publish package -jf npm ci # Clean install -``` - -### Python (pip/pipenv) - -```bash -jf pipc # Configure pip -jf pip install -r requirements.txt -jf pipenv install -``` - -### Go - -```bash -jf goc # Configure Go -jf go build # Build with Artifactory -jf go-publish v1.0.0 # Publish Go module -``` - -### Docker - -```bash -# Pull image through Artifactory -jf docker pull myregistry.jfrog.io/docker-virtual/nginx:latest - -# Build and push -jf docker push myregistry.jfrog.io/docker-local/myapp:1.0 - -# Tag for Artifactory -jf docker tag myapp:latest myregistry.jfrog.io/docker-local/myapp:1.0 -``` - -### NuGet / .NET - -```bash -jf nugetc # Configure NuGet -jf nuget restore # Restore packages -jf dotnet restore # .NET restore -``` - -### Terraform - -```bash -jf terraform-config # Configure Terraform registry -jf terraform publish --namespace=myorg --provider=aws --tag=v1.0 -``` - -## Replication - -```bash -# Transfer files between Artifactory instances -jf rt transfer-files source-server target-server \ - --include-repos="libs-release-local;docker-local" -``` - -## Curl Wrapper - -```bash -# Direct API calls through jf (handles auth automatically) -jf rt curl -XGET /api/system/ping -jf rt curl -XPOST /api/search/aql -d 'items.find({"repo":"my-repo"})' -``` - ---- - -# Security Commands - -## Project Audit - -Scans project dependencies for vulnerabilities, license compliance, and operational risks. - -```bash -# Basic audit (scans current project) -jf audit - -# Audit with watches (applies your Xray policies) -jf audit --watches=prod-watch - -# Audit specific project type -jf audit --mvn # Maven project -jf audit --npm # npm project -jf audit --pip # Python project -jf audit --go # Go project -jf audit --gradle # Gradle project -jf audit --nuget # .NET project - -# Audit with minimum severity filter -jf audit --min-severity=High - -# Audit with fail on specific severity (for CI gates) -jf audit --fail=true -``` - -### Advanced Security (JAS) Flags - -```bash -# Enable all JAS features -jf audit --watches=prod-watch - -# SAST scanning -jf audit --sast - -# Secrets detection -jf audit --secrets - -# Infrastructure as Code scanning -jf audit --iac - -# Combine multiple -jf audit --sast --secrets --iac -``` - -## Binary Scanning - -Scan individual files or Docker images without a project context. - -```bash -# Scan a JAR/WAR file -jf scan ./myapp-1.0.jar - -# Scan with minimum severity -jf scan ./myapp.jar --min-severity=High - -# Scan a directory of artifacts -jf scan ./build/output/ - -# Scan with watches (apply policies) -jf scan ./myapp.jar --watches=prod-watch -``` - -## Docker Scanning - -```bash -# Scan a Docker image -jf docker scan myapp:latest - -# Scan with severity filter -jf docker scan myapp:1.0 --min-severity=Critical - -# Scan with watches -jf docker scan myapp:1.0 --watches=docker-watch -``` - -## Build Scanning - -```bash -# Scan a published build -jf rt build-scan my-build 42 - -# Scan build with fail option (for CI) -jf rt build-scan my-build 42 --fail=true -``` - -## Curation Audit - -Check if your project's dependencies comply with Curation policies. - -```bash -# Audit against curation policies -jf curation-audit - -# Curation audit for specific package manager -jf curation-audit --npm -jf curation-audit --pip -jf curation-audit --mvn -``` - -## SBOM Export - -```bash -# Generate SBOM for a build -jf sbom --build-name=my-build --build-number=42 --format=cyclonedx - -# SBOM for Docker image -jf sbom --image=myapp:1.0 --format=spdx -``` - -## Output Formats - -```bash -# JSON output (for CI/CD integration) -jf audit --format=json - -# Table output (default, human-readable) -jf audit --format=table - -# Simple text output -jf audit --format=simple-json -``` - -## Xray REST API (`jf xr curl`) - -Invoke Xray REST endpoints using the active server from `jf config`. Pass **only the API path** (e.g. `/api/v1/system/ping`): no `https://` URL, and no `/xray/api` prefix (the CLI already routes to Xray). Wrong shapes include a full URL (the CLI rejects them) or paths like `/xray/api/v1/...` (often 404). - -```bash -# Health check -jf xr curl -s -X GET "/api/v1/system/ping" - -# Example POST (component security summary) -jf xr curl -s -X POST "/api/v1/summary/component" \ - -H "Content-Type: application/json" \ - -d '{"component_details": [{"component_id": "npm://lodash:4.17.20"}]}' -``` - -Endpoint paths are cataloged in [security-reference.md](security-reference.md) (table paths such as `/v1/...` map to `/api/v1/...` for `jf xr curl`). - -## CI/CD Integration Pattern - -```bash -# Typical CI pipeline security gate -jf audit --fail=true --min-severity=High -if [ $? -ne 0 ]; then - echo "Security violations found. Build blocked." - exit 1 -fi -``` - ---- - -# Platform Commands - -## Configuration - -```bash -# Add server config -jf config add my-server --url=https://myco.jfrog.io --access-token=$JFROG_ACCESS_TOKEN --interactive=false - -# Use a specific server -jf config use my-server - -# Show all configs -jf config show - -# Remove config -jf config remove my-server - -# Export config (for sharing/CI) -jf config export my-server - -# Import config -jf config import -``` - -## Release Bundles - -```bash -# Create release bundle from build -jf release-bundle-create my-bundle 1.0 \ - --builds="my-build/42" \ - --signing-key=my-gpg-key \ - --sync=true - -# Create from file spec -jf release-bundle-create my-bundle 1.0 \ - --spec=bundle-spec.json \ - --signing-key=my-gpg-key - -# Promote release bundle to environment -jf release-bundle-promote my-bundle 1.0 \ - --environment=STAGING - -jf release-bundle-promote my-bundle 1.0 \ - --environment=PROD - -# Distribute release bundle to edge nodes -jf release-bundle-distribute my-bundle 1.0 \ - --site="edge-*" \ - --sync=true - -# Delete release bundle -jf release-bundle-delete my-bundle 1.0 - -# Get release bundle status -jf release-bundle-status my-bundle 1.0 -``` - -### Bundle Spec File (bundle-spec.json) - -```json -{ - "files": [ - {"build": "my-build/42"}, - {"pattern": "libs-release-local/com/example/app/1.0/*"} - ] -} -``` - -## Evidence - -```bash -# Create a signing key pair -jf evd key-pair create --key-name my-evidence-key - -# Attach evidence to a package -echo '{"actor":"ci-bot","date":"2024-01-15T10:00:00Z","result":"pass"}' > predicate.json - -jf evd create \ - --package-name my-app \ - --package-version 1.0 \ - --package-repo-name docker-local \ - --key "$PRIVATE_KEY" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/signature/v1 - -# Attach evidence to a generic artifact -jf evd create \ - --subject-repo-path generic-local/readme/1.0/README.md \ - --key "$PRIVATE_KEY" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/signature/v1 - -# Attach evidence to a build -jf evd create \ - --build-name my-build --build-number 42 \ - --key "$PRIVATE_KEY" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/build-signature/v1 - -# Attach evidence to a release bundle -jf evd create \ - --release-bundle my-bundle --release-bundle-version 1.0 \ - --key "$PRIVATE_KEY" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/rbv2-signature/v1 -``` - -### Common Predicate Types - -| Type URI | Use Case | -|----------|----------| -| `https://jfrog.com/evidence/signature/v1` | General signing attestation | -| `https://jfrog.com/evidence/build-signature/v1` | Build integrity attestation | -| `https://jfrog.com/evidence/rbv2-signature/v1` | Release bundle attestation | -| `https://jfrog.com/evidence/test-result/v1` | Test execution attestation | - -## Workers - -```bash -# Initialize a new worker -jf worker init my-worker --event BEFORE_DOWNLOAD - -# Test worker -jf worker test my-worker - -# Deploy worker -jf worker deploy my-worker - -# List workers -jf worker list - -# Undeploy worker -jf worker undeploy my-worker -``` - -## Transfer (Migration) - -```bash -# Transfer files between Artifactory instances -jf rt transfer-files source-server target-server \ - --include-repos="libs-release-local;docker-local" \ - --threads=8 - -# Transfer with file filter -jf rt transfer-files source target \ - --include-repos="*-local" \ - --exclude-repos="temp-*" -``` - -## Access Token Management - -```bash -# Create access token -jf rt access-token-create --groups=readers --expiry=3600 - -# Revoke access token -jf rt access-token-revoke -``` - -## Mission Control (Multi-JPD) - -```bash -# Add JPD -jf mc add my-jpd --url=https://jpd1.jfrog.io --access-token=$JFROG_ACCESS_TOKEN - -# List JPDs -jf mc list - -# License management -jf mc license deploy --license-key=$KEY -``` - -## General Flags - -| Flag | Description | -|------|-------------| -| `--server-id` | Use specific server config | -| `--project` | Scope to project key | -| `--quiet` | Suppress prompts | -| `--dry-run` | Preview without executing | -| `--threads` | Number of concurrent operations | -| `--retries` | Number of retry attempts | -| `--detailed-summary` | Print detailed operation summary | diff --git a/plugins/jfrog/skills/jfrog/curation-reference.md b/plugins/jfrog/skills/jfrog/curation-reference.md deleted file mode 100644 index 1a3c0cd..0000000 --- a/plugins/jfrog/skills/jfrog/curation-reference.md +++ /dev/null @@ -1,272 +0,0 @@ -# Curation Reference - -## Core Concepts - -**Curation** is a package firewall that intercepts downloads from remote repositories. Before a package reaches Artifactory, Curation checks it against a pre-indexed catalog of known risks -- without downloading the package first. Non-compliant packages are blocked and never stored. - -### How It Works - -``` -Developer request → Artifactory Remote Repo → Curation Check → Allow/Block → Cache or Reject -``` - -1. Developer requests a package (e.g., `npm install lodash@4.17.20`) -2. Artifactory routes the request through its remote repository -3. Curation evaluates the package against active policies using its pre-indexed catalog -4. If compliant: package is downloaded, cached, and served -5. If non-compliant: request is blocked, package never enters Artifactory - -### Policy Types - -| Policy Type | What it blocks | -|-------------|---------------| -| **Malicious Package** | Packages flagged as malicious by JFrog threat research | -| **Critical Vulnerability** | Packages with CVEs above a severity threshold (CVSS) | -| **Viral License** | Packages with GPL, AGPL, or other copyleft licenses | -| **Outdated Package** | Packages past end-of-life or with much newer versions available | -| **Unofficial Docker Image** | Docker images that are not official or verified | - -### Waivers - -Exceptions for specific packages/versions that bypass curation policies. Used when a blocked package is deemed acceptable after manual security review. Waivers can be scoped to specific repos and have expiration dates. - -### Audit Log - -Every curation decision is logged with: timestamp, package details, policy that triggered, action taken (allowed/blocked), and requesting user. - -## Key API Operations - -### Policies - -```bash -# Create a curation policy -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "block-malicious-and-critical", - "enabled": true, - "conditions": [ - {"type": "malicious_package"}, - {"type": "cvss_score", "min_severity": 9.0} - ], - "repositories": ["npm-remote", "pypi-remote"], - "action": "block" - }' \ - "$JFROG_URL/curation/api/v1/policies" - -# List policies -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/curation/api/v1/policies" - -# Update policy -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"enabled": false}' \ - "$JFROG_URL/curation/api/v1/policies/{policy_id}" -``` - -### Audit Log - -```bash -# Get curation audit events -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/curation/api/v1/audit?repo=npm-remote&action=blocked&from=2024-01-01&limit=50" -``` - -### Waivers - -```bash -# Create a waiver for a specific package -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "package_name": "lodash", - "package_version": "4.17.20", - "package_type": "npm", - "reason": "Reviewed by security team - vulnerability not exploitable", - "expiry_date": "2025-06-30" - }' \ - "$JFROG_URL/curation/api/v1/waivers" - -# List waivers -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" "$JFROG_URL/curation/api/v1/waivers" -``` - -### CLI - -```bash -# Audit current project against curation policies -jf curation-audit -``` - -## Air-Gapped Curation - -### Partially Air-Gapped - -For environments with egress-only connectivity: - -``` -Air-gapped JPD → DMZ JPD (remote repo) → Curation Service → Public Registry -``` - -The air-gapped JPD has a remote repo pointing to the DMZ JPD. The DMZ JPD's remote repos go through Curation before fetching from public registries. - -### Fully Air-Gapped - -For environments with zero network connectivity: - -1. Request ticket for needed packages -2. DMZ system fetches packages through Curation -3. Approved packages are physically exported (media/secure transfer) -4. Imported into air-gapped JPD's local repo - -## Reference Files - -- [api-reference.md](api-reference.md) -- Complete Curation REST API endpoint catalog - -# Curation REST API Reference - -Base URL: `https://$JFROG_URL/curation/api` - -Authentication: `Authorization: Bearer $JFROG_ACCESS_TOKEN` - -## Policies - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/v1/policies` | Create curation policy | -| GET | `/v1/policies` | List policies | -| GET | `/v1/policies/{policyId}` | Get policy | -| PUT | `/v1/policies/{policyId}` | Update policy | -| DELETE | `/v1/policies/{policyId}` | Delete policy | - -### Create Policy Body - -```json -{ - "name": "block-high-risk", - "description": "Block malicious and critically vulnerable packages", - "enabled": true, - "conditions": [ - { - "type": "malicious_package" - }, - { - "type": "cvss_score", - "min_severity": 9.0 - }, - { - "type": "license", - "banned_licenses": ["GPL-3.0", "AGPL-3.0"] - } - ], - "repositories": ["npm-remote", "pypi-remote", "maven-remote"], - "package_types": ["npm", "pypi", "maven"], - "action": "block" -} -``` - -### Condition Types - -| Type | Parameters | Description | -|------|-----------|-------------| -| `malicious_package` | (none) | Block known malicious packages | -| `cvss_score` | `min_severity` (float) | Block by CVSS score threshold | -| `license` | `banned_licenses` (string[]) | Block by license type | -| `package_age` | `max_age_days` (int) | Block packages older than N days | -| `newer_version_available` | `major_versions_behind` (int) | Block if too many major versions behind | -| `unofficial_docker_image` | (none) | Block non-official Docker images | - -## Curated Repositories - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/v1/curated_repos` | List curated repos | -| PUT | `/v1/curated_repos/{repoKey}` | Enable/configure curation on a repo | -| GET | `/v1/curated_repos/{repoKey}` | Get curation config for repo | - -### Enable Curation on a Repo - -```json -{ - "repo_key": "npm-remote", - "enabled": true -} -``` - -## Audit - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/v1/audit` | Get curation audit events | - -### Query Parameters - -| Parameter | Type | Description | -|-----------|------|-------------| -| `repo` | string | Filter by repository | -| `package_type` | string | Filter by package type (npm, pypi, etc.) | -| `action` | string | `blocked` or `allowed` | -| `from` | string | Start date (ISO 8601) | -| `to` | string | End date (ISO 8601) | -| `package_name` | string | Filter by package name | -| `limit` | int | Max results (default 25) | -| `offset` | int | Pagination offset | - -### Sample Response - -```json -{ - "events": [ - { - "id": "evt-123", - "timestamp": "2024-06-15T10:30:00Z", - "repo_key": "npm-remote", - "package_name": "malicious-pkg", - "package_version": "1.0.0", - "package_type": "npm", - "action": "blocked", - "policy_name": "block-high-risk", - "condition_type": "malicious_package", - "requesting_user": "developer1" - } - ], - "total_count": 1 -} -``` - -## Waivers - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/v1/waivers` | Create waiver | -| GET | `/v1/waivers` | List waivers | -| GET | `/v1/waivers/{waiverId}` | Get waiver | -| DELETE | `/v1/waivers/{waiverId}` | Delete waiver | - -### Create Waiver Body - -```json -{ - "package_name": "lodash", - "package_version": "4.17.20", - "package_type": "npm", - "reason": "Security team confirmed: vulnerability not exploitable in our usage", - "expiry_date": "2025-12-31", - "scope": { - "repositories": ["npm-remote"] - } -} -``` - -## Package Status - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/v1/packages/{type}/{name}/{version}/status` | Get curation status of a specific package | - -## System - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/v1/system/ping` | Health check | -| GET | `/v1/system/status` | Curation service status | diff --git a/plugins/jfrog/skills/jfrog/distribution-reference.md b/plugins/jfrog/skills/jfrog/distribution-reference.md deleted file mode 100644 index 6d247cb..0000000 --- a/plugins/jfrog/skills/jfrog/distribution-reference.md +++ /dev/null @@ -1,287 +0,0 @@ -# Distribution Reference - -## Core Concepts - -| Concept | Description | -|---------|-------------| -| **Release Bundle v2** | Immutable, GPG-signed, versioned collection of artifacts representing a release candidate | -| **Environment** | SDLC stage (DEV, STAGING, PROD) for organizing the promotion pipeline | -| **Promotion** | Moving a Release Bundle from one environment to the next (with optional security gate checks) | -| **Distribution** | Delivering Release Bundle content to remote Edge nodes | -| **Edge Node** | Remote Artifactory instance that receives distributed content | -| **Evidence** | Signed attestation (DSSE format) attached to artifacts, builds, or release bundles for auditing | - -## Release Lifecycle Workflow - -``` -Build artifacts → Create Release Bundle → Promote DEV → STAGING → PROD → Distribute to Edge -``` - -### Create Release Bundle - -```bash -# From build info -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "release_bundle_name": "my-app-release", - "release_bundle_version": "1.0.0", - "skip_docker_manifest_resolution": false, - "source_type": "builds", - "source": { - "builds": [{"build_name": "my-app", "build_number": "42"}] - } - }' \ - "$JFROG_URL/lifecycle/api/v2/release_bundle" - -# From file specs (artifacts) -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "release_bundle_name": "my-release", - "release_bundle_version": "2.0.0", - "source_type": "file_specs", - "source": { - "file_specs": [ - {"pattern": "libs-release-local/com/example/app/2.0/*"} - ] - } - }' \ - "$JFROG_URL/lifecycle/api/v2/release_bundle" -``` - -### Promote Release Bundle - -```bash -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "environment": "STAGING", - "included_repository_keys": ["libs-release-local"], - "overwrite_existing_artifacts": false - }' \ - "$JFROG_URL/lifecycle/api/v2/release_bundle/records/my-app-release/1.0.0/promote" -``` - -### Distribute Release Bundle - -```bash -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "auto_create_missing_repositories": true, - "distribution_rules": [ - {"site_name": "edge-us-east"}, - {"site_name": "edge-eu-west"} - ] - }' \ - "$JFROG_URL/distribution/api/v1/distribution/my-app-release/1.0.0" -``` - -### Get Release Bundle Status - -```bash -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/lifecycle/api/v2/release_bundle/records/my-app-release/1.0.0" -``` - -## Evidence Service - -Evidence provides signed attestation metadata for artifacts, builds, and release bundles. Uses the DSSE (Dead Simple Signing Envelope) standard. - -### CLI Approach (Recommended) - -```bash -# Attach evidence to a package -echo '{"actor":"ci-bot","date":"2024-01-15T10:00:00Z"}' > predicate.json -jf evd create \ - --package-name my-app --package-version 1.0 --package-repo-name docker-local \ - --key "$PRIVATE_KEY" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/signature/v1 - -# Attach evidence to an artifact -jf evd create \ - --subject-repo-path generic-local/readme/1.0/README.md \ - --key "$PRIVATE_KEY" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/signature/v1 - -# Attach evidence to a build -jf evd create \ - --build-name my-app --build-number 42 \ - --key "$PRIVATE_KEY" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/build-signature/v1 - -# Attach evidence to a release bundle -jf evd create \ - --release-bundle my-app-release --release-bundle-version 1.0.0 \ - --key "$PRIVATE_KEY" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/rbv2-signature/v1 -``` - -### REST API Approach - -Two-step workflow (alternative to CLI when integrating third-party tools): - -1. **Prepare Evidence**: `POST /evidence/api/v1/evidence/prepare` -- creates DSSE payload -2. **Deploy Evidence**: deploys the signed envelope to Artifactory - -Since 7.129.1. Requires Enterprise+ license. Docs: https://jfrog.com/help/r/jfrog-artifactory-documentation/create-evidence-using-rest-apis - -## Reference Files - -- [api-reference.md](api-reference.md) -- Complete REST API endpoint catalog - -# Distribution & Release Lifecycle REST API Reference - -## Release Bundles (Lifecycle API) - -Base URL: `https://$JFROG_URL/lifecycle/api` - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/v2/release_bundle` | Create release bundle | -| GET | `/v2/release_bundle/records/{name}/{version}` | Get release bundle details | -| GET | `/v2/release_bundle/records` | List release bundles | -| DELETE | `/v2/release_bundle/records/{name}/{version}` | Delete release bundle version | -| POST | `/v2/release_bundle/records/{name}/{version}/promote` | Promote to environment | -| GET | `/v2/release_bundle/records/{name}/{version}/promotion` | Get promotion status | - -### Create Release Bundle (from Build) - -```json -{ - "release_bundle_name": "my-release", - "release_bundle_version": "1.0.0", - "skip_docker_manifest_resolution": false, - "source_type": "builds", - "source": { - "builds": [ - {"build_name": "my-app", "build_number": "42", "build_repository": "artifactory-build-info"} - ] - } -} -``` - -### Create Release Bundle (from File Specs) - -```json -{ - "release_bundle_name": "my-release", - "release_bundle_version": "2.0.0", - "source_type": "file_specs", - "source": { - "file_specs": [ - {"pattern": "libs-release-local/com/example/app/2.0/*"}, - {"pattern": "docker-prod-local/my-app/2.0/*"} - ] - } -} -``` - -### Create Release Bundle (from existing Release Bundle) - -```json -{ - "release_bundle_name": "promoted-release", - "release_bundle_version": "2.0.0", - "source_type": "release_bundles", - "source": { - "release_bundles": [ - {"release_bundle_name": "my-release", "release_bundle_version": "2.0.0"} - ] - } -} -``` - -### Promote Release Bundle - -```json -{ - "environment": "PROD", - "included_repository_keys": ["libs-release-local", "docker-prod-local"], - "overwrite_existing_artifacts": false -} -``` - -## Distribution API - -Base URL: `https://$JFROG_URL/distribution/api` - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/v1/distribution/{name}/{version}` | Distribute release bundle | -| GET | `/v1/distribution/{name}/{version}/status` | Get distribution status | -| DELETE | `/v1/distribution/{name}/{version}` | Delete distribution | - -### Distribute Release Bundle - -```json -{ - "dry_run": false, - "auto_create_missing_repositories": true, - "distribution_rules": [ - { - "site_name": "edge-us-east", - "city_name": "*", - "country_codes": ["US"] - }, - { - "site_name": "edge-eu-west" - } - ] -} -``` - -## Signing Keys - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/v1/keys/gpg` | List GPG signing keys (Lifecycle API) | -| POST | `/v1/keys/gpg` | Create GPG signing key (Lifecycle API) | -| DELETE | `/v1/keys/gpg/{key_alias}` | Delete signing key (Lifecycle API) | - -## Evidence API - -Base URL: `https://$JFROG_URL/evidence/api` - -Since: 7.129.1. License: Enterprise+. - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/v1/evidence/prepare` | Prepare evidence (DSSE format) | -| PUT | `/{deploy_path}` | Deploy evidence (path from prepare response) | - -### Prepare Evidence - -Query params: `include_pae` (boolean) -- include Pre-Authentication Encoding statement - -```json -{ - "subject_repo_path": "docker-local/my-app/1.0/manifest.json", - "predicate": "{\"actor\":\"ci-bot\",\"result\":\"pass\"}", - "predicate_type": "https://jfrog.com/evidence/test-result/v1" -} -``` - -### Evidence CLI Commands - -```bash -# Generate key pair -jf evd key-pair create --key-name my-signing-key - -# Create evidence (4 subject types) -jf evd create --package-name NAME --package-version VER --package-repo-name REPO ... -jf evd create --subject-repo-path REPO/PATH ... -jf evd create --build-name NAME --build-number NUM ... -jf evd create --release-bundle NAME --release-bundle-version VER ... -``` - -## Environments - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/access/api/v1/projects/{project_key}/environments` | List project environments | diff --git a/plugins/jfrog/skills/jfrog/flow-suggestions.md b/plugins/jfrog/skills/jfrog/flow-suggestions.md deleted file mode 100644 index ebb7703..0000000 --- a/plugins/jfrog/skills/jfrog/flow-suggestions.md +++ /dev/null @@ -1,482 +0,0 @@ -# Flow Suggestions - -Use this file in two situations: -1. **After an action** -- identify whether the completed action is part of a larger pattern and suggest the next step. -2. **During exploration** -- when the user doesn't know what to do, asks "what can I do?", or wants to get started with their JFrog environment. - -Always render a mermaid progress diagram and use `AskQuestion` to let the user pick how to proceed. - -## Pre-flight Gate - -Before showing suggestions, run the pre-flight check ([preflight.md](preflight.md)) if it has not been run this session. Use the results to filter out paths for unavailable services: - -- Only offer **Security / Xray** options if Xray is available. -- Only offer **Curation** options if Curation is available. -- Only offer **AppTrust** options if AppTrust is available. -- Only offer **Release Lifecycle / Distribution** options if Lifecycle is available. - -In diagrams, apply `:::unavailable` to nodes for services that are not deployed. In `AskQuestion`, omit options for unavailable services entirely. - -## Diagram conventions - -- Nodes with `:::done` represent completed steps (green border). -- Nodes with `:::next` represent the suggested next step (amber dashed border). -- Nodes with `:::unavailable` represent services not deployed on this instance (grey dashed border). Omit these from `AskQuestion` options. -- Unstyled nodes represent future steps. -- **Always prefer `flowchart LR`** (horizontal) -- this is the default. Avoid fan-out patterns (one node with many outgoing edges) as they stack vertically and create tall graphs. Instead, chain nodes horizontally (`A --> B --> C --> D`). Only use `flowchart TD` when the architecture genuinely requires top-down layout (e.g., load balancer above two JPDs). -- Always include the classDef lines at the end of each diagram. -- **The diagram is mandatory** -- always render it so the user sees their progress visually. -- After the diagram, use the `AskQuestion` tool to offer a selection (see "Suggested options" sections below). - ---- - -## Getting Started (Discovery) - -When the user doesn't know what to do, asks what they can do with JFrog, or wants help getting started -- show the entry-point diagram and let them pick a path. - -### Entry-point diagram - -```mermaid -flowchart LR - Repos["Repository\nSetup"] --> CI["CI\nIntegration"] --> Security["Security\nScanning"] --> RLM["Release\nLifecycle"] --> Curation["Package\nCuration"] - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 - classDef unavailable stroke:#9ca3af,stroke-width:2px,stroke-dasharray:8,color:#9ca3af -``` - -Apply `:::unavailable` to nodes whose service is not deployed (e.g., Security if Xray is down, Curation if Curation is not available). Omit unavailable options from the `AskQuestion` below. - -### Suggested options (Getting Started) - -Show the entry-point diagram, then ask via `AskQuestion`. Only include options for services that are available (per the pre-flight check): - -| Option | Label | Requires | -|--------|-------|----------| -| repo-setup | Set up repositories -- local, remote, and virtual repos for your packages | Artifactory (always) | -| ci-integration | Integrate JFrog with your CI pipeline to collect Build Info | Artifactory (always) | -| security | Set up security scanning with Xray policies and watches | Xray | -| release-lifecycle | Manage releases -- create Release Bundles and promote through environments | Lifecycle | -| curation | Set up package curation to block risky open-source packages | Curation | -| something-else | Something else | -- | - -If the user provides context about their goal (e.g., "I want to secure my supply chain"), narrow the options to the most relevant journey. See the [patterns-journeys.md](patterns-journeys.md) file and the **Cross-Cutting Journey Progress** section below for journey-specific flows. - ---- - -## Artifactory Actions - -| You just... | Part of pattern | Next step | -|---|---|---| -| Created a local repository | Basic Repository Setup [SIMPLE] | Create a remote repo to cache public packages | -| Created a remote repository | Basic Repository Setup [SIMPLE] | Create a virtual repo that unifies local + remote | -| Created a virtual repository | Basic Repository Setup [SIMPLE] | Configure CI to resolve and deploy through the virtual repo | -| Set up basic repos | CI Integration [SIMPLE] | Configure JFrog CLI build integration to collect Build Info | -| Published Build Info | CI Integration with Security Scans [INTERMEDIATE] | Add an Xray security policy and watch for your build | -| Configured replication | Multi-Site Active/Standby [ADVANCED] | Set up Access Federation for user and permission sync | -| Created per-team local repos | Cross-Team Collaboration [ADVANCED] | Create a shared virtual repo and configure per-team permissions | - -### Progress: Basic Repository Setup - -After creating a local repo: - -```mermaid -flowchart LR - A["Local Repo"]:::done --> B["Remote Repo"]:::next --> C["Virtual Repo"] --> D["CI Integration"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -After creating a remote repo: - -```mermaid -flowchart LR - A["Local Repo"]:::done --> B["Remote Repo"]:::done --> C["Virtual Repo"]:::next --> D["CI Integration"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -After creating a virtual repo: - -```mermaid -flowchart LR - A["Local Repo"]:::done --> B["Remote Repo"]:::done --> C["Virtual Repo"]:::done --> D["CI Integration"]:::next - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -### Suggested options (Artifactory) - -After creating a local repo -- show the "after local repo" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| remote-repo | Create a remote repo to cache public packages (next step) | -| ci-integration | Jump ahead to CI integration with this repo | -| something-else | Something else | - -After creating a remote repo -- show the "after remote repo" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| virtual-repo | Create a virtual repo -- single URL for both (next step) | -| security-scanning | Set up security scanning for these repos | -| something-else | Something else | - -After creating a virtual repo -- show the "after virtual repo" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| ci-integration | Set up CI integration to build and deploy through this repo (next step) | -| security-policies | Add security policies and watches for this repo | -| something-else | Something else | - ---- - -## Security Actions - -> **Requires:** Xray (`JFROG_HAS_XRAY=true`). Skip this section if Xray is not available on the instance. - -| You just... | Part of pattern | Next step | -|---|---|---| -| Created a security policy | Xray Security [INTERMEDIATE] | Create a watch that links repos to the policy | -| Created a watch | Xray Security [INTERMEDIATE] | Trigger a scan or review existing violations | -| Scanned a build | Xray Security [INTERMEDIATE] | Review violations and set up ignore rules if needed | -| Reviewed violations | Xray Security [INTERMEDIATE] | Generate a vulnerability report or SBOM | -| Ran `jf audit` in CI | JFrog Advanced Security [ADVANCED] | Enable SAST, secrets detection, and contextual analysis | - -### Progress: Xray Security Setup - -After creating a policy: - -```mermaid -flowchart LR - A["Security Policy"]:::done --> B["Watch"]:::next --> C["Scan"] --> D["Review Violations"] --> E["Reports / SBOM"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -After creating a watch: - -```mermaid -flowchart LR - A["Security Policy"]:::done --> B["Watch"]:::done --> C["Scan"]:::next --> D["Review Violations"] --> E["Reports / SBOM"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -After scanning: - -```mermaid -flowchart LR - A["Security Policy"]:::done --> B["Watch"]:::done --> C["Scan"]:::done --> D["Review Violations"]:::next --> E["Reports / SBOM"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -### Suggested options (Security) - -After creating a policy -- show the "after policy" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| create-watch | Create a watch to connect your repos to this policy (next step) | -| setup-curation | Set up curation to block risky packages at the gate | -| something-else | Something else | - -After creating a watch -- show the "after watch" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| trigger-scan | Trigger a scan on an existing build (next step) | -| review-violations | Review any current violations across watched repos | -| something-else | Something else | - -After scanning -- show the "after scan" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| review-violations | Review violations and set up ignore rules (next step) | -| generate-report | Generate a vulnerability report or SBOM | -| something-else | Something else | - ---- - -## Release Lifecycle Actions - -> **Requires:** Lifecycle service (`JFROG_HAS_LIFECYCLE=true`). Skip this section if Lifecycle is not available on the instance. - -| You just... | Part of pattern | Next step | -|---|---|---| -| Published Build Info | RLM without Security Gates [SIMPLE] | Create a Release Bundle from the build | -| Created a Release Bundle | RLM without Security Gates [SIMPLE] | Promote through environments (DEV, STAGING, PROD) | -| Promoted to PROD | RLM with Distribution [ADVANCED] | Distribute to Edge nodes | -| Created a Release Bundle | RLM with Security Gates [INTERMEDIATE] | Set up an Xray policy to gate promotions | -| Promoted a release | RLM with Evidence [ADVANCED] | Attach signed evidence to the release bundle | - -### Progress: Release Lifecycle (full flow) - -After publishing Build Info: - -```mermaid -flowchart LR - A["Build Info"]:::done --> B["Release Bundle"]:::next --> C["Promote DEV"] --> D["Promote STAGING"] --> E["Promote PROD"] --> F["Distribute"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -After creating a Release Bundle: - -```mermaid -flowchart LR - A["Build Info"]:::done --> B["Release Bundle"]:::done --> C["Promote DEV"]:::next --> D["Promote STAGING"] --> E["Promote PROD"] --> F["Distribute"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -After promoting to PROD: - -```mermaid -flowchart LR - A["Build Info"]:::done --> B["Release Bundle"]:::done --> C["Promote DEV"]:::done --> D["Promote STAGING"]:::done --> E["Promote PROD"]:::done --> F["Distribute"]:::next - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -### Progress: Release Lifecycle with Security Gates - -After creating a Release Bundle (no gates yet): - -```mermaid -flowchart LR - A["Release Bundle"]:::done --> B["Xray Policy"]:::next --> C["Watch"] --> D["Gated Promotion"] - B -.->|"blocks promotion\non violations"| D - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -### Suggested options (Release Lifecycle) - -After publishing Build Info -- show the "after Build Info" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| create-bundle | Create a Release Bundle from this build (next step) | -| add-scanning | Add security scanning to the build first | -| something-else | Something else | - -After creating a Release Bundle -- show the "after Release Bundle" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| promote-dev | Promote through environments -- starting with DEV (next step) | -| add-gates | Add security gates before promotion | -| something-else | Something else | - -After promoting to PROD -- show the "after PROD" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| distribute | Distribute this release to Edge nodes (next step) | -| attach-evidence | Attach signed evidence for compliance | -| something-else | Something else | - ---- - -## Curation Actions - -> **Requires:** Curation service (`JFROG_HAS_CURATION=true`). Skip this section if Curation is not available on the instance. - -| You just... | Part of pattern | Next step | -|---|---|---| -| Enabled curation on a remote repo | Curation & Governance [ADVANCED] | Create a curation policy to define blocking rules | -| Created a curation policy | Curation & Governance [ADVANCED] | Run `jf curation-audit` in your project to test it | -| Ran `jf curation-audit` | CI Integration with Curation [ADVANCED] | Integrate the audit into your CI pipeline | - -### Progress: Curation Setup - -After enabling curation on a remote repo: - -```mermaid -flowchart LR - A["Enable on Remote"]:::done --> B["Curation Policy"]:::next --> C["Audit in Project"] --> D["CI Integration"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -After creating a policy: - -```mermaid -flowchart LR - A["Enable on Remote"]:::done --> B["Curation Policy"]:::done --> C["Audit in Project"]:::next --> D["CI Integration"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -### Suggested options (Curation) - -After enabling curation -- show the "after enabling" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| create-policy | Create a curation policy to define blocking rules (next step) | -| review-audit-log | Review the curation audit log to see what's already been blocked | -| something-else | Something else | - -After creating a policy -- show the "after policy" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| run-audit | Run `jf curation-audit` in your project to test it (next step) | -| ci-integration | Integrate the audit into your CI pipeline | -| something-else | Something else | - ---- - -## Distribution Actions - -> **Requires:** Lifecycle service (`JFROG_HAS_LIFECYCLE=true`). Skip this section if Lifecycle/Distribution is not available on the instance. - -| You just... | Part of pattern | Next step | -|---|---|---| -| Created a Release Bundle | RLM with Distribution [ADVANCED] | Promote through environments before distributing | -| Promoted to final environment | RLM with Distribution [ADVANCED] | Distribute to Edge nodes | -| Distributed to Edge nodes | RLM with Evidence [ADVANCED] | Attach signed evidence for compliance | - -### Progress: Distribution flow - -After promoting to PROD: - -```mermaid -flowchart LR - A["Release Bundle"]:::done --> B["Promote to PROD"]:::done --> C["Distribute to Edge"]:::next --> D["Attach Evidence"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -### Suggested options (Distribution) - -After promoting to PROD -- show the "after PROD" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| distribute | Distribute this release to Edge nodes (next step) | -| attach-evidence | Attach signed evidence before distributing | -| something-else | Something else | - -After distributing -- ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| attach-evidence | Attach signed evidence for compliance (next step) | -| check-status | Check distribution status on Edge nodes | -| something-else | Something else | - ---- - -## AppTrust Actions - -> **Requires:** AppTrust service (`JFROG_HAS_APPTRUST=true`). Skip this section if AppTrust is not available on the instance. - -| You just... | Part of pattern | Next step | -|---|---|---| -| Created an application entity | Application Entity Creation [SIMPLE] | Bind package versions to the application | -| Bound packages to an application | Application Risk Governance [SIMPLE] | Define lifecycle stages and policy gates | -| Created lifecycle stages | Application Risk Governance [SIMPLE] | Create a lifecycle policy with evidence-based gates | - -### Progress: AppTrust Setup - -After creating an application: - -```mermaid -flowchart LR - A["Create App"]:::done --> B["Bind Packages"]:::next --> C["Lifecycle Stages"] --> D["Gate Policies"] --> E["Attach Evidence"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -After binding packages: - -```mermaid -flowchart LR - A["Create App"]:::done --> B["Bind Packages"]:::done --> C["Lifecycle Stages"]:::next --> D["Gate Policies"] --> E["Attach Evidence"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -### Suggested options (AppTrust) - -After creating an application -- show the "after creating application" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| bind-packages | Bind package versions to this application (next step) | -| security-scanning | Set up security scanning for the application's packages | -| something-else | Something else | - -After binding packages -- show the "after binding packages" diagram, then ask via `AskQuestion`: - -| Option | Label | -|--------|-------| -| lifecycle-stages | Define lifecycle stages and create policy gates (next step) | -| review-risk | Review the application's current risk posture | -| something-else | Something else | - ---- - -## Cross-Cutting Journey Progress - -When a user has completed actions across multiple categories, show the journey-level progress. - -### Journey: Modernize Delivery - -```mermaid -flowchart LR - S1["1. Repository\nSetup"] --> S2["2. CI\nIntegration"] --> S3["3. Release\nLifecycle"] --> S4["4. Distribution"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -Mark steps as `:::done` or `:::next` based on what the user has completed. - -### Journey: Secure SDLC - -```mermaid -flowchart LR - S1["1. Package\nCuration"] --> S2["2. Xray\nSCA + SBOM"] --> S3["3. Advanced\nSecurity"] --> S4["4. Runtime\nMonitoring"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -### Journey: Accelerate Productivity - -```mermaid -flowchart LR - S1["1. CI\nIntegration"] --> S2["2. Curation"] --> S3["3. Contextual\nAnalysis"] --> S4["4. Package\nApprovals"] - classDef done stroke:#22c55e,stroke-width:3px - classDef next stroke:#f59e0b,stroke-width:3px,stroke-dasharray:5 -``` - -### Suggested options (Journeys) - -After completing a journey step -- show the journey diagram with completed steps marked, then ask via `AskQuestion` with options built from the journey context: - -| Option | Label | -|--------|-------| -| next-step | [Next step in the journey] (next step) | -| alt-path | [Alternative step or related pattern] | -| something-else | Something else | - -Example after completing repository setup in Modernize Delivery: - -| Option | Label | -|--------|-------| -| ci-integration | Set up CI integration to automate builds (next step in Modernize Delivery) | -| security-scanning | Add security scanning to the repos you just created | -| something-else | Something else | - -Example after completing Xray setup in Secure SDLC: - -| Option | Label | -|--------|-------| -| advanced-security | Enable Advanced Security -- contextual analysis, SAST, secrets detection (next step) | -| setup-curation | Set up curation to block risky packages at the gate | -| something-else | Something else | diff --git a/plugins/jfrog/skills/jfrog/login-flow.md b/plugins/jfrog/skills/jfrog/login-flow.md deleted file mode 100644 index 66e266b..0000000 --- a/plugins/jfrog/skills/jfrog/login-flow.md +++ /dev/null @@ -1,252 +0,0 @@ -# Agent-Driven Login Flow (Multi-Environment) - -This procedure resolves which JFrog Platform environment to use, authenticates if needed, and persists credentials via `jf config`. The agent executes this flow itself. Requires Artifactory 7.64.0+ and the JFrog CLI (`jf`). - -## Security Rules - -- **Never print tokens.** Do not `echo`, `cat`, or otherwise display access tokens in terminal output or chat messages. Use commands that extract tokens into variables silently. -- **Never log token values.** When confirming auth status, say "authenticated as user X" or "token is set" -- never show the token itself. -- **`jf config` is the sole credential store.** Never store tokens in files, environment variable profiles, or project directories. The CLI encrypts tokens at rest. -- **Validate URLs.** Before using a user-provided URL, verify it with the ping endpoint. Do not pass unvalidated URLs to shell commands. - -## Step 0 -- Ensure `jf` CLI Is Installed - -```bash -command -v jf >/dev/null 2>&1 && jf --version -``` - -If `jf` is not found, install it: - -**macOS:** - -```bash -brew install jfrog-cli -``` - -**Linux:** - -```bash -curl -fL https://install-cli.jfrog.io | sh -``` - -Confirm the installation succeeded: - -```bash -jf --version -``` - -If installation fails, ask the user to install manually from the [JFrog CLI install page](https://jfrog.com/help/r/jfrog-cli/install-the-jfrog-cli). - -## Step 1 -- Resolve the Active Environment - -Check for saved credentials. If the user already specified a JFrog URL or domain in their message, match it against saved servers and skip straight to Step 2. - -```bash -jf config show 2>/dev/null -``` - -This lists all configured servers with their IDs and URLs. - -- **0 servers configured** -- ask the user for their JFrog Platform URL, then go to [Web Login](#step-3----web-login). -- **1 server configured** -- use it. Run `jf config use `, then go to Step 2. -- **2+ servers configured** -- list the server IDs and URLs and ask the user which environment they want to use. Example prompt: "I found these JFrog environments: `mycompany` (mycompany.jfrog.io), `staging` (staging.jfrog.io). Which one should I use?" - -To activate a server: - -```bash -jf config use -``` - -If no servers are configured, ask the user: "What is your JFrog Platform URL? (e.g. `https://mycompany.jfrog.io`)" -- then proceed to web login. - -## Step 2 -- Extract Active Credentials - -Once the active environment is resolved (from `jf config` or after web login), extract URL and token into transient shell variables for the current session. These are used by `curl` commands in other skills. - -**Preferred method** -- reliable extraction via `jf config export`: - -```bash -JFROG_SERVER_ID=$(jf config show 2>/dev/null | grep -i 'Server ID' | head -1 | awk '{print $NF}') -JFROG_URL=$(jf config show 2>/dev/null | grep -i 'JFrog Platform URL' | head -1 | awk '{print $NF}' | sed 's|https://||;s|/$||') -JFROG_ACCESS_TOKEN=$(jf config export "$JFROG_SERVER_ID" 2>/dev/null | \ - python3 -c " -import sys, json, base64 -raw = sys.stdin.read().strip() -try: - data = json.loads(raw) -except Exception: - data = json.loads(base64.b64decode(raw)) -print(data.get('accessToken', '')) -") -``` - -`JFROG_SERVER_ID` captures the active server ID from Step 1. It is used here for `jf config export` and by downstream commands that need an explicit `--server-id` (e.g., `jf apptrust ping`). The `jf config export` approach is more reliable than parsing `jf config show` output, which masks the token. - -These variables are transient -- they exist only in the current shell session and are never persisted or exported to child processes. - -> **Agent tooling note:** Shell variables set in one tool call do **not** persist to the next tool call. Always combine credential extraction **and** the API call that uses those credentials in a single shell command. For example, prepend the extraction block above to every `curl` command rather than running them separately. - -## Step 2b -- Generate an Admin-Scoped Token (Optional) - -Some operations (creating projects, users, lifecycle stages) require admin privileges. If the user's session token lacks scope for these operations, generate an admin-scoped token: - -```bash -jf atc --server-id= --groups="*" --expiry=3600 -``` - -> **Note:** Use `jf atc` (the current syntax), not the deprecated `jf rt access-token-create`. The generated token inherits the user's permissions -- it does not elevate a non-admin user to admin. - -## Step 3 -- Web Login - -Run this flow when no valid credentials exist for the target environment. The user only needs to click a link and log in via their browser. - -> **SANDBOX NOTE -- permissions required:** Steps 3a+3b and 3d make `curl` calls to the JFrog Platform URL (an external host) and are blocked by the Cursor sandbox by default. Use these permission levels: -> -> - **Steps 3a+3b:** `required_permissions: ["full_network"]` -- only makes `curl` calls, no filesystem writes outside the workspace. -> - **Step 3d:** `required_permissions: ["all"]` -- in addition to `curl`, this step runs `jf config add` which writes credentials to `~/.jfrog/` (**outside the workspace**). Using `full_network` alone silently blocks the filesystem write, the command exits 1 with no output, and the one-time-use session token is consumed -- requiring the entire login flow to restart. - -### 3a+3b -- Verify the server is reachable and register a login session - -Combine the ping check and session registration into a **single shell command** (both require `full_network`): - -```bash -# Run this with required_permissions: ["full_network"] -JFROG_PLATFORM_URL="https://mycompany.jfrog.io" # substitute actual URL - -PING_CODE=$(curl -s -o /dev/null -w "%{http_code}" "${JFROG_PLATFORM_URL}/artifactory/api/system/ping") -if [ "$PING_CODE" != "200" ]; then - echo "ERROR: Server not reachable (HTTP $PING_CODE). Ask the user to verify the URL." - exit 1 -fi - -SESSION_UUID=$(uuidgen | tr '[:upper:]' '[:lower:]') -VERIFY_CODE=${SESSION_UUID: -4} - -curl -s -X POST "${JFROG_PLATFORM_URL}/access/api/v2/authentication/jfrog_client_login/request" \ - -H "Content-Type: application/json" \ - -d "{\"session\":\"${SESSION_UUID}\"}" - -echo "SESSION_UUID=${SESSION_UUID}" -echo "VERIFY_CODE=${VERIFY_CODE}" -``` - -The final two `echo` lines print the values so you can copy them as literals into Step 3d. No authentication is required for these calls. - -> **Why combined?** Combining ping + session registration avoids a second `full_network` request approval and ensures both values (`SESSION_UUID`, `VERIFY_CODE`) are captured in the same shell output for use in Step 3d. - -### 3c -- Show the verification code and login link - -> Copy `SESSION_UUID` and `VERIFY_CODE` from the output of step 3a+3b above. You will substitute them as literal strings in step 3d. - -Build the login URL. The `jfClientCode` parameter is always `1` (matching the JFrog CLI behavior): - -```bash -LOGIN_URL="${JFROG_PLATFORM_URL}/ui/login?jfClientSession=${SESSION_UUID}&jfClientName=JFrog-Skills&jfClientCode=1" -``` - -Show the verification code **first and prominently**, then the clickable link. Do not open the browser automatically. Example message: - -> ## Verification code: `7890` -> -> Open this link to log in, then enter the code above when prompted: -> -> [Log in to mycompany.jfrog.io](https://mycompany.jfrog.io/ui/login?jfClientSession=a1b2c3d4-e5f6-7890-abcd-ef1234567890&jfClientName=JFrog-Skills&jfClientCode=1) -> -> Let me know when you're done. - -### 3d -- Retrieve token, save credentials, and verify - -**Wait for the user to confirm** they have completed the login. Do not poll automatically. - -> **CRITICAL -- Atomicity requirement:** The entire token retrieval, config save, and verification below **MUST execute in a single shell command**. Shell variables do not persist between separate tool calls. If they run separately, the token will be silently lost. The token endpoint is **one-time use** -- once consumed, the session UUID is invalidated and the entire login flow must restart from Step 3b with a new session. - -> **Variable passing:** The agent must substitute `JFROG_PLATFORM_URL` and `SESSION_UUID` as **literal strings** at the top of the command (copied from the output of Steps 3a-3c). Do not rely on shell variables set in prior tool calls. - -Once the user confirms they have logged in, run this entire block as **one shell command** with `required_permissions: ["all"]`: - -```bash -JFROG_PLATFORM_URL="https://mycompany.jfrog.io" # substitute actual URL -SESSION_UUID="a1b2c3d4-e5f6-7890-abcd-ef1234567890" # substitute actual UUID from Step 3b - -JFROG_HOST=$(echo "$JFROG_PLATFORM_URL" | sed 's|https://||' | sed 's|\.jfrog\.io.*||' | sed 's|[./]|-|g') - -HTTP_CODE=$(curl -s -o /tmp/jf_login_resp.json -w "%{http_code}" \ - "$JFROG_PLATFORM_URL/access/api/v2/authentication/jfrog_client_login/token/$SESSION_UUID") - -if [ "$HTTP_CODE" != "200" ]; then - echo "ERROR: Token retrieval failed (HTTP $HTTP_CODE). User may not have completed login." - rm -f /tmp/jf_login_resp.json - exit 1 -fi - -ACCESS_TOKEN=$(python3 -c "import json; print(json.load(open('/tmp/jf_login_resp.json')).get('access_token',''))") -rm -f /tmp/jf_login_resp.json - -if [ -z "$ACCESS_TOKEN" ]; then - echo "ERROR: Empty token in response. Re-run from Step 3b." - exit 1 -fi - -jf config remove "$JFROG_HOST" --quiet 2>/dev/null || true -jf config add "$JFROG_HOST" \ - --url="$JFROG_PLATFORM_URL" \ - --access-token="$ACCESS_TOKEN" \ - --interactive=false -jf config use "$JFROG_HOST" - -export JFROG_URL=$(echo "$JFROG_PLATFORM_URL" | sed 's|https://||;s|/$||') -export JFROG_ACCESS_TOKEN="$ACCESS_TOKEN" - -echo "--- Verifying authentication ---" -jf rt curl -s "/api/system/version" --server-id="$JFROG_HOST" -``` - -- **HTTP 200** from the token endpoint -- login succeeded; the script continues to save and verify. -- **HTTP 400** -- user has not completed login yet. Ask the user to try again. -- **Verification output** -- the final `jf rt curl` call should return a JSON object with a `version` field. If it returns a 401 error, the token was not saved correctly -- fall back to [Manual Token Setup](#fallback-manual-token-setup). - -The server ID is derived from the hostname: `https://mycompany.jfrog.io` becomes `mycompany`, `https://acme.jfrog.io` becomes `acme`. For self-hosted URLs like `https://artifactory.internal.corp`, the full hostname is slugified: `artifactory-internal-corp`. - -Response body from the token endpoint on success: - -```json -{ - "access_token": "", - "refresh_token": "", - "expires_in": 3600, - "token_type": "Bearer", - "scope": "..." -} -``` - -## Switch Environment Mid-Session - -To switch to a different saved environment during a session: - -```bash -jf config use -``` - -Then re-extract transient credentials for the new environment (same as Step 2). - -## Fallback: Manual Token Setup - -If the web login flow fails (server too old, network restrictions, etc.), ask the user to: - -1. Generate a token in the JFrog UI: **Administration > Identity and Access > Access Tokens > Generate Token** -2. Save it via the CLI (the agent runs this -- the user only pastes the token when prompted): - -```bash -jf config add --url=https:// --access-token= --interactive=false -``` - -Never store the token in environment variable profiles, files, or project directories. - -## REST API Reference - -| Step | Method | Endpoint | Auth Required | Body / Query Params | -|------|--------|----------|---------------|---------------------| -| Ping | GET | `{url}/artifactory/api/system/ping` | No | -- | -| Register session | POST | `{url}/access/api/v2/authentication/jfrog_client_login/request` | No | `{"session":""}` | -| Browser login | GET | `{url}/ui/login?jfClientSession={uuid}&jfClientName=JFrog-Skills&jfClientCode=1` | No | User opens in browser; `jfClientCode` is always `1`. The verification code the user enters is the last 4 characters of the session UUID | -| Poll for token | GET | `{url}/access/api/v2/authentication/jfrog_client_login/token/{uuid}` | No | -- | diff --git a/plugins/jfrog/skills/jfrog/mission-control-reference.md b/plugins/jfrog/skills/jfrog/mission-control-reference.md deleted file mode 100644 index 8f31a28..0000000 --- a/plugins/jfrog/skills/jfrog/mission-control-reference.md +++ /dev/null @@ -1,135 +0,0 @@ -# Mission Control Reference - -## Core Concepts - -| Concept | Description | -|---------|-------------| -| **JPD** | JFrog Platform Deployment — an instance of the JFrog Platform (Artifactory + Xray + services) | -| **License** | Enterprise license attached to a JPD, with type and expiration | -| **Proxy** | Network proxy configured for outbound connections | - -## List All JPD Instances - -Returns all JFrog Platform Deployment instances associated with the current platform. - -```bash -curl -s -X GET "$JFROG_URL/mc/api/v1/jpds" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -Returns an array of JPD objects, each with `id`, `name`, `url`, `status`, `location`, `licenses`, `services`, and `tags`. - -## Get JPD by ID - -Returns details for a specific JPD instance. - -```bash -curl -s -X GET "$JFROG_URL/mc/api/v1/jpds/${JPD_ID}" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -Response includes full JPD details: status, location, license info, and service health. - -## Attach License to JPD - -```bash -curl -s -X POST "$JFROG_URL/mc/api/v1/jpds/${JPD_ID}/attach_license" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"license_key": "your-license-key-here"}' -``` - -## List Proxies - -```bash -curl -s -X GET "$JFROG_URL/mc/api/v1/proxies" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" | jq . -``` - -## Common Workflows - -### Monitor Platform Health Across Deployments - -1. List all JPDs to get an overview of all deployments -2. Check each JPD's `status.code` for `HEALTHY`, `DEGRADED`, or `UNHEALTHY` -3. Inspect individual JPD services for detailed health information - -### Audit Licenses - -1. List all JPDs -2. Review the `licenses` array on each JPD for expiration dates (`valid_through`) and `expired` status -3. Attach new licenses to JPDs as needed - -# Mission Control API Reference - -Base path: `/mc/api/v1/` - -## JPD Instances - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/jpds` | List all JPD instances | -| GET | `/jpds/{id}` | Get specific JPD | -| POST | `/jpds/{id}/attach_license` | Attach license to JPD | - -### JPD Response Object - -```json -{ - "id": "string", - "name": "string", - "url": "https://site-a.jfrog.io", - "status": { - "code": "HEALTHY | DEGRADED | UNHEALTHY", - "message": "string" - }, - "location": { - "city_name": "string", - "country_code": "string", - "latitude": 0.0, - "longitude": 0.0 - }, - "licenses": [ - { - "type": "Enterprise Plus", - "valid_through": "2026-12-31T00:00:00Z", - "expired": false - } - ], - "services": [ - { - "name": "artifactory", - "status": "HEALTHY", - "version": "7.125.0" - } - ], - "tags": ["production", "us-east"] -} -``` - -### Attach License Request Body - -```json -{ - "license_key": "string (required)" -} -``` - -## Proxies - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/proxies` | List all configured proxies | - -### Proxy Response Object - -```json -{ - "key": "string", - "host": "proxy.example.com", - "port": 8080, - "username": "string", - "platform_default": true, - "services": ["artifactory", "xray"] -} -``` diff --git a/plugins/jfrog/skills/jfrog/patterns-apptrust.md b/plugins/jfrog/skills/jfrog/patterns-apptrust.md deleted file mode 100644 index eb298e7..0000000 --- a/plugins/jfrog/skills/jfrog/patterns-apptrust.md +++ /dev/null @@ -1,116 +0,0 @@ -# AppTrust Patterns - -## 1. Application Entity Creation (`app-trust-application-entity-creation`) [SIMPLE, ~3 min] - -**Purpose:** Define application entities with clear business context and ownership. - -**What You Do:** -1. Create applications within projects -2. Associate package versions with applications -3. Define ownership and business criticality - -**JFrog Concepts:** Application Entity, Application Versions - -**AppTrust REST APIs:** https://jfrog.com/help/r/jfrog-rest-apis/apptrust-rest-apis - -API categories: Applications, Application Versions, Bound Packages, Lifecycle Policies, Stages & Lifecycles, Activity Log, Templates, Evaluations, Rules - -**Implementation:** -```bash -# Create an application -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "my-web-app", - "description": "Customer-facing web application", - "project_key": "myproject", - "criticality": "high", - "owner": "platform-team" - }' \ - "$JFROG_URL/access/api/v1/applications" - -# Bind packages to the application -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "application_name": "my-web-app", - "packages": [ - {"name": "my-web-app", "version": "1.0.0", "repo": "docker-local", "type": "docker"} - ] - }' \ - "$JFROG_URL/access/api/v1/applications/my-web-app/versions" -``` - ---- - -## 2. Application Risk Governance (`app-trust-application-risk-management`) [SIMPLE, ~6 min] - -**Purpose:** Define and govern your SDLC with evidence-based policy gates. - -**Architecture:** - -```mermaid -flowchart LR - AV["Application Version"] --> DEV["DEV"] - DEV -->|"Gate Check\n+ Evidence"| QA["QA"] - QA -->|"Gate Check\n+ Evidence"| PROD["PROD"] - PROD --> Badge["Trusted Release"] -``` - -**How It Works:** -1. Define lifecycle stages (DEV → QA → PROD) -2. Define policy gates at each stage boundary (what evidence is required) -3. Application versions must satisfy all gate requirements to advance -4. Versions that pass all gates earn a "Trusted Release" badge - -**JFrog Concepts:** Application Entity, Application Versions, Evidence-based Gates, Trusted Release - -**Implementation:** -```bash -# Create lifecycle stages -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name": "Development", "order": 1}' \ - "$JFROG_URL/access/api/v2/stages/" - -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name": "QA", "order": 2}' \ - "$JFROG_URL/access/api/v2/stages/" - -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name": "Production", "order": 3}' \ - "$JFROG_URL/access/api/v2/stages/" - -# Create lifecycle policy with evidence-based gates -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "standard-release-policy", - "description": "Requires security scan and test evidence at each gate", - "stages": ["Development", "QA", "Production"], - "gates": [ - { - "from_stage": "Development", - "to_stage": "QA", - "required_evidence": ["security-scan", "unit-tests"] - }, - { - "from_stage": "QA", - "to_stage": "Production", - "required_evidence": ["integration-tests", "performance-tests", "security-review"] - } - ] - }' \ - "$JFROG_URL/access/api/v1/lifecycle-policies" - -# Attach evidence at each stage (using jf evd create) -jf evd create \ - --package-name my-web-app --package-version 1.0.0 --package-repo-name docker-local \ - --key "$PRIVATE_KEY" \ - --predicate ./test-results.json \ - --predicate-type https://jfrog.com/evidence/test-result/v1 -``` - -**Docs:** [AppTrust REST APIs](https://jfrog.com/help/r/jfrog-rest-apis/apptrust-rest-apis) diff --git a/plugins/jfrog/skills/jfrog/patterns-ci-integration.md b/plugins/jfrog/skills/jfrog/patterns-ci-integration.md deleted file mode 100644 index c8fac94..0000000 --- a/plugins/jfrog/skills/jfrog/patterns-ci-integration.md +++ /dev/null @@ -1,132 +0,0 @@ -# CI Integration Patterns - -## 1. CI Integration (`builds-ci-integration`) [SIMPLE] - -**Purpose:** Integrate JFrog with any CI tool to cache dependencies, store build artifacts, and collect Build Info metadata. - -**Architecture:** - -```mermaid -flowchart LR - CI["CI Tool"] --> CLI["JFrog CLI"] - CLI --> Virtual["Virtual Repo"] - Virtual --> Remote["Remote Repo\n(cache)"] - Virtual --> Local["Local Repo\n(1st party)"] - CLI --> BuildInfo["Build Info\n(published)"] -``` - -**JFrog Concepts:** Virtual Repository, Remote Repository, Local Repository, Build Info - -**Setup Creates:** Project + local repository + remote repository + virtual repository + CI tool configuration - -**Implementation:** -```bash -# 1. Create repos (jfrog-artifactory skill) -jf rt repo-create local-repo-template.json # local for your artifacts -jf rt repo-create remote-repo-template.json # remote to cache public deps -jf rt repo-create virtual-repo-template.json # virtual to unify both - -# 2. Configure CI build integration -jf npmc --repo-resolve=npm-virtual --repo-deploy=npm-local # npm example -jf npm install --build-name=my-build --build-number=$BUILD_NUM -jf npm publish --build-name=my-build --build-number=$BUILD_NUM - -# 3. Publish Build Info -jf rt build-collect-env my-build $BUILD_NUM -jf rt build-add-git my-build $BUILD_NUM -jf rt build-publish my-build $BUILD_NUM -``` - -**Docs:** [Build Integration](https://jfrog.com/help/r/jfrog-integrations-documentation/build-integration) - ---- - -## 2. CI Integration with Security Scans & SBOM (`builds-ci-integration-with-security-scans`) [INTERMEDIATE] - -**Purpose:** Same as above + continuous artifact scanning + automatic SBOM generation. - -**Additional:** Xray scans complete packages/images upon upload; generates SBOM from Build Info. - -**JFrog Concepts:** All above + Security Policies, Watches - -**Setup Creates:** Project + repos + Xray policies + watches - -**Implementation (additions to pattern 1):** -```bash -# 4. Create security policy (jfrog-security skill) -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name":"ci-security","type":"security","rules":[{"name":"block-critical","criteria":{"min_severity":"Critical"},"actions":{"fail_build":true}}]}' \ - "$JFROG_URL/xray/api/v2/policies" - -# 5. Create watch linking repos to policy -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"general_data":{"name":"ci-watch","active":true},"project_resources":{"resources":[{"type":"repository","name":"npm-local"}]},"assigned_policies":[{"name":"ci-security","type":"security"}]}' \ - "$JFROG_URL/xray/api/v2/watches" - -# 6. Scan build (automatically or on-demand) -jf rt build-scan my-build $BUILD_NUM --fail=true -``` - ---- - -## 3. CI Integration with Curation + Security Scans (`builds-ci-integration-with-package-curation-and-security-scans`) [ADVANCED] - -**Purpose:** Same as above + block risky 3rd-party packages before they enter the organization. - -**Additional:** JFrog Curation validates dependencies against org security criteria before caching. - -**JFrog Concepts:** All above + Curation - -**Requires:** Curation activation on your JFrog instance. - -**Implementation (additions to pattern 2):** -```bash -# 7. Enable curation on remote repos (jfrog-curation skill) -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"repo_key":"npm-remote","enabled":true}' \ - "$JFROG_URL/curation/api/v1/curated_repos/npm-remote" - -# 8. Create curation policy -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name":"block-malicious","enabled":true,"conditions":[{"type":"malicious_package"},{"type":"cvss_score","min_severity":9.0}],"repositories":["npm-remote"],"action":"block"}' \ - "$JFROG_URL/curation/api/v1/policies" - -# 9. Audit project against curation policies -jf curation-audit -``` - ---- - -## 4. CI Integration with Evidence Collection (`builds-ci-integration-with-evidence-collection`) [ADVANCED] - -**Purpose:** Same as CI Integration + gather and attach signed evidence to document the SDLC process. - -**Additional:** JFrog CLI collects evidence during builds; used for auditing and compliance. - -**JFrog Concepts:** All above + Evidence - -**Implementation (additions to pattern 1):** -```bash -# 10. Prepare predicate JSON -echo '{"actor":"ci-bot","date":"'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'","result":"pass"}' > predicate.json - -# 11. Attach evidence to package (jfrog-cli / jfrog-distribution skill) -jf evd create \ - --package-name my-app --package-version $VERSION --package-repo-name npm-local \ - --key "$PRIVATE_KEY" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/signature/v1 - -# 12. Attach evidence to build -jf evd create \ - --build-name my-build --build-number $BUILD_NUM \ - --key "$PRIVATE_KEY" \ - --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/build-signature/v1 -``` - -**Docs:** [Evidence Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/evidence-management), [Evidence Examples](https://github.com/jfrog/Evidence-Examples) diff --git a/plugins/jfrog/skills/jfrog/patterns-journeys.md b/plugins/jfrog/skills/jfrog/patterns-journeys.md deleted file mode 100644 index 3f2c38d..0000000 --- a/plugins/jfrog/skills/jfrog/patterns-journeys.md +++ /dev/null @@ -1,128 +0,0 @@ -# User Journeys -- Goal-Oriented Pattern Selection Guide - -5 journeys to help you pick the right patterns based on your goals. - -## Journey 1: Modernize Delivery - -**Goal:** Unify artifact management and automate CI/CD from dev to deployment. - -### Step 1: Unify and Control All Artifacts -- Centralize all packages and dependencies into one trusted source -- 40+ package types, intelligent caching, local/remote/virtual repos -- **Use patterns:** `repositories-basic-repository-setup`, `repositories-dependency-resolution-from-multiple-upstream-sources` - -### Step 2: Enhance CI/CD Automation -- Automate linking between CI systems and artifact storage -- Full DevOps toolchain compatibility, JFrog CLI, REST API -- **Use patterns:** `builds-ci-integration-with-security-scans`, `builds-ci-integration-with-package-curation-and-security-scans` - -### Step 3: Govern the Release Lifecycle -- Track every artifact across the supply chain from dev to deployment -- Integrated SCA, automated SBOM generation, Build Info and Evidence -- **Use patterns:** `release-lifecycle-management-without-security-gates`, `release-lifecycle-with-security-gates` - -### Step 4: Deliver to Any Runtime Endpoint -- Automate rollout of trusted software to any runtime (cloud to edge) -- Global CDN distribution, atomic Kubernetes deployment -- **Use patterns:** `repositories-setup-for-cross-team-collaboration`, multi-site patterns - ---- - -## Journey 2: Secure SDLC - -**Goal:** Protect the software supply chain at every stage. - -### Step 1: Block Risks Before They Enter -- Secure supply chain at entry point with JFrog Curation -- Automated security gate for 3rd party risk, JFrog Catalog for OSS selection -- **Use patterns:** `curation-security` - -### Step 2: Secure Binaries with SCA and SBOMs -- Deep binary analysis and risk prevention with Xray -- SCA scanning, automatic SBOM generation -- **Use patterns:** `xray-security` - -### Step 3: Fortify Your Code, Remediate Efficiently -- Prioritize real exploitable risks; shift left with SAST and Secrets scanners -- JFrog SAST, Contextual Analysis, Runtime monitoring -- **Use patterns:** `jas-security`, `run-time-security` - ---- - -## Journey 3: Accelerate Productivity - -**Goal:** Reduce developer friction and speed up delivery. - -### Step 1: Shorten Build Cycles -- Reduce developer downtime via dependency caching and early security identification -- Reliable dependency delivery, complete build automation -- **Use patterns:** `builds-ci-integration` - -### Step 2: Simplify Security Overload -- Consolidate security solutions to eliminate friction -- Pre-approved packages (Curation), security noise reduction (Contextual Analysis) -- **Use patterns:** `curation-security`, `xray-security` - -### Step 3: Eliminate Context Switching -- Consolidate all context directly into the developer's IDE/workspace -- MCP + CLI + GitHub integration, unified security toolchain -- **Use patterns:** `run-time-security` - -### Step 4: Automate New Package Approvals -- Automate OSS package review/approval with full auditability -- Policy-driven approval automation, curated OSS catalog -- **Use patterns:** `curation-security`, `app-trust-application-risk-management` - ---- - -## Journey 4: Tackle Enterprise Complexity - -**Goal:** Scale JFrog across a global, complex organization. - -### Step 1: Achieve Architectural Agility -- Develop and deliver across any topology (SaaS, self-managed, hybrid, air-gapped) -- 99.9%+ uptime, global high-resilience sync -- **Use patterns:** `multi-site-active-active-with-geo-dns`, `multi-site-active-standby-with-dns-failover` - -### Step 2: Manage Scaling Infrastructure -- Unify identity, authorization, and project management at enterprise scale -- Projects for resource isolation, centralized IAM (SSO/RBAC) -- **Use patterns:** `repositories-setup-for-cross-team-collaboration`, `repositories-dependency-resolution-from-multiple-upstream-sources`, `release-lifecycle-with-evidence` - -### Step 3: Establish Enterprise Governance -- Unified compliance framework across the entire SDLC -- End-to-end audit trail, proactive risk governance -- **Use patterns:** `app-trust-application-entity-creation`, `app-trust-application-risk-management` - -### Step 4: Optimize Global Distribution -- Fast, trusted software releases worldwide -- Flexible distribution, immutable Release Bundles with SBOMs -- **Use patterns:** `release-lifecycle-management-with-build-integration-security-gates-and-distribution`, `multi-site-partially-air-gapped-package-curation`, `multi-site-fully-air-gapped-package-curation` - ---- - -## Journey 5: Deliver Trusted AI - -**Goal:** Manage AI/ML assets from development to production. - -### Step 1: Centralize & Govern AI Assets -- Unify all AI assets (models, datasets, MCP servers) into one hub -- Unified AI Registry, Secure AI Gateway, proactive security scanning -- **Resources:** JFrog AI Catalog, JFrog ML product page - -### Step 2: Build & Deploy Models -- Bridge experimentation to production with FrogML SDK -- Model Registry, security scanning, automated deployment, A/B and Shadow Mode -- **Resources:** FrogML SDK, Model Registry documentation - -### Step 3: Monitor Model Performance -- Track real-time model health and detect data drift -- Real-time dashboard, automated drift detection (KL Divergence) -- **Resources:** JFrog ML monitoring documentation - -### Step 4: Turn Data Into Features -- Transform raw data into ML features with consistent training/serving -- SQL transformations (Spark SQL), automated materialization -- **Resources:** Feature Store documentation - -> Note: Journey 5 primarily uses JFrog ML features and documentation links rather than the pattern system. Use the JFrog Artifactory skill for storing ML model artifacts (Generic or Docker repos). diff --git a/plugins/jfrog/skills/jfrog/patterns-multi-site.md b/plugins/jfrog/skills/jfrog/patterns-multi-site.md deleted file mode 100644 index d1460b4..0000000 --- a/plugins/jfrog/skills/jfrog/patterns-multi-site.md +++ /dev/null @@ -1,157 +0,0 @@ -# Multi-Site Architecture Patterns - -All multi-site patterns are **ADVANCED** and require multiple JFrog Platform Deployments (JPDs). - -## 1. Active/Standby with DNS Failover (`multi-site-active-standby-with-dns-failover`) - -**Purpose:** High availability with seamless failover using synced sites via load balancer. - -**Architecture:** - -```mermaid -flowchart TD - LB["Load Balancer\n(DNS failover)"] - LB --> Active["Active JPD\n(read + write)"] - LB --> Standby["Standby JPD\n(synced, read-only)"] - Active <-->|"Federated Repos\n+ Access Federation"| Standby -``` - -- Active and Standby JPDs sync repo data + access settings via Federated Repos and Access Federation -- Load balancer redirects traffic on failure -- Admins can switch active site via UI - -**JFrog Concepts:** Federated Repositories, Access Federation - -**Implementation:** -```bash -# On Active JPD: Create federated repo (replace with the other JPD base URL) -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"shared-docker","rclass":"federated","packageType":"docker","members":[{"url":"https:///artifactory/shared-docker","enabled":true}]}' \ - "$JFROG_URL/artifactory/api/repositories/shared-docker" - -# Set up Access Federation (circle of trust) -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"url":"https://","name":"standby-jpd"}' \ - "$JFROG_URL/access/api/v1/federation/circle_of_trust" -``` - ---- - -## 2. Active/Active with Geo DNS (`multi-site-active-active-with-geo-dns`) - -**Purpose:** Seamless global collaboration using synced sites with geographic routing. - -**Architecture:** - -```mermaid -flowchart TD - LB["Geo-aware Load Balancer"] - LB --> USEast["JPD US-East\n(read + write)"] - LB --> EUWest["JPD EU-West\n(read + write)"] - USEast <-->|"Bi-directional Sync"| EUWest -``` - -- Both sites are active, handling reads and writes -- Load balancer routes to geographically closest site -- Bi-directional federated repo sync ensures real-time collaboration - -**Implementation:** Same as Active/Standby but with bi-directional federation on both JPDs. Both members are set as `enabled: true` with full read/write. - ---- - -## 3. CI and CD Separation (`multi-site-with-ci-cd-separation`) - -**Purpose:** Multiple independent CI sites connected to a centralized CD hub. - -**Architecture:** - -```mermaid -flowchart LR - BU1["BU-1 CI JPD"] --> CD["CD JPD\n(centralized releases)"] - BU2["BU-2 CI JPD"] --> CD - BU3["BU-3 CI JPD"] --> CD - CD --> Edge["Distribution\nto Edge"] -``` - -- Business units have independent CI JPDs for development -- Production-ready releases sync to CD site via federated repos -- Ops manage releases centrally from the CD JPD - ---- - -## 4. Partially Air-Gapped Package Curation (`multi-site-partially-air-gapped-package-curation`) - -**Purpose:** OSS dependency control with one-way connectivity (egress only). - -**Architecture:** - -```mermaid -flowchart LR - AG["Air-gapped JPD\n(egress-only)"] --> DMZ["DMZ JPD\n(bridge)"] - DMZ -->|Curation| Public["Public Registry\n(npm, PyPI, etc.)"] -``` - -- Air-gapped JPD has remote repos pointing to DMZ JPD -- DMZ JPD's remote repos go through Curation before fetching from public registries -- Packages cached at both levels -- Developer tracked as requester in audit - -**Implementation:** -```bash -# On DMZ JPD: Create curated remote repo -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN_DMZ" \ - -H "Content-Type: application/json" \ - -d '{"key":"npm-curated","rclass":"remote","packageType":"npm","url":"https://registry.npmjs.org"}' \ - "$DMZ_URL/artifactory/api/repositories/npm-curated" - -# Enable curation on DMZ remote -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN_DMZ" \ - -H "Content-Type: application/json" \ - -d '{"repo_key":"npm-curated","enabled":true}' \ - "$DMZ_URL/curation/api/v1/curated_repos/npm-curated" - -# On Air-gapped JPD: Remote repo pointing to DMZ -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN_AG" \ - -H "Content-Type: application/json" \ - -d '{"key":"npm-remote","rclass":"remote","packageType":"npm","url":"https:///artifactory/npm-curated"}' \ - "$AIRGAP_URL/artifactory/api/repositories/npm-remote" -``` - ---- - -## 5. Fully Air-Gapped Package Curation (`multi-site-fully-air-gapped-package-curation`) - -**Purpose:** OSS dependency control with zero network connectivity. - -**Architecture:** - -```mermaid -flowchart LR - Dev["Developer\n(air-gapped)"] -->|Submit Ticket| Admin["DMZ Admin"] - Admin -->|Fetch + Curate| Export["Export to\nPhysical Storage"] - Export --> Import["Import to\nAir-gapped Local Repo"] -``` - -**Workflow:** -1. Developer submits ticket for needed packages -2. DMZ admin triggers fetch through Curation -3. Curation validates against policies -4. Approved packages exported to physical media or secure transfer -5. Packages imported into air-gapped JPD's local repository - -**Implementation:** -```bash -# On DMZ: Fetch and validate packages (automated or manual) -# Export approved packages -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN_DMZ" \ - -O "$DMZ_URL/artifactory/npm-curated/lodash/-/lodash-4.17.21.tgz" - -# Physical transfer to air-gapped network... - -# On Air-gapped JPD: Import to local repo -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN_AG" \ - -T lodash-4.17.21.tgz \ - "$AIRGAP_URL/artifactory/npm-local/lodash/-/lodash-4.17.21.tgz" -``` diff --git a/plugins/jfrog/skills/jfrog/patterns-reference.md b/plugins/jfrog/skills/jfrog/patterns-reference.md deleted file mode 100644 index 4b5fb2a..0000000 --- a/plugins/jfrog/skills/jfrog/patterns-reference.md +++ /dev/null @@ -1,102 +0,0 @@ -# Patterns Reference - -## What Are Patterns? - -Patterns are recommended architectural setups for the JFrog Platform. Each pattern describes: - -- **What problem it solves** and the architecture -- **JFrog concepts** involved (repos, policies, builds, etc.) -- **Difficulty level** (SIMPLE -> INTERMEDIATE -> ADVANCED) -- **What gets created** when the setup wizard runs (repos, policies, watches, projects) -- **Which skills to use** for API/CLI implementation - -## Pattern Catalog (22 patterns in 6 categories) - -| Category | Patterns | Levels | -|----------|----------|--------| -| [CI Integration](patterns-ci-integration.md) | 4 patterns | SIMPLE to ADVANCED | -| [Repositories](patterns-repositories.md) | 3 patterns | SIMPLE to ADVANCED | -| [Supply Chain Security](patterns-supply-chain-security.md) | 4 patterns | INTERMEDIATE to ADVANCED | -| [Release Lifecycle](patterns-release-lifecycle.md) | 4 patterns | SIMPLE to ADVANCED | -| [Multi-Site Architecture](patterns-multi-site.md) | 5 patterns | All ADVANCED | -| [AppTrust](patterns-apptrust.md) | 2 patterns | Both SIMPLE | - -## Which Pattern Should I Use? - -Use the 5 user journeys to pick the right patterns. See [patterns-journeys.md](patterns-journeys.md) for the full guide. - -| If your goal is... | Start with... | -|---------------------|---------------| -| Centralize artifacts and automate CI/CD | CI Integration + Basic Repo Setup | -| Secure the software supply chain | Xray Security + Curation Security | -| Accelerate developer productivity | CI Integration + Curation + Contextual Analysis | -| Handle enterprise-scale multi-site | Multi-Site Active/Active or Active/Standby | -| Govern releases with compliance | Release Lifecycle + Evidence + AppTrust | -| Deploy trusted AI models | Journey 5 in [patterns-journeys.md](patterns-journeys.md) | - -## Difficulty Progression - -Start at SIMPLE, build up: - -``` -SIMPLE INTERMEDIATE ADVANCED -├── CI Integration ├── CI + Security Scans ├── CI + Curation + Scans -├── Basic Repo Setup ├── Multi-Source Deps ├── Cross-Team Collaboration -├── RLM (no gates) ├── RLM + Security Gates ├── RLM + Distribution -├── AppTrust Entity ├── Xray Security ├── JAS Advanced Security -└── AppTrust Risk Mgmt └── RLM + Security Gates ├── Runtime Security - ├── Curation Enforcement - ├── CI + Evidence - ├── RLM + Evidence - └── Multi-Site (5 patterns) -``` - -## JFrog Concepts Glossary - -| Concept | Definition | -|---------|-----------| -| **Build Info** | Metadata collected by JFrog CLI during CI -- environment params, artifacts, components, SBOM | -| **Remote Repository** | Caches and proxies packages from a public/private registry | -| **Local Repository** | Hosts 1st-party artifacts deployed by your team | -| **Virtual Repository** | Logical router for a set of repos, single URL with priority resolution | -| **Federated Repository** | Mirrors artifacts and metadata across JFrog Platform Deployments (JPDs) | -| **Release Bundle** | Immutable, GPG-signed grouping of files/packages for a software release | -| **Environments** | SDLC stage aggregations (DEV, STAGING, PROD) for release promotion | -| **Distribution** | Securely distributes release binaries to Edge nodes | -| **Evidence** | Signed attestation metadata (DSSE format) for artifacts, builds, and Release Bundles | -| **Curation** | Package firewall that blocks malicious/risky OSS before it enters your Artifactory | -| **Security Policy** | Rules for security, operational risk, and license compliance with automated actions | -| **Access Federation** | Synchronizes users, groups, permissions, and tokens across federated JPDs | -| **Contextual Analysis** | Assesses whether detected CVEs are actually exploitable in your specific context | -| **SAST** | Static Application Security Testing for source code vulnerabilities | -| **Image Integrity** | Verifies container images haven't been tampered with at runtime | -| **Runtime Sensor/Controller** | Lightweight Kubernetes agents for real-time monitoring and policy enforcement | -| **Application Entity** | Business-context wrapper for packages with ownership, criticality, and lifecycle stages | - -## Implementing Patterns with Skills - -Each pattern maps to operations in the atomic product skills: - -| Pattern operations | Use skill | -|-------------------|-----------| -| Create repos (local/remote/virtual) | `jfrog-artifactory` or `jfrog-cli` | -| Create projects, users, permissions | `jfrog-access` | -| Create Xray policies and watches | `jfrog-security` | -| Configure curation policies | `jfrog-curation` | -| Create release bundles, promote, distribute | `jfrog-distribution` | -| Attach evidence to artifacts/builds/bundles | `jfrog-distribution` (evidence section) or `jfrog-cli` | -| Deploy Workers for custom logic | `jfrog-workers` | -| Set up federated repos, access federation | `jfrog-artifactory` + `jfrog-access` | -| Create AppTrust applications and policies | `jfrog-apptrust` + `jfrog-access` | -| Monitor Kubernetes runtime | `jfrog-security` (runtime section) | - -## Reference Files - -- [patterns-ci-integration.md](patterns-ci-integration.md) -- 4 CI Integration patterns -- [patterns-repositories.md](patterns-repositories.md) -- 3 Repository setup patterns -- [patterns-supply-chain-security.md](patterns-supply-chain-security.md) -- 4 Security patterns -- [patterns-release-lifecycle.md](patterns-release-lifecycle.md) -- 4 Release Lifecycle patterns -- [patterns-multi-site.md](patterns-multi-site.md) -- 5 Multi-Site Architecture patterns -- [patterns-apptrust.md](patterns-apptrust.md) -- 2 AppTrust patterns -- [patterns-journeys.md](patterns-journeys.md) -- 5 user journeys (goal-oriented pattern selection) -- [flow-suggestions.md](flow-suggestions.md) -- Action-to-flow mapping with progress diagrams for post-interaction suggestions diff --git a/plugins/jfrog/skills/jfrog/patterns-release-lifecycle.md b/plugins/jfrog/skills/jfrog/patterns-release-lifecycle.md deleted file mode 100644 index 88efbd3..0000000 --- a/plugins/jfrog/skills/jfrog/patterns-release-lifecycle.md +++ /dev/null @@ -1,136 +0,0 @@ -# Release Lifecycle Patterns - -## 1. Release Lifecycle Management (without Security Gates) (`release-lifecycle-management-without-security-gates`) [SIMPLE] - -**Purpose:** Turn CI outputs into immutable releases and advance them through SDLC stages. - -**Architecture:** - -```mermaid -flowchart LR - CI["CI Build"] --> BI["Build Info"] --> RB["Release Bundle\n(GPG-signed)"] - RB --> DEV["DEV"] --> STAGING["STAGING"] --> PROD["PROD"] -``` - -**JFrog Concepts:** Release Bundle (immutable, GPG-signed), Environments (DEV/STAGE/PROD), Build Info - -**Implementation:** -```bash -# 1. Publish build info (from CI) -jf rt build-publish my-app $BUILD_NUM - -# 2. Create immutable Release Bundle from build -jf release-bundle-create my-app-release 1.0.0 \ - --builds="my-app/$BUILD_NUM" \ - --signing-key=my-gpg-key --sync=true - -# 3. Promote through environments -jf release-bundle-promote my-app-release 1.0.0 --environment=DEV -jf release-bundle-promote my-app-release 1.0.0 --environment=STAGING -jf release-bundle-promote my-app-release 1.0.0 --environment=PROD -``` - -**Docs:** [Release Lifecycle Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/release-lifecycle-management) - ---- - -## 2. Release Lifecycle with Security Gates (`release-lifecycle-with-security-gates`) [INTERMEDIATE] - -**Purpose:** Same as above + security scanning before promotion between stages. Violations block promotion. - -**Architecture:** - -```mermaid -flowchart LR - RB["Release Bundle"] -->|"Xray Scan"| DEV["DEV"] - DEV -->|"Xray Scan"| STAGING["STAGING"] - STAGING -->|"Xray Scan"| PROD["PROD"] - DEV -.->|Fail| Block1["Blocked"] - STAGING -.->|Fail| Block2["Blocked"] -``` - -**Implementation (additions to pattern 1):** -```bash -# Create Xray policy that blocks release bundle promotion -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name":"release-gate","type":"security","rules":[{"name":"block-high","criteria":{"min_severity":"High"},"actions":{"block_release_bundle_distribution":true,"fail_build":true}}]}' \ - "$JFROG_URL/xray/api/v2/policies" - -# Create watch on release bundles -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"general_data":{"name":"release-watch","active":true},"project_resources":{"resources":[{"type":"all-release-bundles"}]},"assigned_policies":[{"name":"release-gate","type":"security"}]}' \ - "$JFROG_URL/xray/api/v2/watches" - -# Promotion will be blocked if violations are found -jf release-bundle-promote my-app-release 1.0.0 --environment=PROD -``` - ---- - -## 3. Release Lifecycle with Security Gates & Distribution (`release-lifecycle-management-with-build-integration-security-gates-and-distribution`) [ADVANCED] - -**Purpose:** Same as above + Distribution delivers immutable Release Bundles to Edge nodes. - -**Requires:** Distribution activation on your JFrog instance. - -**Architecture:** - -```mermaid -flowchart LR - RB["Release Bundle"] -->|Scan| DEV["DEV"] --> STAGING["STAGING"] --> PROD["PROD"] - PROD --> Edge1["Edge US-East"] - PROD --> Edge2["Edge EU-West"] -``` - -**Implementation (additions to pattern 2):** -```bash -# Distribute to edge nodes -jf release-bundle-distribute my-app-release 1.0.0 \ - --site="edge-*" --sync=true - -# Or via REST API -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"auto_create_missing_repositories":true,"distribution_rules":[{"site_name":"edge-us-east"},{"site_name":"edge-eu-west"}]}' \ - "$JFROG_URL/distribution/api/v1/distribution/my-app-release/1.0.0" -``` - ---- - -## 4. Release Lifecycle with Evidence (`release-lifecycle-with-evidence`) [ADVANCED] - -**Purpose:** Same as above + signed attestation evidence attached at every stage for compliance. - -**Evidence Chain:** - -```mermaid -flowchart LR - Art["Build Artifact"] -->|Evidence| Build["Publish Build"] - Build -->|Evidence| RB["Release Bundle"] - RB -->|Evidence| Promote["Promote"] - Promote -->|Evidence| Trusted["Trusted Release"] -``` - -**Implementation (additions to pattern 1):** -```bash -echo '{"actor":"ci-bot","date":"'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"}' > predicate.json - -# Evidence on package -jf evd create --package-name my-app --package-version 1.0 --package-repo-name docker-local \ - --key "$PRIVATE_KEY" --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/signature/v1 - -# Evidence on build -jf evd create --build-name my-app --build-number $BUILD_NUM \ - --key "$PRIVATE_KEY" --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/build-signature/v1 - -# Evidence on release bundle -jf evd create --release-bundle my-app-release --release-bundle-version 1.0.0 \ - --key "$PRIVATE_KEY" --predicate ./predicate.json \ - --predicate-type https://jfrog.com/evidence/rbv2-signature/v1 -``` - -**Docs:** [Evidence Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/evidence-management), [Evidence Examples](https://github.com/jfrog/Evidence-Examples) diff --git a/plugins/jfrog/skills/jfrog/patterns-repositories.md b/plugins/jfrog/skills/jfrog/patterns-repositories.md deleted file mode 100644 index 954b383..0000000 --- a/plugins/jfrog/skills/jfrog/patterns-repositories.md +++ /dev/null @@ -1,122 +0,0 @@ -# Repository Setup Patterns - -## 1. Basic Repository Setup (`repositories-basic-repository-setup`) [SIMPLE] - -**Purpose:** Single endpoint to resolve 3rd-party dependencies and deploy 1st-party packages. - -**Architecture:** - -```mermaid -flowchart LR - Dev["Developer"] --> Virtual["Virtual Repo"] - Virtual --> Remote["Remote Repo\n(public cache)"] - Virtual --> Local["Local Repo\n(your artifacts)"] -``` - -Dependencies are cached on first fetch for faster future resolution. - -**Setup Creates:** Project + local + remote + virtual repositories for chosen package type. - -**Implementation:** -```bash -# Create local repo for your artifacts -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"npm-local","rclass":"local","packageType":"npm"}' \ - "$JFROG_URL/artifactory/api/repositories/npm-local" - -# Create remote repo to cache public packages -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"npm-remote","rclass":"remote","packageType":"npm","url":"https://registry.npmjs.org"}' \ - "$JFROG_URL/artifactory/api/repositories/npm-remote" - -# Create virtual repo combining both -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"npm","rclass":"virtual","packageType":"npm","repositories":["npm-local","npm-remote"],"defaultDeploymentRepo":"npm-local"}' \ - "$JFROG_URL/artifactory/api/repositories/npm" -``` - -**Docs:** [Repository Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/repository-management) - ---- - -## 2. Dependency Resolution from Multiple Upstream Sources (`repositories-dependency-resolution-from-multiple-upstream-sources`) [INTERMEDIATE] - -**Purpose:** Pull dependencies from multiple sources with prioritization through a single access point. - -**Architecture:** - -```mermaid -flowchart LR - Dev["Developer"] --> Virtual["Virtual Repo"] - Virtual --> RemoteA["Remote A\n(priority 1)"] - Virtual --> RemoteB["Remote B\n(priority 2)"] - Virtual --> RemoteC["Remote C\n(priority 3)"] -``` - -Virtual repo tries remotes in priority order until the dependency is found, then caches for future. - -**Implementation:** -```bash -# Create multiple remote repos -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"npm-remote-internal","rclass":"remote","packageType":"npm","url":"https://internal-registry.company.com"}' \ - "$JFROG_URL/artifactory/api/repositories/npm-remote-internal" - -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"npm-remote-public","rclass":"remote","packageType":"npm","url":"https://registry.npmjs.org"}' \ - "$JFROG_URL/artifactory/api/repositories/npm-remote-public" - -# Virtual with priority order (array order = priority) -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"npm","rclass":"virtual","packageType":"npm","repositories":["npm-local","npm-remote-internal","npm-remote-public"],"defaultDeploymentRepo":"npm-local"}' \ - "$JFROG_URL/artifactory/api/repositories/npm" -``` - ---- - -## 3. Setup for Cross-Team Collaboration (`repositories-setup-for-cross-team-collaboration`) [ADVANCED] - -**Purpose:** Share certain resources between teams while keeping others dedicated per team. - -**Architecture:** - -```mermaid -flowchart LR - TeamA["Team A"] --> LocalA["npm-team-a-local"] - TeamB["Team B"] --> LocalB["npm-team-b-local"] - TeamC["Team C"] --> LocalC["npm-team-c-local"] - LocalA --> Virtual["npm-virtual\n(shared read, scoped write)"] - LocalB --> Virtual - LocalC --> Virtual -``` - -All teams use the same virtual repo URL. Permissions control who deploys where. Each team has its own local repo but can read from all. - -**Implementation:** -```bash -# Create per-team local repos -for team in team-a team-b team-c; do - curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"key\":\"npm-${team}-local\",\"rclass\":\"local\",\"packageType\":\"npm\"}" \ - "$JFROG_URL/artifactory/api/repositories/npm-${team}-local" -done - -# Virtual combining all -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"key":"npm","rclass":"virtual","packageType":"npm","repositories":["npm-team-a-local","npm-team-b-local","npm-team-c-local","npm-remote"]}' \ - "$JFROG_URL/artifactory/api/repositories/npm" - -# Permissions per team (jfrog-access skill) -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name":"team-a-deploy","resources":{"repository":{"targets":[{"name":"npm-team-a-local"}],"actions":["read","write","annotate"]}},"principals":{"groups":[{"name":"team-a","permissions":["read","write","annotate"]}]}}' \ - "$JFROG_URL/access/api/v2/permissions" -``` diff --git a/plugins/jfrog/skills/jfrog/patterns-supply-chain-security.md b/plugins/jfrog/skills/jfrog/patterns-supply-chain-security.md deleted file mode 100644 index 31af7a0..0000000 --- a/plugins/jfrog/skills/jfrog/patterns-supply-chain-security.md +++ /dev/null @@ -1,153 +0,0 @@ -# Supply Chain Security Patterns - -## 1. Secure Your Supply Chain with Xray (`xray-security`) [INTERMEDIATE] - -**Purpose:** Detect, prioritize, and remediate open source risks across the entire SDLC. - -**Architecture:** - -```mermaid -flowchart LR - IDE["IDE\n(JFrog plugin)"] --> PR["PR\n(Frogbot)"] --> Build["Build / Binary\n(Xray scan)"] --> Monitor["Continuous\nMonitoring"] -``` - -**SDLC Stages Covered:** -1. **IDE** -- real-time scanning via JFrog plugin -2. **PR** -- Frogbot scans pull requests before merge -3. **Build/Binary** -- Xray scans after build publish -4. **Continuous Monitoring** -- ongoing scanning for new CVEs on indexed repos - -**Risk Types:** Malicious Package, Software Vulnerability, License Risk, Operational Risk - -**Implementation:** -```bash -# Create security policy -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name":"sdlc-security","type":"security","rules":[{"name":"block-high","criteria":{"min_severity":"High"},"actions":{"fail_build":true,"block_download":{"active":true}}}]}' \ - "$JFROG_URL/xray/api/v2/policies" - -# Create watch on production repos -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"general_data":{"name":"sdlc-watch","active":true},"project_resources":{"resources":[{"type":"all-repos"}]},"assigned_policies":[{"name":"sdlc-security","type":"security"}]}' \ - "$JFROG_URL/xray/api/v2/watches" - -# CLI scanning in CI -jf audit --fail=true --min-severity=High -``` - -**Docs:** [Xray](https://jfrog.com/help/r/jfrog-security-user-guide/products/xray) - ---- - -## 2. JFrog Advanced Security (`jas-security`) [ADVANCED] - -**Purpose:** Prioritize security risks and identify hidden exposure. Reduces noise by up to 80%. - -**Capabilities:** -- **Contextual Analysis** -- determines if CVEs are actually reachable/exploitable -- **Secrets Detection** -- finds leaked credentials in code and binaries -- **SAST** -- static analysis of source code -- **IaC Scanning** -- checks Terraform, CloudFormation, K8s YAML for misconfigurations -- **App Config Exposures** -- detects insecure application settings - -**Implementation:** -```bash -# JAS features are enabled at system level and apply to all Xray scans -# Use CLI with JAS flags for scanning -jf audit --sast --secrets --iac - -# Results include applicability field for each CVE: -# "applicable", "not_applicable", or "undetermined" -``` - -**Docs:** [Advanced Security](https://jfrog.com/help/r/jfrog-security-user-guide/products/advanced-security) - ---- - -## 3. Runtime Security Monitoring (`run-time-security`) [ADVANCED] - -**Purpose:** Monitor Kubernetes deployments for real-time security threats. - -**Capabilities:** -- Real-time alerts for unauthorized images -- Impact assessment when new CVEs are announced -- Image lineage tracing back to build owner - -**JFrog Concepts:** Image Integrity, Runtime Sensor, Runtime Controller, Package Lineage - -**Requires:** Runtime activation on your JFrog instance. - -**Implementation:** -```bash -# Get registration token (jfrog-security skill) -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/runtime/api/v1/registration-token" - -# Deploy Runtime Sensor in K8s cluster (uses the token) -# List monitored clusters -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"limit":10}' \ - "$JFROG_URL/runtime/api/v1/clusters" - -# List workloads -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"limit":10}' \ - "$JFROG_URL/runtime/api/v1/workloads" -``` - -**Docs:** [Runtime](https://jfrog.com/help/r/jfrog-security-user-guide/products/runtime) - ---- - -## 4. Package Curation & Governance (`curation-security`) [ADVANCED] - -**Purpose:** Block risky packages before they enter the organization. - -**Architecture:** - -```mermaid -flowchart LR - Dev["Developer"] --> Remote["Remote Repo"] - Remote -->|"Curation Check"| Decision{"Policy"} - Decision -->|Pass| Cache["Cache + Allow"] - Decision -->|Fail| Block["Block"] -``` - -**How Blocking Works:** Pre-indexed catalog check (no download needed). Non-compliant dependencies are never stored. - -**Policy Enforcement:** -- Malicious packages -- Viral licenses (GPL, AGPL) -- Critical vulnerabilities (CVSS threshold) -- Outdated packages -- Unofficial Docker images - -**Requires:** Curation activation on your JFrog instance. - -**Implementation:** -```bash -# Enable curation on remote repos -curl -X PUT -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"repo_key":"npm-remote","enabled":true}' \ - "$JFROG_URL/curation/api/v1/curated_repos/npm-remote" - -# Create curation policies -curl -X POST -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{"name":"block-all-risks","enabled":true,"conditions":[{"type":"malicious_package"},{"type":"cvss_score","min_severity":9.0},{"type":"license","banned_licenses":["GPL-3.0","AGPL-3.0"]}],"repositories":["npm-remote","pypi-remote"],"action":"block"}' \ - "$JFROG_URL/curation/api/v1/policies" - -# Audit in CI -jf curation-audit - -# Review audit log -curl -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/curation/api/v1/audit?action=blocked&limit=25" -``` - -**Docs:** [Curation](https://jfrog.com/help/r/jfrog-security-user-guide/products/curation) diff --git a/plugins/jfrog/skills/jfrog/preflight.md b/plugins/jfrog/skills/jfrog/preflight.md deleted file mode 100644 index 72ccd49..0000000 --- a/plugins/jfrog/skills/jfrog/preflight.md +++ /dev/null @@ -1,63 +0,0 @@ -# Pre-flight Service Discovery - -Run this check **once per session** after login (Step 2 of [login-flow.md](login-flow.md)) to discover which JFrog services are available. This avoids wasting time calling APIs for services that are not deployed on the target instance. - -## When to Run - -- Before any multi-service workflow (onboarding, pattern setup, journey execution) -- After switching environments with `jf config use` -- When the user asks "what can I do?" and the agent needs to filter suggestions - -Skip this if the session only uses Artifactory (repos, artifacts, builds) -- Artifactory is always available. - -## Pre-flight Script - -Run all service pings in a **single parallel batch** (independent calls): - -```bash -# Artifactory version and admin check (always available) -curl -s "$JFROG_URL/artifactory/api/system/version" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" - -# Xray -curl -s -o /dev/null -w "%{http_code}" "$JFROG_URL/xray/api/v1/system/ping" - -# Lifecycle (Release Bundles / RLM) -curl -s -o /dev/null -w "%{http_code}" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/lifecycle/api/v2/promotion/records?limit=1" - -# AppTrust (requires explicit --server-id) -jf apptrust ping --server-id="$JFROG_SERVER_ID" 2>&1 - -# Curation -curl -s -o /dev/null -w "%{http_code}" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" \ - "$JFROG_URL/curation/api/v1/system/ping" - -# User admin status -curl -s "$JFROG_URL/artifactory/api/security/users/$USERNAME" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" - -# Existing projects -curl -s "$JFROG_URL/access/api/v1/projects" \ - -H "Authorization: Bearer $JFROG_ACCESS_TOKEN" -``` - -## Interpreting Results - -| Service | Available if | Variable to set | -|---------|-------------|-----------------| -| Artifactory | Ping returns `OK` (always expected) | -- | -| Xray | Ping returns HTTP 200 | `JFROG_HAS_XRAY=true` | -| Lifecycle | Returns HTTP 200 (even with empty results) | `JFROG_HAS_LIFECYCLE=true` | -| AppTrust | `jf apptrust ping --server-id` prints `OK` | `JFROG_HAS_APPTRUST=true` | -| Curation | Ping returns HTTP 200 | `JFROG_HAS_CURATION=true` | -| Admin | User JSON has `"admin": true` | `JFROG_IS_ADMIN=true` | - -## What to Do with Results - -1. **Report to the user** with a short summary table (service name + OK / NOT AVAILABLE). -2. **Filter downstream suggestions.** When using [flow-suggestions.md](flow-suggestions.md), only offer paths for available services. -3. **Stop early** if a required service is missing. Example: if the user asks for AppTrust setup but `JFROG_HAS_APPTRUST` is false, inform them immediately instead of attempting API calls. -4. **Note admin status.** Operations that create projects, users, or lifecycle stages require admin privileges. If `JFROG_IS_ADMIN` is false, warn the user before attempting privileged operations. diff --git a/plugins/jfrog/skills/jfrog/references/apptrust-entities.md b/plugins/jfrog/skills/jfrog/references/apptrust-entities.md new file mode 100644 index 0000000..6ca5088 --- /dev/null +++ b/plugins/jfrog/skills/jfrog/references/apptrust-entities.md @@ -0,0 +1,154 @@ +# AppTrust entities + +When to read this file: + +- Working with **applications**, **application versions**, or **releasables**. +- Querying or managing **application version promotions** through stages. +- Understanding what **sources** (builds, release bundles, other app versions) feed into an application version. +- Using the OneModel GraphQL API with the `applications` query root. + +AppTrust entities are accessed exclusively via the **OneModel GraphQL API** +(`/onemodel/api/v1/graphql`). There are no CLI commands for this domain. + +For the OneModel query workflow (credentials, schema fetch, validation, +execution), read `references/onemodel-graphql.md`. + +## Entity relationship overview + +```mermaid +erDiagram + Application ||--o{ ApplicationVersion : "has versions" + ApplicationVersion ||--o{ Releasable : "contains" + ApplicationVersion ||--o{ Promotion : "promoted through" + ApplicationVersion }o--o{ Source : "assembled from" + Releasable }o--o{ Source : "contributed by" + Releasable ||--o{ Artifact : "contains" + Releasable }o--o| StoredPackageVersionLocation : "located at" + Application }o--o{ Owner : "owned by" + Application }o--o{ Label : "tagged with" + ApplicationVersion }o--o| EvidenceSubject : "attested by" +``` + +## Application + +The top-level entity representing a software application registered in +AppTrust. Applications belong to a JFrog Project and serve as the +organizational container for tracking versions, ownership, and criticality. + +| Field | Description | +|-------|-------------| +| `key` | Unique identifier (referenced as `applicationKey` or `appKey` elsewhere) | +| `projectKey` | JFrog Project this application belongs to | +| `displayName` | Human-readable name | +| `criticality` | `unspecified`, `low`, `medium`, `high`, `critical` | +| `maturityLevel` | `unspecified`, `experimental`, `production`, `end_of_life` | +| `owners` | List of users or groups that own the application | +| `labels` | Key-value pairs for custom categorization | + +Query: `applications.getApplication(key: "...")` or +`applications.searchApplications(where: {...})`. + +## Application version + +A versioned instance of an application. Each version captures a specific set +of releasable artifacts, their sources, and a promotion history through +lifecycle stages. + +| Field | Description | +|-------|-------------| +| `application` | Parent application | +| `version` | Version identifier (semantic or custom) | +| `tag` | Optional tag | +| `status` | Processing status: `STARTED`, `FAILED`, `COMPLETED`, `DELETING` | +| `releaseStatus` | Release maturity: `PRE_RELEASE`, `RELEASED`, `TRUSTED_RELEASE` | +| `currentStageName` | Most recent stage the version has been promoted to (null if never promoted) | +| `createdBy`, `createdAt` | Audit fields | +| `evidenceSubject` | Evidence attestation anchor (shared across domains) | + +The `releaseStatus` field is distinct from `status`: `status` tracks the +version creation process, while `releaseStatus` tracks its release maturity. + +Query: `applications.getApplicationVersion(applicationKey: "...", version: "...")` +or `applications.searchApplicationVersions(where: {...})`. + +## Releasable + +A deployable unit within an application version — either a **package version** +or an individual **artifact**. + +| Field | Description | +|-------|-------------| +| `name` | Package name or artifact file name | +| `version` | Package version (empty for non-package artifacts) | +| `packageType` | Repository package type (docker, maven, generic, etc.) | +| `releasableType` | `artifact` or `package_version` | +| `sha256` | Leading file checksum (e.g. manifest for Docker images) | +| `totalSize` | Sum of all artifact sizes in bytes | +| `sources` | Sources that contributed to this releasable | +| `artifacts` | Individual files that make up the releasable | +| `packageVersionLocation` | Link to `StoredPackageVersionLocation` for package releasables | +| `vcsCommit` | VCS commit details (for AppTrust-bound package versions) | + +Releasables bridge the application model to the underlying Artifactory +storage. The `packageVersionLocation` field connects to the Stored Packages +domain (see `stored-packages-entities.md`). + +## Application version promotion + +Records the promotion of an application version from one stage to another. +All promotions are recorded including failed attempts. + +| Field | Description | +|-------|-------------| +| `sourceStageName` | Stage being promoted from (empty for first promotion) | +| `targetStageName` | Stage being promoted to | +| `status` | `SUBMITTED`, `STARTED`, `PENDING`, `COMPLETED`, `FAILED`, `REJECTED` | +| `createdBy`, `createdAt` | Who initiated and when | +| `artifacts` | Artifacts included in this promotion (repo + path) | +| `messages` | Error messages if the promotion failed | + +Promotions use the same environment/stage model as Release Bundle promotions +(see `release-lifecycle-entities.md`) but at the application level. + +## Sources + +Sources describe how releasables were assembled into an application version. +Four types exist: + +| Source type | Fields | Description | +|-------------|--------|-------------| +| **Build** | `name`, `number`, `startedAt`, `repositoryKey` | A CI/CD build that produced releasables | +| **ReleaseBundle** | `name`, `version` | A release bundle whose artifacts were included | +| **ApplicationVersion** | `applicationKey`, `version` | Another application version (composition) | +| **Direct** | (none) | Directly included without an associated build or bundle | + +Sources appear at both the application version level (all sources) and the +individual releasable level (sources for that specific releasable). + +## Artifacts (within application versions) + +Individual files within releasables. + +| Field | Description | +|-------|-------------| +| `filePath` | Path in the repository (excluding repo key) | +| `downloadPath` | Full path for downloading from a Release Bundle repository | +| `sha256` | Checksum | +| `size` | Size in bytes | +| `evidenceSubject` | Evidence attestation anchor | + +## Cross-domain connections + +AppTrust entities connect to other domains via the OneModel GraphQL API: + +- **Evidence** — `ApplicationVersion.evidenceSubject` and + `ApplicationVersionArtifact.evidenceSubject` link to the Evidence domain + via `EvidenceSubject.fullPath`. This allows querying evidence attached to + app versions and their artifacts. +- **Stored Packages** — `Releasable.packageVersionLocation` links to + `StoredPackageVersionLocation`, connecting the application model to where + packages physically reside in Artifactory. +- **Release Bundles** — source type `ReleaseBundle` references release bundle + name/version from the Release Lifecycle domain. +- **Builds** — source type `Build` references build-info records from + Artifactory. diff --git a/plugins/jfrog/skills/jfrog/references/artifactory-api-gaps.md b/plugins/jfrog/skills/jfrog/references/artifactory-api-gaps.md new file mode 100644 index 0000000..1533d8a --- /dev/null +++ b/plugins/jfrog/skills/jfrog/references/artifactory-api-gaps.md @@ -0,0 +1,206 @@ +# Artifactory API Gaps + +Operations available through REST API but not through CLI commands. +Invoke them via `jf api [flags]` (authentication is handled +automatically against the active `jf config` server; see the base skill's +*Invoking platform APIs with `jf api`* section). + +## Repository management + +### Get repository configuration +```bash +jf api /artifactory/api/repositories/ +``` +Returns the full JSON configuration of a repository. Useful as a template +for creating similar repos. + +### List all repositories +```bash +jf api /artifactory/api/repositories +``` +Optional query params (combinable): `type` (one of `local`, `remote`, +`virtual`, `federated`), `packageType` (e.g. `docker`, `maven`, `npm`, +`pypi`, `generic`), `project`. Examples: +```bash +jf api "/artifactory/api/repositories?type=local" +jf api "/artifactory/api/repositories?packageType=docker" +jf api "/artifactory/api/repositories?type=remote&packageType=maven&project=my-project" +``` + +### Get repositories (v2) +```bash +jf api /artifactory/api/repositories/configurations +``` +Optional query params (combinable, comma-separated values allowed): +`repoType` (case-insensitive; one of `local`, `remote`, `virtual`, +`federated`) and `packageType` (e.g. `maven`, `docker`, `npm`). Note: +`repo_type` is silently ignored — the correct name is `repoType`. +Examples: +```bash +jf api "/artifactory/api/repositories/configurations?repoType=local" +jf api "/artifactory/api/repositories/configurations?packageType=maven" +jf api "/artifactory/api/repositories/configurations?repoType=local,remote&packageType=docker" +``` + +### Check if repository exists +```bash +jf api /artifactory/api/repositories/ -X HEAD +# 200 = exists, 400 = does not exist +``` + +## Storage and system + +### Get storage summary +```bash +jf api /artifactory/api/storageinfo +``` + +### Refresh storage summary +```bash +jf api /artifactory/api/storageinfo/calculate -X POST +``` + +### Get storage item info +```bash +jf api "/artifactory/api/storage//" +``` + +### System ping +```bash +jf api /artifactory/api/system/ping +``` + +### System version +```bash +jf api /artifactory/api/system/version +``` + +### System configuration +```bash +jf api /artifactory/api/system/configuration +``` + +## Search (beyond CLI) + +### AQL queries +```bash +jf api /artifactory/api/search/aql \ + -X POST -H "Content-Type: text/plain" \ + -d 'items.find({"repo":"my-repo","name":{"$match":"*.jar"}})' +``` + +For remote repository content, query the `-cache` suffixed repo: +```bash +jf api /artifactory/api/search/aql \ + -X POST -H "Content-Type: text/plain" \ + -d 'items.find({"repo":"my-remote-cache"})' +``` + +### Property search +```bash +jf api "/artifactory/api/search/prop?key=value&repos=my-repo" +``` + +### Checksum search +```bash +jf api "/artifactory/api/search/checksum?sha256=" +``` + +### GAVC search (Maven) +```bash +jf api "/artifactory/api/search/gavc?g=com.example&a=mylib&v=1.0" +``` + +## User and group management + +User and group operations are handled by the Access service. See +`platform-admin-api-gaps.md` (Users / Groups sections) for the full set. + +## Metadata calculation + +Trigger metadata recalculation for various package types: +```bash +# Maven +jf api /artifactory/api/maven/calculateMetaData/ -X POST + +# npm +jf api /artifactory/api/npm//reindex -X POST + +# Docker +# (automatic, no manual trigger) + +# PyPI +jf api /artifactory/api/pypi//reindex -X POST + +# Helm +jf api /artifactory/api/helm//reindex -X POST + +# Debian +jf api /artifactory/api/deb/reindex/ -X POST +``` + +## Trash can and garbage collection + +### Empty trash +```bash +jf api /artifactory/api/trash/empty -X POST +``` + +### Restore from trash +```bash +jf api "/artifactory/api/trash/restore//" -X POST +``` + +### Run garbage collection +```bash +jf api /artifactory/api/system/storage/gc -X POST +``` + +## Federated repositories (beyond basic CRUD) + +### Get federation status +```bash +jf api /artifactory/api/federation/status/ +``` + +### Trigger full sync +```bash +jf api "/artifactory/api/federation/fullSyncAll/" -X POST +``` + +## Build info (beyond CLI) + +### List builds (prefer scoped queries) + +**Unscoped** `GET /artifactory/api/build` (no query parameters) can **time +out** on busy instances. Prefer **project-scoped** or **repo-scoped** +listing, then detail GETs. Full flow: read `artifactory-operations.md` +§ *Listing builds when the project key is known*. + +```bash +# Project scope — build names (latest per name) +jf api "/artifactory/api/build?project=" + +# Project scope — all run numbers for one build name (response: buildsNumbers) +jf api "/artifactory/api/build/?project=" + +# Build-info repo scope — alternative when you know the repo key +jf api "/artifactory/api/build?buildRepo=" +``` + +### Get build info +```bash +# Default build-info repo only (no project / non-default repo) +jf api "/artifactory/api/build//" + +# Project or custom build-info repo +jf api "/artifactory/api/build//?project=" +jf api "/artifactory/api/build//?buildRepo=" +``` + +### Delete builds +```bash +jf api /artifactory/api/build/delete \ + -X POST -H "Content-Type: application/json" \ + -d '{"buildName":"my-build","buildNumbers":["1","2"]}' +``` diff --git a/plugins/jfrog/skills/jfrog/references/artifactory-aql-syntax.md b/plugins/jfrog/skills/jfrog/references/artifactory-aql-syntax.md new file mode 100644 index 0000000..b120275 --- /dev/null +++ b/plugins/jfrog/skills/jfrog/references/artifactory-aql-syntax.md @@ -0,0 +1,656 @@ +# AQL (Artifactory Query Language) + +AQL queries are sent as POST requests with `Content-Type: text/plain`: + +```bash +jf api /artifactory/api/search/aql \ + -X POST -H "Content-Type: text/plain" -d '' +``` + +## Query structure + +``` +.find() + .include() + .sort() + .offset() + .limit() + .distinct() +``` + +Only `.find()` is required. The others are optional and chainable. +**The chain order above is enforced by the server.** `.include()` must come +before `.sort()`, `.sort()` before `.offset()`, etc. Putting them out of +order (e.g. `.sort()` before `.include()`) produces a parse error. + +**Mandatory include fields:** `items` requires `"repo","path","name"`; +`builds` requires `"name","number","repo"`. Always include these even when +you only need a subset — narrow results with `jq` post-query instead: + +``` +items.find({"name":"commons-lang3-3.12.0.jar"}) + .include("repo","path","name") + .distinct(true) +``` + +## Domains + +AQL has 13 queryable domains. Each domain represents a different entity type +and has its own set of fields. + + +| Domain | Query name | Description | +| -------------------- | ------------------- | ---------------------------------------------- | +| Items | `items` | Artifacts stored in repositories (most common) | +| Properties | `properties` | Key-value properties on items | +| Item infos | `item.infos` | Property modification metadata | +| Statistics | `stats` | Download statistics (local and remote) | +| Builds | `builds` | Build info records | +| Build modules | `modules` | Modules within a build | +| Build artifacts | `artifacts` | Artifacts produced by a build module | +| Build dependencies | `dependencies` | Dependencies consumed by a build module | +| Build properties | `build.properties` | Key-value properties on builds | +| Build promotions | `build.promotions` | Build promotion records | +| Module properties | `module.properties` | Key-value properties on build modules | +| Release bundles | `releases` | Release bundle records | +| Release bundle files | `release_artifacts` | Files within a release bundle | + + +## Domain relationships + +Domains connect through the following join paths. Cross-domain queries +traverse these links — fields from related domains can appear in criteria +and include clauses by prefixing the domain path. + +```mermaid +erDiagram + items ||--o{ properties : "has" + items ||--o| item_infos : "has" + items ||--o{ stats : "has" + items ||--o{ artifacts : "via checksum" + items ||--o{ dependencies : "via checksum" + items ||--o{ release_artifacts : "has" + artifacts }o--|| modules : "belongs to" + dependencies }o--|| modules : "belongs to" + modules }o--|| builds : "belongs to" + modules ||--o{ module_properties : "has" + builds ||--o{ build_properties : "has" + builds ||--o{ build_promotions : "has" + release_artifacts }o--|| releases : "belongs to" +``` + + + +**Key:** Items connect to build artifacts and dependencies through SHA-1 +checksum matching, not a direct key. This means a cross-domain query from +items to builds traverses: items → artifacts → modules → builds. + +### Cross-domain field paths + +To reference a field from a related domain, use dot-separated domain paths: + +``` +items.find({"artifact.module.build.name":"my-build"}) + .include("name","repo","path","artifact.module.build.number") +``` + +Common cross-domain paths from items: + +- `stat.downloads`, `stat.downloaded` — download statistics +- `property.key`, `property.value` — item properties +- `artifact.module.build.name` — build that produced the item +- `artifact.module.build.number` — build number + +From builds: + +- `module.artifact.name` — artifacts in build modules +- `module.dependency.name` — dependencies of build modules + +## Fields by domain + +Field types: `string`, `date`, `int`, `long`, `itemType` (`file`, `folder`, +or `any`). Fields marked "default" are returned without explicit `.include()`. + +### items + + +| Field | Type | Default | +| --------------- | -------- | ------- | +| `repo` | string | yes | +| `path` | string | yes | +| `name` | string | yes | +| `type` | itemType | yes | +| `size` | long | yes | +| `depth` | int | yes | +| `created` | date | yes | +| `created_by` | string | yes | +| `modified` | date | yes | +| `modified_by` | string | yes | +| `updated` | date | yes | +| `actual_md5` | string | no | +| `actual_sha1` | string | no | +| `sha256` | string | no | +| `original_md5` | string | no | +| `original_sha1` | string | no | + + +Computed field: `virtual_repos` — returns virtual repositories that include +the item's actual repository. Must use `.include("virtual_repos")` explicitly; +requires `repo`, `path`, `name` in the result set. + +### properties + + +| Field | Type | Default | +| ------- | ------ | ------- | +| `key` | string | yes | +| `value` | string | yes | + + +### stats + + +| Field | Type | Default | +| ---------------------- | ------ | ------- | +| `downloads` | int | yes | +| `downloaded` | date | yes | +| `downloaded_by` | string | yes | +| `remote_downloads` | int | yes | +| `remote_downloaded` | date | yes | +| `remote_downloaded_by` | string | yes | +| `remote_origin` | string | yes | +| `remote_path` | string | yes | + + +### item.infos + + +| Field | Type | Default | +| ------------------- | ------ | ------- | +| `props_modified` | date | yes | +| `props_modified_by` | string | yes | +| `props_md5` | string | yes | + + +### builds + + +| Field | Type | Default | +| ------------- | ------ | ------- | +| `url` | string | yes | +| `name` | string | yes | +| `number` | string | yes | +| `started` | date | yes | +| `created` | date | yes | +| `created_by` | string | yes | +| `modified` | date | yes | +| `modified_by` | string | yes | +| `repo` | string | no | + + +### modules + + +| Field | Type | Default | +| ------ | ------ | ------- | +| `name` | string | yes | + + +### artifacts + + +| Field | Type | Default | +| ------ | ------ | ------- | +| `name` | string | yes | +| `type` | string | yes | +| `sha1` | string | yes | +| `md5` | string | yes | + + +### dependencies + + +| Field | Type | Default | +| ------- | ------ | ------- | +| `name` | string | yes | +| `scope` | string | yes | +| `type` | string | yes | +| `sha1` | string | yes | +| `md5` | string | yes | + + +### build.properties + + +| Field | Type | Default | +| ------- | ------ | ------- | +| `key` | string | yes | +| `value` | string | yes | + + +### build.promotions + + +| Field | Type | Default | +| ------------ | ------ | ------- | +| `created` | date | yes | +| `created_by` | string | yes | +| `status` | string | yes | +| `repo` | string | yes | +| `comment` | string | yes | +| `user` | string | yes | + + +### module.properties + + +| Field | Type | Default | +| ------- | ------ | ------- | +| `key` | string | yes | +| `value` | string | yes | + + +### releases + + +| Field | Type | Default | +| -------------- | --------------------------- | ------- | +| `name` | string | yes | +| `version` | string | yes | +| `status` | string | yes | +| `created` | date | yes | +| `signature` | string | yes | +| `type` | string (`SOURCE`, `TARGET`) | yes | +| `storing_repo` | string | yes | + + +### release_artifacts + + +| Field | Type | Default | +| ------ | ------ | ------- | +| `path` | string | yes | + + +## Comparators + + +| Operator | Meaning | Example | +| ---------- | -------------------------------- | ------------------------------------ | +| `$eq` | Equals (default if omitted) | `{"type":"file"}` | +| `$ne` | Not equals | `{"type":{"$ne":"folder"}}` | +| `$eqic` | Equals, case-insensitive | `{"name":{"$eqic":"README.md"}}` | +| `$match` | Wildcard match (`*`, `?`) | `{"name":{"$match":"*.jar"}}` | +| `$matchic` | Wildcard match, case-insensitive | `{"name":{"$matchic":"*.JAR"}}` | +| `$nmatch` | Wildcard not-match | `{"name":{"$nmatch":"*-SNAPSHOT*"}}` | +| `$gt` | Greater than | `{"size":{"$gt":"1000000"}}` | +| `$gte` | Greater than or equal | `{"stat.downloads":{"$gte":"10"}}` | +| `$lt` | Less than | `{"size":{"$lt":"5000"}}` | +| `$lte` | Less than or equal | `{"modified":{"$lte":"2025-01-01"}}` | + + +### Boolean operators + + +| Operator | Description | +| -------- | ---------------------------------------------------------------------- | +| `$and` | All conditions must match (implicit when fields are at the same level) | +| `$or` | Any condition must match | + + +``` +items.find({"$and":[ + {"repo":"my-repo"}, + {"$or":[ + {"name":{"$match":"*.jar"}}, + {"name":{"$match":"*.war"}} + ]} +]}) +``` + +### Relative date comparators + +AQL supports relative date queries with `$last` and `$before`: + + +| Operator | Meaning | Example | +| --------- | ------------------------------------------------------- | ------------------------------- | +| `$last` | Within the last N period (equivalent to `$gt` from now) | `{"modified":{"$last":"7d"}}` | +| `$before` | Before the last N period (equivalent to `$lt` from now) | `{"created":{"$before":"3mo"}}` | + + +Supported units: `d` (days), `w` (weeks), `mo` (months), `y` (years), +`s` (seconds), `mi` (minutes), `ms` (milliseconds). + +### Multi-property AND + +To match items that have property A=1 **and** property B=2 (different +property rows), use `$and` with `@` shorthand: + +``` +items.find({"$and":[ + {"@build.name":"my-build"}, + {"@build.number":"42"} +]}) +``` + +AQL also documents a `$msp` (multi-set property) operator for this purpose, +but `$msp` is **unreliable in practice** — it returns 0 results on many +server versions even when matching items exist. Prefer `$and` with `@` +shorthand, which is verified to work correctly. + +## Date queries + +Dates use ISO 8601 format for absolute dates: + +``` +items.find({"modified":{"$gt":"2025-06-01T00:00:00.000Z"}}) +``` + +Or use relative dates (preferred — avoids hardcoding timestamps): + +``` +items.find({"modified":{"$last":"30d"}}) +items.find({"created":{"$before":"6mo"}}) +``` + +## Property queries + +Two equivalent syntaxes for property filtering: + +**`@key` shorthand** — concise, works for single property conditions: + +``` +items.find({"repo":"my-repo","@build.name":"my-build","type":"file"}) +``` + +**Explicit form** — `property.key`/`property.value` pairs: + +``` +items.find({ + "repo":"my-repo", + "property.key":"build.name", + "property.value":"my-build" +}) +``` + +**Multi-property AND** — use `$and` with `@` shorthand to match across +different property rows: + +``` +items.find({"$and":[ + {"@build.name":"my-build"}, + {"@build.number":"42"} +]}) +``` + +> **Note:** The `@key` shorthand works inside `$and`. For `$or`, use the +> explicit `property.key`/`property.value` form if the shorthand does not +> return expected results. + +## Include + +Select which fields to return. Without `.include()`, AQL returns each +domain's default field set. + +**When you use `.include()`, you replace the defaults — so you must +explicitly list any required fields:** + +- `items` domain: always include `"repo","path","name"` (server rejects +the query otherwise) +- `builds` domain: always include `"name","number","repo"` + +``` +items.find({"repo":"my-repo"}) + .include("name","repo","path","size","sha256","stat.downloads") +``` + +Cross-domain includes use dot-separated paths: + +``` +items.find({"repo":"my-repo"}) + .include("name","repo","path","property.key","property.value") +``` + +## Sort and pagination + +``` +items.find({"repo":"my-repo"}) + .sort({"$desc":["modified"]}) + .offset(0) + .limit(50) +``` + +Sort directions: `$asc`, `$desc`. Sort fields must also appear in the result +set (explicit `.include()` or default fields). See +[Before constructing a query](#before-constructing-a-query) for sort +performance rules. + +## Distinct + +Deduplicate result rows: + +``` +items.find({"repo":"my-repo"}).distinct(true) +``` + +## Validation rules + +The server enforces these constraints — violating them produces an error: + +**Non-admin users:** + +- `items` domain queries must include `repo`, `path`, `name` in results +(needed for permission filtering) +- `builds` domain queries must include `name`, `number`, `repo` in results + +**Transitive mode** (`.transitive()` for querying through virtual repos): + +- Only works with `items` domain +- Include subdomains limited to `items` and `properties` +- Repo criteria must use `$eq` (exact match) with a single repository +- No `offset` or `sort` allowed + +## Before constructing a query + +Run through these checks before writing any AQL query: + +1. **Never `.sort()` without a `repo` filter** — forces a full table scan + across all repositories. Sort client-side with `jq` instead. Also, + `.sort()` on cross-domain fields (e.g. `stat.downloads` in `items.find()`) + is silently ignored — fetch all rows and sort client-side. +2. **Always set `.limit()`** — no built-in default limit; unbounded queries + can time out or OOM. Broad queries without a `repo` filter are especially + expensive. +3. **`range.total` = returned count, not total matching** — AQL has no + count-only mode. To find the true total, paginate with `.offset()` until + a page returns fewer results than the limit. +4. **AQL has no repo-type field** — to restrict to local repos, either + pre-query `GET /api/repositories?type=local` and add repo names to + criteria (practical when count is small), or query without a repo filter + and exclude `-cache` / `-virtual` suffixed repos client-side with `jq`. +5. **Narrow server-side first** — add every applicable filter (`created_by`, + `created`, `type`, `name`) before relying on client-side `jq` filtering. + +## Common query patterns + +### Find all JARs in a repo + +``` +items.find({"repo":"libs-release","name":{"$match":"*.jar"}}) +``` + +### Find large files (> 100 MB) + +``` +items.find({"repo":"my-repo","size":{"$gt":"104857600"},"type":"file"}) +``` + +### Find Maven SNAPSHOT JARs + +Use `*-SNAPSHOT*.jar` (not `*-SNAPSHOT.jar`) to also match classifier +artifacts like `-sources.jar` and `-javadoc.jar`: + +``` +items.find({"repo":"libs-snapshot","name":{"$match":"*-SNAPSHOT*.jar"},"type":"file"}) +``` + +### Find artifacts modified in the last 7 days + +``` +items.find({"repo":"my-repo","modified":{"$last":"7d"},"type":"file"}) + .sort({"$desc":["modified"]}) + .limit(100) +``` + +### Docker queries + +Use `"name":"manifest.json"` to **list tags** (one per tag). Use +`"name":{"$match":"*manifest.json"}` to **query all manifests** (includes +`list.manifest.json` for multi-arch tags — see [Gotchas](#gotchas)). + +``` +items.find({"repo":"docker-local","path":{"$match":"my-image/*"},"name":"manifest.json"}) +``` + +### Docker image size + +**Do not use AQL** — layer blobs live at `/sha256:/`, not +under `//`. Use the V2 manifest API (returns `layers[].size`): + +```bash +jf api "/artifactory/api/docker//v2//manifests/" \ + -H "Accept: application/vnd.docker.distribution.manifest.v2+json" +``` + +For multi-arch images the response is an image index; fetch each platform +manifest by digest to get its layers. + +### Find artifacts with a specific property + +``` +items.find({"repo":"my-repo","@build.name":"my-build","type":"file"}) +``` + +### Find never-downloaded files (zero download count) + +Zero-download items lack a stats row — filter client-side instead +(see [Gotchas](#gotchas)): + +```bash +jf api /artifactory/api/search/aql \ + -X POST -H "Content-Type: text/plain" -d ' +items.find({"repo":"my-repo","type":"file"}) + .include("repo","path","name","size","stat.downloads") +' | jq '[.results[] | select((.stats[0].downloads // 0) == 0) | {repo, path, name, size}]' +``` + +### Find artifacts not downloaded in 90 days + +Only matches previously-downloaded items (see [Gotchas](#gotchas)). +Combine with the never-downloaded pattern above for full coverage. + +``` +items.find({ + "repo":"my-repo", + "type":"file", + "stat.downloaded":{"$before":"90d"} +}).include("name","repo","path","stat.downloaded","size") +``` + +### Find items by build name (cross-domain) + +``` +items.find({"artifact.module.build.name":"my-service"}) + .include("name","repo","path","artifact.module.build.number") + .sort({"$desc":["modified"]}) + .limit(50) +``` + +### Find builds by name + +Non-admin users must include `name`, `number`, `repo` — omitting any +produces an error. + +``` +builds.find({"name":{"$match":"*my-service*"}}) + .include("name","number","repo","started") + .sort({"$desc":["started"]}) + .limit(10) +``` + +### Find build artifacts + +``` +artifacts.find({"module.build.name":"my-service","module.build.number":"42"}) + .include("name","type","sha1","md5") +``` + +### Find build dependencies + +``` +dependencies.find({"module.build.name":"my-service","module.build.number":"42"}) + .include("name","scope","type","sha1") +``` + +### Remote repository content + +Remote repo artifacts are stored in a `-cache` suffixed repo. Always query +the cache repo, not the remote repo itself: + +``` +items.find({"repo":"npm-remote-cache","name":{"$match":"*.tgz"}}) +``` + +## Gotchas + +- The request body is **plain text**, not JSON — use +`Content-Type: text/plain`. +- String values in criteria must be quoted, including numeric comparisons +(`"size":{"$gt":"1000"}` not `"size":{"$gt":1000}`). +- Remote repo content lives in `-cache`, not ``. +- Sort fields must appear in the result set (included explicitly or by +default). +- Non-admin `items` queries must return `repo`, `path`, `name`. +- Non-admin `builds` queries must return `name`, `number`, `repo`. +- Items connect to builds through checksum matching (SHA-1), so cross-domain +queries between items and builds are valid but traverse multiple joins. +- The `path` value for items at the **root** of a repository is `"."`, not +`""` or `"/"`. Use `"path":"."` to match root-level files. +- **Docker `list.manifest.json`** — multi-arch images store two manifest files per + tag: `manifest.json` (platform-specific manifest) and `list.manifest.json` (OCI + image index). Filtering by `"name":"manifest.json"` is correct for tag listing + (one result per tag), but silently excludes `list.manifest.json` entries. Use + `"name":{"$match":"*manifest.json"}` when querying by uploader, date range, or + any context where all manifest pushes should be counted. +- **`stat.downloads` filters do not match zero-download items** — never-downloaded + items lack a stats row so the join finds nothing. Use the client-side `jq` + approach in "Find never-downloaded files" above. +- `$match` uses SQL-style wildcards: `*` matches any characters, `?` matches +exactly one character. It is **not** regex. Literal `_` and `%` in patterns +are escaped automatically. +- The `builds.number` field is a **string**, not an integer. Build numbers +like `"42"`, `"1.0.3"`, and `"SNAPSHOT-1"` are all valid. +- Release bundle `type` values are uppercase strings: `"SOURCE"` or +`"TARGET"`. +- Dates accept both ISO 8601 format (`"2025-06-01T00:00:00.000Z"`) and +epoch milliseconds as a string (`"1719792000000"`). +- The server silently excludes trash, support-bundle, and in-transit +repository content from AQL results. If an item exists but doesn't appear +in results, it may be in one of these hidden repos. +- Virtual repo queries are rewritten to search the underlying physical repos. +The `repo` field in results shows the physical repo name, not the virtual +repo name you queried. + +## Official documentation + +- [Artifactory Query Language](https://docs.jfrog.com/artifactory/docs/artifactory-query-language) — overview and architecture +- [Query Structure and Syntax](https://docs.jfrog.com/artifactory/docs/aql-syntax) — domain queries, field references, JSON-like syntax rules +- [Search Criteria and Operators](https://docs.jfrog.com/artifactory/docs/aql-search-criteria) — comparators, wildcards, `$msp`, relative time +- [AQL Entities and Fields Reference](https://docs.jfrog.com/artifactory/docs/aql-entities-fields-reference) — complete field list for all domains +- [Query Output and Modifiers](https://docs.jfrog.com/artifactory/docs/aql-query-output) — `.include()`, `.sort()`, `.offset()`, `.limit()`, `.distinct()` +- [Query Execution and Permissions](https://docs.jfrog.com/artifactory/docs/aql-query-execution) — authentication, scoped tokens, HTTP errors, streaming +- [AQL Examples and Common Patterns](https://docs.jfrog.com/artifactory/docs/aql-examples) — ready-to-use queries by use case +- [Repository-Specific Queries](https://docs.jfrog.com/artifactory/docs/aql-repository-queries) — `.transitive()`, virtual repos, remote search +- [Performance and Operational Controls](https://docs.jfrog.com/artifactory/docs/aql-performance) — result limits, timeouts, rate limiting, optimization + diff --git a/plugins/jfrog/skills/jfrog/references/artifactory-entities.md b/plugins/jfrog/skills/jfrog/references/artifactory-entities.md new file mode 100644 index 0000000..1e4d950 --- /dev/null +++ b/plugins/jfrog/skills/jfrog/references/artifactory-entities.md @@ -0,0 +1,236 @@ +# Artifactory entities + +When to read this file: + +- Working with **repositories** and you need to understand the difference between local, remote, virtual, and federated types. +- Managing **artifacts**, **properties**, or **package types**. +- Working with **builds**, **build promotion**, or **permission targets**. +- Debugging unexpected behavior related to repo types (e.g. upload failures, missing search results). + +For CLI commands see `artifactory-operations.md`. For API gaps see +`artifactory-api-gaps.md`. For AQL syntax see `artifactory-aql-syntax.md`. + +## Repositories + +A repository is the primary storage and resolution unit in Artifactory. Every +repo has a **key** (unique identifier), a **package type** (immutable after +creation), and a **repository class** (`rclass`) that determines its behavior. + +### Repository types + +| Type | `rclass` | Behavior | Stores artifacts? | +|------|----------|----------|-------------------| +| **Local** | `local` | Hosts artifacts deployed directly (upload, promote, copy, move) | Yes | +| **Remote** | `remote` | Proxies an external URL; downloads are cached in a companion `-cache` repo | Only in the `-cache` repo | +| **Virtual** | `virtual` | Aggregates multiple local and remote repos under a single URL for resolution | No (resolves from underlying repos) | +| **Federated** | `federated` | Local repo that bi-directionally synchronizes across Platform Deployments | Yes (replicated across sites) | + +### Key relationships and fields + +- `key` — unique repo identifier (e.g. `libs-release-local`) +- `packageType` — determines layout and protocol (see Package types below) +- `rclass` — `local`, `remote`, `virtual`, or `federated` +- `url` — (remote only) the external source URL being proxied +- `repositories` — (virtual only) ordered list of local/remote repos to aggregate +- `projectKey` — links repo to a JFrog Project (see `platform-access-entities.md`) +- `environments` — environments the repo is assigned to (used in RBAC and lifecycle) + +### System repositories + +Artifactory and Xray maintain several **system repositories** for internal +platform metadata. These are not user-created and should be excluded when +iterating over repositories for reporting, scanning, or auditing: + +| Pattern | Purpose | +|---------|---------| +| `release-bundles` | Release Bundles V1 metadata | +| `release-bundles-v2` | Release Bundles V2 metadata | +| `artifactory-build-info` | Default build info storage | +| `*-release-bundles` | Project-scoped Release Bundles V1 | +| `*-release-bundles-v2` | Project-scoped Release Bundles V2 | +| `*-build-info` | Project-scoped build info storage | +| `*-application-versions` | AppTrust application version metadata | + +Including these in aggregate queries (violation counts, storage reports, etc.) +produces misleading results because they contain platform metadata rather than +user artifacts. + +### Remote repository cache + +When Artifactory downloads an artifact through a remote repo, it stores the +cached copy in a **separate local repo** named `-cache`. This is +critical for: + +- **AQL queries** — search the `-cache` repo, not the remote repo key +- **Properties** — properties on cached artifacts live on the `-cache` repo +- **Storage calculations** — cached artifacts consume storage under the `-cache` repo + +The remote repo key itself is used for **configuration** (URL, credentials, +inclusion/exclusion patterns) but does not directly contain artifacts. + +### Virtual repository resolution + +A virtual repo aggregates **both local and remote repos** under a single URL. +It resolves artifacts by searching its underlying repos in the configured +**order** — when the same artifact exists in multiple underlying repos, the +first match wins. + +A virtual repo may designate one of its underlying **local** repos as the +**default deployment repository**. Uploads through the virtual URL are routed +to that local repo. Without a default deployment repo, the virtual repo is +read-only. + +```mermaid +erDiagram + VirtualRepo ||--o{ LocalRepo : "aggregates" + VirtualRepo ||--o{ RemoteRepo : "aggregates" + VirtualRepo ||--o| LocalRepo : "defaultDeploymentRepo" + RemoteRepo ||--|| CacheRepo : "has -cache" +``` + +## Artifacts + +An artifact is a file stored in a repository. Each artifact is uniquely +identified by the triple **repo + path + name**. + +Key attributes: +- `repo`, `path`, `name` — location identifier +- `size` — bytes +- `sha256`, `sha1`, `md5` — checksums (sha256 is the primary identifier for cross-referencing with builds and Xray) +- `created`, `modified`, `created_by`, `modified_by` — audit fields + +Artifacts are **content-addressable** — build info and Xray reference them by +checksum, not by path. Moving or copying an artifact changes its path but not +its checksum, so build associations follow the artifact. + +## Properties + +Key-value metadata pairs attached to artifacts or folders. + +- Keys are strings; values are strings or arrays of strings +- Set via `jf rt set-props`, queried via AQL or the properties API +- Commonly used for: build metadata, maturity labels, promotion tracking, cleanup policies +- Properties on remote-cached artifacts live on the `-cache` repo + +## Package types + +The `packageType` field on a repository determines how Artifactory interprets +its contents. It controls directory structure conventions, metadata extraction, +and which client protocols are supported (e.g. Docker registry API, npm +registry, Maven layout). + +Common types: `maven`, `gradle`, `npm`, `docker`, `pypi`, `nuget`, `go`, +`helm`, `rpm`, `debian`, `generic`. + +Package type is **immutable** — it cannot be changed after repo creation. Use +`generic` when no specific package type applies. + +## Build info + +A build info record captures CI/CD metadata: which artifacts were produced, +which dependencies were consumed, and the build environment. + +| Field | Description | +|-------|-------------| +| `name` + `number` | Unique identifier for a build run | +| `modules` | List of modules, each with its own artifacts and dependencies | +| `vcs` | Version control metadata (revision, URL, branch) | +| `buildAgent`, `agent` | CI tool info | +| `properties` | Custom build-level properties | + +Build info references artifacts **by checksum** (sha256). This means: +- A build can reference artifacts across multiple repositories +- Moving an artifact does not break the build association +- Xray scans build info by resolving checksums to components + +Lifecycle: collect → publish → (optionally) promote → (optionally) scan. + +## Build promotion + +Promotion changes a build's **status** and can copy or move its artifacts +from a source repo to a target repo. + +| Field | Description | +|-------|-------------| +| `status` | Target status label (e.g. `staged`, `released`) | +| `sourceRepo` | Where artifacts currently reside | +| `targetRepo` | Where artifacts should be moved/copied | +| `copy` | If `true`, copy instead of move | + +Promotion records are queryable via AQL (`build.promotions` domain) and the +build promotion API. + +## Permissions + +Permissions define RBAC policies mapping **resources** and **principals** +(users and groups) to **actions**. Two models exist: + +### Permissions V2 (Access Permissions) — current model + +Managed by the **Access service** (since Artifactory 7.72.0, recommended from +7.77.2). Supports all resource types. + +| Component | Description | +|-----------|-------------| +| `name` | Permission name | +| `resources` | Map of resource type → targets + actions | + +Resource types: `artifact` (repositories), `build`, `release_bundle`, +`destination` (Edge nodes), `pipeline_source`. + +Each resource contains: +- `targets` — map of target names/patterns to include/exclude patterns +- `actions.users` — map of username → list of actions +- `actions.groups` — map of group name → list of actions + +Actions use uppercase: `READ`, `ANNOTATE`, `DEPLOY/CACHE`, `DELETE/OVERWRITE`, +`MANAGE_XRAY_METADATA`, `MANAGE`. + +API: `POST/PUT/GET/DELETE /access/api/v2/permissions/{permissionName}`. + +Documentation: [Permissions](https://docs.jfrog.com/administration/docs/permissions). + +### Permission targets (V1) — legacy model + +Managed by **Artifactory**. Still functional and backwards compatible, but +V2 is recommended for new implementations. The CLI `jf rt permission-target-*` +commands use this API. + +| Component | Description | +|-----------|-------------| +| `repositories` | List of repo keys or patterns | +| `actions.users` | Map of username → list of actions | +| `actions.groups` | Map of group name → list of actions | + +Actions use lowercase: `read`, `write`, `annotate`, `delete`, `manage`. + +Does **not** support `destination` or `pipeline_source` resource types. + +API: `PUT /artifactory/api/security/permissions/{permissionName}`. + +### Key differences + +| Aspect | V1 (Permission Targets) | V2 (Access Permissions) | +|--------|------------------------|------------------------| +| Managed by | Artifactory | Access service | +| API base | `/artifactory/api/security/permissions/` | `/access/api/v2/permissions/` | +| Actions | lowercase (`read`, `write`) | uppercase (`READ`, `WRITE`) | +| Resource types | repos, builds, release bundles | + destinations, pipeline sources | +| Pattern fields | `includes_pattern` / `excludes_pattern` | `include_patterns` / `exclude_patterns` | +| CLI support | `jf rt permission-target-*` | No direct CLI commands (use REST) | + +For project-scoped RBAC, see Project roles in `platform-access-entities.md`. + +## Replication + +Replication synchronizes artifacts and properties between repositories, either +within the same instance or across Platform Deployments. + +| Type | Direction | Trigger | +|------|-----------|---------| +| **Push** | Source pushes to target | Scheduled or event-based | +| **Pull** | Target pulls from source | Scheduled | + +Replication configs are JSON templates applied per repository. Both artifact +content and properties are replicated. For federated repos, replication is +automatic and bi-directional across all member nodes. diff --git a/plugins/jfrog/skills/jfrog/references/artifactory-operations.md b/plugins/jfrog/skills/jfrog/references/artifactory-operations.md new file mode 100644 index 0000000..bab2b65 --- /dev/null +++ b/plugins/jfrog/skills/jfrog/references/artifactory-operations.md @@ -0,0 +1,178 @@ +# Artifactory Operations + +CLI commands for managing Artifactory resources. All commands use the `jf rt` +namespace. Run `jf rt --help` to discover subcommands not listed here. + +## Repository management + +Repositories are created from JSON templates. The workflow is: + +1. Get a template: retrieve an existing repo config via + `jf api /artifactory/api/repositories/` + and modify it, or craft JSON manually. + Note: `jf rt repo-template` is interactive and cannot be used by agents. +2. Create: `jf rt repo-create ` +3. Update: `jf rt repo-update ` +4. Delete: `jf rt repo-delete --quiet` + +To list repositories, use: +`jf api /artifactory/api/repositories` + +## File operations + +- Upload: `jf rt upload ` +- Download: `jf rt download [target]` +- Search: `jf rt search ` +- Move: `jf rt move ` +- Copy: `jf rt copy ` +- Delete: `jf rt delete ` +- Set properties: `jf rt set-props "key=value"` +- Delete properties: `jf rt delete-props "key"` + +### Searching across repositories + +`jf rt search` expects a `/` argument. When the repo is unknown, +agents tend to use a leading wildcard (`jf rt search "*/path/..."`), which +generates an unscoped AQL internally and can time out on large instances. + +Use a direct AQL query with `name` and `path` criteria instead — omitting the +`repo` field searches all accessible repos via indexed columns: + +```bash +jf api /artifactory/api/search/aql \ + -X POST -H "Content-Type: text/plain" \ + -d 'items.find({ + "name":"", + "path":"" + }).include("repo","path","name","size","sha256")' +``` + +Add `"repo":""` to the criteria when the target repo is known, to +narrow the search further. + +## Build info + +**Project scoping rule:** Append `?project=` to **every** build detail +API call. When the user provides a project key, use it. When no project key +is provided, use `?project=default` (the built-in default project that covers +the `artifactory-build-info` repo). For AQL queries, scope by +`"repo":"-build-info"` (or `"repo":"artifactory-build-info"` for +the default project). + +**Server rule:** A 404 from a `?project=` build call is **not** a signal +to try a different server. Use only the resolved server; on any failure, +report and stop. See `SKILL.md` § *Server selection rules*. + +### Publishing builds + +- Collect env: `jf rt build-collect-env ` +- Add git info: `jf rt build-add-git ` +- Publish: `jf rt build-publish ` +- Promote: `jf rt build-promote ` +- Discard: `jf rt build-discard ` + +### Listing build names + +**Do not use `GET /api/build`** — it has no pagination and times out on large +instances. Always use AQL with `limit` and `offset`. + +**All builds** (no project scope): + +```bash +jf api /artifactory/api/search/aql \ + -X POST -H "Content-Type: text/plain" \ + -d 'builds.find().include("name","number","repo","created").sort({"$desc":["created"]}).offset(0).limit(100)' +``` + +**Project-scoped** — filter by the project's build-info repository +(`-build-info`, or `artifactory-build-info` for the default +project): + +```bash +jf api /artifactory/api/search/aql \ + -X POST -H "Content-Type: text/plain" \ + -d 'builds.find({"repo":"-build-info"}).include("name","number","repo","created").sort({"$desc":["created"]}).offset(0).limit(100)' +``` + +**Pagination:** The response includes a `range` object with `total` (total +matching records). If `total` exceeds the `limit`, tell the user: *"Showing +first 100 of N results (paginated). Ask for the next batch if needed."* +For subsequent pages, increment `offset` by 100. + +**Output rule (mandatory):** AQL returns one row per name+number pair. +Extract **unique build names** client-side (e.g. +`jq '[.[].builds.name] | unique'`). Present **only the deduplicated list of +build names** to the user. **Do not** include build numbers, timestamps, run +counts, or any per-run details in the response — not even as a "bonus" or +"most recent" table. The user is asking "what builds exist", not "what runs +happened". Only show run-level details if the user explicitly asks for them +in a follow-up. + +### Listing runs of a specific build + +```bash +jf api /artifactory/api/search/aql \ + -X POST -H "Content-Type: text/plain" \ + -d 'builds.find({"name":""}).include("name","number","repo","created").sort({"$desc":["created"]}).offset(0).limit(100)' +``` + +Add `"repo":"-build-info"` to the criteria when a project key +is known. Apply the same pagination rules as above. + +### Retrieving full build info + +Use the REST detail endpoint for a **single** build run. Always include +`?project=` (or `?project=default` when no key is provided): + +```bash +jf api "/artifactory/api/build//?project=" +``` + +This is the only `/api/build` endpoint that should be used — it returns a +single record and does not need pagination. + +### When a build is not found + +If the detail call returns 404, the build likely belongs to a different +project. **Ask the user for the project key** rather than searching across +repos or servers. + +### Repository listing vs build-info + +`GET /artifactory/api/repositories?project=&type=buildinfo` may return +an empty list even when project-scoped build info exists (for example under +a `*-build-info` repository). Prefer AQL to +discover builds; do not treat an empty repository +list as proof that no +builds exist. + +## Permissions + +Permission targets use JSON templates. +Note: `jf rt permission-target-template` is interactive. + +- Create: `jf rt permission-target-create ` +- Update: `jf rt permission-target-update ` +- Delete: `jf rt permission-target-delete ` + +## Users and groups + +- Create users: `jf rt users-create --csv ` +- Create single user: `jf rt user-create` (check `--help` for options) +- Delete users: `jf rt users-delete ` +- Create group: `jf rt group-create ` +- Delete group: `jf rt group-delete ` +- Add users to group: `jf rt group-add-users ` + +To get user details or update users, use `jf api`: +``` +jf api /access/api/v2/users/ +``` + +## Replication + +Replication configs use JSON templates. +Note: `jf rt replication-template` is interactive. + +- Create: `jf rt replication-create ` +- Delete: `jf rt replication-delete ` diff --git a/plugins/jfrog/skills/jfrog/references/catalog-entities.md b/plugins/jfrog/skills/jfrog/references/catalog-entities.md new file mode 100644 index 0000000..085bea0 --- /dev/null +++ b/plugins/jfrog/skills/jfrog/references/catalog-entities.md @@ -0,0 +1,219 @@ +# Catalog entities + +When to read this file: + +- Querying **public package metadata** (descriptions, vulnerabilities, licenses, operational info). +- Working with the **Custom Catalog** (org-specific labels, package views, federation). +- Looking up **vulnerability details** beyond what Xray provides (advisories, EPSS, CWE, known exploits). +- Querying **OpenSSF scorecards**, **ML model metadata**, or **MCP service** registries. +- Using the OneModel GraphQL API with `publicPackages`, `customPackages`, + `publicSecurityInfo`, `publicLegalInfo`, `publicOperationalInfo`, + `publicCatalogLabels`, or `publicRemoteServices` query roots. + +Catalog entities are accessed via the **OneModel GraphQL API** +(`/onemodel/api/v1/graphql`). + +For the OneModel query workflow (credentials, schema fetch, validation, +execution), read `references/onemodel-graphql.md`. + +## Two catalog layers + +| Layer | Scope | Description | +|-------|-------|-------------| +| **Public Catalog** | Global | JFrog's curated package database — security, legal, and operational metadata for public packages across ecosystems | +| **Custom Catalog** | Organization | Org-specific overlay — custom labels, per-org package views, federation config | + +The Custom Catalog builds on top of the Public Catalog. A public package +can be enriched with org-specific labels and metadata through the Custom +Catalog without altering the underlying public data. + +## Public Catalog entities + +### PublicPackage + +A package as known to JFrog's global package database. + +| Field | Description | +|-------|-------------| +| `name` | Package name (e.g. `lodash`, `spring-boot-starter-web`) | +| `type` | Package type (e.g. `npm`, `maven`, `pypi`) | +| `ecosystem` | Ecosystem identifier | +| `description` | Rich-text description | +| `homepage`, `vcsUrl` | Package URLs | +| `vendor` | Maintainer or organization | +| `latestVersion` | Most recent version | +| `trendingScore` | Popularity score | +| `publishedAt`, `modifiedAt` | Timestamps | +| `mlModel` | ML model metadata (for HuggingFace etc.) | + +Connections: `versionsConnection`, `publicLabelsConnection`, `legalInfo`, +`operationalInfo`, `securityInfo`. + +Query: `publicPackages.searchPackages(where: {...})`. + +### PublicPackageVersion + +A specific version with security, legal, and operational analysis. + +| Field | Description | +|-------|-------------| +| `version` | Version string | +| `isLatest` | Whether this is the latest version | +| `isListedVersion` | Whether visible in Catalog UI | +| `publishedAt`, `modifiedAt` | Timestamps | +| `trendingScore` | Version-level popularity | +| `dependencies` | Dependency information | +| `mlModelMetadata`, `mlInfo` | ML/AI-related metadata | + +Each version carries three info blocks: +- `securityInfo` — vulnerability data, maliciousness, contextual analysis +- `legalInfo` — licenses, copyrights +- `operationalInfo` — end-of-life, OpenSSF scores, popularity metrics + +### PublicVulnerability + +Vulnerability data richer than what Xray violations expose. Useful for +deep-dive security analysis and advisory lookups. + +| Field | Description | +|-------|-------------| +| `name` | CVE identifier (e.g. `CVE-2021-44228`) | +| `ecosystem` | Affected ecosystem | +| `severity` | `CRITICAL`, `HIGH`, `MEDIUM`, `LOW` | +| `description` | Detailed impact description | +| `cvss` | CVSS scores — v2, v3, **and v4** | +| `epss` | EPSS (Exploit Prediction Scoring System) — exploit likelihood | +| `knownExploit` | Known exploit information | +| `withdrawn` | Whether the CVE has been retracted | +| `aliases` | Alternative identifiers | +| `references` | Advisory URLs | +| `publishedAt`, `modifiedAt` | Timestamps | + +Advisory sources (via `advisories` connection): +- **NVD** — NIST National Vulnerability Database +- **GHSA** — GitHub Security Advisory +- **JFrog Advisory** — JFrog's own research (includes impact reasons) +- **Debian Security Tracker** +- **RedHat OVAL** + +Additional connections: `cwesConnection` (CWE entries), `cpesConnection` +(CPE entries), `publicPackageInfo` (affected packages and versions). + +Query: `publicSecurityInfo.searchVulnerabilities(where: {...})`. + +#### Filtering limitations + +`searchVulnerabilities` can filter by CVE name, ecosystem, severity, CVSS, +EPSS, known exploit status, and publication date — but **not** by affected +package name. There is no `hasPublicPackageInfoWith` or similar filter on +`PublicVulnerabilityWhereInput`. To find vulnerabilities affecting a specific +package, use one of these alternatives: + +- **Version-level security info** (GraphQL): query + `publicPackages.getPackage(type, name)` and navigate to + `versionsConnection → securityInfo → vulnerabilitiesConnection` to get + CVEs affecting specific versions. +- **Individual CVE lookup**: use `searchVulnerabilities(where: { name: "" })` + and inspect `publicPackageInfo.vulnerablePublicPackagesConnection` on the + `generic` ecosystem entry. + +#### Ecosystem multiplicity + +A single CVE appears as multiple `PublicVulnerability` entries — one per +ecosystem. The `ecosystem` field determines which entry you see: + +| Ecosystem | Contains | +|-----------|----------| +| `generic` | Non-OS package-level data (npm, maven, pypi, go, etc.) — includes `publicPackageInfo` with vulnerable versions and fix versions | +| `debian`, `redhat`, `ubuntu`, etc. | OS-specific advisory data — severity may differ from NVD; `publicPackageInfo` is typically empty (OS packages are tracked separately) | + +When looking up a CVE by name, `searchVulnerabilities(where: { name: "" })` +returns all ecosystem entries. To get affected packages and fix versions for +libraries like npm or maven, filter for or focus on the `generic` ecosystem +entry. `getVulnerability` requires both `name` and `ecosystem` — use +`searchVulnerabilities` when the ecosystem is unknown. + +### PublicLicense + +License metadata with permission, condition, and limitation details. + +| Field | Description | +|-------|-------------| +| `name` | License name (e.g. `Apache-2.0`, `MIT`) | +| `spdxId` | SPDX identifier | +| `permissions` | What the license permits | +| `limitations` | Restrictions imposed | +| `patentConditions` | Patent grant conditions | +| `noticeFiles` | Required notices | + +Query: `publicLegalInfo.searchLicenses(where: {...})`. + +### PublicPackageOperationalInfo + +Operational risk assessment for packages and versions. + +| Entity | Key data | +|--------|----------| +| **OpenSSF scorecard** | Overall score, individual checks with scores and pass/fail | +| **End-of-life** | Whether the package or version is EOL, justification | +| **Popularity** | JFrog popularity by segment and subscription tier, download counts | + +### MCP services and tools + +The Public Catalog also indexes MCP (Model Context Protocol) services: + +| Entity | Description | +|--------|-------------| +| `PublicMcpService` | An MCP service with name, description, version | +| `PublicMcpTool` | A tool exposed by an MCP service with arguments | +| `PublicMcpRemote` | Remote MCP server configuration | + +Query: `publicRemoteServices.searchMcpServices(where: {...})`. + +## Custom Catalog entities + +### CustomPackage + +A package in the organization's private catalog view. + +| Field | Description | +|-------|-------------| +| `customCatalogId` | Org-scoped identifier | +| `name`, `type`, `ecosystem`, `namespace` | Package identity | +| `isListedPackage` | Whether visible in Catalog UI | +| `customCatalogAddedAt`, `customCatalogModifiedAt` | Org-specific timestamps | + +Connections: `versionsConnection`, `legalInfo`, +`customCatalogLabelsConnection`. + +### CustomCatalogLabel + +Organization-defined labels for categorizing packages. + +| Field | Description | +|-------|-------------| +| `name` | Label name | +| `description` | What the label represents | +| `color` | Display color | +| `labelType` | `MANUAL` or `AUTOMATIC` | +| `assignmentInfo` | How and when the label was assigned | + +Labels can be assigned to both custom packages and public packages/versions +within the org's catalog scope. The Custom Catalog mutations allow +creating, updating, and deleting labels. + +### CustomCatalogFederation + +Configuration for federating catalog data across JFrog deployments. + +## Catalog vs. Xray vs. Stored Packages + +These three domains provide different views of package and security data: + +| Aspect | Catalog | Xray | Stored Packages | +|--------|---------|------|-----------------| +| **Scope** | Global knowledge base + org overlay | Instance-scoped scanning | Instance-scoped storage | +| **Security** | CVE advisories, EPSS, CVSS v2/v3/v4, known exploits | Watches, policies, violations | Vulnerability summary (deprecated) | +| **Packages** | Public metadata (description, homepage, OpenSSF) | Components identified during scanning | Packages/versions stored in Artifactory | +| **Access** | GraphQL only | REST + CLI (`jf api /xray/...`) | GraphQL only | +| **Use case** | Research, compliance reporting, package evaluation | Runtime enforcement, CI/CD gating | Inventory, location queries | diff --git a/plugins/jfrog/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md b/plugins/jfrog/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md new file mode 100644 index 0000000..2b44979 --- /dev/null +++ b/plugins/jfrog/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md @@ -0,0 +1,93 @@ +# Bulk operations and agent execution patterns + +Platform-wide guidance for agents that gather data from multiple JFrog products +(Artifactory, Xray, Access, Distribution, etc.), run long shell +sequences, or parallelize work. Product-specific field names and endpoints live +in the other `references/*` files; this document describes **patterns**, not +one workflow. + +## List vs detail responses + +Many REST surfaces expose a **light list** (keys, names, minimal fields) and a +**richer GET by id or key**. Fields needed for audits, reporting, joins, or +permission checks may appear **only** on the detail response. Before building a +multi-step flow on a single list call, confirm in API docs or with a sample GET +whether the fields you need are present. + +## Volume, batching, and timeouts + +- Estimate **N** round-trips (list + per-item GETs, paginated APIs, etc.) before + starting so execution time and tool timeouts stay predictable. +- Prefer batching independent reads in one Shell invocation when credentials and + tier match (see SKILL.md **Batch and parallel execution**). +- Split very large work across chunks, parallel Shell calls, or subagents when + the skill's tiering guidance says so. +- Before starting an N+1 loop (list + per-item detail), **estimate wall time** + as roughly `N * 1.5s` for sequential calls. Set `block_until_ms` to at + least that estimate plus a 30-second buffer. +- For loops exceeding ~60 items, prefer a single Shell invocation that writes + progress to a log file (`>> /tmp/jf-progress-$$.log`) so partial results + are visible even if the job is interrupted. +- If the task is read-only and items are independent, consider Tier 2 or + Tier 3 parallelism (see `general-parallel-execution.md`) to reduce total time — + but respect rate limits and keep concurrency modest (4-8 parallel calls). + +## Parallelism and shared files + +**Unsafe:** Multiple concurrent processes appending lines to the **same** file +(JSONL, logs, ndjson) without synchronization. Output can interleave on one +line and break parsers (e.g. JSON "Extra data" errors). + +**Safer:** + +- Write sequentially to one file; or +- One temp file per worker or chunk, then concatenate; or +- Use advisory locking (`flock`) if one file must be shared. + +For bulk API or CLI output files, use `/tmp` or `mktemp`; do not use +`~/.jfrog/skills-cache/` except for `jfrog-skill-state.json` and the OneModel +schema file (see main SKILL.md). + +## Shell hygiene + +- Use `set -euo pipefail` in non-trivial scripts so failures are not silent. +- Use unique temp paths (e.g. `$$` in the filename) and **echo the expanded + path** so it can be reused across Shell calls (see SKILL.md **Preserving + command output** for the `$$` + echo, session ID, and hardcoded patterns). +- Parse CLI and API JSON with **`jq`**. + +## Safe multi-response collection + +When looping over items (repos, builds, users) and fetching detail for each: + +1. Save each response to a variable or per-item file. +2. Validate with `jq -e . >/dev/null 2>&1` before appending. +3. On validation failure, write a structured error line so the caller can + report partial results instead of crashing. +4. After the loop, `jq -s '.' results.ndjson` to produce a single array. + +```bash +: >results.ndjson +while read -r key; do + body=$(jf api "/artifactory/api/repositories/$key" || true) + if echo "$body" | jq -e . >/dev/null 2>&1; then + echo "$body" | jq -c . >>results.ndjson + else + printf '{"key":"%s","_error":"invalid_response"}\n' "$key" >>results.ndjson + fi +done < <(jq -r '.[].key' list.json) +jq -s '.' results.ndjson > details.json +``` + +Never pipe a loop of `jf api` calls directly into `jq -s` without +per-body validation. + +## Where to find product specifics + +- Artifactory REST nuances: `references/artifactory-api-gaps.md` +- Platform admin / Access: `references/platform-admin-api-gaps.md` +- JFrog Projects (endpoints): `references/projects-api.md` +- Joining Artifactory repos to Projects (`projectKey`, roles, environments): + `references/platform-access-entities.md` +- Platform API invocation (all products through `jf api`): see + `SKILL.md` § *Invoking platform APIs with `jf api`* diff --git a/plugins/jfrog/skills/jfrog/references/general-parallel-execution.md b/plugins/jfrog/skills/jfrog/references/general-parallel-execution.md new file mode 100644 index 0000000..a0bb9ba --- /dev/null +++ b/plugins/jfrog/skills/jfrog/references/general-parallel-execution.md @@ -0,0 +1,131 @@ +# Batch and Parallel Execution + +When a task requires multiple independent operations, use the lightest +parallelism mechanism that fits. Three tiers are available, from lightest to +heaviest: + +| Tier | Mechanism | Best for | +|------|-----------|----------| +| 1 | Single Shell call with `&&` | Few commands, same credentials | +| 2 | Parallel Shell tool calls | Independent commands that can run concurrently | +| 3 | Parallel subagents (Task tool) | Large multi-step jobs where each branch needs its own reasoning | + +## Tier 1: Batch within a single Shell call + +Combine independent commands with `&&`. All JFrog API calls go through the +same `jf api` command and the same `jf config` server, so batching them +together is both safe and efficient: + +```bash +jf api /artifactory/api/repositories > /tmp/jf-repos-$$.json && \ +jf api /artifactory/api/system/ping > /tmp/jf-ping-$$.json && \ +jf api /artifactory/api/storageinfo > /tmp/jf-storage-$$.json +``` + +Cross-product reads batch the same way: + +```bash +jf api /access/api/v2/users/ > /tmp/jf-users-$$.json && \ +jf api /access/api/v2/groups/ > /tmp/jf-groups-$$.json && \ +jf api /access/api/v2/permissions/ > /tmp/jf-perms-$$.json +``` + +## Tier 2: Parallel Shell tool calls + +Use multiple Shell tool calls in the same message when the commands are +independent and the total runtime benefits from concurrency: + +```bash +# Shell call 1 — echo the expanded path so the agent can reference it later +OUT=/tmp/jf-repos-$$.json +jf api /artifactory/api/repositories > "$OUT" && echo "$OUT" + +# Shell call 2 (parallel) — same pattern, different PID +OUT=/tmp/jf-users-$$.json +jf api /access/api/v2/users/ > "$OUT" && echo "$OUT" +``` + +Each parallel Shell call gets a different PID, so `$$` expands to different +values. Echo the path so the agent knows the literal filename for cross-call +use (see SKILL.md **Preserving command output**). + +## Tier 3: Parallel subagents + +For tasks with multiple independent branches that each require several steps +or their own reasoning — such as generating a platform health report with +separate sections, auditing both repository config and security policies, or +comparing configurations across servers the user explicitly named — launch +parallel subagents using the Task tool. + +Each subagent runs autonomously, executes its own CLI/API calls, and returns +a structured result. The parent agent assembles the final answer. + +### Example — platform audit with three parallel subagents + +``` +Subagent 1 (shell): "Collect repository data" + → jf api /artifactory/api/repositories + → jf api /artifactory/api/storageinfo + → Return repo count, types, total size + +Subagent 2 (shell): "Collect security configuration" + → jf api /xray/api/v2/policies + → jf api /xray/api/v2/watches + → Return policy count, watch count, coverage gaps + +Subagent 3 (shell): "Collect user and permission data" + → jf api /access/api/v2/users/ + → jf api /access/api/v2/groups/ + → jf api /access/api/v2/permissions/ + → Return user count, group count, admin users +``` + +All three subagents run concurrently. Once all complete, the parent agent +merges their results into a unified report. + +### How to structure a subagent prompt + +1. State the goal clearly (e.g. "Collect all Xray policies and watches"). +2. Provide the exact commands to run, or name the API tier and let the + subagent discover via `--help`. +3. Tell the subagent to save output to `/tmp/jf-