diff --git a/src/api/json/catalog.json b/src/api/json/catalog.json index ddbcf886112..9554022b6c8 100644 --- a/src/api/json/catalog.json +++ b/src/api/json/catalog.json @@ -11622,20 +11622,22 @@ "name": "cfgd Config", "description": "cfgd root configuration file (cfgd.yaml)", "fileMatch": ["cfgd.yaml", "cfgd.yml"], - "url": "https://www.schemastore.org/cfgd-config-0.10.0.json", + "url": "https://www.schemastore.org/cfgd-config-0.11.0.json", "versions": { "0.5.0": "https://www.schemastore.org/cfgd-config-0.5.0.json", - "0.10.0": "https://www.schemastore.org/cfgd-config-0.10.0.json" + "0.10.0": "https://www.schemastore.org/cfgd-config-0.10.0.json", + "0.11.0": "https://www.schemastore.org/cfgd-config-0.11.0.json" } }, { "name": "cfgd Module", "description": "cfgd Module definition document", "fileMatch": ["**/modules/*/module.yaml"], - "url": "https://www.schemastore.org/cfgd-module-0.10.0.json", + "url": "https://www.schemastore.org/cfgd-module-0.11.0.json", "versions": { "0.5.0": "https://www.schemastore.org/cfgd-module-0.5.0.json", - "0.10.0": "https://www.schemastore.org/cfgd-module-0.10.0.json" + "0.10.0": "https://www.schemastore.org/cfgd-module-0.10.0.json", + "0.11.0": "https://www.schemastore.org/cfgd-module-0.11.0.json" } }, { @@ -11646,20 +11648,22 @@ "**/profiles/*.yaml", "**/profiles/*.yml" ], - "url": "https://www.schemastore.org/cfgd-profile-0.10.0.json", + "url": "https://www.schemastore.org/cfgd-profile-0.11.0.json", "versions": { "0.5.0": "https://www.schemastore.org/cfgd-profile-0.5.0.json", - "0.10.0": "https://www.schemastore.org/cfgd-profile-0.10.0.json" + "0.10.0": "https://www.schemastore.org/cfgd-profile-0.10.0.json", + "0.11.0": "https://www.schemastore.org/cfgd-profile-0.11.0.json" } }, { "name": "cfgd ConfigSource", "description": "cfgd multi-source configuration manifest (cfgd-source.yaml)", "fileMatch": ["cfgd-source.yaml", "cfgd-source.yml"], - "url": "https://www.schemastore.org/cfgd-configsource-0.10.0.json", + "url": "https://www.schemastore.org/cfgd-configsource-0.11.0.json", "versions": { "0.5.0": "https://www.schemastore.org/cfgd-configsource-0.5.0.json", - "0.10.0": "https://www.schemastore.org/cfgd-configsource-0.10.0.json" + "0.10.0": "https://www.schemastore.org/cfgd-configsource-0.10.0.json", + "0.11.0": "https://www.schemastore.org/cfgd-configsource-0.11.0.json" } }, { diff --git a/src/schema-validation.jsonc b/src/schema-validation.jsonc index a3ddb768ae6..0d63d174bb1 100644 --- a/src/schema-validation.jsonc +++ b/src/schema-validation.jsonc @@ -117,24 +117,12 @@ "minecraft-predicate.json", "minecraft-recipe.json", "minecraft-template-pool.json", - "mtad.json", - "mprocs-0.6.4.json", - "nest-cli.json", - "netlify.json", "nuget-project-3.3.0.json", "nuget-project.json", - "opensrm.json", "opspec-io-0.1.7.json", "package.json", - "paper-plugin.json", - "partial-eslint-plugins.json", - "phrase.json", - "pre-commit-config.json", "prisma.json", - "prometheus.json", "putout.json", - "pyrseas-0.8.json", - "pylock.json", "renovate-39.json", "renovate-40.json", "renovate-41.json", @@ -146,28 +134,15 @@ "renovate-inherited-schema-42.json", "renovate-inherited-schema-43.json", "sigmacv.json", - "size-limit.json", "stylelintrc.json", "template.json", - "tmlanguage.json", "tslint.json", "typings.json", "typingsrc.json", "typo3.json", - "urai-ecma.json", - "utam-page-object.json", - "utam-page-object-1.5.0.json", - "utam-page-object-2.0.3.json", - "utam-page-object-2.2.0.json", "utcm-monitor.json", "vector.json", "vss-extension.json", - "vtesttree-schema-v1.0.0.json", - "vtesttree-schema-v2.0.0.json", - "vtesttree-schema-v2.1.0.json", - "vtesttree-schema-v2.2.0.json", - "vtesttree-schema-v2.3.0.json", - "vtesttree-schema-v2.4.0.json", "webextension.json", "winget-pkgs-singleton-0.1.json", "workflows.json", @@ -183,17 +158,10 @@ "lsdlschema-3.2.json", "lsdlschema-3.3.json", "lsdlschema.json", - "nodemon.json", - "openhab-5.1.json", - "partial-pyright.json", - "pep-723.json", - "pyproject.json", - "starlake.json", "metaschema-draft-07-unofficial-strict.json", "glazewm.json", "youtrack-app.json", "cinnamon-spice-settings.json", - "pnpm-workspace.json", "podman-desktop-extension.json", "podman-desktop-extension-1.27.json" ], @@ -277,7 +245,8 @@ "enonic-xp-task-8.0.0.json", "enonic-xp-webapp-8.0.0.json", "cfgd-module-0.5.0.json", - "cfgd-module-0.10.0.json" + "cfgd-module-0.10.0.json", + "cfgd-module-0.11.0.json" ], "missingCatalogUrl": [ // Below this line are subschemas that are included from other schema @@ -1551,6 +1520,12 @@ }, "vespertide-model.json": { "unknownFormat": ["uint32", "int64", "double", "int32"] + }, + "cfgd-config-0.11.0.json": { + "unknownFormat": ["uint32"] + }, + "cfgd-profile-0.11.0.json": { + "unknownFormat": ["uint32"] } } } diff --git a/src/schemas/json/cfgd-config-0.11.0.json b/src/schemas/json/cfgd-config-0.11.0.json new file mode 100644 index 00000000000..decb059e25c --- /dev/null +++ b/src/schemas/json/cfgd-config-0.11.0.json @@ -0,0 +1,1106 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://cfgd.io/schemas/cfgd-config.schema.json", + "additionalProperties": false, + "definitions": { + "AiConfig": { + "additionalProperties": false, + "description": "`spec.ai`: settings for `cfgd generate`'s AI-guided session.\n\n```yaml\nai:\n provider: claude\n model: claude-sonnet-5\n apiKeyEnv: ANTHROPIC_API_KEY\n```", + "properties": { + "apiKeyEnv": { + "default": "ANTHROPIC_API_KEY", + "description": "Name of the environment variable holding the API key. Default: `ANTHROPIC_API_KEY`.", + "type": "string" + }, + "model": { + "default": "claude-sonnet-5", + "description": "The model identifier to request. Default: `claude-sonnet-5`.", + "type": "string" + }, + "provider": { + "default": "claude", + "description": "The AI provider name. Default: `claude`.", + "type": "string" + } + }, + "type": "object" + }, + "AutoApplyPolicyConfig": { + "additionalProperties": false, + "description": "`spec.daemon.reconcile.policy`: what the daemon does when a source recommends\na module change it did not previously know about.\n\n```yaml\npolicy:\n newRecommended: Accept\n newOptional: Ignore\n lockedConflict: Notify\n```", + "properties": { + "lockedConflict": { + "$ref": "#/definitions/PolicyAction", + "default": "Notify", + "description": "Action when a source's recommendation conflicts with a locked version.\nDefault: `Notify`." + }, + "newOptional": { + "$ref": "#/definitions/PolicyAction", + "default": "Ignore", + "description": "Action for a newly available optional module. Default: `Ignore`." + }, + "newRecommended": { + "$ref": "#/definitions/PolicyAction", + "default": "Notify", + "description": "Action for a newly recommended module. Default: `Notify`." + } + }, + "type": "object" + }, + "ComplianceConfig": { + "additionalProperties": false, + "description": "`spec.compliance`: periodic snapshotting of machine state for drift/audit history.\n\n```yaml\ncompliance:\n enabled: true\n interval: 1h\n retention: 30d\n scope:\n files: true\n packages: true\n export:\n format: Json\n path: ~/.local/state/cfgd/compliance/\n```", + "properties": { + "enabled": { + "default": false, + "description": "Whether the daemon takes compliance snapshots on its tick. Default: `false`.", + "type": "boolean" + }, + "export": { + "$ref": "#/definitions/ComplianceExport", + "default": { + "format": "Json", + "path": "~/.local/state/cfgd/compliance/" + }, + "description": "Where and in what format a snapshot is exported." + }, + "interval": { + "default": "1h", + "description": "How often a snapshot is taken, as a duration string. Default: `1h`.", + "type": "string" + }, + "retention": { + "default": "30d", + "description": "How long a snapshot is kept before being pruned, as a duration string.\nDefault: `30d`.", + "type": "string" + }, + "scope": { + "$ref": "#/definitions/ComplianceScope", + "default": { + "files": true, + "packages": true, + "secrets": true, + "system": true, + "watchPackageManagers": [], + "watchPaths": [] + }, + "description": "Which surfaces a snapshot covers." + } + }, + "type": "object" + }, + "ComplianceExport": { + "additionalProperties": false, + "description": "`spec.compliance.export`: where a compliance snapshot is written.\n\n```yaml\nexport:\n format: Yaml\n path: ~/.local/state/cfgd/compliance/\n```", + "properties": { + "format": { + "$ref": "#/definitions/ComplianceFormat", + "default": "Json", + "description": "Export file format. Default: `Json`." + }, + "path": { + "default": "~/.local/state/cfgd/compliance/", + "description": "Directory a snapshot file is written into. Default:\n`~/.local/state/cfgd/compliance/`.", + "type": "string" + } + }, + "type": "object" + }, + "ComplianceFormat": { + "description": "Serialization format for a compliance export: `Json` or `Yaml`\n(case-insensitive on read; `PascalCase` in generated YAML).", + "enum": ["Json", "Yaml"], + "type": "string" + }, + "ComplianceScope": { + "additionalProperties": false, + "description": "`spec.compliance.scope`: which managed surfaces a snapshot covers.\n\n```yaml\nscope:\n files: true\n packages: true\n system: true\n secrets: false\n watchPaths: [/etc/hosts]\n watchPackageManagers: [apt]\n```", + "properties": { + "files": { + "default": true, + "description": "Include declared files' content/permission state. Default: `true`.", + "type": "boolean" + }, + "packages": { + "default": true, + "description": "Include declared packages' installed state. Default: `true`.", + "type": "boolean" + }, + "secrets": { + "default": true, + "description": "Include declared secrets' presence/hash state (never plaintext). Default: `true`.", + "type": "boolean" + }, + "system": { + "default": true, + "description": "Include system configurator settings. Default: `true`.", + "type": "boolean" + }, + "watchPackageManagers": { + "default": [], + "description": "Extra package managers to watch beyond those a module declares against.", + "items": { + "type": "string" + }, + "type": "array" + }, + "watchPaths": { + "default": [], + "description": "Extra filesystem paths to watch for drift beyond declared files.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "ConfigMetadata": { + "additionalProperties": false, + "description": "`metadata`: identifying information for a `cfgd.yaml` document.", + "properties": { + "name": { + "description": "A human-chosen name for this machine's config, shown in status output.", + "type": "string" + } + }, + "required": ["name"], + "type": "object" + }, + "ConfigSpec": { + "additionalProperties": false, + "description": "`spec`: the body of a `cfgd.yaml` document.", + "properties": { + "ai": { + "anyOf": [ + { + "$ref": "#/definitions/AiConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "AI assistant configuration: provider, model, and API key env var." + }, + "aliases": { + "additionalProperties": { + "type": "string" + }, + "default": {}, + "description": "CLI aliases: map of alias name → command string.\nBuilt-in defaults (add, remove) can be overridden or extended.", + "type": "object" + }, + "compliance": { + "anyOf": [ + { + "$ref": "#/definitions/ComplianceConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Periodic snapshots of machine state, for drift history and audit.\nOmitted, no snapshots are taken and `cfgd compliance` reports only\nwhat it collects on the spot." + }, + "daemon": { + "anyOf": [ + { + "$ref": "#/definitions/DaemonConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The background daemon that watches for drift between reconciles.\nOmitted, no daemon runs and every reconcile is an explicit\n`cfgd apply`." + }, + "fileStrategy": { + "default": "Symlink", + "description": "Global default file deployment strategy. Per-file overrides take precedence.\n\n`Patch` is rejected here: it is defined by a per-file `patch:` block,\nwhich a file inheriting the global default cannot have.", + "enum": ["Symlink", "Copy", "Template", "Hardlink"], + "type": "string" + }, + "modules": { + "anyOf": [ + { + "$ref": "#/definitions/ModulesConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Module configuration: registries and security." + }, + "origin": { + "default": [], + "description": "Git origins this config's changes may be pushed to / pulled from.", + "items": { + "$ref": "#/definitions/OriginSpec" + }, + "type": "array" + }, + "output": { + "anyOf": [ + { + "$ref": "#/definitions/OutputConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "How cfgd renders what it reports: theme, usage hints, and which\ndeclared env values are masked. Omitted, every default applies." + }, + "profile": { + "default": null, + "description": "Name of the active `ProfileSpec` to reconcile against.", + "type": ["string", "null"] + }, + "secrets": { + "anyOf": [ + { + "$ref": "#/definitions/SecretsConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Which backend resolves a `${secret:…}` reference, and how it is\nreached. Omitted, no backend is configured and a declared secret\nreference fails to resolve." + }, + "security": { + "anyOf": [ + { + "$ref": "#/definitions/SecurityConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Security settings for source signature verification." + }, + "sources": { + "default": [], + "description": "Additional config sources this machine subscribes to.", + "items": { + "$ref": "#/definitions/SourceSpec" + }, + "type": "array" + }, + "update": { + "anyOf": [ + { + "$ref": "#/definitions/UpdateConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Update policy for the cfgd binary and authored skills." + } + }, + "type": "object" + }, + "DaemonConfig": { + "additionalProperties": false, + "description": "`spec.daemon`: settings for `cfgd daemon`'s background reconcile loop.\n\n```yaml\ndaemon:\n enabled: true\n reconcile:\n interval: 5m\n autoApply: false\n sync:\n autoPull: true\n notify:\n drift: true\n```", + "properties": { + "enabled": { + "default": false, + "description": "Whether the daemon runs at all. Default: `false`.", + "type": "boolean" + }, + "notify": { + "anyOf": [ + { + "$ref": "#/definitions/NotifyConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "How the daemon reports detected drift." + }, + "reconcile": { + "anyOf": [ + { + "$ref": "#/definitions/ReconcileConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "How often the daemon looks for drift and what it does when it finds\nsome. Omitted, the daemon reconciles on the built-in defaults: every\n`5m`, notifying rather than applying." + }, + "sync": { + "anyOf": [ + { + "$ref": "#/definitions/SyncConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Whether the daemon keeps the config directory in step with its git\nremote, and how often. Omitted, the daemon never touches git and every\npull or push stays a manual `cfgd sync`." + }, + "windowsEventLog": { + "default": false, + "description": "Mirror daemon log output into the Windows Event Log under the `cfgd`\nsource, in addition to the default file appender at\n`%LOCALAPPDATA%\\cfgd\\daemon.log`. No effect on Unix. Read by\n`cfgd daemon install` to bake `--enable-event-log` into the service\nbinPath; changes require reinstalling the service to take effect.", + "type": "boolean" + } + }, + "type": "object" + }, + "DriftPolicy": { + "description": "Daemon drift reconciliation policy. Values are PascalCase, matching\nKubernetes API conventions.", + "oneOf": [ + { + "const": "Auto", + "description": "Apply drift corrections automatically (current behavior, now opt-in).", + "type": "string" + }, + { + "const": "NotifyOnly", + "description": "Notify and record drift, but do not apply. User must run `cfgd apply`.", + "type": "string" + }, + { + "const": "Prompt", + "description": "Future: notify with actionable prompt.", + "type": "string" + } + ] + }, + "MaskEnvValues": { + "description": "Which declared env values cfgd masks on the surfaces that render one\n(`module show`, `profile show`, `source show`, `status `).\n\nA masked value renders as `***` plus its last three characters; the stored\nvalue and `-o json` are untouched either way.", + "oneOf": [ + { + "const": "All", + "description": "Mask every declared value. The default.", + "type": "string" + }, + { + "const": "Secrets", + "description": "Mask only a value a declared secret exports: a name listed in any\n`spec.secrets[].envs` of the resolved chain. Every other value renders\nin full.", + "type": "string" + }, + { + "const": "None", + "description": "Mask nothing: every declared value renders in full, as though\n`--show-values` had been passed to every verb that takes it.", + "type": "string" + } + ] + }, + "ModuleRegistryEntry": { + "additionalProperties": false, + "description": "A module registry — a git repo containing modules in `modules//module.yaml` structure.", + "properties": { + "name": { + "description": "Short name / alias for this source (defaults to GitHub org name).", + "type": "string" + }, + "url": { + "description": "Git URL of the registry repository, in any form git accepts — an HTTPS\nor SSH clone URL, or a GitHub `owner/repo` shorthand cfgd expands to the\nfull URL. Required. The repository is cloned into the local cache and\nscanned for `modules//module.yaml` entries, which is what\n`cfgd module search` and `cfgd module add` resolve against.", + "type": "string" + } + }, + "required": ["name", "url"], + "type": "object" + }, + "ModuleSecurityConfig": { + "additionalProperties": false, + "description": "`spec.modules.security`: signature requirements for modules pulled from a registry.", + "properties": { + "requireSignatures": { + "default": false, + "description": "Require GPG/SSH signatures on all remote module tags.\nWhen true, unsigned modules are rejected unless `--allow-unsigned` is passed.", + "type": "boolean" + } + }, + "type": "object" + }, + "ModulesConfig": { + "additionalProperties": false, + "description": "`spec.modules`: module registries and their security requirements.\n\n```yaml\nmodules:\n registries:\n - name: acme\n url: https://github.com/acme/cfgd-modules\n security:\n requireSignatures: true\n```", + "properties": { + "registries": { + "default": [], + "description": "Module registries — git repos containing modules in a prescribed directory structure.", + "items": { + "$ref": "#/definitions/ModuleRegistryEntry" + }, + "type": "array" + }, + "security": { + "anyOf": [ + { + "$ref": "#/definitions/ModuleSecurityConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Signature requirements for modules pulled from these registries.\nOmitted, signatures are not required and an unsigned module tag is\naccepted." + } + }, + "type": "object" + }, + "NotifyConfig": { + "additionalProperties": false, + "description": "`spec.notify`: how the daemon reports detected drift.\n\n```yaml\nnotify:\n drift: true\n method: Webhook\n webhookUrl: https://example.com/hook\n```", + "properties": { + "drift": { + "default": false, + "description": "Send a notification whenever the daemon detects drift. Default: `false`.", + "type": "boolean" + }, + "method": { + "$ref": "#/definitions/NotifyMethod", + "default": "Desktop", + "description": "Where a drift notification is delivered. Default: `Desktop`." + }, + "webhookUrl": { + "description": "Webhook URL to POST to when `method` is `Webhook`. Required only for that method.", + "type": ["string", "null"] + } + }, + "type": "object" + }, + "NotifyMethod": { + "description": "Delivery method for a `notify.method` value: `Desktop`, `Stdout`, or `Webhook`\n(case-insensitive on read; case-sensitive `PascalCase` in generated YAML).", + "oneOf": [ + { + "const": "Desktop", + "description": "A native desktop notification.", + "type": "string" + }, + { + "const": "Stdout", + "description": "A line written to the daemon's own stdout/log.", + "type": "string" + }, + { + "const": "Webhook", + "description": "A JSON POST to `webhookUrl`.", + "type": "string" + } + ] + }, + "OriginSpec": { + "additionalProperties": false, + "description": "One entry of `spec.origin[]`: a remote this machine's config can sync with.\n\n```yaml\norigin:\n - type: Git\n url: git@github.com:me/dotfiles.git\n branch: main\n```", + "properties": { + "auth": { + "description": "Auth method override for this origin (e.g. a credential-helper name).\nOmitted uses the ambient git/SSH credential configuration.", + "type": ["string", "null"] + }, + "branch": { + "default": "master", + "description": "Branch to sync against. Default: `master`.", + "type": "string" + }, + "sshStrictHostKeyChecking": { + "$ref": "#/definitions/SshHostKeyPolicy", + "default": "AcceptNew", + "description": "SSH `StrictHostKeyChecking` policy for git operations.\n`AcceptNew` (default): accept first-seen keys, reject changed keys.\n`Yes`: require keys to already exist in known_hosts (high-security).\n`No`: accept any key (insecure, not recommended)." + }, + "type": { + "$ref": "#/definitions/OriginType", + "description": "Kind of origin: `Git` (a git remote) or `Server` (the device gateway)." + }, + "url": { + "description": "The origin's URL (a git remote, or the gateway's base URL).", + "type": "string" + } + }, + "required": ["type", "url"], + "type": "object" + }, + "OriginType": { + "description": "Kind of an origin: `Git` (a plain git remote) or `Server` (the device\ngateway's enrollment/check-in API).", + "enum": ["Git", "Server"], + "type": "string" + }, + "OutputConfig": { + "additionalProperties": false, + "description": "`spec.output`: how cfgd renders what it reports.\n\n```yaml\nspec:\n output:\n theme: dracula\n usageHints: true\n maskEnvValues: All\n```\n\nEach key has a per-invocation override (`--theme` / `CFGD_THEME`,\n`--no-hints` / `CFGD_USAGE_HINTS`, `--mask-env-values` /\n`CFGD_MASK_ENV_VALUES`) that outranks what is stored here.", + "properties": { + "maskEnvValues": { + "anyOf": [ + { + "$ref": "#/definitions/MaskEnvValues" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Which declared env values cfgd hides where it renders one. Omitted,\nevery value is masked." + }, + "theme": { + "anyOf": [ + { + "$ref": "#/definitions/ThemeConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Colours and glyphs cfgd renders with: a named preset (`default`,\n`dracula`, `solarized-dark`, `solarized-light`, `nord`, `monokai`,\n`adventure-time`, `catppuccin-mocha`, `gruvbox-dark`, `tokyo-night`,\n`one-dark`, `minimal`) plus per-slot overrides. Omitted, the\n`default` preset applies." + }, + "usageHints": { + "default": null, + "description": "Whether closing `→` usage hints render. Omitted, hints render.", + "type": ["boolean", "null"] + } + }, + "type": "object" + }, + "PolicyAction": { + "description": "An `AutoApplyPolicyConfig` decision: `Notify` (record, don't act), `Accept`\n(apply automatically), `Reject` (never apply), or `Ignore` (skip entirely).", + "enum": ["Notify", "Accept", "Reject", "Ignore"], + "type": "string" + }, + "ReconcileConfig": { + "additionalProperties": false, + "description": "`spec.daemon.reconcile`: how often and how aggressively the daemon reconciles.\n\n```yaml\nreconcile:\n interval: 5m\n onChange: true\n autoApply: false\n driftPolicy: NotifyOnly\n```", + "properties": { + "autoApply": { + "default": false, + "description": "Apply new/changed source-recommended modules automatically. Default:\n`false`. Independent of `driftPolicy`, which governs already-declared\ndrift instead.", + "type": "boolean" + }, + "driftPolicy": { + "$ref": "#/definitions/DriftPolicy", + "default": "NotifyOnly", + "description": "Policy for daemon auto-reconciliation of detected drift.\n`Auto` = silently apply (must opt-in), `NotifyOnly` = notify but don't\napply (safe default), `Prompt` = future interactive approval." + }, + "interval": { + "default": "5m", + "description": "How often the daemon checks for drift, as a duration string. Default: `5m`.", + "type": "string" + }, + "onChange": { + "default": false, + "description": "Trigger an immediate reconcile when a watched file changes, in addition to\nthe timed interval. Default: `false`.", + "type": "boolean" + }, + "patches": { + "default": [], + "description": "Per-module or per-profile reconcile overrides (kustomize-style patches).\nEach patch targets a specific Module or Profile by name and overrides\nindividual reconcile fields. Precedence: Module patch > Profile patch > global.", + "items": { + "$ref": "#/definitions/ReconcilePatch" + }, + "type": "array" + }, + "policy": { + "anyOf": [ + { + "$ref": "#/definitions/AutoApplyPolicyConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Auto-apply decisions for new/changed module recommendations." + } + }, + "type": "object" + }, + "ReconcilePatch": { + "additionalProperties": false, + "description": "A kustomize-style reconcile patch targeting a specific module or profile.\nWhen `name` is omitted, the patch applies to all entities of the given kind.", + "properties": { + "autoApply": { + "description": "Overrides the global `autoApply` for the targeted entity.", + "type": ["boolean", "null"] + }, + "driftPolicy": { + "anyOf": [ + { + "$ref": "#/definitions/DriftPolicy" + }, + { + "type": "null" + } + ], + "description": "Overrides the global `driftPolicy` for the targeted entity." + }, + "interval": { + "description": "Overrides the global reconcile interval for the targeted entity.", + "type": ["string", "null"] + }, + "kind": { + "$ref": "#/definitions/ReconcilePatchKind", + "description": "Whether this patch targets a `Module` or a `Profile`." + }, + "name": { + "description": "Name of the module/profile this patch targets. Omitted to target every\nentity of `kind`.", + "type": ["string", "null"] + } + }, + "required": ["kind"], + "type": "object" + }, + "ReconcilePatchKind": { + "description": "What a `ReconcilePatch` targets: `Module` or `Profile`.", + "enum": ["Module", "Profile"], + "type": "string" + }, + "SecretIntegration": { + "additionalProperties": true, + "description": "One named secret backend integration under `spec.secrets.integrations[]`.\n\nEvery field beyond `name` is backend-specific and captured verbatim into\n`extra`, so it accepts arbitrary per-backend keys (`vault`/`item` for\n1Password, `mount`/`path` for Vault, and so on).\n\n```yaml\nintegrations:\n - name: 1password\n vault: Personal\n item: GitHub Token\n```", + "properties": { + "name": { + "description": "Integration name (`1password`, `bitwarden`, `vault`), referenced by\n`${secret::}`.", + "type": "string" + } + }, + "required": ["name"], + "type": "object" + }, + "SecretsConfig": { + "additionalProperties": false, + "description": "`spec.secrets`: the default secret backend and its integrations.\n\n```yaml\nsecrets:\n backend: sops\n sops:\n ageKey: ~/.config/sops/age/keys.txt\n integrations:\n - name: 1password\n vault: Personal\n```", + "properties": { + "backend": { + "default": "sops", + "description": "Default secret backend name (`sops`, `1password`, `bitwarden`, `vault`, `age`).\nDefault: `sops`.", + "type": "string" + }, + "integrations": { + "default": [], + "description": "Named backend integrations a `${secret::}` reference can select.", + "items": { + "$ref": "#/definitions/SecretIntegration" + }, + "type": "array" + }, + "sops": { + "anyOf": [ + { + "$ref": "#/definitions/SopsConfig" + }, + { + "type": "null" + } + ], + "description": "sops-specific settings, used when `backend` is `sops`." + } + }, + "type": "object" + }, + "SecurityConfig": { + "additionalProperties": false, + "description": "`spec.security`: source signature-verification settings.\n\n```yaml\nsecurity:\n allowUnsigned: false\n```", + "properties": { + "allowUnsigned": { + "default": false, + "description": "Allow unsigned source content even when the source requires signed commits.\nIntended for development/testing environments.", + "type": "boolean" + } + }, + "type": "object" + }, + "SkillUpdateConfig": { + "additionalProperties": false, + "description": "Update configuration specific to authored skills.", + "properties": { + "policy": { + "$ref": "#/definitions/SkillUpdatePolicy", + "default": "Inherit", + "description": "How skill update checks behave. Defaults to `Inherit` (defer to the\nbinary-level policy)." + } + }, + "type": "object" + }, + "SkillUpdatePolicy": { + "description": "Per-skill update policy. Mirrors `UpdatePolicy` but adds `Inherit`, which\ndefers to the binary-level `update.policy`.", + "oneOf": [ + { + "const": "Inherit", + "description": "Defer to the binary-level update policy (`update.policy`).", + "type": "string" + }, + { + "const": "Auto", + "description": "Apply skill updates automatically without prompting.", + "type": "string" + }, + { + "const": "Prompt", + "description": "Ask before applying an available skill update.", + "type": "string" + }, + { + "const": "Notify", + "description": "Report that a skill update is available, but take no action.", + "type": "string" + }, + { + "const": "Manual", + "description": "Disable automatic skill update checks; the user updates manually.", + "type": "string" + } + ] + }, + "SopsConfig": { + "additionalProperties": false, + "description": "sops backend settings under `spec.secrets.sops`.\n\n```yaml\nsops:\n ageKey: ~/.config/sops/age/keys.txt\n```", + "properties": { + "ageKey": { + "description": "Path to the age private key file sops decrypts with. Falls back to sops's\nown default search path when omitted.", + "type": ["string", "null"] + } + }, + "type": "object" + }, + "SourceSpec": { + "additionalProperties": false, + "description": "One entry of `spec.sources[]`: a remote config source this machine\nsubscribes to.\n\n```yaml\nsources:\n - name: team-baseline\n origin:\n type: Git\n url: git@github.com:acme/cfgd-baseline.git\n subscription:\n acceptRecommended: true\n sync:\n interval: 1h\n```", + "properties": { + "name": { + "description": "Local name for this source, used in `cfgd source` commands and status output.", + "type": "string" + }, + "origin": { + "$ref": "#/definitions/OriginSpec", + "description": "Where the source's manifest is fetched from." + }, + "subscription": { + "$ref": "#/definitions/SubscriptionSpec", + "default": { + "acceptRecommended": false, + "allowScripts": false, + "optIn": [], + "overrides": null, + "priority": 500, + "reject": null, + "requireSignedCommits": false + }, + "description": "What this machine accepts from the source and how it applies." + }, + "sync": { + "$ref": "#/definitions/SourceSyncSpec", + "default": { + "autoApply": false, + "interval": "1h", + "required": false + }, + "description": "How often and under what conditions the source is refreshed." + } + }, + "required": ["name", "origin"], + "type": "object" + }, + "SourceSyncSpec": { + "additionalProperties": false, + "description": "`spec.sources[].sync`: how a source is refreshed and pinned.", + "properties": { + "autoApply": { + "default": false, + "description": "After a refresh that CHANGED this source, reconcile the whole profile\nimmediately and apply, forcing `Auto` for that tick regardless of\n`spec.daemon.reconcile.driftPolicy`. The source-decision gate is\nuntouched: an item awaiting a decision is withheld exactly as it would\nbe on any other tick. Default: `false`, which records the change and\nleaves the apply to the ordinary reconcile tick or to `cfgd sync`.", + "type": "boolean" + }, + "interval": { + "default": "1h", + "description": "How often to fetch and re-resolve the source, as a duration string.\nDefault: `1h`.", + "type": "string" + }, + "pinVersion": { + "description": "Pin to a specific git tag/branch/commit instead of tracking the origin's\ndefault branch.", + "type": ["string", "null"] + }, + "required": { + "default": false, + "description": "Fail-closed marker. When `true`, a failure to load this source (fetch,\nmanifest, signature, or an unresolvable `pinVersion`) is fatal — apply /\nplan / compose abort rather than silently dropping the source. Default\n`false` keeps the best-effort warn-and-continue behaviour for optional\nsources. Use it for security or team baselines that must always be\ncomposed in.", + "type": "boolean" + } + }, + "type": "object" + }, + "SshHostKeyPolicy": { + "description": "SSH `StrictHostKeyChecking` policy for git operations over SSH.", + "oneOf": [ + { + "const": "AcceptNew", + "description": "Accept first-seen keys, reject changed keys (safe default for automation).", + "type": "string" + }, + { + "const": "Yes", + "description": "Require keys to already exist in known_hosts (high-security environments).", + "type": "string" + }, + { + "const": "No", + "description": "Accept any key without verification (insecure, not recommended).", + "type": "string" + } + ] + }, + "SubscriptionSpec": { + "additionalProperties": false, + "description": "`spec.sources[].subscription`: the subscriber's own policy toward one source.", + "properties": { + "acceptRecommended": { + "default": false, + "description": "Automatically accept the source's `recommended` policy tier without\nprompting. Default: `false`.", + "type": "boolean" + }, + "allowScripts": { + "default": false, + "description": "Subscriber opt-in to run lifecycle scripts (profile-layer and\nsource-delivered module bodies) from this source even when the source's\n`constraints.noScripts` would otherwise reject them. Default `false`:\nthe source's own `noScripts` constraint governs.", + "type": "boolean" + }, + "optIn": { + "default": [], + "description": "Names from the source's `optional` policy tier to accept.", + "items": { + "type": "string" + }, + "type": "array" + }, + "overrides": { + "default": null, + "description": "Local values to deep-merge on top of what the source delivers, applied\nafter composition." + }, + "priority": { + "default": 500, + "description": "Merge priority against other sources and the local profile; higher wins\non conflicting leaf values. Default: `500`. Capped at\n`MAX_SOURCE_PRIORITY`.", + "format": "uint32", + "minimum": 0, + "type": "integer" + }, + "profile": { + "description": "Which of the source's published profiles to compose against. Omitted\ncomposes every profile the source provides.", + "type": ["string", "null"] + }, + "reject": { + "default": null, + "description": "Items from the source's `recommended` tier to drop entirely rather than\naccept. A mapping under `packages`, `env`, `aliases`, and/or `modules`;\nany other top-level key is rejected as a typo." + }, + "requireSignedCommits": { + "default": false, + "description": "Subscriber-side demand that this source's HEAD commit carry a valid GPG\nor SSH signature.\n\nThe trust anchor for the check. `constraints.requireSignedCommits` says\nthe same thing, but it is read from the source's manifest INSIDE the\ncached clone, so whoever can write the cache can also clear it. This\nflag is read from the subscriber's own config, which the cache cannot\nreach.\n\nORed with the manifest's flag, so it only ever ADDS strictness: a\nmanifest `true` is never weakened by a subscriber `false`. Default\n`false`. `spec.security.allowUnsigned` still bypasses both.", + "type": "boolean" + } + }, + "type": "object" + }, + "SyncConfig": { + "additionalProperties": false, + "description": "`spec.sync`: automatic push/pull settings for the daemon's git sync loop.\n\n```yaml\nsync:\n autoPush: true\n autoPull: true\n interval: 5m\n```", + "properties": { + "autoPull": { + "default": false, + "description": "Automatically pull upstream config changes. Default: `false`.", + "type": "boolean" + }, + "autoPush": { + "default": false, + "description": "Automatically commit and push local config changes. Default: `false`.", + "type": "boolean" + }, + "interval": { + "default": "1h", + "description": "How often the daemon runs the sync loop, as a duration string (`\"5m\"`, `\"1h\"`).\nDefault: `1h`.", + "type": "string" + } + }, + "type": "object" + }, + "ThemeConfig": { + "description": "`spec.output.theme`: the active output preset and any per-color/icon\noverrides.\n\nAccepts either a bare string (the preset name) or a mapping:\n\n```yaml\nspec:\n output:\n theme: dracula\n # or\n theme:\n name: dracula\n overrides:\n header: \"#ff0000\"\n iconOk: \"Y\"\n```", + "properties": { + "name": { + "default": "default", + "description": "Preset name (`default`, `dracula`, `solarized-dark`, `solarized-light`,\n`nord`, `monokai`, `adventure-time`, `catppuccin-mocha`, `gruvbox-dark`,\n`tokyo-night`, `one-dark`, `minimal`). Default: `default`.", + "type": "string" + }, + "overrides": { + "$ref": "#/definitions/ThemeOverrides", + "description": "Per-color and per-icon overrides applied on top of the named preset." + } + }, + "type": "object" + }, + "ThemeOverrides": { + "properties": { + "accent": { + "description": "Color for accent status lines: attention without alarm. Hex color.", + "type": ["string", "null"] + }, + "diffAdd": { + "description": "Color for an added diff line. Hex color.", + "type": ["string", "null"] + }, + "diffContext": { + "description": "Color for an unchanged diff context line. Hex color.", + "type": ["string", "null"] + }, + "diffRemove": { + "description": "Color for a removed diff line. Hex color.", + "type": ["string", "null"] + }, + "error": { + "description": "Color for failure status lines. Hex color.", + "type": ["string", "null"] + }, + "header": { + "description": "Color for a top-level heading. Hex color (`\"#ff0000\"`).", + "type": ["string", "null"] + }, + "iconArrow": { + "description": "Glyph rendered for an `old -> new` relationship (e.g. `→`).", + "type": ["string", "null"] + }, + "iconFail": { + "description": "Glyph for failure status lines. Default varies by preset (e.g. `✗`).", + "type": ["string", "null"] + }, + "iconInfo": { + "description": "Glyph for informational status lines. Default varies by preset.", + "type": ["string", "null"] + }, + "iconOk": { + "description": "Glyph for success status lines. Default varies by preset (e.g. `✓`).", + "type": ["string", "null"] + }, + "iconPending": { + "description": "Glyph for pending status lines. Default varies by preset.", + "type": ["string", "null"] + }, + "iconRunning": { + "description": "Glyph for in-progress status lines. Default varies by preset.", + "type": ["string", "null"] + }, + "iconSkipped": { + "description": "Glyph for skipped status lines. Default varies by preset.", + "type": ["string", "null"] + }, + "iconWarn": { + "description": "Glyph for warning status lines. Default varies by preset (e.g. `⚠`).", + "type": ["string", "null"] + }, + "info": { + "description": "Color for informational status lines. Hex color.", + "type": ["string", "null"] + }, + "muted": { + "description": "Color for de-emphasized text (hints, notes, qualifiers). Hex color.", + "type": ["string", "null"] + }, + "primary": { + "description": "Color for action lines at the deepest nesting level of a run. Hex color\n(`\"#ff0000\"`). Presets that carry no palette foreground of their own\nleave it unset.", + "type": ["string", "null"] + }, + "running": { + "description": "Color for in-progress status lines and spinner labels. Hex color.", + "type": ["string", "null"] + }, + "secondary": { + "description": "Color for secondary status lines: structural pivots, labels, and\nidentifiers. Hex color.", + "type": ["string", "null"] + }, + "success": { + "description": "Color for success status lines. Hex color.", + "type": ["string", "null"] + }, + "typeHint": { + "description": "Color for schema type annotations in explain output. Hex color\n(`\"#8be9fd\"`).", + "type": ["string", "null"] + }, + "warning": { + "description": "Color for warning status lines. Hex color.", + "type": ["string", "null"] + } + }, + "type": "object" + }, + "UpdateConfig": { + "additionalProperties": false, + "description": "Configuration for cfgd self-update checks and authored-skill updates.", + "properties": { + "channel": { + "description": "Release channel to track (e.g. `stable`, `beta`). When unset, cfgd uses\nits built-in default channel.", + "type": ["string", "null"] + }, + "interval": { + "default": "24h", + "description": "How often to check for updates, as a duration string (e.g. `24h`, `7d`,\n`30m`) or a plain number of seconds. Defaults to `24h`.", + "type": "string" + }, + "policy": { + "$ref": "#/definitions/UpdatePolicy", + "default": "Prompt", + "description": "How update checks for the cfgd binary behave. Defaults to `Prompt`." + }, + "skills": { + "$ref": "#/definitions/SkillUpdateConfig", + "default": { + "policy": "Inherit" + }, + "description": "Update policy for authored skills. Defaults to inheriting `policy`." + } + }, + "type": "object" + }, + "UpdatePolicy": { + "description": "Update policy governing how cfgd self-update checks behave.\n\n`Auto` applies updates without prompting, `Prompt` asks before applying,\n`Notify` only reports that an update is available, and `Manual` disables\nautomatic checks entirely (the user runs `cfgd upgrade` themselves).", + "oneOf": [ + { + "const": "Auto", + "description": "Apply updates automatically without prompting.", + "type": "string" + }, + { + "const": "Prompt", + "description": "Ask before applying an available update.", + "type": "string" + }, + { + "const": "Notify", + "description": "Report that an update is available, but take no action.", + "type": "string" + }, + { + "const": "Manual", + "description": "Disable automatic update checks; the user upgrades manually.", + "type": "string" + } + ] + } + }, + "description": "Root configuration file for cfgd (cfgd.yaml)", + "properties": { + "apiVersion": { + "description": "API group/version, e.g. `cfgd.io/v1alpha1`. See `API_VERSION`.", + "type": "string" + }, + "kind": { + "description": "Document kind. Always `CfgdConfig` for this file.", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/ConfigMetadata", + "description": "Identifying metadata for this config document." + }, + "spec": { + "$ref": "#/definitions/ConfigSpec", + "description": "The body of the document: everything cfgd reads to decide what this\nmachine should look like." + } + }, + "required": ["apiVersion", "kind", "metadata", "spec"], + "title": "cfgd Config", + "type": "object" +} diff --git a/src/schemas/json/cfgd-configsource-0.11.0.json b/src/schemas/json/cfgd-configsource-0.11.0.json new file mode 100644 index 00000000000..1af42a356f3 --- /dev/null +++ b/src/schemas/json/cfgd-configsource-0.11.0.json @@ -0,0 +1,1209 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://cfgd.io/schemas/cfgd-source.schema.json", + "additionalProperties": false, + "definitions": { + "AptSpec": { + "additionalProperties": false, + "description": "The object form of `apt`: a package list, a file listing packages, or both.\nA bare list of names folds into `packages`.", + "properties": { + "file": { + "default": null, + "description": "Path to a package-list file to install from, one name per line.\nRelative to the config root.", + "type": ["string", "null"] + }, + "packages": { + "default": [], + "description": "APT package names to install.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "BrewSpec": { + "additionalProperties": false, + "description": "The object form of `brew`: taps, formulae and casks, or a Brewfile. A bare\nlist of names folds into `formulae`.", + "properties": { + "casks": { + "default": [], + "description": "Homebrew casks (GUI applications) to install.", + "items": { + "type": "string" + }, + "type": "array" + }, + "file": { + "default": null, + "description": "Path to a Brewfile to apply instead of (or alongside) `taps`,\n`formulae` and `casks`. Relative to the config root.", + "type": ["string", "null"] + }, + "formulae": { + "default": [], + "description": "Homebrew formulae (CLI packages) to install.", + "items": { + "type": "string" + }, + "type": "array" + }, + "taps": { + "default": [], + "description": "Third-party taps to add before installing formulae/casks.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "CargoSpec": { + "additionalProperties": false, + "description": "The object form of `cargo`: crates to install, a `Cargo.toml` to install\nfrom, or both. A bare list of names folds into `packages`.", + "properties": { + "file": { + "description": "Path to a `Cargo.toml` whose binaries to install instead of `packages`.\nRelative to the config root.", + "type": ["string", "null"] + }, + "packages": { + "default": [], + "description": "Crate names to install (`cargo install`).", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "ConfigSourceMetadata": { + "additionalProperties": false, + "description": "`metadata`: identifying information for a config source.", + "properties": { + "description": { + "default": null, + "description": "A one-line human summary of what this source provides.", + "type": ["string", "null"] + }, + "name": { + "description": "The source's published name, as its maintainer spells it. Shown wherever\nthe manifest is displayed (`cfgd source show`, the summary a subscriber\napproves before trusting the source) and carried in `-o json` output.\nRequired. A subscriber registers the source under a local name of their\nown choosing, so this value identifies the source to a reader rather\nthan keying anything cfgd stores.", + "type": "string" + }, + "version": { + "default": null, + "description": "The source manifest's own version, shown to subscribers.", + "type": ["string", "null"] + } + }, + "required": ["name"], + "type": "object" + }, + "ConfigSourcePolicy": { + "additionalProperties": false, + "description": "`spec.policy`: the four acceptance tiers a config source offers items\nunder, plus the constraints it enforces on every subscriber.\n\n```yaml\npolicy:\n required:\n packages:\n apt: [git]\n recommended:\n modules: [nvim]\n optional:\n modules: [tmux]\n locked:\n env:\n - name: COMPANY_PROXY\n value: http://proxy.internal:3128\n constraints:\n noScripts: true\n```", + "properties": { + "constraints": { + "$ref": "#/definitions/SourceConstraints", + "default": { + "allowSystemChanges": false, + "allowedTargetPaths": [], + "noScripts": true, + "noSecretsRead": true, + "requireSignedCommits": false + }, + "description": "Restrictions this source imposes on how subscribers may compose it." + }, + "locked": { + "$ref": "#/definitions/PolicyItems", + "default": { + "aliases": [], + "env": [], + "files": [], + "modules": [], + "packages": null, + "profiles": [], + "secrets": [], + "system": {} + }, + "description": "Items every subscriber receives and cannot override locally." + }, + "optional": { + "$ref": "#/definitions/PolicyItems", + "default": { + "aliases": [], + "env": [], + "files": [], + "modules": [], + "packages": null, + "profiles": [], + "secrets": [], + "system": {} + }, + "description": "Items a subscriber must explicitly name in `subscription.optIn` to receive." + }, + "recommended": { + "$ref": "#/definitions/PolicyItems", + "default": { + "aliases": [], + "env": [], + "files": [], + "modules": [], + "packages": null, + "profiles": [], + "secrets": [], + "system": {} + }, + "description": "Items a subscriber receives when `subscription.acceptRecommended` is set." + }, + "required": { + "$ref": "#/definitions/PolicyItems", + "default": { + "aliases": [], + "env": [], + "files": [], + "modules": [], + "packages": null, + "profiles": [], + "secrets": [], + "system": {} + }, + "description": "Items every subscriber receives unconditionally." + } + }, + "type": "object" + }, + "ConfigSourceProfileEntry": { + "additionalProperties": false, + "description": "Detailed profile entry in a ConfigSource manifest.\nWhen present, provides richer info than the flat `profiles` list.", + "properties": { + "description": { + "default": null, + "description": "A one-line human summary of the profile.", + "type": ["string", "null"] + }, + "inherits": { + "default": [], + "description": "Names of other published profiles this one inherits from.", + "items": { + "type": "string" + }, + "type": "array" + }, + "name": { + "description": "Name the profile is published under, and the value `cfgd profile\nswitch` takes to activate it.", + "type": "string" + }, + "path": { + "default": null, + "description": "Path to the profile's manifest within the source repository, if not at\nthe conventional location.", + "type": ["string", "null"] + } + }, + "required": ["name"], + "type": "object" + }, + "ConfigSourceProvides": { + "additionalProperties": false, + "description": "`spec.provides`: what a config source makes available to subscribers.", + "properties": { + "modules": { + "default": [], + "description": "Names of modules this source publishes.", + "items": { + "type": "string" + }, + "type": "array" + }, + "platformProfiles": { + "additionalProperties": { + "type": "string" + }, + "default": {}, + "description": "Maps a platform/distro tag (`macos`, `debian`, …) to the profile name\nto use on that platform.", + "type": "object" + }, + "profileDetails": { + "default": [], + "description": "Published profiles with descriptions, paths, and inheritance — richer\nthan the flat `profiles` list.", + "items": { + "$ref": "#/definitions/ConfigSourceProfileEntry" + }, + "type": "array" + }, + "profiles": { + "default": [], + "description": "Flat list of published profile names. Superseded by `profileDetails`\nwhen that list is non-empty.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "ConfigSourceSpec": { + "additionalProperties": false, + "description": "`spec`: the body of a config source manifest.", + "properties": { + "policy": { + "$ref": "#/definitions/ConfigSourcePolicy", + "default": { + "constraints": { + "allowSystemChanges": false, + "allowedTargetPaths": [], + "noScripts": true, + "noSecretsRead": true, + "requireSignedCommits": false + }, + "locked": { + "aliases": [], + "env": [], + "files": [], + "modules": [], + "packages": null, + "profiles": [], + "secrets": [], + "system": {} + }, + "optional": { + "aliases": [], + "env": [], + "files": [], + "modules": [], + "packages": null, + "profiles": [], + "secrets": [], + "system": {} + }, + "recommended": { + "aliases": [], + "env": [], + "files": [], + "modules": [], + "packages": null, + "profiles": [], + "secrets": [], + "system": {} + }, + "required": { + "aliases": [], + "env": [], + "files": [], + "modules": [], + "packages": null, + "profiles": [], + "secrets": [], + "system": {} + } + }, + "description": "Policy tiers (required/recommended/optional/locked) and constraints\nthis source enforces on subscribers." + }, + "provides": { + "$ref": "#/definitions/ConfigSourceProvides", + "default": { + "modules": [], + "platformProfiles": {}, + "profileDetails": [], + "profiles": [] + }, + "description": "Profiles and modules this source publishes." + } + }, + "type": "object" + }, + "CustomManagerSpec": { + "additionalProperties": false, + "description": "A user-defined package manager under `spec.packages.custom[]`, driven\nentirely by shell commands.\n\n```yaml\ncustom:\n - name: asdf\n check: \"command -v asdf\"\n listInstalled: \"asdf list\"\n install: \"asdf install {package}\"\n uninstall: \"asdf uninstall {package}\"\n packages: [nodejs]\n```", + "properties": { + "check": { + "description": "Command that exits zero when this manager is available on the machine.", + "type": "string" + }, + "install": { + "description": "Command template to install a package; `{package}` is substituted.", + "type": "string" + }, + "listInstalled": { + "description": "Command whose stdout lists installed package names, one per line.", + "type": "string" + }, + "name": { + "description": "Manager name, used in `prefer:`/`deny:` lists and status output.", + "type": "string" + }, + "packages": { + "default": [], + "description": "Package names to install with this manager.", + "items": { + "type": "string" + }, + "type": "array" + }, + "uninstall": { + "description": "Command template to uninstall a package; `{package}` is substituted.", + "type": "string" + }, + "update": { + "default": null, + "description": "Command to refresh the manager's own package index/cache before installs.", + "type": ["string", "null"] + } + }, + "required": ["name", "check", "listInstalled", "install", "uninstall"], + "type": "object" + }, + "EncryptionConstraint": { + "additionalProperties": false, + "description": "Encryption constraint applied to files from a config source.", + "properties": { + "backend": { + "description": "If set, restrict which backend is acceptable.", + "type": ["string", "null"] + }, + "mode": { + "anyOf": [ + { + "$ref": "#/definitions/EncryptionMode" + }, + { + "type": "null" + } + ], + "description": "If set, restrict which encryption mode is acceptable." + }, + "requiredTargets": { + "default": [], + "description": "Glob patterns or explicit paths that must be encrypted.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "EncryptionMode": { + "description": "Controls when encryption is required for a managed file.", + "oneOf": [ + { + "const": "InRepo", + "description": "File must be encrypted when stored in the repository.", + "type": "string" + }, + { + "const": "Always", + "description": "File must always be encrypted, including at rest on disk.", + "type": "string" + } + ] + }, + "EncryptionSpec": { + "additionalProperties": false, + "description": "Encryption settings for a managed file.", + "properties": { + "backend": { + "description": "The encryption backend to use (e.g. \"sops\", \"age\").", + "type": "string" + }, + "mode": { + "$ref": "#/definitions/EncryptionMode", + "default": "InRepo", + "description": "When encryption must be enforced. Defaults to `InRepo`." + } + }, + "required": ["backend"], + "type": "object" + }, + "EnvVar": { + "description": "A single `NAME=VALUE` environment variable entry.", + "properties": { + "name": { + "description": "Variable name. Must be shell-safe and not a reserved `CFGD_*` name.", + "type": "string" + }, + "platforms": { + "description": "Platform tags gating this entry alone. Empty means every platform the\ndeclaring module or profile is not already gated off of. Tags are\nmatched against the machine's OS, distro, and arch; use `macos` for\nmacOS. An entry gated off this host is not part of its desired state at\nall: it appears on no surface, exactly as a platform-filtered package\ndoes.", + "items": { + "type": "string" + }, + "type": "array" + }, + "value": { + "description": "Value assigned to the variable, exported verbatim into the shell\nenvironment.", + "type": "string" + } + }, + "required": ["name", "value"], + "type": "object" + }, + "FileStrategy": { + "description": "File deployment strategy.", + "oneOf": [ + { + "const": "Symlink", + "description": "Create a symbolic link from target to source (default).", + "type": "string" + }, + { + "const": "Copy", + "description": "Copy source content to target.", + "type": "string" + }, + { + "const": "Template", + "description": "Render a Tera template and write the output (auto-selected for .tera files).", + "type": "string" + }, + { + "const": "Hardlink", + "description": "Create a hard link from target to source.", + "type": "string" + }, + { + "const": "Patch", + "description": "Merge structured keys/values into the target, or pipe it through a\nscript, leaving everything else untouched. Requires a `patch:` block.", + "type": "string" + } + ] + }, + "FlatpakSpec": { + "additionalProperties": false, + "description": "The object form of `flatpak`: application ids and the remote to install\nthem from. A bare list of ids folds into `packages`.", + "properties": { + "packages": { + "default": [], + "description": "Flatpak application ids to install.", + "items": { + "type": "string" + }, + "type": "array" + }, + "remote": { + "default": null, + "description": "Remote to install from (e.g. `flathub`). Falls back to Flatpak's\nconfigured default remote when omitted.", + "type": ["string", "null"] + } + }, + "type": "object" + }, + "ManagedFileSpec": { + "additionalProperties": false, + "description": "One entry of `spec.files.managed[]`: a file this profile deploys.\n\n```yaml\nfiles:\n managed:\n - source: files/gitconfig\n target: ~/.gitconfig\n permissions: \"644\"\n```", + "properties": { + "encryption": { + "anyOf": [ + { + "$ref": "#/definitions/EncryptionSpec" + }, + { + "type": "null" + } + ], + "description": "Encryption settings for this file." + }, + "patch": { + "anyOf": [ + { + "$ref": "#/definitions/PatchSpec" + }, + { + "type": "null" + } + ], + "description": "Structured merge or script configuration for `strategy: Patch`.\nRequired when `strategy` is `Patch`, rejected otherwise." + }, + "permissions": { + "description": "Unix permission bits (e.g. \"600\", \"644\") to apply after deployment.", + "type": ["string", "null"] + }, + "private": { + "description": "When true, the source file is local-only: auto-added to .gitignore,\nsilently skipped on machines where it doesn't exist.", + "type": "boolean" + }, + "source": { + "default": "", + "description": "Path to the source file. Not required when `strategy` is `Patch`;\nrequired otherwise.", + "type": "string" + }, + "strategy": { + "anyOf": [ + { + "$ref": "#/definitions/FileStrategy" + }, + { + "type": "null" + } + ], + "description": "Per-file deployment strategy override. Omitted, the profile-wide\ndefault applies." + }, + "target": { + "description": "Destination path on the machine. A leading `~` expands to the home\ndirectory.", + "type": "string" + } + }, + "required": ["target"], + "type": "object" + }, + "NpmSpec": { + "additionalProperties": false, + "description": "The object form of `npm`: global packages, a `package.json` to install\nfrom, or both. A bare list of names folds into `global`.", + "properties": { + "file": { + "default": null, + "description": "Path to a `package.json` to install dependencies from. Relative to the\nconfig root.", + "type": ["string", "null"] + }, + "global": { + "default": [], + "description": "Package names to install globally (`npm install -g`).", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "PackageListSpec": { + "additionalProperties": false, + "description": "The map form of a bare-list manager (`pipx`, `dnf`, `apk`, …): the same\nlist under a `packages` key.", + "properties": { + "packages": { + "default": [], + "description": "Package names.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "PackagesSpec": { + "additionalProperties": false, + "description": "`spec.packages`: packages to install, grouped by package manager.\n\nEvery manager field accepts either a bare list of names or (for the\nmanagers with options of their own) a mapping:\n\n```yaml\npackages:\n brew:\n formulae: [ripgrep, fzf]\n casks: [alacritty]\n apt: [curl, git]\n cargo: [ripgrep]\n```", + "properties": { + "apk": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "APK packages (Alpine)." + }, + "apt": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/AptSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "APT packages (Debian/Ubuntu)." + }, + "brew": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/BrewSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Homebrew packages (macOS/Linux)." + }, + "cargo": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/CargoSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Cargo packages (`cargo install`)." + }, + "chocolatey": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Chocolatey packages (Windows)." + }, + "custom": { + "default": [], + "description": "User-defined package managers not built into cfgd, each with its own\ncheck/install/uninstall commands.", + "items": { + "$ref": "#/definitions/CustomManagerSpec" + }, + "type": "array" + }, + "dnf": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "DNF packages (Fedora/RHEL)." + }, + "flatpak": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/FlatpakSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Flatpak packages (Linux)." + }, + "go": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Go packages (`go install`)." + }, + "nix": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Nix packages (`nix-env` / `nix profile`)." + }, + "npm": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/NpmSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "npm global packages." + }, + "pacman": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Pacman packages (Arch)." + }, + "pipx": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "pipx-installed Python applications." + }, + "pkg": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "pkg packages (FreeBSD)." + }, + "scoop": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Scoop packages (Windows)." + }, + "snap": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/SnapSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Snap packages (Linux)." + }, + "winget": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Winget packages (Windows)." + }, + "yum": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Yum packages (legacy RHEL/CentOS)." + }, + "zypper": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Zypper packages (openSUSE)." + } + }, + "type": "object" + }, + "PatchFormat": { + "description": "File format used to interpret and re-serialize a `Patch`-strategy target.", + "oneOf": [ + { + "const": "Ini", + "description": "INI sections/keys, edited line-by-line to preserve comments and layout.", + "type": "string" + }, + { + "const": "Json", + "description": "JSON, re-serialized on write (no comments to preserve).", + "type": "string" + }, + { + "const": "Yaml", + "description": "YAML; comments are NOT preserved across a merge (see docs for the caveat).", + "type": "string" + }, + { + "const": "Toml", + "description": "TOML, edited in place to preserve comments and layout.", + "type": "string" + } + ] + }, + "PatchSpec": { + "additionalProperties": false, + "description": "Configuration for the `Patch` file strategy: a structured merge (`ensure`)\nor a content-rewriting script, applied on top of the target's current\ncontent.", + "properties": { + "ensure": { + "description": "Keys/values to deep-merge into the target, leaving unmentioned keys\nuntouched. Values are literal (no template rendering). Mutually\nexclusive with `script`." + }, + "format": { + "anyOf": [ + { + "$ref": "#/definitions/PatchFormat" + }, + { + "type": "null" + } + ], + "description": "File format to parse the target as. Inferred from the target's\nextension when omitted." + }, + "script": { + "description": "A script path or an inline command that receives the target's current\ncontent on stdin and writes the new content to stdout. A relative path\nresolves against the module directory for a module file\n(`spec.files[]`) and against the config directory for a profile file\n(`spec.files.managed[]`); a value that resolves to no file is run as an\ninline command. Mutually exclusive with `ensure`.", + "type": ["string", "null"] + } + }, + "type": "object" + }, + "PolicyItems": { + "additionalProperties": false, + "description": "The content a config source offers under one policy tier\n(`required`/`recommended`/`optional`/`locked`).", + "properties": { + "aliases": { + "default": [], + "description": "Shell aliases offered at this tier.", + "items": { + "$ref": "#/definitions/ShellAlias" + }, + "type": "array" + }, + "env": { + "default": [], + "description": "Environment variables offered at this tier.", + "items": { + "$ref": "#/definitions/EnvVar" + }, + "type": "array" + }, + "files": { + "default": [], + "description": "Files offered at this tier.", + "items": { + "$ref": "#/definitions/ManagedFileSpec" + }, + "type": "array" + }, + "modules": { + "default": [], + "description": "Module names offered at this tier.", + "items": { + "type": "string" + }, + "type": "array" + }, + "packages": { + "anyOf": [ + { + "$ref": "#/definitions/PackagesSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Packages offered at this tier." + }, + "profiles": { + "default": [], + "description": "Profile names this tier recommends composing in.", + "items": { + "type": "string" + }, + "type": "array" + }, + "secrets": { + "default": [], + "description": "Secrets offered at this tier.", + "items": { + "$ref": "#/definitions/SecretSpec" + }, + "type": "array" + }, + "system": { + "additionalProperties": true, + "default": {}, + "description": "System configurator settings offered at this tier.", + "type": "object" + } + }, + "type": "object" + }, + "SecretSpec": { + "additionalProperties": false, + "description": "One entry of `spec.secrets[]`: a secret resolved into a file, into\nenvironment variables, or both. At least one of `target` / `envs` must be\nset; an entry carrying both writes the file AND exports the variables from\none resolution.\n\n```yaml\nsecrets:\n - source: op://Personal/GitHub/token\n envs: [GITHUB_TOKEN]\n - source: ssh_key\n target: ~/.ssh/id_ed25519\n - source: vault://secret/data/api#key\n target: ~/.config/api-key\n envs: [API_KEY]\n```", + "properties": { + "backend": { + "description": "Secret backend name to resolve `source` with. Falls back to\n`spec.secrets.backend` from `cfgd.yaml` when omitted.", + "type": ["string", "null"] + }, + "envs": { + "description": "Environment variable names to export the decrypted value under. May be\ncombined with `target`.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, + "source": { + "description": "Backend-specific reference to the secret (a 1Password `op://` URI, a\nVault path, a sops-encrypted file key, …).", + "type": "string" + }, + "target": { + "description": "File path to write the decrypted secret to. May be combined with `envs`.", + "type": ["string", "null"] + }, + "template": { + "description": "Template rendered around the resolved value before it is written to\n`target` or exported under `envs`: every `${secret:value}` in it is\nreplaced by the value (`template: \"token: ${secret:value}\"`). Only a\nprovider reference (`op://`, `vault://`, …) resolves to a single value,\nso `template` is rejected on a sops-encrypted file source.", + "type": ["string", "null"] + } + }, + "required": ["source"], + "type": "object" + }, + "ShellAlias": { + "description": "A single shell alias entry.", + "properties": { + "command": { + "description": "Command the alias expands to, written in the syntax of the shell it is\ngenerated for. It may carry arguments, pipes and quotes: cfgd quotes the\nwhole value per dialect when it writes the alias definition, so the text\nreaches the shell exactly as declared. Required — an alias with no\ncommand has nothing to expand to.", + "type": "string" + }, + "name": { + "description": "Alias name, as typed at the shell prompt.", + "type": "string" + }, + "platforms": { + "description": "Platform tags gating this entry alone. Empty means every platform the\ndeclaring module or profile is not already gated off of. Tags are\nmatched against the machine's OS, distro, and arch; use `macos` for\nmacOS. An entry gated off this host is not part of its desired state at\nall: it appears on no surface, exactly as a platform-filtered package\ndoes.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": ["name", "command"], + "type": "object" + }, + "SnapSpec": { + "additionalProperties": false, + "description": "The object form of `snap`: strict and classic-confinement snaps. A bare\nlist of names folds into `packages`.", + "properties": { + "classic": { + "default": [], + "description": "Snap names installed with `--classic` confinement.", + "items": { + "type": "string" + }, + "type": "array" + }, + "packages": { + "default": [], + "description": "Snap names installed with default (strict) confinement.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "SourceConstraints": { + "additionalProperties": false, + "description": "`spec.policy.constraints`: restrictions a config source imposes on every\nsubscriber, independent of which tier delivered an item.", + "properties": { + "allowSystemChanges": { + "default": false, + "description": "Allow this source to deliver `system:` configurator settings. Default: `false`.", + "type": "boolean" + }, + "allowedTargetPaths": { + "default": [], + "description": "Glob patterns restricting which file targets this source may deploy to.\nEmpty means no restriction.", + "items": { + "type": "string" + }, + "type": "array" + }, + "encryption": { + "anyOf": [ + { + "$ref": "#/definitions/EncryptionConstraint" + }, + { + "type": "null" + } + ], + "description": "Encryption requirements imposed on files delivered by this source." + }, + "noScripts": { + "default": true, + "description": "Reject lifecycle scripts (profile-layer and module `run:` bodies) this\nsource delivers, unless a subscriber opts in via\n`subscription.allowScripts`. Default: `true`.", + "type": "boolean" + }, + "noSecretsRead": { + "default": true, + "description": "Reject `${secret:…}` references this source's delivered content\nresolves. Default: `true`.", + "type": "boolean" + }, + "requireSignedCommits": { + "default": false, + "description": "Require that the HEAD commit in this source's git repo has a valid\nGPG or SSH signature. ORed with the subscriber's\n`subscription.requireSignedCommits`, so either side asking is enough.\nSubscribers can bypass both with `spec.security.allowUnsigned`.", + "type": "boolean" + } + }, + "type": "object" + } + }, + "description": "ConfigSource manifest published by teams for multi-source config management (cfgd-source.yaml)", + "properties": { + "apiVersion": { + "description": "API group/version, e.g. `cfgd.io/v1alpha1`.", + "type": "string" + }, + "kind": { + "description": "Document kind. Always `ConfigSource` for this file.", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/ConfigSourceMetadata", + "description": "Identifying metadata for this source." + }, + "spec": { + "$ref": "#/definitions/ConfigSourceSpec", + "description": "What the source publishes and its policy tiers." + } + }, + "required": ["apiVersion", "kind", "metadata", "spec"], + "title": "cfgd ConfigSource", + "type": "object" +} diff --git a/src/schemas/json/cfgd-module-0.11.0.json b/src/schemas/json/cfgd-module-0.11.0.json new file mode 100644 index 00000000000..b0458d2e333 --- /dev/null +++ b/src/schemas/json/cfgd-module-0.11.0.json @@ -0,0 +1,518 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://cfgd.io/schemas/cfgd-module.schema.json", + "$defs": { + "EncryptionMode": { + "description": "Controls when encryption is required for a managed file.", + "oneOf": [ + { + "const": "InRepo", + "description": "File must be encrypted when stored in the repository.", + "type": "string" + }, + { + "const": "Always", + "description": "File must always be encrypted, including at rest on disk.", + "type": "string" + } + ] + }, + "EncryptionSpec": { + "additionalProperties": false, + "description": "Encryption settings for a managed file.", + "properties": { + "backend": { + "description": "The encryption backend to use (e.g. \"sops\", \"age\").", + "type": "string" + }, + "mode": { + "$ref": "#/$defs/EncryptionMode", + "default": "InRepo", + "description": "When encryption must be enforced. Defaults to `InRepo`." + } + }, + "required": ["backend"], + "type": "object" + }, + "EnvVar": { + "description": "A single `NAME=VALUE` environment variable entry.", + "properties": { + "name": { + "description": "Variable name. Must be shell-safe and not a reserved `CFGD_*` name.", + "type": "string" + }, + "platforms": { + "description": "Platform tags gating this entry alone. Empty means every platform the\ndeclaring module or profile is not already gated off of. Tags are\nmatched against the machine's OS, distro, and arch; use `macos` for\nmacOS. An entry gated off this host is not part of its desired state at\nall: it appears on no surface, exactly as a platform-filtered package\ndoes.", + "items": { + "type": "string" + }, + "type": "array" + }, + "value": { + "description": "Value assigned to the variable, exported verbatim into the shell\nenvironment.", + "type": "string" + } + }, + "required": ["name", "value"], + "type": "object" + }, + "FileStrategy": { + "description": "File deployment strategy.", + "oneOf": [ + { + "const": "Symlink", + "description": "Create a symbolic link from target to source (default).", + "type": "string" + }, + { + "const": "Copy", + "description": "Copy source content to target.", + "type": "string" + }, + { + "const": "Template", + "description": "Render a Tera template and write the output (auto-selected for .tera files).", + "type": "string" + }, + { + "const": "Hardlink", + "description": "Create a hard link from target to source.", + "type": "string" + }, + { + "const": "Patch", + "description": "Merge structured keys/values into the target, or pipe it through a\nscript, leaving everything else untouched. Requires a `patch:` block.", + "type": "string" + } + ] + }, + "ModuleFileEntry": { + "additionalProperties": false, + "description": "One entry of `spec.files[]`: a file this module deploys.\n\n```yaml\nfiles:\n - source: files/init.lua\n target: ~/.config/nvim/init.lua\n```", + "properties": { + "encryption": { + "anyOf": [ + { + "$ref": "#/$defs/EncryptionSpec" + }, + { + "type": "null" + } + ], + "description": "Encryption settings for this module file." + }, + "patch": { + "anyOf": [ + { + "$ref": "#/$defs/PatchSpec" + }, + { + "type": "null" + } + ], + "description": "Structured merge or script configuration for `strategy: Patch`.\nRequired when `strategy` is `Patch`, rejected otherwise." + }, + "permissions": { + "description": "Unix permission bits (e.g. \"600\", \"644\") to apply after deployment.", + "type": ["string", "null"] + }, + "private": { + "description": "When true, the source file is local-only: auto-added to .gitignore,\nsilently skipped on machines where it doesn't exist.", + "type": "boolean" + }, + "source": { + "default": "", + "description": "Path to the source file, relative to the module directory. Not\nrequired when `strategy` is `Patch`; required otherwise.", + "type": "string" + }, + "strategy": { + "anyOf": [ + { + "$ref": "#/$defs/FileStrategy" + }, + { + "type": "null" + } + ], + "description": "Per-file deployment strategy override. Omitted, the module-wide default\napplies." + }, + "target": { + "description": "Destination path on the machine. A leading `~` expands to the home\ndirectory.", + "type": "string" + } + }, + "required": ["target"], + "type": "object" + }, + "ModuleMetadata": { + "additionalProperties": false, + "description": "`metadata`: identifying information for a module.", + "properties": { + "description": { + "description": "A one-line human summary shown in `cfgd module list` / `cfgd module show`.", + "type": ["string", "null"] + }, + "name": { + "description": "The module's name, referenced from a profile's `modules:` list.", + "type": "string" + }, + "version": { + "description": "The module's own release version, as `MAJOR.MINOR.PATCH` with optional\npre-release and build metadata (`1.2.0`, `2.0.0-rc.1`). It names the\n`/v` release tag that the workflow from\n`cfgd workflow generate` cuts when the module changes, so bumping it is\nwhat publishes a new release. Absent on modules that are not released\nindependently.", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", + "type": ["string", "null"] + } + }, + "required": ["name"], + "type": "object" + }, + "ModulePackageEntry": { + "additionalProperties": false, + "description": "One entry of `spec.packages[]`: a package this module installs.\n\n```yaml\npackages:\n - name: neovim\n minVersion: \"0.9\"\n prefer: [brew, apt]\n```", + "properties": { + "aliases": { + "additionalProperties": { + "type": "string" + }, + "description": "Manager-specific package name aliases (e.g. `{apt: \"neovim\", brew:\n\"neovim\"}`) for a package named differently across managers.", + "type": "object" + }, + "creates": { + "description": "Skip the install script if this path already exists. A leading `~`\nexpands to the home directory; a relative path resolves against the\nscript's working directory. Existence follows symlinks. Only meaningful\nfor a `prefer: [script]` install; ignored otherwise.", + "type": ["string", "null"] + }, + "deny": { + "description": "Package managers to never use for this package, even if otherwise\navailable and preferred by the profile.", + "items": { + "type": "string" + }, + "type": "array" + }, + "minVersion": { + "description": "Minimum acceptable installed version, loosely parsed (`\"1.2\"`, `\"1\"`).\nA version below this is treated as not satisfying the module.", + "type": ["string", "null"] + }, + "name": { + "default": "", + "description": "The package name as the chosen manager knows it.", + "type": "string" + }, + "onlyIf": { + "description": "Run the install script only if this command exits zero. A non-zero exit\nskips the install (the condition for installing was not met). Only\nmeaningful for a `prefer: [script]` install; ignored for manager-backed\ninstalls (those are idempotent via the manager's installed-package query).", + "type": ["string", "null"] + }, + "platforms": { + "description": "Platform tags gating this package alone. Empty means install on every\nplatform the module itself is not already gated off of.", + "items": { + "type": "string" + }, + "type": "array" + }, + "prefer": { + "description": "Manager preference order for this package, overriding the profile's\ndefault manager priority (e.g. `[brew, apt]`, or `[script]` to force\nthis entry's own `script`).", + "items": { + "type": "string" + }, + "type": "array" + }, + "script": { + "description": "Shell script to run instead of a manager install, selected via\n`prefer: [script]`.", + "type": ["string", "null"] + }, + "unless": { + "description": "Run the install script only if this command exits NON-zero. A zero exit\n(success) skips the install (the package already appears present). Only\nmeaningful for a `prefer: [script]` install; ignored otherwise.", + "type": ["string", "null"] + } + }, + "type": "object" + }, + "ModuleSpec": { + "additionalProperties": false, + "description": "`spec`: the declared surface of a module — everything it contributes to a\nprofile that includes it.", + "properties": { + "aliases": { + "description": "Shell aliases this module contributes.", + "items": { + "$ref": "#/$defs/ShellAlias" + }, + "type": "array" + }, + "depends": { + "description": "Names of other modules this one requires; cfgd resolves and applies them\nfirst.", + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "description": "Environment variables this module contributes.", + "items": { + "$ref": "#/$defs/EnvVar" + }, + "type": "array" + }, + "files": { + "description": "Files this module deploys.", + "items": { + "$ref": "#/$defs/ModuleFileEntry" + }, + "type": "array" + }, + "packages": { + "description": "Packages this module installs.", + "items": { + "$ref": "#/$defs/ModulePackageEntry" + }, + "type": "array" + }, + "platforms": { + "description": "Platform tags gating the whole module. When non-empty and the current\nplatform matches none of them, the module is skipped entirely (it\nappears as a skipped action rather than vanishing). Tags are matched\nagainst the machine's OS, distro, and arch; use `macos` for macOS.", + "items": { + "type": "string" + }, + "type": "array" + }, + "scripts": { + "anyOf": [ + { + "$ref": "#/$defs/ScriptSpec" + }, + { + "type": "null" + } + ], + "description": "Lifecycle scripts (`preApply`, `postApply`, …) this module runs." + }, + "system": { + "additionalProperties": true, + "description": "System configurator settings contributed by this module.\nDeep-merged into the profile system map; module values override profile values at leaf level.", + "type": "object" + } + }, + "type": "object" + }, + "PatchFormat": { + "description": "File format used to interpret and re-serialize a `Patch`-strategy target.", + "oneOf": [ + { + "const": "Ini", + "description": "INI sections/keys, edited line-by-line to preserve comments and layout.", + "type": "string" + }, + { + "const": "Json", + "description": "JSON, re-serialized on write (no comments to preserve).", + "type": "string" + }, + { + "const": "Yaml", + "description": "YAML; comments are NOT preserved across a merge (see docs for the caveat).", + "type": "string" + }, + { + "const": "Toml", + "description": "TOML, edited in place to preserve comments and layout.", + "type": "string" + } + ] + }, + "PatchSpec": { + "additionalProperties": false, + "description": "Configuration for the `Patch` file strategy: a structured merge (`ensure`)\nor a content-rewriting script, applied on top of the target's current\ncontent.", + "properties": { + "ensure": { + "description": "Keys/values to deep-merge into the target, leaving unmentioned keys\nuntouched. Values are literal (no template rendering). Mutually\nexclusive with `script`." + }, + "format": { + "anyOf": [ + { + "$ref": "#/$defs/PatchFormat" + }, + { + "type": "null" + } + ], + "description": "File format to parse the target as. Inferred from the target's\nextension when omitted." + }, + "script": { + "description": "A script path or an inline command that receives the target's current\ncontent on stdin and writes the new content to stdout. A relative path\nresolves against the module directory for a module file\n(`spec.files[]`) and against the config directory for a profile file\n(`spec.files.managed[]`); a value that resolves to no file is run as an\ninline command. Mutually exclusive with `ensure`.", + "type": ["string", "null"] + } + }, + "type": "object" + }, + "ScriptCommand": { + "description": "The mapping form of a script entry: a command with a timeout, shell,\nguard condition or working directory.", + "properties": { + "continueOnError": { + "description": "Treat a non-zero exit as success and continue reconciliation instead\nof failing the run. Default: `false`.", + "type": ["boolean", "null"] + }, + "creates": { + "description": "Skip the script if this path already exists. A leading `~` expands to\nthe home directory; a relative path resolves against the script's\nworking directory. Existence follows symlinks.", + "type": ["string", "null"] + }, + "idleTimeout": { + "description": "Kill the script if it produces no stdout/stderr output for this duration.\nPrevents scripts from silently hanging on unresponsive resources.\nFormat: \"30s\", \"2m\", etc. If unset, no idle timeout is enforced.", + "type": ["string", "null"] + }, + "interactive": { + "description": "Run the script attached to the terminal (inherited stdin/stdout/stderr,\nno spinner, no output capture, no idle timeout) so it can prompt the\nuser — e.g. `echo \"press Enter when done\"; read`. Requires a TTY: when\nstdin is not a terminal (CI, piped input, or any daemon-run phase) the\nscript is skipped with a warning rather than hanging on instant EOF.", + "type": "boolean" + }, + "onlyIf": { + "description": "Run the script only if this command exits zero. A non-zero exit skips\nthe script (the condition for running was not met). Evaluated with the\nsame shell, working directory, and environment as the body.", + "type": ["string", "null"] + }, + "run": { + "description": "The command or script body to run.", + "type": "string" + }, + "shell": { + "$ref": "#/$defs/ScriptShell", + "description": "Interpreter to use for inline commands. Ignored (and rejected) on file scripts." + }, + "timeout": { + "description": "Kill the script if it runs longer than this duration (`\"30s\"`, `\"2m\"`).\nUnset means no timeout.", + "type": ["string", "null"] + }, + "unless": { + "description": "Run the script only if this command exits NON-zero. A zero exit\n(success) skips the script (the guarded state already holds).\nEvaluated with the same shell, working directory, and environment as\nthe body.", + "type": ["string", "null"] + }, + "workdir": { + "description": "Working directory for the script. By default every lifecycle script\nruns in the user's home directory — never the config source tree — so\na relative write can't pollute the user's GitOps repo. Set `workdir`\nto override: a leading `~` expands to home and `$VAR`/`${VAR}` expand\nagainst the script environment (which always carries `$CFGD_MODULE_DIR`\nand `$CFGD_CONFIG_DIR`), so `workdir: ~/.local/share/app`,\n`workdir: $CFGD_MODULE_DIR`, or an absolute path all work.", + "type": ["string", "null"] + } + }, + "required": ["run"], + "type": "object" + }, + "ScriptEntry": { + "anyOf": [ + { + "description": "A bare command string, run with the platform's default shell and no\ntimeout/guard.", + "type": "string" + }, + { + "$ref": "#/$defs/ScriptCommand", + "description": "The mapping form, carrying the body and its knobs." + } + ], + "description": "A lifecycle script entry: either a bare command string, or a mapping for\none that needs a timeout, shell, or guard condition.\n\n```yaml\npreApply: \"echo starting\"\n# or\npostApply:\n run: brew update\n timeout: 2m\n onlyIf: command -v brew\n```" + }, + "ScriptShell": { + "description": "Interpreter for inline lifecycle scripts.", + "oneOf": [ + { + "enum": ["sh", "bash", "zsh", "pwsh", "cmd"], + "type": "string" + }, + { + "const": "auto", + "description": "Platform default: `sh` on Unix, `cmd.exe` on Windows.", + "type": "string" + } + ] + }, + "ScriptSpec": { + "additionalProperties": false, + "description": "`spec.scripts`: lifecycle hooks run at specific points in the reconcile cycle.\n\n```yaml\nscripts:\n preApply: \"echo starting apply\"\n postApply:\n - run: brew cleanup\n continueOnError: true\n onDrift: \"notify-send 'cfgd: drift detected'\"\n```", + "properties": { + "onChange": { + "default": [], + "description": "Run when a watched file changes on disk (requires `daemon.reconcile.onChange`).", + "items": { + "$ref": "#/$defs/ScriptEntry" + }, + "type": "array" + }, + "onDrift": { + "default": [], + "description": "Run when the daemon detects drift, before any auto-apply decision.", + "items": { + "$ref": "#/$defs/ScriptEntry" + }, + "type": "array" + }, + "postApply": { + "default": [], + "description": "Run once after every action in an apply completes.", + "items": { + "$ref": "#/$defs/ScriptEntry" + }, + "type": "array" + }, + "postReconcile": { + "default": [], + "description": "Run once after a daemon reconcile tick completes.", + "items": { + "$ref": "#/$defs/ScriptEntry" + }, + "type": "array" + }, + "preApply": { + "default": [], + "description": "Run once before any action in an apply.", + "items": { + "$ref": "#/$defs/ScriptEntry" + }, + "type": "array" + }, + "preReconcile": { + "default": [], + "description": "Run once before a daemon reconcile tick begins.", + "items": { + "$ref": "#/$defs/ScriptEntry" + }, + "type": "array" + } + }, + "type": "object" + }, + "ShellAlias": { + "description": "A single shell alias entry.", + "properties": { + "command": { + "description": "Command the alias expands to, written in the syntax of the shell it is\ngenerated for. It may carry arguments, pipes and quotes: cfgd quotes the\nwhole value per dialect when it writes the alias definition, so the text\nreaches the shell exactly as declared. Required — an alias with no\ncommand has nothing to expand to.", + "type": "string" + }, + "name": { + "description": "Alias name, as typed at the shell prompt.", + "type": "string" + }, + "platforms": { + "description": "Platform tags gating this entry alone. Empty means every platform the\ndeclaring module or profile is not already gated off of. Tags are\nmatched against the machine's OS, distro, and arch; use `macos` for\nmacOS. An entry gated off this host is not part of its desired state at\nall: it appears on no surface, exactly as a platform-filtered package\ndoes.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": ["name", "command"], + "type": "object" + } + }, + "additionalProperties": false, + "description": "Schema for cfgd Module documents (kind: Module)", + "properties": { + "apiVersion": { + "description": "API group/version, e.g. `cfgd.io/v1alpha1`.", + "type": "string" + }, + "kind": { + "description": "Document kind. Always `Module` for this file.", + "type": "string" + }, + "metadata": { + "$ref": "#/$defs/ModuleMetadata", + "description": "Identifying metadata for this module." + }, + "spec": { + "$ref": "#/$defs/ModuleSpec", + "description": "The module's declared surface." + } + }, + "required": ["apiVersion", "kind", "metadata", "spec"], + "title": "cfgd Module", + "type": "object" +} diff --git a/src/schemas/json/cfgd-profile-0.11.0.json b/src/schemas/json/cfgd-profile-0.11.0.json new file mode 100644 index 00000000000..6b21aaf3c1c --- /dev/null +++ b/src/schemas/json/cfgd-profile-0.11.0.json @@ -0,0 +1,1189 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://cfgd.io/schemas/cfgd-profile.schema.json", + "additionalProperties": false, + "definitions": { + "AptSpec": { + "additionalProperties": false, + "description": "The object form of `apt`: a package list, a file listing packages, or both.\nA bare list of names folds into `packages`.", + "properties": { + "file": { + "default": null, + "description": "Path to a package-list file to install from, one name per line.\nRelative to the config root.", + "type": ["string", "null"] + }, + "packages": { + "default": [], + "description": "APT package names to install.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "BackupSpec": { + "additionalProperties": false, + "description": "A declarative backup: snapshot `source` (a file or directory) into\n`destination`, retaining the newest `retention` snapshots.\n\nThe shape is validated at parse time and run by the backup engine.\nSchedule-less backups (no `schedule`) run automatically on every\n`cfgd apply`; every backup — scheduled or not — can also be run directly\nwith `cfgd backup run [name]`.", + "properties": { + "destination": { + "description": "Where snapshots are written. Defaults to `/backups//`\nwhen omitted — resolved by the backup engine, not at parse time, since\nthe state dir depends on runtime scope/overrides.", + "type": ["string", "null"] + }, + "name": { + "description": "Unique identifier for this backup within `spec.backups`, unique across\nthe list. Keys the `destination` default, run records, and CLI\nselection. Becomes a directory component (`/backups//`)\nand a lock filename (`/locks/backup-.lock`), so it must\nbe non-empty, non-blank, a single segment (no `/` or `\\`), not a\ndirectory reference (`.`, `..`), not rooted (`/daily`, `C:/daily`), and\nfree of `:` anywhere — a drive and NTFS data-stream separator on Windows.\nWindows shapes are rejected on every platform so a name written on one\nOS stays valid on the others.", + "type": "string" + }, + "namePattern": { + "default": "{filename}.{timestamp}", + "description": "Filename template for each snapshot. Supports `{name}`, `{filename}`,\nand `{timestamp}` (UTC, `%Y%m%dT%H%M%SZ`). Unknown `{var}` tokens are\nrejected at parse time. A literal `/` nests the snapshot in a\nsubdirectory of the destination. At run time the rendered value must be\nrelative and every segment must name something: `.` and `..` segments,\nempty segments (`a//b`, `daily/`), rooted values (`/daily`, `C:/daily`,\n`C:daily`, `\\\\server\\share`), and `:` anywhere are all rejected. Windows\nshapes are rejected on every platform, so a pattern is valid everywhere\nor nowhere. A rejection names the `{filename}` it interpolated, so a\ncolon in the source filename points at itself. Defaults to\n`\"{filename}.{timestamp}\"`.", + "type": "string" + }, + "postBackup": { + "default": [], + "description": "Scripts run after the copy step (e.g. restart the service stopped by\n`preBackup`). Always attempted, including after a failed `preBackup` or\na failed copy.", + "items": { + "$ref": "#/definitions/ScriptEntry" + }, + "type": "array" + }, + "preBackup": { + "default": [], + "description": "Scripts run before the snapshot is taken (e.g. stop a service that\nholds `source` open so the snapshot is consistent). A failure skips the\nsnapshot and records a failed run; `postBackup` still runs.", + "items": { + "$ref": "#/definitions/ScriptEntry" + }, + "type": "array" + }, + "retention": { + "default": 10, + "description": "Number of newest snapshots to keep for this backup; older snapshots are\npruned from disk and from the run history. Must be at least 1 (`0` would\nkeep no backups, which is a misconfiguration rather than a supported\n\"unlimited\" mode). Defaults to 10.", + "format": "uint32", + "minimum": 1, + "type": "integer" + }, + "schedule": { + "description": "When to run this backup: a duration interval (e.g. `\"6h\"`) or a cron\nexpression, validated at parse time. Cron expressions may be 5-field\n(`minute hour day month weekday`, e.g. `\"0 3 * * *\"`) or 6-field with a\nleading seconds field (`second minute hour day month weekday`, e.g.\n`\"30 0 3 * * *\"`), and are evaluated in the machine's LOCAL timezone,\nlike a crontab entry. An interval is measured from the unit's last\nrecorded run, so a `\"1d\"` backup on a machine rebooted daily still fires\ndaily. Setting this hands the backup to the daemon's timers and takes it\nout of apply; omitted means \"run on every apply\".", + "type": ["string", "null"] + }, + "scheduleOwner": { + "$ref": "#/definitions/ScheduleOwner", + "default": "Cluster", + "description": "Which layer owns this unit's schedule. `Cluster` (the default) lets a\ncluster `BackupPolicy` set or replace this unit's `schedule` and\n`retention`; `Local` pins the unit to the machine, so a policy reports\nit but projects no schedule onto it. Parsed case-insensitively." + }, + "source": { + "description": "File or directory to snapshot. A leading `~` expands to the home\ndirectory. Must not contain, or sit inside, the resolved `destination` —\na nested pair is rejected before any copy, with symlinks resolved on both\nsides. Its filename is what `{filename}` interpolates, so a source whose\nfilename contains `:` (legal on Unix, a drive and data-stream separator\non Windows) needs an explicit `namePattern` that leaves `{filename}` out.", + "type": "string" + } + }, + "required": ["name", "source"], + "type": "object" + }, + "BrewSpec": { + "additionalProperties": false, + "description": "The object form of `brew`: taps, formulae and casks, or a Brewfile. A bare\nlist of names folds into `formulae`.", + "properties": { + "casks": { + "default": [], + "description": "Homebrew casks (GUI applications) to install.", + "items": { + "type": "string" + }, + "type": "array" + }, + "file": { + "default": null, + "description": "Path to a Brewfile to apply instead of (or alongside) `taps`,\n`formulae` and `casks`. Relative to the config root.", + "type": ["string", "null"] + }, + "formulae": { + "default": [], + "description": "Homebrew formulae (CLI packages) to install.", + "items": { + "type": "string" + }, + "type": "array" + }, + "taps": { + "default": [], + "description": "Third-party taps to add before installing formulae/casks.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "CargoSpec": { + "additionalProperties": false, + "description": "The object form of `cargo`: crates to install, a `Cargo.toml` to install\nfrom, or both. A bare list of names folds into `packages`.", + "properties": { + "file": { + "description": "Path to a `Cargo.toml` whose binaries to install instead of `packages`.\nRelative to the config root.", + "type": ["string", "null"] + }, + "packages": { + "default": [], + "description": "Crate names to install (`cargo install`).", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "CustomManagerSpec": { + "additionalProperties": false, + "description": "A user-defined package manager under `spec.packages.custom[]`, driven\nentirely by shell commands.\n\n```yaml\ncustom:\n - name: asdf\n check: \"command -v asdf\"\n listInstalled: \"asdf list\"\n install: \"asdf install {package}\"\n uninstall: \"asdf uninstall {package}\"\n packages: [nodejs]\n```", + "properties": { + "check": { + "description": "Command that exits zero when this manager is available on the machine.", + "type": "string" + }, + "install": { + "description": "Command template to install a package; `{package}` is substituted.", + "type": "string" + }, + "listInstalled": { + "description": "Command whose stdout lists installed package names, one per line.", + "type": "string" + }, + "name": { + "description": "Manager name, used in `prefer:`/`deny:` lists and status output.", + "type": "string" + }, + "packages": { + "default": [], + "description": "Package names to install with this manager.", + "items": { + "type": "string" + }, + "type": "array" + }, + "uninstall": { + "description": "Command template to uninstall a package; `{package}` is substituted.", + "type": "string" + }, + "update": { + "default": null, + "description": "Command to refresh the manager's own package index/cache before installs.", + "type": ["string", "null"] + } + }, + "required": ["name", "check", "listInstalled", "install", "uninstall"], + "type": "object" + }, + "EncryptionMode": { + "description": "Controls when encryption is required for a managed file.", + "oneOf": [ + { + "const": "InRepo", + "description": "File must be encrypted when stored in the repository.", + "type": "string" + }, + { + "const": "Always", + "description": "File must always be encrypted, including at rest on disk.", + "type": "string" + } + ] + }, + "EncryptionSpec": { + "additionalProperties": false, + "description": "Encryption settings for a managed file.", + "properties": { + "backend": { + "description": "The encryption backend to use (e.g. \"sops\", \"age\").", + "type": "string" + }, + "mode": { + "$ref": "#/definitions/EncryptionMode", + "default": "InRepo", + "description": "When encryption must be enforced. Defaults to `InRepo`." + } + }, + "required": ["backend"], + "type": "object" + }, + "EnvScope": { + "description": "How far `spec.env` exports reach across the current user's environment.\n\nThe two env fields differ by *scope of affected users*: `spec.env` targets\nthe current user, `spec.system.environment` targets all users (privileged).\nThis knob narrows the *current-user* reach; it never widens beyond the user.", + "oneOf": [ + { + "const": "All", + "description": "Every standard user entry point cfgd can safely touch: interactive +\nlogin shells, `systemd --user` / Wayland GUI sessions, macOS GUI apps,\nand an immediate live-session refresh. The default — no gotchas.", + "type": "string" + }, + { + "const": "Login", + "description": "Interactive shells plus login shells (`~/.zshenv`, `~/.profile`, and an\nexisting `~/.bash_profile`). Excludes the GUI / `systemd --user` session\nsurfaces and the live-session refresh.", + "type": "string" + }, + { + "const": "Interactive", + "description": "Interactive shells only (`~/.bashrc` / `~/.zshrc`, fish conf.d) — the\nhistorical behavior before full reach.", + "type": "string" + } + ] + }, + "EnvVar": { + "description": "A single `NAME=VALUE` environment variable entry.", + "properties": { + "name": { + "description": "Variable name. Must be shell-safe and not a reserved `CFGD_*` name.", + "type": "string" + }, + "platforms": { + "description": "Platform tags gating this entry alone. Empty means every platform the\ndeclaring module or profile is not already gated off of. Tags are\nmatched against the machine's OS, distro, and arch; use `macos` for\nmacOS. An entry gated off this host is not part of its desired state at\nall: it appears on no surface, exactly as a platform-filtered package\ndoes.", + "items": { + "type": "string" + }, + "type": "array" + }, + "value": { + "description": "Value assigned to the variable, exported verbatim into the shell\nenvironment.", + "type": "string" + } + }, + "required": ["name", "value"], + "type": "object" + }, + "FileStrategy": { + "description": "File deployment strategy.", + "oneOf": [ + { + "const": "Symlink", + "description": "Create a symbolic link from target to source (default).", + "type": "string" + }, + { + "const": "Copy", + "description": "Copy source content to target.", + "type": "string" + }, + { + "const": "Template", + "description": "Render a Tera template and write the output (auto-selected for .tera files).", + "type": "string" + }, + { + "const": "Hardlink", + "description": "Create a hard link from target to source.", + "type": "string" + }, + { + "const": "Patch", + "description": "Merge structured keys/values into the target, or pipe it through a\nscript, leaving everything else untouched. Requires a `patch:` block.", + "type": "string" + } + ] + }, + "FilesSpec": { + "additionalProperties": false, + "description": "`spec.files`: files this profile deploys and their permission overrides.\n\n```yaml\nfiles:\n managed:\n - source: files/gitconfig\n target: ~/.gitconfig\n permissions:\n ~/.ssh/id_ed25519: \"0600\"\n```", + "properties": { + "managed": { + "default": [], + "description": "Files this profile deploys, each pairing a source in the config\ndirectory with a target on the machine. Empty, no files are managed.", + "items": { + "$ref": "#/definitions/ManagedFileSpec" + }, + "type": "array" + }, + "permissions": { + "additionalProperties": { + "type": "string" + }, + "default": {}, + "description": "Octal permission strings (`\"0600\"`) keyed by target path, applied after\ndeployment.", + "type": "object" + } + }, + "type": "object" + }, + "FlatpakSpec": { + "additionalProperties": false, + "description": "The object form of `flatpak`: application ids and the remote to install\nthem from. A bare list of ids folds into `packages`.", + "properties": { + "packages": { + "default": [], + "description": "Flatpak application ids to install.", + "items": { + "type": "string" + }, + "type": "array" + }, + "remote": { + "default": null, + "description": "Remote to install from (e.g. `flathub`). Falls back to Flatpak's\nconfigured default remote when omitted.", + "type": ["string", "null"] + } + }, + "type": "object" + }, + "ManagedFileSpec": { + "additionalProperties": false, + "description": "One entry of `spec.files.managed[]`: a file this profile deploys.\n\n```yaml\nfiles:\n managed:\n - source: files/gitconfig\n target: ~/.gitconfig\n permissions: \"644\"\n```", + "properties": { + "encryption": { + "anyOf": [ + { + "$ref": "#/definitions/EncryptionSpec" + }, + { + "type": "null" + } + ], + "description": "Encryption settings for this file." + }, + "patch": { + "anyOf": [ + { + "$ref": "#/definitions/PatchSpec" + }, + { + "type": "null" + } + ], + "description": "Structured merge or script configuration for `strategy: Patch`.\nRequired when `strategy` is `Patch`, rejected otherwise." + }, + "permissions": { + "description": "Unix permission bits (e.g. \"600\", \"644\") to apply after deployment.", + "type": ["string", "null"] + }, + "private": { + "description": "When true, the source file is local-only: auto-added to .gitignore,\nsilently skipped on machines where it doesn't exist.", + "type": "boolean" + }, + "source": { + "default": "", + "description": "Path to the source file. Not required when `strategy` is `Patch`;\nrequired otherwise.", + "type": "string" + }, + "strategy": { + "anyOf": [ + { + "$ref": "#/definitions/FileStrategy" + }, + { + "type": "null" + } + ], + "description": "Per-file deployment strategy override. Omitted, the profile-wide\ndefault applies." + }, + "target": { + "description": "Destination path on the machine. A leading `~` expands to the home\ndirectory.", + "type": "string" + } + }, + "required": ["target"], + "type": "object" + }, + "NpmSpec": { + "additionalProperties": false, + "description": "The object form of `npm`: global packages, a `package.json` to install\nfrom, or both. A bare list of names folds into `global`.", + "properties": { + "file": { + "default": null, + "description": "Path to a `package.json` to install dependencies from. Relative to the\nconfig root.", + "type": ["string", "null"] + }, + "global": { + "default": [], + "description": "Package names to install globally (`npm install -g`).", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "PackageListSpec": { + "additionalProperties": false, + "description": "The map form of a bare-list manager (`pipx`, `dnf`, `apk`, …): the same\nlist under a `packages` key.", + "properties": { + "packages": { + "default": [], + "description": "Package names.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "PackagesSpec": { + "additionalProperties": false, + "description": "`spec.packages`: packages to install, grouped by package manager.\n\nEvery manager field accepts either a bare list of names or (for the\nmanagers with options of their own) a mapping:\n\n```yaml\npackages:\n brew:\n formulae: [ripgrep, fzf]\n casks: [alacritty]\n apt: [curl, git]\n cargo: [ripgrep]\n```", + "properties": { + "apk": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "APK packages (Alpine)." + }, + "apt": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/AptSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "APT packages (Debian/Ubuntu)." + }, + "brew": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/BrewSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Homebrew packages (macOS/Linux)." + }, + "cargo": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/CargoSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Cargo packages (`cargo install`)." + }, + "chocolatey": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Chocolatey packages (Windows)." + }, + "custom": { + "default": [], + "description": "User-defined package managers not built into cfgd, each with its own\ncheck/install/uninstall commands.", + "items": { + "$ref": "#/definitions/CustomManagerSpec" + }, + "type": "array" + }, + "dnf": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "DNF packages (Fedora/RHEL)." + }, + "flatpak": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/FlatpakSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Flatpak packages (Linux)." + }, + "go": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Go packages (`go install`)." + }, + "nix": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Nix packages (`nix-env` / `nix profile`)." + }, + "npm": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/NpmSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "npm global packages." + }, + "pacman": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Pacman packages (Arch)." + }, + "pipx": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "pipx-installed Python applications." + }, + "pkg": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "pkg packages (FreeBSD)." + }, + "scoop": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Scoop packages (Windows)." + }, + "snap": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/SnapSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Snap packages (Linux)." + }, + "winget": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Winget packages (Windows)." + }, + "yum": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Yum packages (legacy RHEL/CentOS)." + }, + "zypper": { + "anyOf": [ + { + "description": "Package names, as a bare list.", + "items": { + "type": "string" + }, + "type": "array" + }, + { + "$ref": "#/definitions/PackageListSpec" + }, + { + "type": "null" + } + ], + "default": [], + "description": "Zypper packages (openSUSE)." + } + }, + "type": "object" + }, + "PatchFormat": { + "description": "File format used to interpret and re-serialize a `Patch`-strategy target.", + "oneOf": [ + { + "const": "Ini", + "description": "INI sections/keys, edited line-by-line to preserve comments and layout.", + "type": "string" + }, + { + "const": "Json", + "description": "JSON, re-serialized on write (no comments to preserve).", + "type": "string" + }, + { + "const": "Yaml", + "description": "YAML; comments are NOT preserved across a merge (see docs for the caveat).", + "type": "string" + }, + { + "const": "Toml", + "description": "TOML, edited in place to preserve comments and layout.", + "type": "string" + } + ] + }, + "PatchSpec": { + "additionalProperties": false, + "description": "Configuration for the `Patch` file strategy: a structured merge (`ensure`)\nor a content-rewriting script, applied on top of the target's current\ncontent.", + "properties": { + "ensure": { + "description": "Keys/values to deep-merge into the target, leaving unmentioned keys\nuntouched. Values are literal (no template rendering). Mutually\nexclusive with `script`." + }, + "format": { + "anyOf": [ + { + "$ref": "#/definitions/PatchFormat" + }, + { + "type": "null" + } + ], + "description": "File format to parse the target as. Inferred from the target's\nextension when omitted." + }, + "script": { + "description": "A script path or an inline command that receives the target's current\ncontent on stdin and writes the new content to stdout. A relative path\nresolves against the module directory for a module file\n(`spec.files[]`) and against the config directory for a profile file\n(`spec.files.managed[]`); a value that resolves to no file is run as an\ninline command. Mutually exclusive with `ensure`.", + "type": ["string", "null"] + } + }, + "type": "object" + }, + "ProfileMetadata": { + "additionalProperties": false, + "description": "`metadata`: identifying information for a profile.", + "properties": { + "name": { + "description": "The profile's name, referenced by `spec.profile` in `cfgd.yaml` and by\n`inherits:` in another profile.", + "type": "string" + } + }, + "required": ["name"], + "type": "object" + }, + "ProfileSpec": { + "additionalProperties": false, + "description": "`spec`: the declared surface of a profile.", + "properties": { + "aliases": { + "default": [], + "description": "Shell aliases this profile sets.", + "items": { + "$ref": "#/definitions/ShellAlias" + }, + "type": "array" + }, + "backups": { + "default": [], + "description": "Declarative backup jobs this profile schedules.", + "items": { + "$ref": "#/definitions/BackupSpec" + }, + "type": "array" + }, + "env": { + "default": [], + "description": "Environment variables this profile sets.", + "items": { + "$ref": "#/definitions/EnvVar" + }, + "type": "array" + }, + "envScope": { + "anyOf": [ + { + "$ref": "#/definitions/EnvScope" + }, + { + "type": "null" + } + ], + "description": "How far `spec.env` exports reach across the current user's environment.\nOmitted means \"inherit\" (a parent layer's value survives); the resolved\ndefault when no layer sets it is `All` — every standard user entry point\ncfgd can safely touch. Narrow it to `Login` or `Interactive` to opt out\nof the broader session surfaces." + }, + "files": { + "anyOf": [ + { + "$ref": "#/definitions/FilesSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Files this profile deploys." + }, + "inherits": { + "default": [], + "description": "Names of base profiles to merge under this one. Later fields in this\nprofile override an inherited base's; lists are unioned.", + "items": { + "type": "string" + }, + "type": "array" + }, + "modules": { + "default": [], + "description": "Names of modules this profile includes.", + "items": { + "type": "string" + }, + "type": "array" + }, + "packages": { + "anyOf": [ + { + "$ref": "#/definitions/PackagesSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Packages this profile installs, grouped by manager." + }, + "scripts": { + "anyOf": [ + { + "$ref": "#/definitions/ScriptSpec" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Lifecycle scripts (`preApply`, `postApply`, …) this profile runs." + }, + "secrets": { + "default": [], + "description": "Secrets this profile resolves into files or environment variables.", + "items": { + "$ref": "#/definitions/SecretSpec" + }, + "type": "array" + }, + "system": { + "additionalProperties": true, + "default": {}, + "description": "System configurator settings (`macosDefaults`, `systemd`, `sysctl`, …),\nkeyed by configurator name.", + "type": "object" + } + }, + "type": "object" + }, + "ScheduleOwner": { + "description": "Which layer owns a backup unit's schedule.\n\n`Cluster` (the default) leaves the unit open to a cluster `BackupPolicy`,\nwhich may set or replace its `schedule` and `retention`. `Local` pins the\nunit to the machine: the policy still reports it, but projects no schedule\nonto it.", + "oneOf": [ + { + "const": "Cluster", + "description": "A cluster `BackupPolicy` may override this unit's schedule (default).", + "type": "string" + }, + { + "const": "Local", + "description": "The profile keeps this unit's schedule; no policy projects onto it.", + "type": "string" + } + ] + }, + "ScriptCommand": { + "description": "The mapping form of a script entry: a command with a timeout, shell,\nguard condition or working directory.", + "properties": { + "continueOnError": { + "description": "Treat a non-zero exit as success and continue reconciliation instead\nof failing the run. Default: `false`.", + "type": ["boolean", "null"] + }, + "creates": { + "description": "Skip the script if this path already exists. A leading `~` expands to\nthe home directory; a relative path resolves against the script's\nworking directory. Existence follows symlinks.", + "type": ["string", "null"] + }, + "idleTimeout": { + "description": "Kill the script if it produces no stdout/stderr output for this duration.\nPrevents scripts from silently hanging on unresponsive resources.\nFormat: \"30s\", \"2m\", etc. If unset, no idle timeout is enforced.", + "type": ["string", "null"] + }, + "interactive": { + "description": "Run the script attached to the terminal (inherited stdin/stdout/stderr,\nno spinner, no output capture, no idle timeout) so it can prompt the\nuser — e.g. `echo \"press Enter when done\"; read`. Requires a TTY: when\nstdin is not a terminal (CI, piped input, or any daemon-run phase) the\nscript is skipped with a warning rather than hanging on instant EOF.", + "type": "boolean" + }, + "onlyIf": { + "description": "Run the script only if this command exits zero. A non-zero exit skips\nthe script (the condition for running was not met). Evaluated with the\nsame shell, working directory, and environment as the body.", + "type": ["string", "null"] + }, + "run": { + "description": "The command or script body to run.", + "type": "string" + }, + "shell": { + "$ref": "#/definitions/ScriptShell", + "description": "Interpreter to use for inline commands. Ignored (and rejected) on file scripts." + }, + "timeout": { + "description": "Kill the script if it runs longer than this duration (`\"30s\"`, `\"2m\"`).\nUnset means no timeout.", + "type": ["string", "null"] + }, + "unless": { + "description": "Run the script only if this command exits NON-zero. A zero exit\n(success) skips the script (the guarded state already holds).\nEvaluated with the same shell, working directory, and environment as\nthe body.", + "type": ["string", "null"] + }, + "workdir": { + "description": "Working directory for the script. By default every lifecycle script\nruns in the user's home directory — never the config source tree — so\na relative write can't pollute the user's GitOps repo. Set `workdir`\nto override: a leading `~` expands to home and `$VAR`/`${VAR}` expand\nagainst the script environment (which always carries `$CFGD_MODULE_DIR`\nand `$CFGD_CONFIG_DIR`), so `workdir: ~/.local/share/app`,\n`workdir: $CFGD_MODULE_DIR`, or an absolute path all work.", + "type": ["string", "null"] + } + }, + "required": ["run"], + "type": "object" + }, + "ScriptEntry": { + "anyOf": [ + { + "description": "A bare command string, run with the platform's default shell and no\ntimeout/guard.", + "type": "string" + }, + { + "$ref": "#/definitions/ScriptCommand", + "description": "The mapping form, carrying the body and its knobs." + } + ], + "description": "A lifecycle script entry: either a bare command string, or a mapping for\none that needs a timeout, shell, or guard condition.\n\n```yaml\npreApply: \"echo starting\"\n# or\npostApply:\n run: brew update\n timeout: 2m\n onlyIf: command -v brew\n```" + }, + "ScriptShell": { + "description": "Interpreter for inline lifecycle scripts.", + "oneOf": [ + { + "enum": ["sh", "bash", "zsh", "pwsh", "cmd"], + "type": "string" + }, + { + "const": "auto", + "description": "Platform default: `sh` on Unix, `cmd.exe` on Windows.", + "type": "string" + } + ] + }, + "ScriptSpec": { + "additionalProperties": false, + "description": "`spec.scripts`: lifecycle hooks run at specific points in the reconcile cycle.\n\n```yaml\nscripts:\n preApply: \"echo starting apply\"\n postApply:\n - run: brew cleanup\n continueOnError: true\n onDrift: \"notify-send 'cfgd: drift detected'\"\n```", + "properties": { + "onChange": { + "default": [], + "description": "Run when a watched file changes on disk (requires `daemon.reconcile.onChange`).", + "items": { + "$ref": "#/definitions/ScriptEntry" + }, + "type": "array" + }, + "onDrift": { + "default": [], + "description": "Run when the daemon detects drift, before any auto-apply decision.", + "items": { + "$ref": "#/definitions/ScriptEntry" + }, + "type": "array" + }, + "postApply": { + "default": [], + "description": "Run once after every action in an apply completes.", + "items": { + "$ref": "#/definitions/ScriptEntry" + }, + "type": "array" + }, + "postReconcile": { + "default": [], + "description": "Run once after a daemon reconcile tick completes.", + "items": { + "$ref": "#/definitions/ScriptEntry" + }, + "type": "array" + }, + "preApply": { + "default": [], + "description": "Run once before any action in an apply.", + "items": { + "$ref": "#/definitions/ScriptEntry" + }, + "type": "array" + }, + "preReconcile": { + "default": [], + "description": "Run once before a daemon reconcile tick begins.", + "items": { + "$ref": "#/definitions/ScriptEntry" + }, + "type": "array" + } + }, + "type": "object" + }, + "SecretSpec": { + "additionalProperties": false, + "description": "One entry of `spec.secrets[]`: a secret resolved into a file, into\nenvironment variables, or both. At least one of `target` / `envs` must be\nset; an entry carrying both writes the file AND exports the variables from\none resolution.\n\n```yaml\nsecrets:\n - source: op://Personal/GitHub/token\n envs: [GITHUB_TOKEN]\n - source: ssh_key\n target: ~/.ssh/id_ed25519\n - source: vault://secret/data/api#key\n target: ~/.config/api-key\n envs: [API_KEY]\n```", + "properties": { + "backend": { + "description": "Secret backend name to resolve `source` with. Falls back to\n`spec.secrets.backend` from `cfgd.yaml` when omitted.", + "type": ["string", "null"] + }, + "envs": { + "description": "Environment variable names to export the decrypted value under. May be\ncombined with `target`.", + "items": { + "type": "string" + }, + "type": ["array", "null"] + }, + "source": { + "description": "Backend-specific reference to the secret (a 1Password `op://` URI, a\nVault path, a sops-encrypted file key, …).", + "type": "string" + }, + "target": { + "description": "File path to write the decrypted secret to. May be combined with `envs`.", + "type": ["string", "null"] + }, + "template": { + "description": "Template rendered around the resolved value before it is written to\n`target` or exported under `envs`: every `${secret:value}` in it is\nreplaced by the value (`template: \"token: ${secret:value}\"`). Only a\nprovider reference (`op://`, `vault://`, …) resolves to a single value,\nso `template` is rejected on a sops-encrypted file source.", + "type": ["string", "null"] + } + }, + "required": ["source"], + "type": "object" + }, + "ShellAlias": { + "description": "A single shell alias entry.", + "properties": { + "command": { + "description": "Command the alias expands to, written in the syntax of the shell it is\ngenerated for. It may carry arguments, pipes and quotes: cfgd quotes the\nwhole value per dialect when it writes the alias definition, so the text\nreaches the shell exactly as declared. Required — an alias with no\ncommand has nothing to expand to.", + "type": "string" + }, + "name": { + "description": "Alias name, as typed at the shell prompt.", + "type": "string" + }, + "platforms": { + "description": "Platform tags gating this entry alone. Empty means every platform the\ndeclaring module or profile is not already gated off of. Tags are\nmatched against the machine's OS, distro, and arch; use `macos` for\nmacOS. An entry gated off this host is not part of its desired state at\nall: it appears on no surface, exactly as a platform-filtered package\ndoes.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": ["name", "command"], + "type": "object" + }, + "SnapSpec": { + "additionalProperties": false, + "description": "The object form of `snap`: strict and classic-confinement snaps. A bare\nlist of names folds into `packages`.", + "properties": { + "classic": { + "default": [], + "description": "Snap names installed with `--classic` confinement.", + "items": { + "type": "string" + }, + "type": "array" + }, + "packages": { + "default": [], + "description": "Snap names installed with default (strict) confinement.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + }, + "description": "Profile document for cfgd (profiles/*.yaml)", + "properties": { + "apiVersion": { + "description": "API group/version, e.g. `cfgd.io/v1alpha1`.", + "type": "string" + }, + "kind": { + "description": "Document kind. Always `Profile` for this file.", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/ProfileMetadata", + "description": "Identifying metadata for this profile." + }, + "spec": { + "$ref": "#/definitions/ProfileSpec", + "description": "The profile's declared surface." + } + }, + "required": ["apiVersion", "kind", "metadata", "spec"], + "title": "cfgd Profile", + "type": "object" +} diff --git a/src/schemas/json/mprocs-0.6.4.json b/src/schemas/json/mprocs-0.6.4.json index 8a4f6bb5db2..991ac29bdde 100644 --- a/src/schemas/json/mprocs-0.6.4.json +++ b/src/schemas/json/mprocs-0.6.4.json @@ -100,9 +100,15 @@ }, "oneOf": [ { + "properties": { + "shell": {} + }, "required": ["shell"] }, { + "properties": { + "cmd": {} + }, "required": ["cmd"] } ], diff --git a/src/schemas/json/nest-cli.json b/src/schemas/json/nest-cli.json index eb8ad2059a9..1cb76abaebe 100644 --- a/src/schemas/json/nest-cli.json +++ b/src/schemas/json/nest-cli.json @@ -144,27 +144,34 @@ }, "AssetsOptions": { "$comment": "https://docs.nestjs.com/cli/monorepo#assets", - "type": ["string", "object"], "description": "For finer control, the element can be object.", - "properties": { - "include": { - "type": "string", - "description": "Glob-like file specifications for the assets to be distributed." - }, - "exclude": { - "type": "string", - "description": "Glob-like file specifications for the assets to be excluded from the include list." - }, - "outDir": { - "type": "string", - "description": "A string specifying the path (relative to the root folder) where the assets should be distributed. Defaults to the same output directory configured for compiler output." + "oneOf": [ + { + "type": "string" }, - "watchAssets": { - "type": "boolean", - "description": "If true, run in watch mode watching specified assets. Setting watchAssets in a top-level compilerOptions property overrides any watchAssets settings within the assets property." + { + "type": "object", + "properties": { + "include": { + "type": "string", + "description": "Glob-like file specifications for the assets to be distributed." + }, + "exclude": { + "type": "string", + "description": "Glob-like file specifications for the assets to be excluded from the include list." + }, + "outDir": { + "type": "string", + "description": "A string specifying the path (relative to the root folder) where the assets should be distributed. Defaults to the same output directory configured for compiler output." + }, + "watchAssets": { + "type": "boolean", + "description": "If true, run in watch mode watching specified assets. Setting watchAssets in a top-level compilerOptions property overrides any watchAssets settings within the assets property." + } + }, + "additionalProperties": false } - }, - "additionalProperties": false + ] }, "GenerateOptions": { "$comment": "https://docs.nestjs.com/cli/monorepo#global-generate-options", @@ -192,155 +199,162 @@ }, "GenerateSpecOptions": { "$comment": "https://docs.nestjs.com/cli/monorepo#global-generate-options", - "type": ["boolean", "object"], "description": "If the value is boolean, a value of true enables spec generation by default and a value of false disables it. A flag passed on the CLI command line overrides this setting, as does a project-specific generateOptions setting (more below). If the value is an object, each key represents a schematic name, and the boolean value determines whether the default spec generation is enabled / disabled for that specific schematic. See https://docs.nestjs.com/cli/monorepo#global-generate-options for details.", - "properties": { - "application": { - "type": "boolean", - "description": "Generate spec file for application schematics or not." - }, - "class": { - "type": "boolean", - "description": "Disable spec file generation for class schematics." - }, - "cl": { - "type": "boolean", - "description": "Alias for class" - }, - "configuration": { - "type": "boolean", - "description": "Generate spec file for configuration schematics or not." - }, - "config": { - "type": "boolean", - "description": "Alias for configuration" - }, - "controller": { - "type": "boolean", - "description": "Generate spec file for controller schematics or not." - }, - "co": { - "type": "boolean", - "description": "Alias for controller" - }, - "decorator": { - "type": "boolean", - "description": "Generate spec file for decorator schematics or not." - }, - "d": { - "type": "boolean", - "description": "Alias for decorator" - }, - "filter": { - "type": "boolean", - "description": "Generate spec file for filter schematics or not." - }, - "f": { - "type": "boolean", - "description": "Alias for filter" - }, - "gateway": { - "type": "boolean", - "description": "Generate spec file for gateway schematics or not." - }, - "ga": { - "type": "boolean", - "description": "Alias for gateway" - }, - "guard": { - "type": "boolean", - "description": "Generate spec file for guard schematics or not." - }, - "gu": { - "type": "boolean", - "description": "Alias for guard" - }, - "interceptor": { - "type": "boolean", - "description": "Generate spec file for interceptor schematics or not." - }, - "in": { - "type": "boolean", - "description": "Alias for interceptor" - }, - "interface": { - "type": "boolean", - "description": "Generate spec file for interface schematics or not." - }, - "middleware": { - "type": "boolean", - "description": "Generate spec file for middleware schematics or not." - }, - "mi": { - "type": "boolean", - "description": "Alias for middleware" - }, - "module": { - "type": "boolean", - "description": "Generate spec file for module schematics or not." - }, - "mo": { - "type": "boolean", - "description": "Alias for module" - }, - "pipe": { - "type": "boolean", - "description": "Generate spec file for pipe schematics or not." - }, - "pi": { - "type": "boolean", - "description": "Alias for pipe" - }, - "provider": { - "type": "boolean", - "description": "Generate spec file for provider schematics or not." - }, - "pr": { - "type": "boolean", - "description": "Alias for provider" - }, - "resolver": { - "type": "boolean", - "description": "Generate spec file for resolver schematics or not." - }, - "r": { - "type": "boolean", - "description": "Alias for resolver" - }, - "service": { - "type": "boolean", - "description": "Generate spec file for service schematics or not." - }, - "s": { - "type": "boolean", - "description": "Alias for resolver" - }, - "library": { - "type": "boolean", - "description": "Generate spec file for library schematics or not." - }, - "lib": { - "type": "boolean", - "description": "Alias for library" - }, - "sub-app": { - "type": "boolean", - "description": "Generate spec file for sub-app schematics or not." - }, - "app": { - "type": "boolean", - "description": "Alias for sub-app" - }, - "resource": { - "type": "boolean", - "description": "Generate spec file for resource schematics or not." - }, - "res": { - "type": "boolean", - "description": "Alias for resource" + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "application": { + "type": "boolean", + "description": "Generate spec file for application schematics or not." + }, + "class": { + "type": "boolean", + "description": "Disable spec file generation for class schematics." + }, + "cl": { + "type": "boolean", + "description": "Alias for class" + }, + "configuration": { + "type": "boolean", + "description": "Generate spec file for configuration schematics or not." + }, + "config": { + "type": "boolean", + "description": "Alias for configuration" + }, + "controller": { + "type": "boolean", + "description": "Generate spec file for controller schematics or not." + }, + "co": { + "type": "boolean", + "description": "Alias for controller" + }, + "decorator": { + "type": "boolean", + "description": "Generate spec file for decorator schematics or not." + }, + "d": { + "type": "boolean", + "description": "Alias for decorator" + }, + "filter": { + "type": "boolean", + "description": "Generate spec file for filter schematics or not." + }, + "f": { + "type": "boolean", + "description": "Alias for filter" + }, + "gateway": { + "type": "boolean", + "description": "Generate spec file for gateway schematics or not." + }, + "ga": { + "type": "boolean", + "description": "Alias for gateway" + }, + "guard": { + "type": "boolean", + "description": "Generate spec file for guard schematics or not." + }, + "gu": { + "type": "boolean", + "description": "Alias for guard" + }, + "interceptor": { + "type": "boolean", + "description": "Generate spec file for interceptor schematics or not." + }, + "in": { + "type": "boolean", + "description": "Alias for interceptor" + }, + "interface": { + "type": "boolean", + "description": "Generate spec file for interface schematics or not." + }, + "middleware": { + "type": "boolean", + "description": "Generate spec file for middleware schematics or not." + }, + "mi": { + "type": "boolean", + "description": "Alias for middleware" + }, + "module": { + "type": "boolean", + "description": "Generate spec file for module schematics or not." + }, + "mo": { + "type": "boolean", + "description": "Alias for module" + }, + "pipe": { + "type": "boolean", + "description": "Generate spec file for pipe schematics or not." + }, + "pi": { + "type": "boolean", + "description": "Alias for pipe" + }, + "provider": { + "type": "boolean", + "description": "Generate spec file for provider schematics or not." + }, + "pr": { + "type": "boolean", + "description": "Alias for provider" + }, + "resolver": { + "type": "boolean", + "description": "Generate spec file for resolver schematics or not." + }, + "r": { + "type": "boolean", + "description": "Alias for resolver" + }, + "service": { + "type": "boolean", + "description": "Generate spec file for service schematics or not." + }, + "s": { + "type": "boolean", + "description": "Alias for resolver" + }, + "library": { + "type": "boolean", + "description": "Generate spec file for library schematics or not." + }, + "lib": { + "type": "boolean", + "description": "Alias for library" + }, + "sub-app": { + "type": "boolean", + "description": "Generate spec file for sub-app schematics or not." + }, + "app": { + "type": "boolean", + "description": "Alias for sub-app" + }, + "resource": { + "type": "boolean", + "description": "Generate spec file for resource schematics or not." + }, + "res": { + "type": "boolean", + "description": "Alias for resource" + } + }, + "additionalProperties": false } - }, - "additionalProperties": false + ] }, "GenerateBaseDirOptions": { "type": "string", @@ -373,26 +387,33 @@ }, "PluginItems": { "$comment": "https://docs.nestjs.com/openapi/cli-plugin#using-the-cli-plugin", - "type": ["string", "object"], - "properties": { - "name": { - "type": "string", - "description": "The npm package name of the cli plugin, eg @nestjs/swagger." + "oneOf": [ + { + "type": "string" }, - "options": { - "anyOf": [ - { - "$ref": "#/definitions/PluginOptions" - }, - { - "$ref": "#/definitions/GraphQLPluginOptions" + { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The npm package name of the cli plugin, eg @nestjs/swagger." }, - { - "$ref": "#/definitions/SwaggerPluginOptions" + "options": { + "anyOf": [ + { + "$ref": "#/definitions/PluginOptions" + }, + { + "$ref": "#/definitions/GraphQLPluginOptions" + }, + { + "$ref": "#/definitions/SwaggerPluginOptions" + } + ] } - ] + } } - } + ] }, "PluginOptions": { "type": "object", diff --git a/src/schemas/json/netlify.json b/src/schemas/json/netlify.json index eab4c2f055c..2a5fd36f2c7 100644 --- a/src/schemas/json/netlify.json +++ b/src/schemas/json/netlify.json @@ -3,6 +3,7 @@ "$id": "https://json.schemastore.org/netlify.json", "definitions": { "collectionItems": { + "type": "object", "properties": { "fields": { "$ref": "#/definitions/fields" @@ -77,9 +78,17 @@ "required": ["name"], "oneOf": [ { + "type": "object", + "properties": { + "files": {} + }, "required": ["files"] }, { + "type": "object", + "properties": { + "folder": {} + }, "required": ["folder"] } ] @@ -88,6 +97,7 @@ "type": "array", "description": "The fields option maps editor UI widgets to field-value pairs in the saved file. The order of the fields in your Netlify CMS config.yml file determines their order in the editor UI and in the saved file.", "items": { + "type": "object", "properties": { "name": { "type": "string", @@ -120,24 +130,33 @@ } }, "widget": { - "properties": { - "required": { - "type": "boolean", - "description": "Defaults to True" + "oneOf": [ + { + "type": "object", + "properties": { + "required": { + "type": "boolean", + "description": "Defaults to True" + }, + "hint": { + "description": "optionally add helper text directly below a widget.", + "type": "string" + }, + "pattern": { + "description": "add field validation by specifying a list with a regex pattern and an error message; more extensive validation can be achieved with custom widgets", + "type": "array" + } + } }, - "hint": { - "description": "optionally add helper text directly below a widget.", + { "type": "string" - }, - "pattern": { - "description": "add field validation by specifying a list with a regex pattern and an error message; more extensive validation can be achieved with custom widgets", - "type": "array" } - } + ] }, "files": { "type": "array", "items": { + "type": "object", "properties": { "name": { "description": "unique identifier for the file", diff --git a/src/schemas/json/nodemon.json b/src/schemas/json/nodemon.json index fc86fa987db..a94da20c451 100644 --- a/src/schemas/json/nodemon.json +++ b/src/schemas/json/nodemon.json @@ -54,6 +54,9 @@ }, "dependencies": { "pollingInterval": { + "properties": { + "legacyWatch": {} + }, "required": ["legacyWatch"] }, "nodeArgs": { diff --git a/src/schemas/json/openhab-5.1.json b/src/schemas/json/openhab-5.1.json index 7bcf8119392..9495c42a4ee 100644 --- a/src/schemas/json/openhab-5.1.json +++ b/src/schemas/json/openhab-5.1.json @@ -92,18 +92,32 @@ }, "allOf": [ { - "if": { "required": ["type"] }, + "if": { + "type": "object", + "properties": { "type": {} }, + "required": ["type"] + }, "then": { "not": { "anyOf": [ - { "required": ["kind"] }, - { "required": ["itemType"] } + { + "properties": { "kind": {} }, + "required": ["kind"] + }, + { + "properties": { "itemType": {} }, + "required": ["itemType"] + } ] } } }, { - "if": { "type": "object", "required": ["itemDimension"] }, + "if": { + "type": "object", + "properties": { "itemDimension": {} }, + "required": ["itemDimension"] + }, "then": { "properties": { "itemType": { "const": "Number" } } } @@ -115,7 +129,12 @@ "itemType": { "not": { "const": "Number" } } } }, - "then": { "not": { "required": ["itemDimension"] } } + "then": { + "not": { + "properties": { "itemDimension": {} }, + "required": ["itemDimension"] + } + } } ] } @@ -168,7 +187,13 @@ }, "allOf": [ { - "if": { "type": "object", "required": ["dimension"] }, + "if": { + "type": "object", + "properties": { + "dimension": {} + }, + "required": ["dimension"] + }, "then": { "properties": { "type": { "const": "Number" } } } }, { @@ -176,7 +201,12 @@ "type": "object", "properties": { "type": { "not": { "const": "Number" } } } }, - "then": { "not": { "required": ["dimension"] } } + "then": { + "not": { + "properties": { "dimension": {} }, + "required": ["dimension"] + } + } } ] }, @@ -221,7 +251,11 @@ }, "allOf": [ { - "if": { "type": "object", "required": ["dimension"] }, + "if": { + "type": "object", + "properties": { "dimension": {} }, + "required": ["dimension"] + }, "then": { "properties": { "type": { "const": "Number" } } } }, { @@ -229,10 +263,19 @@ "type": "object", "properties": { "type": { "not": { "const": "Number" } } } }, - "then": { "not": { "required": ["dimension"] } } + "then": { + "not": { + "properties": { "dimension": {} }, + "required": ["dimension"] + } + } }, { "not": { + "properties": { + "channel": {}, + "channels": {} + }, "required": ["channel", "channels"] } } diff --git a/src/schemas/json/opensrm.json b/src/schemas/json/opensrm.json index 6918db646bb..8020d55a660 100644 --- a/src/schemas/json/opensrm.json +++ b/src/schemas/json/opensrm.json @@ -83,11 +83,36 @@ } }, "anyOf": [ - { "required": ["p50"] }, - { "required": ["p90"] }, - { "required": ["p95"] }, - { "required": ["p99"] }, - { "required": ["p999"] } + { + "properties": { + "p50": {} + }, + "required": ["p50"] + }, + { + "properties": { + "p90": {} + }, + "required": ["p90"] + }, + { + "properties": { + "p95": {} + }, + "required": ["p95"] + }, + { + "properties": { + "p99": {} + }, + "required": ["p99"] + }, + { + "properties": { + "p999": {} + }, + "required": ["p999"] + } ] }, "ErrorRateSLO": { @@ -163,10 +188,30 @@ } }, "anyOf": [ - { "required": ["p50"] }, - { "required": ["p90"] }, - { "required": ["p95"] }, - { "required": ["p99"] } + { + "properties": { + "p50": {} + }, + "required": ["p50"] + }, + { + "properties": { + "p90": {} + }, + "required": ["p90"] + }, + { + "properties": { + "p95": {} + }, + "required": ["p95"] + }, + { + "properties": { + "p99": {} + }, + "required": ["p99"] + } ] }, "LagSLO": { @@ -241,10 +286,30 @@ } }, "anyOf": [ - { "required": ["p50"] }, - { "required": ["p90"] }, - { "required": ["p95"] }, - { "required": ["p99"] } + { + "properties": { + "p50": {} + }, + "required": ["p50"] + }, + { + "properties": { + "p90": {} + }, + "required": ["p90"] + }, + { + "properties": { + "p95": {} + }, + "required": ["p95"] + }, + { + "properties": { + "p99": {} + }, + "required": ["p99"] + } ] }, "ScheduleAdherenceSLO": { @@ -318,11 +383,36 @@ } }, "anyOf": [ - { "required": ["p50"] }, - { "required": ["p90"] }, - { "required": ["p95"] }, - { "required": ["p99"] }, - { "required": ["p999"] } + { + "properties": { + "p50": {} + }, + "required": ["p50"] + }, + { + "properties": { + "p90": {} + }, + "required": ["p90"] + }, + { + "properties": { + "p95": {} + }, + "required": ["p95"] + }, + { + "properties": { + "p99": {} + }, + "required": ["p99"] + }, + { + "properties": { + "p999": {} + }, + "required": ["p999"] + } ] }, "ReplicationLagSLO": { @@ -422,7 +512,20 @@ "type": "object", "description": "Feedback latency SLO - measures time until decision quality is known\nhttps://github.com/rsionnach/opensrm#judgment-slos", "additionalProperties": false, - "anyOf": [{ "required": ["p50"] }, { "required": ["p90"] }], + "anyOf": [ + { + "properties": { + "p50": {} + }, + "required": ["p50"] + }, + { + "properties": { + "p90": {} + }, + "required": ["p90"] + } + ], "properties": { "p50": { "$ref": "#/definitions/Duration", diff --git a/src/schemas/json/paper-plugin.json b/src/schemas/json/paper-plugin.json index 0e6cbc1aa62..052fa1edd14 100644 --- a/src/schemas/json/paper-plugin.json +++ b/src/schemas/json/paper-plugin.json @@ -122,17 +122,17 @@ "authors": { "type": "array", "description": "Main authors of the plugin", + "uniqueItems": true, "items": { - "type": "string", - "uniqueItems": true + "type": "string" } }, "contributors": { "type": "array", "description": "Other contributors to the plugin", + "uniqueItems": true, "items": { - "type": "string", - "uniqueItems": true + "type": "string" } }, "website": { @@ -153,6 +153,7 @@ }, "permissions": { "description": "Permissions for this plugin", + "type": "object", "additionalProperties": { "$ref": "#/definitions/permission" } diff --git a/src/schemas/json/partial-pyright.json b/src/schemas/json/partial-pyright.json index 6b749fa4bb0..f4343f21536 100644 --- a/src/schemas/json/partial-pyright.json +++ b/src/schemas/json/partial-pyright.json @@ -722,8 +722,16 @@ "x-intellij-html-description": "Set of identifiers that should be assumed to contain a constant value wherever used within this program. For example, { "DEBUG": true } indicates that pyright should assume that the identifier DEBUG will always be equal to True. If this identifier is used within a conditional expression (such as if not DEBUG:) pyright will use the indicated value to determine whether the guarded block is reachable or not. Member expressions that reference one of these constants (e.g. my_module.DEBUG) are also supported.", "properties": {}, "additionalProperties": { - "type": ["string", "boolean"], - "title": "Value of constant (boolean or string)" + "oneOf": [ + { + "type": "string", + "title": "Value of constant (boolean or string)" + }, + { + "type": "boolean", + "title": "Value of constant (boolean or string)" + } + ] } }, "typeCheckingMode": { diff --git a/src/schemas/json/phrase.json b/src/schemas/json/phrase.json index 9bb78a8e339..b09ca608099 100644 --- a/src/schemas/json/phrase.json +++ b/src/schemas/json/phrase.json @@ -1,6 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://json.schemastore.org/phrase.json", + "type": "object", "definitions": { "project_id": { "description": "ID of the project", diff --git a/src/schemas/json/pnpm-workspace.json b/src/schemas/json/pnpm-workspace.json index d790e59b0f2..3dd9b001c78 100644 --- a/src/schemas/json/pnpm-workspace.json +++ b/src/schemas/json/pnpm-workspace.json @@ -121,10 +121,8 @@ }, "catalog": { "$comment": "https://pnpm.io/catalogs", - "$ref": "#/definitions/dependency", "description": "Define dependency version ranges as reusable constants,\nfor later reference in package.json files.\nThis (singular) field creates a catalog named default.\n", - "type": ["object", "null"], - "minProperties": 1 + "anyOf": [{ "$ref": "#/definitions/dependency" }, { "type": "null" }] }, "catalogs": { "description": "Define arbitrarily named catalogs", @@ -781,8 +779,12 @@ "description": "This setting allows the checking of the state of dependencies before running scripts.", "oneOf": [ { - "type": ["string", "boolean"], - "enum": ["install", "warn", "error", "prompt", false] + "type": "string", + "enum": ["install", "warn", "error", "prompt"] + }, + { + "type": "boolean", + "enum": [false] } ] }, diff --git a/src/schemas/json/pre-commit-config.json b/src/schemas/json/pre-commit-config.json index 47327c90d59..84cf29e1496 100644 --- a/src/schemas/json/pre-commit-config.json +++ b/src/schemas/json/pre-commit-config.json @@ -42,6 +42,12 @@ "items": { "$ref": "#/definitions/hook_definition", "type": "object", + "properties": { + "id": {}, + "name": {}, + "entry": {}, + "language": {} + }, "required": ["id", "name", "entry", "language"] } } diff --git a/src/schemas/json/prometheus.json b/src/schemas/json/prometheus.json index 73f26127f20..a4b2939bf49 100644 --- a/src/schemas/json/prometheus.json +++ b/src/schemas/json/prometheus.json @@ -49,9 +49,15 @@ }, "oneOf": [ { + "properties": { + "password": {} + }, "required": ["password"] }, { + "properties": { + "password_file": {} + }, "required": ["password_file"] } ], @@ -78,9 +84,15 @@ }, "oneOf": [ { + "properties": { + "credentials": {} + }, "required": ["credentials"] }, { + "properties": { + "credentials_file": {} + }, "required": ["credentials_file"] } ], @@ -145,6 +157,7 @@ } }, "sdk": { + "type": "object", "properties": { "tenant_id": { "type": "string" @@ -200,9 +213,15 @@ }, "oneOf": [ { + "properties": { + "client_secret": {} + }, "required": ["client_secret"] }, { + "properties": { + "client_secret_file": {} + }, "required": ["client_secret_file"] } ], @@ -222,6 +241,7 @@ { "if": { "not": { + "type": "object", "properties": { "basic_auth": { "const": null @@ -230,6 +250,7 @@ } }, "then": { + "type": "object", "properties": { "authorization": { "const": null @@ -252,6 +273,7 @@ { "if": { "not": { + "type": "object", "properties": { "authorization": { "const": null @@ -260,6 +282,7 @@ } }, "then": { + "type": "object", "properties": { "basic_auth": { "const": null @@ -282,6 +305,7 @@ { "if": { "not": { + "type": "object", "properties": { "sigv4": { "const": null @@ -290,6 +314,7 @@ } }, "then": { + "type": "object", "properties": { "basic_auth": { "const": null @@ -312,6 +337,7 @@ { "if": { "not": { + "type": "object", "properties": { "oauth2": { "const": null @@ -320,6 +346,7 @@ } }, "then": { + "type": "object", "properties": { "basic_auth": { "const": null @@ -342,6 +369,7 @@ { "if": { "not": { + "type": "object", "properties": { "bearer_token": { "const": null @@ -350,6 +378,7 @@ } }, "then": { + "type": "object", "properties": { "basic_auth": { "const": null @@ -372,6 +401,7 @@ { "if": { "not": { + "type": "object", "properties": { "bearer_token_file": { "const": null @@ -380,6 +410,7 @@ } }, "then": { + "type": "object", "properties": { "basic_auth": { "const": null @@ -457,6 +488,7 @@ } }, "if": { + "type": "object", "properties": { "action": { "const": "replace" @@ -464,6 +496,9 @@ } }, "then": { + "properties": { + "target_label": {} + }, "required": ["target_label"] } } diff --git a/src/schemas/json/pylock.json b/src/schemas/json/pylock.json index 249fdbb8e85..664c454490b 100644 --- a/src/schemas/json/pylock.json +++ b/src/schemas/json/pylock.json @@ -164,6 +164,7 @@ } }, "1.0": { + "type": "object", "additionalProperties": false, "required": ["lock-version", "created-by", "packages"], "properties": { @@ -225,40 +226,82 @@ "allOf": [ { "if": { + "type": "object", + "properties": { + "vcs": {} + }, "required": ["vcs"] }, "then": { "not": { + "type": "object", + "properties": { + "directory": {}, + "archive": {}, + "sdist": {}, + "wheels": {} + }, "required": ["directory", "archive", "sdist", "wheels"] } } }, { "if": { + "type": "object", + "properties": { + "directory": {} + }, "required": ["directory"] }, "then": { "not": { + "type": "object", + "properties": { + "vcs": {}, + "archive": {}, + "sdist": {}, + "wheels": {} + }, "required": ["vcs", "archive", "sdist", "wheels"] } } }, { "if": { + "type": "object", + "properties": { + "sdist": {} + }, "required": ["sdist"] }, "then": { "not": { + "type": "object", + "properties": { + "vcs": {}, + "directory": {}, + "archive": {} + }, "required": ["vcs", "directory", "archive"] } } }, { "if": { + "type": "object", + "properties": { + "wheels": {} + }, "required": ["wheels"] }, "then": { "not": { + "type": "object", + "properties": { + "vcs": {}, + "directory": {}, + "archive": {} + }, "required": ["vcs", "directory", "archive"] } } diff --git a/src/schemas/json/pyproject.json b/src/schemas/json/pyproject.json index eb86382d753..ddbc9408c9f 100644 --- a/src/schemas/json/pyproject.json +++ b/src/schemas/json/pyproject.json @@ -742,11 +742,6 @@ "description": "Named groups of dependencies, similar to `requirements.txt` files, which launchers, IDEs, and other tools can find and identify by name. Each item in `[dependency-groups]` is defined as mapping of group name to list of [dependency specifiers](https://packaging.python.org/en/latest/specifications/dependency-specifiers/).", "markdownDescription": "Named groups of dependencies, similar to `requirements.txt` files, which launchers, IDEs, and other tools can find and identify by name. Each item in `[dependency-groups]` is defined as mapping of group name to list of [dependency specifiers](https://packaging.python.org/en/latest/specifications/dependency-specifiers/).", "type": "object", - "properties": { - "dev": { - "$ref": "#/definitions/DependencyGroup" - } - }, "patternProperties": { "^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9])$": { "$ref": "#/definitions/DependencyGroup" diff --git a/src/schemas/json/pyrseas-0.8.json b/src/schemas/json/pyrseas-0.8.json index 5e339fae427..9900e21a0b7 100644 --- a/src/schemas/json/pyrseas-0.8.json +++ b/src/schemas/json/pyrseas-0.8.json @@ -25,6 +25,7 @@ "additionalProperties": false, "properties": { "all": { + "type": "object", "additionalProperties": false, "properties": { "grantable": { @@ -39,6 +40,7 @@ "additionalProperties": false, "properties": { "insert": { + "type": "object", "additionalProperties": false, "properties": { "grantable": { @@ -53,6 +55,7 @@ "additionalProperties": false, "properties": { "delete": { + "type": "object", "additionalProperties": false, "properties": { "grantable": { @@ -67,6 +70,7 @@ "additionalProperties": false, "properties": { "select": { + "type": "object", "additionalProperties": false, "properties": { "grantable": { @@ -81,6 +85,7 @@ "additionalProperties": false, "properties": { "update": { + "type": "object", "additionalProperties": false, "properties": { "grantable": { @@ -95,6 +100,7 @@ "additionalProperties": false, "properties": { "truncate": { + "type": "object", "additionalProperties": false, "properties": { "grantable": { @@ -109,6 +115,7 @@ "additionalProperties": false, "properties": { "references": { + "type": "object", "additionalProperties": false, "properties": { "grantable": { @@ -123,6 +130,7 @@ "additionalProperties": false, "properties": { "trigger": { + "type": "object", "additionalProperties": false, "properties": { "grantable": { @@ -137,6 +145,7 @@ "additionalProperties": false, "properties": { "usage": { + "type": "object", "additionalProperties": false, "properties": { "grantable": { @@ -151,6 +160,7 @@ "additionalProperties": false, "properties": { "execute": { + "type": "object", "additionalProperties": false, "properties": { "grantable": { @@ -165,6 +175,7 @@ "additionalProperties": false, "properties": { "create": { + "type": "object", "additionalProperties": false, "properties": { "grantable": { diff --git a/src/schemas/json/size-limit.json b/src/schemas/json/size-limit.json index a42a3600a55..7e95074ee4b 100644 --- a/src/schemas/json/size-limit.json +++ b/src/schemas/json/size-limit.json @@ -116,6 +116,7 @@ { "if": { "not": { + "type": "object", "properties": { "webpack": { "type": "boolean", @@ -125,6 +126,7 @@ } }, "then": { + "type": "object", "properties": { "config": { "title": "a path to a custom webpack config.", diff --git a/src/schemas/json/starlake.json b/src/schemas/json/starlake.json index cc6eebadffe..9a1657b0499 100644 --- a/src/schemas/json/starlake.json +++ b/src/schemas/json/starlake.json @@ -1614,6 +1614,7 @@ "$ref": "#/definitions/JDBCSchemaBase" }, { + "type": "object", "properties": { "tables": { "type": "array", @@ -1640,6 +1641,7 @@ "$ref": "#/definitions/ExtractV1Base" }, { + "type": "object", "properties": { "jdbcSchemas": { "description": "Describe what to fetch from a database connection. Scope: Schema and Data extraction.", @@ -1662,7 +1664,20 @@ } }, "not": { - "anyOf": [{ "required": ["openAPI"] }, { "required": ["restAPI"] }] + "anyOf": [ + { + "properties": { + "openAPI": {} + }, + "required": ["openAPI"] + }, + { + "properties": { + "restAPI": {} + }, + "required": ["restAPI"] + } + ] } } ] @@ -1832,6 +1847,7 @@ "$ref": "#/definitions/ExtractV1Base" }, { + "type": "object", "properties": { "openAPI": { "$ref": "#/definitions/OpenAPIV1", @@ -2168,6 +2184,7 @@ "$ref": "#/definitions/ExtractV1Base" }, { + "type": "object", "properties": { "restAPI": { "$ref": "#/definitions/RestAPIV1", @@ -2254,6 +2271,7 @@ "required": ["input", "output"] }, "KafkaTopicConfigV1": { + "type": "object", "properties": { "topicName": { "$ref": "#/definitions/ConvertibleToString", @@ -2772,36 +2790,69 @@ }, "oneOf": [ { + "properties": { + "extract": {} + }, "required": ["extract"] }, { + "properties": { + "load": {} + }, "required": ["load"] }, { + "properties": { + "transform": {} + }, "required": ["transform"] }, { + "properties": { + "env": {} + }, "required": ["env"] }, { + "properties": { + "types": {} + }, "required": ["types"] }, { + "properties": { + "tables": {} + }, "required": ["tables"] }, { + "properties": { + "table": {} + }, "required": ["table"] }, { + "properties": { + "task": {} + }, "required": ["task"] }, { + "properties": { + "application": {} + }, "required": ["application"] }, { + "properties": { + "refs": {} + }, "required": ["refs"] }, { + "properties": { + "dag": {} + }, "required": ["dag"] } ] diff --git a/src/schemas/json/tmlanguage.json b/src/schemas/json/tmlanguage.json index d7ad91fd2a6..55b2ca65f07 100644 --- a/src/schemas/json/tmlanguage.json +++ b/src/schemas/json/tmlanguage.json @@ -161,9 +161,17 @@ "begin": { "anyOf": [ { + "type": "object", + "properties": { + "end": {} + }, "required": ["end"] }, { + "type": "object", + "properties": { + "while": {} + }, "required": ["while"] } ] @@ -173,9 +181,19 @@ "contentName": { "anyOf": [ { + "type": "object", + "properties": { + "begin": {}, + "end": {} + }, "required": ["begin", "end"] }, { + "type": "object", + "properties": { + "begin": {}, + "while": {} + }, "required": ["begin", "while"] } ] @@ -183,9 +201,19 @@ "beginCaptures": { "anyOf": [ { + "type": "object", + "properties": { + "begin": {}, + "end": {} + }, "required": ["begin", "end"] }, { + "type": "object", + "properties": { + "begin": {}, + "while": {} + }, "required": ["begin", "while"] } ] diff --git a/src/schemas/json/utam-page-object-1.5.0.json b/src/schemas/json/utam-page-object-1.5.0.json index 2e934843c6a..49921bcb8ae 100644 --- a/src/schemas/json/utam-page-object-1.5.0.json +++ b/src/schemas/json/utam-page-object-1.5.0.json @@ -1,11 +1,13 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://json.schemastore.org/utam-page-object.json", + "$id": "https://json.schemastore.org/utam-page-object-1.5.0.json", "allOf": [ { "if": { + "type": "object", "properties": { "interface": { + "type": "boolean", "const": false } } @@ -16,8 +18,10 @@ }, { "if": { + "type": "object", "properties": { "interface": { + "type": "boolean", "const": true } }, @@ -77,21 +81,16 @@ "beforeLoad": { "title": "Preload Criteria", "description": "The beforeLoad array sets the criteria to be satisfied before the load method completes. If you don't specify a beforeLoad array, the load method finds a root element for a regular page object, or waits for the root element to be present for a root page object), by default.", - "type": ["array"], + "type": "array", "items": { - "allOf": [ - { - "$ref": "#/definitions/predicateStatement" - }, - { - "properties": { - "element": { - "type": "string", - "enum": ["document", "root"] - } - } + "$ref": "#/definitions/predicateStatement", + "type": "object", + "properties": { + "element": { + "type": "string", + "enum": ["document", "root"] } - ] + } } }, "elements": { @@ -167,16 +166,21 @@ "type": "string" }, "type": { - "type": ["string", "array"], - "items": [ + "anyOf": [ { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } } ] }, @@ -378,16 +382,21 @@ } }, "returnType": { - "type": ["string", "array"], - "items": [ + "anyOf": [ { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } } ] }, @@ -446,7 +455,23 @@ "type": "string" }, "applyExternal": { - "type": "object" + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "invoke": { + "type": "string" + }, + "args": { + "type": "array", + "items": { + "$ref": "#/definitions/arg" + } + } + }, + "required": ["type", "invoke"], + "additionalProperties": false }, "args": { "type": "array", @@ -470,50 +495,24 @@ "default": false } }, - "allOf": [ - { - "if": { - "required": ["apply"] - }, - "then": { - "not": { - "required": ["applyExternal"] - } + "dependencies": { + "apply": { + "not": { + "properties": { + "applyExternal": true + }, + "required": ["applyExternal"] } }, - { - "if": { - "required": ["applyExternal"] - }, - "then": { + "applyExternal": { + "not": { "properties": { - "applyExternal": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "invoke": { - "type": "string" - }, - "args": { - "type": "array", - "items": { - "$ref": "#/definitions/arg" - } - } - }, - "required": ["type", "invoke"], - "additionalProperties": false - } + "apply": true }, - "required": ["applyExternal"], - "not": { - "required": ["apply"] - } + "required": ["apply"] } } - ] + } }, "arg": { "type": "object", @@ -537,7 +536,23 @@ ] }, "value": { - "type": ["integer", "string", "boolean", "number", "object"] + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "object" + } + ] }, "predicate": { "type": "array" @@ -570,7 +585,7 @@ ] }, "name": { - "type": ["string"] + "type": "string" } }, "required": ["type", "name"] @@ -589,7 +604,16 @@ "value": { "anyOf": [ { - "type": ["integer", "string", "boolean", "number"] + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" }, { "$ref": "#/definitions/selector", @@ -613,7 +637,7 @@ "type": "string" }, "predicate": { - "type": ["array"], + "type": "array", "items": { "$ref": "#/definitions/predicateStatement" } @@ -639,16 +663,21 @@ "type": "string" }, "type": { - "type": ["string", "array"], - "items": [ + "anyOf": [ { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } } ] }, @@ -680,47 +709,61 @@ "rootDescription": { "title": "Root element description", "description": "summary of the functionality and use cases", - "type": ["object", "string"], - "properties": { - "text": { - "type": "array", - "items": { - "type": "string" - } - }, - "author": { + "anyOf": [ + { "type": "string" }, - "deprecated": { - "type": "string" + { + "type": "object", + "properties": { + "text": { + "type": "array", + "items": { + "type": "string" + } + }, + "author": { + "type": "string" + }, + "deprecated": { + "type": "string" + } + }, + "required": ["text"], + "additionalProperties": false } - }, - "required": ["text"], - "additionalProperties": false + ] }, "methodDescription": { "title": "Method description", "description": "summary at the method or element level", - "type": ["object", "string"], - "properties": { - "text": { - "type": "array", - "items": { - "type": "string" - } - }, - "return": { - "type": "string" - }, - "throws": { + "anyOf": [ + { "type": "string" }, - "deprecated": { - "type": "string" + { + "type": "object", + "properties": { + "text": { + "type": "array", + "items": { + "type": "string" + } + }, + "return": { + "type": "string" + }, + "throws": { + "type": "string" + }, + "deprecated": { + "type": "string" + } + }, + "required": ["text"], + "additionalProperties": false } - }, - "required": ["text"], - "additionalProperties": false + ] } }, "properties": { diff --git a/src/schemas/json/utam-page-object-2.0.3.json b/src/schemas/json/utam-page-object-2.0.3.json index de932560d10..424a1c4372c 100644 --- a/src/schemas/json/utam-page-object-2.0.3.json +++ b/src/schemas/json/utam-page-object-2.0.3.json @@ -1,9 +1,10 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://json.schemastore.org/utam-page-object.json", + "$id": "https://json.schemastore.org/utam-page-object-2.0.3.json", "allOf": [ { "if": { + "type": "object", "properties": { "interface": { "const": false @@ -16,6 +17,7 @@ }, { "if": { + "type": "object", "properties": { "interface": { "const": true @@ -77,21 +79,16 @@ "beforeLoad": { "title": "Preload Criteria", "description": "The beforeLoad array sets the criteria to be satisfied before the load method completes. If you don't specify a beforeLoad array, the load method finds a root element for a regular page object, or waits for the root element to be present for a root page object), by default.", - "type": ["array"], + "type": "array", "items": { - "allOf": [ - { - "$ref": "#/definitions/predicateStatement" - }, - { - "properties": { - "element": { - "type": "string", - "enum": ["document", "root", "navigation"] - } - } + "$ref": "#/definitions/predicateStatement", + "type": "object", + "properties": { + "element": { + "type": "string", + "enum": ["document", "root", "navigation"] } - ] + } } }, "elements": { @@ -173,16 +170,21 @@ "type": "string" }, "type": { - "type": ["string", "array"], - "items": [ + "anyOf": [ { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } } ] }, @@ -384,16 +386,21 @@ } }, "returnType": { - "type": ["string", "array"], - "items": [ + "anyOf": [ { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } } ] }, @@ -452,7 +459,23 @@ "type": "string" }, "applyExternal": { - "type": "object" + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "invoke": { + "type": "string" + }, + "args": { + "type": "array", + "items": { + "$ref": "#/definitions/arg" + } + } + }, + "required": ["type", "invoke"], + "additionalProperties": false }, "args": { "type": "array", @@ -476,50 +499,24 @@ "default": false } }, - "allOf": [ - { - "if": { - "required": ["apply"] - }, - "then": { - "not": { - "required": ["applyExternal"] - } + "dependencies": { + "apply": { + "not": { + "properties": { + "applyExternal": true + }, + "required": ["applyExternal"] } }, - { - "if": { - "required": ["applyExternal"] - }, - "then": { + "applyExternal": { + "not": { "properties": { - "applyExternal": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "invoke": { - "type": "string" - }, - "args": { - "type": "array", - "items": { - "$ref": "#/definitions/arg" - } - } - }, - "required": ["type", "invoke"], - "additionalProperties": false - } + "apply": true }, - "required": ["applyExternal"], - "not": { - "required": ["apply"] - } + "required": ["apply"] } } - ] + } }, "arg": { "type": "object", @@ -543,7 +540,23 @@ ] }, "value": { - "type": ["integer", "string", "boolean", "number", "object"] + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "object" + } + ] }, "predicate": { "type": "array" @@ -576,7 +589,7 @@ ] }, "name": { - "type": ["string"] + "type": "string" } }, "required": ["type", "name"] @@ -595,7 +608,16 @@ "value": { "anyOf": [ { - "type": ["integer", "string", "boolean", "number"] + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" }, { "$ref": "#/definitions/selector", @@ -619,7 +641,7 @@ "type": "string" }, "predicate": { - "type": ["array"], + "type": "array", "items": { "$ref": "#/definitions/predicateStatement" } @@ -645,16 +667,21 @@ "type": "string" }, "type": { - "type": ["string", "array"], - "items": [ + "anyOf": [ { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } } ] }, @@ -686,28 +713,35 @@ "rootDescription": { "title": "Root element description", "description": "summary of the functionality and use cases", - "type": ["object", "string"], - "properties": { - "text": { - "type": "array", - "items": { - "type": "string" - } - }, - "author": { + "anyOf": [ + { "type": "string" }, - "deprecated": { - "type": "string" + { + "type": "object", + "properties": { + "text": { + "type": "array", + "items": { + "type": "string" + } + }, + "author": { + "type": "string" + }, + "deprecated": { + "type": "string" + } + }, + "required": ["text"], + "additionalProperties": false } - }, - "required": ["text"], - "additionalProperties": false + ] }, "metadata": { "title": "Page Object Metadata", "description": "track miscellaneous information for the page object", - "type": ["object"], + "type": "object", "properties": { "status": { "type": "string" @@ -721,26 +755,33 @@ "methodDescription": { "title": "Method description", "description": "summary at the method or element level", - "type": ["object", "string"], - "properties": { - "text": { - "type": "array", - "items": { - "type": "string" - } - }, - "return": { - "type": "string" - }, - "throws": { + "anyOf": [ + { "type": "string" }, - "deprecated": { - "type": "string" + { + "type": "object", + "properties": { + "text": { + "type": "array", + "items": { + "type": "string" + } + }, + "return": { + "type": "string" + }, + "throws": { + "type": "string" + }, + "deprecated": { + "type": "string" + } + }, + "required": ["text"], + "additionalProperties": false } - }, - "required": ["text"], - "additionalProperties": false + ] } }, "properties": { diff --git a/src/schemas/json/utam-page-object-2.2.0.json b/src/schemas/json/utam-page-object-2.2.0.json index 8114b6eed64..8c4b262d673 100644 --- a/src/schemas/json/utam-page-object-2.2.0.json +++ b/src/schemas/json/utam-page-object-2.2.0.json @@ -1,9 +1,10 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://json.schemastore.org/utam-page-object.json", + "$id": "https://json.schemastore.org/utam-page-object-2.2.0.json", "allOf": [ { "if": { + "type": "object", "properties": { "interface": { "const": false @@ -16,6 +17,7 @@ }, { "if": { + "type": "object", "properties": { "interface": { "const": true @@ -77,21 +79,16 @@ "beforeLoad": { "title": "Preload Criteria", "description": "The beforeLoad array sets the criteria to be satisfied before the load method completes. If you don't specify a beforeLoad array, the load method finds a root element for a regular page object, or waits for the root element to be present for a root page object), by default.", - "type": ["array"], + "type": "array", "items": { - "allOf": [ - { - "$ref": "#/definitions/predicateStatement" - }, - { - "properties": { - "element": { - "type": "string", - "enum": ["document", "root", "navigation"] - } - } + "$ref": "#/definitions/predicateStatement", + "type": "object", + "properties": { + "element": { + "type": "string", + "enum": ["document", "root", "navigation"] } - ] + } } }, "elements": { @@ -173,16 +170,23 @@ "type": "string" }, "type": { - "type": ["string", "array"], - "items": { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] - } + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } + } + ] }, "selector": { "$ref": "#/definitions/selector" @@ -382,16 +386,23 @@ } }, "returnType": { - "type": ["string", "array"], - "items": { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] - } + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } + } + ] }, "returnAll": { "type": "boolean", @@ -448,7 +459,23 @@ "type": "string" }, "applyExternal": { - "type": "object" + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "invoke": { + "type": "string" + }, + "args": { + "type": "array", + "items": { + "$ref": "#/definitions/arg" + } + } + }, + "required": ["type", "invoke"], + "additionalProperties": false }, "args": { "type": "array", @@ -472,50 +499,24 @@ "default": false } }, - "allOf": [ - { - "if": { - "required": ["apply"] - }, - "then": { - "not": { - "required": ["applyExternal"] - } + "dependencies": { + "apply": { + "not": { + "properties": { + "applyExternal": true + }, + "required": ["applyExternal"] } }, - { - "if": { - "required": ["applyExternal"] - }, - "then": { + "applyExternal": { + "not": { "properties": { - "applyExternal": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "invoke": { - "type": "string" - }, - "args": { - "type": "array", - "items": { - "$ref": "#/definitions/arg" - } - } - }, - "required": ["type", "invoke"], - "additionalProperties": false - } + "apply": true }, - "required": ["applyExternal"], - "not": { - "required": ["apply"] - } + "required": ["apply"] } } - ] + } }, "arg": { "type": "object", @@ -539,7 +540,23 @@ ] }, "value": { - "type": ["integer", "string", "boolean", "number", "object"] + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "object" + } + ] }, "predicate": { "type": "array" @@ -572,7 +589,7 @@ ] }, "name": { - "type": ["string"] + "type": "string" } }, "required": ["type", "name"] @@ -591,7 +608,16 @@ "value": { "anyOf": [ { - "type": ["integer", "string", "boolean", "number"] + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" }, { "$ref": "#/definitions/selector", @@ -615,7 +641,7 @@ "type": "string" }, "predicate": { - "type": ["array"], + "type": "array", "items": { "$ref": "#/definitions/predicateStatement" } @@ -641,16 +667,23 @@ "type": "string" }, "type": { - "type": ["string", "array"], - "items": { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] - } + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } + } + ] }, "shadow": { "type": "object", @@ -680,28 +713,35 @@ "rootDescription": { "title": "Root element description", "description": "summary of the functionality and use cases", - "type": ["object", "string"], - "properties": { - "text": { - "type": "array", - "items": { - "type": "string" - } - }, - "author": { + "anyOf": [ + { "type": "string" }, - "deprecated": { - "type": "string" + { + "type": "object", + "properties": { + "text": { + "type": "array", + "items": { + "type": "string" + } + }, + "author": { + "type": "string" + }, + "deprecated": { + "type": "string" + } + }, + "required": ["text"], + "additionalProperties": false } - }, - "required": ["text"], - "additionalProperties": false + ] }, "metadata": { "title": "Page Object Metadata", "description": "track miscellaneous information for the page object", - "type": ["object"], + "type": "object", "properties": { "status": { "type": "string" @@ -715,26 +755,33 @@ "methodDescription": { "title": "Method description", "description": "summary at the method or element level", - "type": ["object", "string"], - "properties": { - "text": { - "type": "array", - "items": { - "type": "string" - } - }, - "return": { - "type": "string" - }, - "throws": { + "anyOf": [ + { "type": "string" }, - "deprecated": { - "type": "string" + { + "type": "object", + "properties": { + "text": { + "type": "array", + "items": { + "type": "string" + } + }, + "return": { + "type": "string" + }, + "throws": { + "type": "string" + }, + "deprecated": { + "type": "string" + } + }, + "required": ["text"], + "additionalProperties": false } - }, - "required": ["text"], - "additionalProperties": false + ] } }, "properties": { diff --git a/src/schemas/json/utam-page-object.json b/src/schemas/json/utam-page-object.json index 73689c452d2..823af1301b8 100644 --- a/src/schemas/json/utam-page-object.json +++ b/src/schemas/json/utam-page-object.json @@ -4,6 +4,7 @@ "allOf": [ { "if": { + "type": "object", "properties": { "interface": { "const": false @@ -16,6 +17,7 @@ }, { "if": { + "type": "object", "properties": { "interface": { "const": true @@ -77,21 +79,16 @@ "beforeLoad": { "title": "Preload Criteria", "description": "The beforeLoad array sets the criteria to be satisfied before the load method completes. If you don't specify a beforeLoad array, the load method finds a root element for a regular page object, or waits for the root element to be present for a root page object), by default.", - "type": ["array"], + "type": "array", "items": { - "allOf": [ - { - "$ref": "#/definitions/predicateStatement" - }, - { - "properties": { - "element": { - "type": "string", - "enum": ["document", "root", "navigation"] - } - } + "$ref": "#/definitions/predicateStatement", + "type": "object", + "properties": { + "element": { + "type": "string", + "enum": ["document", "root", "navigation"] } - ] + } } }, "elements": { @@ -173,16 +170,21 @@ "type": "string" }, "type": { - "type": ["string", "array"], - "items": [ + "anyOf": [ { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } } ] }, @@ -392,16 +394,21 @@ } }, "returnType": { - "type": ["string", "array"], - "items": [ + "anyOf": [ { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } } ] }, @@ -460,7 +467,23 @@ "type": "string" }, "applyExternal": { - "type": "object" + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "invoke": { + "type": "string" + }, + "args": { + "type": "array", + "items": { + "$ref": "#/definitions/arg" + } + } + }, + "required": ["type", "invoke"], + "additionalProperties": false }, "args": { "type": "array", @@ -484,50 +507,24 @@ "default": false } }, - "allOf": [ - { - "if": { - "required": ["apply"] - }, - "then": { - "not": { - "required": ["applyExternal"] - } + "dependencies": { + "apply": { + "not": { + "properties": { + "applyExternal": true + }, + "required": ["applyExternal"] } }, - { - "if": { - "required": ["applyExternal"] - }, - "then": { + "applyExternal": { + "not": { "properties": { - "applyExternal": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "invoke": { - "type": "string" - }, - "args": { - "type": "array", - "items": { - "$ref": "#/definitions/arg" - } - } - }, - "required": ["type", "invoke"], - "additionalProperties": false - } + "apply": true }, - "required": ["applyExternal"], - "not": { - "required": ["apply"] - } + "required": ["apply"] } } - ] + } }, "arg": { "type": "object", @@ -551,7 +548,23 @@ ] }, "value": { - "type": ["integer", "string", "boolean", "number", "object"] + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" + }, + { + "type": "object" + } + ] }, "predicate": { "type": "array" @@ -584,7 +597,7 @@ ] }, "name": { - "type": ["string"] + "type": "string" } }, "required": ["type", "name"] @@ -603,7 +616,16 @@ "value": { "anyOf": [ { - "type": ["integer", "string", "boolean", "number"] + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + }, + { + "type": "number" }, { "$ref": "#/definitions/selector", @@ -627,7 +649,7 @@ "type": "string" }, "predicate": { - "type": ["array"], + "type": "array", "items": { "$ref": "#/definitions/predicateStatement" } @@ -653,16 +675,21 @@ "type": "string" }, "type": { - "type": ["string", "array"], - "items": [ + "anyOf": [ { - "enum": [ - "actionable", - "clickable", - "editable", - "draggable", - "touchable" - ] + "type": "string" + }, + { + "type": "array", + "items": { + "enum": [ + "actionable", + "clickable", + "editable", + "draggable", + "touchable" + ] + } } ] }, @@ -694,28 +721,35 @@ "rootDescription": { "title": "Root element description", "description": "summary of the functionality and use cases", - "type": ["object", "string"], - "properties": { - "text": { - "type": "array", - "items": { - "type": "string" - } - }, - "author": { + "anyOf": [ + { "type": "string" }, - "deprecated": { - "type": "string" + { + "type": "object", + "properties": { + "text": { + "type": "array", + "items": { + "type": "string" + } + }, + "author": { + "type": "string" + }, + "deprecated": { + "type": "string" + } + }, + "required": ["text"], + "additionalProperties": false } - }, - "required": ["text"], - "additionalProperties": false + ] }, "metadata": { "title": "Page Object Metadata", "description": "track miscellaneous information for the page object", - "type": ["object"], + "type": "object", "properties": { "status": { "type": "string" @@ -729,26 +763,33 @@ "methodDescription": { "title": "Method description", "description": "summary at the method or element level", - "type": ["object", "string"], - "properties": { - "text": { - "type": "array", - "items": { - "type": "string" - } - }, - "return": { - "type": "string" - }, - "throws": { + "anyOf": [ + { "type": "string" }, - "deprecated": { - "type": "string" + { + "type": "object", + "properties": { + "text": { + "type": "array", + "items": { + "type": "string" + } + }, + "return": { + "type": "string" + }, + "throws": { + "type": "string" + }, + "deprecated": { + "type": "string" + } + }, + "required": ["text"], + "additionalProperties": false } - }, - "required": ["text"], - "additionalProperties": false + ] } }, "properties": { diff --git a/src/schemas/json/vtesttree-schema-v2.1.0.json b/src/schemas/json/vtesttree-schema-v2.1.0.json index 7cb51749e14..4a8f6363ada 100644 --- a/src/schemas/json/vtesttree-schema-v2.1.0.json +++ b/src/schemas/json/vtesttree-schema-v2.1.0.json @@ -306,11 +306,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-completion": true + }, "required": ["dotnet-completion"] } }, { "not": { + "properties": { + "python-completion": true + }, "required": ["python-completion"] } } @@ -320,11 +326,17 @@ "allOf": [ { "not": { + "properties": { + "capl-completion": true + }, "required": ["capl-completion"] } }, { "not": { + "properties": { + "python-completion": true + }, "required": ["python-completion"] } } @@ -334,11 +346,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-completion": true + }, "required": ["dotnet-completion"] } }, { "not": { + "properties": { + "capl-completion": true + }, "required": ["capl-completion"] } } @@ -348,11 +366,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-preparation": true + }, "required": ["dotnet-preparation"] } }, { "not": { + "properties": { + "python-preparation": true + }, "required": ["python-preparation"] } } @@ -362,11 +386,17 @@ "allOf": [ { "not": { + "properties": { + "capl-preparation": true + }, "required": ["capl-preparation"] } }, { "not": { + "properties": { + "python-preparation": true + }, "required": ["python-preparation"] } } @@ -376,11 +406,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-preparation": true + }, "required": ["dotnet-preparation"] } }, { "not": { + "properties": { + "capl-preparation": true + }, "required": ["capl-preparation"] } } diff --git a/src/schemas/json/vtesttree-schema-v2.2.0.json b/src/schemas/json/vtesttree-schema-v2.2.0.json index 867af8081f8..354037b2d74 100644 --- a/src/schemas/json/vtesttree-schema-v2.2.0.json +++ b/src/schemas/json/vtesttree-schema-v2.2.0.json @@ -327,11 +327,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-completion": true + }, "required": ["dotnet-completion"] } }, { "not": { + "properties": { + "python-completion": true + }, "required": ["python-completion"] } } @@ -341,11 +347,17 @@ "allOf": [ { "not": { + "properties": { + "capl-completion": true + }, "required": ["capl-completion"] } }, { "not": { + "properties": { + "python-completion": true + }, "required": ["python-completion"] } } @@ -355,11 +367,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-completion": true + }, "required": ["dotnet-completion"] } }, { "not": { + "properties": { + "capl-completion": true + }, "required": ["capl-completion"] } } @@ -369,11 +387,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-preparation": true + }, "required": ["dotnet-preparation"] } }, { "not": { + "properties": { + "python-preparation": true + }, "required": ["python-preparation"] } } @@ -383,11 +407,17 @@ "allOf": [ { "not": { + "properties": { + "capl-preparation": true + }, "required": ["capl-preparation"] } }, { "not": { + "properties": { + "python-preparation": true + }, "required": ["python-preparation"] } } @@ -397,11 +427,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-preparation": true + }, "required": ["dotnet-preparation"] } }, { "not": { + "properties": { + "capl-preparation": true + }, "required": ["capl-preparation"] } } diff --git a/src/schemas/json/vtesttree-schema-v2.3.0.json b/src/schemas/json/vtesttree-schema-v2.3.0.json index 3df5181d34f..4a59644c135 100644 --- a/src/schemas/json/vtesttree-schema-v2.3.0.json +++ b/src/schemas/json/vtesttree-schema-v2.3.0.json @@ -239,11 +239,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-completion": true + }, "required": ["dotnet-completion"] } }, { "not": { + "properties": { + "python-completion": true + }, "required": ["python-completion"] } } @@ -253,11 +259,17 @@ "allOf": [ { "not": { + "properties": { + "capl-completion": true + }, "required": ["capl-completion"] } }, { "not": { + "properties": { + "python-completion": true + }, "required": ["python-completion"] } } @@ -267,11 +279,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-completion": true + }, "required": ["dotnet-completion"] } }, { "not": { + "properties": { + "capl-completion": true + }, "required": ["capl-completion"] } } @@ -281,11 +299,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-preparation": true + }, "required": ["dotnet-preparation"] } }, { "not": { + "properties": { + "python-preparation": true + }, "required": ["python-preparation"] } } @@ -295,11 +319,17 @@ "allOf": [ { "not": { + "properties": { + "capl-preparation": true + }, "required": ["capl-preparation"] } }, { "not": { + "properties": { + "python-preparation": true + }, "required": ["python-preparation"] } } @@ -309,11 +339,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-preparation": true + }, "required": ["dotnet-preparation"] } }, { "not": { + "properties": { + "capl-preparation": true + }, "required": ["capl-preparation"] } } diff --git a/src/schemas/json/vtesttree-schema-v2.4.0.json b/src/schemas/json/vtesttree-schema-v2.4.0.json index 1920b1c1685..ee9e21fa116 100644 --- a/src/schemas/json/vtesttree-schema-v2.4.0.json +++ b/src/schemas/json/vtesttree-schema-v2.4.0.json @@ -64,29 +64,12 @@ "a3b17": { "full": { "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/param-values-vectors-combinatorics", "additionalProperties": false, "description": "Definition of calls to a CAPL test case with a list of parameter combinations.", "required": ["capl-test-case-list"], "title": "CAPL test case list", "type": "object", - "not": { - "anyOf": [ - { - "required": ["param-values", "param-vectors"] - }, - { - "required": ["combinatorics", "param-vectors"] - } - ] - }, - "oneOf": [ - { - "required": ["param-values"] - }, - { - "required": ["param-vectors"] - } - ], "properties": { "capl-test-case-list": { "type": "string", @@ -156,6 +139,7 @@ "a828f": { "full": { "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/param-values-vectors-combinatorics", "title": ".NET test case list", "description": "Definition of calls to a .NET test case with a list of parameter combinations.", "type": "object", @@ -190,24 +174,6 @@ "param-vectors": { "$ref": "#/definitions/fe80e/full" } - }, - "oneOf": [ - { - "required": ["param-values"] - }, - { - "required": ["param-vectors"] - } - ], - "not": { - "anyOf": [ - { - "required": ["param-values", "param-vectors"] - }, - { - "required": ["combinatorics", "param-vectors"] - } - ] } } }, @@ -237,9 +203,38 @@ } } }, + "param-values-vectors-combinatorics": { + "type": "object", + "not": { + "properties": { + "combinatorics": true, + "param-vectors": true + }, + "required": ["combinatorics", "param-vectors"] + }, + "oneOf": [ + { + "not": { + "properties": { + "param-values": true + }, + "required": ["param-values"] + } + }, + { + "not": { + "properties": { + "param-vectors": true + }, + "required": ["param-vectors"] + } + } + ] + }, "c1632": { "full": { "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/param-values-vectors-combinatorics", "title": ".NET test sequence list", "description": "Definition of calls to a .NET test sequence with a list of parameter combinations.", "type": "object", @@ -270,24 +265,6 @@ "param-vectors": { "$ref": "#/definitions/fe80e/full" } - }, - "oneOf": [ - { - "required": ["param-values"] - }, - { - "required": ["param-vectors"] - } - ], - "not": { - "anyOf": [ - { - "required": ["param-values", "param-vectors"] - }, - { - "required": ["combinatorics", "param-vectors"] - } - ] } } }, @@ -375,11 +352,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-completion": true + }, "required": ["dotnet-completion"] } }, { "not": { + "properties": { + "python-completion": true + }, "required": ["python-completion"] } } @@ -389,11 +372,17 @@ "allOf": [ { "not": { + "properties": { + "capl-completion": true + }, "required": ["capl-completion"] } }, { "not": { + "properties": { + "python-completion": true + }, "required": ["python-completion"] } } @@ -403,11 +392,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-completion": true + }, "required": ["dotnet-completion"] } }, { "not": { + "properties": { + "capl-completion": true + }, "required": ["capl-completion"] } } @@ -417,11 +412,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-preparation": true + }, "required": ["dotnet-preparation"] } }, { "not": { + "properties": { + "python-preparation": true + }, "required": ["python-preparation"] } } @@ -431,11 +432,17 @@ "allOf": [ { "not": { + "properties": { + "capl-preparation": true + }, "required": ["capl-preparation"] } }, { "not": { + "properties": { + "python-preparation": true + }, "required": ["python-preparation"] } } @@ -445,11 +452,17 @@ "allOf": [ { "not": { + "properties": { + "dotnet-preparation": true + }, "required": ["dotnet-preparation"] } }, { "not": { + "properties": { + "capl-preparation": true + }, "required": ["capl-preparation"] } } @@ -587,6 +600,7 @@ "61082": { "full": { "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/param-values-vectors-combinatorics", "title": "CAPL test sequence list", "description": "Definition of calls to a CAPL test sequence with a list of parameter combinations.", "type": "object", @@ -617,30 +631,13 @@ "param-vectors": { "$ref": "#/definitions/fe80e/full" } - }, - "oneOf": [ - { - "required": ["param-values"] - }, - { - "required": ["param-vectors"] - } - ], - "not": { - "anyOf": [ - { - "required": ["param-values", "param-vectors"] - }, - { - "required": ["combinatorics", "param-vectors"] - } - ] } } }, "45a84": { "full": { "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/param-values-vectors-combinatorics", "title": "Python test case list", "description": "Definition of calls to a Python test case with a list of parameter combinations.", "type": "object", @@ -675,24 +672,6 @@ "param-vectors": { "$ref": "#/definitions/fe80e/full" } - }, - "oneOf": [ - { - "required": ["param-values"] - }, - { - "required": ["param-vectors"] - } - ], - "not": { - "anyOf": [ - { - "required": ["param-values", "param-vectors"] - }, - { - "required": ["combinatorics", "param-vectors"] - } - ] } } }, @@ -725,6 +704,7 @@ "7f0f0": { "full": { "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/param-values-vectors-combinatorics", "title": "Python test sequence list", "description": "Definition of calls to a Python test sequence with a list of parameter combinations.", "type": "object", @@ -755,24 +735,6 @@ "param-vectors": { "$ref": "#/definitions/fe80e/full" } - }, - "oneOf": [ - { - "required": ["param-values"] - }, - { - "required": ["param-vectors"] - } - ], - "not": { - "anyOf": [ - { - "required": ["param-values", "param-vectors"] - }, - { - "required": ["combinatorics", "param-vectors"] - } - ] } } }, diff --git a/src/test/pnpm-workspace/pnpm-workspace2.yaml b/src/test/pnpm-workspace/pnpm-workspace2.yaml new file mode 100644 index 00000000000..20330862517 --- /dev/null +++ b/src/test/pnpm-workspace/pnpm-workspace2.yaml @@ -0,0 +1,3 @@ +# yaml-language-server: $schema=../../schemas/json/pnpm-workspace.json +# https://pnpm.io/catalogs +catalog: null