Skip to content

Commit

Permalink
Add initial support for Workflow connectors
Browse files Browse the repository at this point in the history
- lower `AdaptiveCardMaxVersion` from `1.5` to `1.4`
  - this almost seems like a bug on Teams' end as this limitation is
    not communicated (from what I could tell) via
    https://adaptivecards.io/designer/
  - using a value of `1.4` appears to work equally well for O365 and
    Workflow connectors
- treat a 202 response code as sufficient response verification
  - instead of expecting a `1` in the response body as previously
    confirmed
  - see also #59
- add `logic.azure.com` to valid URL patterns for default validation
- debugging / troubleshooting
    - log status code and response string for O365 connector responses
    - log validation pattern match

refs GH-262
  • Loading branch information
atc0005 committed Jul 24, 2024
1 parent 56c6bcf commit 245024b
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 4 deletions.
8 changes: 7 additions & 1 deletion adaptivecard/adaptivecard.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,13 @@ const (
//
// https://docs.microsoft.com/en-us/microsoftteams/platform/task-modules-and-cards/cards/cards-reference#support-for-adaptive-cards
// https://adaptivecards.io/designer
AdaptiveCardMaxVersion float64 = 1.5
//
// NOTE: Documented as 1.5 (adaptivecards.io/designer), but in practice >
// 1.4 is rejected for Power Automate workflow connectors.
//
// Setting to 1.4 works both for legacy O365 connectors and Workflow
// connectors.
AdaptiveCardMaxVersion float64 = 1.4
AdaptiveCardMinVersion float64 = 1.0
AdaptiveCardVersionTmpl string = "%0.1f"
)
Expand Down
36 changes: 33 additions & 3 deletions send.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ const (
WebhookURLOrgWebhookPrefix = "https://example.webhook.office.com"
)

// Known Workflow URL patterns for submitting messages to Microsoft Teams.
const (
WorkflowURLBaseDomain = "logic.azure.com"

Check failure

Code scanning / CodeQL

Missing regular expression anchor High

When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it.

Check failure

Code scanning / CodeQL

Incomplete regular expression for hostnames High

This regular expression has an unescaped dot before 'azure.com', so it might match more hosts than expected when
the regular expression is used
.
)

// DisableWebhookURLValidation is a special keyword used to indicate to
// validation function(s) that webhook URL validation should be disabled.
//
Expand Down Expand Up @@ -380,6 +385,7 @@ func processResponse(response *http.Response) (string, error) {
}
responseString := string(responseData)

// TODO: Refactor for v3 series once O365 connector support is dropped.
switch {
// 400 Bad Response is likely an indicator that we failed to provide a
// required field in our JSON payload. For example, when leaving out the
Expand All @@ -393,15 +399,34 @@ func processResponse(response *http.Response) (string, error) {

return "", err

// Microsoft Teams developers have indicated that a 200 status code is
// insufficient to confirm that a message was successfully submitted.
case response.StatusCode == 202:
// 202 Accepted response is expected for Workflow connector URL
// submissions.

logger.Println("202 Accepted response received as expected for workflow connector")

return responseString, nil

// DEPRECATED
//
// See https://github.com/atc0005/go-teams-notify/issues/262
//
// Microsoft Teams developers have indicated that receiving a 200 status
// code when submitting payloads to O365 connectors is insufficient to
// confirm that a message was successfully submitted.
//
// Instead, clients should ensure that a specific response string was also
// returned along with a 200 status code to confirm that a message was
// sent successfully. Because there is a chance that unintentional
// whitespace could be included, we explicitly strip it out.
//
// See atc0005/go-teams-notify#59 for more information.
case responseString != strings.TrimSpace(ExpectedWebhookURLResponseText):
logger.Printf(
"StatusCode: %v, Status: %v\n", response.StatusCode, response.Status,
)
logger.Printf("ResponseString: %v\n", responseString)

err = fmt.Errorf(
"got %q, expected %q: %w",
responseString,
Expand Down Expand Up @@ -432,7 +457,10 @@ func validateWebhook(webhookURL string, skipWebhookValidation bool, patterns []s
}

if len(patterns) == 0 {
patterns = []string{DefaultWebhookURLValidationPattern}
patterns = []string{
DefaultWebhookURLValidationPattern,
WorkflowURLBaseDomain,

Check failure

Code scanning / CodeQL

Missing regular expression anchor High

When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it.
}
}

// Indicate passing validation if at least one pattern matches.
Expand All @@ -442,6 +470,8 @@ func validateWebhook(webhookURL string, skipWebhookValidation bool, patterns []s
return err
}
if matched {
logger.Printf("Pattern %v matched", pat)

return nil
}
}
Expand Down

0 comments on commit 245024b

Please sign in to comment.