Skip to content
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

Bmoric/refacto secret processor #11362

Merged
merged 19 commits into from
Mar 30, 2022
Merged

Conversation

benmoriceau
Copy link
Contributor

@benmoriceau benmoriceau commented Mar 23, 2022

What

Follow up on the comments on #11296

It is reactoring the JsonProcessor by making it being generated through a factory. This allow to avoid propagated the feature flag inside the JsonProcessor.

@github-actions github-actions bot removed area/scheduler area/worker Related to worker labels Mar 23, 2022
@benmoriceau benmoriceau temporarily deployed to more-secrets March 23, 2022 17:52 Inactive
@benmoriceau benmoriceau temporarily deployed to more-secrets March 23, 2022 17:52 Inactive
try {
final UUID sourceDefinitionId = configWithMetadata.getConfig().getSourceDefinitionId();
final StandardSourceDefinition standardSourceDefinition = getConfig(
ConfigSchema.STANDARD_SOURCE_DEFINITION,
sourceDefinitionId.toString(),
StandardSourceDefinition.class);
final JsonNode connectionSpecs = standardSourceDefinition.getSpec().getConnectionSpecification();
final JsonNode sanitizedConfig = jsonSecretsProcessor.maskSecrets(Jsons.jsonNode(configWithMetadata.getConfig()), connectionSpecs);
final JsonNode sanitizedConfig = jsonSecretsProcessor.transformJson(Jsons.jsonNode(configWithMetadata.getConfig()),
Copy link
Contributor

@michel-tricot michel-tricot Mar 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not what I had in mind. You still have complex logic.

What about instead you do the following:

when you instantiate the DatabaseConfigPersistence:
JsonSecretsProcessor jsp = flag ? new RealJsonSecretsProcessor() : new NoOpJsonSecretsProcessor();

new DatabaseConfigPersistence(jsp);

This way you don't create more complex logic in the config persistence, the testing of that class is simple, you don't need to pass a colloection for feature flags.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to a class, I am not 100% satisfy with it because we don't really want a no op for the copy secrets step since it is not affected by the previous comments. I think that I should change it to a factory instead to generate the JsonSecretsProcessor that will do or not do an operation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current state is definitely in the vein of what I had in mind.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to a factory. I prefer this implementation because while it is allowing to have a single pace for implementation, it allows to have several type of combination, like copy but don't mask, mask and copy, etc ...

@benmoriceau benmoriceau temporarily deployed to more-secrets March 25, 2022 00:50 Inactive
@benmoriceau benmoriceau temporarily deployed to more-secrets March 25, 2022 00:50 Inactive
@benmoriceau benmoriceau temporarily deployed to more-secrets March 25, 2022 17:09 Inactive
@benmoriceau benmoriceau temporarily deployed to more-secrets March 25, 2022 17:09 Inactive
@benmoriceau benmoriceau marked this pull request as ready for review March 25, 2022 18:28
@benmoriceau benmoriceau requested a review from edgao March 25, 2022 18:28
public JsonSecretsProcessor createJsonSecretsProcessor() {
return new JsonSecretsProcessor() {

@Override
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure I understand why these methods need to be overridden here. I.e. why not just move maskSecrets and copySecrets into JsonSecretsProcessor and make it a concrete class?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It comes from a previous PR: #11296. In order to still be able to use the export functionality, we want to sometime not mask the secret. That's why we have this behavior of having a flag to mask or not mask the secrets.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my question is more about why JsonSecretsProcessor needs to be an abstract class, and why we need to create an anonymous inner class in the factory. I.e. could JsonSecretsProcessor look something like this:

// note the non-abstract class
public class JsonSecretsProcessor {
  private final boolean maskSecrets;
  private final boolean copySecrets;

  public JsonNode maskSecrets(final JsonNode obj, final JsonNode schema) {
    // do stuff...
  }

  public JsonNode copySecrets(final JsonNode src, final JsonNode dst, final JsonNode schema) {
    // do other stuff...
  }
}

and then JsonSecretsProcessorFactory#createJsonSecretsProcessor would just be return new JsonSecretsProcessor(maskSecrets, copySecrets);

if (!canBeProcessed(schema)) {
return obj;
}
Preconditions.checkArgument(schema.isObject());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: canBeProcessed is already checking that schema is an object, so this check is unnecessary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


final JsonNode fieldSchema = properties.get(key);
// We only copy the original secret if the destination object isn't attempting to overwrite it
// i.e: if the value of the secret isn't set to the mask
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// i.e: if the value of the secret isn't set to the mask
// I.e. if the destination object's value is set to the mask, then we can copy the original secret

nitpick: match the comment ("copy if equal to mask") with what the branch is actually doing (if (dst.get(key) == MASK) { dst.set(src.get(key)) })

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
dstCopy.set(key, combinationCopy);
} else {
// Otherwise, this is just a plain old json object; recurse into it.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I wrote this else-case originally so this is a bit awkward, but this would be a more helpful comment (right?):

Suggested change
// Otherwise, this is just a plain old json object; recurse into it.
// Otherwise, this is just a plain old json node; recurse into it. If it's not actually an object, the recursive call will exit immediately.

return new JsonSecretsProcessor() {

@Override
public JsonNode maskSecrets(final JsonNode obj, final JsonNode schema) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: it seems a bit weird that maskSecrets doesn't actually mask secrets sometimes. Not sure what a better name would be though - maybe prepareSecretsForOutput or something? (I'm very bad at naming :P )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true, I have updated it.

private boolean maskSecrets = true;

@Builder.Default
private boolean copySecrets = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this ever set to false in production? (and why is it necessary for tests?)

@benmoriceau benmoriceau requested a review from edgao March 29, 2022 20:48
@benmoriceau benmoriceau temporarily deployed to more-secrets March 29, 2022 20:49 Inactive
@benmoriceau benmoriceau temporarily deployed to more-secrets March 29, 2022 20:50 Inactive
Copy link
Contributor

@edgao edgao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one last comment about the class structure; otherwise :shipit:

public JsonSecretsProcessor createJsonSecretsProcessor() {
return new JsonSecretsProcessor() {

@Override
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my question is more about why JsonSecretsProcessor needs to be an abstract class, and why we need to create an anonymous inner class in the factory. I.e. could JsonSecretsProcessor look something like this:

// note the non-abstract class
public class JsonSecretsProcessor {
  private final boolean maskSecrets;
  private final boolean copySecrets;

  public JsonNode maskSecrets(final JsonNode obj, final JsonNode schema) {
    // do stuff...
  }

  public JsonNode copySecrets(final JsonNode src, final JsonNode dst, final JsonNode schema) {
    // do other stuff...
  }
}

and then JsonSecretsProcessorFactory#createJsonSecretsProcessor would just be return new JsonSecretsProcessor(maskSecrets, copySecrets);

@benmoriceau benmoriceau temporarily deployed to more-secrets March 30, 2022 16:37 Inactive
@benmoriceau benmoriceau temporarily deployed to more-secrets March 30, 2022 16:37 Inactive
@benmoriceau benmoriceau merged commit 394b8c9 into master Mar 30, 2022
@benmoriceau benmoriceau deleted the bmoric/refacto-secret-processor branch March 30, 2022 18:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/platform issues related to the platform area/scheduler area/server area/worker Related to worker
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants