Skip to content

Commit ede7fdb

Browse files
DEVELOPER-DEEVENDEVELOPER-DEEVEN
authored andcommitted
fix(oracle): handle bracketed proxy usernames in go-ora URL
1 parent af146cf commit ede7fdb

File tree

10 files changed

+144
-96
lines changed

10 files changed

+144
-96
lines changed

.github/workflows/deploy_versioned_docs.yaml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ jobs:
3535
ref: ${{ github.event.release.tag_name }}
3636

3737
- name: Get Version from Release Tag
38-
run: echo "VERSION=${GITHUB_EVENT_RELEASE_TAG_NAME}" >> $GITHUB_ENV
39-
env:
40-
GITHUB_EVENT_RELEASE_TAG_NAME: ${{ github.event.release.tag_name }}
38+
run: echo "VERSION=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
4139

4240
- name: Setup Hugo
4341
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3

.github/workflows/link_checker_workflow.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jobs:
4141
--no-progress
4242
--cache
4343
--max-cache-age 1d
44+
--accept 200,206,302
4445
--exclude '^neo4j\+.*' --exclude '^bolt://.*'
4546
README.md
4647
docs/

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ require (
2929
github.com/fsnotify/fsnotify v1.9.0
3030
github.com/go-chi/chi/v5 v5.2.3
3131
github.com/go-chi/cors v1.2.2
32-
github.com/go-chi/httplog/v3 v3.3.0
32+
github.com/go-chi/httplog/v2 v2.1.1
3333
github.com/go-chi/render v1.0.3
3434
github.com/go-goquery/goquery v1.0.1
3535
github.com/go-playground/validator/v10 v10.28.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -902,8 +902,8 @@ github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
902902
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
903903
github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE=
904904
github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
905-
github.com/go-chi/httplog/v3 v3.3.0 h1:Gr6Y7nSzbpyCyRwKPOVKjDH3BH6TH5uvRNDsTZWDpvU=
906-
github.com/go-chi/httplog/v3 v3.3.0/go.mod h1:N/J1l5l1fozUrqIVuT8Z/HzNeSy8TF2EFyokPLe6y2w=
905+
github.com/go-chi/httplog/v2 v2.1.1 h1:ojojiu4PIaoeJ/qAO4GWUxJqvYUTobeo7zmuHQJAxRk=
906+
github.com/go-chi/httplog/v2 v2.1.1/go.mod h1:/XXdxicJsp4BA5fapgIC3VuTD+z0Z/VzukoB3VDc1YE=
907907
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
908908
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
909909
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=

internal/log/log.go

Lines changed: 8 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -59,35 +59,25 @@ func NewStdLogger(outW, errW io.Writer, logLevel string) (Logger, error) {
5959
}
6060

6161
// DebugContext logs debug messages
62-
func (sl *StdLogger) DebugContext(ctx context.Context, msg string, keysAndValues ...any) {
62+
func (sl *StdLogger) DebugContext(ctx context.Context, msg string, keysAndValues ...interface{}) {
6363
sl.outLogger.DebugContext(ctx, msg, keysAndValues...)
6464
}
6565

6666
// InfoContext logs debug messages
67-
func (sl *StdLogger) InfoContext(ctx context.Context, msg string, keysAndValues ...any) {
67+
func (sl *StdLogger) InfoContext(ctx context.Context, msg string, keysAndValues ...interface{}) {
6868
sl.outLogger.InfoContext(ctx, msg, keysAndValues...)
6969
}
7070

7171
// WarnContext logs warning messages
72-
func (sl *StdLogger) WarnContext(ctx context.Context, msg string, keysAndValues ...any) {
72+
func (sl *StdLogger) WarnContext(ctx context.Context, msg string, keysAndValues ...interface{}) {
7373
sl.errLogger.WarnContext(ctx, msg, keysAndValues...)
7474
}
7575

7676
// ErrorContext logs error messages
77-
func (sl *StdLogger) ErrorContext(ctx context.Context, msg string, keysAndValues ...any) {
77+
func (sl *StdLogger) ErrorContext(ctx context.Context, msg string, keysAndValues ...interface{}) {
7878
sl.errLogger.ErrorContext(ctx, msg, keysAndValues...)
7979
}
8080

81-
// SlogLogger returns a single standard *slog.Logger that routes
82-
// records to the outLogger or errLogger based on the log level.
83-
func (sl *StdLogger) SlogLogger() *slog.Logger {
84-
splitHandler := &SplitHandler{
85-
OutHandler: sl.outLogger.Handler(),
86-
ErrHandler: sl.errLogger.Handler(),
87-
}
88-
return slog.New(splitHandler)
89-
}
90-
9181
const (
9282
Debug = "DEBUG"
9383
Info = "INFO"
@@ -187,64 +177,21 @@ func NewStructuredLogger(outW, errW io.Writer, logLevel string) (Logger, error)
187177
}
188178

189179
// DebugContext logs debug messages
190-
func (sl *StructuredLogger) DebugContext(ctx context.Context, msg string, keysAndValues ...any) {
180+
func (sl *StructuredLogger) DebugContext(ctx context.Context, msg string, keysAndValues ...interface{}) {
191181
sl.outLogger.DebugContext(ctx, msg, keysAndValues...)
192182
}
193183

194184
// InfoContext logs info messages
195-
func (sl *StructuredLogger) InfoContext(ctx context.Context, msg string, keysAndValues ...any) {
185+
func (sl *StructuredLogger) InfoContext(ctx context.Context, msg string, keysAndValues ...interface{}) {
196186
sl.outLogger.InfoContext(ctx, msg, keysAndValues...)
197187
}
198188

199189
// WarnContext logs warning messages
200-
func (sl *StructuredLogger) WarnContext(ctx context.Context, msg string, keysAndValues ...any) {
190+
func (sl *StructuredLogger) WarnContext(ctx context.Context, msg string, keysAndValues ...interface{}) {
201191
sl.errLogger.WarnContext(ctx, msg, keysAndValues...)
202192
}
203193

204194
// ErrorContext logs error messages
205-
func (sl *StructuredLogger) ErrorContext(ctx context.Context, msg string, keysAndValues ...any) {
195+
func (sl *StructuredLogger) ErrorContext(ctx context.Context, msg string, keysAndValues ...interface{}) {
206196
sl.errLogger.ErrorContext(ctx, msg, keysAndValues...)
207197
}
208-
209-
// SlogLogger returns a single standard *slog.Logger that routes
210-
// records to the outLogger or errLogger based on the log level.
211-
func (sl *StructuredLogger) SlogLogger() *slog.Logger {
212-
splitHandler := &SplitHandler{
213-
OutHandler: sl.outLogger.Handler(),
214-
ErrHandler: sl.errLogger.Handler(),
215-
}
216-
return slog.New(splitHandler)
217-
}
218-
219-
type SplitHandler struct {
220-
OutHandler slog.Handler
221-
ErrHandler slog.Handler
222-
}
223-
224-
func (h *SplitHandler) Enabled(ctx context.Context, level slog.Level) bool {
225-
if level >= slog.LevelWarn {
226-
return h.ErrHandler.Enabled(ctx, level)
227-
}
228-
return h.OutHandler.Enabled(ctx, level)
229-
}
230-
231-
func (h *SplitHandler) Handle(ctx context.Context, r slog.Record) error {
232-
if r.Level >= slog.LevelWarn {
233-
return h.ErrHandler.Handle(ctx, r)
234-
}
235-
return h.OutHandler.Handle(ctx, r)
236-
}
237-
238-
func (h *SplitHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
239-
return &SplitHandler{
240-
OutHandler: h.OutHandler.WithAttrs(attrs),
241-
ErrHandler: h.ErrHandler.WithAttrs(attrs),
242-
}
243-
}
244-
245-
func (h *SplitHandler) WithGroup(name string) slog.Handler {
246-
return &SplitHandler{
247-
OutHandler: h.OutHandler.WithGroup(name),
248-
ErrHandler: h.ErrHandler.WithGroup(name),
249-
}
250-
}

internal/log/logger.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,16 @@ package log
1616

1717
import (
1818
"context"
19-
"log/slog"
2019
)
2120

2221
// Logger is the interface used throughout the project for logging.
2322
type Logger interface {
2423
// DebugContext is for reporting additional information about internal operations.
25-
DebugContext(ctx context.Context, format string, args ...any)
24+
DebugContext(ctx context.Context, format string, args ...interface{})
2625
// InfoContext is for reporting informational messages.
27-
InfoContext(ctx context.Context, format string, args ...any)
26+
InfoContext(ctx context.Context, format string, args ...interface{})
2827
// WarnContext is for reporting warning messages.
29-
WarnContext(ctx context.Context, format string, args ...any)
28+
WarnContext(ctx context.Context, format string, args ...interface{})
3029
// ErrorContext is for reporting errors.
31-
ErrorContext(ctx context.Context, format string, args ...any)
32-
// Single standard slog.Logger that routes records to the outLogger or
33-
// errLogger based on log levels
34-
SlogLogger() *slog.Logger
30+
ErrorContext(ctx context.Context, format string, args ...interface{})
3531
}

internal/server/server.go

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
"github.com/go-chi/chi/v5"
2929
"github.com/go-chi/chi/v5/middleware"
3030
"github.com/go-chi/cors"
31-
"github.com/go-chi/httplog/v3"
31+
"github.com/go-chi/httplog/v2"
3232
"github.com/googleapis/genai-toolbox/internal/auth"
3333
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
3434
"github.com/googleapis/genai-toolbox/internal/log"
@@ -347,16 +347,31 @@ func NewServer(ctx context.Context, cfg ServerConfig) (*Server, error) {
347347
if err != nil {
348348
return nil, fmt.Errorf("unable to initialize http log: %w", err)
349349
}
350-
351-
schema := *httplog.SchemaGCP
352-
schema.Level = cfg.LogLevel.String()
353-
schema.Concise(true)
354-
httpOpts := &httplog.Options{
355-
Level: logLevel,
356-
Schema: &schema,
350+
var httpOpts httplog.Options
351+
switch cfg.LoggingFormat.String() {
352+
case "json":
353+
httpOpts = httplog.Options{
354+
JSON: true,
355+
LogLevel: logLevel,
356+
Concise: true,
357+
RequestHeaders: false,
358+
MessageFieldName: "message",
359+
SourceFieldName: "logging.googleapis.com/sourceLocation",
360+
TimeFieldName: "timestamp",
361+
LevelFieldName: "severity",
362+
}
363+
case "standard":
364+
httpOpts = httplog.Options{
365+
LogLevel: logLevel,
366+
Concise: true,
367+
RequestHeaders: false,
368+
MessageFieldName: "message",
369+
}
370+
default:
371+
return nil, fmt.Errorf("invalid Logging format: %q", cfg.LoggingFormat.String())
357372
}
358-
logger := l.SlogLogger()
359-
r.Use(httplog.RequestLogger(logger, httpOpts))
373+
httpLogger := httplog.NewLogger("httplog", httpOpts)
374+
r.Use(httplog.RequestLogger(httpLogger))
360375

361376
sourcesMap, authServicesMap, embeddingModelsMap, toolsMap, toolsetsMap, promptsMap, promptsetsMap, err := InitializeConfigs(ctx, cfg)
362377
if err != nil {

internal/sources/oracle/oracle.go

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"database/sql"
77
"encoding/json"
88
"fmt"
9+
"net/url"
910
"os"
1011
"strings"
1112

@@ -237,6 +238,32 @@ func (s *Source) RunSQL(ctx context.Context, statement string, params []any) (an
237238
return out, nil
238239
}
239240

241+
func buildGoOraConnString(user, password, connectStringBase, walletLocation string) string {
242+
userInfo := url.UserPassword(
243+
decodePercentEncodedUserInfo(user),
244+
decodePercentEncodedUserInfo(password),
245+
).String()
246+
247+
base := fmt.Sprintf("oracle://%s@%s", userInfo, connectStringBase)
248+
trimmedWalletLocation := strings.TrimSpace(walletLocation)
249+
if trimmedWalletLocation == "" {
250+
return base
251+
}
252+
253+
q := url.Values{}
254+
q.Set("ssl", "true")
255+
q.Set("wallet", trimmedWalletLocation)
256+
return fmt.Sprintf("%s?%s", base, q.Encode())
257+
}
258+
259+
func decodePercentEncodedUserInfo(value string) string {
260+
decoded, err := url.PathUnescape(value)
261+
if err != nil {
262+
return value
263+
}
264+
return decoded
265+
}
266+
240267
func initOracleConnection(ctx context.Context, tracer trace.Tracer, config Config) (*sql.DB, error) {
241268
//nolint:all // Reassigned ctx
242269
ctx, span := sources.InitConnectionSpan(ctx, tracer, SourceType, config.Name)
@@ -289,16 +316,11 @@ func initOracleConnection(ctx context.Context, tracer trace.Tracer, config Confi
289316
// Use go-ora driver (pure Go)
290317
driverName = "oracle"
291318

292-
user := config.User
293-
password := config.Password
319+
finalConnStr = buildGoOraConnString(config.User, config.Password, connectStringBase, config.WalletLocation)
294320

295321
if hasWallet {
296-
finalConnStr = fmt.Sprintf("oracle://%s:%s@%s?ssl=true&wallet=%s",
297-
user, password, connectStringBase, config.WalletLocation)
322+
logger.DebugContext(ctx, fmt.Sprintf("Using go-ora driver (pure-Go) with wallet and serverString: %s\n", connectStringBase))
298323
} else {
299-
// Standard go-ora connection
300-
finalConnStr = fmt.Sprintf("oracle://%s:%s@%s",
301-
config.User, config.Password, connectStringBase)
302324
logger.DebugContext(ctx, fmt.Sprintf("Using go-ora driver (pure-Go) with serverString: %s\n", connectStringBase))
303325
}
304326
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package oracle
2+
3+
import "testing"
4+
5+
func TestBuildGoOraConnString(t *testing.T) {
6+
t.Parallel()
7+
8+
testCases := []struct {
9+
name string
10+
user string
11+
password string
12+
connBase string
13+
walletLocation string
14+
want string
15+
}{
16+
{
17+
name: "encodes credentials and wallet",
18+
user: "user[client]",
19+
password: "pa:ss@word",
20+
connBase: "dbhost:1521/XEPDB1",
21+
walletLocation: "/tmp/my wallet",
22+
want: "oracle://user%5Bclient%5D:pa%3Ass%40word@dbhost:1521/XEPDB1?ssl=true&wallet=%2Ftmp%2Fmy+wallet",
23+
},
24+
{
25+
name: "no wallet",
26+
user: "scott",
27+
password: "tiger",
28+
connBase: "dbhost:1521/ORCL",
29+
walletLocation: "",
30+
want: "oracle://scott:tiger@dbhost:1521/ORCL",
31+
},
32+
{
33+
name: "does not double encode percent encoded user",
34+
user: "app_user%5BCLIENT_A%5D",
35+
password: "secret",
36+
connBase: "dbhost:1521/ORCL",
37+
walletLocation: "",
38+
want: "oracle://app_user%5BCLIENT_A%5D:secret@dbhost:1521/ORCL",
39+
},
40+
{
41+
name: "uses trimmed wallet location",
42+
user: "scott",
43+
password: "tiger",
44+
connBase: "dbhost:1521/ORCL",
45+
walletLocation: " /tmp/wallet ",
46+
want: "oracle://scott:tiger@dbhost:1521/ORCL?ssl=true&wallet=%2Ftmp%2Fwallet",
47+
},
48+
}
49+
50+
for _, tc := range testCases {
51+
tc := tc
52+
t.Run(tc.name, func(t *testing.T) {
53+
t.Parallel()
54+
got := buildGoOraConnString(tc.user, tc.password, tc.connBase, tc.walletLocation)
55+
if got != tc.want {
56+
t.Fatalf("buildGoOraConnString() = %q, want %q", got, tc.want)
57+
}
58+
})
59+
}
60+
}

internal/tools/bigquery/bigqueryexecutesql/bigqueryexecutesql.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,24 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
107107
return nil, fmt.Errorf("expected allowedDataset to have at least 2 parts (project.dataset): %s", datasetFQN)
108108
}
109109
datasetID := parts[1]
110-
fmt.Fprintf(&sqlDescriptionBuilder, " The query must only access the `%s` dataset. "+
111-
"To query a table within this dataset (e.g., `my_table`), "+
112-
"qualify it with the dataset id (e.g., `%s.my_table`).", datasetFQN, datasetID)
110+
fmt.Fprintf(
111+
&sqlDescriptionBuilder,
112+
" The query must only access the `%s` dataset. "+
113+
"To query a table within this dataset (e.g., `my_table`), "+
114+
"qualify it with the dataset id (e.g., `%s.my_table`).",
115+
datasetFQN,
116+
datasetID,
117+
)
113118
} else {
114119
datasetIDs := []string{}
115120
for _, ds := range allowedDatasets {
116121
datasetIDs = append(datasetIDs, fmt.Sprintf("`%s`", ds))
117122
}
118-
fmt.Fprintf(&sqlDescriptionBuilder, " The query must only access datasets from the following list: %s.", strings.Join(datasetIDs, ", "))
123+
fmt.Fprintf(
124+
&sqlDescriptionBuilder,
125+
" The query must only access datasets from the following list: %s.",
126+
strings.Join(datasetIDs, ", "),
127+
)
119128
}
120129
}
121130

0 commit comments

Comments
 (0)