{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://unpkg.com/depcurfew/schema.json",
  "title": "depcurfew policy",
  "description": "One supply-chain security policy for npm, pnpm, Yarn, Bun, Deno, uv, pip, Poetry, PDM, Pipenv, Composer, Bundler, Cargo, Renovate and Dependabot.",
  "type": "object",
  "properties": {
    "$schema": {
      "description": "JSON Schema of this file, for editor support.",
      "type": "string"
    },
    "version": {
      "description": "Version of the policy format.",
      "type": "integer",
      "const": 1
    },
    "cooldown": {
      "description": "Release-age delay (cooldown): freshly published versions wait before they are used.",
      "type": "object",
      "properties": {
        "minimum": {
          "description": "Minimum age of a release before it is installed or proposed: a whole number followed by m (minutes), h (hours), d (days) or w (weeks). Converted to each tool's unit, always rounding up.",
          "type": "string",
          "pattern": "^[1-9][0-9]*[mhdw]$",
          "examples": [
            "3d",
            "36h",
            "1w"
          ]
        },
        "exclude": {
          "description": "Packages that skip the release-age delay, e.g. your own scope.",
          "type": "array",
          "items": {
            "description": "An npm package name such as \"esbuild\" or \"@scope/name\", or a pattern with *, such as \"@scope/*\". Python packages take the prefix pypi:, e.g. \"pypi:requests\" or \"pypi:acme-*\", and Composer packages the prefix composer:, e.g. \"composer:monolog/monolog\" or \"composer:acme/*\". No versions.",
            "type": "string",
            "pattern": "^(?:pypi:(?!\\*+$)[A-Za-z0-9*](?:[A-Za-z0-9._*-]*[A-Za-z0-9*])?|composer:(?!\\*+/\\*+$)[a-z0-9*](?:[a-z0-9._*-]*[a-z0-9*])?/[a-z0-9*](?:[a-z0-9._*-]*[a-z0-9*])?|(?!\\*+$)(@[A-Za-z0-9~*-][A-Za-z0-9._~*_-]*/)?[A-Za-z0-9~*-][A-Za-z0-9._~*_-]*)$"
          },
          "uniqueItems": true,
          "default": []
        },
        "securityUpdates": {
          "description": "Whether security updates skip the delay (\"bypass\") or wait like other updates (\"delay\"), where the tool can tell them apart.",
          "type": "string",
          "enum": [
            "bypass",
            "delay"
          ],
          "default": "bypass"
        }
      },
      "required": [
        "minimum"
      ],
      "additionalProperties": false
    },
    "installScripts": {
      "description": "Code that dependencies run when they are installed: lifecycle scripts in npm, building from source in Python, plugins in Composer.",
      "type": "object",
      "properties": {
        "default": {
          "description": "Whether dependency lifecycle scripts (preinstall, install, postinstall) run by default; for Python, whether packages may be built from source; for Composer, whether plugins may run.",
          "type": "string",
          "enum": [
            "allow",
            "deny"
          ]
        },
        "allow": {
          "description": "Packages whose lifecycle scripts may run when the default is \"deny\"; Python packages listed here are always built from source; Composer packages listed here are the plugins allow-plugins lets run.",
          "type": "array",
          "items": {
            "description": "An npm package name such as \"esbuild\" or \"@scope/name\", or a pattern with *, such as \"@scope/*\". Python packages take the prefix pypi:, e.g. \"pypi:requests\" or \"pypi:acme-*\", and Composer packages the prefix composer:, e.g. \"composer:monolog/monolog\" or \"composer:acme/*\". No versions.",
            "type": "string",
            "pattern": "^(?:pypi:(?!\\*+$)[A-Za-z0-9*](?:[A-Za-z0-9._*-]*[A-Za-z0-9*])?|composer:(?!\\*+/\\*+$)[a-z0-9*](?:[a-z0-9._*-]*[a-z0-9*])?/[a-z0-9*](?:[a-z0-9._*-]*[a-z0-9*])?|(?!\\*+$)(@[A-Za-z0-9~*-][A-Za-z0-9._~*_-]*/)?[A-Za-z0-9~*-][A-Za-z0-9._~*_-]*)$"
          },
          "uniqueItems": true,
          "default": []
        },
        "deny": {
          "description": "Packages you reviewed that work without their lifecycle scripts, so the scripts stay blocked on purpose and doctor does not report them, for example \"fsevents\", which ships a prebuilt binary. depcurfew init fills it with the packages of the lockfile whose scripts depcurfew knows to be unneeded (esbuild, fsevents) or to do only a task of the project (lefthook). A package cannot be in both lists, also not through two patterns that match the same name. Python packages listed here must not be built from source: doctor reports a tool that would still build one. Composer packages listed here are plugins that allow-plugins disallows.",
          "type": "array",
          "items": {
            "description": "An npm package name such as \"esbuild\" or \"@scope/name\", or a pattern with *, such as \"@scope/*\". Python packages take the prefix pypi:, e.g. \"pypi:requests\" or \"pypi:acme-*\", and Composer packages the prefix composer:, e.g. \"composer:monolog/monolog\" or \"composer:acme/*\". No versions.",
            "type": "string",
            "pattern": "^(?:pypi:(?!\\*+$)[A-Za-z0-9*](?:[A-Za-z0-9._*-]*[A-Za-z0-9*])?|composer:(?!\\*+/\\*+$)[a-z0-9*](?:[a-z0-9._*-]*[a-z0-9*])?/[a-z0-9*](?:[a-z0-9._*-]*[a-z0-9*])?|(?!\\*+$)(@[A-Za-z0-9~*-][A-Za-z0-9._~*_-]*/)?[A-Za-z0-9~*-][A-Za-z0-9._~*_-]*)$"
          },
          "uniqueItems": true,
          "default": []
        }
      },
      "required": [
        "default"
      ],
      "additionalProperties": false
    },
    "sources": {
      "description": "Where dependencies may come from besides the registry. An absent field is not managed.",
      "type": "object",
      "properties": {
        "git": {
          "description": "Dependencies installed from git repositories.",
          "type": "string",
          "enum": [
            "allow",
            "deny"
          ]
        },
        "remoteTarball": {
          "description": "Dependencies installed from tarball URLs outside the registry.",
          "type": "string",
          "enum": [
            "allow",
            "deny"
          ]
        },
        "file": {
          "description": "Dependencies installed from local tarball files.",
          "type": "string",
          "enum": [
            "allow",
            "deny"
          ]
        },
        "directory": {
          "description": "Dependencies installed from local directories.",
          "type": "string",
          "enum": [
            "allow",
            "deny"
          ]
        }
      },
      "additionalProperties": false
    },
    "targets": {
      "description": "Tools to configure: \"auto\" detects them in the repository, or list them explicitly.",
      "anyOf": [
        {
          "description": "Configure the tools detected in the repository.",
          "type": "string",
          "const": "auto"
        },
        {
          "description": "Configure exactly these tools.",
          "type": "array",
          "items": {
            "description": "A tool depcurfew can configure.",
            "type": "string",
            "enum": [
              "npm",
              "pnpm",
              "yarn",
              "bun",
              "deno",
              "uv",
              "pip",
              "poetry",
              "pdm",
              "pipenv",
              "composer",
              "bundler",
              "cargo",
              "renovate",
              "dependabot"
            ]
          },
          "uniqueItems": true,
          "minItems": 1
        }
      ],
      "default": "auto"
    },
    "projects": {
      "description": "Directories of independent projects in this repository, each with its own manifest and lockfile (e.g. frontend and backend). depcurfew configures each one with this policy as a project of its own, and configures Renovate and Dependabot once, from the repository root, for all of them. The repository root is always configured as well. A project must not be inside another one, must not be a workspace package of the root and must not have a depcurfew.json of its own.",
      "type": "array",
      "items": {
        "description": "A directory relative to the repository root, with / between directories, e.g. \"frontend\" or \"services/api\". No patterns, no \"..\", no / at either end.",
        "type": "string",
        "pattern": "^(?!\\.\\.?(?:/|$))(?!.*/\\.\\.?(?:/|$))(?!(?:.*/)?(?:node_modules|\\.git)(?:/|$))[^/\\\\:*?\"<>|\\u0000-\\u001f\\u007f]+(?:/[^/\\\\:*?\"<>|\\u0000-\\u001f\\u007f]+)*$",
        "examples": [
          "frontend",
          "services/api"
        ]
      },
      "uniqueItems": true,
      "default": []
    },
    "doctor": {
      "description": "How depcurfew doctor and the GitHub Action treat findings. Without this section only errors fail, as before; depcurfew init writes \"failOn\": \"warning\".",
      "type": "object",
      "properties": {
        "failOn": {
          "description": "Which findings make depcurfew doctor exit with 1 and fail the GitHub Action: \"error\" (only errors, also when left out) or \"warning\" (warnings too). Notes never fail. doctor --fail-on and the input fail-on of the Action override it.",
          "type": "string",
          "enum": [
            "error",
            "warning"
          ]
        }
      },
      "additionalProperties": false
    }
  },
  "required": [
    "version"
  ],
  "additionalProperties": false
}
