mirror of
https://github.com/thegeeklab/wp-matrix.git
synced 2024-11-21 14:20:41 +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)
|
||||
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: |
|
||||
Status: **{{ .Pipeline.Status }}**<br/>
|
||||
Build: [{{ .Repository.Slug }}]({{ .Pipeline.URL }}){{ if .Curr.Branch }} ({{ .Curr.Branch }}){{ end }} by {{ .Curr.Author.Name }}<br/>
|
||||
Status: **{{ .Pipeline.Status }}**
|
||||
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 }}
|
||||
type: string
|
||||
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"
|
||||
)
|
||||
|
||||
//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.
|
||||
func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
@ -68,9 +61,16 @@ func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
Name: "template",
|
||||
EnvVars: []string{"PLUGIN_TEMPLATE", "MATRIX_TEMPLATE"},
|
||||
Usage: "message template",
|
||||
Value: defaultTemplate,
|
||||
Value: plugin.DefaultMessageTemplate,
|
||||
Destination: &settings.Template,
|
||||
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"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
@ -75,14 +76,11 @@ func (p *Plugin) Execute() error {
|
||||
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 {
|
||||
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 {
|
||||
return fmt.Errorf("failed to submit message: %w", err)
|
||||
}
|
||||
@ -92,6 +90,26 @@ func (p *Plugin) Execute() error {
|
||||
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 {
|
||||
if strings.TrimSpace(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"
|
||||
)
|
||||
|
||||
//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.
|
||||
type Plugin struct {
|
||||
*wp.Plugin
|
||||
@ -25,6 +32,7 @@ type Settings struct {
|
||||
Homeserver string
|
||||
RoomID string
|
||||
Template string
|
||||
TemplateUnsafe bool
|
||||
}
|
||||
|
||||
func New(options wp.Options, settings *Settings) *Plugin {
|
||||
|
Loading…
Reference in New Issue
Block a user