Skip to content

Commit 2c07844

Browse files
committed
CNDB-15280: Address review feedback on redaction
1 parent c51ea1d commit 2c07844

File tree

16 files changed

+82
-83
lines changed

16 files changed

+82
-83
lines changed

src/java/org/apache/cassandra/db/AbstractReadQuery.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public TableMetadata metadata()
6464
// Monitorable interface
6565
public String name()
6666
{
67-
return toCQLString();
67+
return toRedactedCQLString();
6868
}
6969

7070
@Override
@@ -100,18 +100,24 @@ public ColumnFilter columnFilter()
100100
/**
101101
* Recreates the CQL string corresponding to this query, representing any specific values with '?',
102102
* to prevent leaking sensitive data.
103-
* <p>
104-
* Note that in general the returned string will not be exactly the original user string, first
105-
* because there isn't always a single syntax for a given query, but also because we don't have
106-
* all the information needed (we know the non-PK columns queried but not the PK ones as internally
107-
* we query them all). So this shouldn't be relied upon too strongly, but this should be good enough for
108-
* monitoring purposes which is what this is for.
103+
* @see #toCQLString(boolean)
109104
*/
110-
public String toCQLString()
105+
public String toRedactedCQLString()
111106
{
112107
return toCQLString(true);
113108
}
114109

110+
/**
111+
* Recreates the CQL string corresponding to this query, printing specific values without any redaction.
112+
* This might leak sensitive data if the query string ends up in logs or any other unprotected place, so this only
113+
* should be used for debugging purposes or to present the query string to the same end user that created the query.
114+
* @see #toCQLString(boolean)
115+
*/
116+
public String toUnredactedCQLString()
117+
{
118+
return toCQLString(false);
119+
}
120+
115121
/**
116122
* Recreates the CQL string corresponding to this query.
117123
* </p>
@@ -130,7 +136,7 @@ public String toCQLString()
130136
* @param redact whether to redact the queried column values.
131137
*/
132138
@VisibleForTesting
133-
public String toCQLString(boolean redact)
139+
protected String toCQLString(boolean redact)
134140
{
135141
CqlBuilder builder = new CqlBuilder();
136142
builder.append("SELECT ").append(columnFilter().toCQLString(redact));

src/java/org/apache/cassandra/db/ReadCommand.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ private Threshold.GuardedCounter createTombstoneCounter()
607607
Threshold guardrail = shouldRespectTombstoneThresholds()
608608
? Guardrails.scannedTombstones
609609
: DefaultGuardrail.DefaultThreshold.NEVER_TRIGGERED;
610-
return guardrail.newCounter(ReadCommand.this::toCQLString, false, null);
610+
return guardrail.newCounter(ReadCommand.this::toRedactedCQLString, false, null);
611611
}
612612

613613
private MetricRecording()
@@ -671,7 +671,7 @@ private void countTombstone(ClusteringPrefix<?> clustering)
671671
{
672672
metric.tombstoneFailures.inc();
673673
throw new TombstoneOverwhelmingException(tombstones.get(),
674-
ReadCommand.this.toCQLString(),
674+
ReadCommand.this.toRedactedCQLString(),
675675
ReadCommand.this.metadata(),
676676
currentKey,
677677
clustering);

src/java/org/apache/cassandra/db/ReadExecutionController.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ int oldestUnrepairedTombstone()
112112
{
113113
return oldestUnrepairedTombstone;
114114
}
115-
115+
116116
void updateMinOldestUnrepairedTombstone(int candidate)
117117
{
118118
oldestUnrepairedTombstone = Math.min(oldestUnrepairedTombstone, candidate);
@@ -254,15 +254,15 @@ public boolean isRepairedDataDigestConclusive()
254254
{
255255
return repairedDataInfo.isConclusive();
256256
}
257-
257+
258258
public RepairedDataInfo getRepairedDataInfo()
259259
{
260260
return repairedDataInfo;
261261
}
262262

263263
private void addSample()
264264
{
265-
String cql = command.toCQLString();
265+
String cql = command.toRedactedCQLString();
266266
int timeMicros = (int) Math.min(TimeUnit.NANOSECONDS.toMicros(clock.now() - createdAtNanos), Integer.MAX_VALUE);
267267
ColumnFamilyStore cfs = ColumnFamilyStore.getIfExists(baseMetadata.id);
268268
if (cfs != null)

src/java/org/apache/cassandra/db/filter/RowFilter.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,18 +1423,17 @@ public String toCQLString(boolean redact)
14231423
private String likeToCQLString(String pattern, AbstractType<?> type, boolean redact)
14241424
{
14251425
if (redact)
1426-
return String.format("%s LIKE ?", column.name);
1426+
return String.format("%s LIKE ?", column.name.toCQLString());
14271427

14281428
String stringValue = String.format(pattern, type.getString(value));
1429-
return String.format("%s LIKE %s", column.name, truncateValue(stringValue));
1429+
return String.format("%s LIKE %s", column.name.toCQLString(), truncateValue(stringValue));
14301430
}
14311431

14321432
private static String truncateValue(String value)
14331433
{
14341434
return value.length() > 9 ? value.substring(0, 6) + "..." : value;
14351435
}
14361436

1437-
14381437
@Override
14391438
protected Kind kind()
14401439
{

src/java/org/apache/cassandra/db/marshal/AbstractType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public ByteBuffer decompose(T value)
183183
}
184184

185185
/**
186-
* Generates a CQL literal representing the specified binary value.
186+
* Returns a CQL literal representing the specified binary value, or "?" if redaction is requested.
187187
*
188188
* @param bytes the value to convert to a CQL literal.
189189
* @param redact whether to mask the value with '?' (for redaction purposes)

src/java/org/apache/cassandra/index/sai/plan/Plan.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -284,31 +284,40 @@ enum ControlFlow { Continue, Break }
284284
protected abstract double estimateSelectivity();
285285

286286
/**
287-
* Formats the whole plan as a pretty tree
287+
* Formats the whole plan as a pretty tree, redacting the queried column values.
288288
*/
289-
public final String toStringRecursive()
289+
public final String toRedactedStringRecursive()
290290
{
291291
return toStringRecursive(true);
292292
}
293293

294+
/**
295+
* Formats the whole plan as a pretty tree, redacting the queried column values.
296+
*/
297+
public final String toUnredactedStringRecursive()
298+
{
299+
return toStringRecursive(false);
300+
}
301+
294302
/**
295303
* Formats the whole plan as a pretty tree
296304
*
297305
* @param redact whether to redact the queried column values.
298306
*/
299-
public final String toStringRecursive(boolean redact)
307+
private final String toStringRecursive(boolean redact)
300308
{
301309
TreeFormatter<Plan> formatter = new TreeFormatter<>(plan -> plan.toString(redact), Plan::subplans);
302310
return formatter.format(this);
303311
}
304312

305313
/**
306-
* Returns the string representation of this node only
314+
* Returns the string representation of this node only, without redacting the queried column values.
315+
* @see #toString(boolean)
307316
*/
308317
@Override
309318
public final String toString()
310319
{
311-
return toString(true);
320+
return toString(false);
312321
}
313322

314323
/**
@@ -327,7 +336,7 @@ public final String toString(boolean redact)
327336

328337
/**
329338
* Returns additional information specific to the node displayed in the first line.
330-
* The information is included in the output of {@link #toString()} and {@link #toStringRecursive()}.
339+
* The information is included in the output of {@link #toString()} and {@link #toRedactedStringRecursive()}.
331340
* It is up to subclasses to implement it.
332341
*/
333342
protected String title(boolean redact)
@@ -337,7 +346,7 @@ protected String title(boolean redact)
337346

338347
/**
339348
* Returns additional information specific to the node, displayed below the title.
340-
* The information is included in the output of {@link #toString()} and {@link #toStringRecursive()}.
349+
* The information is included in the output of {@link #toString()} and {@link #toRedactedStringRecursive()}.
341350
* It is up to subclasses to implement it.
342351
*/
343352
protected String description()
@@ -366,7 +375,7 @@ protected String description()
366375
public final Plan optimize()
367376
{
368377
if (logger.isTraceEnabled())
369-
logger.trace("Optimizing plan:\n{}", toStringRecursive());
378+
logger.trace("Optimizing plan:\n{}", toRedactedStringRecursive());
370379

371380
Plan bestPlanSoFar = this;
372381
List<Leaf> leaves = nodesOfType(Leaf.class);
@@ -381,14 +390,14 @@ public final Plan optimize()
381390

382391
Plan candidate = bestPlanSoFar.removeRestriction(leaf.id);
383392
if (logger.isTraceEnabled())
384-
logger.trace("Candidate query plan:\n{}", candidate.toStringRecursive());
393+
logger.trace("Candidate query plan:\n{}", candidate.toRedactedStringRecursive());
385394

386395
if (candidate.fullCost() <= bestPlanSoFar.fullCost())
387396
bestPlanSoFar = candidate;
388397
}
389398

390399
if (logger.isTraceEnabled())
391-
logger.trace("Optimized plan:\n{}", bestPlanSoFar.toStringRecursive());
400+
logger.trace("Optimized plan:\n{}", bestPlanSoFar.toRedactedStringRecursive());
392401
return bestPlanSoFar;
393402
}
394403

src/java/org/apache/cassandra/index/sai/plan/QueryController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -415,11 +415,11 @@ Plan buildPlan()
415415
updateIndexMetricsQueriesCount(plan);
416416

417417
if (logger.isTraceEnabled())
418-
logger.trace("Query execution plan:\n" + plan.toStringRecursive());
418+
logger.trace("Query execution plan:\n" + plan.toRedactedStringRecursive());
419419

420420
if (Tracing.isTracing())
421421
{
422-
Tracing.trace("Query execution plan:\n" + plan.toStringRecursive(false));
422+
Tracing.trace("Query execution plan:\n" + plan.toUnredactedStringRecursive());
423423
List<Plan.IndexScan> origIndexScans = keysIterationPlan.nodesOfType(Plan.IndexScan.class);
424424
List<Plan.IndexScan> selectedIndexScans = plan.nodesOfType(Plan.IndexScan.class);
425425
Tracing.trace("Selecting {} {} of {} out of {} indexes",

src/java/org/apache/cassandra/service/context/DefaultOperationContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static class Factory implements OperationContext.Factory
5858
@Override
5959
public OperationContext forRead(ReadCommand command, ColumnFamilyStore cfs)
6060
{
61-
return new DefaultOperationContext(command::toCQLString);
61+
return new DefaultOperationContext(command::toRedactedCQLString);
6262
}
6363
}
6464
}

src/java/org/apache/cassandra/service/reads/ReplicaFilteringProtection.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ public void close()
199199
String message = String.format("Replica filtering protection has cached up to %d rows during query %s, " +
200200
"which is over the warning threshold of %d rows defined by " +
201201
"'cached_replica_rows_warn_threshold' in cassandra.yaml.",
202-
maxRowsCached, command.toCQLString(), cachedRowsWarnThreshold);
202+
maxRowsCached, command.toRedactedCQLString(), cachedRowsWarnThreshold);
203203

204204
ClientWarn.instance.warn(message);
205205
oneMinuteLogger.warn(message);
@@ -289,7 +289,7 @@ private void incrementCachedRows()
289289
String message = String.format("Replica filtering protection has cached %d rows during query %s, " +
290290
"which is over the failure threshold of %d rows defined by " +
291291
"'cached_replica_rows_fail_threshold' in cassandra.yaml.",
292-
currentRowsCached, command.toCQLString(), cachedRowsFailThreshold);
292+
currentRowsCached, command.toRedactedCQLString(), cachedRowsFailThreshold);
293293

294294
logger.error(message);
295295
Tracing.trace(message);

src/java/org/apache/cassandra/service/reads/repair/ReadRepairEvent.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.util.Collection;
2323
import java.util.HashMap;
2424
import java.util.HashSet;
25-
import java.util.List;
2625
import java.util.Map;
2726
import java.util.Set;
2827
import java.util.stream.Collectors;
@@ -66,7 +65,7 @@ enum ReadRepairEventType
6665
{
6766
this.keyspace = readRepair.cfs.keyspace;
6867
this.tableName = readRepair.cfs.getTableName();
69-
this.cqlCommand = readRepair.command.toCQLString();
68+
this.cqlCommand = readRepair.command.toRedactedCQLString();
7069
this.consistency = readRepair.replicaPlan().consistencyLevel();
7170
this.speculativeRetry = readRepair.cfs.metadata().params.speculativeRetry.kind();
7271
this.destinations = destinations;

0 commit comments

Comments
 (0)