Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Chandler <wchandler@gitlab.com>2022-09-01 21:21:51 +0300
committerWill Chandler <wchandler@gitlab.com>2022-09-01 21:54:27 +0300
commite22d809f60467fa63a8be52d610d032cf0a0d7bb (patch)
treee1c8222378b09546548744d121ff5ead013ca279
parent69420b517a18582cfefeab4297c0ac2456b96de8 (diff)
praefect: Read line-by-line in track-repositories
When parsing invalid input `json.Decoder` may go into an infinite loop and consume an unbounded amount of memory. Admins who accidentally pass a badly formatted file to `track-repositories` are at risk of accidentally triggering OOM kills as a result. To mitigate this risk, let's read the input line-by-line and then attempt to unmarshall it, which will gracefully fail on invalid JSON. This does prevent us from checking for unexpected fields in the input, but so long as the expected fields are present extra data isn't a problem.
-rw-r--r--cmd/praefect/subcmd_track_repositories.go12
-rw-r--r--cmd/praefect/subcmd_track_repositories_test.go6
2 files changed, 9 insertions, 9 deletions
diff --git a/cmd/praefect/subcmd_track_repositories.go b/cmd/praefect/subcmd_track_repositories.go
index 44bdb8c71..a5ebac7c7 100644
--- a/cmd/praefect/subcmd_track_repositories.go
+++ b/cmd/praefect/subcmd_track_repositories.go
@@ -1,6 +1,7 @@
package main
import (
+ "bufio"
"context"
"encoding/json"
"flag"
@@ -55,8 +56,8 @@ func (cmd *trackRepositories) FlagSet() *flag.FlagSet {
printfErr("Description:\n" +
" This command allows bulk requests for repositories to be tracked by Praefect.\n" +
" The -input-path flag must be the path of a file containing the details of the repositories\n" +
- " to track as a list of newline-delimited JSON objects. Each entry must contain the\n" +
- " following keys:\n\n" +
+ " to track as a list of newline-delimited JSON objects. Each line must contain the details for\n" +
+ " one and only one repository. Each item must contain the following keys:\n\n" +
" relative_path - The relative path of the repository on-disk.\n" +
" virtual_storage - The Praefect virtual storage name.\n" +
" authoritative_storage - Which storage to consider as the canonical copy of the repository.\n\n" +
@@ -92,8 +93,7 @@ func (cmd trackRepositories) Exec(flags *flag.FlagSet, cfg config.Config) error
}
defer f.Close()
- d := json.NewDecoder(f)
- d.DisallowUnknownFields()
+ scanner := bufio.NewScanner(f)
fmt.Fprintf(cmd.w, "Validating repository information in %q\n", cmd.inputPath)
@@ -105,13 +105,13 @@ func (cmd trackRepositories) Exec(flags *flag.FlagSet, cfg config.Config) error
// Read in and validate all requests from input file before executing. This prevents us from
// partially executing a file, which makes it difficult to tell which repos were actually
// tracked.
- for d.More() {
+ for scanner.Scan() {
repoNum++
request := trackRepositoryRequest{}
badReq := invalidRequest{reqNum: repoNum}
- if err := d.Decode(&request); err != nil {
+ if err := json.Unmarshal(scanner.Bytes(), &request); err != nil {
badReq.errs = append(badReq.errs, err)
repoErrs = append(repoErrs, badReq)
diff --git a/cmd/praefect/subcmd_track_repositories_test.go b/cmd/praefect/subcmd_track_repositories_test.go
index cd8e97a1b..c644f88d2 100644
--- a/cmd/praefect/subcmd_track_repositories_test.go
+++ b/cmd/praefect/subcmd_track_repositories_test.go
@@ -109,9 +109,9 @@ func TestAddRepositories_Exec_invalidInput(t *testing.T) {
expectedError: "no repository information found",
},
{
- input: `{"foo":"bar"}`,
- desc: "unexpected key in JSON",
- expectedOutput: `json: unknown field "foo"`,
+ input: "@hashed/01/23/01234567890123456789.git",
+ desc: "invalid JSON",
+ expectedOutput: "invalid character '@' looking for beginning of value",
expectedError: invalidEntryErr,
},
{