Manifest schema

This page describes the current app-side manifest validation surfaces. The on-disk JSON Schema at apps/desktop/src/data/osc-manifest-schema.json drives Monaco/editor validation for the form-supported Windows resource types. Registration also runs the core shape validator in packages/core/src/platform.ts. The targeted oscfg version is tracked separately in packages/core/src/oscfg/registered-types.ts.

Top-level grammar

resources:                       # REQUIRED - top-level ARRAY
  - name: <string>               # required by core registration for top-level resources; optional in the editor JSON Schema
    type: <string>               # REQUIRED, fully-qualified, slash-notation
    properties: { ... }          # required by the editor JSON Schema for modeled resource items; optional at core shape-validation level

Note: resources: must be an array of objects. A bare object, a string, or a non-existent key all produce a status-400 hard block at register time. Core registration requires each top-level resource to have name and type; nested Group resources can inherit identity from the parent. properties, when present, must be an object. The editor JSON Schema requires type and properties for the resource items it models.

Reserved property keys

The following keys are special - interpreted by the CLI rather than passed through to the resource:

KeyUsed byPurpose
expressionMicrosoft.OSConfig/TestCompliance assertion expression.
complianceMicrosoft.OSConfig/TestOne of equal, gte, lte, …
templateMicrosoft.OSConfig/TestOptional message template.
resourceMicrosoft.OSConfig/TestThe resource the test asserts on.

Resource wrappers

Microsoft.OSConfig/Group and Microsoft.OSConfig/Test are wrappers - they nest other resources:

resources:
  - name: ssh-hardening
    type: Microsoft.OSConfig/Group
    properties:
      resources:                # ← nested array
        - name: PermitRootLogin
          type: Microsoft.OSConfig/Test
          properties:
            resource:
              type: Microsoft.OSConfig/FileLine
              properties:
                path: /etc/ssh/sshd_config
                line: PermitRootLogin no
            expression: "PermitRootLogin == 'no'"
            compliance: equal

The core validator walks both wrappers recursively. A 'mixed' platform manifest is detected even when the offending type is buried inside a wrapper.

Registry resource

The most-used Windows resource. All three of keyPath, valueName, and valueType are required at the schema level - see the required: ["keyPath","valueName","valueType"] line in the shipped JSON Schema's registry definition. The value shape is constrained by valueType via a oneOf:

resources:
  - name: NTLMOutgoingHardening
    type: Microsoft.Windows/Registry
    properties:
      keyPath: HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
      valueName: NtlmMinClientSec
      valueType: Dword
      value: 537395200

The shipped schema accepts both the modern OSConfig names and the legacy REG_* names. The pairing rules are:

valueTypevalue JSON type
String, ExpandString, Binary, REG_SZ, REG_EXPAND_SZ, REG_BINARYstring
Dword, QWord, REG_DWORD, REG_QWORDinteger
MultiString, REG_MULTI_SZarray of string

A value whose type doesn't match the valueType category will fail the editor JSON-Schema oneOf constraint. The core register validator is intentionally lighter and only enforces manifest shape.

The CSV / security-definition import (packages/core/src/handlers/import.ts) calls inferRegistryValueType(expectedValue) to satisfy the valueType requirement automatically - integer-shaped strings or numbers become Dword, everything else becomes String. Adding new import sources? Re-use that helper.

Microsoft.OSConfig/BaselineRule placeholder (v0.2.2+)

Emitted by the importer when the source is an Azure Policy Guest Configuration baseline catalog (a JSON with a settingsReference[] array). Each entry maps to one of these placeholders carrying the rule identity (ruleId, displayName, severity, schemaType, originalSettingName) without the implementation. The OSConfig agent on the target machine is the only thing that knows how to evaluate each rule by its ruleId.

resources:
  - name: 1_1_1_1_Ensure_cramfs_kernel_module_is_not_available
    type: Microsoft.OSConfig/BaselineRule
    properties:
      ruleId: 2b568469-ea61-c184-66ba-db6720414ddd
      displayName: 1.1.1.1 Ensure cramfs kernel module is not available
      severity: Critical
      schemaType: string

This type is intentionally not in the editor's schema validator's oneOf - the validator flags it as an unknown type so users see the constraint immediately. The oscfg CLI also doesn't recognise it, so audit/deploy fails loudly. The Azure Policy export refuses any manifest containing this type (would silently report Compliant for every VM otherwise). Map each placeholder to a concrete resource type (Microsoft.Windows/Registry, Microsoft.OSConfig/FileLine, etc.) with real implementation details before deployment.

CSP resource

resources:
  - name: TelemetryAllowed
    type: Microsoft.Windows/CSP
    properties:
      path: ./Vendor/MSFT/Policy/Config/System/AllowTelemetry
      type: integer
      value: 0

properties.path is either a string or { get, set } object pair (see the csp definition in the schema). properties.type is one of string / integer / boolean / array. properties.name is optional.

Audit policy resource

resources:
  - name: AuditLogonEvents
    type: Microsoft.Windows/AuditPolicy
    properties:
      subcategory: "Logon"
      value: 3        # 0=none, 1=success, 2=failure, 3=success+failure

Microsoft.Windows/AuditPolicy is in the current registered-type whitelist. Earlier preview builds returned Unsupported resource type for it; ConfigForge surfaced that as a soft warning at register time. If you target an older CLI version, that soft-warning path still triggers - see Reference → Registered types.

Validation

Validation is split across two layers:

CheckWhereWhat it does
validateManifestSchema()packages/core/src/platform.tsTop-level object, required resources array, resource object/name/type checks, optional properties object check, recursive Group/Test traversal. Hard errors → status 400.
detectManifestPlatform()packages/core/src/platform.tsClassifies into windows / linux / cross-platform / mixed.
hasMixedPlatformResources()packages/core/src/platform.tsIndependent mixed-platform detector (catches mixes buried in wrappers).
isRegisteredType(t, platform)packages/core/src/oscfg/registered-types.tsWhitelist lookup. Types missing from the whitelist soft-warn at register time when the manifest targets this host.
Editor inline validatorapps/desktop/src/components/manifest-editor.tsxThe tighter Monaco-side validator: enforces e.g. keyPath + valueName + valueType on Registry resources for early UX feedback.
Editor JSON-Schema validatorMonaco JSON language service against apps/desktop/src/data/osc-manifest-schema.jsonThe structural pass for schema-modeled resources.

Verified bounds

The code currently exposes these verified app-side bounds:

BoundDefault
Max Group/Test traversal depth in core validation50
Max IPC manifest/import content payload10 MB (MAX_MANIFEST_CONTENT_LEN / MAX_IMPORT_BYTES, CF-SEC-003)

No separate max-resource-count or per-field string bound is documented here because the current core validator does not expose one.

See also