Redaction and Privacy
CodeScout records what your app sends, including the Authorization header, until you tell it
not to. That is a deliberate choice for development, because the token is sometimes the exact
thing you are trying to debug, and a logger that hides it is a logger you have to switch off to
do the job.
It is the wrong default for production, so this is a decision to make before you point Code Scout at real users rather than after.
Turning it on
Section titled “Turning it on”One line covers the usual suspects:
CodeScoutConfiguration( redaction: RedactionBehavior.recommended(),)That hides the headers that almost always carry credentials, including Authorization,
Cookie, Set-Cookie and X-Api-Key, along with the body keys that usually do, such as
password, token and secret.
Add whatever is specific to your app:
CodeScoutConfiguration( redaction: RedactionBehavior.recommended( headers: {'X-Device-Signature'}, bodyKeys: {'order_signature', 'device_pin_hash'}, ),)Those additions are combined with the common lists rather than replacing them, so you keep the defaults and add your own on top.
If you would rather start from nothing and name everything yourself, use the plain constructor
instead of recommended(). Whatever you pass is then the entire list.
What matching is like
Section titled “What matching is like”Body and metadata keys are matched case-insensitively and ignore separators, so writing apikey
also catches api_key, API-KEY and apiKey. You do not need to list the spellings for those.
Header names are matched case-insensitively but not separator-insensitively, because a header name
is written one way on the wire. authorization catches Authorization, and x-api-key catches
X-Api-Key, but xapikey catches neither. Spell a header the way your server spells it.
Matching is on the whole name and not on part of it. Listing token hides a field called
token, but it does not hide refresh_token or user_token, so name those too if you want
them gone.
Body keys are matched at any depth. A password nested four levels inside a JSON object is
found, and so is one inside an array of objects.
Where it happens, and where it does not
Section titled “Where it happens, and where it does not”Network headers and bodies are redacted as the call is captured, so a named value never reaches
SQLite and is never in an upload. The console printer and the in-app panel read that same redacted
copy, so they show [redacted] too. The one place the original still sits is the in-flight request
CodeScout holds while it waits for the response, which is in memory only and is dropped once the
response arrives.
The same is true of the metadata: maps you write yourself. Anything you named in bodyKeys is
stripped from metadata as well, at any depth, because a developer writing
metadata: {'token': ...} by hand has exactly the same problem.
Four things are not covered, and it is better to know now.
The log message itself is never touched. If you write
scout.i('Signing in with $token'), that string is stored and uploaded exactly as you built it.
Redaction works on named fields, and a message has no field names in it.
Nor is the error you log. It is stored as its text, and some exceptions quote what they failed
on. A FormatException from jsonDecode carries the part of the body where parsing stopped, so if
that body can hold a value you named, log the exception’s message rather than the exception.
A body that is not JSON is not scanned. Body keys are found by reading the body as JSON. A
body that is not valid JSON, such as a broken one or the form-encoded string package:http sends
for a Map body, has no keys to match, and nothing in it is redacted.
A URL is not scanned either. A token in a query string, as in
/v2/session?access_token=abc123, is recorded as part of the URL. If your API does that, keep
it out of the URL or do not capture that call.
Confirming it is on
Section titled “Confirming it is on”Open the in-app panel and tap the info icon. The Info screen shows how many headers and how many body keys redaction is currently stripping. If that line says nothing is being stripped, your configuration did not take effect.
You can also just look. Make a call and open its row in the Network tab. A redacted header shows as a marker rather than as a value, so you can see the redaction working rather than trusting that it is.
The marker is a contract
Section titled “The marker is a contract”A stripped value becomes the exact string [redacted]. The dashboard and the panel both
recognise that string and draw it as a redaction rather than printing it as though it were the
header’s value.
This matters if you are writing anything that reads CodeScout’s data: [redacted] means the
value was removed on the device and never left it, not that the field contained that text.
Logs written before you turned it on
Section titled “Logs written before you turned it on”Redaction happens when a log is created, so it applies from that moment forward. Logs already sitting in the database on somebody’s phone were captured under the old configuration and are uploaded as they were recorded.
If you have shipped a build that captured something it should not have, changing the configuration does not reach back. Rotate whatever leaked.
Body size
Section titled “Body size”Bodies over 32 KB are cut off, and a line is appended telling you how large the whole body was, so you can tell whether you are missing a little or a lot. That limit is about upload size rather than about secrets: a single response can run to megabytes, and sending it off somebody’s phone costs them data.
RedactionBehavior.recommended(maxBodyBytes: 64 * 1024)Set it to 0 to keep everything.
The database browser
Section titled “The database browser”Redaction applies there too. A column you have named is redacted in the rows the browser reads, so it is hidden on the device and on the dashboard alike. A redacted cell is also read-only, because an edit carries the old value back to detect a conflict and a value nobody was shown cannot be compared against anything.
What leaves the device
Section titled “What leaves the device”The SDK talks to the server you configured and to nothing else. There is no analytics, no telemetry and no third party in the path.
The dashboard makes exactly one outbound request of its own. Once a day it asks GitHub whether there is a newer release, sending nothing about your instance, and you can switch it off in Settings.