{
  "schema": "aaes/capability-pack/1",
  "provider": "artifactory",
  "version": "1.0.0",
  "description": "JFrog Artifactory REST API on the customer's own deployment: list repositories and storage items, search with AQL, deploy artifacts, and delete items and repositories.",
  "notes": "The endpoint host 'artifactory-server.invalid' is a reserved non-production placeholder (an RFC 2606 reserved TLD): substitute the customer's own JFrog Platform Deployment host before enabling, in every endpoint, in the resource locator and in every egress allowlist entry. The allowlist matches exactly, so endpoints and allowlist must be substituted together, and substitution is a required deployment step. REPO_KEY and FILE_PATH in the endpoint paths are placeholders: bind them to the repository key and the item path this capability governs before enabling.\n\nThis pack registers only Artifactory's documented REST API: listing repositories, storage item info, AQL search, artifact deploy, item delete, repository create and repository delete.\n\nApproval classification: reads and the read-only AQL query sit at the minimum R0 tier. Artifact deploy (PUT on the item path) is registered as create and update at the minimum R2 tier: uploading an artifact adds a new binary and, with Artifactory's default non-unique snapshot layouts or release paths, does not destroy other artifacts — but where a repository layout permits overwriting an existing path, a deploy replaces the stored binary, so the update action is declared, and this registration cannot restrict the bytes a caller uploads.\n\nRepository create is R2 create; its request body is the full repository configuration, which this registration does not constrain. Item delete and repository delete sit at the minimum R3 tier: delete is one of the designated actions requiring human approval. Repository delete removes the repository and every artifact in it — Artifactory's trash can (when enabled) retains deleted ITEMS but not a deleted repository's configuration — and this registration makes no restoration claim.\n\nSearch scope: AQL is a POST carrying a query body (a raw AQL statement, Content-Type text/plain) used read-only — it performs no mutation, so it is registered as a read at the minimum R0 tier with the body shape noted here; the statement itself is unrestricted AQL and can enumerate anything the token's user may read.\n\nDocumented exclusions: this pack does not register permission-target management (PUT/DELETE /api/security/permissions/...), user or group management, the Access token REST API (token issuance is an external custody process — see the credential note), Empty Trash Can (POST /api/trash/empty — a permanent purge of soft-deleted items, distinct from item delete and deliberately left out), replication configuration, system import/export, and all Xray and Distribution APIs. Source basis: the individual JFrog operation pages were retrieved from JFrog's docs.jfrog.com markdown/OpenAPI mirror (the llms.txt operation index plus the per-operation.md pages for Get Repositories by Type and Project, Get Storage Item Information, Search AQL, Deploy Artifact, Create Repository, Delete Repository and Empty Trash Can, all appended to review.sources).\n\nEvery registered method and path was confirmed against JFrog's OpenAPI definitions on those pages: GET /artifactory/api/repositories, GET /artifactory/api/storage/{repoKey}/{itemPath}, POST /artifactory/api/search/aql (text/plain AQL body), PUT /artifactory/{repoKey}/{filePath}, DELETE /artifactory/{repoKey}/{filePath}, PUT and DELETE /artifactory/api/repositories/{repoKey}, and the excluded POST /artifactory/api/trash/empty (admin only). Confirm each path and request contract against the target deployment's own API documentation before enabling — documentation review is complete; target-deployment confirmation remains required before use.",
  "credential": {
    "secret_ref_id": "secret-ref-artifactory-access-token",
    "custody": "customer_vault",
    "inject": "header",
    "inject_name": "Authorization",
    "note": "A JFrog Platform access token, held in the client's own secret manager. Token issuance is external: an administrator creates a scoped token in the JFrog Platform UI (User Management | Access Tokens) or via the Create Token REST API, and the deployment's custody job stores the result under this reference. The stored material must be the complete Authorization header value (scheme included): 'Bearer ' followed by the access token — JFrog documents using an access token as a bearer token in the Authorization header. JFrog also accepts a reference token as the password half of HTTP Basic authentication; this pack registers the Bearer header form only.\n\nExpiry and revocation behavior, tokens are created with an expiry (default one hour; zero means non-expiring and valid until actively revoked), and JFrog's revocable-expiry-threshold (default six hours) means a token created with a shorter lifetime cannot be revoked — it remains valid until it expires naturally. Disabling token issuance, or removing the creating admin, does not invalidate already-issued tokens; only an explicit revoke of a revocable token, or resetting the token certificates (which revokes all tokens), terminates one.\n\nPrefer the shortest expiry that covers the deployment's renewal cadence, or a refreshable token renewed by the custody job; an expired value fails closed.\n\nLeast privilege: create the token with group scopes granting only the permissions the enabled capabilities need (read on the bound repositories; deploy/delete only where the write capabilities are enabled) — never an admin-scoped token FOR THE READ, AQL, DEPLOY and ITEM-DELETE CAPABILITIES. The repository create and delete capabilities are different: JFrog documents repository administration as requiring an administrator, so this pack registers those two capabilities against a SEPARATE reference (secret-ref-artifactory-admin-token) holding an admin-permission credential — a deployment that cannot justify an admin credential must remove those two capabilities rather than widen the main token.\n\nNote also that delete operations require the user or group to hold delete permission per JFrog's documentation.\n\nExecutor hygiene: the value must live only in executor memory for the lifetime of a call, must never be written to logs, traces or diagnostics, and must not appear in crash dumps; a deployment that cannot meet that bar must not enable the pack."
  },
  "capabilities": [
    {
      "capability_id": "artifactory.repositories.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "artifactory-server.invalid"
      ],
      "endpoint": "https://artifactory-server.invalid/artifactory/api/repositories",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-artifactory-access-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "artifactory-instance",
      "description": "List the repositories on the deployment: keys, types and package types — a collection read that reveals the organization's artifact landscape at the internal class.\n\nThe host is a reserved placeholder: substitute the customer's JFrog host before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "artifactory.storage.item.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "artifactory-server.invalid"
      ],
      "endpoint": "https://artifactory-server.invalid/artifactory/api/storage/REPO_KEY/FILE_PATH",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-artifactory-access-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "artifactory-instance",
      "description": "Read storage information (metadata, checksums, timestamps, URIs) for one item or folder via the Get Storage Item Information operation; this reads metadata, not the artifact binary — artifact download itself is not registered by this pack. REPO_KEY and FILE_PATH are placeholders to bind before enabling; the host is a reserved placeholder to substitute.",
      "requires_review": true
    },
    {
      "capability_id": "artifactory.search.aql",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "artifactory-server.invalid"
      ],
      "endpoint": "https://artifactory-server.invalid/artifactory/api/search/aql",
      "method": "POST",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-artifactory-access-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "artifactory-instance",
      "description": "Run an Artifactory Query Language search. This is a POST-with-query-body endpoint used read-only: the request body is a raw AQL statement (Content-Type text/plain, for example items.find({...})) and the operation performs no mutation, so it registers as read at the minimum R0 tier.\n\nRequest limits: the statement is unrestricted AQL — this registration cannot limit which items, properties or builds a caller enumerates beyond what the token's user may read.\n\nThe host is a reserved placeholder: substitute before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "artifactory.artifact.deploy",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R2",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "artifactory-server.invalid"
      ],
      "endpoint": "https://artifactory-server.invalid/artifactory/REPO_KEY/FILE_PATH",
      "method": "PUT",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-artifactory-access-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "create",
        "update"
      ],
      "resource_id": "artifactory-instance",
      "description": "Deploy an artifact (or create a directory) to a repository path — the documented Deploy Artifact operation. Registered as create and update at the minimum R2 tier: uploading to a path that does not exist creates the artifact, and where the repository layout permits overwriting an existing path, a deploy replaces the stored binary — the previous bytes are not recoverable from Artifactory afterward, so this is not a create-only registration.\n\nThis registration does not restrict the uploaded bytes; deployments that require immutability should enforce it in repository configuration, which this pack does not register. Requires deploy permission on the target repository. REPO_KEY and FILE_PATH are placeholders to bind before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "artifactory.item.delete",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "artifactory-server.invalid"
      ],
      "endpoint": "https://artifactory-server.invalid/artifactory/REPO_KEY/FILE_PATH",
      "method": "DELETE",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-artifactory-access-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "delete"
      ],
      "resource_id": "artifactory-instance",
      "description": "Delete a file or folder from a local repository or remote repository cache — the documented Delete Item operation, which JFrog's documentation states requires delete permission and returns 405 for repository types that do not support deletion. Registered as delete at the minimum R3 tier: delete is one of the designated actions requiring human approval.\n\nOn supported AAES-mediated execution paths, irreversible actions require approval by an authorized person; this does not prevent calls through bypass or observation-only paths. Where the deployment has the trash can enabled, the deleted item may be recoverable from trash; this registration makes no restoration claim, and permanently purging trash (POST /api/trash/empty) is deliberately not registered. REPO_KEY and FILE_PATH are placeholders to bind before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "artifactory.repository.create",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R2",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "artifactory-server.invalid"
      ],
      "endpoint": "https://artifactory-server.invalid/artifactory/api/repositories/REPO_KEY",
      "method": "PUT",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-artifactory-admin-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "create"
      ],
      "resource_id": "artifactory-instance",
      "description": "Create a repository — the documented Create Repository operation, which takes the repository configuration JSON in the request body. Registered as create at the minimum R2 tier; a created repository can be removed by the registered delete capability.\n\nRequest limits: the configuration body is unrestricted by this registration — repository type, layout, remote URL and other settings are the caller's input and the deployment's review; in particular a configured REMOTE repository URL causes ARTIFACTORY-SIDE outbound access to that destination when artifacts are resolved, which AAES's egress allowlist on this capability does not constrain. This capability uses a separate admin credential reference (secret-ref-artifactory-admin-token) — see the pack credential note. REPO_KEY is a placeholder to bind before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "artifactory.repository.delete",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "artifactory-server.invalid"
      ],
      "endpoint": "https://artifactory-server.invalid/artifactory/api/repositories/REPO_KEY",
      "method": "DELETE",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-artifactory-admin-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "delete"
      ],
      "resource_id": "artifactory-instance",
      "description": "Delete a repository — the documented Delete Repository operation. This removes the repository and every artifact stored in it: a broad-impact delete registered at the minimum R3 tier. Artifactory's trash can retains deleted items, not a deleted repository's configuration, so this registration makes no restoration claim. This capability uses a separate admin credential reference (secret-ref-artifactory-admin-token) — see the pack credential note. REPO_KEY is a placeholder to bind before enabling.\n\nOn supported AAES-mediated execution paths, the declared irreversible actions require an authorized person’s approval. Observation-only and bypass calls cannot be stopped by this control.",
      "requires_review": true
    }
  ],
  "resources": [
    {
      "resource_id": "artifactory-instance",
      "kind": "api",
      "locator": "https://artifactory-server.invalid/artifactory",
      "data_class": "internal",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    }
  ],
  "review": {
    "state": "library",
    "date": "2026-09-22",
    "sources": [
      "https://jfrog.com/help/r/jfrog-rest-apis/delete-item (retrieved 2026-09-21)",
      "https://jfrog.com/help/r/jfrog-platform-administration-documentation/access-tokens (retrieved 2026-09-21)",
      "https://docs.jfrog.com/artifactory/reference/llms.txt (retrieved 2026-09-21)",
      "https://docs.jfrog.com/artifactory/reference/deployartifact.md (retrieved 2026-09-21)",
      "https://docs.jfrog.com/artifactory/reference/getstorageitem.md (retrieved 2026-09-21)",
      "https://docs.jfrog.com/artifactory/reference/createrepository.md (retrieved 2026-09-21)",
      "https://docs.jfrog.com/artifactory/reference/deleterepository.md (retrieved 2026-09-21)",
      "https://docs.jfrog.com/artifactory/reference/emptytrashcan.md (retrieved 2026-09-21)",
      "https://docs.jfrog.com/artifactory/reference/searchaql.md (retrieved 2026-09-21)",
      "https://docs.jfrog.com/artifactory/reference/getrepositoriesbytypeandproject.md (retrieved 2026-09-21)"
    ],
    "reviewer_id": "aaes-eng"
  }
}
