action-validator icon indicating copy to clipboard operation
action-validator copied to clipboard

`permissions` in a job are incorrectly flagged

Open nedbat opened this issue 1 year ago • 3 comments

I ran action-validator on my current publish.yml action, and got this output:

Validation failed: ValidationState {
    action_type: Some(
        Workflow,
    ),
    file_path: Some(
        "./.github/workflows/publish.yml",
    ),
    errors: [
        OneOf {
            code: "one_of",
            detail: None,
            path: "/jobs/publish-to-pypi",
            title: "OneOf conditions are not met",
            states: [
                ValidationState {
                    action_type: None,
                    file_path: None,
                    errors: [
                        OneOf {
                            code: "one_of",
                            detail: None,
                            path: "/jobs/publish-to-pypi/permissions",
                            title: "OneOf conditions are not met",
                            states: [
                                ValidationState {
                                    action_type: None,
                                    file_path: None,
                                    errors: [
                                        Enum {
                                            code: "enum",
                                            detail: None,
                                            path: "/jobs/publish-to-pypi/permissions",
                                            title: "Enum conditions are not met",
                                        },
                                        WrongType {
                                            code: "wrong_type",
                                            detail: Some(
                                                "The value must be string",
                                            ),
                                            path: "/jobs/publish-to-pypi/permissions",
                                            title: "Type of the value is wrong",
                                        },
                                    ],
                                },
                                ValidationState {
                                    action_type: None,
                                    file_path: None,
                                    errors: [
                                        Properties {
                                            code: "properties",
                                            detail: Some(
                                                "Additional property 'attestations' is not allowed",
                                            ),
                                            path: "/jobs/publish-to-pypi/permissions",
                                            title: "Property conditions are not met",
                                        },
                                    ],
                                },
                            ],
                        },
                    ],
                },
                ValidationState {
                    action_type: None,
                    file_path: None,
                    errors: [
                        Properties {
                            code: "properties",
                            detail: Some(
                                "Additional property 'environment' is not allowed",
                            ),
                            path: "/jobs/publish-to-pypi",
                            title: "Property conditions are not met",
                        },
                        OneOf {
                            code: "one_of",
                            detail: None,
                            path: "/jobs/publish-to-pypi/permissions",
                            title: "OneOf conditions are not met",
                            states: [
                                ValidationState {
                                    action_type: None,
                                    file_path: None,
                                    errors: [
                                        Enum {
                                            code: "enum",
                                            detail: None,
                                            path: "/jobs/publish-to-pypi/permissions",
                                            title: "Enum conditions are not met",
                                        },
                                        WrongType {
                                            code: "wrong_type",
                                            detail: Some(
                                                "The value must be string",
                                            ),
                                            path: "/jobs/publish-to-pypi/permissions",
                                            title: "Type of the value is wrong",
                                        },
                                    ],
                                },
                                ValidationState {
                                    action_type: None,
                                    file_path: None,
                                    errors: [
                                        Properties {
                                            code: "properties",
                                            detail: Some(
                                                "Additional property 'attestations' is not allowed",
                                            ),
                                            path: "/jobs/publish-to-pypi/permissions",
                                            title: "Property conditions are not met",
                                        },
                                    ],
                                },
                            ],
                        },
                        Properties {
                            code: "properties",
                            detail: Some(
                                "Additional property 'runs-on' is not allowed",
                            ),
                            path: "/jobs/publish-to-pypi",
                            title: "Property conditions are not met",
                        },
                        Properties {
                            code: "properties",
                            detail: Some(
                                "Additional property 'steps' is not allowed",
                            ),
                            path: "/jobs/publish-to-pypi",
                            title: "Property conditions are not met",
                        },
                        Required {
                            code: "required",
                            detail: None,
                            path: "/jobs/publish-to-pypi/uses",
                            title: "This property is required",
                        },
                    ],
                },
            ],
        },
        OneOf {
            code: "one_of",
            detail: None,
            path: "/jobs/publish-to-test-pypi",
            title: "OneOf conditions are not met",
            states: [
                ValidationState {
                    action_type: None,
                    file_path: None,
                    errors: [
                        OneOf {
                            code: "one_of",
                            detail: None,
                            path: "/jobs/publish-to-test-pypi/permissions",
                            title: "OneOf conditions are not met",
                            states: [
                                ValidationState {
                                    action_type: None,
                                    file_path: None,
                                    errors: [
                                        Enum {
                                            code: "enum",
                                            detail: None,
                                            path: "/jobs/publish-to-test-pypi/permissions",
                                            title: "Enum conditions are not met",
                                        },
                                        WrongType {
                                            code: "wrong_type",
                                            detail: Some(
                                                "The value must be string",
                                            ),
                                            path: "/jobs/publish-to-test-pypi/permissions",
                                            title: "Type of the value is wrong",
                                        },
                                    ],
                                },
                                ValidationState {
                                    action_type: None,
                                    file_path: None,
                                    errors: [
                                        Properties {
                                            code: "properties",
                                            detail: Some(
                                                "Additional property 'attestations' is not allowed",
                                            ),
                                            path: "/jobs/publish-to-test-pypi/permissions",
                                            title: "Property conditions are not met",
                                        },
                                    ],
                                },
                            ],
                        },
                    ],
                },
                ValidationState {
                    action_type: None,
                    file_path: None,
                    errors: [
                        Properties {
                            code: "properties",
                            detail: Some(
                                "Additional property 'environment' is not allowed",
                            ),
                            path: "/jobs/publish-to-test-pypi",
                            title: "Property conditions are not met",
                        },
                        OneOf {
                            code: "one_of",
                            detail: None,
                            path: "/jobs/publish-to-test-pypi/permissions",
                            title: "OneOf conditions are not met",
                            states: [
                                ValidationState {
                                    action_type: None,
                                    file_path: None,
                                    errors: [
                                        Enum {
                                            code: "enum",
                                            detail: None,
                                            path: "/jobs/publish-to-test-pypi/permissions",
                                            title: "Enum conditions are not met",
                                        },
                                        WrongType {
                                            code: "wrong_type",
                                            detail: Some(
                                                "The value must be string",
                                            ),
                                            path: "/jobs/publish-to-test-pypi/permissions",
                                            title: "Type of the value is wrong",
                                        },
                                    ],
                                },
                                ValidationState {
                                    action_type: None,
                                    file_path: None,
                                    errors: [
                                        Properties {
                                            code: "properties",
                                            detail: Some(
                                                "Additional property 'attestations' is not allowed",
                                            ),
                                            path: "/jobs/publish-to-test-pypi/permissions",
                                            title: "Property conditions are not met",
                                        },
                                    ],
                                },
                            ],
                        },
                        Properties {
                            code: "properties",
                            detail: Some(
                                "Additional property 'runs-on' is not allowed",
                            ),
                            path: "/jobs/publish-to-test-pypi",
                            title: "Property conditions are not met",
                        },
                        Properties {
                            code: "properties",
                            detail: Some(
                                "Additional property 'steps' is not allowed",
                            ),
                            path: "/jobs/publish-to-test-pypi",
                            title: "Property conditions are not met",
                        },
                        Required {
                            code: "required",
                            detail: None,
                            path: "/jobs/publish-to-test-pypi/uses",
                            title: "This property is required",
                        },
                    ],
                },
            ],
        },
    ],
}

It seems to object to permissions in a job:

jobs:
  publish-to-test-pypi:
    name: "Publish to Test PyPI"
    if: ${{ github.event.action == 'publish-testpypi' }}
    permissions:
      id-token: write
      attestations: write

Am I misunderstanding the output? Job permissions are documented: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idpermissions

If I comment out the two places I use them, validation passes.

nedbat avatar Nov 02 '24 09:11 nedbat

Well, first off, well done figuring out what the JSON schema validator output is actually talking about. :grin: My first thought was that this might be a newer feature than the version of the GitHub workflow schema that's embedded, but as best as I can tell, support for permissions was added a long, long time ago.

Are you able to reduce the bug to a minimal schema that I can easily drop into the test suite? That'll save me some faffing around, and make it easier for me to find the time and energy to dive into the depths of the schema and figure out what's going on.

mpalmer avatar Nov 03 '24 04:11 mpalmer

It looks like attestations is the issue. This passes:

name: "Publish"

on:
  push:

jobs:
  publish-to-pypi:
    name: foo
    runs-on: ubuntu
    permissions:
      id-token: write

    steps:
    - uses: pypa/gh-action-pypi-publish

This fails:

name: "Publish"

on:
  push:

jobs:
  publish-to-pypi:
    name: foo
    runs-on: ubuntu
    permissions:
      attestations: write

    steps:
    - uses: pypa/gh-action-pypi-publish

nedbat avatar Nov 03 '24 11:11 nedbat

Aha! You've cracked the case. That was added to the schema more recently than what we're currently using. A schema bump will fix this; PR if you like, or I'll get around to it soonish.

mpalmer avatar Nov 04 '24 08:11 mpalmer

👋 hey! I've hit the same issue! :D

@mpalmer I'm going to bump the schemastore submodule and make a PR!

jjmaestro avatar Jun 19 '25 16:06 jjmaestro

This was fixed by #96.

mpalmer avatar Jul 07 '25 01:07 mpalmer