Sanitize upon saving

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-03-30 17:52:25 +04:00
parent 62e68dfb6f
commit f3982f23f9
23 changed files with 471 additions and 356 deletions

View File

@@ -41,7 +41,7 @@ func TestDocument_Create(t *testing.T) {
name: "with full details",
input: map[string]any{
"title": "Security Policy",
"content": "This is the security policy content.",
"content": testutil.ProseMirrorTextDoc("This is the security policy content."),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -52,7 +52,7 @@ func TestDocument_Create(t *testing.T) {
name: "with POLICY type",
input: map[string]any{
"title": "Policy Document",
"content": "Policy content",
"content": testutil.ProseMirrorTextDoc("Policy content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -63,7 +63,7 @@ func TestDocument_Create(t *testing.T) {
name: "with PROCEDURE type",
input: map[string]any{
"title": "Procedure Document",
"content": "Procedure content",
"content": testutil.ProseMirrorTextDoc("Procedure content"),
"documentType": "PROCEDURE",
"classification": "INTERNAL",
},
@@ -74,7 +74,7 @@ func TestDocument_Create(t *testing.T) {
name: "with GOVERNANCE type",
input: map[string]any{
"title": "Governance Document",
"content": "Governance content",
"content": testutil.ProseMirrorTextDoc("Governance content"),
"documentType": "GOVERNANCE",
"classification": "INTERNAL",
},
@@ -85,7 +85,7 @@ func TestDocument_Create(t *testing.T) {
name: "with OTHER type",
input: map[string]any{
"title": "Other Document",
"content": "Other content",
"content": testutil.ProseMirrorTextDoc("Other content"),
"documentType": "OTHER",
"classification": "INTERNAL",
},
@@ -157,7 +157,7 @@ func TestDocument_Create_Validation(t *testing.T) {
name: "missing organizationId",
input: map[string]any{
"title": "Test Document",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -168,7 +168,7 @@ func TestDocument_Create_Validation(t *testing.T) {
name: "title with HTML tags",
input: map[string]any{
"title": "<script>alert('xss')</script>",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -178,7 +178,7 @@ func TestDocument_Create_Validation(t *testing.T) {
name: "title with newline",
input: map[string]any{
"title": "Test\nDocument",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -188,7 +188,7 @@ func TestDocument_Create_Validation(t *testing.T) {
name: "title with carriage return",
input: map[string]any{
"title": "Test\rDocument",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -198,7 +198,7 @@ func TestDocument_Create_Validation(t *testing.T) {
name: "title with null byte",
input: map[string]any{
"title": "Test\x00Document",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -208,7 +208,7 @@ func TestDocument_Create_Validation(t *testing.T) {
name: "title with tab character",
input: map[string]any{
"title": "Test\tDocument",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -218,7 +218,7 @@ func TestDocument_Create_Validation(t *testing.T) {
name: "title with zero-width space",
input: map[string]any{
"title": "Test\u200BDocument",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -228,7 +228,7 @@ func TestDocument_Create_Validation(t *testing.T) {
name: "title with zero-width joiner",
input: map[string]any{
"title": "Test\u200DDocument",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -238,7 +238,7 @@ func TestDocument_Create_Validation(t *testing.T) {
name: "title with right-to-left override",
input: map[string]any{
"title": "Test\u202EDocument",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -611,7 +611,7 @@ func TestDocument_Timestamps(t *testing.T) {
"input": map[string]any{
"organizationId": owner.GetOrganizationID().String(),
"title": "Timestamp Test Document",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -740,7 +740,7 @@ func TestDocument_RBAC(t *testing.T) {
"input": map[string]any{
"organizationId": owner.GetOrganizationID().String(),
"title": "RBAC Test Document",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -762,7 +762,7 @@ func TestDocument_RBAC(t *testing.T) {
"input": map[string]any{
"organizationId": admin.GetOrganizationID().String(),
"title": "RBAC Test Document",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -784,7 +784,7 @@ func TestDocument_RBAC(t *testing.T) {
"input": map[string]any{
"organizationId": viewer.GetOrganizationID().String(),
"title": "RBAC Test Document",
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -1007,7 +1007,7 @@ func TestDocument_MaxLength_Validation(t *testing.T) {
"input": map[string]any{
"organizationId": owner.GetOrganizationID().String(),
"title": longTitle,
"content": "Test content",
"content": testutil.ProseMirrorTextDoc("Test content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},

View File

@@ -73,7 +73,7 @@ func createTestDocument(t *testing.T, owner *testutil.Client) (docID string, doc
"input": map[string]any{
"organizationId": owner.GetOrganizationID().String(),
"title": "Test Document",
"content": "Initial content",
"content": testutil.ProseMirrorTextDoc("Initial content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -282,15 +282,17 @@ func TestDocumentVersion_UpdateContent(t *testing.T) {
} `json:"updateDocumentVersionContent"`
}
wantContent := testutil.ProseMirrorTextDoc("Updated content for the document version")
err := owner.Execute(query, map[string]any{
"input": map[string]any{
"id": draftVersionID,
"content": "Updated content for the document version",
"content": wantContent,
},
}, &result)
require.NoError(t, err)
assert.Equal(t, "Updated content for the document version", result.UpdateDocumentVersionContent.Content)
assert.JSONEq(t, wantContent, result.UpdateDocumentVersionContent.Content)
}
func TestDocumentVersion_RequestSignature(t *testing.T) {

View File

@@ -393,7 +393,7 @@ func TestControlDocumentMapping_CreateDelete(t *testing.T) {
"input": map[string]any{
"organizationId": owner.GetOrganizationID().String(),
"title": "Document for Control Mapping",
"content": "Document content",
"content": testutil.ProseMirrorTextDoc("Document content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},
@@ -781,7 +781,7 @@ func TestRiskDocumentMapping_CreateDelete(t *testing.T) {
"input": map[string]any{
"organizationId": owner.GetOrganizationID().String(),
"title": "Document for Risk Mapping",
"content": "Document content",
"content": testutil.ProseMirrorTextDoc("Document content"),
"documentType": "POLICY",
"classification": "INTERNAL",
},

View File

@@ -0,0 +1,40 @@
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package testutil
import (
"encoding/json"
)
// ProseMirrorTextDoc returns minimal ProseMirror/Tiptap JSON accepted by the API:
// a doc with one paragraph containing a single text node.
func ProseMirrorTextDoc(text string) string {
doc := map[string]any{
"type": "doc",
"content": []any{
map[string]any{
"type": "paragraph",
"content": []any{
map[string]any{"type": "text", "text": text},
},
},
},
}
b, err := json.Marshal(doc)
if err != nil {
panic(err)
}
return string(b)
}