From ccb4e53b630a215755bdb2514533ad218e6c42a1 Mon Sep 17 00:00:00 2001 From: Ptroger <44851272+Ptroger@users.noreply.github.com> Date: Wed, 30 Oct 2024 11:12:12 +0100 Subject: [PATCH] Setup Regal (#559) * added custom config * first lint fix * Revert "first lint fix" This reverts commit d949e4b04ab18ba6fc1c57846bbac003da476119. * changed CI and makefile command * switched OPA to regal in CI * add lint check rule to makefile * renaming on the way, added a readme * compiling * moved buildChainAccount to entity query lib * desactivated some rules - compiled and lint * test passing - lint check seem ok * format and re-added format check for rego * re-setup opa formatter in CI * rerun format * annotate 'evaluate' rule * removed lint rules for no entrypoint * format config.yaml * reactivated linter on full rego, moved main so that it's recognized in engine * remove messy-incr-rule * good naming * activated strict syntax check with OPA native * added syntax check to CI, updated linter config * moved config to root * directory match package structure rule * renamed contains operator * removed unused imports * readme update * format readme * typo * add a test section to readme * fixed comment in regal config * renamed makefile * correct config argument * enabled camelCase in tests and for variables and packages * corrected usageof armory.testData * renamed buildIntent.. to intentTo * ignore build files * improved comments in regal config --- .github/workflows/policy-engine.yml | 11 +- .regal/config.yaml | 72 +++++ apps/policy-engine/Makefile | 17 ++ .../unit/rego-transpiler.util.spec.ts | 10 +- .../__test__/unit/wasm-build.util.spec.ts | 6 +- .../core/util/rego-transpiler.util.ts | 12 +- .../resource/open-policy-agent/rego/README.md | 44 +++ .../__test__/criteria/intent/amount_test.rego | 32 --- .../criteria/intent/assigned_test.rego | 5 - .../__test__/criteria/intent/permit_test.rego | 26 -- .../__test__/criteria/intent/source_test.rego | 37 --- .../__test__/criteria/principal_test.rego | 13 - .../rego/__test__/criteria/resource_test.rego | 21 -- .../criteria/transactionRequest/gas_test.rego | 29 -- .../rego/__test__/utils_test.rego | 29 -- .../rego/armory/constants/constants.rego | 35 +++ .../criteria/__test__/checkAccount_test.rego | 23 ++ .../__test__/checkApprovals_test.rego} | 39 +-- .../criteria/__test__/checkAssigned_test.rego | 8 + .../__test__/checkDestination_test.rego} | 27 +- .../__test__/checkGasFeeAmount_test.rego | 33 +++ .../__test__/checkIntentAmount_test.rego | 37 +++ .../criteria/__test__/checkNonce_test.rego} | 13 +- .../__test__/checkPermitDeadline_test.rego | 31 +++ .../__test__/checkPrincipal_test.rego | 16 ++ .../__test__/checkRateLimit_test.rego} | 45 ++-- .../__test__/checkSpendingLimit_test.rego} | 54 ++-- .../criteria/__test__}/contractCall_test.rego | 21 +- .../__test__}/contractDeploy_test.rego | 17 +- .../criteria/__test__}/permission_test.rego | 15 +- .../policies/approvals_policies_test.rego} | 12 +- .../__test__/policies/approvals_test.rego | 47 ++-- .../policies/spendings_policies_test.rego} | 22 +- .../__test__/policies/spendings_test.rego | 83 +++--- .../policies/userOperation_policy_test.rego} | 6 +- .../__test__/policies/userOperation_test.rego | 11 +- .../criteria/__test__}/signMessage_test.rego | 49 ++-- .../armory/criteria/__test__/source_test.rego | 40 +++ .../__test__}/tokenAllowance_test.rego | 23 +- .../criteria/__test__}/transferNft_test.rego | 50 ++-- .../__test__}/transferToken_test.rego | 39 +-- .../__test__}/typedDataMessage_test.rego | 19 +- .../__test__}/userOperation_test.rego | 11 +- .../armory/criteria/checkAccountAddress.rego | 11 + .../armory/criteria/checkAccountAssigned.rego | 12 + .../armory/criteria/checkAccountChainId.rego | 11 + .../armory/criteria/checkAccountGroup.rego | 12 + .../rego/armory/criteria/checkAccountId.rego | 11 + .../armory/criteria/checkAccountType.rego | 10 + .../rego/armory/criteria/checkAction.rego | 7 + .../rego/armory/criteria/checkApprovals.rego | 120 +++++++++ .../criteria/checkDestinationAccountType.rego | 10 + .../criteria/checkDestinationAddress.rego | 11 + .../checkDestinationClassification.rego | 10 + .../armory/criteria/checkDestinationId.rego | 11 + .../rego/armory/criteria/checkEntrypoint.rego | 26 ++ .../armory/criteria/checkErc1155TokenId.rego | 10 + .../criteria/checkErc1155Transfers.rego | 25 ++ .../armory/criteria/checkGasFeeAmount.rego | 88 ++++++ .../armory/criteria/checkIntentAlgorithm.rego | 7 + .../armory/criteria/checkIntentAmount.rego | 88 ++++++ .../criteria/checkIntentBeneficiary.rego | 7 + .../armory/criteria/checkIntentChainId.rego | 9 + .../armory/criteria/checkIntentContract.rego | 8 + .../armory/criteria/checkIntentDomain.rego | 31 +++ .../criteria/checkIntentHexSignature.rego | 9 + .../armory/criteria/checkIntentMessage.rego | 25 ++ .../armory/criteria/checkIntentPayload.rego | 25 ++ .../armory/criteria/checkIntentSpender.rego | 9 + .../armory/criteria/checkIntentToken.rego | 9 + .../rego/armory/criteria/checkIntentType.rego | 7 + .../checkIntentTypedDataMessage.rego} | 12 +- .../armory/criteria/checkNonceExists.rego | 7 + .../armory/criteria/checkNonceNotExists.rego | 7 + .../rego/armory/criteria/checkPermission.rego | 9 + .../armory/criteria/checkPermitDeadline.rego | 51 ++++ .../armory/criteria/checkPrincipalGroup.rego | 13 + .../armory/criteria/checkPrincipalId.rego | 12 + .../armory/criteria/checkPrincipalRole.rego | 11 + .../rego/armory/criteria/checkRateLimit.rego | 83 ++++++ .../rego/armory/criteria/checkResource.rego | 11 + .../criteria/checkSourceAccountType.rego | 10 + .../armory/criteria/checkSourceAddress.rego | 11 + .../criteria/checkSourceClassification.rego | 10 + .../rego/armory/criteria/checkSourceId.rego | 11 + .../armory/criteria/checkSpendingLimit.rego | 122 +++++++++ .../criteria/userOperation/amount/amount.rego | 69 +++++ .../checkUserOperationIntents.rego} | 80 +++--- .../destination/destination.rego | 16 ++ .../criteria/userOperation/permit/permit.rego | 51 ++++ .../userOperation/signMessage/domain.rego | 13 + .../userOperation/signMessage/message.rego | 25 ++ .../userOperation/signMessage/payload.rego | 25 ++ .../criteria/userOperation/source/source.rego | 16 ++ .../transfers/userOperation_transfer.rego | 46 ++++ .../util/__test__/transfers_test.rego | 32 +++ .../rego/armory/criteria/util/transfers.rego | 250 +++++++++++++++++ .../__test__/buildChainAccount_test.rego} | 29 +- .../entities/__test__/entityQueries_test.rego | 137 ++++++++++ .../entities/buildChainAccount.rego} | 85 +++--- .../entities}/entityQueries.rego | 117 ++++---- .../rego/armory/feeds/feeds.rego | 15 ++ .../rego/armory/lib/__test__/lib_test.rego | 7 + .../rego/armory/lib/case.rego | 24 ++ .../rego/armory/lib/number.rego | 11 + .../rego/{utils => armory/lib}/time.rego | 20 +- .../test_data}/main_test.rego | 47 ++-- .../rego/criteria/action.rego | 7 - .../rego/criteria/approval.rego | 122 --------- .../rego/criteria/intent/amount.rego | 85 ------ .../rego/criteria/intent/destination.rego | 25 -- .../rego/criteria/intent/intent.rego | 36 --- .../rego/criteria/intent/permit.rego | 49 ---- .../criteria/intent/signMessage/message.rego | 21 -- .../criteria/intent/signMessage/payload.rego | 21 -- .../criteria/intent/signTypedData/domain.rego | 28 -- .../rego/criteria/intent/source.rego | 26 -- .../rego/criteria/intent/transfers.rego | 28 -- .../intent/userOperation/entryPoint.rego | 26 -- .../intent/userOperation/intents/amount.rego | 64 ----- .../userOperation/intents/destination.rego | 13 - .../intent/userOperation/intents/permit.rego | 49 ---- .../intents/signMessage/domain.rego | 11 - .../intents/signMessage/message.rego | 21 -- .../intents/signMessage/payload.rego | 21 -- .../intent/userOperation/intents/source.rego | 13 - .../userOperation/intents/transfers.rego | 42 --- .../rego/criteria/permission.rego | 16 -- .../rego/criteria/principal.rego | 25 -- .../rego/criteria/rateLimit.rego | 76 ------ .../rego/criteria/resource.rego | 38 --- .../rego/criteria/spendingLimit.rego | 115 -------- .../rego/criteria/transactionRequest/gas.rego | 80 ------ .../criteria/transactionRequest/nonce.rego | 9 - .../resource/open-policy-agent/rego/main.rego | 112 -------- .../rego/main/default_policies.rego | 24 ++ .../open-policy-agent/rego/main/evaluate.rego | 56 ++++ .../open-policy-agent/rego/rules.template.hbs | 2 +- .../utils/__test__/entityQueries_test.rego | 135 ---------- .../open-policy-agent/rego/utils/case.rego | 26 -- .../open-policy-agent/rego/utils/number.rego | 9 - .../rego/utils/transfers.rego | 252 ------------------ examples/escrow/README.md | 4 +- 143 files changed, 2708 insertions(+), 2283 deletions(-) create mode 100644 .regal/config.yaml create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/README.md delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/amount_test.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/assigned_test.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/permit_test.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/source_test.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/principal_test.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/resource_test.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/transactionRequest/gas_test.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/__test__/utils_test.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/constants/constants.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkAccount_test.rego rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/approval_test.rego => armory/criteria/__test__/checkApprovals_test.rego} (57%) create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkAssigned_test.rego rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/intent/destination_test.rego => armory/criteria/__test__/checkDestination_test.rego} (60%) create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkGasFeeAmount_test.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkIntentAmount_test.rego rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/transactionRequest/nonce_test.rego => armory/criteria/__test__/checkNonce_test.rego} (60%) create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkPermitDeadline_test.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkPrincipal_test.rego rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/rateLimit_test.rego => armory/criteria/__test__/checkRateLimit_test.rego} (87%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/spendingLimit_test.rego => armory/criteria/__test__/checkSpendingLimit_test.rego} (72%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/intent => armory/criteria/__test__}/contractCall_test.rego (74%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/intent => armory/criteria/__test__}/contractDeploy_test.rego (70%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria => armory/criteria/__test__}/permission_test.rego (60%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/policies/approvals.rego => armory/criteria/__test__/policies/approvals_policies_test.rego} (92%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{ => armory/criteria}/__test__/policies/approvals_test.rego (63%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/policies/spendings.rego => armory/criteria/__test__/policies/spendings_policies_test.rego} (89%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{ => armory/criteria}/__test__/policies/spendings_test.rego (84%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/policies/userOperation.rego => armory/criteria/__test__/policies/userOperation_policy_test.rego} (94%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{ => armory/criteria}/__test__/policies/userOperation_test.rego (82%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/intent => armory/criteria/__test__}/signMessage_test.rego (53%) create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/source_test.rego rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/intent => armory/criteria/__test__}/tokenAllowance_test.rego (64%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/intent => armory/criteria/__test__}/transferNft_test.rego (62%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/intent => armory/criteria/__test__}/transferToken_test.rego (58%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/intent => armory/criteria/__test__}/typedDataMessage_test.rego (83%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__/criteria/intent => armory/criteria/__test__}/userOperation_test.rego (90%) create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountAddress.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountAssigned.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountChainId.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountGroup.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountId.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountType.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAction.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkApprovals.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationAccountType.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationAddress.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationClassification.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationId.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkEntrypoint.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkErc1155TokenId.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkErc1155Transfers.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkGasFeeAmount.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentAlgorithm.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentAmount.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentBeneficiary.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentChainId.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentContract.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentDomain.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentHexSignature.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentMessage.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentPayload.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentSpender.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentToken.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentType.rego rename apps/policy-engine/src/resource/open-policy-agent/rego/{criteria/intent/signTypedData/message.rego => armory/criteria/checkIntentTypedDataMessage.rego} (64%) create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkNonceExists.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkNonceNotExists.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPermission.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPermitDeadline.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalGroup.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalId.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalRole.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkRateLimit.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkResource.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceAccountType.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceAddress.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceClassification.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceId.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSpendingLimit.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/amount/amount.rego rename apps/policy-engine/src/resource/open-policy-agent/rego/{criteria/intent/userOperation/userOperation.rego => armory/criteria/userOperation/checkUserOperationIntents.rego} (64%) create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/destination/destination.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/permit/permit.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/domain.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/message.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/payload.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/source/source.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/transfers/userOperation_transfer.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/util/__test__/transfers_test.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/util/transfers.rego rename apps/policy-engine/src/resource/open-policy-agent/rego/{utils/__test__/chainAccount_test.rego => armory/entities/__test__/buildChainAccount_test.rego} (82%) create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/__test__/entityQueries_test.rego rename apps/policy-engine/src/resource/open-policy-agent/rego/{utils/chainAccount.rego => armory/entities/buildChainAccount.rego} (61%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{utils => armory/entities}/entityQueries.rego (75%) create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/feeds/feeds.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/__test__/lib_test.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/case.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/number.rego rename apps/policy-engine/src/resource/open-policy-agent/rego/{utils => armory/lib}/time.rego (52%) rename apps/policy-engine/src/resource/open-policy-agent/rego/{__test__ => armory/test_data}/main_test.rego (86%) delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/action.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/approval.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/amount.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/destination.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/intent.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/permit.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signMessage/message.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signMessage/payload.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signTypedData/domain.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/source.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/transfers.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/entryPoint.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/amount.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/destination.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/permit.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/domain.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/message.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/payload.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/source.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/transfers.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/permission.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/principal.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/rateLimit.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/resource.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/spendingLimit.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/transactionRequest/gas.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/criteria/transactionRequest/nonce.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/main.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/main/default_policies.rego create mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/main/evaluate.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/utils/__test__/entityQueries_test.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/utils/case.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/utils/number.rego delete mode 100644 apps/policy-engine/src/resource/open-policy-agent/rego/utils/transfers.rego diff --git a/.github/workflows/policy-engine.yml b/.github/workflows/policy-engine.yml index 4512ecc50..0ad62efd8 100644 --- a/.github/workflows/policy-engine.yml +++ b/.github/workflows/policy-engine.yml @@ -120,14 +120,23 @@ jobs: - name: Check out repository code uses: actions/checkout@v4 + - name: Setup Regal + uses: StyraInc/setup-regal@v1.0.0 + - name: Setup OPA uses: open-policy-agent/setup-opa@v2 with: version: latest - - name: Code format + - name: Format run: make policy-engine/rego/format/check + - name: Syntax + run: make policy-engine/rego/syntax/check + + - name: Lint + run: make policy-engine/rego/lint/check REGAL_FORMAT=github + - name: Test run: make policy-engine/rego/test diff --git a/.regal/config.yaml b/.regal/config.yaml new file mode 100644 index 000000000..f51b5a3cb --- /dev/null +++ b/.regal/config.yaml @@ -0,0 +1,72 @@ +ignore: + # Ignore userOperation files as functionality is not certain yet. + # Ignore dist and rego-build directories as they don't need linting. + files: + - '*userOperation*' + - 'dist/**' + - 'rego-build/**' +rules: + style: + # This rule is disabled in tests to let us paste in big JSON payloads without having to worry about line length. + rule-length: + level: error + ignore: + files: + - '*_test.rego' + line-length: + level: error + ignore: + files: + - '*_test.rego' + # Signal TODO comments to the PR reviewer + todo-comment: + level: warning + # We use camel case to comply with our naming conventions + prefer-snake-case: + level: ignore + # In the future, it can be beneficial to re-activate this rule to ensure one source of truth for data and input shape. + # It is already done for "data" part, through 'armory.entities' package. "input" is still accessed on the fly when needed. + # If we do so, then we can ignore this rule only in querying packages. + external-reference: + level: ignore + custom: + naming-convention: + level: error + ignore: + # Ignore the naming convention for 'policy' files - Our policy definition can't be camelCased: permit[{...}]. + files: + - '*_policies*.rego' + conventions: + # We use camelCase to comply with our monorepo naming conventions + # OPA test runner requires test rules to start with "test_", which is not camelCase. + # Regal naming conventions applies to all files, we can't subset them by file groups + # So we tolerate both standards in the same naming convetion, only for 'rules'. + - pattern: '^(test_)?[a-z]+([A-Z][a-z0-9]+)*$' + targets: + - rule + description: 'Use camelCase or test_camelCase for rules' + - pattern: '^[a-z]+([A-Z][a-z0-9]+)*$' + targets: + - function + description: 'Use camelCase for all functions' + - pattern: ^([a-z][a-z0-9]*([A-Z][a-z0-9]+)*|\$\d+)$ + targets: + - variable + description: 'Use camelCase for variables or "$number" for unused variables' + - pattern: '^[a-z]+([A-Z][a-z0-9]+)*(\.[a-z]+([A-Z][a-z0-9]+)*)*$' + targets: + - package + description: 'Use camelCase.camelCase... for packages' + # Future improvement: remove ignore for test files. + # It would be better to strictly split test and production code in different packages to make sure test code is never hit by production one + idiomatic: + directory-package-mismatch: + level: error + ignore: + files: + - '*_test.rego' + # Disabling this rule allows to call tested function from the test file without importing functionality package. + # Related to comment above, this ignore can be removed if we split test and production code in different packages. + testing: + test-outside-test-package: + level: ignore diff --git a/apps/policy-engine/Makefile b/apps/policy-engine/Makefile index 8c60d853c..29ee09bfb 100644 --- a/apps/policy-engine/Makefile +++ b/apps/policy-engine/Makefile @@ -2,6 +2,7 @@ POLICY_ENGINE_PROJECT_NAME := policy-engine POLICY_ENGINE_PROJECT_DIR := ./apps/policy-engine POLICY_ENGINE_DATABASE_SCHEMA := ${POLICY_ENGINE_PROJECT_DIR}/src/shared/module/persistence/schema/schema.prisma POLICY_ENGINE_REGO_DIST = ./dist/rego +REGAL_FORMAT ?= pretty # === Start === @@ -158,6 +159,22 @@ policy-engine/rego/format/check: opa fmt \ --fail ${POLICY_ENGINE_PROJECT_DIR}/src/resource/open-policy-agent/rego +policy-engine/rego/syntax/check: + opa check \ + --strict \ + ${POLICY_ENGINE_PROJECT_DIR}/src/resource/open-policy-agent/rego + +policy-engine/rego/lint/fix: + regal fix \ + ${POLICY_ENGINE_PROJECT_DIR}/src/resource/open-policy-agent/rego \ + --config-file .regal/config.yaml + +policy-engine/rego/lint/check: + regal lint \ + --format ${REGAL_FORMAT} \ + ${POLICY_ENGINE_PROJECT_DIR}/src/resource/open-policy-agent/rego \ + --config-file .regal/config.yaml + policy-engine/rego/test/watch: make policy-engine/rego/test ARGS=--watch diff --git a/apps/policy-engine/src/open-policy-agent/core/util/__test__/unit/rego-transpiler.util.spec.ts b/apps/policy-engine/src/open-policy-agent/core/util/__test__/unit/rego-transpiler.util.spec.ts index cb1a61c55..281778dbd 100644 --- a/apps/policy-engine/src/open-policy-agent/core/util/__test__/unit/rego-transpiler.util.spec.ts +++ b/apps/policy-engine/src/open-policy-agent/core/util/__test__/unit/rego-transpiler.util.spec.ts @@ -42,7 +42,7 @@ describe('transpileCriterion', () => { criterion: Criterion.CHECK_NONCE_EXISTS, args: null } - expect(transpileCriterion(item)).toEqual(Criterion.CHECK_NONCE_EXISTS) + expect(transpileCriterion(item)).toEqual(`criteria.${Criterion.CHECK_NONCE_EXISTS}`) }) it('returns criterion if args is an array of strings', () => { @@ -51,7 +51,7 @@ describe('transpileCriterion', () => { args: ['0x123', '0x456'] } - expect(transpileCriterion(item)).toEqual(`${Criterion.CHECK_ACCOUNT_ADDRESS}({"0x123", "0x456"})`) + expect(transpileCriterion(item)).toEqual(`criteria.${Criterion.CHECK_ACCOUNT_ADDRESS}({"0x123", "0x456"})`) }) it('returns criterion if args is an array of objects', () => { @@ -61,7 +61,7 @@ describe('transpileCriterion', () => { } expect(transpileCriterion(item)).toEqual( - `${Criterion.CHECK_ERC1155_TRANSFERS}([${item.args.map((el) => JSON.stringify(el)).join(', ')}])` + `criteria.${Criterion.CHECK_ERC1155_TRANSFERS}([${item.args.map((el) => JSON.stringify(el)).join(', ')}])` ) }) @@ -74,7 +74,7 @@ describe('transpileCriterion', () => { } } - expect(transpileCriterion(item)).toEqual(`${Criterion.CHECK_INTENT_AMOUNT}(${JSON.stringify(item.args)})`) + expect(transpileCriterion(item)).toEqual(`criteria.${Criterion.CHECK_INTENT_AMOUNT}(${JSON.stringify(item.args)})`) }) it('returns approvals criterion', () => { @@ -91,7 +91,7 @@ describe('transpileCriterion', () => { } expect(transpileCriterion(item)).toEqual( - `approvals = ${Criterion.CHECK_APPROVALS}([${item.args.map((el) => JSON.stringify(el)).join(', ')}])` + `approvals = criteria.${Criterion.CHECK_APPROVALS}([${item.args.map((el) => JSON.stringify(el)).join(', ')}])` ) }) }) diff --git a/apps/policy-engine/src/open-policy-agent/core/util/__test__/unit/wasm-build.util.spec.ts b/apps/policy-engine/src/open-policy-agent/core/util/__test__/unit/wasm-build.util.spec.ts index c04220f7c..5421c606f 100644 --- a/apps/policy-engine/src/open-policy-agent/core/util/__test__/unit/wasm-build.util.spec.ts +++ b/apps/policy-engine/src/open-policy-agent/core/util/__test__/unit/wasm-build.util.spec.ts @@ -73,8 +73,8 @@ describe('copyRegoCore', () => { destination: path }) - expect(existsSync(`${path}/criteria`)).toEqual(true) - expect(existsSync(`${path}/main.rego`)).toEqual(true) + expect(existsSync(`${path}/armory`)).toEqual(true) + expect(existsSync(`${path}/main/evaluate.rego`)).toEqual(true) }) }) @@ -128,7 +128,7 @@ describe('unzip', () => { // gzip file. That's why the `path` exists within the dist directory as // well. // See https://www.openpolicyagent.org/docs/latest/management-bundles/#bundle-file-format - expect(existsSync(`${distDirectory}/${path}/rego/main.rego`)).toEqual(true) + expect(existsSync(`${distDirectory}/${path}/rego/main/evaluate.rego`)).toEqual(true) }) }) }) diff --git a/apps/policy-engine/src/open-policy-agent/core/util/rego-transpiler.util.ts b/apps/policy-engine/src/open-policy-agent/core/util/rego-transpiler.util.ts index 3b29ca07c..5feee378e 100644 --- a/apps/policy-engine/src/open-policy-agent/core/util/rego-transpiler.util.ts +++ b/apps/policy-engine/src/open-policy-agent/core/util/rego-transpiler.util.ts @@ -15,22 +15,20 @@ export const transpileCriterion = (item: PolicyCriterion) => { if (!isEmpty(args)) { if (Array.isArray(args)) { if (typeof args[0] === 'string') { - return `${criterion}({${args.map((el) => `"${el}"`).join(', ')}})` + return `criteria.${criterion}({${args.map((el) => `"${el}"`).join(', ')}})` } if (criterion === Criterion.CHECK_APPROVALS) { // TODO: (@wcalderipe, 18/03/24): Explore with team a threat model on // string interpolation injection. - return `approvals = ${criterion}([${args.map((el) => JSON.stringify(el)).join(', ')}])` + return `approvals = criteria.${criterion}([${args.map((el) => JSON.stringify(el)).join(', ')}])` } - - return `${criterion}([${args.map((el) => JSON.stringify(el)).join(', ')}])` + return `criteria.${criterion}([${args.map((el) => JSON.stringify(el)).join(', ')}])` } - - return `${criterion}(${JSON.stringify(args)})` + return `criteria.${criterion}(${JSON.stringify(args)})` } - return `${criterion}` + return `criteria.${criterion}` } export const transpileReason = (item: Policy & { id: string }) => { diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/README.md b/apps/policy-engine/src/resource/open-policy-agent/rego/README.md new file mode 100644 index 000000000..9c5423571 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/README.md @@ -0,0 +1,44 @@ +# Packages + +## Main + +The implementation of engine general logic. This package is the one were transpiled policy are written +Transpiled policies then use Armory/criteria functions to evaluate input + +## Armory + +### Constants + +This package contains all constants that are used by production code + +### Criteria + +Criteria contains the function that build the logic for every transpiled policy. +**This package should have exactly the same number of files as we have supported criteria** + +### Feeds + +Criteria that needs to access our feeds should be depending from this package + +### Entities + +Functions used to query loaded data. It serves as a source of truth to know if something is in data.entities. + +- Enforce invariants like lowercasing hex addresses +- Aggregate data from multiple places in entity in order to build useful relationships +- build runtime types that depends on entity data result + +### Lib + +Utils that are not domain specific, like case insensitive comparison or time. + +### Test_Data + +Values that are specifically used by tests. +**this shouldn't be imported in production code** + +# Tests + +Currently tests are not separated in different package. Future improvement should be to strictly separate test and production code +By moving tests in separate packages. +We can enforce it by re-enabling `test-outside-test-package` rule in `.regal/config.yaml` diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/amount_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/amount_test.rego deleted file mode 100644 index 06f77f153..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/amount_test.rego +++ /dev/null @@ -1,32 +0,0 @@ -package main - -test_calculateIntentAmount { - resOne = calculateIntentAmount(wildcard) with input as requestWithEip1559Transaction with data.entities as entities - resOne == to_number(oneMatic) - - resTwo = calculateIntentAmount("fiat:usd") with input as requestWithEip1559Transaction with data.entities as entities - resTwo == to_number(oneMaticValue) -} - -test_checkIntentAmount { - checkIntentAmount({"operator": operators.equal, "value": oneMatic}) with input as requestWithEip1559Transaction with data.entities as entities - checkIntentAmount({"operator": operators.notEqual, "value": tenMatic}) with input as requestWithEip1559Transaction with data.entities as entities - checkIntentAmount({"operator": operators.greaterThan, "value": halfMatic}) with input as requestWithEip1559Transaction with data.entities as entities - checkIntentAmount({"operator": operators.lessThan, "value": tenMatic}) with input as requestWithEip1559Transaction with data.entities as entities - checkIntentAmount({"operator": operators.greaterThanOrEqual, "value": oneMatic}) with input as requestWithEip1559Transaction with data.entities as entities - checkIntentAmount({"operator": operators.lessThanOrEqual, "value": oneMatic}) with input as requestWithEip1559Transaction with data.entities as entities -} - -test_checkIntentAmountValue { - checkIntentAmount({"currency": "fiat:usd", "operator": operators.equal, "value": oneMaticValue}) with input as requestWithEip1559Transaction with data.entities as entities - checkIntentAmount({"currency": "fiat:usd", "operator": operators.notEqual, "value": tenMaticValue}) with input as requestWithEip1559Transaction with data.entities as entities - checkIntentAmount({"currency": "fiat:usd", "operator": operators.greaterThan, "value": halfMaticValue}) with input as requestWithEip1559Transaction with data.entities as entities - checkIntentAmount({"currency": "fiat:usd", "operator": operators.lessThan, "value": tenMaticValue}) with input as requestWithEip1559Transaction with data.entities as entities - checkIntentAmount({"currency": "fiat:usd", "operator": operators.greaterThanOrEqual, "value": oneMaticValue}) with input as requestWithEip1559Transaction with data.entities as entities - checkIntentAmount({"currency": "fiat:usd", "operator": operators.lessThanOrEqual, "value": oneMaticValue}) with input as requestWithEip1559Transaction with data.entities as entities -} - -test_checkIntentAmount2 { - requ := object.union(requestWithEip1559Transaction, {"intent": object.union(requestWithEip1559Transaction.intent, {"amount": "100000000000000000000000000000000000000000000000000000000000000000000"})}) - checkIntentAmount({"operator": operators.greaterThan, "value": "10"}) with input as requ with data.entities as entities -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/assigned_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/assigned_test.rego deleted file mode 100644 index 0f4d1bbd1..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/assigned_test.rego +++ /dev/null @@ -1,5 +0,0 @@ -package main - -test_assigned_account { - checkAccountAssigned with input as requestWithEip1559Transaction with data.entities as entities -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/permit_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/permit_test.rego deleted file mode 100644 index 381990132..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/permit_test.rego +++ /dev/null @@ -1,26 +0,0 @@ -package main - -test_permit { - permitRequest = object.union(requestWithEip1559Transaction, { - "action": "signTypedData", - "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, - "intent": { - "type": "permit", - "spender": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", - "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - "amount": "1000000000000000000", - "deadline": 1634025600, # in ms - }, - }) - checkIntentType({"permit", "permit2"}) with input as permitRequest with data.entities as entities - checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as permitRequest with data.entities as entities - checkIntentSpender({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as permitRequest with data.entities as entities - checkIntentToken({"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"}) with input as permitRequest with data.entities as entities - checkIntentAmount({"operator": operators.lessThanOrEqual, "value": "1000000000000000000"}) with input as permitRequest with data.entities as entities - checkPermitDeadline({"operator": operators.equal, "value": "1634025600"}) with input as permitRequest with data.entities as entities - checkPermitDeadline({"operator": operators.notEqual, "value": "111111111"}) with input as permitRequest with data.entities as entities - checkPermitDeadline({"operator": operators.lessThanOrEqual, "value": "1634025600"}) with input as permitRequest with data.entities as entities - checkPermitDeadline({"operator": operators.greaterThanOrEqual, "value": "1634025600"}) with input as permitRequest with data.entities as entities - checkPermitDeadline({"operator": operators.lessThan, "value": "16340256000"}) with input as permitRequest with data.entities as entities - checkPermitDeadline({"operator": operators.greaterThan, "value": "163402560"}) with input as permitRequest with data.entities as entities -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/source_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/source_test.rego deleted file mode 100644 index 3f2e3d270..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/source_test.rego +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import data.armory.lib.chainAccount.build - -test_source { - res = build.intentSourceChainAccount(input.intent) with input as requestWithEip1559Transaction with data.entities as entities - - expected := { - "id": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98E", - "address": "0xddcf208f219a6e6af072f2cfdc615b2c1805f98E", - "chainId": 137, - "classification": "managed", - "accountType": "eoa", - "assignees": ["test-bOb-uid", "test-alicE-uid", "test-foo-uid", "test-bar-uid"], - "groups": {"test-account-group-ONE-uid"}, - } - - expected == res - - checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as requestWithEip1559Transaction with data.entities as entities - checkSourceAddress({"0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as requestWithEip1559Transaction with data.entities as entities - checkSourceAccountType({"eoa"}) with input as requestWithEip1559Transaction with data.entities as entities -} - -test_source_internal_not_account { - req = object.union(requestWithEip1559Transaction, {"intent": object.union(requestWithEip1559Transaction.intent, {"from": "eip155:137:0x2227be636c3ad8cf9d08ba8bdba4abd2ef29bd23"})}) - enti = object.union( - entities, - {"addressBook": object.union(entities.addressBook, {"eip155:137:0x2227be636c3ad8cf9d08ba8bdba4abd2ef29bd23": { - "id": "eip155:137:0x2227be636c3ad8cf9d08ba8bdba4abd2ef29bd23", - "address": "0x2227be636c3ad8cf9d08ba8bdba4abd2ef29bd23", - "chainId": 137, - "classification": "internal", - }})}, - ) - checkSourceClassification({"internal"}) with input as req with data.entities as enti -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/principal_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/principal_test.rego deleted file mode 100644 index 90a92dc78..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/principal_test.rego +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import data.armory.entities.get - -test_principal { - user = get.user(input.principal.userId) with input as requestWithEip1559Transaction with data.entities as entities - - user == {"id": "test-BOB-uid", "role": "root", "groups": {"test-USER-group-one-uid", "test-USER-group-two-uid"}} - - checkPrincipalId({"test-bob-uid", "test-alice-uid"}) with input as requestWithEip1559Transaction with data.entities as entities - checkPrincipalRole({"root", "admin"}) with input as requestWithEip1559Transaction with data.entities as entities - checkPrincipalGroup({"test-user-group-one-uid"}) with input as requestWithEip1559Transaction with data.entities as entities -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/resource_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/resource_test.rego deleted file mode 100644 index 7ec663366..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/resource_test.rego +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import data.armory.entities.get - -test_resource { - account = get.account(input.resource.uid) with input as requestWithEip1559Transaction with data.entities as entities - - expected := { - "id": "eip155:eoa:0xDDcf208f219a6e6af072f2cfdc615b2c1805f98e", - "address": "0xddcf208F219a6e6af072f2cfdc615b2c1805f98e", - "accountType": "eoa", - "assignees": ["test-bOb-uid", "test-alicE-uid", "test-foo-uid", "test-bar-uid"], - "groups": {"test-account-group-ONE-uid"}, - } - account == expected - - checkAccountId({"eip155:eoa:0xdDcF208f219a6e6af072f2cfdc615b2c1805F98E"}) with input as requestWithEip1559Transaction with data.entities as entities - checkAccountAddress({"0xdDCf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as requestWithEip1559Transaction with data.entities as entities - checkAccountType({"eoa"}) with input as requestWithEip1559Transaction with data.entities as entities - checkAccountGroup({"teST-account-groUp-one-uid"}) with input as requestWithEip1559Transaction with data.entities as entities -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/transactionRequest/gas_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/transactionRequest/gas_test.rego deleted file mode 100644 index 18370ba61..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/transactionRequest/gas_test.rego +++ /dev/null @@ -1,29 +0,0 @@ -package main - -test_checkEip1559GasFeeAmount { - gasFee = 483000000000000 - gasFeeUsd = 483000000000000 * 0.99 - moreGasFee = gasFee + 1000000000 - lessGasFee = gasFee - 1000000000 - checkGasFeeAmount({"operator": operators.equal, "value": gasFee}) with input as requestWithEip1559Transaction with data.entities as entities - checkGasFeeAmount({"operator": operators.notEqual, "value": moreGasFee}) with input as requestWithEip1559Transaction with data.entities as entities - checkGasFeeAmount({"operator": operators.greaterThan, "value": lessGasFee}) with input as requestWithEip1559Transaction with data.entities as entities - checkGasFeeAmount({"operator": operators.lessThan, "value": moreGasFee}) with input as requestWithEip1559Transaction with data.entities as entities - checkGasFeeAmount({"operator": operators.greaterThanOrEqual, "value": gasFee}) with input as requestWithEip1559Transaction with data.entities as entities - checkGasFeeAmount({"operator": operators.lessThanOrEqual, "value": gasFee}) with input as requestWithEip1559Transaction with data.entities as entities - gasFeeUsd == getGasFeeAmount("fiat:usd") with input as requestWithEip1559Transaction with data.entities as entities -} - -test_checkLegacyGasFeeAmount { - legacyGasFee = 420000000000000 - legacyGasFeeUsd = 420000000000000 * 0.99 - legacyMoreGasFee = legacyGasFee + 1000000000 - legacyLessGasFee = legacyGasFee - 1000000000 - checkGasFeeAmount({"operator": operators.equal, "value": legacyGasFee}) with input as requestWithLegacyTransaction with data.entities as entities - checkGasFeeAmount({"operator": operators.notEqual, "value": legacyMoreGasFee}) with input as requestWithLegacyTransaction with data.entities as entities - checkGasFeeAmount({"operator": operators.greaterThan, "value": legacyLessGasFee}) with input as requestWithLegacyTransaction with data.entities as entities - checkGasFeeAmount({"operator": operators.lessThan, "value": legacyMoreGasFee}) with input as requestWithLegacyTransaction with data.entities as entities - checkGasFeeAmount({"operator": operators.greaterThanOrEqual, "value": legacyGasFee}) with input as requestWithLegacyTransaction with data.entities as entities - checkGasFeeAmount({"operator": operators.lessThanOrEqual, "value": legacyGasFee}) with input as requestWithLegacyTransaction with data.entities as entities - legacyGasFeeUsd == getGasFeeAmount("fiat:usd") with input as requestWithLegacyTransaction with data.entities as entities -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/utils_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/utils_test.rego deleted file mode 100644 index 930b6fa92..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/utils_test.rego +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import data.armory.lib.chainAccount.build.extractAddressFromAccountId - -test_transformIntentToTransferObject { - res = transformIntentToTransferObject(input.intent) with input as requestWithEip1559Transaction with data.entities as entities - - expected := { - "amount": "1000000000000000000", - "chainId": 137, - "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98E", - "initiatedBy": "test-bob-Uid", - "rates": {"fiat:eur": "1.10", "fiat:usd": "0.99"}, - "resourceId": "eip155:eoa:0xDDcf208f219a6e6af072f2cfdc615b2c1805f98e", - "timestamp": nowSeconds * 1000, - "to": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7A3", - "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aA84174", - } - res == expected -} - -test_parseUnits { - parseUnits("3000", 6) == 3000000000 -} - -test_extractAddressFromAccountId { - address = extractAddressFromAccountId("eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e") - address == "0xddcf208f219a6e6af072f2cfdc615b2c1805f98e" -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/constants/constants.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/constants/constants.rego new file mode 100644 index 000000000..2d4ee2776 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/constants/constants.rego @@ -0,0 +1,35 @@ +package armory.constants + +import rego.v1 + +wildcard := "*" + +actions := { + "signTransaction": "signTransaction", + "signRaw": "signRaw", + "signMessage": "signMessage", + "signTypedData": "signTypedData", + "grantPermission": "grantPermission", +} + +operators := { + "equal": "eq", + "notEqual": "ne", + "greaterThan": "gt", + "greaterThanOrEqual": "gte", + "lessThan": "lt", + "lessThanOrEqual": "lte", + # 'contains' is a restricted keyword in Rego - it's the native 'contains' function + "has": "contains", +} + +chainAssetId := { + "1": "eip155:1/slip44:60", + "10": "eip155:10/slip44:614", + "56": "eip155:56/slip44:714", + "137": "eip155:137/slip44:966", + "250": "eip155:250/slip44:1007", + "42161": "eip155:42161/slip44:9001", + "42220": "eip155:42220/slip44:52752", + "43114": "eip155:43114/slip44:9000", +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkAccount_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkAccount_test.rego new file mode 100644 index 000000000..c2ba02624 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkAccount_test.rego @@ -0,0 +1,23 @@ +package armory.criteria + +import data.armory.entities +import data.armory.testData +import rego.v1 + +test_resource if { + account = entities.getAccount(input.resource.uid) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + + expected := { + "id": "eip155:eoa:0xDDcf208f219a6e6af072f2cfdc615b2c1805f98e", + "address": "0xddcf208F219a6e6af072f2cfdc615b2c1805f98e", + "accountType": "eoa", + "assignees": ["test-bOb-uid", "test-alicE-uid", "test-foo-uid", "test-bar-uid"], + "groups": {"test-account-group-ONE-uid"}, + } + account == expected + + checkAccountId({"eip155:eoa:0xdDcF208f219a6e6af072f2cfdc615b2c1805F98E"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkAccountAddress({"0xdDCf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkAccountType({"eoa"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkAccountGroup({"teST-account-groUp-one-uid"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/approval_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkApprovals_test.rego similarity index 57% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/approval_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkApprovals_test.rego index 02fee40ac..8ca0842a6 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/approval_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkApprovals_test.rego @@ -1,39 +1,42 @@ -package main +package armory.criteria -test_checkApprovalByUserId { +import data.armory.testData +import rego.v1 + +test_checkApprovalByUserIdOneApproval if { requiredApproval = { "approvalCount": 2, "countPrincipal": true, "approvalEntityType": "Narval::User", "entityIds": ["test-bob-uid", "test-bar-uid", "test-approver-uid"], } - res = checkApproval(requiredApproval) with input as requestWithEip1559Transaction with data.entities as entities + res = checkApproval(requiredApproval) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 1 } -test_checkApprovalByUserId { +test_checkApprovalByUserIdNoApproval if { requiredApproval = { "approvalCount": 1, "countPrincipal": false, "approvalEntityType": "Narval::User", "entityIds": ["test-bob-uid", "test-bar-uid", "test-approver-uid"], } - res = checkApproval(requiredApproval) with input as requestWithEip1559Transaction with data.entities as entities + res = checkApproval(requiredApproval) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 0 } -test_checkApprovalByUserGroup { +test_checkApprovalByUserGroupOneApproval if { requiredApproval = { "approvalCount": 2, "countPrincipal": true, "approvalEntityType": "Narval::UserGroup", "entityIds": ["test-user-group-one-uid"], } - res = checkApproval(requiredApproval) with input as requestWithEip1559Transaction with data.entities as entities + res = checkApproval(requiredApproval) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 1 } -test_checkApprovalByUserGroup { +test_checkApprovalByUserGroupNoApproval if { requiredApproval = { "approvalCount": 1, "countPrincipal": false, @@ -41,35 +44,35 @@ test_checkApprovalByUserGroup { "entityIds": ["test-user-group-one-uid"], } - res = checkApproval(requiredApproval) with input as requestWithEip1559Transaction with data.entities as entities + res = checkApproval(requiredApproval) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 0 } -test_checkApprovalByUserRole { +test_checkApprovalByUserRoleTwoApprovals if { requiredApproval = { "approvalCount": 2, "countPrincipal": false, "approvalEntityType": "Narval::UserRole", "entityIds": ["root", "admin"], } - res = checkApproval(requiredApproval) with input as requestWithEip1559Transaction with data.entities as entities + res = checkApproval(requiredApproval) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 2 } -test_checkApprovalByUserRole { +test_checkApprovalByUserRoleThreeApprovals if { requiredApproval = { "approvalCount": 2, "countPrincipal": true, "approvalEntityType": "Narval::UserRole", "entityIds": ["root", "admin"], } - res = checkApproval(requiredApproval) with input as requestWithEip1559Transaction with data.entities as entities + res = checkApproval(requiredApproval) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 3 } -test_checkApprovalWithoutCountingDuplicates { - requestWithDuplicates = object.union(requestWithEip1559Transaction, {"principal": {"userId": "test-alice-uid"}, "approvals": [ +test_checkApprovalWithoutCountingDuplicates if { + requestWithDuplicates = object.union(testData.requestWithEip1559Transaction, {"principal": {"userId": "test-alice-uid"}, "approvals": [ { "userId": "test-bar-uid", "alg": "ES256K", @@ -97,12 +100,12 @@ test_checkApprovalWithoutCountingDuplicates { "entityIds": ["test-bar-uid"], } - res = checkApproval(requiredApproval) with input as requestWithDuplicates with data.entities as entities + res = checkApproval(requiredApproval) with input as requestWithDuplicates with data.entities as testData.entities res == 1 } -test_checkApprovals { +test_checkApprovals if { satisfied = { "approvalCount": 1, "countPrincipal": true, @@ -117,7 +120,7 @@ test_checkApprovals { "entityIds": ["test-bob-uid", "test-bar-uid", "test-approver-uid"], } - res = checkApprovals([satisfied, missing]) with input as requestWithEip1559Transaction with data.entities as entities + res = checkApprovals([satisfied, missing]) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == { "approvalsSatisfied": [satisfied], diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkAssigned_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkAssigned_test.rego new file mode 100644 index 000000000..45cf0ccd3 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkAssigned_test.rego @@ -0,0 +1,8 @@ +package armory.criteria + +import data.armory.testData +import rego.v1 + +test_assignedAccount if { + checkAccountAssigned with input as testData.requestWithEip1559Transaction with data.entities as testData.entities +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/destination_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkDestination_test.rego similarity index 60% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/destination_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkDestination_test.rego index a6d2e9e7a..c09d97f6c 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/destination_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkDestination_test.rego @@ -1,21 +1,24 @@ -package main +package armory.criteria -test_checkDestinationId { - checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as requestWithEip1559Transaction with data.entities as entities +import data.armory.testData +import rego.v1 + +test_checkDestinationId if { + checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities } -test_checkDestinationAddress { - checkDestinationAddress({"0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as requestWithEip1559Transaction with data.entities as entities +test_checkDestinationAddress if { + checkDestinationAddress({"0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities } -test_checkDestinationClassification { - checkDestinationClassification({"internal"}) with input as requestWithEip1559Transaction with data.entities as entities +test_checkDestinationClassification if { + checkDestinationClassification({"internal"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities } -test_checkDestinationClassification_on_managed_Account { +test_checkDestinationClassificationOnManagedAccount if { # NOTE: The Account address is the same from the Intent.to derived from - # requestWithEip1559Transaction. - checkDestinationClassification({"managed"}) with input as requestWithEip1559Transaction with data.entities as {"accounts": {"eip155:eoa:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3": { + # testData.requestWithEip1559Transaction. + checkDestinationClassification({"managed"}) with input as testData.requestWithEip1559Transaction with data.entities as {"accounts": {"eip155:eoa:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3": { "id": "eip155:eoa:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", "address": "0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", "accountType": "eoa", @@ -23,7 +26,7 @@ test_checkDestinationClassification_on_managed_Account { }}} } -test_checkDestinationClassification_on_no_addressbook_or_account { +test_checkDestinationClassificationOnNoAddressbookOrAccount if { req = { "action": "signTransaction", "principal": { @@ -54,5 +57,5 @@ test_checkDestinationClassification_on_no_addressbook_or_account { "resource": {"uid": "eip155:eoa:0x0301e2724a40e934cce3345928b88956901aa127"}, } - not checkDestinationClassification({"managed"}) with input as req with data.entities as entities + not checkDestinationClassification({"managed"}) with input as req with data.entities as testData.entities } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkGasFeeAmount_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkGasFeeAmount_test.rego new file mode 100644 index 000000000..9eb93a0b5 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkGasFeeAmount_test.rego @@ -0,0 +1,33 @@ +package armory.criteria + +import data.armory.constants +import data.armory.testData +import rego.v1 + +test_checkEip1559GasFeeAmount if { + gasFee = 483000000000000 + gasFeeUsd = 483000000000000 * 0.99 + moreGasFee = gasFee + 1000000000 + lessGasFee = gasFee - 1000000000 + checkGasFeeAmount({"operator": constants.operators.equal, "value": gasFee}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkGasFeeAmount({"operator": constants.operators.notEqual, "value": moreGasFee}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkGasFeeAmount({"operator": constants.operators.greaterThan, "value": lessGasFee}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkGasFeeAmount({"operator": constants.operators.lessThan, "value": moreGasFee}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkGasFeeAmount({"operator": constants.operators.greaterThanOrEqual, "value": gasFee}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkGasFeeAmount({"operator": constants.operators.lessThanOrEqual, "value": gasFee}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + gasFeeUsd == getGasFeeAmount("fiat:usd") with input as testData.requestWithEip1559Transaction with data.entities as testData.entities +} + +test_checkLegacyGasFeeAmount if { + legacyGasFee = 420000000000000 + legacyGasFeeUsd = 420000000000000 * 0.99 + legacyMoreGasFee = legacyGasFee + 1000000000 + legacyLessGasFee = legacyGasFee - 1000000000 + checkGasFeeAmount({"operator": constants.operators.equal, "value": legacyGasFee}) with input as testData.requestWithLegacyTransaction with data.entities as testData.entities + checkGasFeeAmount({"operator": constants.operators.notEqual, "value": legacyMoreGasFee}) with input as testData.requestWithLegacyTransaction with data.entities as testData.entities + checkGasFeeAmount({"operator": constants.operators.greaterThan, "value": legacyLessGasFee}) with input as testData.requestWithLegacyTransaction with data.entities as testData.entities + checkGasFeeAmount({"operator": constants.operators.lessThan, "value": legacyMoreGasFee}) with input as testData.requestWithLegacyTransaction with data.entities as testData.entities + checkGasFeeAmount({"operator": constants.operators.greaterThanOrEqual, "value": legacyGasFee}) with input as testData.requestWithLegacyTransaction with data.entities as testData.entities + checkGasFeeAmount({"operator": constants.operators.lessThanOrEqual, "value": legacyGasFee}) with input as testData.requestWithLegacyTransaction with data.entities as testData.entities + legacyGasFeeUsd == getGasFeeAmount("fiat:usd") with input as testData.requestWithLegacyTransaction with data.entities as testData.entities +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkIntentAmount_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkIntentAmount_test.rego new file mode 100644 index 000000000..ef5acce73 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkIntentAmount_test.rego @@ -0,0 +1,37 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants +import data.armory.testData + +test_calculateIntentAmount if { + resOne = calculateIntentAmount(constants.wildcard) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + resOne == to_number(testData.oneMatic) + + resTwo = calculateIntentAmount("fiat:usd") with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + resTwo == to_number(testData.oneMaticValue) +} + +test_checkIntentAmount if { + checkIntentAmount({"operator": constants.operators.equal, "value": testData.oneMatic}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkIntentAmount({"operator": constants.operators.notEqual, "value": testData.tenMatic}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkIntentAmount({"operator": constants.operators.greaterThan, "value": testData.halfMatic}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkIntentAmount({"operator": constants.operators.lessThan, "value": testData.tenMatic}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkIntentAmount({"operator": constants.operators.greaterThanOrEqual, "value": testData.oneMatic}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkIntentAmount({"operator": constants.operators.lessThanOrEqual, "value": testData.oneMatic}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities +} + +test_checkIntentAmountValue if { + checkIntentAmount({"currency": "fiat:usd", "operator": constants.operators.equal, "value": testData.oneMaticValue}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkIntentAmount({"currency": "fiat:usd", "operator": constants.operators.notEqual, "value": testData.tenMaticValue}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkIntentAmount({"currency": "fiat:usd", "operator": constants.operators.greaterThan, "value": testData.halfMaticValue}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkIntentAmount({"currency": "fiat:usd", "operator": constants.operators.lessThan, "value": testData.tenMaticValue}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkIntentAmount({"currency": "fiat:usd", "operator": constants.operators.greaterThanOrEqual, "value": testData.oneMaticValue}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkIntentAmount({"currency": "fiat:usd", "operator": constants.operators.lessThanOrEqual, "value": testData.oneMaticValue}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities +} + +test_checkIntentAmount2 if { + requ := object.union(testData.requestWithEip1559Transaction, {"intent": object.union(testData.requestWithEip1559Transaction.intent, {"amount": "100000000000000000000000000000000000000000000000000000000000000000000"})}) + checkIntentAmount({"operator": constants.operators.greaterThan, "value": "10"}) with input as requ with data.entities as testData.entities +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/transactionRequest/nonce_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkNonce_test.rego similarity index 60% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/transactionRequest/nonce_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkNonce_test.rego index 447539f3c..2d050a7aa 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/transactionRequest/nonce_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkNonce_test.rego @@ -1,10 +1,13 @@ -package main +package armory.criteria -test_checkNonceExists { - checkNonceExists with input as requestWithEip1559Transaction with data.entities as entities +import data.armory.testData +import rego.v1 + +test_checkNonceExists if { + checkNonceExists with input as testData.requestWithEip1559Transaction with data.entities as testData.entities } -test_checkNonceNotExists { +test_checkNonceNotExists if { requestWithoutNonce = {"transactionRequest": { "from": "0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "to": "0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", @@ -17,5 +20,5 @@ test_checkNonceNotExists { "type": "2", }} - checkNonceNotExists with input as requestWithoutNonce with data.entities as entities + checkNonceNotExists with input as requestWithoutNonce with data.entities as testData.entities } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkPermitDeadline_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkPermitDeadline_test.rego new file mode 100644 index 000000000..f27b19d07 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkPermitDeadline_test.rego @@ -0,0 +1,31 @@ +package armory.criteria + +import data.armory.testData +import rego.v1 + +import data.armory.constants + +test_permit if { + permitRequest = object.union(testData.requestWithEip1559Transaction, { + "action": "signTypedData", + "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, + "intent": { + "type": "permit", + "spender": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", + "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", + "amount": "1000000000000000000", + "deadline": 1634025600, # in ms + }, + }) + checkIntentType({"permit", "permit2"}) with input as permitRequest with data.entities as testData.entities + checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as permitRequest with data.entities as testData.entities + checkIntentSpender({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as permitRequest with data.entities as testData.entities + checkIntentToken({"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"}) with input as permitRequest with data.entities as testData.entities + checkIntentAmount({"operator": constants.operators.lessThanOrEqual, "value": "1000000000000000000"}) with input as permitRequest with data.entities as testData.entities + checkPermitDeadline({"operator": constants.operators.equal, "value": "1634025600"}) with input as permitRequest with data.entities as testData.entities + checkPermitDeadline({"operator": constants.operators.notEqual, "value": "111111111"}) with input as permitRequest with data.entities as testData.entities + checkPermitDeadline({"operator": constants.operators.lessThanOrEqual, "value": "1634025600"}) with input as permitRequest with data.entities as testData.entities + checkPermitDeadline({"operator": constants.operators.greaterThanOrEqual, "value": "1634025600"}) with input as permitRequest with data.entities as testData.entities + checkPermitDeadline({"operator": constants.operators.lessThan, "value": "16340256000"}) with input as permitRequest with data.entities as testData.entities + checkPermitDeadline({"operator": constants.operators.greaterThan, "value": "163402560"}) with input as permitRequest with data.entities as testData.entities +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkPrincipal_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkPrincipal_test.rego new file mode 100644 index 000000000..e02b2f73a --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkPrincipal_test.rego @@ -0,0 +1,16 @@ +package armory.criteria + +import data.armory.testData +import rego.v1 + +import data.armory.entities + +test_principal if { + user = entities.getUser(input.principal.userId) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + + user == {"id": "test-BOB-uid", "role": "root", "groups": {"test-USER-group-one-uid", "test-USER-group-two-uid"}} + + checkPrincipalId({"test-bob-uid", "test-alice-uid"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkPrincipalRole({"root", "admin"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkPrincipalGroup({"test-user-group-one-uid"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/rateLimit_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkRateLimit_test.rego similarity index 87% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/rateLimit_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkRateLimit_test.rego index 8844e4d62..edeef1cf7 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/rateLimit_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkRateLimit_test.rego @@ -1,6 +1,10 @@ -package main +package armory.criteria -rateFixedPeriodRequest = object.union(requestWithEip1559Transaction, { +import data.armory.lib +import data.armory.testData +import rego.v1 + +rateFixedPeriodRequest := object.union(testData.requestWithEip1559Transaction, { "principal": {"userId": "test-alice-uid"}, "intent": { "type": "transferERC20", @@ -35,7 +39,7 @@ rateFixedPeriodRequest = object.union(requestWithEip1559Transaction, { "to": "eip155:137:0x000c0d191308a336356bee3813cc17f6868972c4", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99", "fiat:eur": "1.10"}, - "timestamp": (getStartDateInNanoSeconds("1d") / 1000000) + ((60 * 60) * 1000), # current day plus 1 hour + "timestamp": (lib.getStartDateInNanoSeconds("1d") / 1000000) + ((60 * 60) * 1000), # current day plus 1 hour "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -46,7 +50,7 @@ rateFixedPeriodRequest = object.union(requestWithEip1559Transaction, { "to": "eip155:137:0x000c0d191308a336356bee3813cc17f6868972c4", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99", "fiat:eur": "1.10"}, - "timestamp": (getStartDateInNanoSeconds("1d") / 1000000) - (((2 * 60) * 60) * 1000), # the day before minus 2 hours + "timestamp": (lib.getStartDateInNanoSeconds("1d") / 1000000) - (((2 * 60) * 60) * 1000), # the day before minus 2 hours "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -57,7 +61,7 @@ rateFixedPeriodRequest = object.union(requestWithEip1559Transaction, { "to": "eip155:137:0x000c0d191308a336356bee3813cc17f6868972c4", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99", "fiat:eur": "1.10"}, - "timestamp": (getStartDateInNanoSeconds("1d") / 1000000) - ((60 * 60) * 1000), # the day before minus 1 hour + "timestamp": (lib.getStartDateInNanoSeconds("1d") / 1000000) - ((60 * 60) * 1000), # the day before minus 1 hour "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -66,7 +70,7 @@ rateFixedPeriodRequest = object.union(requestWithEip1559Transaction, { ], }) -test_calculateCurrentRateByRollingPeriod { +test_calculateCurrentRateByRollingPeriod if { conditions = { "limit": 10, "timeWindow": { @@ -79,11 +83,11 @@ test_calculateCurrentRateByRollingPeriod { }, } - res = calculateCurrentRate(conditions) with input as requestWithEip1559Transaction with data.entities as entities + res = calculateCurrentRate(conditions) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 2 } -test_calculateCurrentRateByRollingPeriod { +test_calculateCurrentRateByRollingPeriodAlice if { conditions = { "limit": 10, "timeWindow": { @@ -96,11 +100,11 @@ test_calculateCurrentRateByRollingPeriod { }, } - res = calculateCurrentRate(conditions) with input as requestWithEip1559Transaction with data.entities as entities + res = calculateCurrentRate(conditions) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 3 } -test_calculateCurrentRateByRollingPeriod { +test_calculateCurrentRateByRollingPeriodBob if { conditions = { "limit": 10, "timeWindow": { @@ -113,11 +117,11 @@ test_calculateCurrentRateByRollingPeriod { }, } - res = calculateCurrentRate(conditions) with input as requestWithEip1559Transaction with data.entities as entities + res = calculateCurrentRate(conditions) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 1 } -test_calculateCurrentRateByFixedPeriod { +test_calculateCurrentRateByFixedPeriodAlice if { conditions = { "limit": 10, "timeWindow": { @@ -130,12 +134,12 @@ test_calculateCurrentRateByFixedPeriod { }, } - res = calculateCurrentRate(conditions) with input as rateFixedPeriodRequest with data.entities as entities + res = calculateCurrentRate(conditions) with input as rateFixedPeriodRequest with data.entities as testData.entities res == 2 } -test_calculateCurrentRateByFixedPeriod { +test_calculateCurrentRateByFixedPeriodBob if { conditions = { "limit": 10, "timeWindow": { @@ -148,11 +152,11 @@ test_calculateCurrentRateByFixedPeriod { }, } - res = calculateCurrentRate(conditions) with input as rateFixedPeriodRequest with data.entities as entities + res = calculateCurrentRate(conditions) with input as rateFixedPeriodRequest with data.entities as testData.entities res == 0 } -test_calculateCurrentRateForUserOperationIntent { +test_calculateCurrentRateForUserOperationIntent if { userOperationRequest = object.union(rateFixedPeriodRequest, {"intent": { "type": "userOperation", "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", @@ -195,11 +199,12 @@ test_calculateCurrentRateForUserOperationIntent { }, } - res = calculateCurrentRate(conditions) with input as userOperationRequest with data.entities as entities + res = calculateCurrentRate(conditions) with input as userOperationRequest with data.entities as testData.entities + res == 2 } -test_checkRateLimitPerPrincipal { +test_checkRateLimitPerPrincipal if { inputReq = { "action": "signTransaction", "principal": { @@ -266,7 +271,7 @@ test_checkRateLimitPerPrincipal { "rates": {}, "initiatedBy": "test-bob-user-uid", "createdAt": "2024-08-22T10:24:15.729Z", - "timestamp": time.now_ns(), + "timestamp": lib.nowSeconds * 1000, }, { "id": "111118953-2d66-4f42-ae98-8bfd7f26ed98", @@ -280,7 +285,7 @@ test_checkRateLimitPerPrincipal { "rates": {}, "initiatedBy": "test-bob-user-uid", "createdAt": "2024-08-22T10:24:15.729Z", - "timestamp": time.now_ns(), + "timestamp": lib.nowSeconds * 1000, }, ], }, diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/spendingLimit_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkSpendingLimit_test.rego similarity index 72% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/spendingLimit_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkSpendingLimit_test.rego index 25e439e96..17bcb4537 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/spendingLimit_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/checkSpendingLimit_test.rego @@ -1,6 +1,10 @@ -package main +package armory.criteria -spendingsFixedPeriodRequest = object.union(requestWithEip1559Transaction, { +import data.armory.lib +import data.armory.testData +import rego.v1 + +spendingsFixedPeriodRequest := object.union(testData.requestWithEip1559Transaction, { "principal": {"userId": "test-alice-uid"}, "intent": { "type": "transferERC20", @@ -35,7 +39,7 @@ spendingsFixedPeriodRequest = object.union(requestWithEip1559Transaction, { "to": "eip155:137:0x000c0d191308a336356bee3813cc17f6868972c4", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99", "fiat:eur": "1.10"}, - "timestamp": (getStartDateInNanoSeconds("1d") / 1000000) + ((60 * 60) * 1000), # current day plus 1 hour + "timestamp": (lib.getStartDateInNanoSeconds("1d") / 1000000) + ((60 * 60) * 1000), # current day plus 1 hour "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -46,7 +50,7 @@ spendingsFixedPeriodRequest = object.union(requestWithEip1559Transaction, { "to": "eip155:137:0x000c0d191308a336356bee3813cc17f6868972c4", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99", "fiat:eur": "1.10"}, - "timestamp": (getStartDateInNanoSeconds("1d") / 1000000) - (((2 * 60) * 60) * 1000), # the day before minus 2 hours + "timestamp": (lib.getStartDateInNanoSeconds("1d") / 1000000) - (((2 * 60) * 60) * 1000), # the day before minus 2 hours "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -57,7 +61,7 @@ spendingsFixedPeriodRequest = object.union(requestWithEip1559Transaction, { "to": "eip155:137:0x000c0d191308a336356bee3813cc17f6868972c4", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99", "fiat:eur": "1.10"}, - "timestamp": (getStartDateInNanoSeconds("1d") / 1000000) - ((60 * 60) * 1000), # the day before minus 1 hour + "timestamp": (lib.getStartDateInNanoSeconds("1d") / 1000000) - ((60 * 60) * 1000), # the day before minus 1 hour "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -66,7 +70,7 @@ spendingsFixedPeriodRequest = object.union(requestWithEip1559Transaction, { ], }) -test_calculateCurrentSpendingsByRollingPeriod { +test_calculateCurrentSpendingsByRollingPeriodPerToken if { conditions = { "timeWindow": { "type": "rolling", @@ -78,11 +82,11 @@ test_calculateCurrentSpendingsByRollingPeriod { }, } - res = calculateCurrentSpendings(conditions) with input as requestWithEip1559Transaction with data.entities as entities + res = calculateCurrentSpendings(conditions) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 400000000000000000 } -test_calculateCurrentSpendingsByRollingPeriod { +test_calculateCurrentSpendingsByRollingPeriodPerUsd if { conditions = { "currency": "fiat:usd", "timeWindow": { @@ -95,11 +99,11 @@ test_calculateCurrentSpendingsByRollingPeriod { }, } - res = calculateCurrentSpendings(conditions) with input as requestWithEip1559Transaction with data.entities as entities + res = calculateCurrentSpendings(conditions) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 396000000000000000 # convert amount to fiat } -test_calculateCurrentSpendingsByRollingPeriod { +test_calculateCurrentSpendingsByRollingPerioWithBob if { conditions = { "timeWindow": { "type": "rolling", @@ -111,11 +115,11 @@ test_calculateCurrentSpendingsByRollingPeriod { }, } - res = calculateCurrentSpendings(conditions) with input as requestWithEip1559Transaction with data.entities as entities + res = calculateCurrentSpendings(conditions) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 1000000000000000000 } -test_calculateCurrentSpendingsByFixedPeriod { +test_calculateCurrentSpendingsByFixedPeriod if { conditions = { "timeWindow": { "type": "fixed", @@ -127,11 +131,11 @@ test_calculateCurrentSpendingsByFixedPeriod { }, } - res = calculateCurrentSpendings(conditions) with input as spendingsFixedPeriodRequest with data.entities as entities + res = calculateCurrentSpendings(conditions) with input as spendingsFixedPeriodRequest with data.entities as testData.entities res == 400000000000000000 } -test_calculateCurrentSpendingsByFixedPeriod { +test_calculateCurrentSpendingsByFixedPeriodPerUsd if { conditions = { "currency": "fiat:usd", "timeWindow": { @@ -144,11 +148,11 @@ test_calculateCurrentSpendingsByFixedPeriod { }, } - res = calculateCurrentSpendings(conditions) with input as spendingsFixedPeriodRequest with data.entities as entities + res = calculateCurrentSpendings(conditions) with input as spendingsFixedPeriodRequest with data.entities as testData.entities res == 396000000000000000 # convert amount to fiat } -test_calculateCurrentSpendingsByFixedPeriod { +test_calculateCurrentSpendingsByFixedPeriodPerToken if { conditions = { "timeWindow": { "type": "fixed", @@ -160,34 +164,34 @@ test_calculateCurrentSpendingsByFixedPeriod { }, } - res = calculateCurrentSpendings(conditions) with input as spendingsFixedPeriodRequest with data.entities as entities + res = calculateCurrentSpendings(conditions) with input as spendingsFixedPeriodRequest with data.entities as testData.entities res == 0 } -test_calculateCurrentSpendingsByPrincipal { +test_calculateCurrentSpendingsByPrincipal if { conditions = {"filters": { "perPrincipal": true, "tokens": {"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"}, }} - res = calculateCurrentSpendings(conditions) with input as requestWithEip1559Transaction with data.entities as entities + res = calculateCurrentSpendings(conditions) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities res == 1000000000000000000 } -test_calculateCurrentSpendingsByPrincipal { - perPrincipalReq = object.union(requestWithEip1559Transaction, {"principal": {"userId": "test-alice-uid"}}) +test_calculateCurrentSpendingsByPrincipalWithAlice if { + prePrincipalReq = object.union(testData.requestWithEip1559Transaction, {"principal": {"userId": "test-alice-uid"}}) conditions = {"filters": { "perPrincipal": true, "tokens": {"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"}, }} - res = calculateCurrentSpendings(conditions) with input as perPrincipalReq with data.entities as entities + res = calculateCurrentSpendings(conditions) with input as prePrincipalReq with data.entities as testData.entities res == 1600000000000000000 } -test_calculateCurrentSpendingsForUserOperationIntent { - userOperationRequest = object.union(requestWithEip1559Transaction, { +test_calculateCurrentSpendingsForUserOperationIntent if { + userOperationRequest = object.union(testData.requestWithEip1559Transaction, { "principal": {"userId": "test-alice-uid"}, "intent": { "type": "userOperation", @@ -231,7 +235,7 @@ test_calculateCurrentSpendingsForUserOperationIntent { }, } - res = calculateCurrentSpendings(conditions) with input as userOperationRequest with data.entities as entities + res = calculateCurrentSpendings(conditions) with input as userOperationRequest with data.entities as testData.entities res == 2400000000000000000 } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/contractCall_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/contractCall_test.rego similarity index 74% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/contractCall_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/contractCall_test.rego index 2b75f0821..da15fe903 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/contractCall_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/contractCall_test.rego @@ -1,7 +1,10 @@ -package main +package armory.criteria -test_contractCall { - contractCallRequest = object.union(requestWithEip1559Transaction, { +import data.armory.testData +import rego.v1 + +test_contractCall if { + contractCallRequest = object.union(testData.requestWithEip1559Transaction, { "action": "signTransaction", "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "intent": { @@ -12,10 +15,10 @@ test_contractCall { "hexSignature": "0x12345", }, }) - checkIntentType({"contractCall"}) with input as contractCallRequest with data.entities as entities - checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as contractCallRequest with data.entities as entities - checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as contractCallRequest with data.entities as entities - checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as contractCallRequest with data.entities as entities - checkIntentContract({"eip155:137/erc721:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4"}) with input as contractCallRequest with data.entities as entities - checkIntentHexSignature({"0x12345"}) with input as contractCallRequest with data.entities as entities + checkIntentType({"contractCall"}) with input as contractCallRequest with data.entities as testData.entities + checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as contractCallRequest with data.entities as testData.entities + checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as contractCallRequest with data.entities as testData.entities + checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as contractCallRequest with data.entities as testData.entities + checkIntentContract({"eip155:137/erc721:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4"}) with input as contractCallRequest with data.entities as testData.entities + checkIntentHexSignature({"0x12345"}) with input as contractCallRequest with data.entities as testData.entities } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/contractDeploy_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/contractDeploy_test.rego similarity index 70% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/contractDeploy_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/contractDeploy_test.rego index d77de613f..e9b670ef1 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/contractDeploy_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/contractDeploy_test.rego @@ -1,7 +1,10 @@ -package main +package armory.criteria -test_contractDeploy { - contractDeployRequest = object.union(requestWithEip1559Transaction, { +import data.armory.testData +import rego.v1 + +test_contractDeploy if { + contractDeployRequest = object.union(testData.requestWithEip1559Transaction, { "action": "signTransaction", "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "intent": { @@ -10,8 +13,8 @@ test_contractDeploy { "chainId": "137", }, }) - checkIntentType({"deployContract", "deployErc4337Account", "deploySafeAccount"}) with input as contractDeployRequest with data.entities as entities - checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as contractDeployRequest with data.entities as entities - checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as contractDeployRequest with data.entities as entities - checkIntentChainId({"137"}) with input as contractDeployRequest with data.entities as entities + checkIntentType({"deployContract", "deployErc4337Account", "deploySafeAccount"}) with input as contractDeployRequest with data.entities as testData.entities + checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as contractDeployRequest with data.entities as testData.entities + checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as contractDeployRequest with data.entities as testData.entities + checkIntentChainId({"137"}) with input as contractDeployRequest with data.entities as testData.entities } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/permission_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/permission_test.rego similarity index 60% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/permission_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/permission_test.rego index de1395dc2..58b6e1e8e 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/permission_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/permission_test.rego @@ -1,14 +1,17 @@ -package main +package armory.criteria -test_permission { +import data.armory.testData +import rego.v1 + +test_permission if { grantPermissionRequest = { "action": "grantPermission", "principal": {"userId": "test-bar-uid"}, "resource": {"uid": "vault"}, "permissions": ["wallet:read", "wallet:create", "wallet:import"], } - checkAction({"grantPermission"}) with input as grantPermissionRequest with data.entities as entities - checkPrincipalRole({"admin"}) with input as grantPermissionRequest with data.entities as entities - checkResource({"vault"}) with input as grantPermissionRequest with data.entities as entities - checkPermission({"wallet:read", "wallet:create", "wallet:import"}) with input as grantPermissionRequest with data.entities as entities + checkAction({"grantPermission"}) with input as grantPermissionRequest with data.entities as testData.entities + checkPrincipalRole({"admin"}) with input as grantPermissionRequest with data.entities as testData.entities + checkResource({"vault"}) with input as grantPermissionRequest with data.entities as testData.entities + checkPermission({"wallet:read", "wallet:create", "wallet:import"}) with input as grantPermissionRequest with data.entities as testData.entities } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/approvals.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/approvals_policies_test.rego similarity index 92% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/approvals.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/approvals_policies_test.rego index 562ae51b7..96942498f 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/approvals.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/approvals_policies_test.rego @@ -1,8 +1,8 @@ -package main +package armory.criteria -import future.keywords.in +import rego.v1 -permit[{"policyId": "approvalByUsers"}] = reason { +permit[{"policyId": "approvalByUsers"}] := reason if { resources = {"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"} transferTypes = {"transferERC20"} tokens = {"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"} @@ -32,7 +32,7 @@ permit[{"policyId": "approvalByUsers"}] = reason { } } -permit[{"policyId": "approvalByUserGroups"}] = reason { +permit[{"policyId": "approvalByUserGroups"}] := reason if { resources = {"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"} transferTypes = {"transferERC20"} tokens = {"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"} @@ -61,7 +61,7 @@ permit[{"policyId": "approvalByUserGroups"}] = reason { } } -permit[{"policyId": "approvalByUserRoles"}] = reason { +permit[{"policyId": "approvalByUserRoles"}] := reason if { resources = {"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"} transferTypes = {"transferERC20"} tokens = {"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"} @@ -91,7 +91,7 @@ permit[{"policyId": "approvalByUserRoles"}] = reason { } } -permit[{"policyId": "withoutApprovals"}] = reason { +permit[{"policyId": "withoutApprovals"}] := reason if { resources = {"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"} transferTypes = {"transferERC20"} tokens = {"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/approvals_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/approvals_test.rego similarity index 63% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/approvals_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/approvals_test.rego index a38bdbb94..b98c50c6c 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/approvals_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/approvals_test.rego @@ -1,7 +1,10 @@ -package main +package armory.criteria -test_approvalByUsers { - approvalByUsersReq = object.union(requestWithEip1559Transaction, { +import data.armory.testData +import rego.v1 + +test_approvalByUsers if { + approvalByUsersReq = object.union(testData.requestWithEip1559Transaction, { "principal": {"userId": "test-alice-uid"}, "approvals": [ {"userId": "test-bob-uid"}, @@ -9,7 +12,7 @@ test_approvalByUsers { ], }) - res = permit[{"policyId": "approvalByUsers"}] with input as approvalByUsersReq with data.entities as entities + res = permit[{"policyId": "approvalByUsers"}] with input as approvalByUsersReq with data.entities as testData.entities res == { "approvalsMissing": [], @@ -24,8 +27,8 @@ test_approvalByUsers { } } -test_approvalByUserGroups { - approvalByUserGroupsReq = object.union(requestWithEip1559Transaction, { +test_approvalByUserGroups if { + approvalByUserGroupsReq = object.union(testData.requestWithEip1559Transaction, { "principal": {"userId": "test-alice-uid"}, "approvals": [ {"userId": "test-bob-uid"}, @@ -33,7 +36,7 @@ test_approvalByUserGroups { ], }) - res = permit[{"policyId": "approvalByUserGroups"}] with input as approvalByUserGroupsReq with data.entities as entities + res = permit[{"policyId": "approvalByUserGroups"}] with input as approvalByUserGroupsReq with data.entities as testData.entities expected := { "approvalsMissing": [], @@ -49,8 +52,8 @@ test_approvalByUserGroups { res == expected } -test_approvalByUserRoles { - approvalByUserRolesReq = object.union(requestWithEip1559Transaction, { +test_approvalByUserRoles if { + approvalByUserRolesReq = object.union(testData.requestWithEip1559Transaction, { "principal": {"userId": "test-alice-uid"}, "approvals": [ {"userId": "test-bar-uid"}, @@ -58,7 +61,7 @@ test_approvalByUserRoles { ], }) - res = permit[{"policyId": "approvalByUserRoles"}] with input as approvalByUserRolesReq with data.entities as entities + res = permit[{"policyId": "approvalByUserRoles"}] with input as approvalByUserRolesReq with data.entities as testData.entities res == { "approvalsMissing": [], @@ -73,16 +76,16 @@ test_approvalByUserRoles { } } -test_withoutApprovalsEIP1559 { +test_withoutApprovalsEip1559 if { withoutApprovalsReq = { "action": "signTransaction", - "transactionRequest": transactionRequestEIP1559, - "principal": principalReq, - "resource": resourceReq, - "intent": intentReq, + "transactionRequest": testData.transactionRequestEip1559, + "principal": testData.principalReq, + "resource": testData.resourceReq, + "intent": testData.intentReq, } - res := permit[{"policyId": "withoutApprovals"}] with input as withoutApprovalsReq with data.entities as entities + res := permit[{"policyId": "withoutApprovals"}] with input as withoutApprovalsReq with data.entities as testData.entities res == { "type": "permit", @@ -92,16 +95,16 @@ test_withoutApprovalsEIP1559 { } } -test_withoutApprovalsLegacy { +test_withoutApprovalsLegacy if { withoutApprovalsReq = { "action": "signTransaction", - "transactionRequest": transactionRequestLegacy, - "principal": principalReq, - "resource": resourceReq, - "intent": intentReq, + "transactionRequest": testData.transactionRequestLegacy, + "principal": testData.principalReq, + "resource": testData.resourceReq, + "intent": testData.intentReq, } - res := permit[{"policyId": "withoutApprovals"}] with input as withoutApprovalsReq with data.entities as entities + res := permit[{"policyId": "withoutApprovals"}] with input as withoutApprovalsReq with data.entities as testData.entities res == { "type": "permit", diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/spendings.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/spendings_policies_test.rego similarity index 89% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/spendings.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/spendings_policies_test.rego index a51f48ceb..94282a73c 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/spendings.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/spendings_policies_test.rego @@ -1,9 +1,9 @@ -package main +package armory.criteria -import future.keywords.in +import rego.v1 # Members can't transfer >$5k usd value of USDC in 12 hours on a rolling basis -forbid[{"policyId": "spendingLimitByRole"}] = reason { +forbid[{"policyId": "spendingLimitByRole"}] := reason if { checkAccountAssigned checkAction({"signTransaction"}) checkIntentType({"transferERC20"}) @@ -30,7 +30,7 @@ forbid[{"policyId": "spendingLimitByRole"}] = reason { } # Alice can't transfer >$5k usd value of USDC in 12 hours on a rolling basis -forbid[{"policyId": "spendingLimitByUser"}] = reason { +forbid[{"policyId": "spendingLimitByUser"}] := reason if { checkAccountAssigned checkAction({"signTransaction"}) checkPrincipalId({"test-alice-uid"}) @@ -55,7 +55,7 @@ forbid[{"policyId": "spendingLimitByUser"}] = reason { } # Resource account can't transfer > $5k usd value in 12 hours on a rolling basis -forbid[{"policyId": "spendingLimitByAccountResource"}] = reason { +forbid[{"policyId": "spendingLimitByAccountResource"}] := reason if { checkAccountAssigned checkAction({"signTransaction"}) checkIntentType({"transferERC20"}) @@ -79,7 +79,7 @@ forbid[{"policyId": "spendingLimitByAccountResource"}] = reason { } # User group can't transfer > $5k usd value in 12 hours on a rolling basis -forbid[{"policyId": "spendingLimitByUserGroup"}] = reason { +forbid[{"policyId": "spendingLimitByUserGroup"}] := reason if { checkAccountAssigned checkAction({"signTransaction"}) checkIntentType({"transferERC20"}) @@ -102,7 +102,7 @@ forbid[{"policyId": "spendingLimitByUserGroup"}] = reason { } # Account group can't transfer > $5k usd value in 12 hours on a rolling basis -forbid[{"policyId": "spendingLimitByAccountGroup"}] = reason { +forbid[{"policyId": "spendingLimitByAccountGroup"}] := reason if { checkAccountAssigned checkAction({"signTransaction"}) checkIntentType({"transferERC20"}) @@ -126,7 +126,7 @@ forbid[{"policyId": "spendingLimitByAccountGroup"}] = reason { } # If Alice transfers >$5k usd value of USDC in a 12 hour rolling window, then require approvals -permit[{"policyId": "spendingLimitWithApprovals"}] = reason { +permit[{"policyId": "spendingLimitWithApprovals"}] := reason if { checkAccountAssigned checkAction({"signTransaction"}) checkIntentType({"transferERC20"}) @@ -160,7 +160,7 @@ permit[{"policyId": "spendingLimitWithApprovals"}] = reason { } # Allow Alice to transfer up to 1 USDC per day -permit[{"policyId": "spendingLimitWithFixedPeriod"}] = reason { +permit[{"policyId": "spendingLimitWithFixedPeriod"}] := reason if { checkAccountAssigned checkAction({"signTransaction"}) checkIntentType({"transferERC20"}) @@ -185,7 +185,7 @@ permit[{"policyId": "spendingLimitWithFixedPeriod"}] = reason { } } -permit[{"policyId": "spendingLimitWithRange"}] = reason { +permit[{"policyId": "spendingLimitWithRange"}] := reason if { checkIntentToken({"eip155:1/slip44:60"}) checkSpendingLimit({ "limit": "1000000000000000000", @@ -220,7 +220,7 @@ permit[{"policyId": "spendingLimitWithRange"}] = reason { } } -pemrmit[{"policyId": "minimalSpendingLimit"}] = reason { +pemrmit[{"policyId": "minimalSpendingLimit"}] := reason if { checkSpendingLimit({ "limit": "1", "operator": "lte", diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/spendings_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/spendings_test.rego similarity index 84% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/spendings_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/spendings_test.rego index 67c01f532..6cb5a6e53 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/spendings_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/spendings_test.rego @@ -1,12 +1,15 @@ -package main +package armory.criteria -spendingLimitReq = object.union(requestWithEip1559Transaction, { +import data.armory.testData +import rego.v1 + +spendingLimitReq := object.union(testData.requestWithEip1559Transaction, { "principal": {"userId": "test-alice-uid"}, "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, }) -test_spendingLimitByRole { - res = forbid[{"policyId": "spendingLimitByRole"}] with input as spendingLimitReq with data.entities as entities +test_spendingLimitByRole if { + res = forbid[{"policyId": "spendingLimitByRole"}] with input as spendingLimitReq with data.entities as testData.entities res == { "type": "forbid", @@ -16,8 +19,8 @@ test_spendingLimitByRole { } } -test_spendingLimitByUser { - res = forbid[{"policyId": "spendingLimitByUser"}] with input as spendingLimitReq with data.entities as entities +test_spendingLimitByUser if { + res = forbid[{"policyId": "spendingLimitByUser"}] with input as spendingLimitReq with data.entities as testData.entities res == { "type": "forbid", @@ -27,8 +30,8 @@ test_spendingLimitByUser { } } -test_spendingLimitByAccountResource { - res = forbid[{"policyId": "spendingLimitByAccountResource"}] with input as spendingLimitReq with data.entities as entities +test_spendingLimitByAccountResource if { + res = forbid[{"policyId": "spendingLimitByAccountResource"}] with input as spendingLimitReq with data.entities as testData.entities res == { "type": "forbid", @@ -38,7 +41,7 @@ test_spendingLimitByAccountResource { } } -test_spendingLimitByUserGroup { +test_spendingLimitByUserGroup if { spendingLimitByUserGroupReq = object.union(spendingLimitReq, { "principal": {"userId": "test-bar-uid"}, "feeds": [ @@ -64,7 +67,7 @@ test_spendingLimitByUserGroup { "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99"}, - "timestamp": elevenHoursAgo, + "timestamp": testData.elevenHoursAgo, "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -73,7 +76,7 @@ test_spendingLimitByUserGroup { "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99"}, - "timestamp": tenHoursAgo, + "timestamp": testData.tenHoursAgo, "chainId": 137, "initiatedBy": "test-bar-uid", }, @@ -82,7 +85,7 @@ test_spendingLimitByUserGroup { "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99"}, - "timestamp": twentyHoursAgo, + "timestamp": testData.twentyHoursAgo, "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -91,7 +94,7 @@ test_spendingLimitByUserGroup { ], }) - res = forbid[{"policyId": "spendingLimitByUserGroup"}] with input as spendingLimitByUserGroupReq with data.entities as entities + res = forbid[{"policyId": "spendingLimitByUserGroup"}] with input as spendingLimitByUserGroupReq with data.entities as testData.entities res == { "type": "forbid", @@ -101,7 +104,7 @@ test_spendingLimitByUserGroup { } } -test_spendingLimitByAccountGroup { +test_spendingLimitByAccountGroup if { spendingLimitByAccountGroupReq = object.union(spendingLimitReq, { "principal": {"userId": "test-bar-uid"}, "feeds": [ @@ -127,7 +130,7 @@ test_spendingLimitByAccountGroup { "from": "eip155:137:0xbbbb208f219a6e6af072f2cfdc615b2c1805f98e", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99"}, - "timestamp": elevenHoursAgo, + "timestamp": testData.elevenHoursAgo, "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -136,7 +139,7 @@ test_spendingLimitByAccountGroup { "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99"}, - "timestamp": tenHoursAgo, + "timestamp": testData.tenHoursAgo, "chainId": 137, "initiatedBy": "test-bar-uid", }, @@ -145,7 +148,7 @@ test_spendingLimitByAccountGroup { "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99"}, - "timestamp": twentyHoursAgo, + "timestamp": testData.twentyHoursAgo, "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -154,7 +157,7 @@ test_spendingLimitByAccountGroup { ], }) - res = forbid[{"policyId": "spendingLimitByAccountGroup"}] with input as spendingLimitByAccountGroupReq with data.entities as entities + res = forbid[{"policyId": "spendingLimitByAccountGroup"}] with input as spendingLimitByAccountGroupReq with data.entities as testData.entities res == { "type": "forbid", @@ -164,8 +167,8 @@ test_spendingLimitByAccountGroup { } } -test_permitRuleSpendingLimit { - res = permit[{"policyId": "spendingLimitWithApprovals"}] with input as spendingLimitReq with data.entities as entities +test_permitRuleSpendingLimitUnsatisfied if { + res = permit[{"policyId": "spendingLimitWithApprovals"}] with input as spendingLimitReq with data.entities as testData.entities res == { "approvalsMissing": [{ @@ -180,8 +183,8 @@ test_permitRuleSpendingLimit { } } -test_permitRuleSpendingLimit { - spendingLimitWithApprovalsReq = object.union(requestWithEip1559Transaction, { +test_permitRuleSpendingLimitSatisfied if { + spendingLimitWithApprovalsReq = object.union(testData.requestWithEip1559Transaction, { "principal": {"userId": "test-alice-uid"}, "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "approvals": [ {"userId": "test-bob-uid"}, @@ -189,7 +192,7 @@ test_permitRuleSpendingLimit { ], }) - res = permit[{"policyId": "spendingLimitWithApprovals"}] with input as spendingLimitWithApprovalsReq with data.entities as entities + res = permit[{"policyId": "spendingLimitWithApprovals"}] with input as spendingLimitWithApprovalsReq with data.entities as testData.entities res == { "approvalsMissing": [], @@ -204,8 +207,8 @@ test_permitRuleSpendingLimit { } } -test_spendingLimitWithFixedPeriod { - spendingLimitWithFixedPeriodReq = object.union(requestWithEip1559Transaction, { +test_spendingLimitWithFixedPeriod if { + spendingLimitWithFixedPeriodReq = object.union(testData.requestWithEip1559Transaction, { "principal": {"userId": "test-alice-uid"}, "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "approvals": [ {"userId": "test-bob-uid"}, @@ -242,7 +245,7 @@ test_spendingLimitWithFixedPeriod { "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99", "fiat:eur": "1.10"}, - "timestamp": elevenHoursAgo, + "timestamp": testData.elevenHoursAgo, "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -251,7 +254,7 @@ test_spendingLimitWithFixedPeriod { "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99", "fiat:eur": "1.10"}, - "timestamp": tenHoursAgo, + "timestamp": testData.tenHoursAgo, "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -260,7 +263,7 @@ test_spendingLimitWithFixedPeriod { "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", "rates": {"fiat:usd": "0.99", "fiat:eur": "1.10"}, - "timestamp": twentyHoursAgo, + "timestamp": testData.twentyHoursAgo, "chainId": 137, "initiatedBy": "test-alice-uid", }, @@ -269,7 +272,7 @@ test_spendingLimitWithFixedPeriod { ], }) - res = permit[{"policyId": "spendingLimitWithFixedPeriod"}] with input as spendingLimitWithFixedPeriodReq with data.entities as entities + res = permit[{"policyId": "spendingLimitWithFixedPeriod"}] with input as spendingLimitWithFixedPeriodReq with data.entities as testData.entities res == { "approvalsMissing": [], @@ -280,9 +283,9 @@ test_spendingLimitWithFixedPeriod { } # If we have an empty historical-transfer-feed, then that's okay; it's the first one -test_spendingLimitWithEmptyHistoricalDataFeed { - transactionRequest = object.union(requestWithEip1559Transaction.transactionRequest, {"value": "0x10F0CF064DD5920000000"}) - spendingLimitWithApprovalsReq = object.union(requestWithEip1559Transaction, { +test_spendingLimitWithEmptyHistoricalDataFeed if { + transactionRequest = object.union(testData.requestWithEip1559Transaction.transactionRequest, {"value": "0x10F0CF064DD5920000000"}) + spendingLimitWithApprovalsReq = object.union(testData.requestWithEip1559Transaction, { "principal": {"userId": "test-alice-uid"}, "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "approvals": [ {"userId": "test-bob-uid"}, @@ -312,13 +315,13 @@ test_spendingLimitWithEmptyHistoricalDataFeed { ], }) - res = permit[{"policyId": "spendingLimitWithApprovals"}] with input as spendingLimitWithApprovalsReq with data.entities as entities + res = permit[{"policyId": "spendingLimitWithApprovals"}] with input as spendingLimitWithApprovalsReq with data.entities as testData.entities } # If we do not even have a historical-transfer-feed, then spending limits will not match at all; otherwise we'd acccidentally treat every tx as the "first" one, being overly permissive. -test_spendingLimitWithoutHistoricalDataFeed { - transactionRequest = object.union(requestWithEip1559Transaction.transactionRequest, {"value": "0x10F0CF064DD5920000000"}) - spendingLimitWithApprovalsReq = object.union(requestWithEip1559Transaction, { +test_spendingLimitWithoutHistoricalDataFeed if { + transactionRequest = object.union(testData.requestWithEip1559Transaction.transactionRequest, {"value": "0x10F0CF064DD5920000000"}) + spendingLimitWithApprovalsReq = object.union(testData.requestWithEip1559Transaction, { "principal": {"userId": "test-alice-uid"}, "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "approvals": [ {"userId": "test-bob-uid"}, @@ -341,10 +344,10 @@ test_spendingLimitWithoutHistoricalDataFeed { }], }) - not permit[{"policyId": "spendingLimitWithApprovals"}] with input as spendingLimitWithApprovalsReq with data.entities as entities + not permit[{"policyId": "spendingLimitWithApprovals"}] with input as spendingLimitWithApprovalsReq with data.entities as testData.entities } -test_spendingLimitWithRange { +test_spendingLimitWithRange if { spendingLimitWithRangeReq = { "action": "signTransaction", "transactionRequest": { @@ -390,7 +393,7 @@ test_spendingLimitWithRange { ], } - res = permit[{"policyId": "spendingLimitWithRange"}] with input as spendingLimitWithRangeReq with data.entities as entities + res = permit[{"policyId": "spendingLimitWithRange"}] with input as spendingLimitWithRangeReq with data.entities as testData.entities res == { "approvalsMissing": [], @@ -400,7 +403,7 @@ test_spendingLimitWithRange { } } -test_spendingLimitTooHighForRange { +test_spendingLimitTooHighForRange if { spendingLimitTooHighForRangeReq = { "action": "signTransaction", "principal": {"userId": "test-alice-uid"}, diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/userOperation.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/userOperation_policy_test.rego similarity index 94% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/userOperation.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/userOperation_policy_test.rego index e3f64bed8..4297d65dc 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/userOperation.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/userOperation_policy_test.rego @@ -1,6 +1,8 @@ -package main +package armory.criteria -permit[{"policyId": "userOperationWithTransfers"}] = reason { +import rego.v1 + +permit[{"policyId": "userOperationWithTransfers"}] := reason if { checkAccountAssigned checkAction({"signTransaction"}) checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/userOperation_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/userOperation_test.rego similarity index 82% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/userOperation_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/userOperation_test.rego index 401a5a352..ed95996bb 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/policies/userOperation_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/policies/userOperation_test.rego @@ -1,7 +1,10 @@ -package main +package armory.criteria -test_userOperationWithTransfers { - userOperationWithTransfersRequest = object.union(requestWithEip1559Transaction, {"intent": { +import data.armory.testData +import rego.v1 + +test_userOperationWithTransfers if { + userOperationWithTransfersRequest = object.union(testData.requestWithEip1559Transaction, {"intent": { "type": "userOperation", "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "entrypoint": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", @@ -24,7 +27,7 @@ test_userOperationWithTransfers { ], }}) - res = permit[{"policyId": "userOperationWithTransfers"}] with input as userOperationWithTransfersRequest with data.entities as entities + res = permit[{"policyId": "userOperationWithTransfers"}] with input as userOperationWithTransfersRequest with data.entities as testData.entities res == { "type": "permit", diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/signMessage_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/signMessage_test.rego similarity index 53% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/signMessage_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/signMessage_test.rego index 918718a4b..f2a8b7fab 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/signMessage_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/signMessage_test.rego @@ -1,7 +1,12 @@ -package main +package armory.criteria -test_checkSignMessage { - signMessageRequest = object.union(requestWithEip1559Transaction, { +import data.armory.testData +import rego.v1 + +import data.armory.constants + +test_checkSignMessage if { + signMessageRequest = object.union(testData.requestWithEip1559Transaction, { "action": "signMessage", "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "intent": { @@ -9,15 +14,15 @@ test_checkSignMessage { "message": "Hello world!", }, }) - checkAction({"signMessage"}) with input as signMessageRequest with data.entities as entities - checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as signMessageRequest with data.entities as entities - checkIntentType({"signMessage", "signRawMessage"}) with input as signMessageRequest with data.entities as entities - checkIntentMessage({"operator": operators.equal, "value": "Hello world!"}) with input as signMessageRequest with data.entities as entities - checkIntentMessage({"operator": operators.contains, "value": "Hello"}) with input as signMessageRequest with data.entities as entities + checkAction({"signMessage"}) with input as signMessageRequest with data.entities as testData.entities + checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as signMessageRequest with data.entities as testData.entities + checkIntentType({"signMessage", "signRawMessage"}) with input as signMessageRequest with data.entities as testData.entities + checkIntentMessage({"operator": constants.operators.equal, "value": "Hello world!"}) with input as signMessageRequest with data.entities as testData.entities + checkIntentMessage({"operator": constants.operators.has, "value": "Hello"}) with input as signMessageRequest with data.entities as testData.entities } -test_checkSignRawPayload { - signRawPayloadRequest = object.union(requestWithEip1559Transaction, { +test_checkSignRawPayload if { + signRawPayloadRequest = object.union(testData.requestWithEip1559Transaction, { "action": "signRaw", "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "intent": { @@ -26,16 +31,16 @@ test_checkSignRawPayload { "algorithm": "ES256K", }, }) - checkAction({"signRaw"}) with input as signRawPayloadRequest with data.entities as entities - checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as signRawPayloadRequest with data.entities as entities - checkIntentType({"signRawPayload"}) with input as signRawPayloadRequest with data.entities as entities - checkIntentPayload({"operator": operators.equal, "value": "Hello world!"}) with input as signRawPayloadRequest with data.entities as entities - checkIntentPayload({"operator": operators.contains, "value": "Hello"}) with input as signRawPayloadRequest with data.entities as entities - checkIntentAlgorithm({"ES256K"}) with input as signRawPayloadRequest with data.entities as entities + checkAction({"signRaw"}) with input as signRawPayloadRequest with data.entities as testData.entities + checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as signRawPayloadRequest with data.entities as testData.entities + checkIntentType({"signRawPayload"}) with input as signRawPayloadRequest with data.entities as testData.entities + checkIntentPayload({"operator": constants.operators.equal, "value": "Hello world!"}) with input as signRawPayloadRequest with data.entities as testData.entities + checkIntentPayload({"operator": constants.operators.has, "value": "Hello"}) with input as signRawPayloadRequest with data.entities as testData.entities + checkIntentAlgorithm({"ES256K"}) with input as signRawPayloadRequest with data.entities as testData.entities } -test_checkSignTypedData { - signTypedDataRequest = object.union(requestWithEip1559Transaction, { +test_checkSignTypedData if { + signTypedDataRequest = object.union(testData.requestWithEip1559Transaction, { "action": "signTypedData", "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "intent": { @@ -48,12 +53,12 @@ test_checkSignTypedData { }}, }, }) - checkAction({"signTypedData"}) with input as signTypedDataRequest with data.entities as entities - checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as signTypedDataRequest with data.entities as entities - checkIntentType({"signTypedData"}) with input as signTypedDataRequest with data.entities as entities + checkAction({"signTypedData"}) with input as signTypedDataRequest with data.entities as testData.entities + checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as signTypedDataRequest with data.entities as testData.entities + checkIntentType({"signTypedData"}) with input as signTypedDataRequest with data.entities as testData.entities checkIntentDomain({ "chainId": ["1", "137"], "name": ["UNI", "LINK"], "verifyingContract": ["eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"], - }) with input as signTypedDataRequest with data.entities as entities + }) with input as signTypedDataRequest with data.entities as testData.entities } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/source_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/source_test.rego new file mode 100644 index 000000000..c7663ad3b --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/source_test.rego @@ -0,0 +1,40 @@ +package armory.criteria + +import data.armory.testData +import rego.v1 + +import data.armory.entities + +test_source if { + res = entities.buildIntentSourceChainAccount(input.intent) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + + expected := { + "id": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98E", + "address": "0xddcf208f219a6e6af072f2cfdc615b2c1805f98E", + "chainId": 137, + "classification": "managed", + "accountType": "eoa", + "assignees": ["test-bOb-uid", "test-alicE-uid", "test-foo-uid", "test-bar-uid"], + "groups": {"test-account-group-ONE-uid"}, + } + + expected == res + + checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkSourceAddress({"0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + checkSourceAccountType({"eoa"}) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities +} + +test_sourceInternalNotAccount if { + req = object.union(testData.requestWithEip1559Transaction, {"intent": object.union(testData.requestWithEip1559Transaction.intent, {"from": "eip155:137:0x2227be636c3ad8cf9d08ba8bdba4abd2ef29bd23"})}) + enti = object.union( + testData.entities, + {"addressBook": object.union(testData.entities.addressBook, {"eip155:137:0x2227be636c3ad8cf9d08ba8bdba4abd2ef29bd23": { + "id": "eip155:137:0x2227be636c3ad8cf9d08ba8bdba4abd2ef29bd23", + "address": "0x2227be636c3ad8cf9d08ba8bdba4abd2ef29bd23", + "chainId": 137, + "classification": "internal", + }})}, + ) + checkSourceClassification({"internal"}) with input as req with data.entities as enti +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/tokenAllowance_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/tokenAllowance_test.rego similarity index 64% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/tokenAllowance_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/tokenAllowance_test.rego index c1fa3abe3..72a08490d 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/tokenAllowance_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/tokenAllowance_test.rego @@ -1,7 +1,12 @@ -package main +package armory.criteria -test_tokenAllowance { - tokenAllowanceRequest = object.union(requestWithEip1559Transaction, { +import data.armory.testData +import rego.v1 + +import data.armory.constants + +test_tokenAllowance if { + tokenAllowanceRequest = object.union(testData.requestWithEip1559Transaction, { "action": "signTransaction", "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "intent": { @@ -12,10 +17,10 @@ test_tokenAllowance { "amount": "1000000000000000000", }, }) - checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as tokenAllowanceRequest with data.entities as entities - checkIntentType({"approveTokenAllowance"}) with input as tokenAllowanceRequest with data.entities as entities - checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as tokenAllowanceRequest with data.entities as entities - checkIntentSpender({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as tokenAllowanceRequest with data.entities as entities - checkIntentToken({"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"}) with input as tokenAllowanceRequest with data.entities as entities - checkIntentAmount({"operator": operators.lessThanOrEqual, "value": "1000000000000000000"}) with input as tokenAllowanceRequest with data.entities as entities + checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as tokenAllowanceRequest with data.entities as testData.entities + checkIntentType({"approveTokenAllowance"}) with input as tokenAllowanceRequest with data.entities as testData.entities + checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as tokenAllowanceRequest with data.entities as testData.entities + checkIntentSpender({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as tokenAllowanceRequest with data.entities as testData.entities + checkIntentToken({"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"}) with input as tokenAllowanceRequest with data.entities as testData.entities + checkIntentAmount({"operator": constants.operators.lessThanOrEqual, "value": "1000000000000000000"}) with input as tokenAllowanceRequest with data.entities as testData.entities } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/transferNft_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/transferNft_test.rego similarity index 62% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/transferNft_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/transferNft_test.rego index 250b4d72c..efc4557bf 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/transferNft_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/transferNft_test.rego @@ -1,7 +1,10 @@ -package main +package armory.criteria -test_transferERC721 { - erc721Request = object.union(requestWithEip1559Transaction, { +import data.armory.testData +import rego.v1 + +test_transferErc721 if { + erc721Request = object.union(testData.requestWithEip1559Transaction, { "action": "signTransaction", "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "intent": { @@ -12,16 +15,16 @@ test_transferERC721 { "token": "eip155:137/erc721:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", }, }) - checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc721Request with data.entities as entities - checkIntentType({"transferERC721"}) with input as erc721Request with data.entities as entities - checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc721Request with data.entities as entities - checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as erc721Request with data.entities as entities - checkIntentContract({"eip155:137/erc721:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4"}) with input as erc721Request with data.entities as entities - checkIntentToken({"eip155:137/erc721:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173"}) with input as erc721Request with data.entities as entities + checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc721Request with data.entities as testData.entities + checkIntentType({"transferERC721"}) with input as erc721Request with data.entities as testData.entities + checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc721Request with data.entities as testData.entities + checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as erc721Request with data.entities as testData.entities + checkIntentContract({"eip155:137/erc721:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4"}) with input as erc721Request with data.entities as testData.entities + checkIntentToken({"eip155:137/erc721:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173"}) with input as erc721Request with data.entities as testData.entities } -test_transferERC1155 { - erc1155Request = object.union(requestWithEip1559Transaction, { +test_transferErc1155 if { + erc1155Request = object.union(testData.requestWithEip1559Transaction, { "action": "signTransaction", "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "intent": { @@ -45,25 +48,16 @@ test_transferERC1155 { ], }, }) - checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc1155Request with data.entities as entities - checkIntentType({"transferERC1155"}) with input as erc1155Request with data.entities as entities - checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc1155Request with data.entities as entities - checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as erc1155Request with data.entities as entities - checkIntentContract({"eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4"}) with input as erc1155Request with data.entities as entities - checkErc1155TokenId({"eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173"}) with input as erc1155Request with data.entities as entities - checkErc1155TokenId({"eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/55555"}) with input as erc1155Request with data.entities as entities + checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc1155Request with data.entities as testData.entities + checkIntentType({"transferERC1155"}) with input as erc1155Request with data.entities as testData.entities + checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc1155Request with data.entities as testData.entities + checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as erc1155Request with data.entities as testData.entities + checkIntentContract({"eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4"}) with input as erc1155Request with data.entities as testData.entities + checkErc1155TokenId({"eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173"}) with input as erc1155Request with data.entities as testData.entities + checkErc1155TokenId({"eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/55555"}) with input as erc1155Request with data.entities as testData.entities checkErc1155Transfers([ {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": "lt", "value": "2"}, {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/44444", "operator": "lt", "value": "3"}, {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/55555", "operator": "lt", "value": "6"}, - ]) with input as erc1155Request with data.entities as entities -} - -test_checkERC1155TokenAmount { - checkTransferAmount("1", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": operators.notEqual, "value": "2"}) - checkTransferAmount("1", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": operators.equal, "value": "1"}) - checkTransferAmount("5", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": operators.greaterThanOrEqual, "value": "4"}) - checkTransferAmount("3", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": operators.lessThanOrEqual, "value": "5"}) - checkTransferAmount("5", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": operators.greaterThan, "value": "3"}) - checkTransferAmount("3", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": operators.lessThan, "value": "5"}) + ]) with input as erc1155Request with data.entities as testData.entities } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/transferToken_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/transferToken_test.rego similarity index 58% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/transferToken_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/transferToken_test.rego index cb2a8ca02..70633d202 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/transferToken_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/transferToken_test.rego @@ -1,7 +1,12 @@ -package main +package armory.criteria -test_transferNative { - nativeRequest = object.union(requestWithEip1559Transaction, { +import data.armory.testData +import rego.v1 + +import data.armory.constants + +test_transferNative if { + nativeRequest = object.union(testData.requestWithEip1559Transaction, { "action": "signTransaction", "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "intent": { @@ -12,16 +17,16 @@ test_transferNative { "token": "eip155:137/slip44:966", }, }) - checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as nativeRequest with data.entities as entities - checkIntentType({"transferNative"}) with input as nativeRequest with data.entities as entities - checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as nativeRequest with data.entities as entities - checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as nativeRequest with data.entities as entities - checkIntentToken({"eip155:137/slip44:966"}) with input as nativeRequest with data.entities as entities - checkIntentAmount({"operator": operators.lessThanOrEqual, "value": "1000000000000000000"}) with input as nativeRequest with data.entities as entities + checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as nativeRequest with data.entities as testData.entities + checkIntentType({"transferNative"}) with input as nativeRequest with data.entities as testData.entities + checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as nativeRequest with data.entities as testData.entities + checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as nativeRequest with data.entities as testData.entities + checkIntentToken({"eip155:137/slip44:966"}) with input as nativeRequest with data.entities as testData.entities + checkIntentAmount({"operator": constants.operators.lessThanOrEqual, "value": "1000000000000000000"}) with input as nativeRequest with data.entities as testData.entities } -test_transferERC20 { - erc20Request = object.union(requestWithEip1559Transaction, { +test_transferErc20 if { + erc20Request = object.union(testData.requestWithEip1559Transaction, { "action": "signTransaction", "resource": {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}, "intent": { @@ -32,10 +37,10 @@ test_transferERC20 { "contract": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174", }, }) - checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc20Request with data.entities as entities - checkIntentType({"transferERC20"}) with input as erc20Request with data.entities as entities - checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc20Request with data.entities as entities - checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as erc20Request with data.entities as entities - checkIntentContract({"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"}) with input as erc20Request with data.entities as entities - checkIntentAmount({"operator": operators.lessThanOrEqual, "value": "1000000000000000000"}) with input as erc20Request with data.entities as entities + checkAccountId({"eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc20Request with data.entities as testData.entities + checkIntentType({"transferERC20"}) with input as erc20Request with data.entities as testData.entities + checkSourceId({"eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"}) with input as erc20Request with data.entities as testData.entities + checkDestinationId({"eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3"}) with input as erc20Request with data.entities as testData.entities + checkIntentContract({"eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174"}) with input as erc20Request with data.entities as testData.entities + checkIntentAmount({"operator": constants.operators.lessThanOrEqual, "value": "1000000000000000000"}) with input as erc20Request with data.entities as testData.entities } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/typedDataMessage_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/typedDataMessage_test.rego similarity index 83% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/typedDataMessage_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/typedDataMessage_test.rego index 8635161c4..b71fcb389 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/typedDataMessage_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/typedDataMessage_test.rego @@ -1,6 +1,9 @@ -package main +package armory.criteria -typedDataInput = { +import data.armory.testData +import rego.v1 + +typedDataInput := { "action": "signTypedData", "principal": { "userId": "test-alice-user-uid", @@ -66,21 +69,21 @@ typedDataInput = { "resource": {"uid": "eip155:eoa:0x0f610AC9F0091f8F573c33f15155afE8aD747495"}, } -test_checkIntentTypedDataMessageCondition { +test_checkIntentTypedDataMessageCondition if { filters := [[{"key": "condition", "value": "I agree to link this wallet to my Immutable Passport account."}]] - checkIntentTypedDataMessage(filters) with input as typedDataInput with data.entities as entities + checkIntentTypedDataMessage(filters) with input as typedDataInput with data.entities as testData.entities } -test_checkIntentTypedDataMessageCondition_one_wrong_value_one_correct_value_in_condition_should_not_match { +test_checkIntentTypedDataMessageConditionOneWrongValueOneCorrectValueInConditionShouldNotMatch if { conditions := [[{"key": "walletAddress", "value": "0xwrongaddress"}, {"key": "condition", "value": "I agree to link this wallet to my Immutable Passport account."}]] - not checkIntentTypedDataMessage(conditions) with input as typedDataInput with data.entities as entities + not checkIntentTypedDataMessage(conditions) with input as typedDataInput with data.entities as testData.entities } -test_checkIntentTypedDataMessageCondition_one_wrong_condition_one_correct_condition_should_match { +test_checkIntentTypedDataMessageConditionOneWrongConditionOneCorrectConditionShouldMatch if { conditions := [ [{"key": "condition", "value": "I agree to link this wallet to my Immutable Passport account."}], [{"key": "wrongKey", "value": "0x299697552cd035afd7e08600c4001fff48498263"}], ] - checkIntentTypedDataMessage(conditions) with input as typedDataInput with data.entities as entities + checkIntentTypedDataMessage(conditions) with input as typedDataInput with data.entities as testData.entities } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/userOperation_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/userOperation_test.rego similarity index 90% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/userOperation_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/userOperation_test.rego index d12c556f7..c80eb1037 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/criteria/intent/userOperation_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/__test__/userOperation_test.rego @@ -1,7 +1,10 @@ -package main +package armory.criteria -test_checkUserOperationIntents { - userOperationRequest = object.union(requestWithEip1559Transaction, {"intent": { +import data.armory.testData +import rego.v1 + +test_checkUserOperationIntents if { + userOperationRequest = object.union(testData.requestWithEip1559Transaction, {"intent": { "type": "userOperation", "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "entrypoint": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", @@ -70,5 +73,5 @@ test_checkUserOperationIntents { }, ] - checkUserOperationIntents(conditions) with input as userOperationRequest with data.entities as entities + checkUserOperationIntents(conditions) with input as userOperationRequest with data.entities as testData.entities } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountAddress.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountAddress.rego new file mode 100644 index 000000000..dcd675c76 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountAddress.rego @@ -0,0 +1,11 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +checkAccountAddress(values) if { + resource := entities.getAccount(input.resource.uid) + lib.caseInsensitiveFindInSet(resource.address, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountAssigned.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountAssigned.rego new file mode 100644 index 000000000..0d1939735 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountAssigned.rego @@ -0,0 +1,12 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +checkAccountAssigned if { + principal := entities.getUser(input.principal.userId) + resource := entities.getAccount(input.resource.uid) + lib.caseInsensitiveFindInSet(principal.id, resource.assignees) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountChainId.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountChainId.rego new file mode 100644 index 000000000..2ab9f4d2f --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountChainId.rego @@ -0,0 +1,11 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +checkAccountChainId(values) if { + resource := entities.getAccount(input.resource.uid) + lib.numberToString(resource.chainId) in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountGroup.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountGroup.rego new file mode 100644 index 000000000..1adf9227a --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountGroup.rego @@ -0,0 +1,12 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +checkAccountGroup(values) if { + resource := entities.getAccount(input.resource.uid) + some group in resource.groups + lib.caseInsensitiveFindInSet(group, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountId.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountId.rego new file mode 100644 index 000000000..81066e625 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountId.rego @@ -0,0 +1,11 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +checkAccountId(values) if { + resource := entities.getAccount(input.resource.uid) + lib.caseInsensitiveFindInSet(resource.id, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountType.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountType.rego new file mode 100644 index 000000000..f046a2996 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAccountType.rego @@ -0,0 +1,10 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities + +checkAccountType(values) if { + resource := entities.getAccount(input.resource.uid) + resource.accountType in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAction.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAction.rego new file mode 100644 index 000000000..8227468e0 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkAction.rego @@ -0,0 +1,7 @@ +package armory.criteria + +import rego.v1 + +checkAction(values) if { + input.action in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkApprovals.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkApprovals.rego new file mode 100644 index 000000000..a278dea9d --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkApprovals.rego @@ -0,0 +1,120 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +getApprovalsCount(possibleApprovers) := result if { + matchedApprovers = {approval.userId | + some approval in input.approvals + lib.caseInsensitiveFindInSet(approval.userId, possibleApprovers) + } + result = count(matchedApprovers) +} + +# User approvals + +checkApproval(approval) := result if { + principal := entities.getUser(input.principal.userId) + + approval.countPrincipal == true + approval.approvalEntityType == "Narval::User" + possibleApprovers = { + entity | + some entity in approval.entityIds + } | {principal.id} + result = getApprovalsCount(possibleApprovers) +} + +checkApproval(approval) := result if { + principal := entities.getUser(input.principal.userId) + + approval.countPrincipal == false + approval.approvalEntityType == "Narval::User" + possibleApprovers = {entity | + some entity in approval.entityIds + not lib.caseInsensitiveEqual(entity, principal.id) + } + result = getApprovalsCount(possibleApprovers) +} + +# User group approvals + +checkApproval(approval) := result if { + principal := entities.getUser(input.principal.userId) + + approval.countPrincipal == true + approval.approvalEntityType == "Narval::UserGroup" + possibleApprovers = {user | + some entity in approval.entityIds + users = entities.getUserGroup(entity).users + some user in users + } | {principal.id} + + result = getApprovalsCount(possibleApprovers) +} + +checkApproval(approval) := result if { + principal := entities.getUser(input.principal.userId) + + approval.countPrincipal == false + approval.approvalEntityType == "Narval::UserGroup" + possibleApprovers = {user | + some entity in approval.entityIds + users = entities.getUserGroup(entity).users + some user in users + not lib.caseInsensitiveEqual(user, principal.id) + } + + result = getApprovalsCount(possibleApprovers) +} + +# User role approvals + +checkApproval(approval) := result if { + approval.countPrincipal == true + approval.approvalEntityType == "Narval::UserRole" + + possibleApprovers := {user | + some role in approval.entityIds + users := entities.getUsersByRole(role) + some user in users + } + + result = getApprovalsCount(possibleApprovers) +} + +checkApproval(approval) := result if { + approval.countPrincipal == false + approval.approvalEntityType == "Narval::UserRole" + principal := entities.getUser(input.principal.userId) + possibleApprovers := {user | + some role in approval.entityIds + users := entities.getUsersByRole(role) + some user in users + not lib.caseInsensitiveEqual(user, principal.id) + } + + result = getApprovalsCount(possibleApprovers) +} + +checkApprovals(approvals) := result if { + approvalsMissing = [approval | + some approval in approvals + approvalCount = checkApproval(approval) + approvalCount < approval.approvalCount + ] + + approvalsSatisfied = [approval | + some approval in approvals + + approvalCount = checkApproval(approval) + approvalCount >= approval.approvalCount + ] + + result = { + "approvalsSatisfied": approvalsSatisfied, + "approvalsMissing": approvalsMissing, + } +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationAccountType.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationAccountType.rego new file mode 100644 index 000000000..543b90ff3 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationAccountType.rego @@ -0,0 +1,10 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities + +checkDestinationAccountType(values) if { + destination = entities.intentDestinationToChainAccount(input.intent) + destination.accountType in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationAddress.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationAddress.rego new file mode 100644 index 000000000..ae090a281 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationAddress.rego @@ -0,0 +1,11 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +checkDestinationAddress(values) if { + destination = entities.intentDestinationToChainAccount(input.intent) + lib.caseInsensitiveFindInSet(destination.address, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationClassification.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationClassification.rego new file mode 100644 index 000000000..cb7af8dc4 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationClassification.rego @@ -0,0 +1,10 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities + +checkDestinationClassification(values) if { + destination = entities.intentDestinationToChainAccount(input.intent) + destination.classification in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationId.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationId.rego new file mode 100644 index 000000000..5b5864b6b --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkDestinationId.rego @@ -0,0 +1,11 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +checkDestinationId(values) if { + destination = entities.intentDestinationToChainAccount(input.intent) + lib.caseInsensitiveFindInSet(destination.id, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkEntrypoint.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkEntrypoint.rego new file mode 100644 index 000000000..daaf553b0 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkEntrypoint.rego @@ -0,0 +1,26 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +checkEntryPointId(values) if { + entrypoint = entities.getEntryPoint(input.intent) + lib.caseInsensitiveFindInSet(entrypoint.id, values) +} + +checkEntryPointAddress(values) if { + entrypoint = entities.getEntryPoint(input.intent) + lib.caseInsensitiveFindInSet(entrypoint.address, values) +} + +checkEntryPointAccountType(values) if { + entrypoint = entities.getEntryPoint(input.intent) + entrypoint.accountType in values +} + +checkEntryPointClassification(values) if { + entrypoint = entities.getEntryPoint(input.intent) + entrypoint.classification in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkErc1155TokenId.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkErc1155TokenId.rego new file mode 100644 index 000000000..f98d139ed --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkErc1155TokenId.rego @@ -0,0 +1,10 @@ +package armory.criteria + +import data.armory.lib +import rego.v1 + +checkErc1155TokenId(values) if { + intentTransfers := input.intent.transfers + some transfer in intentTransfers + lib.caseInsensitiveFindInSet(transfer.token, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkErc1155Transfers.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkErc1155Transfers.rego new file mode 100644 index 000000000..8a7c7fefb --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkErc1155Transfers.rego @@ -0,0 +1,25 @@ +package armory.criteria + +import data.armory.criteria.util +import data.armory.lib +import rego.v1 + +checkErc1155Transfers(conditions) if { + intentTransfers := input.intent.transfers + matches = [e | + some transfer in intentTransfers + some condition in conditions + lib.caseInsensitiveEqual(transfer.token, condition.token) + + e = [transfer, condition] + ] + + validTransfers = [transfer | + some m in matches + transfer = m[0] + condition = m[1] + util.checkTransferAmount(transfer.amount, condition) + ] + + count(intentTransfers) == count(validTransfers) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkGasFeeAmount.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkGasFeeAmount.rego new file mode 100644 index 000000000..fef50facd --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkGasFeeAmount.rego @@ -0,0 +1,88 @@ +package armory.criteria + +import data.armory.constants +import data.armory.feeds + +import rego.v1 + +gasFeeAmount := result if { + input.transactionRequest.maxFeePerGas + input.transactionRequest.maxPriorityFeePerGas + maxFee := to_number(input.transactionRequest.maxFeePerGas) + maxPriorityFee := to_number(input.transactionRequest.maxPriorityFeePerGas) + gas := to_number(input.transactionRequest.gas) + result = (maxFee + maxPriorityFee) * gas +} + +gasFeeAmount := result if { + not input.transactionRequest.maxFeePerGas + not input.transactionRequest.maxPriorityFeePerGas + result = to_number(input.transactionRequest.gasPrice) * to_number(input.transactionRequest.gas) +} + +getGasFeeAmountCondition(filters) := object.union( + { + "currency": constants.wildcard, + "operator": constants.wildcard, + "value": constants.wildcard, + }, + filters, +) + +getGasFeeAmount(currency) := result if { + currency == constants.wildcard + result = gasFeeAmount +} + +getGasFeeAmount(currency) := result if { + currency != constants.wildcard + some chainId, token in constants.chainAssetId + price := to_number(feeds.priceFeed[token][currency]) + result := gasFeeAmount * price +} + +checkGasFeeAmount(filters) if { + condition = getGasFeeAmountCondition(filters) + condition.operator == constants.wildcard +} + +checkGasFeeAmount(filters) if { + condition = getGasFeeAmountCondition(filters) + condition.value == constants.wildcard +} + +checkGasFeeAmount(filters) if { + condition = getGasFeeAmountCondition(filters) + condition.operator == constants.operators.equal + to_number(condition.value) == getGasFeeAmount(condition.currency) +} + +checkGasFeeAmount(filters) if { + condition = getGasFeeAmountCondition(filters) + condition.operator == constants.operators.notEqual + to_number(condition.value) != getGasFeeAmount(condition.currency) +} + +checkGasFeeAmount(filters) if { + condition = getGasFeeAmountCondition(filters) + condition.operator == constants.operators.greaterThan + to_number(condition.value) < getGasFeeAmount(condition.currency) +} + +checkGasFeeAmount(filters) if { + condition = getGasFeeAmountCondition(filters) + condition.operator == constants.operators.lessThan + to_number(condition.value) > getGasFeeAmount(condition.currency) +} + +checkGasFeeAmount(filters) if { + condition = getGasFeeAmountCondition(filters) + condition.operator == constants.operators.greaterThanOrEqual + to_number(condition.value) <= getGasFeeAmount(condition.currency) +} + +checkGasFeeAmount(filters) if { + condition = getGasFeeAmountCondition(filters) + condition.operator == constants.operators.lessThanOrEqual + to_number(condition.value) >= getGasFeeAmount(condition.currency) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentAlgorithm.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentAlgorithm.rego new file mode 100644 index 000000000..84bf45ee0 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentAlgorithm.rego @@ -0,0 +1,7 @@ +package armory.criteria + +import rego.v1 + +checkIntentAlgorithm(values) if { + input.intent.algorithm in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentAmount.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentAmount.rego new file mode 100644 index 000000000..7738d943b --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentAmount.rego @@ -0,0 +1,88 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants +import data.armory.feeds + +intentAmount := to_number(input.intent.amount) + +getAmountCondition(filters) := object.union( + { + "currency": constants.wildcard, + "operator": constants.wildcard, + "value": constants.wildcard, + }, + filters, +) + +calculateIntentAmount(currency) := result if { + currency == constants.wildcard + result = intentAmount +} + +calculateIntentAmount(currency) := result if { + currency != constants.wildcard + token = input.intent.token + price = to_number(feeds.priceFeed[lower(token)][lower(currency)]) + result = intentAmount * price +} + +calculateIntentAmount(currency) := result if { + currency != constants.wildcard + contract = input.intent.contract + price = to_number(feeds.priceFeed[lower(contract)][lower(currency)]) + result = intentAmount * price +} + +checkIntentAmount(filters) if { + condition = getAmountCondition(filters) + condition.operator == constants.wildcard +} + +checkIntentAmount(filters) if { + condition = getAmountCondition(filters) + condition.value == constants.wildcard +} + +checkIntentAmount(filters) if { + condition = getAmountCondition(filters) + condition.value != constants.wildcard + condition.operator == constants.operators.equal + calculateIntentAmount(condition.currency) == to_number(condition.value) +} + +checkIntentAmount(filters) if { + condition = getAmountCondition(filters) + condition.value != constants.wildcard + condition.operator == constants.operators.notEqual + calculateIntentAmount(condition.currency) != to_number(condition.value) +} + +checkIntentAmount(filters) if { + condition = getAmountCondition(filters) + condition.value != constants.wildcard + condition.operator == constants.operators.greaterThan + calculateIntentAmount(condition.currency) > to_number(condition.value) +} + +checkIntentAmount(filters) if { + condition = getAmountCondition(filters) + condition.value != constants.wildcard + condition.operator == constants.operators.lessThan + calculateIntentAmount(condition.currency) < to_number(condition.value) +} + +checkIntentAmount(filters) if { + condition = getAmountCondition(filters) + condition.value != constants.wildcard + condition.operator == constants.operators.greaterThanOrEqual + calculateIntentAmount(condition.currency) >= to_number(condition.value) +} + +checkIntentAmount(filters) if { + condition = getAmountCondition(filters) + condition.value != constants.wildcard + condition.operator == constants.operators.lessThanOrEqual + calculateIntentAmount(condition.currency) <= to_number(condition.value) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentBeneficiary.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentBeneficiary.rego new file mode 100644 index 000000000..68bdd7d12 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentBeneficiary.rego @@ -0,0 +1,7 @@ +package armory.criteria + +import rego.v1 + +checkIntentBeneficiary(values) if { + input.intent.beneficiary in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentChainId.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentChainId.rego new file mode 100644 index 000000000..425600d86 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentChainId.rego @@ -0,0 +1,9 @@ +package armory.criteria + +import rego.v1 + +import data.armory.lib + +checkIntentChainId(values) if { + lib.numberToString(input.intent.chainId) in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentContract.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentContract.rego new file mode 100644 index 000000000..c68343e52 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentContract.rego @@ -0,0 +1,8 @@ +package armory.criteria + +import data.armory.lib +import rego.v1 + +checkIntentContract(values) if { + lib.caseInsensitiveFindInSet(input.intent.contract, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentDomain.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentDomain.rego new file mode 100644 index 000000000..5b9c2e1fd --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentDomain.rego @@ -0,0 +1,31 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants +import data.armory.lib + +wildcardIntentDomain := { + "version": constants.wildcard, + "chainId": constants.wildcard, + "name": constants.wildcard, + "verifyingContract": constants.wildcard, +} + +checkDomainCondition(_, set) if { + set == constants.wildcard +} + +checkDomainCondition(value, set) if { + set != constants.wildcard + value in set +} + +checkIntentDomain(filters) if { + domain = object.union(wildcardIntentDomain, input.intent.typedData.domain) + conditions = object.union(wildcardIntentDomain, filters) + checkDomainCondition(domain.version, conditions.version) + checkDomainCondition(lib.numberToString(domain.chainId), conditions.chainId) + checkDomainCondition(domain.name, conditions.name) + checkDomainCondition(domain.verifyingContract, conditions.verifyingContract) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentHexSignature.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentHexSignature.rego new file mode 100644 index 000000000..2dd4fec61 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentHexSignature.rego @@ -0,0 +1,9 @@ +package armory.criteria + +import rego.v1 + +import data.armory.lib + +checkIntentHexSignature(values) if { + lib.caseInsensitiveFindInSet(input.intent.hexSignature, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentMessage.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentMessage.rego new file mode 100644 index 000000000..8afb6462f --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentMessage.rego @@ -0,0 +1,25 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants + +checkIntentMessage(condition) if { + condition.operator == constants.wildcard +} + +checkIntentMessage(condition) if { + condition.value == constants.wildcard +} + +checkIntentMessage(condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.equal + condition.value == input.intent.message +} + +checkIntentMessage(condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.has + contains(input.intent.message, condition.value) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentPayload.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentPayload.rego new file mode 100644 index 000000000..962c3c2f6 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentPayload.rego @@ -0,0 +1,25 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants + +checkIntentPayload(condition) if { + condition.operator == constants.wildcard +} + +checkIntentPayload(condition) if { + condition.value == constants.wildcard +} + +checkIntentPayload(condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.equal + condition.value == input.intent.payload +} + +checkIntentPayload(condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.has + contains(input.intent.payload, condition.value) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentSpender.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentSpender.rego new file mode 100644 index 000000000..718ff0b0f --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentSpender.rego @@ -0,0 +1,9 @@ +package armory.criteria + +import rego.v1 + +import data.armory.lib + +checkIntentSpender(values) if { + lib.caseInsensitiveFindInSet(input.intent.spender, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentToken.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentToken.rego new file mode 100644 index 000000000..585f6c73f --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentToken.rego @@ -0,0 +1,9 @@ +package armory.criteria + +import rego.v1 + +import data.armory.lib + +checkIntentToken(values) if { + lib.caseInsensitiveFindInSet(input.intent.token, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentType.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentType.rego new file mode 100644 index 000000000..059a0b5d6 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentType.rego @@ -0,0 +1,7 @@ +package armory.criteria + +import rego.v1 + +checkIntentType(values) if { + input.intent.type in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signTypedData/message.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentTypedDataMessage.rego similarity index 64% rename from apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signTypedData/message.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentTypedDataMessage.rego index 92cc7a906..268d5b3bf 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signTypedData/message.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkIntentTypedDataMessage.rego @@ -1,19 +1,21 @@ -package main +package armory.criteria -typedDataMessageKeyValueCheck(conditions) { +import rego.v1 + +typedDataMessageKeyValueCheck(conditions) if { count(conditions) > 0 inputMessage = input.intent.typedData.message checkedConditions = [condition | - condition = conditions[_] + some condition in conditions inputMessage[condition.key] == condition.value ] count(checkedConditions) == count(conditions) } -checkIntentTypedDataMessage(args) { +checkIntentTypedDataMessage(args) if { count(args) > 0 checkedArgs = [singleCondition | - singleCondition = args[_] + some singleCondition in args typedDataMessageKeyValueCheck(singleCondition) ] count(checkedArgs) > 0 diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkNonceExists.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkNonceExists.rego new file mode 100644 index 000000000..fd68019a8 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkNonceExists.rego @@ -0,0 +1,7 @@ +package armory.criteria + +import rego.v1 + +checkNonceExists if { + input.transactionRequest.nonce +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkNonceNotExists.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkNonceNotExists.rego new file mode 100644 index 000000000..b00cf4a9a --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkNonceNotExists.rego @@ -0,0 +1,7 @@ +package armory.criteria + +import rego.v1 + +checkNonceNotExists if { + not input.transactionRequest.nonce +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPermission.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPermission.rego new file mode 100644 index 000000000..e6c412995 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPermission.rego @@ -0,0 +1,9 @@ +package armory.criteria + +import rego.v1 + +checkPermission(grantedPermission) if { + every permission in input.permissions { + permission in grantedPermission + } +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPermitDeadline.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPermitDeadline.rego new file mode 100644 index 000000000..3558d9b1e --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPermitDeadline.rego @@ -0,0 +1,51 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants + +permitDeadlineMs := to_number(input.intent.deadline) + +checkPermitDeadline(condition) if { + condition.operator == constants.wildcard +} + +checkPermitDeadline(condition) if { + condition.value == constants.wildcard +} + +checkPermitDeadline(condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.equal + permitDeadlineMs == to_number(condition.value) +} + +checkPermitDeadline(condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.notEqual + permitDeadlineMs != to_number(condition.value) +} + +checkPermitDeadline(condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.lessThanOrEqual + permitDeadlineMs <= to_number(condition.value) +} + +checkPermitDeadline(condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.greaterThanOrEqual + permitDeadlineMs >= to_number(condition.value) +} + +checkPermitDeadline(condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.lessThan + permitDeadlineMs < to_number(condition.value) +} + +checkPermitDeadline(condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.greaterThan + permitDeadlineMs > to_number(condition.value) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalGroup.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalGroup.rego new file mode 100644 index 000000000..ed082796d --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalGroup.rego @@ -0,0 +1,13 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +## Ids are lowercased +checkPrincipalGroup(values) if { + principalGroups := entities.getUser(input.principal.userId).groups + some group in principalGroups + lib.caseInsensitiveFindInSet(group, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalId.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalId.rego new file mode 100644 index 000000000..b1ef77892 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalId.rego @@ -0,0 +1,12 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +## Id are lowercased +checkPrincipalId(values) if { + principal := entities.getUser(input.principal.userId) + lib.caseInsensitiveFindInSet(principal.id, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalRole.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalRole.rego new file mode 100644 index 000000000..8775c9426 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkPrincipalRole.rego @@ -0,0 +1,11 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities + +## roles are constants +checkPrincipalRole(values) if { + principal := entities.getUser(input.principal.userId) + principal.role in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkRateLimit.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkRateLimit.rego new file mode 100644 index 000000000..d8aff2650 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkRateLimit.rego @@ -0,0 +1,83 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants +import data.armory.criteria.util +import data.armory.feeds +import data.armory.lib + +rateLimitWildcardConditions := { + "limit": constants.wildcard, + "timeWindow": { + "type": constants.wildcard, # rolling, fixed + "period": constants.wildcard, # 1d, 1m, 1y + "value": constants.wildcard, # in seconds + "startDate": constants.wildcard, # in seconds + "endDate": constants.wildcard, # in seconds + }, + "filters": { + "perPrincipal": false, + "tokens": constants.wildcard, + "users": constants.wildcard, + "resources": constants.wildcard, + "destinations": constants.wildcard, + "chains": constants.wildcard, + "userGroups": constants.wildcard, + "accountGroups": constants.wildcard, + }, +} + +# Check Rate Limit + +calculateCurrentRate(params) := result if { + conditions = object.union(rateLimitWildcardConditions, params) + rateLimit = conditions.limit + timeWindow = conditions.timeWindow + filters = conditions.filters + transfers = array.concat(feeds.transferFeed, util.intentTransferObjects) + + result = count([transfer | + some transfer in transfers + + # filter by principal + util.checkTransferByPrincipal(transfer.initiatedBy, filters.perPrincipal) + + # filter by tokens + util.checkTransferCondition(transfer.token, filters.tokens) + + # filter by users + util.checkTransferCondition(transfer.initiatedBy, filters.users) + + # filter by resource accounts + util.checkTransferCondition(transfer.resourceId, filters.resources) + + # filter by destination accounts + util.checkTransferCondition(transfer.to, filters.destinations) + + # filter by chains + util.checkTransferCondition(lib.numberToString(transfer.chainId), filters.chains) + + # filter by user groups + util.checkTransferByUserGroups(transfer.initiatedBy, filters.userGroups) + + # filter by account groups + util.checkTransferByAccountGroups(transfer.from, filters.accountGroups) + + # filter by start date + util.checkTransferFromStartDate(transfer.timestamp, timeWindow) + + # filter by end date + util.checkTransferToEndDate(transfer.timestamp, timeWindow) + + # filter by time window type + util.checkTransferTimeWindow(transfer.timestamp, timeWindow) + ]) +} + +checkRateLimit(params) if { + conditions = object.union(rateLimitWildcardConditions, params) + rateLimit = to_number(conditions.limit) + + calculateCurrentRate(conditions) <= rateLimit +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkResource.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkResource.rego new file mode 100644 index 000000000..5fb9c7d50 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkResource.rego @@ -0,0 +1,11 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants +import data.armory.lib + +checkResource(values) if { + input.action in {constants.actions.grantPermission} + lib.caseInsensitiveFindInSet(input.resource.uid, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceAccountType.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceAccountType.rego new file mode 100644 index 000000000..f8c04592f --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceAccountType.rego @@ -0,0 +1,10 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities + +checkSourceAccountType(values) if { + source = entities.buildIntentSourceChainAccount(input.intent) + source.accountType in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceAddress.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceAddress.rego new file mode 100644 index 000000000..351dc6536 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceAddress.rego @@ -0,0 +1,11 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +checkSourceAddress(values) if { + source = entities.buildIntentSourceChainAccount(input.intent) + lib.caseInsensitiveFindInSet(source.address, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceClassification.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceClassification.rego new file mode 100644 index 000000000..74f88bb4f --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceClassification.rego @@ -0,0 +1,10 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities + +checkSourceClassification(values) if { + source = entities.buildIntentSourceChainAccount(input.intent) + source.classification in values +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceId.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceId.rego new file mode 100644 index 000000000..29bde2c58 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSourceId.rego @@ -0,0 +1,11 @@ +package armory.criteria + +import rego.v1 + +import data.armory.entities +import data.armory.lib + +checkSourceId(values) if { + source = entities.buildIntentSourceChainAccount(input.intent) + lib.caseInsensitiveFindInSet(source.id, values) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSpendingLimit.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSpendingLimit.rego new file mode 100644 index 000000000..2ad7c62d9 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/checkSpendingLimit.rego @@ -0,0 +1,122 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants +import data.armory.criteria.util +import data.armory.feeds +import data.armory.lib + +spendingWildcardConditions := { + "currency": constants.wildcard, + "limit": constants.wildcard, + "operator": constants.wildcard, + "timeWindow": { + "type": constants.wildcard, # rolling, fixed + "period": constants.wildcard, # 1d, 1m, 1y + "value": constants.wildcard, # in seconds + "startDate": constants.wildcard, # in seconds + "endDate": constants.wildcard, # in seconds + }, + "filters": { + "perPrincipal": false, + "tokens": constants.wildcard, + "users": constants.wildcard, + "resources": constants.wildcard, + "destinations": constants.wildcard, + "chains": constants.wildcard, + "userGroups": constants.wildcard, + "accountGroups": constants.wildcard, + }, +} + +# Calculate Spending + +calculateTransferSpending(transfer, currency) := result if { + currency == constants.wildcard + result = to_number(transfer.amount) +} + +calculateTransferSpending(transfer, currency) := result if { + currency != constants.wildcard + result = to_number(transfer.amount) * to_number(transfer.rates[lower(currency)]) +} + +# Check Spendings + +checkSpendingOperator(spendings, operator, limit) if { + operator == constants.operators.lessThan + spendings < limit +} + +checkSpendingOperator(spendings, operator, limit) if { + operator == constants.operators.lessThanOrEqual + spendings <= limit +} + +checkSpendingOperator(spendings, operator, limit) if { + operator == constants.operators.greaterThan + spendings > limit +} + +checkSpendingOperator(spendings, operator, limit) if { + operator == constants.operators.greaterThanOrEqual + spendings >= limit +} + +# Check Spending Limit + +calculateCurrentSpendings(params) := result if { + conditions = object.union(spendingWildcardConditions, params) + timeWindow = conditions.timeWindow + filters = conditions.filters + transfers = array.concat(feeds.transferFeed, util.intentTransferObjects) + + result = sum([spending | + some transfer in transfers + + # filter by principal + util.checkTransferByPrincipal(transfer.initiatedBy, filters.perPrincipal) + + # filter by tokens + util.checkTransferCondition(transfer.token, filters.tokens) + + # filter by users + util.checkTransferCondition(transfer.initiatedBy, filters.users) + + # filter by resource accounts + util.checkTransferCondition(transfer.resourceId, filters.resources) + + # filter by destination accounts + util.checkTransferCondition(transfer.to, filters.destinations) + + # filter by chains + util.checkTransferCondition(lib.numberToString(transfer.chainId), filters.chains) + + # filter by user groups + util.checkTransferByUserGroups(transfer.initiatedBy, filters.userGroups) + + # filter by account groups + util.checkTransferByAccountGroups(transfer.from, filters.accountGroups) + + # filter by start date + util.checkTransferFromStartDate(transfer.timestamp, timeWindow) + + # filter by end date + util.checkTransferToEndDate(transfer.timestamp, timeWindow) + + # filter by time window type + util.checkTransferTimeWindow(transfer.timestamp, timeWindow) + + spending = calculateTransferSpending(transfer, conditions.currency) + ]) +} + +checkSpendingLimit(params) if { + conditions = object.union(spendingWildcardConditions, params) + spendings = calculateCurrentSpendings(conditions) + operator = conditions.operator + limit = to_number(conditions.limit) + + checkSpendingOperator(spendings, operator, limit) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/amount/amount.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/amount/amount.rego new file mode 100644 index 000000000..8cdc9c23d --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/amount/amount.rego @@ -0,0 +1,69 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants +import data.armory.feeds + +calculateIntentAmountForUserOperation(intent, currency) := result if { + currency == constants.wildcard + result = to_number(intent.amount) +} + +calculateIntentAmountForUserOperation(intent, currency) := result if { + currency != constants.wildcard + amount = to_number(intent.amount) + price = to_number(feeds.priceFeed[intent.token][currency]) + result = amount * price +} + +calculateIntentAmountForUserOperation(intent, currency) := result if { + currency != constants.wildcard + amount = to_number(intent.amount) + price = to_number(feeds.priceFeed[intent.contract][currency]) + result = amount * price +} + +checkUserOperationAmount(_, condition) if { + condition.operator == constants.wildcard +} + +checkUserOperationAmount(_, condition) if { + condition.value == constants.wildcard +} + +checkUserOperationAmount(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.equal + calculateIntentAmountForUserOperation(intent, condition.currency) == to_number(condition.value) +} + +checkUserOperationAmount(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.notEqual + calculateIntentAmountForUserOperation(intent, condition.currency) != to_number(condition.value) +} + +checkUserOperationAmount(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.greaterThan + calculateIntentAmountForUserOperation(intent, condition.currency) > to_number(condition.value) +} + +checkUserOperationAmount(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.lessThan + calculateIntentAmountForUserOperation(intent, condition.currency) < to_number(condition.value) +} + +checkUserOperationAmount(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.greaterThanOrEqual + calculateIntentAmountForUserOperation(intent, condition.currency) >= to_number(condition.value) +} + +checkUserOperationAmount(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.lessThanOrEqual + calculateIntentAmountForUserOperation(intent, condition.currency) <= to_number(condition.value) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/userOperation.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/checkUserOperationIntents.rego similarity index 64% rename from apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/userOperation.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/checkUserOperationIntents.rego index c30837442..411a88407 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/userOperation.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/checkUserOperationIntents.rego @@ -1,65 +1,67 @@ -package main - -import future.keywords.in - -userOperationWildcardConditions = { - "type": wildcard, - "contract": wildcard, - "token": wildcard, - "spender": wildcard, - "chainId": wildcard, - "hexSignature": wildcard, - "algorithm": wildcard, +package armory.criteria + +import rego.v1 + +import data.armory.constants + +userOperationWildcardConditions := { + "type": constants.wildcard, + "contract": constants.wildcard, + "token": constants.wildcard, + "spender": constants.wildcard, + "chainId": constants.wildcard, + "hexSignature": constants.wildcard, + "algorithm": constants.wildcard, "source": { - "id": wildcard, - "address": wildcard, - "accountType": wildcard, - "classification": wildcard, + "id": constants.wildcard, + "address": constants.wildcard, + "accountType": constants.wildcard, + "classification": constants.wildcard, }, "destination": { - "id": wildcard, - "address": wildcard, - "accountType": wildcard, - "classification": wildcard, + "id": constants.wildcard, + "address": constants.wildcard, + "accountType": constants.wildcard, + "classification": constants.wildcard, }, "amount": { - "currency": wildcard, - "operator": wildcard, - "value": wildcard, + "currency": constants.wildcard, + "operator": constants.wildcard, + "value": constants.wildcard, }, "transfers": { - "tokens": wildcard, - "amounts": wildcard, + "tokens": constants.wildcard, + "amounts": constants.wildcard, }, "message": { - "operator": wildcard, - "value": wildcard, + "operator": constants.wildcard, + "value": constants.wildcard, }, "payload": { - "operator": wildcard, - "value": wildcard, + "operator": constants.wildcard, + "value": constants.wildcard, }, "domain": { - "version": wildcard, - "chainId": wildcard, - "name": wildcard, - "verifyingContract": wildcard, + "version": constants.wildcard, + "chainId": constants.wildcard, + "name": constants.wildcard, + "verifyingContract": constants.wildcard, }, "deadline": { - "operator": wildcard, - "value": wildcard, + "operator": constants.wildcard, + "value": constants.wildcard, }, } -checkUserOperationCondition(key, intent, condition) { - condition[key] == wildcard +checkUserOperationCondition(key, _, condition) if { + condition[key] == constants.wildcard } -checkUserOperationCondition(key, intent, condition) { +checkUserOperationCondition(key, intent, condition) if { intent[key] in condition[key] } -checkUserOperationIntents(conditions) { +checkUserOperationIntents(conditions) if { matchedConditions = [e | some intent in input.intent.operationIntents some c in conditions diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/destination/destination.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/destination/destination.rego new file mode 100644 index 000000000..78b00a355 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/destination/destination.rego @@ -0,0 +1,16 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants + +import data.armory.entities + +checkUserOperationDestination(key, _, condition) if { + condition[key] == constants.wildcard +} + +checkUserOperationDestination(key, intent, condition) if { + destination = entities.intentDestinationToChainAccount(intent) + destination[key] in condition[key] +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/permit/permit.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/permit/permit.rego new file mode 100644 index 000000000..af7f89ead --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/permit/permit.rego @@ -0,0 +1,51 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants + +getPermitDeadlineMs(intent) := to_number(intent.deadline) + +checkUserOperationPermitDeadline(_, condition) if { + condition.operator == constants.wildcard +} + +checkUserOperationPermitDeadline(_, condition) if { + condition.value == constants.wildcard +} + +checkUserOperationPermitDeadline(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.equal + getPermitDeadlineMs(intent) == to_number(condition.value) +} + +checkUserOperationPermitDeadline(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.notEqual + getPermitDeadlineMs(intent) != to_number(condition.value) +} + +checkUserOperationPermitDeadline(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.lessThanOrEqual + getPermitDeadlineMs(intent) <= to_number(condition.value) +} + +checkUserOperationPermitDeadline(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.greaterThanOrEqual + getPermitDeadlineMs(intent) >= to_number(condition.value) +} + +checkUserOperationPermitDeadline(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.lessThan + getPermitDeadlineMs(intent) < to_number(condition.value) +} + +checkUserOperationPermitDeadline(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.greaterThan + getPermitDeadlineMs(intent) > to_number(condition.value) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/domain.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/domain.rego new file mode 100644 index 000000000..621deeba0 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/domain.rego @@ -0,0 +1,13 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants + +checkUserOperationDomain(key, _, condition) if { + condition[key] == constants.wildcard +} + +checkUserOperationDomain(key, intent, condition) if { + intent.domain[key] in condition[key] +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/message.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/message.rego new file mode 100644 index 000000000..b577f142f --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/message.rego @@ -0,0 +1,25 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants + +checkUserOperationMessage(_, condition) if { + condition.operator == constants.wildcard +} + +checkUserOperationMessage(_, condition) if { + condition.value == constants.wildcard +} + +checkUserOperationMessage(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.equal + condition.value == intent.message +} + +checkUserOperationMessage(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.has + contains(intent.message, condition.value) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/payload.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/payload.rego new file mode 100644 index 000000000..975038921 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/signMessage/payload.rego @@ -0,0 +1,25 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants + +checkUserOperationPayload(_, condition) if { + condition.operator == constants.wildcard +} + +checkUserOperationPayload(_, condition) if { + condition.value == constants.wildcard +} + +checkUserOperationPayload(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.equal + condition.value == intent.payload +} + +checkUserOperationPayload(intent, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.has + contains(intent.payload, condition.value) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/source/source.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/source/source.rego new file mode 100644 index 000000000..54e2aa2b0 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/source/source.rego @@ -0,0 +1,16 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants + +import data.armory.entities + +checkUserOperationSource(key, _, condition) if { + condition[key] == constants.wildcard +} + +checkUserOperationSource(key, intent, condition) if { + source = entities.buildIntentSourceChainAccount(intent) + source[key] in condition[key] +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/transfers/userOperation_transfer.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/transfers/userOperation_transfer.rego new file mode 100644 index 000000000..834fa574c --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/userOperation/transfers/userOperation_transfer.rego @@ -0,0 +1,46 @@ +package armory.criteria + +import rego.v1 + +import data.armory.constants +import data.armory.criteria.util +import data.armory.lib + +getIntentTransfers(intent) := intent.transfers + +checkUserOperationTokensTransfers(_, condition) if { + condition == constants.wildcard +} + +checkUserOperationTokensTransfers(intent, condition) if { + condition != constants.wildcard + intentTransfers = getIntentTransfers(intent) + some transfer in intentTransfers + lib.caseInsensitiveFindInSet(transfer.token, condition) +} + +checkUserOperationAmountsTransfers(_, conditions) if { + conditions == constants.wildcard +} + +checkUserOperationAmountsTransfers(intent, conditions) if { + conditions != constants.wildcard + + intentTransfers = getIntentTransfers(intent) + + matches = [e | + some transfer in intentTransfers + some condition in conditions + transfer.token == condition.token + e = [transfer, condition] + ] + + validTransfers = [transfer | + some m in matches + transfer = m[0] + condition = m[1] + util.checkTransferAmount(transfer.amount, condition) + ] + + count(intentTransfers) == count(validTransfers) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/util/__test__/transfers_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/util/__test__/transfers_test.rego new file mode 100644 index 000000000..1db0053ba --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/util/__test__/transfers_test.rego @@ -0,0 +1,32 @@ +package armory.criteria.util + +import data.armory.constants +import data.armory.lib +import data.armory.testData +import rego.v1 + +test_checkErc1155TokenAmount if { + checkTransferAmount("1", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": constants.operators.notEqual, "value": "2"}) + checkTransferAmount("1", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": constants.operators.equal, "value": "1"}) + checkTransferAmount("5", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": constants.operators.greaterThanOrEqual, "value": "4"}) + checkTransferAmount("3", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": constants.operators.lessThanOrEqual, "value": "5"}) + checkTransferAmount("5", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": constants.operators.greaterThan, "value": "3"}) + checkTransferAmount("3", {"token": "eip155:137/erc1155:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4/41173", "operator": constants.operators.lessThan, "value": "5"}) +} + +test_transformIntentToTransferObject if { + res = transformIntentToTransferObject(input.intent) with input as testData.requestWithEip1559Transaction with data.entities as testData.entities + + expected := { + "amount": "1000000000000000000", + "chainId": 137, + "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98E", + "initiatedBy": "test-BOB-uid", + "rates": {"fiat:eur": "1.10", "fiat:usd": "0.99"}, + "resourceId": "eip155:eoa:0xDDcf208f219a6e6af072f2cfdc615b2c1805f98e", + "timestamp": lib.nowSeconds * 1000, + "to": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7A3", + "token": "eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aA84174", + } + res == expected +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/util/transfers.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/util/transfers.rego new file mode 100644 index 000000000..6b8e424f0 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/criteria/util/transfers.rego @@ -0,0 +1,250 @@ +package armory.criteria.util + +import rego.v1 + +import data.armory.constants +import data.armory.entities +import data.armory.feeds +import data.armory.lib + +transformIntentToTransferObject(intent) := result if { + contract = intent.contract + not feeds.priceFeed[contract] + resource := entities.getAccount(input.resource.uid) + + principal := entities.getUser(input.principal.userId) + + result = { + "amount": intent.amount, + "resourceId": resource.id, + "from": intent.from, + "to": intent.to, + "token": contract, + "rates": {}, + "timestamp": lib.nowSeconds * 1000, + "chainId": input.transactionRequest.chainId, + "initiatedBy": principal.id, + } +} + +# Case 1: When token is not in feeds.priceFeed +transformIntentToTransferObject(intent) := result if { + token := intent.token + not feeds.priceFeed[lower(token)] + + resource := entities.getAccount(input.resource.uid) + principal := entities.getUser(input.principal.userId) + + result := { + "amount": intent.amount, + "resourceId": resource.id, + "from": intent.from, + "to": intent.to, + "token": token, + "rates": {}, + "timestamp": lib.nowSeconds * 1000, + "chainId": input.transactionRequest.chainId, + "initiatedBy": principal.id, + } +} + +# Case 2: When token is in feeds.priceFeed +transformIntentToTransferObject(intent) := result if { + token := intent.token + feeds.priceFeed[lower(token)] + + resource := entities.getAccount(input.resource.uid) + principal := entities.getUser(input.principal.userId) + + result := { + "amount": intent.amount, + "resourceId": resource.id, + "from": intent.from, + "to": intent.to, + "token": token, + "rates": feeds.priceFeed[lower(token)], + "timestamp": lib.nowSeconds * 1000, + "chainId": input.transactionRequest.chainId, + "initiatedBy": principal.id, + } +} + +# Case 3: When intent has a contract field instead of token +transformIntentToTransferObject(intent) := result if { + token := intent.contract + + resource := entities.getAccount(input.resource.uid) + principal := entities.getUser(input.principal.userId) + + result := { + "amount": intent.amount, + "resourceId": resource.id, + "from": intent.from, + "to": intent.to, + "token": token, + "rates": feeds.priceFeed[lower(token)], + "timestamp": lib.nowSeconds * 1000, + "chainId": input.transactionRequest.chainId, + "initiatedBy": principal.id, + } +} + +intentTransferObjects := result if { + input.intent.type != "userOperation" + result = [transformIntentToTransferObject(input.intent)] +} + +intentTransferObjects := result if { + input.intent.type == "userOperation" + result = [transferObject | + some userOperationIntent in input.intent.operationIntents + transferObject = transformIntentToTransferObject(userOperationIntent) + ] +} + +# Check By Condition + +checkTransferCondition(_, set) if { + set == constants.wildcard +} + +checkTransferCondition(value, set) if { + set != constants.wildcard + lib.caseInsensitiveFindInSet(value, set) +} + +# Check By Principal + +checkTransferByPrincipal(_, false) + +checkTransferByPrincipal(initiator, true) if { + principal := entities.getUser(input.principal.userId) + lib.caseInsensitiveEqual(initiator, principal.id) +} + +# Check By User Groups + +checkTransferByUserGroups(_, values) if { + values == constants.wildcard +} + +checkTransferByUserGroups(userId, values) if { + values != constants.wildcard + groups = entities.getUser(userId).groups + some group in groups + lib.caseInsensitiveFindInSet(group, values) +} + +# Check By Account Groups +checkTransferByAccountGroups(_, values) if { + values == constants.wildcard +} + +## if accountId is not an eoa id +checkTransferByAccountGroups(accountId, values) if { + values != constants.wildcard + + address := entities.parseChainAccount(accountId).address + groups := entities.getAccount(address).groups + + some group in groups + lib.caseInsensitiveFindInSet(group, values) +} + +checkTransferByAccountGroups(accountId, values) if { + values != constants.wildcard + groups = entities.getAccount(accountId).groups + + some group in groups + lib.caseInsensitiveFindInSet(group, values) +} + +# Check By Start Date + +checkTransferFromStartDate(_, timeWindow) if { + timeWindow.startDate == constants.wildcard +} + +checkTransferFromStartDate(timestamp, timeWindow) if { + timeWindow.startDate != constants.wildcard + timestampNs = timestamp * 1000000 # convert ms to ns + timestampNs >= lib.secondsToNanoSeconds(timeWindow.startDate) +} + +# Check By End Date + +checkTransferToEndDate(_, timeWindow) if { + timeWindow.endDate == constants.wildcard +} + +checkTransferToEndDate(timestamp, timeWindow) if { + timeWindow.endDate != constants.wildcard + timestampNs = timestamp * 1000000 # convert ms to ns + timestampNs <= lib.secondsToNanoSeconds(timeWindow.endDate) +} + +# Check By Time Window Type + +checkTransferTimeWindow(_, timeWindow) if { + timeWindow.type == constants.wildcard +} + +checkTransferTimeWindow(timestamp, timeWindow) if { + timeWindow.type == "rolling" + timeWindow.value != constants.wildcard + timestampNs = timestamp * 1000000 # convert ms to ns + timestampNs >= time.now_ns() - lib.secondsToNanoSeconds(timeWindow.value) +} + +checkTransferTimeWindow(timestamp, timeWindow) if { + timeWindow.type == "fixed" + timeWindow.period != constants.wildcard + timestampNs = timestamp * 1000000 # convert ms to ns + timestampNs >= lib.getStartDateInNanoSeconds(timeWindow.period) +} + +# Check By Transfer Amount + +checkTransferAmount(_, condition) if { + condition.operator == constants.wildcard +} + +checkTransferAmount(_, condition) if { + condition.value == constants.wildcard +} + +checkTransferAmount(amount, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.equal + to_number(condition.value) == to_number(amount) +} + +checkTransferAmount(amount, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.notEqual + to_number(condition.value) != to_number(amount) +} + +checkTransferAmount(amount, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.greaterThan + to_number(condition.value) < to_number(amount) +} + +checkTransferAmount(amount, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.lessThan + to_number(condition.value) > to_number(amount) +} + +checkTransferAmount(amount, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.greaterThanOrEqual + to_number(condition.value) <= to_number(amount) +} + +checkTransferAmount(amount, condition) if { + condition.value != constants.wildcard + condition.operator == constants.operators.lessThanOrEqual + to_number(condition.value) >= to_number(amount) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/__test__/chainAccount_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/__test__/buildChainAccount_test.rego similarity index 82% rename from apps/policy-engine/src/resource/open-policy-agent/rego/utils/__test__/chainAccount_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/__test__/buildChainAccount_test.rego index 402709734..7c926b195 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/__test__/chainAccount_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/__test__/buildChainAccount_test.rego @@ -1,9 +1,14 @@ -package main +package armory.entities -import data.armory.lib.chainAccount.build.intentDestinationChainAccount +import rego.v1 -test_intentDestinationChainAccount_returns_implicit_managed_AddressBook_for_EOA_Account_found { - entry = intentDestinationChainAccount({ +test_extractAddressFromAccountId if { + address = extractAddressFromAccountId("eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e") + address == "0xddcf208f219a6e6af072f2cfdc615b2c1805f98e" +} + +test_intentDestinationChainAccountReturnsImplicitManagedAddressBookForEoaAccountFound if { + entry = intentDestinationToChainAccount({ "type": "transferERC20", "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "to": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", @@ -30,8 +35,8 @@ test_intentDestinationChainAccount_returns_implicit_managed_AddressBook_for_EOA_ } } -test_intentDestinationChainAccount_returns_implicit_managed_AddressBook_for_smart_Account_found { - entry = intentDestinationChainAccount({ +test_intentDestinationChainAccountReturnsImplicitManagedAddressBookForSmartAccountFound if { + entry = intentDestinationToChainAccount({ "type": "transferERC20", "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "to": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", @@ -59,8 +64,8 @@ test_intentDestinationChainAccount_returns_implicit_managed_AddressBook_for_smar } } -test_intentDestinationChainAccount_looks_up_AddressBook_by_intent_to_property { - intentDestinationChainAccount({ +test_intentDestinationChainAccountLooksUpAddressBookByIntentToProperty if { + intentDestinationToChainAccount({ "type": "transferERC20", "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "to": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", @@ -77,8 +82,8 @@ test_intentDestinationChainAccount_looks_up_AddressBook_by_intent_to_property { } } -test_intentDestinationChainAccount_returns_AddressBook_over_Account { - entry = intentDestinationChainAccount({ +test_intentDestinationChainAccountReturnsAddressBookOverAccount if { + entry = intentDestinationToChainAccount({ "type": "transferERC20", "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", "to": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", @@ -103,8 +108,8 @@ test_intentDestinationChainAccount_returns_AddressBook_over_Account { entry.classification == "internal" } -test_intentDestinationChainAccount_ignores_case_on_look_up { - entry = intentDestinationChainAccount({ +test_intentDestinationChainAccountIgnoresCaseOnLookup if { + entry = intentDestinationToChainAccount({ "to": "eip155:1:0x76d1b7f9b3f69c435eef76a98a415332084a856f", "from": "eip155:1:0x0301e2724a40e934cce3345928b88956901aa127", "type": "transferNative", diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/__test__/entityQueries_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/__test__/entityQueries_test.rego new file mode 100644 index 000000000..8b3842dc9 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/__test__/entityQueries_test.rego @@ -0,0 +1,137 @@ +package armory.entities + +import data.armory.testData +import rego.v1 + +test_account if { + account := getAccount("eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e") with data.entities as testData.entities + + expected := { + "accountType": "eoa", + "address": "0xddcf208F219a6e6af072f2cfdc615b2c1805f98e", + "assignees": ["test-bOb-uid", "test-alicE-uid", "test-foo-uid", "test-bar-uid"], + "groups": {"test-account-group-ONE-uid"}, + "id": "eip155:eoa:0xDDcf208f219a6e6af072f2cfdc615b2c1805f98e", + } + account == expected + + # Test case insensitivity + accountUpper := getAccount("eip155:eoa:0xDDCF208F219a6e6af072f2cfdc615b2c1805f98e") with data.entities as testData.entities + account == accountUpper +} + +test_accountFromAddress if { + account := getAccount("0xddcf208F219a6e6af072f2cfdc615b2c1805f98e") with data.entities as testData.entities + expected := { + "accountType": "eoa", + "address": "0xddcf208F219a6e6af072f2cfdc615b2c1805f98e", + "assignees": ["test-bOb-uid", "test-alicE-uid", "test-foo-uid", "test-bar-uid"], + "groups": {"test-account-group-ONE-uid"}, + "id": "eip155:eoa:0xDDcf208f219a6e6af072f2cfdc615b2c1805f98e", + } + account == expected + + # Test case insensitivity + accountUpper := getAccount("0xDDCF208F219a6e6af072f2cfdc615b2c1805f98e") with data.entities as testData.entities + account == accountUpper +} + +test_accountGroups if { + # Test finding a group by ID + group := getAccountGroup("test-account-group-ONE-uid") with data.entities as testData.entities + expectedGroup := { + "id": "test-account-group-ONE-uid", + "accounts": [ + "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", + "eip155:eoa:0xbbBB208f219a6e6af072f2cfdc615b2c1805f98e", + ], + "name": "dev", + } + group == expectedGroup + + # Test case insensitivity + groupsUpper := getAccountGroup("test-account-group-one-uid") with data.entities as testData.entities + group == groupsUpper + + # Test non-existent input + nonExistent := getAccountGroup("unknown") with data.entities as testData.entities + nonExistent == null +} + +test_userGroups if { + # Test finding a group by ID + group := getUserGroup("test-USER-group-one-uid") with data.entities as testData.entities + expectedGroup := { + "id": "test-USER-group-one-uid", + "name": "dev", + "users": ["test-Bob-uid", "test-Bar-uid"], + } + group == expectedGroup + + # Test case insensitivity + groupsUpper := getUserGroup("test-user-group-one-UID") with data.entities as testData.entities + group == groupsUpper + + # Test non-existent input + nonExistent := getUserGroup("unknown") with data.entities as testData.entities + nonExistent == null +} + +test_addressBookEntry if { + entry := getAddressBookEntry("eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3") with data.entities as testData.entities + expected := { + "id": "eip155:137:0xA45E21e9370ba031c5e1f47dedca74a7ce2ed7a3", + "address": "0xa45e21E9370Ba031c5e1f47dedca74a7ce2ed7a3", + "chainId": 137, + "classification": "internal", + } + entry == expected + + # Test case insensitivity + entryUpper := getAddressBookEntry("EIP155:137:0xA45E21E9370ba031c5e1f47dedca74a7ce2ed7a3") with data.entities as testData.entities + entry == entryUpper +} + +test_token if { + token := getToken("eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174") with data.entities as testData.entities + expected := { + "id": "eip155:137/erc20:0x2791bCA1f2de4661ed88a30c99a7a9449aa84174", + "address": "0x2791bca1f2de4661ED88a30c99a7a9449aa84174", + "symbol": "USDC", + "chainId": 137, + "decimals": 6, + } + + token == expected + + # Test case insensitivity + tokenUpper := getToken("EIP155:137/ERC20:0x2791BCA1f2de4661ed88a30c99a7a9449aa84174") with data.entities as testData.entities + token == tokenUpper +} + +test_user if { + user := getUser("test-bob-uid") with data.entities as testData.entities + + user == { + "id": "test-BOB-uid", + "role": "root", + "groups": {"test-USER-group-one-uid", "test-USER-group-two-uid"}, + } + + # Test case insensitivity + userUpper := getUser("test-BOB-uid") with data.entities as testData.entities + user == userUpper +} + +test_usersByRole if { + root := getUsersByRole("root") with data.entities as testData.entities + + root == {"test-BOB-uid"} + + admin := getUsersByRole("admin") with data.entities as testData.entities + admin == { + "test-Bar-uid", + "test-Foo-uid", + "0xAAA8ee1cbaa1856f4550c6fc24abb16c5c9b2a43", + } +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/chainAccount.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/buildChainAccount.rego similarity index 61% rename from apps/policy-engine/src/resource/open-policy-agent/rego/utils/chainAccount.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/buildChainAccount.rego index 6226687ec..4abfcf315 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/chainAccount.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/buildChainAccount.rego @@ -1,26 +1,13 @@ -package armory.lib.chainAccount.build +package armory.entities -import data.armory.entities.get -import data.armory.lib.case.equalsIgnoreCase +import rego.v1 -# EOA accounts are multichain by design. -_getChainId(account, chainAccount) = chainId { - account.accountType == "eoa" - chainId := chainAccount.chainId -} - -# Smart accounts are chain specific. -_getChainId(account, chainAccount) = chainId { - account.accountType == "4337" - chainId := account.chainId -} - -extractAddressFromAccountId(accountId) = result { +extractAddressFromAccountId(accountId) := result if { arr = split(accountId, ":") result := arr[count(arr) - 1] } -parseChainAccount(accountId) = chainAccount { +parseChainAccount(accountId) := chainAccount if { parts = split(accountId, ":") chainAccount := { "id": accountId, @@ -31,7 +18,7 @@ parseChainAccount(accountId) = chainAccount { } # Build chainAccount by merging accountData and addressBookData -mergeAccountAndAddressBook(chainAccount, accountData, addressBookData) = built { +mergeAccountAndAddressBook(chainAccount, accountData, addressBookData) := built if { addressBookData accountData @@ -40,7 +27,7 @@ mergeAccountAndAddressBook(chainAccount, accountData, addressBookData) = built { "address": chainAccount.address, "chainId": chainAccount.chainId, "classification": addressBookData.classification, - # we can default to 'managed' because its in entities.accounts + # we can default to 'managed' because its in accounts # TODO: @ptroger add addressBookGroups when implemented "accountType": accountData.accountType, "assignees": accountData.assignees, @@ -49,12 +36,12 @@ mergeAccountAndAddressBook(chainAccount, accountData, addressBookData) = built { } # Default source information when 'from' address is not found in account or address book -intentSourceChainAccount(intent) = source { +buildIntentSourceChainAccount(intent) := source if { intent.from chainAccount = parseChainAccount(intent.from) - get.account(chainAccount.address) == null - get.addressBookEntry(intent.from) == null + getAccount(chainAccount.address) == null + getAddressBookEntry(intent.from) == null source := { "id": intent.from, @@ -67,18 +54,18 @@ intentSourceChainAccount(intent) = source { } # Get source information when there is only an account entry -intentSourceChainAccount(intent) = source { +buildIntentSourceChainAccount(intent) := source if { chainAccount = parseChainAccount(intent.from) - accountData := get.account(chainAccount.address) - get.addressBookEntry(intent.from) == null + accountData := getAccount(chainAccount.address) + getAddressBookEntry(intent.from) == null source := { "id": chainAccount.id, "address": chainAccount.address, "chainId": chainAccount.chainId, "classification": "managed", - # we can default to 'managed' because its in entities.accounts + # we can default to 'managed' because its in accounts "accountType": accountData.accountType, "assignees": accountData.assignees, "groups": accountData.groups, @@ -86,11 +73,11 @@ intentSourceChainAccount(intent) = source { } # Get source information when there is only an address book entry -intentSourceChainAccount(intent) = source { +buildIntentSourceChainAccount(intent) := source if { chainAccount = parseChainAccount(intent.from) - get.account(chainAccount.address) == null - addressBookData = get.addressBookEntry(intent.from) + getAccount(chainAccount.address) == null + addressBookData = getAddressBookEntry(intent.from) source := { "id": chainAccount.id, @@ -102,19 +89,19 @@ intentSourceChainAccount(intent) = source { } # Get source information when there is both an account and address book entry -intentSourceChainAccount(intent) = source { +buildIntentSourceChainAccount(intent) := source if { chainAccount = parseChainAccount(intent.from) - addressBookData = get.addressBookEntry(intent.from) - accountData = get.account(chainAccount.address) + addressBookData = getAddressBookEntry(intent.from) + accountData = getAccount(chainAccount.address) source := mergeAccountAndAddressBook(chainAccount, accountData, addressBookData) } # Get destination information when there is neither account or address book entry, but an intent.to -intentDestinationChainAccount(intent) = destination { +intentDestinationToChainAccount(intent) := destination if { intent.to chainAccount = parseChainAccount(intent.to) - get.account(chainAccount.address) == null - get.addressBookEntry(intent.to) == null + getAccount(chainAccount.address) == null + getAddressBookEntry(intent.to) == null destination := { "id": intent.to, "address": chainAccount.address, @@ -123,16 +110,16 @@ intentDestinationChainAccount(intent) = destination { } # Get destination information when there is only an account entry -intentDestinationChainAccount(intent) = destination { +intentDestinationToChainAccount(intent) := destination if { chainAccount = parseChainAccount(intent.to) - get.addressBookEntry(intent.to) == null - accountData = get.account(chainAccount.address) + getAddressBookEntry(intent.to) == null + accountData = getAccount(chainAccount.address) destination := { "id": chainAccount.id, "address": chainAccount.address, "chainId": chainAccount.chainId, "classification": "managed", - # we can default to 'managed' because its in entities.accounts + # we can default to 'managed' because its in accounts "accountType": accountData.accountType, "assignees": accountData.assignees, "groups": accountData.groups, @@ -140,10 +127,10 @@ intentDestinationChainAccount(intent) = destination { } # Get destination information when there is only an address book entry -intentDestinationChainAccount(intent) = destination { +intentDestinationToChainAccount(intent) := destination if { chainAccount = parseChainAccount(intent.to) - get.account(chainAccount.address) == null - addressBookData = get.addressBookEntry(intent.to) + getAccount(chainAccount.address) == null + addressBookData = getAddressBookEntry(intent.to) destination := { "id": chainAccount.id, @@ -154,17 +141,17 @@ intentDestinationChainAccount(intent) = destination { } # Get destination information when there is both an account and address book entry -intentDestinationChainAccount(intent) = destination { - addressBookData = get.addressBookEntry(intent.to) +intentDestinationToChainAccount(intent) := destination if { + addressBookData = getAddressBookEntry(intent.to) chainAccount = parseChainAccount(intent.to) - accountData = get.account(chainAccount.address) + accountData = getAccount(chainAccount.address) destination := mergeAccountAndAddressBook(chainAccount, accountData, addressBookData) } -getEntryPoint(intent) = entrypoint { - entrypoint := get.account(intent.entrypoint) +getEntryPoint(intent) := entrypoint if { + entrypoint := getAccount(intent.entrypoint) entrypoint != null -} else = entrypoint { - entrypoint := get.addressBookEntry(intent.entrypoint) +} else := entrypoint if { + entrypoint := getAddressBookEntry(intent.entrypoint) } diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/entityQueries.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/entityQueries.rego similarity index 75% rename from apps/policy-engine/src/resource/open-policy-agent/rego/utils/entityQueries.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/entityQueries.rego index 66f43e163..97b149752 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/entityQueries.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/entities/entityQueries.rego @@ -1,23 +1,19 @@ -package armory.entities.get +package armory.entities -import data.armory.lib.case.equalsIgnoreCase -import data.armory.lib.case.findCaseInsensitive -import future.keywords.in +import rego.v1 + +import data.armory.lib # Helper function to find an account by its lowercased ID -accountById(id) = account { - account := data.entities.accounts[lower(id)] -} +getAccountById(id) := data.entities.accounts[lower(id)] # Helper function to find an account by its address # It returns the first account found with the given address ## NOTE: When/if we actuallys support Smart Accounts, we will need to return all accounts with the given address -accountByAddress(address) = account { - account := {account | - account := data.entities.accounts[_] - equalsIgnoreCase(account.address, address) - }[_] +getAccountByAddress(address) := account if { + some account in data.entities.accounts + lib.caseInsensitiveEqual(account.address, address) } ## Account @@ -28,7 +24,8 @@ accountByAddress(address) = account { ## ## Input: string ## Output: account object with its groups | null -## This function doesn't assumes wether the string is an ID or an address. It just tries its best to find an account giving a string. +## This function doesn't assumes wether the string is an ID or an address. +## It just tries its best to find an account giving a string. ## - It first treats string as an ID, and try to lookup at account index. ## - If not found, it treats string as an address, and try to find a matching address. ## @@ -61,7 +58,7 @@ accountByAddress(address) = account { ## } ## ## -## get.account("eip155:eoa:0x123") +## entities.getAccount("eip155:eoa:0x123") ## RETURNS { ## "accountType": "eoa", ## "address": "0x123", @@ -70,7 +67,7 @@ accountByAddress(address) = account { ## "id": "eip155:eoa:0x123", ## } ## -## get.account("eip155:137:0x456") +## entities.getAccount("eip155:137:0x456") ## RETURNS { ## "accountType": "4337", ## "address": "0x456", @@ -79,7 +76,7 @@ accountByAddress(address) = account { ## "id": "eip155:137:0x456", ## } ## -## get.account("0x456") +## entities.getAccount("0x456") ## RETURNS { ## "accountType": "4337", ## "address": "0x456", @@ -88,18 +85,18 @@ accountByAddress(address) = account { ## "id": "eip155:137:0x456", ## } ## -## Query4: get.account("foo") => null -account(string) = accountData { +## Query4: entities.getAccount("foo") => null +getAccount(string) := accountData if { # First, try to find the account by ID - account := accountById(string) - accountGroups := groupsByAccount(account.id) + account := getAccountById(string) + accountGroups := getGroupsByAccount(account.id) accountData := object.union(account, {"groups": accountGroups}) -} else = accountData { +} else := accountData if { # If not found by ID, try to find by address - account := accountByAddress(string) - accountGroups := groupsByAccount(account.id) + account := getAccountByAddress(string) + accountGroups := getGroupsByAccount(account.id) accountData := object.union(account, {"groups": accountGroups}) -} else = null +} else := null # If not found by ID or address, return null @@ -123,7 +120,7 @@ account(string) = accountData { ## }, ## } ## -## get.accountGroups("test-account-group-ONE-uid") +## entities.getAccountGroup("test-account-group-ONE-uid") ## RETURNS { ## "id": "test-account-group-ONE-uid", ## "accounts": ["eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e"], @@ -131,11 +128,11 @@ account(string) = accountData { ## } ## ## -## get.accountGroups("unknown") +## entities.getAccountGroup("unknown") ## RETURNS null -accountGroups(string) = group { +getAccountGroup(string) := group if { group := data.entities.accountGroups[lower(string)] -} else = null +} else := null ## Groups by Account ## @@ -144,17 +141,17 @@ accountGroups(string) = group { ## ## This function returns a set of account group IDs that the account is a member of. ## -## get.groupsByAccount("eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e") +## entities.getGroupsByAccount("eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e") ## RETURNS {"test-account-group-ONE-uid"} ## -## get.groupsByAccount("unknown") +## entities.getGroupsByAccount("unknown") ## RETURNS {} -groupsByAccount(accountId) = groups { +getGroupsByAccount(accountId) := groups if { groups := {group.id | - group := data.entities.accountGroups[_] - findCaseInsensitive(accountId, group.accounts) + some group in data.entities.accountGroups + lib.caseInsensitiveFindInSet(accountId, group.accounts) } -} else = null +} else := null ## User Groups ## @@ -176,7 +173,7 @@ groupsByAccount(accountId) = groups { ## }, ## } ## -## get.userGroups("test-USER-group-one-uid") +## entities.getUserGroup("test-USER-group-one-uid") ## RETURNS { ## "id": "test-USER-group-one-uid", ## "name": "dev", @@ -184,11 +181,11 @@ groupsByAccount(accountId) = groups { ## } ## ## -## get.userGroups("unknown") +## entities.getUserGroup("unknown") ## RETURNS null -userGroups(string) = group { +getUserGroup(string) := group if { group := data.entities.userGroups[lower(string)] -} else = null +} else := null ## Groups by User ## @@ -197,17 +194,17 @@ userGroups(string) = group { ## ## This function returns a set of user group IDs that the user is a member of. ## -## get.groupsByUser("test-bob-uid") +## entities.getGroupsByUser("test-bob-uid") ## RETURNS {"test-USER-group-one-uid"} ## -## get.groupsByUser("unknown") +## entities.getGroupsByUser("unknown") ## RETURNS {} -groupsByUser(userId) = groups { +getGroupsByUser(userId) := groups if { groups := {group.id | - group := data.entities.userGroups[_] - findCaseInsensitive(userId, group.users) + some group in data.entities.userGroups + lib.caseInsensitiveFindInSet(userId, group.users) } -} else = null +} else := null ## Address Book Entry ## @@ -230,7 +227,7 @@ groupsByUser(userId) = groups { ## }, ## } ## -## get.addressBookEntry("eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3") +## entities.getAddressBookEntry("eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3") ## RETURNS { ## "id": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", ## "address": "0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3", @@ -238,11 +235,11 @@ groupsByUser(userId) = groups { ## "chainId": 137, ## } ## -## Query2: get.addressBookEntry("eip155:137:0x123") +## Query2: entities.getAddressBookEntry("eip155:137:0x123") ## RETURNS null -addressBookEntry(id) = entry { +getAddressBookEntry(id) := entry if { entry := data.entities.addressBook[lower(id)] -} else = null +} else := null ## Token ## @@ -277,9 +274,9 @@ addressBookEntry(id) = entry { ## ## get.token("unknown") ## RETURNS null -token(id) = tokenData { +getToken(id) := tokenData if { tokenData := data.entities.tokens[lower(id)] -} else = null +} else := null ## User ## @@ -305,20 +302,20 @@ token(id) = tokenData { ## }, ## } ## -## get.user("test-bob-uid") +## entities.getUser("test-bob-uid") ## RETURNS { ## "id": "test-BOB-uid", ## "role": "root", ## "groups": {"test-USER-group-one-uid"}, ## } ## -## get.user("unknown") +## entities.getUser("unknown") ## RETURNS null -user(id) = userData { +getUser(id) := userData if { user := data.entities.users[lower(id)] - groups := groupsByUser(user.id) + groups := getGroupsByUser(user.id) userData := object.union(user, {"groups": groups}) -} else = null +} else := null ## User by role ## @@ -342,14 +339,14 @@ user(id) = userData { ## }, ## } ## -## get.usersByRole("root") +## entities.getUsersByRole("root") ## RETURNS {"test-BOB-uid"} ## -## get.usersByRole("admin") +## entities.getUsersByRole("admin") ## RETURNS null -usersByRole(role) = users { +getUsersByRole(role) := users if { users := {user.id | - user := data.entities.users[_] + some user in data.entities.users user.role == role } -} else = null +} else := null diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/feeds/feeds.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/feeds/feeds.rego new file mode 100644 index 000000000..af081751c --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/feeds/feeds.rego @@ -0,0 +1,15 @@ +package armory.feeds + +import rego.v1 + +priceFeed := result if { + some feed in input.feeds + feed.source == "armory/price-feed" + result = feed.data +} + +transferFeed := result if { + some feed in input.feeds + feed.source == "armory/historical-transfer-feed" + result = feed.data +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/__test__/lib_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/__test__/lib_test.rego new file mode 100644 index 000000000..68c2e01ab --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/__test__/lib_test.rego @@ -0,0 +1,7 @@ +package armory.lib + +import rego.v1 + +test_parseUnits if { + parseUnits("3000", 6) == 3000000000 +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/case.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/case.rego new file mode 100644 index 000000000..df7d90100 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/case.rego @@ -0,0 +1,24 @@ +package armory.lib + +import rego.v1 + +## Case insensitive string comparison +## +## Example: +## lib.caseInsensitiveEqual("foo", "FOO") permit +## lib.caseInsensitiveEqual("foo", "bar") deny +## +## This should be use for every id and hex string comparison. +caseInsensitiveEqual(a, b) if lower(a) == lower(b) + +## Find a case-insensitive match in a SET +## +## Example: +## lib.caseInsensitiveFindInSet("foo", {"bar", "foo", "baz"}) => permit +## lib.caseInsensitiveFindInSet("foo", {"bar", "baz"}) => deny +## +caseInsensitiveFindInSet(needle, set) if { + lowerNeedle := lower(needle) + some elem in set + lower(elem) == lowerNeedle +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/number.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/number.rego new file mode 100644 index 000000000..7761c42cb --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/number.rego @@ -0,0 +1,11 @@ +package armory.lib + +import rego.v1 + +numberToString(n) := format_int(to_number(n), 10) + +parseUnits(value, decimals) := result if { + range = numbers.range(1, decimals) + powTen = [10 | some i in range] + result = to_number(value) * product(powTen) +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/time.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/time.rego similarity index 52% rename from apps/policy-engine/src/resource/open-policy-agent/rego/utils/time.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/time.rego index 5acf4c7ee..1d519bed5 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/time.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/lib/time.rego @@ -1,31 +1,33 @@ -package main +package armory.lib + +import rego.v1 # DON'T CHANGE 01 AND 02 # 01 always displays current month # 02 always displays current day -dateFormat = "2006-01-02" # YYYY-MM-DD +dateFormat := "2006-01-02" # YYYY-MM-DD -todayFormatted = time.format([time.now_ns(), "UTC", dateFormat]) +todayFormatted := time.format([time.now_ns(), "UTC", dateFormat]) -nowSeconds = nanoSecondsToSeconds(time.now_ns()) +nowSeconds := nanoSecondsToSeconds(time.now_ns()) -secondsToNanoSeconds(epochS) = epochS * 1000000000 +secondsToNanoSeconds(epochSec) := epochSec * 1000000000 -nanoSecondsToSeconds(epochNs) = epochNs / 1000000000 +nanoSecondsToSeconds(epochNs) := epochNs / 1000000000 -getStartDateInNanoSeconds(period) = result { +getStartDateInNanoSeconds(period) := result if { period == "1d" result = time.parse_ns(dateFormat, todayFormatted) } -getStartDateInNanoSeconds(period) = result { +getStartDateInNanoSeconds(period) := result if { period == "1m" todayArr = split(todayFormatted, "-") startMonth = concat("-", [todayArr[0], todayArr[1], "01"]) result = time.parse_ns(dateFormat, startMonth) } -getStartDateInNanoSeconds(period) = result { +getStartDateInNanoSeconds(period) := result if { period == "1y" todayArr = split(todayFormatted, "-") startYear = concat("-", [todayArr[0], "01", "01"]) diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/main_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/test_data/main_test.rego similarity index 86% rename from apps/policy-engine/src/resource/open-policy-agent/rego/__test__/main_test.rego rename to apps/policy-engine/src/resource/open-policy-agent/rego/armory/test_data/main_test.rego index 8ba86e0e7..e05eaeffb 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/__test__/main_test.rego +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/armory/test_data/main_test.rego @@ -1,30 +1,33 @@ -package main +package armory.testData -halfMatic = "500000000000000000" +import data.armory.lib +import rego.v1 -oneMatic = "1000000000000000000" +halfMatic := "500000000000000000" -tenMatic = "10000000000000000000" +oneMatic := "1000000000000000000" -halfMaticValue = "495000000000000000" +tenMatic := "10000000000000000000" -oneMaticValue = "990000000000000000" +halfMaticValue := "495000000000000000" -tenMaticValue = "9900000000000000000" +oneMaticValue := "990000000000000000" -twentyHoursAgo = (nowSeconds - ((20 * 60) * 60)) * 1000 # in ms +tenMaticValue := "9900000000000000000" -elevenHoursAgo = (nowSeconds - ((11 * 60) * 60)) * 1000 # in ms +twentyHoursAgo := (lib.nowSeconds - ((20 * 60) * 60)) * 1000 # in ms -tenHoursAgo = (nowSeconds - ((10 * 60) * 60)) * 1000 # in ms +elevenHoursAgo := (lib.nowSeconds - ((11 * 60) * 60)) * 1000 # in ms -nineHoursAgo = (nowSeconds - ((9 * 60) * 60)) * 1000 # in ms +tenHoursAgo := (lib.nowSeconds - ((10 * 60) * 60)) * 1000 # in ms -principalReq = {"userId": "test-bob-Uid"} +nineHoursAgo := (lib.nowSeconds - ((9 * 60) * 60)) * 1000 # in ms -resourceReq = {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98E"} +principalReq := {"userId": "test-bob-Uid"} -transactionRequestEIP1559 = { +resourceReq := {"uid": "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98E"} + +transactionRequestEip1559 := { "from": "0xddcf208f219a6e6af072f2cfdc615b2c1805f98E", "to": "0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7A3", "chainId": 137, @@ -37,7 +40,7 @@ transactionRequestEIP1559 = { "type": "2", } -transactionRequestLegacy = { +transactionRequestLegacy := { "from": "0xddcf208f219a6e6af072f2cfdc615b2c1805f98E", "to": "0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7A3", "chainId": 137, @@ -49,7 +52,7 @@ transactionRequestLegacy = { "type": "0", } -intentReq = { +intentReq := { "type": "transferERC20", "from": "eip155:137:0xddcf208f219a6e6af072f2cfdc615b2c1805f98E", "to": "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7A3", @@ -57,14 +60,14 @@ intentReq = { "amount": "1000000000000000000", # 1 USDC } -approvalsReq = [ +approvalsReq := [ {"userId": "test-bob-uiD"}, {"userId": "test-alice-uiD"}, {"userId": "test-foo-uiD"}, {"userId": "0xaaa8ee1cbaa1856f4550c6fc24abb16c5c9b2A43"}, ] -feedsReq = [ +feedsReq := [ { "source": "armory/price-feed", "sig": {}, @@ -120,9 +123,9 @@ feedsReq = [ }, ] -requestWithEip1559Transaction = { +requestWithEip1559Transaction := { "action": "signTransaction", - "transactionRequest": transactionRequestEIP1559, + "transactionRequest": transactionRequestEip1559, "principal": principalReq, "resource": resourceReq, "intent": intentReq, @@ -130,7 +133,7 @@ requestWithEip1559Transaction = { "feeds": feedsReq, } -requestWithLegacyTransaction = { +requestWithLegacyTransaction := { "action": "signTransaction", "transactionRequest": transactionRequestLegacy, "principal": principalReq, @@ -140,7 +143,7 @@ requestWithLegacyTransaction = { "feeds": feedsReq, } -entities = { +entities := { "addressBook": { "eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3": { "id": "eip155:137:0xA45E21e9370ba031c5e1f47dedca74a7ce2ed7a3", diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/action.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/action.rego deleted file mode 100644 index 34da42810..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/action.rego +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import future.keywords.in - -checkAction(values) { - input.action in values -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/approval.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/approval.rego deleted file mode 100644 index c47557aec..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/approval.rego +++ /dev/null @@ -1,122 +0,0 @@ -package main - -import data.armory.entities.get -import data.armory.lib.case.equalsIgnoreCase -import data.armory.lib.case.findCaseInsensitive -import future.keywords.in - -getApprovalsCount(possibleApprovers) = result { - matchedApprovers = {approval.userId | - approval = input.approvals[_] - findCaseInsensitive(approval.userId, possibleApprovers) - } - result = count(matchedApprovers) -} - -# User approvals - -checkApproval(approval) = result { - principal := get.user(input.principal.userId) - - approval.countPrincipal == true - approval.approvalEntityType == "Narval::User" - possibleApprovers = {entity | entity = approval.entityIds[_]} | {principal.id} - result = getApprovalsCount(possibleApprovers) -} - -checkApproval(approval) = result { - principal := get.user(input.principal.userId) - - approval.countPrincipal == false - approval.approvalEntityType == "Narval::User" - possibleApprovers = {entity | - entity = approval.entityIds[_] - equalsIgnoreCase(entity, principal.id) == false - } - result = getApprovalsCount(possibleApprovers) -} - -# User group approvals - -checkApproval(approval) = result { - principal := get.user(input.principal.userId) - - approval.countPrincipal == true - approval.approvalEntityType == "Narval::UserGroup" - possibleApprovers = {user | - entity = approval.entityIds[_] - users = get.userGroups(entity).users - user = users[_] - } | {principal.id} - - result = getApprovalsCount(possibleApprovers) -} - -checkApproval(approval) = result { - principal := get.user(input.principal.userId) - - approval.countPrincipal == false - approval.approvalEntityType == "Narval::UserGroup" - possibleApprovers = {user | - entity = approval.entityIds[_] - users = get.userGroups(entity).users - user = users[_] - equalsIgnoreCase(user, principal.id) == false - } - - result = getApprovalsCount(possibleApprovers) -} - -# User role approvals - -checkApproval(approval) = result { - principal := get.user(input.principal.userId) - - approval.countPrincipal == true - approval.approvalEntityType == "Narval::UserRole" - possibleApprovers := {user | - role := approval.entityIds[_] - users := get.usersByRole(role) - user := users[_] - } - - result = getApprovalsCount(possibleApprovers) -} - -checkApproval(approval) = result { - principal := get.user(input.principal.userId) - - approval.countPrincipal == false - approval.approvalEntityType == "Narval::UserRole" - role := approval.entityIds[_] - - possibleApprovers := {user | - role_id := approval.entityIds[_] - users := get.usersByRole(role_id) - user := users[_] - equalsIgnoreCase(user, principal.id) == false - } - - result = getApprovalsCount(possibleApprovers) -} - -checkApprovals(approvals) = result { - principal := get.user(input.principal.userId) - - approvalsMissing = [approval | - approval = approvals[_] - approvalCount = checkApproval(approval) - approvalCount < approval.approvalCount - ] - - approvalsSatisfied = [approval | - approval = approvals[_] - approvalCount = checkApproval(approval) - approvalCount >= approval.approvalCount - ] - - result = { - "approvalsSatisfied": approvalsSatisfied, - "approvalsMissing": approvalsMissing, - } -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/amount.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/amount.rego deleted file mode 100644 index 1a0b3a1cf..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/amount.rego +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import future.keywords.in - -intentAmount = to_number(input.intent.amount) - -getAmountCondition(filters) = object.union( - { - "currency": wildcard, - "operator": wildcard, - "value": wildcard, - }, - filters, -) - -calculateIntentAmount(currency) = result { - currency == wildcard - result = intentAmount -} - -calculateIntentAmount(currency) = result { - currency != wildcard - token = input.intent.token - price = to_number(priceFeed[lower(token)][lower(currency)]) - result = intentAmount * price -} - -calculateIntentAmount(currency) = result { - currency != wildcard - contract = input.intent.contract - price = to_number(priceFeed[lower(contract)][lower(currency)]) - result = intentAmount * price -} - -checkIntentAmount(filters) { - condition = getAmountCondition(filters) - condition.operator == wildcard -} - -checkIntentAmount(filters) { - condition = getAmountCondition(filters) - condition.value == wildcard -} - -checkIntentAmount(filters) { - condition = getAmountCondition(filters) - condition.value != wildcard - condition.operator == operators.equal - calculateIntentAmount(condition.currency) == to_number(condition.value) -} - -checkIntentAmount(filters) { - condition = getAmountCondition(filters) - condition.value != wildcard - condition.operator == operators.notEqual - calculateIntentAmount(condition.currency) != to_number(condition.value) -} - -checkIntentAmount(filters) { - condition = getAmountCondition(filters) - condition.value != wildcard - condition.operator == operators.greaterThan - calculateIntentAmount(condition.currency) > to_number(condition.value) -} - -checkIntentAmount(filters) { - condition = getAmountCondition(filters) - condition.value != wildcard - condition.operator == operators.lessThan - calculateIntentAmount(condition.currency) < to_number(condition.value) -} - -checkIntentAmount(filters) { - condition = getAmountCondition(filters) - condition.value != wildcard - condition.operator == operators.greaterThanOrEqual - calculateIntentAmount(condition.currency) >= to_number(condition.value) -} - -checkIntentAmount(filters) { - condition = getAmountCondition(filters) - condition.value != wildcard - condition.operator == operators.lessThanOrEqual - calculateIntentAmount(condition.currency) <= to_number(condition.value) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/destination.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/destination.rego deleted file mode 100644 index a8d0eace2..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/destination.rego +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import data.armory.lib.case.findCaseInsensitive -import data.armory.lib.chainAccount.build -import future.keywords.in - -checkDestinationId(values) { - destination = build.intentDestinationChainAccount(input.intent) - findCaseInsensitive(destination.id, values) -} - -checkDestinationAddress(values) { - destination = build.intentDestinationChainAccount(input.intent) - findCaseInsensitive(destination.address, values) -} - -checkDestinationAccountType(values) { - destination = build.intentDestinationChainAccount(input.intent) - destination.accountType in values -} - -checkDestinationClassification(values) { - destination = build.intentDestinationChainAccount(input.intent) - destination.classification in values -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/intent.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/intent.rego deleted file mode 100644 index 1163e89e3..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/intent.rego +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import data.armory.lib.case.findCaseInsensitive -import future.keywords.in - -checkIntentType(values) { - input.intent.type in values -} - -checkIntentContract(values) { - findCaseInsensitive(input.intent.contract, values) -} - -checkIntentToken(values) { - findCaseInsensitive(input.intent.token, values) -} - -checkIntentSpender(values) { - findCaseInsensitive(input.intent.spender, values) -} - -checkIntentChainId(values) { - numberToString(input.intent.chainId) in values -} - -checkIntentHexSignature(values) { - findCaseInsensitive(input.intent.hexSignature, values) -} - -checkIntentAlgorithm(values) { - input.intent.algorithm in values -} - -checkIntentBeneficiary(values) { - input.intent.beneficiary in values -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/permit.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/permit.rego deleted file mode 100644 index 86cb5b5f4..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/permit.rego +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import future.keywords.in - -permitDeadlineMs = to_number(input.intent.deadline) - -checkPermitDeadline(condition) { - condition.operator == wildcard -} - -checkPermitDeadline(condition) { - condition.value == wildcard -} - -checkPermitDeadline(condition) { - condition.value != wildcard - condition.operator == operators.equal - permitDeadlineMs == to_number(condition.value) -} - -checkPermitDeadline(condition) { - condition.value != wildcard - condition.operator == operators.notEqual - permitDeadlineMs != to_number(condition.value) -} - -checkPermitDeadline(condition) { - condition.value != wildcard - condition.operator == operators.lessThanOrEqual - permitDeadlineMs <= to_number(condition.value) -} - -checkPermitDeadline(condition) { - condition.value != wildcard - condition.operator == operators.greaterThanOrEqual - permitDeadlineMs >= to_number(condition.value) -} - -checkPermitDeadline(condition) { - condition.value != wildcard - condition.operator == operators.lessThan - permitDeadlineMs < to_number(condition.value) -} - -checkPermitDeadline(condition) { - condition.value != wildcard - condition.operator == operators.greaterThan - permitDeadlineMs > to_number(condition.value) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signMessage/message.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signMessage/message.rego deleted file mode 100644 index c00a6246d..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signMessage/message.rego +++ /dev/null @@ -1,21 +0,0 @@ -package main - -checkIntentMessage(condition) { - condition.operator == wildcard -} - -checkIntentMessage(condition) { - condition.value == wildcard -} - -checkIntentMessage(condition) { - condition.value != wildcard - condition.operator == operators.equal - condition.value == input.intent.message -} - -checkIntentMessage(condition) { - condition.value != wildcard - condition.operator == operators.contains - contains(input.intent.message, condition.value) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signMessage/payload.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signMessage/payload.rego deleted file mode 100644 index 508d25624..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signMessage/payload.rego +++ /dev/null @@ -1,21 +0,0 @@ -package main - -checkIntentPayload(condition) { - condition.operator == wildcard -} - -checkIntentPayload(condition) { - condition.value == wildcard -} - -checkIntentPayload(condition) { - condition.value != wildcard - condition.operator == operators.equal - condition.value == input.intent.payload -} - -checkIntentPayload(condition) { - condition.value != wildcard - condition.operator == operators.contains - contains(input.intent.payload, condition.value) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signTypedData/domain.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signTypedData/domain.rego deleted file mode 100644 index b5984412a..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/signTypedData/domain.rego +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import future.keywords.in - -wildcardIntentDomain = { - "version": wildcard, - "chainId": wildcard, - "name": wildcard, - "verifyingContract": wildcard, -} - -checkDomainCondition(value, set) { - set == wildcard -} - -checkDomainCondition(value, set) { - set != wildcard - value in set -} - -checkIntentDomain(filters) { - domain = object.union(wildcardIntentDomain, input.intent.typedData.domain) - conditions = object.union(wildcardIntentDomain, filters) - checkDomainCondition(domain.version, conditions.version) - checkDomainCondition(numberToString(domain.chainId), conditions.chainId) - checkDomainCondition(domain.name, conditions.name) - checkDomainCondition(domain.verifyingContract, conditions.verifyingContract) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/source.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/source.rego deleted file mode 100644 index f7f291a5d..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/source.rego +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import data.armory.lib.case.findCaseInsensitive -import data.armory.lib.chainAccount.build - -import future.keywords.in - -checkSourceId(values) { - source = build.intentSourceChainAccount(input.intent) - findCaseInsensitive(source.id, values) -} - -checkSourceAddress(values) { - source = build.intentSourceChainAccount(input.intent) - findCaseInsensitive(source.address, values) -} - -checkSourceAccountType(values) { - source = build.intentSourceChainAccount(input.intent) - source.accountType in values -} - -checkSourceClassification(values) { - source = build.intentSourceChainAccount(input.intent) - source.classification in values -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/transfers.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/transfers.rego deleted file mode 100644 index 2ed1ba5c7..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/transfers.rego +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import future.keywords.in - -intentTransfers = input.intent.transfers - -checkErc1155TokenId(values) { - transfer = intentTransfers[_] - transfer.token in values -} - -checkErc1155Transfers(conditions) { - matches = [e | - some transfer in intentTransfers - some condition in conditions - transfer.token == condition.token - e = [transfer, condition] - ] - - validTransfers = [transfer | - some m in matches - transfer = m[0] - condition = m[1] - checkTransferAmount(transfer.amount, condition) - ] - - count(intentTransfers) == count(validTransfers) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/entryPoint.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/entryPoint.rego deleted file mode 100644 index f860ec715..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/entryPoint.rego +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import data.armory.lib.case.findCaseInsensitive -import data.armory.lib.chainAccount.build.getEntryPoint -import future.keywords.in - -checkEntryPointId(values) { - entrypoint = getEntryPoint(input.intent) - print("entrypoint.id: ", entrypoint.id) - findCaseInsensitive(entrypoint.id, values) -} - -checkEntryPointAddress(values) { - entrypoint = getEntryPoint(input.intent) - findCaseInsensitive(entrypoint.address, values) -} - -checkEntryPointAccountType(values) { - entrypoint = getEntryPoint(input.intent) - entrypoint.accountType in values -} - -checkEntryPointClassification(values) { - entrypoint = getEntryPoint(input.intent) - entrypoint.classification in values -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/amount.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/amount.rego deleted file mode 100644 index 7ca77c621..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/amount.rego +++ /dev/null @@ -1,64 +0,0 @@ -package main - -calculateIntentAmountForUserOperation(intent, currency) = result { - currency == wildcard - result = to_number(intent.amount) -} - -calculateIntentAmountForUserOperation(intent, currency) = result { - currency != wildcard - amount = to_number(intent.amount) - price = to_number(priceFeed[intent.token][currency]) - result = amount * price -} - -calculateIntentAmountForUserOperation(intent, currency) = result { - currency != wildcard - amount = to_number(intent.amount) - price = to_number(priceFeed[intent.contract][currency]) - result = amount * price -} - -checkUserOperationAmount(intent, condition) { - condition.operator == wildcard -} - -checkUserOperationAmount(intent, condition) { - condition.value == wildcard -} - -checkUserOperationAmount(intent, condition) { - condition.value != wildcard - condition.operator == operators.equal - calculateIntentAmountForUserOperation(intent, condition.currency) == to_number(condition.value) -} - -checkUserOperationAmount(intent, condition) { - condition.value != wildcard - condition.operator == operators.notEqual - calculateIntentAmountForUserOperation(intent, condition.currency) != to_number(condition.value) -} - -checkUserOperationAmount(intent, condition) { - condition.value != wildcard - condition.operator == operators.greaterThan - calculateIntentAmountForUserOperation(intent, condition.currency) > to_number(condition.value) -} - -checkUserOperationAmount(intent, condition) { - condition.value != wildcard - condition.operator == operators.lessThan - calculateIntentAmountForUserOperation(intent, condition.currency) < to_number(condition.value) -} - -checkUserOperationAmount(intent, condition) { - condition.value != wildcard - condition.operator == operators.greaterThanOrEqual - calculateIntentAmountForUserOperation(intent, condition.currency) >= to_number(condition.value) -} - -checkUserOperationAmount(intent, condition) { - condition.value != wildcard - condition.operator == operators.lessThanOrEqual - calculateIntentAmountForUserOperation(intent, condition.currency) <= to_number(condition.value) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/destination.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/destination.rego deleted file mode 100644 index 3beeea177..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/destination.rego +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import data.armory.lib.chainAccount.build.intentDestinationChainAccount -import future.keywords.in - -checkUserOperationDestination(key, intent, condition) { - condition[key] == wildcard -} - -checkUserOperationDestination(key, intent, condition) { - destination = intentDestinationChainAccount(intent) - destination[key] in condition[key] -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/permit.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/permit.rego deleted file mode 100644 index c3df083fe..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/permit.rego +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import future.keywords.in - -getPermitDeadlineMs(intent) = to_number(intent.deadline) - -checkUserOperationPermitDeadline(intent, condition) { - condition.operator == wildcard -} - -checkUserOperationPermitDeadline(intent, condition) { - condition.value == wildcard -} - -checkUserOperationPermitDeadline(intent, condition) { - condition.value != wildcard - condition.operator == operators.equal - getPermitDeadlineMs(intent) == to_number(condition.value) -} - -checkUserOperationPermitDeadline(intent, condition) { - condition.value != wildcard - condition.operator == operators.notEqual - getPermitDeadlineMs(intent) != to_number(condition.value) -} - -checkUserOperationPermitDeadline(intent, condition) { - condition.value != wildcard - condition.operator == operators.lessThanOrEqual - getPermitDeadlineMs(intent) <= to_number(condition.value) -} - -checkUserOperationPermitDeadline(intent, condition) { - condition.value != wildcard - condition.operator == operators.greaterThanOrEqual - getPermitDeadlineMs(intent) >= to_number(condition.value) -} - -checkUserOperationPermitDeadline(intent, condition) { - condition.value != wildcard - condition.operator == operators.lessThan - getPermitDeadlineMs(intent) < to_number(condition.value) -} - -checkUserOperationPermitDeadline(intent, condition) { - condition.value != wildcard - condition.operator == operators.greaterThan - getPermitDeadlineMs(intent) > to_number(condition.value) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/domain.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/domain.rego deleted file mode 100644 index 4f65296f6..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/domain.rego +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import future.keywords.in - -checkUserOperationDomain(key, intent, condition) { - condition[key] == wildcard -} - -checkUserOperationDomain(key, intent, condition) { - intent.domain[key] in condition[key] -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/message.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/message.rego deleted file mode 100644 index 5a69ec317..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/message.rego +++ /dev/null @@ -1,21 +0,0 @@ -package main - -checkUserOperationMessage(intent, condition) { - condition.operator == wildcard -} - -checkUserOperationMessage(intent, condition) { - condition.value == wildcard -} - -checkUserOperationMessage(intent, condition) { - condition.value != wildcard - condition.operator == operators.equal - condition.value == intent.message -} - -checkUserOperationMessage(intent, condition) { - condition.value != wildcard - condition.operator == operators.contains - contains(intent.message, condition.value) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/payload.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/payload.rego deleted file mode 100644 index d55ec88c7..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/signMessage/payload.rego +++ /dev/null @@ -1,21 +0,0 @@ -package main - -checkUserOperationPayload(intent, condition) { - condition.operator == wildcard -} - -checkUserOperationPayload(intent, condition) { - condition.value == wildcard -} - -checkUserOperationPayload(intent, condition) { - condition.value != wildcard - condition.operator == operators.equal - condition.value == intent.payload -} - -checkUserOperationPayload(intent, condition) { - condition.value != wildcard - condition.operator == operators.contains - contains(intent.payload, condition.value) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/source.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/source.rego deleted file mode 100644 index 68606d413..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/source.rego +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import data.armory.lib.chainAccount.build -import future.keywords.in - -checkUserOperationSource(key, intent, condition) { - condition[key] == wildcard -} - -checkUserOperationSource(key, intent, condition) { - source = build.intentSourceChainAccount(intent) - source[key] in condition[key] -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/transfers.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/transfers.rego deleted file mode 100644 index f4e7f2a14..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/intent/userOperation/intents/transfers.rego +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import future.keywords.in - -getIntentTransfers(intent) = intent.transfers - -checkUserOperationTokensTransfers(intent, condition) { - condition == wildcard -} - -checkUserOperationTokensTransfers(intent, condition) { - condition != wildcard - intentTransfers = getIntentTransfers(intent) - transfer = intentTransfers[_] - transfer.token in condition -} - -checkUserOperationAmountsTransfers(intent, conditions) { - conditions == wildcard -} - -checkUserOperationAmountsTransfers(intent, conditions) { - conditions != wildcard - - intentTransfers = getIntentTransfers(intent) - - matches = [e | - some transfer in intentTransfers - some condition in conditions - transfer.token == condition.token - e = [transfer, condition] - ] - - validTransfers = [transfer | - some m in matches - transfer = m[0] - condition = m[1] - checkTransferAmount(transfer.amount, condition) - ] - - count(intentTransfers) == count(validTransfers) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/permission.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/permission.rego deleted file mode 100644 index 0c5946250..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/permission.rego +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import data.armory.lib.case.findCaseInsensitive -import future.keywords.every -import future.keywords.in - -checkResource(values) { - input.action in {actions.grantPermission} - findCaseInsensitive(input.resource.uid, values) -} - -checkPermission(grantedPermission) { - every permission in input.permissions { - permission in grantedPermission - } -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/principal.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/principal.rego deleted file mode 100644 index deb100f6f..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/principal.rego +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import data.armory.entities.get -import data.armory.lib.case.findCaseInsensitive - -import future.keywords.in - -## Id are lowercased -checkPrincipalId(values) { - principal := get.user(input.principal.userId) - findCaseInsensitive(principal.id, values) -} - -## roles are constants -checkPrincipalRole(values) { - principal := get.user(input.principal.userId) - principal.role in values -} - -## Ids are lowercased -checkPrincipalGroup(values) { - principalGroups := get.user(input.principal.userId).groups - some group in principalGroups - findCaseInsensitive(group, values) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/rateLimit.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/rateLimit.rego deleted file mode 100644 index 493e1cf0c..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/rateLimit.rego +++ /dev/null @@ -1,76 +0,0 @@ -package main - -rateLimitWildcardConditions = { - "limit": wildcard, - "timeWindow": { - "type": wildcard, # rolling, fixed - "period": wildcard, # 1d, 1m, 1y - "value": wildcard, # in seconds - "startDate": wildcard, # in seconds - "endDate": wildcard, # in seconds - }, - "filters": { - "perPrincipal": false, - "tokens": wildcard, - "users": wildcard, - "resources": wildcard, - "destinations": wildcard, - "chains": wildcard, - "userGroups": wildcard, - "accountGroups": wildcard, - }, -} - -# Check Rate Limit - -calculateCurrentRate(params) = result { - conditions = object.union(rateLimitWildcardConditions, params) - rateLimit = conditions.limit - timeWindow = conditions.timeWindow - filters = conditions.filters - transfers = array.concat(transferFeed, intentTransferObjects) - - result = count([transfer | - transfer = transfers[_] - - # filter by principal - checkTransferByPrincipal(transfer.initiatedBy, filters.perPrincipal) - - # filter by tokens - checkTransferCondition(transfer.token, filters.tokens) - - # filter by users - checkTransferCondition(transfer.initiatedBy, filters.users) - - # filter by resource accounts - checkTransferCondition(transfer.resourceId, filters.resources) - - # filter by destination accounts - checkTransferCondition(transfer.to, filters.destinations) - - # filter by chains - checkTransferCondition(numberToString(transfer.chainId), filters.chains) - - # filter by user groups - checkTransferByUserGroups(transfer.initiatedBy, filters.userGroups) - - # filter by account groups - checkTransferByAccountGroups(transfer.from, filters.accountGroups) - - # filter by start date - checkTransferFromStartDate(transfer.timestamp, timeWindow) - - # filter by end date - checkTransferToEndDate(transfer.timestamp, timeWindow) - - # filter by time window type - checkTransferTimeWindow(transfer.timestamp, timeWindow) - ]) -} - -checkRateLimit(params) { - conditions = object.union(rateLimitWildcardConditions, params) - rateLimit = to_number(conditions.limit) - - calculateCurrentRate(conditions) <= rateLimit -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/resource.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/resource.rego deleted file mode 100644 index 6f8ef746a..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/resource.rego +++ /dev/null @@ -1,38 +0,0 @@ -package main - -import data.armory.entities.get -import data.armory.lib.case.findCaseInsensitive - -import future.keywords.in - -checkAccountAssigned { - principal := get.user(input.principal.userId) - resource := get.account(input.resource.uid) - findCaseInsensitive(principal.id, resource.assignees) -} - -checkAccountId(values) { - resource := get.account(input.resource.uid) - findCaseInsensitive(resource.id, values) -} - -checkAccountAddress(values) { - resource := get.account(input.resource.uid) - findCaseInsensitive(resource.address, values) -} - -checkAccountType(values) { - resource := get.account(input.resource.uid) - resource.accountType in values -} - -checkAccountChainId(values) { - resource := get.account(input.resource.uid) - numberToString(resource.chainId) in values -} - -checkAccountGroup(values) { - resource := get.account(input.resource.uid) - group = resource.groups[_] - findCaseInsensitive(group, values) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/spendingLimit.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/spendingLimit.rego deleted file mode 100644 index 8a029eb8a..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/spendingLimit.rego +++ /dev/null @@ -1,115 +0,0 @@ -package main - -spendingWildcardConditions = { - "currency": wildcard, - "limit": wildcard, - "operator": wildcard, - "timeWindow": { - "type": wildcard, # rolling, fixed - "period": wildcard, # 1d, 1m, 1y - "value": wildcard, # in seconds - "startDate": wildcard, # in seconds - "endDate": wildcard, # in seconds - }, - "filters": { - "perPrincipal": false, - "tokens": wildcard, - "users": wildcard, - "resources": wildcard, - "destinations": wildcard, - "chains": wildcard, - "userGroups": wildcard, - "accountGroups": wildcard, - }, -} - -# Calculate Spending - -calculateTransferSpending(transfer, currency) = result { - currency == wildcard - result = to_number(transfer.amount) -} - -calculateTransferSpending(transfer, currency) = result { - currency != wildcard - result = to_number(transfer.amount) * to_number(transfer.rates[lower(currency)]) -} - -# Check Spendings - -checkSpendingOperator(spendings, operator, limit) { - operator == operators.lessThan - spendings < limit -} - -checkSpendingOperator(spendings, operator, limit) { - operator == operators.lessThanOrEqual - spendings <= limit -} - -checkSpendingOperator(spendings, operator, limit) { - operator == operators.greaterThan - spendings > limit -} - -checkSpendingOperator(spendings, operator, limit) { - operator == operators.greaterThanOrEqual - spendings >= limit -} - -# Check Spending Limit - -calculateCurrentSpendings(params) = result { - conditions = object.union(spendingWildcardConditions, params) - timeWindow = conditions.timeWindow - filters = conditions.filters - transfers = array.concat(transferFeed, intentTransferObjects) - - result = sum([spending | - transfer = transfers[_] - - # filter by principal - checkTransferByPrincipal(transfer.initiatedBy, filters.perPrincipal) - - # filter by tokens - checkTransferCondition(transfer.token, filters.tokens) - - # filter by users - checkTransferCondition(transfer.initiatedBy, filters.users) - - # filter by resource accounts - checkTransferCondition(transfer.resourceId, filters.resources) - - # filter by destination accounts - checkTransferCondition(transfer.to, filters.destinations) - - # filter by chains - checkTransferCondition(numberToString(transfer.chainId), filters.chains) - - # filter by user groups - checkTransferByUserGroups(transfer.initiatedBy, filters.userGroups) - - # filter by account groups - checkTransferByAccountGroups(transfer.from, filters.accountGroups) - - # filter by start date - checkTransferFromStartDate(transfer.timestamp, timeWindow) - - # filter by end date - checkTransferToEndDate(transfer.timestamp, timeWindow) - - # filter by time window type - checkTransferTimeWindow(transfer.timestamp, timeWindow) - - spending = calculateTransferSpending(transfer, conditions.currency) - ]) -} - -checkSpendingLimit(params) { - conditions = object.union(spendingWildcardConditions, params) - spendings = calculateCurrentSpendings(conditions) - operator = conditions.operator - limit = to_number(conditions.limit) - - checkSpendingOperator(spendings, operator, limit) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/transactionRequest/gas.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/transactionRequest/gas.rego deleted file mode 100644 index d74be3ee0..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/transactionRequest/gas.rego +++ /dev/null @@ -1,80 +0,0 @@ -package main - -gasFeeAmount = result { - input.transactionRequest.maxFeePerGas - input.transactionRequest.maxPriorityFeePerGas - result = (to_number(input.transactionRequest.maxFeePerGas) + to_number(input.transactionRequest.maxPriorityFeePerGas)) * to_number(input.transactionRequest.gas) -} - -gasFeeAmount = result { - not input.transactionRequest.maxFeePerGas - not input.transactionRequest.maxPriorityFeePerGas - result = to_number(input.transactionRequest.gasPrice) * to_number(input.transactionRequest.gas) -} - -getGasFeeAmountCondition(filters) = object.union( - { - "currency": wildcard, - "operator": wildcard, - "value": wildcard, - }, - filters, -) - -getGasFeeAmount(currency) = result { - currency == wildcard - result = gasFeeAmount -} - -getGasFeeAmount(currency) = result { - currency != wildcard - token = chainAssetId[chainId] - price = to_number(priceFeed[token][currency]) - result = gasFeeAmount * price -} - -checkGasFeeAmount(filters) { - condition = getGasFeeAmountCondition(filters) - condition.operator == wildcard -} - -checkGasFeeAmount(filters) { - condition = getGasFeeAmountCondition(filters) - condition.value == wildcard -} - -checkGasFeeAmount(filters) { - condition = getGasFeeAmountCondition(filters) - condition.operator == operators.equal - to_number(condition.value) == getGasFeeAmount(condition.currency) -} - -checkGasFeeAmount(filters) { - condition = getGasFeeAmountCondition(filters) - condition.operator == operators.notEqual - to_number(condition.value) != getGasFeeAmount(condition.currency) -} - -checkGasFeeAmount(filters) { - condition = getGasFeeAmountCondition(filters) - condition.operator == operators.greaterThan - to_number(condition.value) < getGasFeeAmount(condition.currency) -} - -checkGasFeeAmount(filters) { - condition = getGasFeeAmountCondition(filters) - condition.operator == operators.lessThan - to_number(condition.value) > getGasFeeAmount(condition.currency) -} - -checkGasFeeAmount(filters) { - condition = getGasFeeAmountCondition(filters) - condition.operator == operators.greaterThanOrEqual - to_number(condition.value) <= getGasFeeAmount(condition.currency) -} - -checkGasFeeAmount(filters) { - condition = getGasFeeAmountCondition(filters) - condition.operator == operators.lessThanOrEqual - to_number(condition.value) >= getGasFeeAmount(condition.currency) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/transactionRequest/nonce.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/transactionRequest/nonce.rego deleted file mode 100644 index 9453143bf..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/criteria/transactionRequest/nonce.rego +++ /dev/null @@ -1,9 +0,0 @@ -package main - -checkNonceExists { - input.transactionRequest.nonce -} - -checkNonceNotExists { - not input.transactionRequest.nonce -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/main.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/main.rego deleted file mode 100644 index 3c09fcd89..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/main.rego +++ /dev/null @@ -1,112 +0,0 @@ -package main - -import future.keywords.in - -wildcard = "*" - -actions = { - "signTransaction": "signTransaction", - "signRaw": "signRaw", - "signMessage": "signMessage", - "signTypedData": "signTypedData", - "grantPermission": "grantPermission", -} - -operators = { - "equal": "eq", - "notEqual": "ne", - "greaterThan": "gt", - "greaterThanOrEqual": "gte", - "lessThan": "lt", - "lessThanOrEqual": "lte", - "contains": "contains", -} - -chainAssetId = { - "1": "eip155:1/slip44:60", - "10": "eip155:10/slip44:614", - "56": "eip155:56/slip44:714", - "137": "eip155:137/slip44:966", - "250": "eip155:250/slip44:1007", - "42161": "eip155:42161/slip44:9001", - "42220": "eip155:42220/slip44:52752", - "43114": "eip155:43114/slip44:9000", -} - -priceFeed = result { - feed = input.feeds[_] - feed.source == "armory/price-feed" - result = feed.data -} - -transferFeed = result { - feed = input.feeds[_] - feed.source == "armory/historical-transfer-feed" - result = feed.data -} - -default evaluate = { - "permit": false, - "reasons": set(), - # The default flag indicates whether the rule was evaluated as expected or if - # it fell back to the default value. It also helps identify cases of what we - # call "implicit deny" in the legacy policy engine. - "default": true, -} - -permit[{"policyId": "allow-root-user", "policyName": "Allow root user"}] = reason { - checkPrincipalRole({"root"}) - - reason = { - "type": "permit", - "policyId": "allow-root-user", - "policyName": "Allow root user", - "approvalsSatisfied": [], - "approvalsMissing": [], - } -} - -forbid[{"policyId": "default-forbid-policy", "policyName": "Default Forbid Policy"}] = reason { - false - - reason = { - "type": "forbid", - "policyId": "default-forbid-policy", - "policyName": "Default Forbid Policy", - "approvalsSatisfied": [], - "approvalsMissing": [], - } -} - -evaluate = decision { - permitSet = {p | p = permit[_]} - forbidSet = {f | f = forbid[_]} - - count(forbidSet) == 0 - count(permitSet) > 0 - - # If ALL Approval in permitSet has count(approval.approvalsMissing) == 0, set "permit": true. - # We "Stack" approvals, so multiple polices that match & each have different requirements, ALL must succeed. - # If you want to avoid this, the rules should get upper bounded so they're mutually exlusive, but that's done at the policy-builder time, not here. - - # Filter permitSet to only include objects where approvalsMissing is empty - filteredPermitSet = {p | p = permitSet[_]; count(p.approvalsMissing) == 0} - - decision = { - "permit": count(filteredPermitSet) == count(permitSet), - "reasons": permitSet, - } -} - -evaluate = decision { - permitSet = {p | p = permit[_]} - forbidSet = {f | f = forbid[_]} - - # If the forbid set is not empty, set "permit": false. - count(forbidSet) > 0 - - decision = { - "permit": false, - "reasons": forbidSet, - } -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/main/default_policies.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/main/default_policies.rego new file mode 100644 index 000000000..0fa53358c --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/main/default_policies.rego @@ -0,0 +1,24 @@ +package main + +import data.armory.criteria +import rego.v1 + +permit[{"policyId": "allow-root-user", "policyName": "Allow root user"}] := reason if { + criteria.checkPrincipalRole({"root"}) + + reason := { + "type": "permit", + "policyId": "allow-root-user", + "policyName": "Allow root user", + "approvalsSatisfied": [], + "approvalsMissing": [], + } +} + +forbid[{"policyId": "default-forbid-policy", "policyName": "Default Forbid Policy"}] := { + "type": "forbid", + "policyId": "default-forbid-policy", + "policyName": "Default Forbid Policy", + "approvalsSatisfied": [], + "approvalsMissing": [], +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/main/evaluate.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/main/evaluate.rego new file mode 100644 index 000000000..35e8e2403 --- /dev/null +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/main/evaluate.rego @@ -0,0 +1,56 @@ +package main + +import rego.v1 + +# METADATA +# description: returns a decision based on the evaluation of the rules +# a root user will always be permitted +# if no rule is matched, the default policy will be to forbid +# entrypoint: true +default evaluate := { + "permit": false, + "reasons": set(), + "default": true, +} + +evaluate := decision if { + permitSet := {matchedPermit | some matchedPermit in permit} + forbidSet := {matchedForbid | + some matchedForbid in forbid + matchedForbid.policyId != "default-forbid-policy" + } + + count(forbidSet) == 0 + count(permitSet) > 0 + + # If ALL Approval in permitSet has count(approval.approvalsMissing) == 0, set "permit": true. + # We "Stack" approvals, so multiple polices that match & each have different requirements, ALL must succeed. + # If you want to avoid this, the rules should get upper bounded so they're mutually exlusive. + # That's done at the policy-builder time, not here. + + # Filter permitSet to only include objects where approvalsMissing is empty + filteredPermitSet := {p | + some p in permitSet + count(object.get(p, "approvalsMissing", [])) == 0 + } + + decision = { + "permit": count(filteredPermitSet) == count(permitSet), + "reasons": permitSet, + } +} + +evaluate := decision if { + forbidSet := {matchedForbid | + some matchedForbid in forbid + matchedForbid.policyId != "default-forbid-policy" + } + + # If the forbid set is not empty, set "permit": false. + count(forbidSet) > 0 + + decision = { + "permit": false, + "reasons": forbidSet, + } +} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/rules.template.hbs b/apps/policy-engine/src/resource/open-policy-agent/rego/rules.template.hbs index fa46ec924..58682266d 100644 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/rules.template.hbs +++ b/apps/policy-engine/src/resource/open-policy-agent/rego/rules.template.hbs @@ -1,4 +1,4 @@ -package main +package main import data.armory.criteria {{#each policies}} {{then}}[{"policyId": "{{id}}", "policyName": "{{name}}" }] = reason { diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/__test__/entityQueries_test.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/utils/__test__/entityQueries_test.rego deleted file mode 100644 index 869677971..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/__test__/entityQueries_test.rego +++ /dev/null @@ -1,135 +0,0 @@ -package main - -import data.armory.entities.get -import data.armory.lib.case.findCaseInsensitive - -test_account { - account := get.account("eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e") with data.entities as entities - - expected := { - "accountType": "eoa", - "address": "0xddcf208F219a6e6af072f2cfdc615b2c1805f98e", - "assignees": ["test-bOb-uid", "test-alicE-uid", "test-foo-uid", "test-bar-uid"], - "groups": {"test-account-group-ONE-uid"}, - "id": "eip155:eoa:0xDDcf208f219a6e6af072f2cfdc615b2c1805f98e", - } - account == expected - - # Test case insensitivity - account_upper := get.account("eip155:eoa:0xDDCF208F219a6e6af072f2cfdc615b2c1805f98e") with data.entities as entities - account == account_upper -} - -test_account_from_address { - account := get.account("0xddcf208F219a6e6af072f2cfdc615b2c1805f98e") with data.entities as entities - expected := { - "accountType": "eoa", - "address": "0xddcf208F219a6e6af072f2cfdc615b2c1805f98e", - "assignees": ["test-bOb-uid", "test-alicE-uid", "test-foo-uid", "test-bar-uid"], - "groups": {"test-account-group-ONE-uid"}, - "id": "eip155:eoa:0xDDcf208f219a6e6af072f2cfdc615b2c1805f98e", - } - account == expected - - # Test case insensitivity - account_upper := get.account("0xDDCF208F219a6e6af072f2cfdc615b2c1805f98e") with data.entities as entities - account == account_upper -} - -test_accountGroups { - # Test finding a group by ID - group := get.accountGroups("test-account-group-ONE-uid") with data.entities as entities - expected_group := { - "id": "test-account-group-ONE-uid", - "accounts": [ - "eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e", - "eip155:eoa:0xbbBB208f219a6e6af072f2cfdc615b2c1805f98e", - ], - "name": "dev", - } - group == expected_group - - # Test case insensitivity - groups_upper := get.accountGroups("test-account-group-one-uid") with data.entities as entities - group == groups_upper - - # Test non-existent input - non_existent := get.accountGroups("unknown") with data.entities as entities - non_existent == null -} - -test_userGroups { - # Test finding a group by ID - group := get.userGroups("test-USER-group-one-uid") with data.entities as entities - expected_group := { - "id": "test-USER-group-one-uid", - "name": "dev", - "users": ["test-Bob-uid", "test-Bar-uid"], - } - group == expected_group - - # Test case insensitivity - groups_upper := get.userGroups("test-user-group-one-UID") with data.entities as entities - group == groups_upper - - # Test non-existent input - non_existent := get.userGroups("unknown") with data.entities as entities - non_existent == null -} - -test_addressBookEntry { - entry := get.addressBookEntry("eip155:137:0xa45e21e9370ba031c5e1f47dedca74a7ce2ed7a3") with data.entities as entities - expected := { - "id": "eip155:137:0xA45E21e9370ba031c5e1f47dedca74a7ce2ed7a3", - "address": "0xa45e21E9370Ba031c5e1f47dedca74a7ce2ed7a3", - "chainId": 137, - "classification": "internal", - } - entry == expected - - # Test case insensitivity - entry_upper := get.addressBookEntry("EIP155:137:0xA45E21E9370ba031c5e1f47dedca74a7ce2ed7a3") with data.entities as entities - entry == entry_upper -} - -test_token { - token := get.token("eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174") with data.entities as entities - expected := { - "id": "eip155:137/erc20:0x2791bCA1f2de4661ed88a30c99a7a9449aa84174", - "address": "0x2791bca1f2de4661ED88a30c99a7a9449aa84174", - "symbol": "USDC", - "chainId": 137, - "decimals": 6, - } - - # Test case insensitivity - token_upper := get.token("EIP155:137/ERC20:0x2791BCA1f2de4661ed88a30c99a7a9449aa84174") with data.entities as entities - token == token_upper -} - -test_user { - user := get.user("test-bob-uid") with data.entities as entities - - user == { - "id": "test-BOB-uid", - "role": "root", - "groups": {"test-USER-group-one-uid", "test-USER-group-two-uid"}, - } - - # Test case insensitivity - user_upper := get.user("test-BOB-uid") with data.entities as entities - user == user_upper -} - -test_usersByRole { - root := get.usersByRole("root") with data.entities as entities - - root == {"test-BOB-uid"} - - admin := get.usersByRole("admin") with data.entities as entities - admin == { - "test-Bar-uid", - "test-Foo-uid", - "0xAAA8ee1cbaa1856f4550c6fc24abb16c5c9b2a43", - } -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/case.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/utils/case.rego deleted file mode 100644 index eaf706214..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/case.rego +++ /dev/null @@ -1,26 +0,0 @@ -package armory.lib.case - -import future.keywords.in - -## Case insensitive string comparison -## -## Example: -## equalsIgnoreCase("foo", "FOO") => true -## equalsIgnoreCase("foo", "bar") => false -## -## This should be use for every id and hex string comparison. -equalsIgnoreCase(a, b) = result { - result := lower(a) == lower(b) -} - -## Find a case-insensitive match in a SET -## -## Example: -## findCaseInsensitive("foo", {"bar", "foo", "baz"}) => true -## findCaseInsensitive("foo", {"bar", "baz"}) => false -## -findCaseInsensitive(needle, set) { - lowerNeedle := lower(needle) - some elem in set - lower(elem) == lowerNeedle -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/number.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/utils/number.rego deleted file mode 100644 index f018ee1a6..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/number.rego +++ /dev/null @@ -1,9 +0,0 @@ -package main - -numberToString(n) = format_int(to_number(n), 10) - -parseUnits(value, decimals) = result { - range = numbers.range(1, decimals) - powTen = [n | i = range[_]; n = 10] - result = to_number(value) * product(powTen) -} diff --git a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/transfers.rego b/apps/policy-engine/src/resource/open-policy-agent/rego/utils/transfers.rego deleted file mode 100644 index a30bdfd9c..000000000 --- a/apps/policy-engine/src/resource/open-policy-agent/rego/utils/transfers.rego +++ /dev/null @@ -1,252 +0,0 @@ -package main - -import future.keywords.in - -import data.armory.entities.get -import data.armory.lib.case.equalsIgnoreCase -import data.armory.lib.case.findCaseInsensitive -import data.armory.lib.chainAccount.build.parseChainAccount - -transformIntentToTransferObject(intent) = result { - contract = intent.contract - not priceFeed[contract] - - resource := get.account(input.resource.uid) - principal := get.user(input.principal.userId) - - result = { - "amount": intent.amount, - "resourceId": resource.id, - "from": intent.from, - "to": intent.to, - "token": contract, - "rates": {}, - "timestamp": nowSeconds * 1000, - "chainId": input.transactionRequest.chainId, - "initiatedBy": input.principal.userId, - } -} - -# Case 1: When token is not in priceFeed -transformIntentToTransferObject(intent) = result { - token := intent.token - not priceFeed[lower(token)] - - resource := get.account(input.resource.uid) - principal := get.user(input.principal.userId) - - result := { - "amount": intent.amount, - "resourceId": resource.id, - "from": intent.from, - "to": intent.to, - "token": token, - "rates": {}, - "timestamp": nowSeconds * 1000, - "chainId": input.transactionRequest.chainId, - "initiatedBy": input.principal.userId, - } -} - -# Case 2: When token is in priceFeed -transformIntentToTransferObject(intent) = result { - token := intent.token - priceFeed[lower(token)] - - resource := get.account(input.resource.uid) - principal := get.user(input.principal.userId) - - result := { - "amount": intent.amount, - "resourceId": resource.id, - "from": intent.from, - "to": intent.to, - "token": token, - "rates": priceFeed[lower(token)], - "timestamp": nowSeconds * 1000, - "chainId": input.transactionRequest.chainId, - "initiatedBy": input.principal.userId, - } -} - -# Case 3: When intent has a contract field instead of token -transformIntentToTransferObject(intent) = result { - token := intent.contract - - resource := get.account(input.resource.uid) - principal := get.user(input.principal.userId) - - result := { - "amount": intent.amount, - "resourceId": resource.id, - "from": intent.from, - "to": intent.to, - "token": token, - "rates": priceFeed[lower(token)], - "timestamp": nowSeconds * 1000, - "chainId": input.transactionRequest.chainId, - "initiatedBy": input.principal.userId, - } -} - -intentTransferObjects = result { - input.intent.type != "userOperation" - result = [transformIntentToTransferObject(input.intent)] -} - -intentTransferObjects = result { - input.intent.type == "userOperation" - result = [transferObject | - userOperationIntent = input.intent.operationIntents[_] - transferObject = transformIntentToTransferObject(userOperationIntent) - ] -} - -# Check By Condition - -checkTransferCondition(value, set) { - set == wildcard -} - -checkTransferCondition(value, set) { - set != wildcard - findCaseInsensitive(value, set) -} - -# Check By Principal - -checkTransferByPrincipal(initiator, perPrincipal) { - perPrincipal == false -} - -checkTransferByPrincipal(initiator, perPrincipal) { - principal := get.user(input.principal.userId) - perPrincipal == true - equalsIgnoreCase(initiator, principal.id) -} - -# Check By User Groups - -checkTransferByUserGroups(userId, values) { - values == wildcard -} - -checkTransferByUserGroups(userId, values) { - values != wildcard - groups = get.user(userId).groups - group := groups[_] - res := findCaseInsensitive(group, values) -} - -# Check By Account Groups -checkTransferByAccountGroups(accountId, values) { - values == wildcard -} - -## if accountId is not an eoa id -checkTransferByAccountGroups(chainAccountId, values) { - values != wildcard - - address := parseChainAccount(chainAccountId).address - groups := get.account(address).groups - - group := groups[_] - findCaseInsensitive(group, values) -} - -checkTransferByAccountGroups(accountId, values) { - values != wildcard - groups = get.account(accountId).groups - group = groups[_] - findCaseInsensitive(group, values) -} - -# Check By Start Date - -checkTransferFromStartDate(timestamp, timeWindow) { - timeWindow.startDate == wildcard -} - -checkTransferFromStartDate(timestamp, timeWindow) { - timeWindow.startDate != wildcard - timestampNs = timestamp * 1000000 # convert ms to ns - timestampNs >= secondsToNanoSeconds(timeWindow.startDate) -} - -# Check By End Date - -checkTransferToEndDate(timestamp, timeWindow) { - timeWindow.endDate == wildcard -} - -checkTransferToEndDate(timestamp, timeWindow) { - timeWindow.endDate != wildcard - timestampNs = timestamp * 1000000 # convert ms to ns - timestampNs <= secondsToNanoSeconds(timeWindow.endDate) -} - -# Check By Time Window Type - -checkTransferTimeWindow(timestamp, timeWindow) { - timeWindow.type == wildcard -} - -checkTransferTimeWindow(timestamp, timeWindow) { - timeWindow.type == "rolling" - timeWindow.value != wildcard - timestampNs = timestamp * 1000000 # convert ms to ns - timestampNs >= time.now_ns() - secondsToNanoSeconds(timeWindow.value) -} - -checkTransferTimeWindow(timestamp, timeWindow) { - timeWindow.type == "fixed" - timeWindow.period != wildcard - timestampNs = timestamp * 1000000 # convert ms to ns - timestampNs >= getStartDateInNanoSeconds(timeWindow.period) -} - -# Check By Transfer Amount - -checkTransferAmount(amount, condition) { - condition.operator == wildcard -} - -checkTransferAmount(amount, condition) { - condition.value == wildcard -} - -checkTransferAmount(amount, condition) { - condition.value != wildcard - condition.operator == operators.equal - to_number(condition.value) == to_number(amount) -} - -checkTransferAmount(amount, condition) { - condition.value != wildcard - condition.operator == operators.notEqual - to_number(condition.value) != to_number(amount) -} - -checkTransferAmount(amount, condition) { - condition.value != wildcard - condition.operator == operators.greaterThan - to_number(condition.value) < to_number(amount) -} - -checkTransferAmount(amount, condition) { - condition.value != wildcard - condition.operator == operators.lessThan - to_number(condition.value) > to_number(amount) -} - -checkTransferAmount(amount, condition) { - condition.value != wildcard - condition.operator == operators.greaterThanOrEqual - to_number(condition.value) <= to_number(amount) -} - -checkTransferAmount(amount, condition) { - condition.value != wildcard - condition.operator == operators.lessThanOrEqual - to_number(condition.value) >= to_number(amount) -} diff --git a/examples/escrow/README.md b/examples/escrow/README.md index cb9645cdd..7b8ef61a9 100644 --- a/examples/escrow/README.md +++ b/examples/escrow/README.md @@ -5,6 +5,7 @@ Setup `npm i` (run from this directory) Copy the `.env.default` file into `.env`, and add your values + - `AUTH_HOST`, `VAULT_HOST`, `CLIENT_ID` & `CLIENT_SECRET` provided when you activated your Armory stack - `DATA_STORE_SIGNER_ADDRESS` and `DATA_STORE_PRIVATE_KEY` were what YOU set when activating your Armory stack - Player 1, 2, and 3 info can be used with the defaults (DO NOT TRANSFER REAL FUNDS TO THESE!) or enter your own private keys. @@ -34,7 +35,6 @@ If you want to keep going: `tsx 4-p2-withdrawal.ts $ESCROW_ADDRESS` -6. As P1, approve the previous transfer (copy/paste the displayed output from previous to get the $REQUEST_ID) +6. As P1, approve the previous transfer (copy/paste the displayed output from previous to get the $REQUEST_ID) `tsx 5-p1-transfer.ts` -