cycloidio / webhook

webhook is a lightweight configurable tool written in Go, that allows you to easily create HTTP endpoints (hooks) on your server, which you can use to execute configured commands.
MIT License
1 stars 0 forks source link

Proposal: add suport of web API call instead of command #9

Open xlr-8 opened 8 years ago

xlr-8 commented 8 years ago

Proposal

As projects and software industry evolve towards API, providing the possibility to trigger API call instead of running commands could be great. To do so relying on oauth mechanism, supported by github/bitbucket/slack, seems the most logical/straight forward.

Implementation

Oauth token

Because of the way outgoing hooks are implemented it seems easier to add a parameter to the URL such as: access_token cf. RFC 2.3, that will be then forwarded as Authorization: Bearer $TOKEN cf. RFC 2.1

Now I'm aware of the security threat that it creates to have the token in the URL. However I believe everyone should be aware of such condition (the webhook documentation could be adapted, to emphasise it), but given the current possibilities provided by github/bitbucket/slack, I don't see much more solution around it. The use of SSL and also secrets is obviously advised.

Hook modifications

Adding API call, implies to have:

As specified in the previous section.

New Hook structure

Modification of the hooks structure - addition of APICall and PassArgumentsToAPI:

type Hook struct {
    ID                       string          `json:"id,omitempty"`
    ExecuteCommand           string          `json:"execute-command,omitempty"`
    CommandWorkingDirectory  string          `json:"command-working-directory,omitempty"`
    APICall                  string          `json:"execute-api-call,omitempty"`
    ResponseMessage          string          `json:"response-message,omitempty"`
    ResponseHeaders          ResponseHeaders `json:"response-headers,omitempty"`
    CaptureCommandOutput     bool            `json:"include-command-output-in-response,omitempty"`
    PassEnvironmentToCommand []Argument      `json:"pass-environment-to-command,omitempty"`
    PassArgumentsToCommand   []Argument      `json:"pass-arguments-to-command,omitempty"`
    PassArgumentsToAPI       []Argument      `json:"pass-arguments-to-api,omitempty"`
    JSONStringParameters     []Argument      `json:"parse-parameters-as-json,omitempty"`
    TriggerRule              *Rules          `json:"trigger-rule,omitempty"`
}
New argument/source type

Introduce two new source types: apiheader & apibody. Body would be like the default SourceString but would have to match apibody. Headers will be key/value parameters that should eventually be concatenated to avoid breaking the definition of the Get method:

func (ha *Argument) Get(headers, query, payload *map[string]interface{}) (string, bool) {

That would give something like this as source:

const (
    SourceHeader        string = "header"
    SourceQuery         string = "url"
    SourcePayload       string = "payload"
    SourceString        string = "string"
    SourceAPIHeader     string = "apiheader"
    SourceAPIBody       string = "apibody"
    SourceEntirePayload string = "entire-payload"
    SourceEntireQuery   string = "entire-query"
    SourceEntireHeaders string = "entire-headers"
)

The Argument struct would also have to be adapted to read body/headers. So two new variables are added to reflect the new implementation Name string & Key string:

type Argument struct {
    Source  string `json:"source,omitempty"`
    Name    string `json:"name,omitempty"`
    Key     string `json:"key,omitempty"`
    Value   string `json:"value,omitempty"`
    EnvName string `json:"envname,omitempty"`
}

The rest would follow the same logic: extraction of arguments, re-using them in the hookHandler & hookHandle methods.

Testing

The testing of the outgoing call, cannot of course be tested fully. So the idea would be to mock webhooks from github/bitbucket or slack, create the API call and then call a mini http-server mocking answers based on: missing body, missing headers, 4xx/5xx return code, etc.

Backward compatibility

There should not be any problem of backward compatibility as it is an addition of feature, thus both should remain possible at any time.

xlr-8 commented 8 years ago

After double consideration, I think that this issue will need to wait. Indeed we are currently not aware enough of what type of data we want/need to extract and where to set them.

The current proposal is very "static" oriented, but of course we might need to extract some information. E.g:

So until this is not clarify, it might be hard to work on this issue.