├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── action.yml └── entrypoint.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | LABEL "name"="bash" 4 | LABEL "repository"="https://github.com/distributhor/workflow-webhook" 5 | LABEL "version"="1.0.0" 6 | 7 | LABEL com.github.actions.name="Workflow Webhook" 8 | LABEL com.github.actions.description="An action that will call a webhook from your Github workflow" 9 | LABEL com.github.actions.icon="upload-cloud" 10 | LABEL com.github.actions.color="gray-dark" 11 | 12 | RUN apk add --no-cache bash curl openssl util-linux xxd jq jo 13 | 14 | COPY LICENSE README.md / 15 | COPY entrypoint.sh /entrypoint.sh 16 | 17 | RUN chmod +x /entrypoint.sh 18 | 19 | ENTRYPOINT ["/entrypoint.sh"] 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 distributhor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Workflow Webhook Action 2 | 3 | [![GitHub Release][ico-release]][link-github-release] 4 | [![License][ico-license]](LICENSE) 5 | 6 | A Github workflow action to call a remote webhook endpoint with a JSON or form-urlencoded 7 | payload, and support for BASIC authentication. A hash signature is passed with each request, 8 | derived from the payload and a configurable secret token. The hash signature is 9 | identical to that which a regular Github webhook would generate, and sent in a header 10 | field named `X-Hub-Signature`. Therefore any existing Github webhook signature 11 | validation will continue to work. For more information on how to valiate the signature, 12 | see . 13 | 14 | By default, the values of the following GitHub workflow environment variables are sent in the 15 | payload: `GITHUB_REPOSITORY`, `GITHUB_REF`, `GITHUB_HEAD_REF`, `GITHUB_SHA`, `GITHUB_EVENT_NAME` 16 | and `GITHUB_WORKFLOW`. For more information on what is contained in these variables, see 17 | . 18 | 19 | These values map to the payload as follows: 20 | 21 | ```json 22 | { 23 | "event": "GITHUB_EVENT_NAME", 24 | "repository": "GITHUB_REPOSITORY", 25 | "commit": "GITHUB_SHA", 26 | "ref": "GITHUB_REF", 27 | "head": "GITHUB_HEAD_REF", 28 | "workflow": "GITHUB_WORKFLOW" 29 | } 30 | ``` 31 | 32 | If you are interested in receiving more comprehensive data about the GitHub event than just the 33 | above fields, then the action can be configured to send the whole JSON payload of the GitHub event, 34 | as per the `GITHUB_EVENT_PATH` variable in the environment variable documentation referenced above. 35 | The official documentation and reference for the payload itself can be found here: 36 | , and the details on how to configure it, 37 | is further down in the **Usage** section of this README. 38 | 39 | Additional (custom) data can also be added/merged to the payload (see further down). 40 | 41 | 42 | ## Usage 43 | 44 | The following are example snippets for a Github yaml workflow configuration.
45 | 46 | Send the JSON (default) payload to a webhook: 47 | 48 | ```yml 49 | - name: Invoke deployment hook 50 | uses: distributhor/workflow-webhook@v3 51 | with: 52 | webhook_url: ${{ secrets.WEBHOOK_URL }} 53 | webhook_secret: ${{ secrets.WEBHOOK_SECRET }} 54 | ``` 55 | 56 | Will deliver a payload with the following properties: 57 | 58 | ```json 59 | { 60 | "event": "push", 61 | "repository": "owner/project", 62 | "commit": "a636b6f0861bbee98039bf3df66ee13d8fbc9c74", 63 | "ref": "refs/heads/master", 64 | "head": "", 65 | "workflow": "Build and deploy", 66 | "requestID": "74b1912d19cfe780f1fada4b525777fd" 67 | } 68 | ``` 69 | `requestID` contains a randomly generated identifier for each request. 70 | 71 |
72 | 73 | Add additional data to the payload: 74 | 75 | ```yml 76 | - name: Invoke deployment hook 77 | uses: distributhor/workflow-webhook@v3 78 | with: 79 | webhook_url: ${{ secrets.WEBHOOK_URL }} 80 | webhook_secret: ${{ secrets.WEBHOOK_SECRET }} 81 | data: '{ "weapon": "hammer", "drink" : "beer" }' 82 | ``` 83 | 84 | The additional information will become available on a `data` property, 85 | and now look like: 86 | 87 | ```json 88 | { 89 | "event": "push", 90 | "repository": "owner/project", 91 | "commit": "a636b6f0861bbee98039bf3df66ee13d8fbc9c74", 92 | "ref": "refs/heads/master", 93 | "head": "", 94 | "workflow": "Build and deploy", 95 | "data": { 96 | "weapon": "hammer", 97 | "drink": "beer" 98 | }, 99 | "requestID": "74b1912d19cfe780f1fada4b525777fd" 100 | } 101 | ``` 102 | 103 | Send a form-urlencoded payload instead: 104 | 105 | ```yml 106 | - name: Invoke deployment hook 107 | uses: distributhor/workflow-webhook@v3 108 | with: 109 | webhook_type: 'form-urlencoded' 110 | webhook_url: ${{ secrets.WEBHOOK_URL }} 111 | webhook_secret: ${{ secrets.WEBHOOK_SECRET }} 112 | data: 'weapon=hammer&drink=beer' 113 | ``` 114 | 115 | Will set the `Content-Type` header to `application/x-www-form-urlencoded` and deliver: 116 | 117 | ```csv 118 | "event=push&repository=owner/project&commit=a636b6f0....&weapon=hammer&drink=beer" 119 | ``` 120 | 121 | Finally, if you prefer to receive the whole original GitHub payload as JSON (as opposed 122 | to the default JSON snippet above), then configure the webhook with a `webhook_type` of 123 | `json-extended`: 124 | 125 | ```yml 126 | - name: Invoke deployment hook 127 | uses: distributhor/workflow-webhook@v3 128 | with: 129 | webhook_type: 'json-extended' 130 | webhook_url: ${{ secrets.WEBHOOK_URL }} 131 | webhook_secret: ${{ secrets.WEBHOOK_SECRET }} 132 | data: '{ "weapon": "hammer", "drink" : "beer" }' 133 | ``` 134 | 135 | You can still add custom JSON data, which will be available on a `data` property, included 136 | on the GitHub payload. Importantly, the sending of the whole GitHub payload 137 | is only supported as JSON, and not currently available as urlencoded form parameters. 138 | 139 | ## Arguments 140 | 141 | ```yml 142 | webhook_url: "https://your.webhook" 143 | ``` 144 | 145 | *Required*. The HTTP URI of the webhook endpoint to invoke. The endpoint must accept 146 | an HTTP POST request.

147 | 148 | 149 | ```yml 150 | webhook_secret: "Y0uR5ecr3t" 151 | ``` 152 | 153 | Optional. The secret with which to generate the signature hash. If no secret is configured, 154 | then the URL itself will be used as the value with which to generate the signature hash. 155 | This is useful for use-cases where the webhook URL might be an obscure, random or temporary 156 | link. In general it is advisable to use a webhook secret.

157 | 158 | ```yml 159 | webhook_auth_type: "bearer" 160 | ``` 161 | 162 | The type of authentication to use when invoking the webhook URL. Valid values are `basic`, 163 | `bearer` and `header`. Defaults to `basic` if not specified. In addition, if no value 164 | is set for `webhook_auth`, then it is assumed that no authentication is required, and this 165 | value, even if configured, will have no effect. It only takes effect when used in conjunction 166 | with `webhook_auth`. The expectations for how each option behaves, is explained in the 167 | `webhook_auth` section below.

168 | 169 | ```yml 170 | webhook_auth: "username:password" 171 | webhook_auth: "Token:ABC" 172 | webhook_auth: "ABC" 173 | ``` 174 | 175 | The credentials to be used for authentication of the the endpoint. If not configured, 176 | authentication is assumed not to be required.

177 | 178 | If the `webhook_auth_type` is set to `basic`, then this value is expected to be a 179 | `username:password` string, used for BASIC authentication against the endpoint. It must follow 180 | this format, as specified in the `curl` man pages, since it is passed verbatim to the 181 | `curl -u` option.

182 | 183 | If the `webhook_auth_type` is set to `bearer`, then this value is expected to be an 184 | access token. It will set a header named `Authorization` with a value of `Bearer ${webhook_auth}`. 185 |

186 | 187 | If the `webhook_auth_type` is set to `header`, then the expecation is to receive a string similar 188 | in format to `basic`, except that the delimiter (a colon) will delimit a header name and header 189 | value. For example a value of `Token:ABC` will set a header named `Token` with a value of `ABC`. 190 | If no colon is present (no delimiter specified) then it will default to setting a header named 191 | `Authorization` of which the value will be whatever was configured for `${webhook_auth}`, 192 | ie (no 'bearer') prefix. As an example, when configured with a value of `ABC`, a header named 193 | `Authorization` will be set to the value `ABC`. 194 |

195 | 196 | ```yml 197 | webhook_type: "json | form-urlencoded | json-extended" 198 | ``` 199 | 200 | The default endpoint type is JSON. The argument is only required if you wish to send urlencoded form data. 201 | Otherwise it's optional.

202 | 203 | ```yml 204 | verbose: true 205 | ``` 206 | 207 | To enable verbose output in curl set the argument `verbose` to `true`. The default value is `false`. See also: [`curl` docs on option `-v`](https://curl.se/docs/manpage.html#-v). 208 | 209 | :warning: **Warning:** This might lead to domain and IP leaking, as well as other security issues as the logs are public. 210 | See also [#21](https://github.com/distributhor/workflow-webhook/issues/21) and [#22](https://github.com/distributhor/workflow-webhook/issues/22).

211 | 212 | 213 | ```yml 214 | silent: true 215 | ``` 216 | 217 | To hide the output from curl set the argument `silent` to `true`. The default value is `false`.

218 | 219 | ```yml 220 | timeout: 30 221 | ``` 222 | 223 | To set a maximum time, in seconds, by which to establish an initial connection to the server. Once a connection has been 224 | established, the option is not used in any further way with regards to the duration of connection.

225 | 226 | ```yml 227 | max_time: 30 228 | ``` 229 | 230 | To set a maximum time, in seconds, by which the server needs to respond to the request. 231 | This also includes the time needed for the server to respond. May be used in combination with `timeout`.

232 | 233 | ```yml 234 | curl_opts: '--speed-limit 5000' 235 | curl_opts: '-H "X-Beverage: Beer"' 236 | ``` 237 | 238 | You can use `curl_opts` to pass in arbitrary options to the curl request. NOTE: this is an experimental feature and not 239 | guaranteed to work for all options. The string configured here will be passed in verbatim to curl, and it is quite easy to 240 | break things when using it. For simple curl options it should work, but for others it may not suffice. Also, take care with 241 | escaping characters in YAML.

242 | 243 | ```yml 244 | verify_ssl: false 245 | ``` 246 | 247 | To disable verification of SSL-certificates in curl set the argument `verify_ssl` to `false`. The default value is `true`. 248 | See also: [`curl` docs on option `-k`](https://curl.se/docs/manpage.html#-k).

249 | 250 | 251 | ```yml 252 | event_name: 'NAME' 253 | ``` 254 | 255 | Optional. A custom event name sent to the webhook endpoint

256 | 257 | ```yml 258 | data: "Additional JSON or URL encoded data" 259 | ``` 260 | 261 | 262 | Additional data to include in the payload. It is optional. This data will attempted to be 263 | merged 'as-is' with the existing payload, and is expected to already be sanitized and valid. 264 | 265 | In the case of JSON, the custom data will be available on a property named `data`, and it will be 266 | run through a JSON validator. Invalid JSON will cause the action to break and exit. For example, using 267 | single quotes for JSON properties and values instead of double quotes, will show the 268 | following (somewhat confusing) message in your workflow output: `Invalid numeric literal`. 269 | Such messages are the direct output from the validation library . 270 | The supplied JSON must pass the validation run through `jq`. 271 | 272 | ## Output 273 | 274 | ```yml 275 | response-body: 'The body of the webook response' 276 | ``` 277 | 278 | ## License 279 | 280 | The MIT License (MIT). Please see [License File](LICENSE) for more information. 281 | 282 | [ico-release]: https://img.shields.io/github/tag/distributhor/workflow-webhook.svg 283 | [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg 284 | [link-github-release]: https://github.com/distributhor/workflow-webhook/releases 285 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Workflow Webhook Action' 2 | description: 'A Github workflow action to call a webhook with payload data from the event. Support for JSON or URL encoded endpoints.' 3 | inputs: 4 | webhook_url: 5 | description: 'The HTTP URI of the webhook endpoint to invoke' 6 | required: true 7 | webhook_secret: 8 | description: 'The secret with which a signature hash is generated. If omitted, the URL itself will be used as the value with which to generate the hash.' 9 | webhook_auth: 10 | description: 'Optional. The BASIC auth credentials (a "username:password" string) OR a bearer access token OR a custom header to be used for authentication' 11 | webhook_auth_type: 12 | description: 'Optional. What type of authentication to use for invoking the webhook URL. Valid values are "basic", "bearer", "header". Defaults to "basic" if not specified.' 13 | default: "basic" 14 | webhook_type: 15 | description: 'json | form-urlencoded | json-extended' 16 | verbose: 17 | description: 'Optional. Set to true to enable verbose output. Warning: this might lead to domain and IP leaking, as well as other security issues as the logs are public.' 18 | silent: 19 | description: 'Optional. Set to true to disable output and therefore IP leaking.' 20 | timeout: 21 | description: 'Optional. Set a maximum time, in seconds, by which to establish a connection to the server.' 22 | max_time: 23 | description: 'Optional. Set a maximum time, in seconds, the request to the server can take, before being cancelled.' 24 | curl_opts: 25 | description: 'Optional (and experimental). Pass arbitrary options to the curl request.' 26 | verify_ssl: 27 | description: 'Optional. Set to false to disable verification of SSL certificates.' 28 | default: true 29 | event_name: 30 | description: 'Optional. Specify a custom event name sent to the webhook endpoint, if not defined it defaults to GITHUB_EVENT_NAME.' 31 | data: 32 | description: 'Optional. Specify additional data to include in the payload.' 33 | 34 | outputs: 35 | response-body: 36 | description: The response body of the webook response 37 | 38 | runs: 39 | using: 'docker' 40 | # image: 'Dockerfile' 41 | image: 'docker://ghcr.io/distributhor/workflow-webhook-container:v3.0.8' 42 | 43 | branding: 44 | icon: 'terminal' 45 | color: 'gray-dark' 46 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Enable the printing of trace messages 4 | set -o errtrace 5 | trap 'echo "Error occurred on line $BASH_LINENO"; exit 1' ERR 6 | 7 | # Github Inputs/Envs Fix: Iterate over environment variables starting with INPUT_ and export them as lowercase variables without input_ prefix. 8 | for var in "${!INPUT_@}"; do 9 | # Remove the INPUT_ prefix 10 | name="${var#INPUT_}" 11 | 12 | # Convert name to lowercase 13 | name_lower="${name,,}" 14 | 15 | # Access the value of the environment variable 16 | value="${!var}" 17 | 18 | # Check if the variable is already exported 19 | if [[ -z "${!name_lower+x}" ]]; then 20 | if [ "$fine" = true ]; then 21 | # Export the variable if it's not already present 22 | echo "INFO: Converting INPUT_${name}=$value to $name_lower=$value" 23 | fi 24 | export "$name_lower"="$value" 25 | else 26 | echo "WARN: Variable already exists with $(env | grep "${name_lower}="), not exporting." 27 | fi 28 | done 29 | 30 | # For backwards compatibility, 31 | # may be deprecated in future major version 32 | if [ -n "$WEBHOOK_AUTH" ]; then 33 | webhook_auth=$WEBHOOK_AUTH 34 | fi 35 | 36 | if [ -n "$WEBHOOK_AUTH_TYPE" ]; then 37 | webhook_auth_type=$WEBHOOK_AUTH_TYPE 38 | fi 39 | 40 | if [ -n "$WEBHOOK_SECRET" ]; then 41 | webhook_secret=$WEBHOOK_SECRET 42 | fi 43 | 44 | if [ -n "$WEBHOOK_TYPE" ]; then 45 | webhook_type=$WEBHOOK_TYPE 46 | fi 47 | 48 | if [ -n "$WEBHOOK_URL" ]; then 49 | webhook_url=$WEBHOOK_URL 50 | fi 51 | 52 | if [ -n "$SILENT" ]; then 53 | silent=$SILENT 54 | fi 55 | 56 | if [ -n "$VERBOSE" ]; then 57 | verbose=$VERBOSE 58 | fi 59 | 60 | if [ -n "$VERIFY_SSL" ]; then 61 | verify_ssl=$VERIFY_SSL 62 | fi 63 | 64 | if [ -n "$TIMEOUT" ]; then 65 | timeout=$TIMEOUT 66 | fi 67 | 68 | if [ -n "$MAX_TIME" ]; then 69 | max_time=$MAX_TIME 70 | fi 71 | 72 | if [ -n "$CURL_OPTS" ]; then 73 | curl_opts=$CURL_OPTS 74 | fi 75 | 76 | if [ -n "$EVENT_NAME" ]; then 77 | event_name=$EVENT_NAME 78 | fi 79 | 80 | if [ -n "$DATA" ]; then 81 | data=$DATA 82 | fi 83 | 84 | urlencode() { 85 | local length="${#1}" 86 | for (( i = 0; i < length; i++ )); do 87 | local c="${1:i:1}" 88 | case $c in 89 | [a-zA-Z0-9.~_-]) printf "$c" ;; 90 | *) printf '%s' "$c" | xxd -p -c1 | 91 | while read c; do printf '%%%s' "$c"; done ;; 92 | esac 93 | done 94 | } 95 | 96 | urldecode() { 97 | local url_encoded="${1//+/ }" 98 | printf '%b' "${url_encoded//%/\\x}" 99 | } 100 | 101 | set -e 102 | 103 | if [ -z "$webhook_url" ]; then 104 | echo "No webhook_url configured" 105 | exit 1 106 | fi 107 | 108 | if [ -z "$webhook_secret" ]; then 109 | webhook_secret=$webhook_url 110 | fi 111 | 112 | # 113 | # This method does not require additional package installation (of util-linux) 114 | # on docker image, resulting in a slightly smaller image file 115 | # 116 | # REQUEST_ID=$(cat /dev/urandom | tr -dc '0-9a-f' | fold -w 32 | head -n 1) 117 | 118 | # 119 | # This method is cleaner, but requires util-linux to be installed on Alpine image, 120 | # resuling in a slightly larger image file 121 | # 122 | REQUEST_ID=$(uuidgen) 123 | 124 | if [ "$silent" != true ]; then 125 | echo "Webhook Request ID: $REQUEST_ID" 126 | fi 127 | 128 | if [ -n "$event_name" ]; then 129 | EVENT_NAME=$event_name 130 | else 131 | EVENT_NAME=$GITHUB_EVENT_NAME 132 | fi 133 | 134 | if [ -n "$webhook_type" ] && [ "$webhook_type" == "form-urlencoded" ]; then 135 | EVENT=`urlencode "$EVENT_NAME"` 136 | REPOSITORY=`urlencode "$GITHUB_REPOSITORY"` 137 | COMMIT=`urlencode "$GITHUB_SHA"` 138 | REF=`urlencode "$GITHUB_REF"` 139 | HEAD=`urlencode "$GITHUB_HEAD_REF"` 140 | WORKFLOW=`urlencode "$GITHUB_WORKFLOW"` 141 | 142 | CONTENT_TYPE="application/x-www-form-urlencoded" 143 | WEBHOOK_DATA="event=$EVENT&repository=$REPOSITORY&commit=$COMMIT&ref=$REF&head=$HEAD&workflow=$WORKFLOW&requestID=$REQUEST_ID" 144 | 145 | if [ -n "$data" ]; then 146 | WEBHOOK_DATA="${WEBHOOK_DATA}&${data}" 147 | fi 148 | else 149 | CONTENT_TYPE="application/json" 150 | 151 | if [ -n "$webhook_type" ] && [ "$webhook_type" == "json-extended" ]; then 152 | RAW_FILE_DATA=`cat $GITHUB_EVENT_PATH` 153 | WEBHOOK_DATA=$(echo -n "$RAW_FILE_DATA" | jq -c '.') 154 | else 155 | WEBHOOK_DATA=$(jo event="$EVENT_NAME" repository="$GITHUB_REPOSITORY" commit="$GITHUB_SHA" ref="$GITHUB_REF" head="$GITHUB_HEAD_REF" workflow="$GITHUB_WORKFLOW") 156 | fi 157 | 158 | if [ -n "$data" ]; then 159 | CUSTOM_JSON_DATA=$(echo -n "$data" | jq -c '.') 160 | WEBHOOK_DATA=$(jq -s '.[0] * .[1]' <(echo $WEBHOOK_DATA) <(jo requestID="$REQUEST_ID" data="$CUSTOM_JSON_DATA")) 161 | else 162 | WEBHOOK_DATA=$(jq -s '.[0] * .[1]' <(echo $WEBHOOK_DATA) <(jo requestID="$REQUEST_ID")) 163 | fi 164 | fi 165 | 166 | WEBHOOK_SIGNATURE=$(echo -n "$WEBHOOK_DATA" | openssl dgst -sha1 -hmac "$webhook_secret" -binary | xxd -p) 167 | WEBHOOK_SIGNATURE_256=$(echo -n "$WEBHOOK_DATA" | openssl dgst -sha256 -hmac "$webhook_secret" -binary | xxd -p |tr -d '\n') 168 | WEBHOOK_ENDPOINT=$webhook_url 169 | 170 | if [ -n "$webhook_auth_type" ] && [ "$webhook_auth_type" == "bearer" ]; then 171 | auth_type="bearer" 172 | elif [ -n "$webhook_auth_type" ] && [ "$webhook_auth_type" == "header" ]; then 173 | auth_type="header" 174 | else 175 | auth_type="basic" 176 | fi 177 | 178 | if [ -n "$webhook_auth" ] && [ "$auth_type" == "basic" ]; then 179 | WEBHOOK_ENDPOINT="-u $webhook_auth $webhook_url" 180 | fi 181 | 182 | options="--http1.1 --fail-with-body" 183 | 184 | if [ "$verbose" = true ]; then 185 | options="$options -v" 186 | options="$options -sS" 187 | elif [ "$silent" = true ]; then 188 | options="$options -s" 189 | else 190 | # The -s disables the progress meter, as well as error messages. 191 | # We want Curl to report errors, which we reenable with -S 192 | options="$options -sS" 193 | fi 194 | 195 | if [ "$verify_ssl" = false ]; then 196 | options="$options -k" 197 | fi 198 | 199 | if [ -n "$timeout" ]; then 200 | options="$options --connect-timeout $timeout" 201 | fi 202 | 203 | if [ -n "$max_time" ]; then 204 | options="$options --max-time $max_time" 205 | fi 206 | 207 | if [ -n "$curl_opts" ]; then 208 | options="$options $curl_opts" 209 | fi 210 | 211 | if [ "$verbose" = true ]; then 212 | echo "curl $options \\" 213 | echo "-H 'Content-Type: $CONTENT_TYPE' \\" 214 | echo "-H 'User-Agent: GitHub-Hookshot/$REQUEST_ID' \\" 215 | echo "-H 'X-Hub-Signature: sha1=$WEBHOOK_SIGNATURE' \\" 216 | echo "-H 'X-Hub-Signature-256: sha256=$WEBHOOK_SIGNATURE_256' \\" 217 | echo "-H 'X-GitHub-Delivery: $REQUEST_ID' \\" 218 | echo "-H 'X-GitHub-Event: $EVENT_NAME' \\" 219 | echo "-H 'Connection: close' \\" 220 | echo "--data '$WEBHOOK_DATA'" 221 | fi 222 | 223 | set +e 224 | 225 | # auth_header='' 226 | 227 | if [ -n "$webhook_auth" ] && [ "$auth_type" == "bearer" ]; then 228 | # auth_header="-H \"Authorization: Bearer $webhook_auth\"" 229 | response=$(curl $options \ 230 | -H "Authorization: Bearer $webhook_auth" \ 231 | -H "Content-Type: $CONTENT_TYPE" \ 232 | -H "User-Agent: GitHub-Hookshot/$REQUEST_ID" \ 233 | -H "X-Hub-Signature: sha1=$WEBHOOK_SIGNATURE" \ 234 | -H "X-Hub-Signature-256: sha256=$WEBHOOK_SIGNATURE_256" \ 235 | -H "X-GitHub-Delivery: $REQUEST_ID" \ 236 | -H "X-GitHub-Event: $EVENT_NAME" \ 237 | -H "Connection: close" \ 238 | --data "$WEBHOOK_DATA" $WEBHOOK_ENDPOINT) 239 | elif [ -n "$webhook_auth" ] && [ "$auth_type" == "header" ]; then 240 | header_name=`[[ $webhook_auth =~ ([^:]*) ]] && echo "${BASH_REMATCH[1]}"` 241 | header_value=`[[ $webhook_auth =~ :(.*) ]] && echo "${BASH_REMATCH[1]}"` 242 | if [ -z "$header_value" ]; then 243 | # if the webhook_auth value contains no colon, then it is a configuration error 244 | # we should not handle such cases, but in instead of throwing an error, we try 245 | # and consider a potential fail-safe for user error, and resort to setting the 246 | # entire value as an Authorization token - the attempt at trying to resolve what 247 | # the author meant may or may not be a better approach than just letting it error? 248 | # 249 | # auth_header="-H \"Authorization: $webhook_auth\"" 250 | response=$(curl $options \ 251 | -H "Authorization: $webhook_auth" \ 252 | -H "Content-Type: $CONTENT_TYPE" \ 253 | -H "User-Agent: GitHub-Hookshot/$REQUEST_ID" \ 254 | -H "X-Hub-Signature: sha1=$WEBHOOK_SIGNATURE" \ 255 | -H "X-Hub-Signature-256: sha256=$WEBHOOK_SIGNATURE_256" \ 256 | -H "X-GitHub-Delivery: $REQUEST_ID" \ 257 | -H "X-GitHub-Event: $EVENT_NAME" \ 258 | -H "Connection: close" \ 259 | --data "$WEBHOOK_DATA" $WEBHOOK_ENDPOINT) 260 | else 261 | # auth_header="-H \"$header_name: $header_value\"" 262 | response=$(curl $options \ 263 | -H "$header_name: $header_value" \ 264 | -H "Content-Type: $CONTENT_TYPE" \ 265 | -H "User-Agent: GitHub-Hookshot/$REQUEST_ID" \ 266 | -H "X-Hub-Signature: sha1=$WEBHOOK_SIGNATURE" \ 267 | -H "X-Hub-Signature-256: sha256=$WEBHOOK_SIGNATURE_256" \ 268 | -H "X-GitHub-Delivery: $REQUEST_ID" \ 269 | -H "X-GitHub-Event: $EVENT_NAME" \ 270 | -H "Connection: close" \ 271 | --data "$WEBHOOK_DATA" $WEBHOOK_ENDPOINT) 272 | fi 273 | else 274 | response=$(curl $options \ 275 | -H "Content-Type: $CONTENT_TYPE" \ 276 | -H "User-Agent: GitHub-Hookshot/$REQUEST_ID" \ 277 | -H "X-Hub-Signature: sha1=$WEBHOOK_SIGNATURE" \ 278 | -H "X-Hub-Signature-256: sha256=$WEBHOOK_SIGNATURE_256" \ 279 | -H "X-GitHub-Delivery: $REQUEST_ID" \ 280 | -H "X-GitHub-Event: $EVENT_NAME" \ 281 | -H "Connection: close" \ 282 | --data "$WEBHOOK_DATA" $WEBHOOK_ENDPOINT) 283 | fi 284 | 285 | # headers="-H \"Content-Type: $CONTENT_TYPE\"" 286 | # headers="$headers -H \"User-Agent: GitHub-Hookshot/$REQUEST_ID\"" 287 | # headers="$headers -H \"X-Hub-Signature: sha1=$WEBHOOK_SIGNATURE\"" 288 | # headers="$headers -H \"X-Hub-Signature-256: sha256=$WEBHOOK_SIGNATURE_256\"" 289 | # headers="$headers -H \"X-GitHub-Delivery: $REQUEST_ID\"" 290 | # headers="$headers -H \"X-GitHub-Event: $EVENT_NAME\"" 291 | # headers="$headers -H \"Connection: close\"" 292 | 293 | # if [ "$verbose" = true ]; then 294 | # echo "curl $options \\" 295 | # if [ -n "$auth_header" ]; then 296 | # echo "$auth_header $headers \\" 297 | # else 298 | # echo "$headers \\" 299 | # fi 300 | # echo "--data '$WEBHOOK_DATA'" 301 | # # some console logs will remove the log statement if its a URL 302 | # # so we need to remove the protocol if we want to display this 303 | # noproto_webhook_url=`echo $WEBHOOK_ENDPOINT | sed -E 's/^\s*.*:\/\///g'` 304 | # echo "WEBHOOK_ENDPOINT: $noproto_webhook_url" 305 | # fi 306 | 307 | # set +e 308 | 309 | # response=$(curl $options $auth_header $headers --data "$WEBHOOK_DATA" $WEBHOOK_ENDPOINT) 310 | 311 | CURL_STATUS=$? 312 | 313 | # echo "response-body=$response" >> $GITHUB_OUTPUT 314 | echo "response-body<<$REQUEST_ID" >> $GITHUB_OUTPUT 315 | echo "$response" >> $GITHUB_OUTPUT 316 | echo "$REQUEST_ID" >> $GITHUB_OUTPUT 317 | 318 | if [ "$verbose" = true ]; then 319 | echo "Webhook Response [$CURL_STATUS]:" 320 | echo "${response}" 321 | fi 322 | 323 | exit $CURL_STATUS 324 | --------------------------------------------------------------------------------