Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding stripe modular example #29

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions stores/stripe/accounts.fga
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

module account

type user
type account
relations
define owner: [user]
define admin: [user] or owner
define iam_admin: [user] or admin
define developer: [user] or admin
define transfer_analyst: [user] or admin
define view_only: [user] or admin
define transfer_analyst_in_test_mode: transfer_analyst but not transfer_analyst from test_mode # intermediate relations, just used for evaluating other relations

define test_mode: [account] # self-defining relationship, used to set a type into a true/false state
Copy link
Member

Choose a reason for hiding this comment

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

We should explain in the comments what is test mode used for in Stripe


define can_close_account: owner
define can_change_owner: owner
define can_invite: iam_admin
define can_add_bank_account: admin but not admin from test_mode # exclusion operator
define can_delete_default_bank_account: owner

type bank_account
relations
define account: [account]
define can_delete_bank_account: admin from account
define can_view: admin from account
define can_transfer_balance: transfer_analyst from account
5 changes: 5 additions & 0 deletions stores/stripe/fga.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
schema: '1.2'
contents:
- accounts.fga
- payments.fga
- issuing.fga
34 changes: 34 additions & 0 deletions stores/stripe/issuing.fga
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module issuing
Copy link
Member

Choose a reason for hiding this comment

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

Looks like an odd module name. What would be the app component handling this called? "card-management""


extend type account
relations
define card: [card] # dual-writes relationships between card & account, when you need to traverse relations on two types checking both ways (starting at card then going up or account then going down)
Copy link
Member

Choose a reason for hiding this comment

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

Can you clarify why we need to traverse it both ways?

define cardholder: cardholder from card
define cardholder_in_test_mode: cardholder from test_mode # exclusion operator

type card
relations
define account: [account]
define cardholder: [user]
define digital_wallet: [digital_wallet]
define active: [card] # self-defining relationship
define can_purchase: cardholder from active but not cardholder_in_test_mode from account
define can_view_transactions: cardholder or admin from account
define spending_limit_policy: [card#cardholder with spending_limit]

type transaction
relations
define card: [card]
define can_view: can_view_transactions from card

type digital_wallet
relations
define owner: [user]

# spending control condition
## default spending limit is 500 USD a day
## could be 100 USD per transaction
## could be 3000 USD per month
condition spending_limit(transaction_amount: double, transaction_limit: double, daily_amount: double, daily_limit: double, monthly_amount: double, monthly_limit: double) {
Copy link
Member

Choose a reason for hiding this comment

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

We should have tuples/tests that use the condition

transaction_amount + daily_amount <= daily_limit || transaction_amount <= transaction_limit || transaction_amount + monthly_amount <= monthly_limit
}
5 changes: 5 additions & 0 deletions stores/stripe/payments.fga
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module payments

type payment
type subscription
type invoice
179 changes: 179 additions & 0 deletions stores/stripe/stripe.fga.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
name: Stripe
model_file: ./fga.mod
tuples:
### Stripe Core Tuples ###
# Tyler is the owner of account:1
- user: user:tyler
relation: owner
object: account:1
# Andres is an admin of account:1
- user: user:andres
relation: admin
object: account:1
# Dongni can only view account:1
- user: user:dongni
relation: view_only
object: account:1
# The bank_account:1 belongs to account:1
- user: account:1
relation: account
object: bank_account:1

### Stripe Issuing Tuples ###
# SCENARIO 1: An account manages 2 cards, assinged to users Raghd and Jon. Raghd's card is active and makes two purcahses. Jon's card is inactive and makes one purchase
# OBJECTS: account:1, user:raghd, user:jon, card:1, card:2, transaction:1, transaction:2, transaction:3
- user: user:raghd # Raghd is the cardholder of card:1
relation: cardholder
object: card:1
- user: account:1 # The card:1 belongs to account:1
relation: account
object: card:1
- user: card:1 # The account:1 manages card:1
relation: card
object: account:1
- user: card:1 # The card:1 is activated
relation: active
object: card:1
- user: card:1 # The card:1 was used for transaction:1
relation: card
object: transaction:1
- user: card:1 # The card:1 was used for transaction:2
relation: card
object: transaction:2
- user: user:jon # Jon is the cardholder of card:2
relation: cardholder
object: card:2
- user: account:1 # The card:2 belongs to account:1
relation: account
object: card:2
- user: card:2 # The account:1 manages card:2
relation: card
object: account:1
- user: card:2 # The card:2 was used for transaction:3
relation: card
object: transaction:3
# but no card:2 "active" relationship tuple

# SCENARIO 2: A Stripe account (in test mode) manges one active card that tries to make a purchase.
# OBJECTS: account:2, card:3, transaction:4
- user: user:tyler # Tyler is the owner of account:2
relation: owner
object: account:2
- user: account:2 # The account:2 is in test mode
relation: test_mode
object: account:2
- user: card:3 # The account:2 manages card:3
relation: card
object: account:2
- user: account:2 # The card:3 belongs to account:2
relation: account
object: card:3
- user: user:maria # Maria is the cardholder of card:3
relation: cardholder
object: card:3
- user: card:3 # The card:3 is activated
relation: active
object: card:3

tests:
- name: Stripe Core Tests
check:
- user: user:tyler
object: account:1
assertions:
owner: true # "Is Tyler an owner of account:1?" | check direct relationship with account owner
iam_admin: true # "Is Tyler an iam_admin of account:1?" | check indirect 'concentric' relationship inherited from admin and owner
- user: user:dongni
object: account:1
assertions:
admin: false # "Is Dongni an admin of account:1?"
- user: user:tyler
object: bank_account:1
assertions:
can_delete_bank_account: true # "Can Tyler delete bank_account:1 from account:1?" | check parent-child inheritance
can_view: true # "Can Tyler view bank_account:1?"
can_transfer_balance: true # "Can Tyler transfer the balance in bank_account:1?"
- user: user:dongni
object: bank_account:1
assertions:
can_view: false # "Can Dongni view bank_account:1?"
- user: user:tyler
object: account:2
assertions:
can_add_bank_account: false # "Can Tyler add a bank_account if account:2 is in test_mode?" | check exclusion operator with self-defining attribute

- name: Stripe Issuing Tests
check:
- user: user:raghd
object: card:1
assertions:
cardholder: true # "Is Raghd the cardholder for card:1?"
- user: user:raghd
object: card:2
assertions:
cardholder: false # "Is Raghd the cardholder for card:2?"
- user: user:raghd
object: transaction:1
assertions:
can_view: true # "Can Raghd view transaction:1?"
- user: user:tyler
object: transaction:1
assertions:
can_view: true # "Can Tyler (an account owner that manages the card) view transaction:1?"

- user: card:1
object: card:1
assertions:
active: true # "Is card:1 active?" | check if card:1=active self-defining attribute tuple is set
- user: user:raghd
object: card:1
assertions:
can_purchase: true # "Can Raghd make a purchase with card:1?" if card:1 is active

- user: card:2
object: card:2
assertions:
active: false # "Is card:2 active?" | check if the active self-defining relationship tuple is set on card:2
- user: user:jon
object: card:2
assertions:
can_purchase: false # "Can Jon make a purchase with card:2?" if card:2 is inactive

- user: card:3
object: card:3
assertions:
active: true # "Is card:3 active?" | check if the active self-defining relationship tuple is set on card:3
- user: account:2
object: account:2
assertions:
test_mode: true # "Is account:2 in test_mode?" | check if the test_mode self-defining relationship tuple is set on account:2
- user: user:maria
object: card:3
assertions:
can_purchase: false # "Can Maria make a purchase with card:3 but the account is in test_mode)?" | check dual-write relationship inheritance

# todo: can someone make a purchase above a contextual spending limit?
# todo: can someone add a card to a wallet?

list_objects:
- user: user:raghd
type: card
assertions:
cardholder:
- card:1
- user: user:raghd
type: transaction
assertions:
can_view:
- transaction:1
- transaction:2
- user: user:jon
type: card
assertions:
cardholder:
- card:2
- user: user:jon
type: transaction
assertions:
can_view:
- transaction:3