Skip to content

Commit 417ce33

Browse files
authored
ast: implement SensitiveStmtNode for BRIEStmt (pingcap#842)
1 parent 7559f56 commit 417ce33

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

ast/misc.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package ast
1616
import (
1717
"bytes"
1818
"fmt"
19+
"net/url"
1920
"strconv"
2021
"strings"
2122

@@ -2436,6 +2437,38 @@ func (n *BRIEStmt) Restore(ctx *format.RestoreCtx) error {
24362437
return nil
24372438
}
24382439

2440+
// SecureText implements SensitiveStmtNode
2441+
func (n *BRIEStmt) SecureText() string {
2442+
// FIXME: this solution is not scalable, and duplicates some logic from BR.
2443+
redactedStorage := n.Storage
2444+
u, err := url.Parse(n.Storage)
2445+
if err == nil {
2446+
if u.Scheme == "s3" {
2447+
query := u.Query()
2448+
for key := range query {
2449+
switch strings.ToLower(strings.ReplaceAll(key, "_", "-")) {
2450+
case "access-key", "secret-access-key":
2451+
query[key] = []string{"xxxxxx"}
2452+
}
2453+
}
2454+
u.RawQuery = query.Encode()
2455+
redactedStorage = u.String()
2456+
}
2457+
}
2458+
2459+
redactedStmt := &BRIEStmt{
2460+
Kind: n.Kind,
2461+
Schemas: n.Schemas,
2462+
Tables: n.Tables,
2463+
Storage: redactedStorage,
2464+
Options: n.Options,
2465+
}
2466+
2467+
var sb strings.Builder
2468+
_ = redactedStmt.Restore(format.NewRestoreCtx(format.DefaultRestoreFlags, &sb))
2469+
return sb.String()
2470+
}
2471+
24392472
// Ident is the table identifier composed of schema name and table name.
24402473
type Ident struct {
24412474
Schema model.CIStr

ast/misc_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package ast_test
1616
import (
1717
. "github.com/pingcap/check"
1818
"github.com/pingcap/parser"
19+
"github.com/pingcap/parser/ast"
1920
. "github.com/pingcap/parser/ast"
2021
"github.com/pingcap/parser/auth"
2122
"github.com/pingcap/parser/mysql"
@@ -277,3 +278,40 @@ func (ts *testMiscSuite) TestChangeStmtRestore(c *C) {
277278
}
278279
RunNodeRestoreTest(c, testCases, "%s", extractNodeFunc)
279280
}
281+
282+
func (ts *testMiscSuite) TestBRIESecureText(c *C) {
283+
testCases := []struct {
284+
input string
285+
secured string
286+
}{
287+
{
288+
input: "restore database * from 'local:///tmp/br01' snapshot = 23333",
289+
secured: `^\QRESTORE DATABASE * FROM 'local:///tmp/br01' SNAPSHOT = 23333\E$`,
290+
},
291+
{
292+
input: "backup database * to 's3://bucket/prefix?region=us-west-2'",
293+
secured: `^\QBACKUP DATABASE * TO 's3://bucket/prefix?region=us-west-2'\E$`,
294+
},
295+
{
296+
// we need to use regexp to match to avoid the random ordering since a map was used.
297+
// unfortunately Go's regexp doesn't support lookahead assertion, so the test case below
298+
// has false positives.
299+
input: "backup database * to 's3://bucket/prefix?access-key=abcdefghi&secret-access-key=123&force-path-style=true'",
300+
secured: `^\QBACKUP DATABASE * TO 's3://bucket/prefix?\E((access-key=xxxxxx|force-path-style=true|secret-access-key=xxxxxx)(&|'$)){3}`,
301+
},
302+
{
303+
input: "backup database * to 'gcs://bucket/prefix?access-key=irrelevant&credentials-file=/home/user/secrets.txt'",
304+
secured: `^\QBACKUP DATABASE * TO 'gcs://bucket/prefix?\E((access-key=irrelevant|credentials-file=/home/user/secrets\.txt)(&|'$)){2}`,
305+
},
306+
}
307+
308+
parser := parser.New()
309+
for _, tc := range testCases {
310+
comment := Commentf("input = %s", tc.input)
311+
node, err := parser.ParseOneStmt(tc.input, "", "")
312+
c.Assert(err, IsNil, comment)
313+
n, ok := node.(ast.SensitiveStmtNode)
314+
c.Assert(ok, IsTrue, comment)
315+
c.Assert(n.SecureText(), Matches, tc.secured, comment)
316+
}
317+
}

0 commit comments

Comments
 (0)