From b55078e33ae559fce8ab48ab9f91a8c5db4c68db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20Papp=20=28TWiStErRob=29?= Date: Fri, 4 Sep 2026 19:06:59 +0100 Subject: [PATCH 1/2] AI(gpt-5.6-sol): Add action output dispatch regression tests Each fixture was added individually on top of master, then tested with: node ./cli.js check --schema-name=github-action.json `outputs-empty.json`: >> Failed to validate file "src/test/github-action/outputs-empty.json" against schema file "./src/schemas/json/github-action.json" >> Showing first error out of 1 total error(s) { instancePath: '/outputs', schemaPath: '#/properties/outputs/oneOf', keyword: 'oneOf', params: { passingSchemas: [ 0, 1 ] }, message: 'must match exactly one schema in oneOf' } `output-id-runs.json`: >> Failed to validate file "src/test/github-action/output-id-runs.json" against schema file "./src/schemas/json/github-action.json" >> Showing first error out of 3 total error(s) { instancePath: '/outputs', schemaPath: '#/definitions/outputs-composite/dependencies/runs/required', keyword: 'required', params: { missingProperty: 'using' }, message: "must have required property 'using'" } `javascript-output-with-value.json`: >> Schema validation succeeded for test file "./src/negative_test/github-action/javascript-output-with-value.json", but was supposed to fail >> For schema "./src/schemas/json/github-action.json" `composite-output-missing-value.json`: >> Schema validation succeeded for test file "./src/negative_test/github-action/composite-output-missing-value.json", but was supposed to fail >> For schema "./src/schemas/json/github-action.json" Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../composite-output-missing-value.json | 18 ++++++++++++++++++ .../javascript-output-with-value.json | 14 ++++++++++++++ src/test/github-action/output-id-runs.json | 13 +++++++++++++ src/test/github-action/outputs-empty.json | 9 +++++++++ 4 files changed, 54 insertions(+) create mode 100644 src/negative_test/github-action/composite-output-missing-value.json create mode 100644 src/negative_test/github-action/javascript-output-with-value.json create mode 100644 src/test/github-action/output-id-runs.json create mode 100644 src/test/github-action/outputs-empty.json diff --git a/src/negative_test/github-action/composite-output-missing-value.json b/src/negative_test/github-action/composite-output-missing-value.json new file mode 100644 index 00000000000..94588ee7440 --- /dev/null +++ b/src/negative_test/github-action/composite-output-missing-value.json @@ -0,0 +1,18 @@ +{ + "description": "Composite action with an output missing its value", + "name": "Test composite output without value", + "outputs": { + "result": { + "description": "Missing value" + } + }, + "runs": { + "steps": [ + { + "run": "echo test", + "shell": "bash" + } + ], + "using": "composite" + } +} diff --git a/src/negative_test/github-action/javascript-output-with-value.json b/src/negative_test/github-action/javascript-output-with-value.json new file mode 100644 index 00000000000..95efa6ccbc0 --- /dev/null +++ b/src/negative_test/github-action/javascript-output-with-value.json @@ -0,0 +1,14 @@ +{ + "description": "JavaScript action with a composite-only output value", + "name": "Test JavaScript output with value", + "outputs": { + "result": { + "description": "Unexpected value", + "value": "${{ steps.test.outputs.result }}" + } + }, + "runs": { + "main": "index.js", + "using": "node24" + } +} diff --git a/src/test/github-action/output-id-runs.json b/src/test/github-action/output-id-runs.json new file mode 100644 index 00000000000..2145a9d3a52 --- /dev/null +++ b/src/test/github-action/output-id-runs.json @@ -0,0 +1,13 @@ +{ + "description": "JavaScript action with an output named runs", + "name": "Test output named runs", + "outputs": { + "runs": { + "description": "An output whose identifier matches a top-level property" + } + }, + "runs": { + "main": "index.js", + "using": "node24" + } +} diff --git a/src/test/github-action/outputs-empty.json b/src/test/github-action/outputs-empty.json new file mode 100644 index 00000000000..f252cd6e3c2 --- /dev/null +++ b/src/test/github-action/outputs-empty.json @@ -0,0 +1,9 @@ +{ + "description": "JavaScript action with an empty output map", + "name": "Test empty outputs", + "outputs": {}, + "runs": { + "main": "index.js", + "using": "node24" + } +} From 19b1e2b2d1007acb49e8e9624f8ad9abeac97975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20Papp=20=28TWiStErRob=29?= Date: Fri, 4 Sep 2026 19:01:21 +0100 Subject: [PATCH 2/2] AI(gpt-5.6-sol): Restore action output schema dispatch The strict-validation rewrite moved runtime-dependent output selection into `dependencies` nested under each output definition. At that level, `runs` means an output identifier rather than the top-level action runtime, so the schema cannot distinguish composite outputs from JavaScript or Docker outputs. Restore top-level `if` / `then` / `else` dispatch based on `runs.using`. Keep the placeholder `outputs` property required by draft-07 `additionalProperties: false`, and declare the nested `runs` condition as an object so AJV strict type validation still passes. This makes empty output maps and output IDs named `runs` valid again, rejects JavaScript outputs containing composite-only `value`, and requires `value` for composite outputs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/schemas/json/github-action.json | 59 +++++++++++++---------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/src/schemas/json/github-action.json b/src/schemas/json/github-action.json index fe8fc78c048..83068c489ca 100644 --- a/src/schemas/json/github-action.json +++ b/src/schemas/json/github-action.json @@ -300,20 +300,7 @@ "additionalProperties": false } }, - "additionalProperties": false, - "dependencies": { - "runs": { - "type": "object", - "properties": { - "using": { - "not": { - "const": "composite" - } - } - }, - "required": ["using"] - } - } + "additionalProperties": false }, "outputs-composite": { "$comment": "https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#outputs-for-composite-actions", @@ -340,16 +327,24 @@ "additionalProperties": false } }, - "additionalProperties": false, - "dependencies": { - "runs": { - "type": "object", - "properties": { - "using": { - "const": "composite" - } - }, - "required": ["using"] + "additionalProperties": false + } + }, + "else": { + "properties": { + "outputs": { + "$ref": "#/definitions/outputs" + } + } + }, + "if": { + "properties": { + "runs": { + "type": "object", + "properties": { + "using": { + "const": "composite" + } } } } @@ -407,14 +402,7 @@ "additionalProperties": false }, "outputs": { - "oneOf": [ - { - "$ref": "#/definitions/outputs-composite" - }, - { - "$ref": "#/definitions/outputs" - } - ] + "$comment": "Because of `additionalProperties: false`, this empty schema is needed to allow the `outputs` property. The `outputs` subschema is determined by the if/then/else keywords." }, "runs": { "oneOf": [ @@ -719,5 +707,12 @@ } }, "required": ["name", "description", "runs"], + "then": { + "properties": { + "outputs": { + "$ref": "#/definitions/outputs-composite" + } + } + }, "type": "object" }