diff --git a/features/activity_management.feature b/features/activity_management.feature index cb53c84..3255038 100644 --- a/features/activity_management.feature +++ b/features/activity_management.feature @@ -2,27 +2,31 @@ Feature: management of account activities and transactions As a system administrator, I want to record on-boarding transactions -so as to show/charge back costs of account management +so as to monitor and to manage service usage per cost center As a system administrator, I want to record maintenance transactions -so as to show/charge back costs of account management +so as to monitor and to manage service usage per cost center As a system administrator, I want to record console logins -so as to show/charge back costs of account management +so as to monitor and to manage service usage per cost center + +As a system administrator, +I want to record acknowledged notifications of account holders +so as to monitor and to manage service usage per cost center As a system administrator, I observe activities as daily metrics -so as to monitor and to manage account usage per cost center +so as to monitor and to manage service usage per cost center As a system administrator, I check the on-going report on activities -so as to monitor the daily report on SPA usage +so as to monitor and to manage service usage per cost center As a system administrator, I check the monthly reports on activities -so as to monitor the reports daily report on SPA usage +so as to monitor and to manage service usage per cost center Scenario: where a successful on-boarding transaction is recorded Given an existing SPA system @@ -48,20 +52,30 @@ Scenario: where a regular console login event is metered And a data point is put to metric 'TransactionsByCostCenter' And a data point is put to metric 'TransactionsByLabel' +Scenario: where an acknowledged notification is metered + Given an existing SPA system + When a 'AcknowledgedNotificationEvent' event for account '123456789012' is put from 'SustainablePersonalAccounts' + Then lambda function 'OnActivityEvent' is executed with the event + And details of the activity are put in a new record in the table 'ActivitiesTable' + And a data point is put to metric 'TransactionsByCostCenter' + And a data point is put to metric 'TransactionsByLabel' + Scenario: where activities appear in the monitoring dashboard Given an existing SPA system Then the monitoring dashboard displays metric 'TransactionsByCostCenter' And the monitoring dashboard displays metric 'TransactionsByLabel' -Scenario: where activites are reported everyday for current month +Scenario: where activites are reported for current month Given an existing SPA system - When the Lambda function 'OnDailyActivitiesReport' is invoked - Then code scans the table 'ActivitiesTable' for current month + When time is coming for a scheduled execution of 'OnOngoingActivitiesReport' + Then the Lambda function 'OnOngoingActivitiesReport' is invoked + And code scans the table 'ActivitiesTable' for current month And code reports a list of activities as one CSV file per month on S3 reporting bucket Scenario: where activities are reported for previous month Given an existing SPA system - When the Lambda function 'OnMonthlyActivitiesReport' is invoked - Then code scans the table 'ActivitiesTable' for previous month + When time is coming for a scheduled execution of 'OnPastActivitiesReport' + Then the Lambda function 'OnPastActivitiesReport' is invoked + And code scans the table 'ActivitiesTable' for previous month And code reports a list of activities as one CSV file per month on S3 reporting bucket diff --git a/features/cost_management.feature b/features/cost_management.feature index ea51cb7..594745b 100644 --- a/features/cost_management.feature +++ b/features/cost_management.feature @@ -33,8 +33,9 @@ Scenario: where additional currencies are configured for reports Scenario: where cloud costs are computed and released every day Given an existing SPA system - When the Lambda function 'OnDailyCostsMetric' is invoked - Then code inspects all accounts managed in the system + When time is coming for a scheduled execution of 'OnDailyCostsMetric' + Then the Lambda function 'OnDailyCostsMetric' is invoked + And code inspects all accounts managed in the system And code computes cost report for each account on previous day And code sums up cost reports per cost center And code pushes daily costs as a CloudWatch Metric @@ -42,8 +43,9 @@ Scenario: where cloud costs are computed and released every day Scenario: where cloud costs are computed and released every month Given an existing SPA system - When the Lambda function 'OnMonthlyCostsReport' is invoked - Then code inspects all accounts managed in the system + When time is coming for a scheduled execution of 'OnMonthlyCostsReport' + Then the Lambda function 'OnMonthlyCostsReport' is invoked + And code inspects all accounts managed in the system And code computes cost report for each account on previous month And code sums up cost reports per cost center And code pushes detailed monthly reports as one CSV file per cost center on S3 reporting bucket diff --git a/features/exception_management.feature b/features/exception_management.feature index 153823f..8271bd5 100644 --- a/features/exception_management.feature +++ b/features/exception_management.feature @@ -6,37 +6,42 @@ so as to support incident management and problem analysis Scenario: where a budget alert triggers an exception Given an existing SPA system - When the event 'BudgetAlertException' is emitted + When an event 'BudgetAlertException' is emitted Then the Lambda function 'OnException' is invoked Scenario: where a failed codebuild project triggers an exception Given an existing SPA system - When the event 'FailedCodebuildException' is emitted + When an event 'FailedCodebuildException' is emitted Then the Lambda function 'OnException' is invoked Scenario: where a failed on-boarding transaction triggers an exception Given an existing SPA system - When the event 'FailedOnBoardingException' is emitted + When an event 'FailedOnBoardingException' is emitted Then the Lambda function 'OnException' is invoked Scenario: where a failed maintenance transaction triggers an exception Given an existing SPA system - When the event 'FailedMaintenanceException' is emitted + When an event 'FailedMaintenanceException' is emitted Then the Lambda function 'OnException' is invoked Scenario: where a console login with root credentials triggers an exception Given an existing SPA system - When the event 'ConsoleLoginWithRootException' is emitted + When an event 'ConsoleLoginWithRootException' is emitted Then the Lambda function 'OnException' is invoked Scenario: where a console login with IAM user credentials triggers an exception Given an existing SPA system - When the event 'ConsoleLoginWithIamUserException' is emitted + When an event 'ConsoleLoginWithIamUserException' is emitted + Then the Lambda function 'OnException' is invoked + +Scenario: where an unacknowledged notification triggers an exception + Given an existing SPA system + When an event 'UnacknowledgedNotificationException' is emitted Then the Lambda function 'OnException' is invoked Scenario: where a generic exception is handled Given an existing SPA system - When the event 'GenericException' is emitted + When an event 'GenericException' is emitted Then the Lambda function 'OnException' is invoked Scenario: where an incident record is created on exception @@ -48,7 +53,7 @@ Scenario: where an incident record is created on exception Scenario: where an incident record is enriched with account information Given an exception that conveys an account id is put on the automation bus - And an incident record is created on exception + When an incident record is created on exception Then the incident record is tagged with account information And a cost report for current month for this account is attached to the incident record diff --git a/features/transaction_metering.feature b/features/transaction_metering.feature index 55274b5..ad64739 100644 --- a/features/transaction_metering.feature +++ b/features/transaction_metering.feature @@ -26,15 +26,15 @@ Scenario: where an on-boarding transaction ends Scenario: where an on-boarding transaction fails on timeout Given an account '123456789012' that is managed by SPA And a transaction of type 'on-boarding' for account '123456789012' with stamp of 'CreatedEvent' is recorded in table 'TransactionsTable' - When no event 'ReleasedEvent' is emitted for account '123456789012' during 'transactions_timeout_in_seconds' + When no event 'ReleasedEvent' is emitted for account '123456789012' during 'on_boarding_timeout_in_seconds' Then lambda function 'OnTransactionTimeOut' is executed with the expired record from table 'TransactionsTable' - And an event 'FailedOnboardingEvent' is emitted for account '123456789012' with data from the expired record + And an event 'FailedOnboardingException' is emitted for account '123456789012' with data from the expired record Scenario: where a maintenance transaction begins Given an account '123456789012' that is managed by SPA When the event 'ExpiredEvent' is emitted for account '123456789012' Then lambda function 'OnTransactionMetering' is executed with the event - And a transaction of type 'maintenance' for account '123456789012' with stamp of 'CreatedEvent' is recorded in table 'TransactionsTable' + And a transaction of type 'maintenance' for account '123456789012' with stamp of 'ExpiredEvent' is recorded in table 'TransactionsTable' Scenario: where a maintenance transaction ends Given an account '123456789012' that is managed by SPA @@ -46,8 +46,29 @@ Scenario: where a maintenance transaction ends Scenario: where a maintenance transaction fails on timeout Given an account '123456789012' that is managed by SPA - And a transaction of type 'maintenance' for account '123456789012' with stamp of 'CreatedEvent' is recorded in table 'TransactionsTable' - When no event 'ReleasedEvent' is emitted for account '123456789012' during 'transactions_timeout_in_seconds' + And a transaction of type 'maintenance' for account '123456789012' with stamp of 'ExpiredEvent' is recorded in table 'TransactionsTable' + When no event 'ReleasedEvent' is emitted for account '123456789012' during 'maintenance_timeout_in_seconds' + Then lambda function 'OnTransactionTimeOut' is executed with the expired record from table 'TransactionsTable' + And an event 'FailedMaintenanceException' is emitted for account '123456789012' with data from the expired record + +Scenario: where a notification transaction begins + Given an account '123456789012' that is managed by SPA + When the event 'NotificationEvent' is emitted for account '123456789012' + Then lambda function 'OnTransactionMetering' is executed with the event + And a transaction with identifier '123456789012 notification' with stamp of 'NotificationEvent' is recorded in table 'TransactionsTable' + +Scenario: where a notification transaction ends + Given an account '123456789012' that is managed by SPA + And a transaction with identifier '123456789012 notification' with stamp of 'NotificationEvent' is recorded in table 'TransactionsTable' + When the event 'AcknowledgementEvent' is emitted for account '123456789012' + Then lambda function 'OnTransactionMetering' is executed with the event + And transaction '123456789012 notification' is retrieved + And an event 'AcknowledgedNotificationEvent' is emitted with duration between 'NotificationEvent' and 'AcknowledgementEvent' + +Scenario: where a notification transaction fails on timeout + Given an account '123456789012' that is managed by SPA + And a transaction with identifier '123456789012 notification' with stamp of 'NotificationEvent' is recorded in table 'TransactionsTable' + When no event 'AcknowledgementEvent' is emitted for account '123456789012' during 'notification_timeout_in_seconds' Then lambda function 'OnTransactionTimeOut' is executed with the expired record from table 'TransactionsTable' - And an event 'FailedMaintenanceEvent' is emitted for account '123456789012' with data from the expired record + And an event 'UnacknowlegdedNotificationException' is emitted for account '123456789012' with data from the expired record diff --git a/features/user_confirmations.feature b/features/user_confirmations.feature deleted file mode 100644 index 01bbd1b..0000000 --- a/features/user_confirmations.feature +++ /dev/null @@ -1,83 +0,0 @@ -Feature: manage confirmations from end users - -As a system administrator, -I maintain a list of documents for end users -so as to ensure automatic awareness of term and conditions across end users - -As an end user, -I can access documents pushed to me and express feedback -so as to stay informed of terms of service and similar documents related to the service - - -Scenario: where no sending recipient has been configured - Given a settings file 'settings.yaml' adapted to SPA semantics - When the attribute 'with_sending_email_address' is not set in the section 'features' - And SPA is deployed with the settings file 'settings.yaml' - Then cloud resources are not deployed for automated confirmations - -Scenario: where a sending recipient is configured - Given a settings file 'settings.yaml' adapted to SPA semantics - When the attribute 'with_sending_email_address' is set to 'service@example.com' in the section 'features' - And SPA is deployed with the settings file 'settings.yaml' - Then cloud resources are deployed for automated confirmations - And lambda function 'OnUserDocumentAssociation' is triggered on event 'UserDocumentAssociation' - And lambda function 'OnUserDocumentConfirmation' is triggered on function URL - And lambda function 'OnUserDocumentExpiration' is triggered on transaction stream - And lambda function 'OnMonthlyConfirmationsReport' is triggered on first day of each month - -Scenario: where end-user documents are loaded into the system - Given a settings file 'settings.yaml' adapted to SPA semantics - When the attribute 'with_sending_email_address' is set to 'service@example.com' in the section 'features' - And the attribute 'with_end_user_documents' is set in the section 'features' - And SPA is deployed with the settings file 'settings.yaml' - Then SPA loads all files mentioned in the attribute 'with_end_user_documents' - And each document is put as a separate parameter in the SSM Parameter Store - -Scenario: where missing confirmations are checked on account release - Given an existing SPA system - When an event 'ReleasedAccount' for account '123456789012' is posted to the bus - Then lambda function 'OnUserDocumentCheck' handles the event 'ReleasedAccount' - And code retrieves settings for account '123456789012' - And the configuration item has attribute 'enabled' set to 'true' in attribute 'confirmations' - And code retrieves the email 'alice@example.com' associated with the account - And code scans the list of documents from SSM parameter store - And code scans transactions for 'alice@example.com' - And code emits event 'UserDocumentAssociation' for email 'alice@example.com' and for first missing document - -Scenario: where an end-user is associated with a document - Given an existing SPA system - When the attribute 'with_sending_email_address' is set to 'service@example.com' in the section 'features' - And an event 'UserDocumentAssociation' for email 'alice@example.com' and document 'terms_v0' is posted to the bus - Then lambda function 'OnUserDocumentAssociation' handles the event 'UserDocumentAssociation' - And code loads content of document 'terms_v0' from the SSM Parameter Store - And code stops if a transaction 'alice@example.com terms_v0' already exists - And a transaction 'alice@example.com terms_v0' is set with time of 'UserDocumentAssociation' and short-term ttl - And code prepares a mail message based on 'terms_v0' and with feedback link to Lambda function 'OnUserDocumentConfirmation' - And code sends the mail message from recipient 'service@example.com' to recipient 'alice@example.com' - -Scenario: where an end-user confirms the reading of the document - Given an existing SPA system - And a confirmation message is sent over email to 'alice@example.com' - When recipient of the message activates the confirmation link placed at the bottom of the message - Then lambda function 'OnUserDocumentConfirmation' is executed with parameter 'alice@example.com terms_v0' - And code retrieves transaction 'alice@example.com terms_v0' - And code stops if there is no transaction 'alice@example.com terms_v0' - And code stops if transaction 'alice@example.com terms_v0' has been already stamped - And code stamps transaction 'alice@example.com terms_v0' with current time and long-term ttl - And an event 'SuccessfulUserDocumentAssociation' is emitted for email 'alice@example.com' and document 'terms_v0' - -Scenario: where a document association fails on time-out - Given an existing SPA system - And a confirmation message is sent over email to 'alice@example.com' - When no invocation of lambda function 'OnUserDocumentConfirmation' is taking place with parameter 'alice@example.com terms_v0' - Then the transaction 'alice@example.com terms_v0' is expired - And lambda function 'OnUserDocumentExpiration' is executed - And an event 'FailedUserDocumentAssociation' is emitted for email 'alice@example.com' and document 'terms_v0' - -Scenario: where confirmations are reported every month - Given an existing SPA system - When the Lambda function 'OnMonthlyConfirmationsReport' is invoked - Then code scans transactions - And code pushes list of emails and confirmed documents as monthly CSV files on S3 reporting bucket - - diff --git a/features/user_notifications.feature b/features/user_notifications.feature new file mode 100644 index 0000000..bd69722 --- /dev/null +++ b/features/user_notifications.feature @@ -0,0 +1,86 @@ +Feature: manage notifications to end users + +As a system administrator, +I submit terms and conditions to end users and get confirmations +so as to ensure automatic awareness of term and conditions across end users + +As a system administrator, +I submit documents to end users and get confirmations +so as to notify end users through the life cycle of their personal accounts + +As an end user, +I can access documents pushed to me and express feedback +so as to stay informed of terms of service and similar documents related to the service + + +Scenario: where no sending recipient has been configured + Given a settings file 'settings.yaml' adapted to SPA semantics + When the attribute 'with_sending_email_address' is not set in the section 'features' + And SPA is deployed with the settings file 'settings.yaml' + Then there is a warning that notifications are not effective + +Scenario: where default notifications are configured + Given a settings file 'settings.yaml' adapted to SPA semantics + When the attribute 'notifications' is set in the configuration item 'defaults' + And the configuration item has attribute 'enabled' set to boolean value in attribute 'notifications' + And the configuration item has attribute 'documents' set to a list of key-values in attribute 'notifications' + And the configuration item has attribute 'context' set to a list of key-values in attribute 'notifications' + And SPA is deployed with the settings file 'settings.yaml' + Then SPA loads all labels and files mentioned in the attribute 'documents' + And one parameter is created in SSM Parameter Store for each label and file content + +Scenario: where notifications are configured for an account + Given a settings file 'settings.yaml' adapted to SPA semantics + When a configuration item with identifier '123456789012' is added to the section 'accounts' + And the configuration item has attribute 'enabled' set to boolean value in attribute 'notifications' + And the configuration item has attribute 'documents' set to a list of key-values in attribute 'notifications' + And the configuration item has attribute 'context' set to a list of key-values in attribute 'notifications' + And SPA is deployed with the settings file 'settings.yaml' + Then SPA loads all labels and files mentioned in the attribute 'documents' + And each label is suffixed with '-123456789012' + And one parameter is created in SSM Parameter Store for each label and file content + +Scenario: where notifications are configured for all accounts of an organizational unit + Given a settings file 'settings.yaml' adapted to SPA semantics + When a configuration item with identifier 'ou-abc' is added to the section 'organizational_units' + And the configuration item has attribute 'enabled' set to boolean value in attribute 'notifications' + And the configuration item has attribute 'documents' set to a list of key-values in attribute 'notifications' + And the configuration item has attribute 'context' set to a list of key-values in attribute 'notifications' + And SPA is deployed with the settings file 'settings.yaml' + Then SPA loads all labels and files mentioned in the attribute 'documents' + And each label is suffixed with '-ou-abc' + And one parameter is created in SSM Parameter Store for each label and file content + +Scenario: where first missing notification is sent on account release + Given an existing SPA system + When lambda function 'OnReleasedAccount' is executed on account '123456789012' + Then code retrieves settings for account '123456789012' + And the configuration item has attribute 'enabled' set to 'true' in attribute 'notifications' + And code retrieves the email 'alice@example.com' associated with the account + And code retrieves past notifications for email 'alice@example.com' from the table 'NotificationsTable' + And first missing notification is 'terms_v0' + And code loads content of document 'terms_v0' from the SSM Parameter Store + And code contextualises document with key-values from 'context' in attribute 'notifications' + And code records notification for identifier 'alice@example.com' and order 'terms_v0' in the table 'NotificationsTable' + And code prepares a mail message based on 'terms_v0' and with feedback link to Lambda function 'OnAcknowledgement' + And code sends the mail message from recipient 'service@example.com' to recipient 'alice@example.com' + And an event 'NotificationEvent' is emitted for account '123456789012' + +Scenario: where a notification is acknowledged by end-user + Given an existing SPA system + And a notification message is sent over email to 'alice@example.com' + When recipient of the message activates the notification link placed at the bottom of the message + Then lambda function 'OnAcknowledgement' is executed with parameter 'alice@example.com terms_v0' + And code retrieves record for identifier 'alice@example.com' and order 'terms_v0' from the table 'NotificationsTable' + And code stops if record has been already stamped + And code stamps record with current time and long-term ttl + And an event 'AckowledgementEvent' is emitted for account '123456789012' + +Scenario: where notifications are reported every month + Given an existing SPA system + When time is coming for a scheduled execution of 'OnMonthlyNotificationsReport' + Then the Lambda function 'OnMonthlyNotificationsReport' is invoked + And code scans records from table 'NotificationsTable' + And code pushes list of emails and confirmed documents as monthly CSV files on S3 reporting bucket + + diff --git a/fixtures/messages/terms-of-use-template.md b/fixtures/documents/terms-of-use.md similarity index 83% rename from fixtures/messages/terms-of-use-template.md rename to fixtures/documents/terms-of-use.md index b39bee9..396d8d6 100644 --- a/fixtures/messages/terms-of-use-template.md +++ b/fixtures/documents/terms-of-use.md @@ -1,9 +1,9 @@ --- title: User Agreement for Personal Sandbox AWS Account --- -# User Agreement for Personal Sandbox AWS Account +# {{ title }} -This User Agreement ("Agreement") governs your use of the personal AWS sandbox account ("Account") provided to you by ___corporation___. By accessing or using this Sandbox Account, you agree to be bound by this Agreement. +This User Agreement ("Agreement") governs your use of the personal AWS sandbox account ("Account") provided to you by {{ corporation }}. By accessing or using this Sandbox Account, you agree to be bound by this Agreement. ## Purpose of the Account @@ -11,13 +11,13 @@ The Account is provided to you for the purpose of accelerating innovation at ind ## Shared responsibility model -The Account is governed by a shared security model, where you are responsible for data and for cloud resources that you create or deploy on this account, and where ___corporation___ is responsible of the funding and for the blueprints and guardrails supporting cloud operations. +The Account is governed by a shared security model, where you are responsible for data and for cloud resources that you create or deploy on this account, and where {{ corporation }} is responsible of the funding and for the blueprints and guardrails supporting cloud operations. -## Responsibilities of ___corporation___ +## Responsibilities of {{ corporation }} -___corporation___ provides long-term support to employees involved in cloud innovation, by provisioning and assigning AWS accounts to these employees. ___corporation___ support costs incurred, and allow the users of these sandboxes to learn and to experiment. Learning is referring to practical interactions with AWS Console, API and SDK. This can be done with tutorials, with guided workshops, or with the deployment of existing templates or code available from trusted sources on the Internet. Experimentations is referring to small-scale integration tests or configuration tests. This can be done with some lines of code or templates, with the objective to validate an idea and to document experimentation results. +{{ corporation }} provides long-term support to employees involved in cloud innovation, by provisioning and assigning AWS accounts to these employees. {{ corporation }} support costs incurred, and allow the users of these sandboxes to learn and to experiment. Learning is referring to practical interactions with AWS Console, API and SDK. This can be done with tutorials, with guided workshops, or with the deployment of existing templates or code available from trusted sources on the Internet. Experimentations is referring to small-scale integration tests or configuration tests. This can be done with some lines of code or templates, with the objective to validate an idea and to document experimentation results. -For each sandbox account, ___corporation___ provides clear governance rules, such as: +For each sandbox account, {{ corporation }} provides clear governance rules, such as: - Level of monthly budget that you are entitled to consume on AWS platform – currently, $30 per ccount and per month @@ -31,15 +31,15 @@ For each sandbox account, ___corporation___ provides clear governance rules, suc ## Your responsibilities -You are responsible for capitalising on lessons that you have learnt while using your Account. For example, we recommend to use code to deploy cloud resources, so that automation is captured in git repositories and benefits all of ___corporation___. +You are responsible for capitalising on lessons that you have learnt while using your Account. For example, we recommend to use code to deploy cloud resources, so that automation is captured in git repositories and benefits all of {{ corporation }}. -You are responsible for all cloud resources that you deploy on the Account assigned to you, and to related data. This is meaning that you explicitly have to enforce corporate policies of ___corporation___, for example: +You are responsible for all cloud resources that you deploy on the Account assigned to you, and to related data. This is meaning that you explicitly have to enforce corporate policies of {{ corporation }}, for example: - Preserve confidentiality and security of credentials related to your Account (e.g., username and password, MFA). - Use the Account only for the intended purpose described before. -- Comply with all applicable laws, regulations, and AWS & policies of ___corporation___. +- Comply with all applicable laws, regulations, and AWS & policies of {{ corporation }}. - Notify Security & IT Ops team immediately of any unauthorized use or suspected security breach of your Account. @@ -61,8 +61,8 @@ While the Account is supporting most products and services of the AWS platform, ## Termination of the Account -___corporation___ may terminate your Account at any time for any reason without notice. You may also terminate your Account at any time by following the instructions provided by ___corporation___. +{{ corporation }} may terminate your Account at any time for any reason without notice. You may also terminate your Account at any time by following the instructions provided by {{ corporation }}. ## Limitations of Liability -___corporation___ will not be liable to you or any third party for any damages or losses arising from your use of the Account, including but not limited to direct, indirect, incidental, consequential, or punitive damages, even if ___corporation___ or AWS has been advised of the possibility of such damages. \ No newline at end of file +{{ corporation }} will not be liable to you or any third party for any damages or losses arising from your use of the Account, including but not limited to direct, indirect, incidental, consequential, or punitive damages, even if {{ corporation }} or AWS has been advised of the possibility of such damages. \ No newline at end of file