···1097 })
1098 conn.ExecContext(ctx, "pragma foreign_keys = on;")
10991100+ // knots may report the combined patch for a comparison, we can store that on the appview side
1101+ // (but not on the pds record), because calculating the combined patch requires a git index
1102+ runMigration(conn, logger, "add-combined-column-submissions", func(tx *sql.Tx) error {
1103+ _, err := tx.Exec(`
1104+ alter table pull_submissions add column combined text;
1105+ `)
1106+ return err
1107+ })
1108+1109 return &DB{
1110 db,
1111 logger,
···1+package validator
2+3+import (
4+ "fmt"
5+ "strings"
6+7+ "tangled.org/core/patchutil"
8+)
9+10+func (v *Validator) ValidatePatch(patch *string) error {
11+ if patch == nil || *patch == "" {
12+ return fmt.Errorf("patch is empty")
13+ }
14+15+ // add newline if not present to diff style patches
16+ if !patchutil.IsFormatPatch(*patch) && !strings.HasSuffix(*patch, "\n") {
17+ *patch = *patch + "\n"
18+ }
19+20+ if err := patchutil.IsPatchValid(*patch); err != nil {
21+ return err
22+ }
23+24+ return nil
25+}
+2-1
docs/knot-hosting.md
···39```
4041Next, move the `knot` binary to a location owned by `root` --
42-`/usr/local/bin/knot` is a good choice:
4344```
45sudo mv knot /usr/local/bin/knot
046```
4748This is necessary because SSH `AuthorizedKeysCommand` requires [really
···39```
4041Next, move the `knot` binary to a location owned by `root` --
42+`/usr/local/bin/` is a good choice. Make sure the binary itself is also owned by `root`:
4344```
45sudo mv knot /usr/local/bin/knot
46+sudo chown root:root /usr/local/bin/knot
47```
4849This is necessary because SSH `AuthorizedKeysCommand` requires [really