Protect against arbitrary JSON breaking my workflows

I am having a hell of a time dealing with JSON that may, or may not, have a value.

What’s the best way to protect myself from arbitrary JSON killing my workflows?

This JSON:

      "payload": {
        "version": "5.3.3"
      }

With this Step (fromJson):

      - name: Deployment Payload - fromJson
        if: ${{ github.event.deployment.payload }}
        env:
          DEPLOYMENT_PAYLOAD: ${{ fromJson(github.event.deployment.payload) }}
        run: echo "$DEPLOYMENT_PAYLOAD"

Produces this error:

##[error].github/workflows/test-deployment.yml (Line: 22, Col: 31):
##[error]The template is not valid. .github/workflows/test-deployment.yml (Line: 22, Col: 31): Unexpected character encountered while parsing value: O. Path '', line 0, position 0.

With this Step:

      - name: Deployment Payload
        id: deployment_payload
        if: ${{ github.event.deployment.payload }}
        env:
          DEPLOYMENT_PAYLOAD: ${{ github.event.deployment.payload }}
        run: |
          echo "::set-output name=payload::$DEPLOYMENT_PAYLOAD"
          echo "$DEPLOYMENT_PAYLOAD"

Produces this error:

##[error].github/workflows/test-deployment.yml (Line: 23, Col: 31): A mapping was not expected
##[error]The template is not valid. .github/workflows/test-deployment.yml (Line: 23, Col: 31): A mapping was not expected

Hi @rbellamy,

fromJson(value) will return a JSON object for value, which cannot be set as the env value, you can use toJson(value) instead, it returns a pretty-print JSON representation of value .

      - name: Deployment Payload - fromJson1
        if: ${{ github.event.deployment.payload }}
        env:
          DEPLOYMENT_PAYLOAD: ${{ toJson(github.event.deployment.payload) }}
        run: echo "$DEPLOYMENT_PAYLOAD"

And same for ${{ github.event.deployment.payload }}, it’s an object, add toJson() as below:

      - name: Deployment Payload
        id: deployment_payload
        if: ${{ github.event.deployment.payload }}
        env:
          DEPLOYMENT_PAYLOAD: ${{ toJson(github.event.deployment.payload) }}
        run: |
          echo "::set-output name=payload::$DEPLOYMENT_PAYLOAD"
          echo "$DEPLOYMENT_PAYLOAD"

It will return ${{ toJson(github.event.deployment.payload) }} as below:
image

If you’d like only get the version number 5.3.3, you need to use ${{ github.event.deployment.payload.version }}.

Please refer to the official doc for more details.
https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#tojson

Thanks

I think you’re missing my question, so let me ask it a different way.

If github.event.deployment.payload isn’t passed to the event, the if conditional should be false, and that step shouldn’t run, and yet I get a templating error caused by a JSON parsing error.

How can I protect myself from that scenario?

One more clarifying point: this is a question of data validation of an unknown JSON structure in github.event.deployment.payload. Because the payload is of unknown structure, I can’t predict whether it’s well-formed JSON, and therefore run into this problem with JSON parse errors.

While it’s true that a deployment payload SHOULD be well-formed, I’ve already found one implementation that breaks that rule - the one used by Slack. Slack escapes the payload, so the only way to get at the version is something like ${{ fromJson(github.event.deployment.payload).version }}. Curl, of course, doesn’t have this problem. Nor does the actions/request-action.

This means that one of three primary methods of triggering a deployment is different than the others, and I’ve been stuck trying to support all three without success because of these JSON parsing errors.

Hi @rbellamy,

Please try below if expression when payload is not defined.

      - name: Deployment Payload - fromJson1
        if: toJson(github.event.deployment.payload) != '{}'
        env:
          DEPLOYMENT_PAYLOAD: ${{ toJson(github.event.deployment.payload) }}
        run: echo "$DEPLOYMENT_PAYLOAD"

Thanks