Skip to content

chore: mask metastore credentials in GraphConfig log output - #489

Open
eazyhozy wants to merge 2 commits into
mainfrom
chore/mask-credentials-in-config-log
Open

chore: mask metastore credentials in GraphConfig log output#489
eazyhozy wants to merge 2 commits into
mainfrom
chore/mask-credentials-in-config-log

Conversation

@eazyhozy

@eazyhozy eazyhozy commented Aug 11, 2026

Copy link
Copy Markdown
Member

Summary

Graph logs the whole GraphConfig at INFO on startup, and the generated data class toString() renders every field — so the metastore user and password land in the log in plain text.

Before:

graph initialized with config: GraphConfig(phase=local, tenant=local, metastoreUrl=jdbc:mysql://db.example.com:3306/actionbase, metastoreUser=graph_app, metastorePassword=s3cr3t-p4ssw0rd, metastoreDriver=null, metastoreTable=ab_default, ...)

After:

graph initialized with config: GraphConfig(phase=local, tenant=local, metastoreUrl=jdbc:mysql://db.example.com:3306/actionbase, metastoreUser=****, metastorePassword=****, metastoreDriver=null, metastoreTable=ab_default, ...)

Changes

  • Add GraphConfig.redacted() — a copy() with the two credentials masked — and call it from the three sites that log the config.
  • An empty credential stays empty rather than ****, so "not configured" stays distinguishable from "configured".
  • metastoreUrl is left as is: credentials reach the driver through the separate user/password fields, and the URL is the most useful part of the line when diagnosing which metastore an instance is talking to.

copy() keeps the generated toString(), so nothing has to be maintained by hand as the class grows. The trade-off is that toString() itself still renders the credentials, so a caller that logs the config directly would leak them again.

How to Test

./gradlew :engine:compileKotlin :engine:compileTestKotlin

No test included: redacted() is a single copy() call, so a test would restate the implementation rather than constrain behaviour.

AI Assistance

  • This PR was written largely with AI assistance.
    • Tool / model: Claude Code (Opus 5)

Graph logs the whole GraphConfig at INFO on startup. The generated data
class toString() renders every field, so the metastore user and password
end up in the log in plain text.

Hand-write toString() to mask just those two fields. Everything else
stays visible: that log line is the primary record of how an instance was
configured. An empty credential still renders as empty, so "not
configured" stays distinguishable from "configured".

A hand-written toString() can fall behind the constructor, so the test
walks the declared fields by reflection and fails if any property stops
being rendered.
@eazyhozy eazyhozy self-assigned this Aug 11, 2026
…ring()

The previous commit hand-wrote toString() to mask the credentials. That
made the default safe, but it also pinned a 28-field rendering that has to
be extended by hand every time a property is added, and a stale rendering
fails silently.

Move the masking to a redacted() copy and call it from the three sites
that log the config. copy() keeps the generated toString(), so nothing
drifts when the class grows.

The trade-off is that toString() itself still renders the credentials, so
a future caller that logs the config directly would leak them again.
@eazyhozy
eazyhozy marked this pull request as ready for review August 11, 2026 08:39
@eazyhozy
eazyhozy requested a review from em3s as a code owner August 11, 2026 08:39
@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. maintenance Maintenance work. labels Aug 11, 2026
@eazyhozy
eazyhozy requested a review from zipdoki August 11, 2026 08:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintenance Maintenance work. size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant