Skip to content

Commit

Permalink
improved documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
gmmorris committed Jun 18, 2020
1 parent 1c205c6 commit aac18a6
Showing 1 changed file with 65 additions and 0 deletions.
65 changes: 65 additions & 0 deletions x-pack/plugins/encrypted_saved_objects/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,71 @@ const savedObjectWithDecryptedContent = await esoClient.getDecryptedAsInternalU
one would pass to `SavedObjectsClient.get`. These argument allows to specify `namespace` property that, for example, is
required if Saved Object was created within a non-default space.

### defining migrations
EncryptedSavedObjects rely on standard SavedObject migrations, but due to the additional complexity introduced by the need to decrypt and reencrypt the migrated document, there are some caveats to how we support this.
The good news is, most of this complexity is abstracted away by the plugin and all you need to do is leverage our api.

The `EncryptedSavedObjects` Plugin _SetupContract_ exposes an `createMigration` api which facilitates defining a migration for your EncryptedSavedObject type.

The `createMigration` function takes four arguments:

|Argument|Description|Type|
|---|---|---|
|isMigrationNeededPredicate|A predicate which is called for each document, prior to being decrypted, which confirms whether a document requires migration or not. This predicate is important as the decryption step is costly and we would rather not decrypt and re-encrypt a document if we can avoid it.|function|
|migration|A migration function which will migrate each decrypted document from the old shape to the new one.|function|
|inputType|An `EncryptedSavedObjectTypeRegistration` which describes the ESOType of the input (the document prior to migration).|object|
|migratedType| Optional. An `EncryptedSavedObjectTypeRegistration` which describes the ESOType of the output (the document after migration). If this type isn't provided, we'll assume the type remains unchanged before and after the migration.|object|

For example:

```typescript
const migration790 = encryptedSavedObjects.createMigration<RawAlert, RawAlert>(
function shouldbeMigrated(doc): doc is SavedObjectUnsanitizedDoc<RawAlert> {
return doc.consumer === 'alerting' || doc.consumer === undefined;
},
(doc: SavedObjectUnsanitizedDoc<RawAlert>): SavedObjectUnsanitizedDoc<RawAlert> => {
const {
attributes: { consumer },
} = doc;
return {
...doc,
attributes: {
...doc.attributes,
consumer: consumer === 'alerting' || !consumer ? 'alerts' : consumer,
},
};
},
// type hasn't changed as the field we're updating is not an encrypted one
{
type: 'alert',
attributesToEncrypt: new Set(['apiKey']),
attributesToExcludeFromAAD: new Set(['mutedInstanceIds', 'updatedBy']),
}
);
```

In the above example you can see thwe following:
1. In `shouldbeMigrated` we limit the migrated alerts to those whose `consumer` field equals `alerting` or is undefined.
2. In the migration function we then migrate the value of `consumer` to the value we want (`alerts` or `unknown`, dependsing on the current value). In this function we can assume that only documents with a `consumer` of `alerting` or `undefined` will be passed in, but it's still safest not to, and so we use the current `consumer` as the default when needed.
3. We provide the type, which remains unchanged across this migration and so we can omit the fourth argument.

As we said above, an EncryptedSavedObject migration is a normal SavedObjects migration, and so we can plug it into the underlying SavedObject just like any other kind of migration:

```typescript
savedObjects.registerType({
name: 'alert',
hidden: true,
namespaceType: 'single',
migrations: {
// apply this migration in 7.9.0
'7.9.0': migration790,
},
mappings: {
//...
},
});
```

## Testing

### Unit tests
Expand Down

0 comments on commit aac18a6

Please sign in to comment.