Skip to content

microsoft/apm shared workflow uncompilable: import-schema items + strategy.matrix #33572

@rhardouin

Description

@rhardouin

Analysis

Following the officially-documented APM integration path (docs/src/content/docs/reference/dependencies.md):

APM is configured by importing the shared/apm.md workflow, which creates a dedicated apm job.

Reproduction is direct and confirmed on both v0.74.4 and v0.74.7 (latest pre-release at time of report) — identical error strings at identical (line, col) positions. Separately, the schema definitions on main (commit 8c2c89f, quoted verbatim below) still contain both restrictions, so main is also affected.

$ gh aw --version
gh aw version v0.74.4
$ gh aw add microsoft/apm/.github/workflows/shared/apm.md --dir shared --force
ℹ Overwriting existing file: …/shared/apm.md
✓ Added workflow: …/shared/apm.md
$ gh aw compile shared/apm.md
✗ Compiled 1 workflow(s): 1 error(s), 0 warning(s)

✗ Failed workflows:
  ✗ apm.md

shared/apm.md:120:7: error: Multiple schema validation failures:
- 'import-schema/apps' (line 120, col 7): Unknown property: properties
- 'jobs/apm/strategy' (line 272, col 14): 'matrix': got string, want object
117 |       multiple orgs requiring different App installations.
118 |     items:
119 |       type: object
120 |       properties:
            ^^^^^^^^^^
121 |         id:
122 |           type: string
123 |           required: false

✗ compilation failed

Re-tested on v0.74.7 (same two errors, identical positions):

$ gh aw --version
gh aw version v0.74.7
$ gh aw compile shared/apm.md
✗ Compiled 1 workflow(s): 2 error(s) across 1 failed workflow(s), 0 warning(s)

✗ Failed workflows:
  ✗ apm.md

apm.md (2 error(s)):
  🟡 MEDIUM PRIORITY:
    1. .github/workflows/shared/apm.md:120:7: error: 'import-schema/apps' (line 120, col 7): Unknown property: properties
       → Fix this configuration issue and re-run `gh aw compile`.
    2. .github/workflows/shared/apm.md:120:7: error: 'jobs/apm/strategy' (line 272, col 14): 'matrix': got string, want object
       → Fix this configuration issue and re-run `gh aw compile`.

Minimum-repro workflows isolating each gap independently of the full microsoft/apm shared workflow can be provided on request.

The file is microsoft/apm@main:.github/workflows/shared/apm.md (blob sha 47194cd1d976899e4d8c8131dc043d0342dbcf64). Both errors come from gh-aw's static schema. The import-schema block is gh-aw frontmatter (not GitHub Actions YAML), and the strategy.matrix construct is a standard GitHub Actions feature; together they're the form Microsoft ships for APM consumers via gh-aw's own documented integration.

The two restrictions are independent and both must be relaxed to unblock the integration; partial fixes leave shared/apm.md uncompilable even for consumers who use the no-credential or single-app forms (the unsupported constructs are in the shared workflow itself, not just in optional inputs).

Root cause 1 — import-schema.items only accepts primitive types

In pkg/parser/schemas/main_workflow_schema.json, properties.import-schema.additionalProperties.oneOf[0].properties.items is:

"items": {
  "type": "object",
  "description": "Schema for individual array elements. Typically {\"type\": \"string\"}.",
  "properties": {
    "type": {
      "type": "string",
      "enum": ["string", "number", "boolean"],
      "description": "Type of each array item."
    }
  },
  "additionalProperties": false
}

additionalProperties: false is what rejects properties: under items:, and the enum excludes object. The APM apps: input is an array of typed objects (cross-org GitHub App credential groups):

apps:
  type: array
  items:
    type: object
    properties:
      id:           { type: string,  required: false }
      app-id:       { type: string,  required: true  }
      private-key:  { type: string,  required: true  }
      owner:        { type: string,  required: false }
      repositories: { type: string,  required: false }
      packages:
        type: array
        items: { type: string }
        required: true

This array-of-objects shape is unrepresentable in today's import-schema grammar. import-schema already supports top-level object inputs (the second oneOf branch under additionalProperties, described in the schema as "Input parameter definition for object type (one level deep). Use 'properties' to declare the expected sub-fields."), but array items are limited to primitive element types (string / number / boolean), so an array input cannot declare object elements with nested properties.

Root cause 2 — strategy.matrix rejects dynamic expression form

In the same schema, $defs.job_strategy.matrix is:

"matrix": {
  "type": "object",
  "description": "Matrix variables for creating job variants. Each key defines a dimension of the matrix, with values as arrays (e.g., {os: [ubuntu-latest, windows-latest]}). Use 'include' to add extra configurations and 'exclude' to remove specific combinations.",
  "additionalProperties": true
}

There is no oneOf branch for a string expression. The APM workflow uses GitHub Actions' standard dynamic matrix from a previous job's output:

apm:
  needs: [activation, apm-prep]
  strategy:
    fail-fast: false
    matrix: ${{ fromJSON(needs.apm-prep.outputs.matrix) }}

This is documented GitHub Actions behavior — the fromJSON "Example returning a JSON object" shows the whole strategy.matrix field form, i.e. matrix: ${{ fromJSON(needs.job1.outputs.matrix) }}. gh-aw rejects it at compile time even though the GitHub Actions runner accepts it at runtime.

Implementation Plan

Please implement the following changes:

  1. Allow object-typed items in import-schema (pkg/parser/schemas/main_workflow_schema.json):

    • Hoist the existing scalar/array input schema (currently properties.import-schema.additionalProperties.oneOf[0]) into a reusable $defs.import-schema-input so it can be referenced from object-item sub-properties.
    • Extend the items sub-schema to a oneOf with the current primitive form or a new object form. The validator schema below is itself a JSON Schema, so it naturally uses the JSON-Schema keywords required and additionalProperties to constrain what users can write — that is unchanged. The point is to keep gh-aw's user-facing import-schema grammar on its existing per-property required: true|false convention; do not extend the user-facing grammar with JSON-Schema-style object-level required: [keys] or per-items additionalProperties semantics (those would be separate features and would distract from this bug):
      "items": {
        "oneOf": [
          {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "type": { "enum": ["string", "number", "boolean"] }
            }
          },
          {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "type": { "const": "object" },
              "properties": {
                "type": "object",
                "additionalProperties": { "$ref": "#/$defs/import-schema-input" }
              }
            },
            "required": ["type", "properties"]
          }
        ]
      }
    • Scope: this is schema-acceptance only. It does not require changes to runtime input substitution. The microsoft/apm workflow uses the whole-array substitution form ${{ github.aw.import-inputs.apps }}, which already resolves correctly once the schema accepts the declaration. Indexed substitution like apps[0].owner is out of scope for this bug.
  2. Allow dynamic strategy.matrix expressions (pkg/parser/schemas/main_workflow_schema.json):

    • Change $defs.job_strategy.matrix to a oneOf:
      "matrix": {
        "oneOf": [
          {
            "type": "object",
            "additionalProperties": true,
            "description": "Static matrix object."
          },
          {
            "type": "string",
            "pattern": "^\\s*\\$\\{\\{[\\s\\S]+\\}\\}\\s*$",
            "description": "Dynamic matrix from a GitHub Actions expression, e.g. ${{ fromJSON(needs.prep.outputs.matrix) }}."
          }
        ]
      }
    • The pattern keeps validation tight: only ${{ ... }} expressions are accepted in string form, not arbitrary text.
  3. Update validation error messages (pkg/workflow/schema_validation.go, pkg/parser/schema_errors.go):

    • When strategy.matrix is a non-expression string, keep the existing 'matrix': got string, want object recovery but extend the suggestion to also mention the dynamic form. Style:
      • Example error: 'matrix': got plain string, want object or '${{ ... }}' expression. Example (static): matrix:\n os: [ubuntu-latest, windows-latest]. Example (dynamic): matrix: ${{ fromJSON(needs.prep.outputs.matrix) }}
    • When import-schema/<key> rejects properties: under items: for a primitive item type, suggest switching items.type to object (now allowed after Implementation Plan step 1 above).
  4. Add tests (pkg/workflow/import_schema_test.go):

    • Positive: apps[] with object items + nested properties (mirroring the microsoft/apm shape) compiles. Verify whole-array substitution ${{ github.aw.import-inputs.apps }} still resolves end-to-end.
    • Positive: an object item with a required: true sub-property rejects a with: value that omits that sub-property at consumer-side validation (using gh-aw's existing per-property required convention).
    • Negative: unknown sub-property inside an object item is still rejected (preserves the current strictness for typo detection).
    • Regression: existing primitive-item tests stay green.
  5. Add tests (pkg/workflow/compiler_yaml_test.go or the closest existing strategy/matrix test file):

    • Positive: matrix: ${{ fromJSON(needs.prep.outputs.matrix) }} compiles and round-trips into the lock file unchanged.
    • Negative: matrix: "not-an-expression" (plain non-expression string) still rejected by the new pattern.
    • Regression: existing static matrix: { os: [...], node: [...] } cases stay green.
  6. Add a regression fixture (wired into pkg/workflow/shared_workflow_test.go):

    • Preferred (low-friction): a minimal hand-written fixture that exercises just the import-schema array-of-typed-objects shape and the dynamic matrix: form — independent of any upstream workflow and stable across microsoft/apm churn.
    • Optional (end-to-end): if maintainers want full integration coverage, also vendor a pinned copy of microsoft/apm@<sha>:.github/workflows/shared/apm.md as pkg/workflow/testdata/shared_workflow_apm.md. The pinned-vendoring approach trades maintenance and licensing surface for tighter regression guarantees on the documented integration.
  7. Update documentation (paths TBD — please point me to the canonical files; I checked docs/src/content/docs/reference/dependencies.md exists, but did not find a dedicated import-schema.md):

    • Wherever import-schema is documented, add an example of object-typed items matching the microsoft/apm apps[] shape.
    • Wherever job strategy / matrix: is documented, add a short subsection on dynamic matrices and link to the GHA fromJSON example showing the whole-field form.
    • In docs/src/content/docs/reference/dependencies.md, note the minimum gh-aw version that supports the APM shared workflow once these changes ship.
  8. Follow Guidelines:

    • Run make agent-finish before completing.
    • Use the existing schema-validation error message style ([what's wrong]. [what's expected]. [example]) per pkg/console conventions.
    • No CLI surface change; no console formatting work expected beyond error messages.

Environment

Field Value
gh aw confirmed on v0.74.4 and v0.74.7 (latest at time of report)
OS macOS 25.4.0 (darwin)
Shell zsh
Source file microsoft/apm@main:.github/workflows/shared/apm.md, blob sha 47194cd1d976899e4d8c8131dc043d0342dbcf64
Doc followed docs/src/content/docs/reference/dependencies.md @ commit 8c2c89ffa00af3d2988d2fd93a2d4ebcdf03c900

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions