mirror of
https://github.com/thegeeklab/wp-matrix.git
synced 2024-11-24 23:30:40 +00:00
fix: fix multiline template rendering and add test (#59)
This commit is contained in:
parent
af84b2a8af
commit
4221876450
@ -36,8 +36,16 @@ properties:
|
|||||||
Golang template for the message. The [Metadata struct](https://pkg.go.dev/github.com/thegeeklab/wp-plugin-go/plugin#Metadata)
|
Golang template for the message. The [Metadata struct](https://pkg.go.dev/github.com/thegeeklab/wp-plugin-go/plugin#Metadata)
|
||||||
is exposed to the template and all fields can be referenced. To extend the functionality, [sprig functions](https://masterminds.github.io/sprig/) can also be used.
|
is exposed to the template and all fields can be referenced. To extend the functionality, [sprig functions](https://masterminds.github.io/sprig/) can also be used.
|
||||||
defaultValue: |
|
defaultValue: |
|
||||||
Status: **{{ .Pipeline.Status }}**<br/>
|
Status: **{{ .Pipeline.Status }}**
|
||||||
Build: [{{ .Repository.Slug }}]({{ .Pipeline.URL }}){{ if .Curr.Branch }} ({{ .Curr.Branch }}){{ end }} by {{ .Curr.Author.Name }}<br/>
|
Build: [{{ .Repository.Slug }}]({{ .Pipeline.URL }}){{ if .Curr.Branch }} ({{ .Curr.Branch }}){{ end }} by {{ .Curr.Author.Name }}
|
||||||
Message: {{ .Curr.Message }}{{ if .Curr.URL }} ([source]({{ .Curr.URL }})){{ end }}
|
Message: {{ .Curr.Message }}{{ if .Curr.URL }} ([source]({{ .Curr.URL }})){{ end }}
|
||||||
type: string
|
type: string
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
|
- name: template_unsafe
|
||||||
|
description: |
|
||||||
|
By default, raw HTML and potentially dangerous links in the template are not rendered. If you want to use inline HTML, you may need to turn this on.
|
||||||
|
In such cases, please ensure that the CI configuration files in the Git repository are protected against malicious changes.
|
||||||
|
defaultValue: false
|
||||||
|
type: bool
|
||||||
|
required: false
|
||||||
|
@ -11,13 +11,6 @@ import (
|
|||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint:lll
|
|
||||||
const defaultTemplate = `
|
|
||||||
Status: **{{ .Pipeline.Status }}**<br/>
|
|
||||||
Build: [{{ .Repository.Slug }}]({{ .Pipeline.URL }}){{ if .Curr.Branch }} ({{ .Curr.Branch }}){{ end }} by {{ .Curr.Author.Name }}<br/>
|
|
||||||
Message: {{ .Curr.Title }}{{ if .Curr.URL }} ([source]({{ .Curr.URL }})){{ end }}
|
|
||||||
`
|
|
||||||
|
|
||||||
// settingsFlags has the cli.Flags for the plugin.Settings.
|
// settingsFlags has the cli.Flags for the plugin.Settings.
|
||||||
func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||||
return []cli.Flag{
|
return []cli.Flag{
|
||||||
@ -68,9 +61,16 @@ func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
|||||||
Name: "template",
|
Name: "template",
|
||||||
EnvVars: []string{"PLUGIN_TEMPLATE", "MATRIX_TEMPLATE"},
|
EnvVars: []string{"PLUGIN_TEMPLATE", "MATRIX_TEMPLATE"},
|
||||||
Usage: "message template",
|
Usage: "message template",
|
||||||
Value: defaultTemplate,
|
Value: plugin.DefaultMessageTemplate,
|
||||||
Destination: &settings.Template,
|
Destination: &settings.Template,
|
||||||
Category: category,
|
Category: category,
|
||||||
},
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "template-unsafe",
|
||||||
|
EnvVars: []string{"PLUGIN_TEMPLATE_UNSAFE", "MATRIX_TEMPLATE_UNSAFE"},
|
||||||
|
Usage: "render raw HTML and potentially dangerous links in template",
|
||||||
|
Destination: &settings.TemplateUnsafe,
|
||||||
|
Category: category,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/microcosm-cc/bluemonday"
|
"github.com/microcosm-cc/bluemonday"
|
||||||
@ -75,14 +76,11 @@ func (p *Plugin) Execute() error {
|
|||||||
return fmt.Errorf("failed to join room: %w", err)
|
return fmt.Errorf("failed to join room: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
message, err := template.RenderTrim(p.Network.Context, *p.Network.Client, p.Settings.Template, p.Metadata)
|
content, err := p.messageContent(p.Network.Context, *p.Network.Client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to render template: %w", err)
|
return fmt.Errorf("failed to render template: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
formatted := bluemonday.UGCPolicy().SanitizeBytes([]byte(message))
|
|
||||||
content := format.RenderMarkdown(string(formatted), true, false)
|
|
||||||
|
|
||||||
if _, err := client.SendMessageEvent(joined.RoomID, event.EventMessage, content); err != nil {
|
if _, err := client.SendMessageEvent(joined.RoomID, event.EventMessage, content); err != nil {
|
||||||
return fmt.Errorf("failed to submit message: %w", err)
|
return fmt.Errorf("failed to submit message: %w", err)
|
||||||
}
|
}
|
||||||
@ -92,6 +90,26 @@ func (p *Plugin) Execute() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Plugin) messageContent(ctx context.Context, client http.Client) (event.MessageEventContent, error) {
|
||||||
|
message, err := template.RenderTrim(ctx, client, p.Settings.Template, p.Metadata)
|
||||||
|
if err != nil {
|
||||||
|
return event.MessageEventContent{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
content := format.RenderMarkdown(message, true, p.Settings.TemplateUnsafe)
|
||||||
|
|
||||||
|
safeBody := format.HTMLToMarkdown(bluemonday.UGCPolicy().Sanitize(content.FormattedBody))
|
||||||
|
if content.Body != safeBody {
|
||||||
|
content.Body = safeBody
|
||||||
|
}
|
||||||
|
|
||||||
|
if content.FormattedBody != "" {
|
||||||
|
content.FormattedBody = bluemonday.UGCPolicy().Sanitize(content.FormattedBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
return content, nil
|
||||||
|
}
|
||||||
|
|
||||||
func prepend(prefix, input string) string {
|
func prepend(prefix, input string) string {
|
||||||
if strings.TrimSpace(input) == "" {
|
if strings.TrimSpace(input) == "" {
|
||||||
return input
|
return input
|
||||||
|
78
plugin/impl_test.go
Normal file
78
plugin/impl_test.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
wp "github.com/thegeeklab/wp-plugin-go/plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_messageContent(t *testing.T) {
|
||||||
|
//nolint:lll
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
want string
|
||||||
|
unsafe bool
|
||||||
|
template string
|
||||||
|
meta wp.Metadata
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "render default template",
|
||||||
|
want: "Status: **success**\nBuild: [octocat/demo](https://ci.example.com) (main) by octobot\nMessage: feat: demo commit title ([source](https://git.example.com))",
|
||||||
|
template: DefaultMessageTemplate,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "render unsafe html template",
|
||||||
|
want: "Status: **success**\nBuild: octocat/demo",
|
||||||
|
unsafe: true,
|
||||||
|
template: "Status: **{{ .Pipeline.Status }}**<br>Build: {{ .Repository.Slug }}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "render html xss template",
|
||||||
|
want: "Status: **success**\nBuild: octocat/demo",
|
||||||
|
unsafe: true,
|
||||||
|
template: "Status: **{{ .Pipeline.Status }}**<br>Build: <a href=\"javascript:alert('XSS1')\" onmouseover=\"alert('XSS2')\">{{ .Repository.Slug }}<a>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "render markdown xss template",
|
||||||
|
want: "Status: **success**\nBuild: octocat/demo",
|
||||||
|
unsafe: true,
|
||||||
|
template: "Status: **{{ .Pipeline.Status }}**<br>Build: [{{ .Repository.Slug }}](javascript:alert(XSS1'))",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
options := wp.Options{
|
||||||
|
Name: "wp-matrix",
|
||||||
|
Execute: func(ctx context.Context) error { return nil },
|
||||||
|
}
|
||||||
|
|
||||||
|
p := New(options, &Settings{})
|
||||||
|
p.Metadata = wp.Metadata{
|
||||||
|
Curr: wp.Commit{
|
||||||
|
Branch: "main",
|
||||||
|
Title: "feat: demo commit title",
|
||||||
|
URL: "https://git.example.com",
|
||||||
|
Author: wp.Author{
|
||||||
|
Name: "octobot",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Pipeline: wp.Pipeline{
|
||||||
|
Status: "success",
|
||||||
|
URL: "https://ci.example.com",
|
||||||
|
},
|
||||||
|
Repository: wp.Repository{
|
||||||
|
Slug: "octocat/demo",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
p.Settings.Template = tt.template
|
||||||
|
p.Settings.TemplateUnsafe = tt.unsafe
|
||||||
|
content, _ := p.messageContent(context.Background(), http.Client{})
|
||||||
|
|
||||||
|
if content.Body != tt.want {
|
||||||
|
t.Errorf("messageContent: %q got: %q, want: %q", tt.name, content.Body, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,13 @@ import (
|
|||||||
wp "github.com/thegeeklab/wp-plugin-go/plugin"
|
wp "github.com/thegeeklab/wp-plugin-go/plugin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:lll
|
||||||
|
const DefaultMessageTemplate = `
|
||||||
|
Status: **{{ .Pipeline.Status }}**
|
||||||
|
Build: [{{ .Repository.Slug }}]({{ .Pipeline.URL }}){{ if .Curr.Branch }} ({{ .Curr.Branch }}){{ end }} by {{ .Curr.Author.Name }}
|
||||||
|
Message: {{ .Curr.Title }}{{ if .Curr.URL }} ([source]({{ .Curr.URL }})){{ end }}
|
||||||
|
`
|
||||||
|
|
||||||
// Plugin implements provide the plugin.
|
// Plugin implements provide the plugin.
|
||||||
type Plugin struct {
|
type Plugin struct {
|
||||||
*wp.Plugin
|
*wp.Plugin
|
||||||
@ -18,13 +25,14 @@ type Plugin struct {
|
|||||||
|
|
||||||
// Settings for the plugin.
|
// Settings for the plugin.
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
Username string
|
Username string
|
||||||
Password string
|
Password string
|
||||||
UserID string
|
UserID string
|
||||||
AccessToken string
|
AccessToken string
|
||||||
Homeserver string
|
Homeserver string
|
||||||
RoomID string
|
RoomID string
|
||||||
Template string
|
Template string
|
||||||
|
TemplateUnsafe bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(options wp.Options, settings *Settings) *Plugin {
|
func New(options wp.Options, settings *Settings) *Plugin {
|
||||||
|
Loading…
Reference in New Issue
Block a user