-
Notifications
You must be signed in to change notification settings - Fork 8
feat(redact): add a dictionary of secrets to redact MCP-29 #569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
With this feature we support redacting known secrets from a dictionary. This is value for environments like the MCP Server where we create new users (user/password) or when we can infer secrets from CLI arguments (--user, --pasword).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds support for redacting known secrets from a dictionary in the mongodb-redact package. The feature allows environments like MCP Server to redact specific user credentials, passwords, and other sensitive data that can be inferred from CLI arguments or user creation flows.
Key changes:
- Add a new
secrets.ts
module withredactSecrets
function and secret type definitions - Extract utility functions to
utils.ts
for code reusability - Update the main
redact
function to accept optional secrets dictionary parameter
Reviewed Changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
File | Description |
---|---|
packages/mongodb-redact/tsconfig.json | Adds esModuleInterop compiler option for better module compatibility |
packages/mongodb-redact/src/utils.ts | Extracts isPlainObject utility function for code reuse |
packages/mongodb-redact/src/secrets.ts | Implements core secret redaction functionality with type definitions |
packages/mongodb-redact/src/secrets.spec.ts | Comprehensive test suite for secret redaction functionality |
packages/mongodb-redact/src/index.ts | Updates main redact function to support optional secrets parameter |
packages/mongodb-redact/src/index.spec.ts | Adds integration test for secret redaction feature |
packages/mongodb-redact/package.json | Adds regexp.escape dependency and type definitions |
Comments suppressed due to low confidence (1)
packages/mongodb-redact/src/index.ts:1
- The recursive call to
redact(value)
doesn't pass thesecrets
parameter, so secret redaction won't work for nested objects and arrays. It should beredact(value, secrets)
.
import { regexes } from './regexes';
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
packages/mongodb-redact/src/utils.ts
Outdated
if (proto === null) return true; | ||
if (!Object.prototype.hasOwnProperty.call(proto, 'constructor')) return false; | ||
const ctor = proto.constructor; | ||
if (typeof ctor !== 'function') return ctor; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line returns ctor
when it should return a boolean. The function signature indicates it should return val is object
, but here it's returning the constructor itself when it's not a function.
if (typeof ctor !== 'function') return ctor; | |
if (typeof ctor !== 'function') return false; |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ Copilot seems right about this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the constructor is not a function, it doesn't have a constructor, so returning a "truthy" value is correct here because it's a plain object. Right?
This code was as is, so after taking a look it seemed to be right, but maybe I misunderstood it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I wrote that previous code, so this is just Copilot pointing out that I'm wrong, not you 😅
If the constructor is not a function, it doesn't have a constructor
Not really, right? Does Object.create({ constructor: 42 })
"have" a constructor? Certainly not in the sense of a constructor function, but we shouldn't count this as a "plain object" in the sense of "objects whose prototype is null
or Object.prototype
"
so returning a "truthy" value is correct here because it's a plain object. Right?
Right now, this would say that Object.create({ constructor: true })
is a plain object and Object.create({ constructor: false })
isn't, which is wrong – these two are definitely the same degree of "not-plain-object-y" 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then, the condition would have to be:
if (ctor) return false;
right? We don't mind about the type of the constructor, we only care if it exists or not. Isn't it?
Edit:
Btw, both your cases with create would return true, because neither true and false are functions, so the constructor is considered just a plain property with a primitive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't mind about the type of the constructor, we only care if it exists or not. Isn't it?
Once we've established that val
has a prototype proto
, we want to return true
if proto.constructor
is the JS Object
builtin, and false
otherwise – that's the goal here
const regex = new RegExp(`\\b${escape(value)}\\b`); | ||
result = result.replace(regex, `<${kind}>`) as T; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const regex = new RegExp(`\\b${escape(value)}\\b`); | |
result = result.replace(regex, `<${kind}>`) as T; | |
const regex = new RegExp(`\\b${escape(value)}\\b`, 'g'); | |
result = result.replace(regex, `<${kind}>`) as T; |
Otherwise this only replaces the first instance of the secret (this should probably also be tested 🙂)
packages/mongodb-redact/src/utils.ts
Outdated
if (proto === null) return true; | ||
if (!Object.prototype.hasOwnProperty.call(proto, 'constructor')) return false; | ||
const ctor = proto.constructor; | ||
if (typeof ctor !== 'function') return ctor; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ Copilot seems right about this one?
return Object.fromEntries( | ||
Object.entries(message).map(([key, value]) => [ | ||
key, | ||
redactSecrets(value, secrets), | ||
]), | ||
) as T; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return Object.fromEntries( | |
Object.entries(message).map(([key, value]) => [ | |
key, | |
redactSecrets(value, secrets), | |
]), | |
) as T; | |
return Object.setPrototypeOf(Object.fromEntries( | |
Object.entries(message).map(([key, value]) => [ | |
key, | |
redactSecrets(value, secrets), | |
]), | |
), Object.getPrototypeOf(message)) as T; |
since isPlainObject()
also (correctly imo) returns true
for objects with a null
prototype?
packages/mongodb-redact/src/index.ts
Outdated
secrets: Secret[] | undefined = undefined, | ||
): T { | ||
if (secrets) { | ||
message = redactSecrets(message, secrets); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a blocker for sure, but I'd suggest merging the object walking here with the object walking in redactSecrets()
, they do very similar transformations in a very similar fashion
We don't want to return a truthy value if the ctor is a non function value (like an object). Plain objects either have a plain object as a prototype or a null prototype
Description
With this feature we support redacting known secrets from a dictionary. This is valuable for environments like the MCP Server where we create new users (user/password) or when we can infer secrets from CLI arguments (--user, --pasword).
Open Questions
Checklist