Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/npm_and_yarn/follow-redirects-1.15.6
Browse files Browse the repository at this point in the history
  • Loading branch information
collins-w authored Sep 11, 2024
2 parents a4a03fe + 5da771a commit 289fb26
Show file tree
Hide file tree
Showing 40 changed files with 1,684 additions and 1,954 deletions.
16 changes: 3 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ resources:
relayers:
relayer-1:
name: 'Test Relayer 1'
network: 'goerli'
network: 'sepolia'
min-balance: 1000
policy: ${self:resources.policies.policy-1}
api-keys:
Expand All @@ -99,16 +99,14 @@ A list of properties that support direct referencing:
- `action-trigger` may reference an `actionid` in Monitor
- `action-condition` may reference an `actionId` in Monitor
- `address-from-relayer` may reference a `relayerId` in Relayer
- `notification-ids` may reference multiple `notificationId` in Category
- `notify-config.channels` may reference multiple `notificationId` in Monitor
- `notify-config.category` may reference a `categoryId` in Monitor
- `contracts` may be used over `addresses` and reference multiple `contractId` in Monitor
The following is an example of how a direct reference to a Defender contract and relayer can be used in monitor and action respectively:

```yaml
...
contracts:
contract-1: 'goerli-0xd70d6A0480420b4C788AF91d0E1b0ca6141A9De8' # contractId of an existing resource in Defender
contract-1: 'sepolia-0x62034459131329bE4349A9cc322B03c63806Aa11' # contractId of an existing resource in Defender
relayers:
relayer-2: 'bcb659c6-7e11-4d37-a15b-0fa9f3d3442c' # relayerId of an existing relayer in Defender
actions:
Expand All @@ -124,7 +122,7 @@ monitors:
block-example:
name: 'Block Example'
type: 'BLOCK'
network: 'goerli'
network: 'sepolia'
risk-category: 'TECHNICAL'
# optional - either contracts OR addresses should be defined
contracts:
Expand Down Expand Up @@ -209,14 +207,6 @@ More information can be found on our documentation page [here](https://docs.open

## Caveats

Note that when setting up the notification configuration for a monitor, the `channels` property will always be prioritised over `category`. A notification category can only be associated to a monitor with no linked notification channels. This means that the `channels` property should be assigned the value `[]` in order to prioritise the `category` property.

```yaml
notify-config:
channels: [] # assign channels as empty list if you wish to use a category
category: ${self:resources.categories.medium-severity} # optional
```

Errors thrown during the `deploy` process, will not revert any prior changes. Common errors are:

- Not having set the API key and secret
Expand Down
29 changes: 5 additions & 24 deletions examples/defender-test-project/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ resources:
- '0x0f06aB75c7DD497981b75CD82F6566e3a5CAd8f2'
# optional
eip1559-pricing: true
private-transactions: true
private-transactions: 'flashbots-fast'

secrets:
# optional - global secrets are not affected by stackName changes
Expand All @@ -78,12 +78,12 @@ resources:
abi: ${file(./abis/demoflash.json.abi)}
# optional
nat-spec: null
contract-2: 'goerli-0xd70d6A0480420b4C788AF91d0E1b0ca6141A9De8'
contract-2: 'sepolia-0x62034459131329bE4349A9cc322B03c63806Aa11'

relayers:
relayer-1:
name: 'Test Relayer 1'
network: 'goerli'
network: 'sepolia'
min-balance: 1000
# optional
policy: ${self:resources.policies.policy-1}
Expand Down Expand Up @@ -121,30 +121,12 @@ resources:
url: ${self:custom.config.notifications.slack}
paused: false

categories:
high-severity:
name: High Severity
# optional
description: A default category to be assigned for high risk monitors.
low-severity:
name: Low Severity
# optional
description: A default category to be assigned for low risk monitors.
medium-severity:
name: Medium Severity
# optional
description: A default category to be assigned for medium risk monitors.
# optional
notification-ids:
- ${self:resources.notifications.email-1}
- ${self:resources.notifications.slack-1}

monitors:
# unique resource name
block-example:
name: 'Block Example'
type: 'BLOCK'
network: 'goerli'
network: 'sepolia'
risk-category: 'TECHNICAL' # optional
# optional - either contracts OR addresses should be defined
contracts:
Expand Down Expand Up @@ -193,8 +175,7 @@ resources:
notify-config:
timeout: 0 # optional
message: null # optional
channels: [] # assign channels as empty list if you wish to use a category
category: ${self:resources.categories.medium-severity} # optional (only used if channels is empty)
channels: [] # optional
# optional
conditions:
min-scanner-count: 1
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openzeppelin/defender-as-code",
"version": "2.6.0",
"version": "3.0.0",
"description": "Configure your Defender environment via code",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
Expand Down Expand Up @@ -70,7 +70,7 @@
"typescript": "^4.9.5"
},
"dependencies": {
"@openzeppelin/defender-sdk": "^1.10.0",
"@openzeppelin/defender-sdk": "^1.13.1",
"keccak256": "^1.0.6",
"lodash": "^4.17.21",
"prompt": "^1.3.0"
Expand Down
125 changes: 4 additions & 121 deletions src/cmd/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
getEquivalentResourceByKey,
getConsolidatedSecrets,
validateTypesAndSanitise,
constructNotificationCategory,
validateAdditionalPermissionsOrThrow,
getDeployClient,
formatABI,
Expand Down Expand Up @@ -49,7 +48,6 @@ import {
DefenderMonitorTrigger,
DefenderMonitorFilterTrigger,
DefenderBlockExplorerApiKey,
DefenderCategory,
DefenderFortaMonitorResponse,
DefenderBlockMonitorResponse,
Resources,
Expand All @@ -63,8 +61,6 @@ import {
Actions,
BlockExplorerApiKey,
BlockExplorerApiKeys,
Categories,
Category,
Contract,
Contracts,
DefenderID,
Expand Down Expand Up @@ -116,7 +112,6 @@ export default class DefenderDeploy {
monitors: [],
actions: [],
notifications: [],
categories: [],
contracts: [],
relayerApiKeys: [],
secrets: [],
Expand Down Expand Up @@ -224,20 +219,6 @@ export default class DefenderDeploy {
},
);

// Notification Categories
const categories: Categories = this.resources?.categories ?? {};
const dCategories = await monitorClient.listNotificationCategories();
const categoryDifference = _.differenceWith(
dCategories,
Object.entries(categories),
(a: DefenderCategory, b: [string, Category | DefenderID]) => {
if (isDefenderId(b[1])) {
return a.categoryId === b[1];
}
return a.stackResourceId === getResourceID(getStackName(this.serverless), b[0]);
},
);

// Actions
const actions: Actions = this.resources.actions ?? {};
const actionClient = getActionClient(this.teamKey!);
Expand Down Expand Up @@ -282,7 +263,6 @@ export default class DefenderDeploy {
difference.contracts = contractDifference;
difference.monitors = monitorDifference;
difference.notifications = notificationDifference;
difference.categories = categoryDifference;
difference.actions = actionDifference;
difference.secrets = secretsDifference;
difference.blockExplorerApiKeys = blockExplorerApiKeyDifference;
Expand Down Expand Up @@ -461,7 +441,7 @@ export default class DefenderDeploy {
};
},
// on create
async (contract: Contract, stackResourceId: string) => {
async (contract: Contract, _stackResourceId: string) => {
const importedContract = await client.addContract({
name: contract.name,
network: contract.network,
Expand Down Expand Up @@ -713,100 +693,14 @@ export default class DefenderDeploy {
);
}

private async deployCategories(output: DeployOutput<DefenderCategory>) {
const categories: Categories = this.resources?.categories ?? {};
const client = getMonitorClient(this.teamKey!);
const notifications = await client.listNotificationChannels();
const retrieveExisting = () => client.listNotificationCategories();

await this.wrapper<Category, DefenderCategory>(
this.serverless,
'Categories',
removeDefenderIdReferences(categories),
retrieveExisting,
// on update
async (category: Category, match: DefenderCategory) => {
const matchStackResourceId =
match.stackResourceId ?? getResourceID(getStackName(this.serverless), _.kebabCase(match.name));
const newCategory = constructNotificationCategory(
this.serverless,
this.resources,
category,
matchStackResourceId,
notifications,
);

const mappedMatch = {
name: match.name,
description: match.description,
notificationIds: match.notificationIds,
stackResourceId: matchStackResourceId,
};
if (_.isEqual(validateTypesAndSanitise(newCategory), validateTypesAndSanitise(mappedMatch))) {
return {
name: matchStackResourceId,
id: match.categoryId,
success: false,
response: match,
notice: `Skipped ${matchStackResourceId} - no changes detected`,
};
}

const updatedCategory = await client.updateNotificationCategory(match.categoryId, {
categoryId: match.categoryId,
...newCategory,
});

return {
name: matchStackResourceId,
id: updatedCategory.categoryId,
success: true,
response: updatedCategory,
};
},
// on create
async (_: Category, stackResourceId: string) => {
return {
name: stackResourceId,
id: '',
success: false,
notice: 'Creating custom notification categories is not yet supported',
};
// const createdCategory = await client.createNotificationCategory(
// constructNotificationCategory(this.serverless, category, stackResourceId, notifications),
// );
// return {
// name: stackResourceId,
// id: createdCategory.categoryId,
// success: true,
// response: createdCategory,
// };
},
// on remove
async (_: DefenderCategory[]) => {
this.log.warn(`Deleting notification categories is not yet supported.`);
// await Promise.all(categories.map(async (n) => await client.deleteNotificationCategory(n.categoryId)));
},
// overrideMatchDefinition
// TODO: remove this when we allow creating new categories
(a: DefenderCategory, b: Category) => {
return a.name === b.name;
},
output,
this.ssotDifference?.categories,
);
}

private async deployMonitors(output: DeployOutput<DefenderMonitor>) {
try {
const monitors: Monitors = this.resources?.monitors ?? {};
const client = getMonitorClient(this.teamKey!);
const actions = await getActionClient(this.teamKey!).list();
const notifications = await client.listNotificationChannels();
const categories = await client.listNotificationCategories();

// TODO: Add a new endpoint in defender-sdk which includes contract ABI and NatSpec
const contracts = await getProposalClient(this.teamKey!).listContracts();
const contracts = await getProposalClient(this.teamKey!).listContracts({ includeAbi: true });

const retrieveExisting = () => client.list().then((r) => r.items);

Expand Down Expand Up @@ -855,7 +749,6 @@ export default class DefenderDeploy {
notifications,
actions.items,
blockwatchersForNetwork,
categories,
contracts,
);

Expand All @@ -881,9 +774,7 @@ export default class DefenderDeploy {
notificationChannels: match.notifyConfig?.notifications.map(
(n: DefenderNotificationReference) => n.notificationId,
),
notificationCategoryId: _.isEmpty(match.notifyConfig?.notifications)
? match.notifyConfig?.notificationCategoryId
: undefined,
severityLevel: match.notifyConfig?.severityLevel,
type: match.type,
stackResourceId: match.stackResourceId,
network: match.network,
Expand Down Expand Up @@ -950,7 +841,6 @@ export default class DefenderDeploy {
notifications,
actions.items,
blockwatchersForNetwork,
categories,
contracts,
),
);
Expand Down Expand Up @@ -1527,11 +1417,6 @@ export default class DefenderDeploy {
created: [],
updated: [],
};
const categories: DeployOutput<DefenderCategory> = {
removed: [],
created: [],
updated: [],
};
const secrets: DeployOutput<string> = {
removed: [],
created: [],
Expand Down Expand Up @@ -1574,7 +1459,6 @@ export default class DefenderDeploy {
contracts,
relayers,
notifications,
categories,
secrets,
blockExplorerApiKeys,
forkedNetworks,
Expand All @@ -1588,9 +1472,8 @@ export default class DefenderDeploy {
// Always deploy relayers before actions
await this.deployRelayers(stdOut.relayers);
await this.deployActions(stdOut.actions);
// Deploy notifications before monitors and categories
// Deploy notifications before monitors
await this.deployNotifications(stdOut.notifications);
await this.deployCategories(stdOut.categories);
await this.deployMonitors(stdOut.monitors);
await this.deployBlockExplorerApiKey(stdOut.blockExplorerApiKeys);

Expand Down
Loading

0 comments on commit 289fb26

Please sign in to comment.