├── .env.dev.example ├── .env.example ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── pull_request_template.md └── workflows │ ├── backend.yml │ ├── frontend.yml │ └── main.yml ├── .gitignore ├── .vscode └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── backend ├── Dockerfile ├── Dockerfile.dev ├── README.md ├── api │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── auth.py │ ├── authentication │ │ └── adapters │ │ │ ├── github.py │ │ │ ├── gitlab.py │ │ │ └── google.py │ ├── config.py │ ├── content_negotiation.py │ ├── emails.py │ ├── management │ │ └── commands │ │ │ ├── purge_app_logs.py │ │ │ └── rqworker.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_organisation.py │ │ ├── 0003_organisation_owner.py │ │ ├── 0004_rename_created_on_customuser_created_at_and_more.py │ │ ├── 0005_organisation_identity_key_organisation_name.py │ │ ├── 0006_app.py │ │ ├── 0007_alter_organisation_name.py │ │ ├── 0008_app_app_seed_alter_app_app_token_and_more.py │ │ ├── 0009_alter_app_id_alter_organisation_id.py │ │ ├── 0010_alter_customuser_username.py │ │ ├── 0011_alter_app_id_alter_customuser_userid_and_more.py │ │ ├── 0012_alter_app_id_alter_customuser_userid_and_more.py │ │ ├── 0013_app_version.py │ │ ├── 0014_rename_version_app_app_version.py │ │ ├── 0015_app_deleted_at_app_is_deleted.py │ │ ├── 0016_organisation_plan.py │ │ ├── 0017_environment_secret_secrettag_secretevent_and_more.py │ │ ├── 0018_rename_environment_token_environmentsecret_name_and_more.py │ │ ├── 0019_remove_secret_user_remove_secretevent_collection_and_more.py │ │ ├── 0020_remove_organisation_owner_and_more.py │ │ ├── 0021_remove_secretevent_timestamp.py │ │ ├── 0022_secretevent_timestamp.py │ │ ├── 0023_environment_identity_key.py │ │ ├── 0024_alter_environment_wrapped_salt_and_more.py │ │ ├── 0025_rename_environmentsecret_environmenttoken_usertoken.py │ │ ├── 0026_secretfolder_color_remove_secret_tags_secret_tags.py │ │ ├── 0027_remove_secretfolder_color_secrettag_color.py │ │ ├── 0028_remove_secretevent_tags_secretevent_tags.py │ │ ├── 0029_servicetoken.py │ │ ├── 0030_usertoken_expires_at.py │ │ ├── 0031_organisationmemberinvite.py │ │ ├── 0032_organisationmemberinvite_apps.py │ │ ├── 0033_organisationmemberinvite_role.py │ │ ├── 0034_organisationmember_apps.py │ │ ├── 0035_alter_organisationmember_deleted_at.py │ │ ├── 0036_alter_organisationmember_apps.py │ │ ├── 0037_organisationmember_wrapped_recovery.py │ │ ├── 0038_secretevent_ip_address_secretevent_user_agent.py │ │ ├── 0039_personalsecret.py │ │ ├── 0040_personalsecret_isactive_alter_personalsecret_value.py │ │ ├── 0041_rename_isactive_personalsecret_is_active.py │ │ ├── 0042_serverenvironmentkey.py │ │ ├── 0043_environmentsync.py │ │ ├── 0044_environmentsync_last_sync.py │ │ ├── 0045_alter_environmentsync_service_environmentsyncevent.py │ │ ├── 0046_alter_environmentsyncevent_meta.py │ │ ├── 0047_environmentsync_status.py │ │ ├── 0048_delete_existing_syncs.py │ │ ├── 0049_alter_environmentsync_service_and_more.py │ │ ├── 0050_alter_environmentsync_status_and_more.py │ │ ├── 0051_alter_environmentsync_service_and_more.py │ │ ├── 0052_alter_environmentsync_service_and_more.py │ │ ├── 0053_alter_environmentsync_service_and_more.py │ │ ├── 0054_alter_environmentsync_service.py │ │ ├── 0055_alter_providercredentials_provider.py │ │ ├── 0056_alter_environmentsync_service.py │ │ ├── 0057_remove_secretfolder_parent_secret_path_and_more.py │ │ ├── 0058_secretevent_path.py │ │ ├── 0059_secretfolder_folder.py │ │ ├── 0060_alter_secretfolder_unique_together.py │ │ ├── 0061_environmentsync_path.py │ │ ├── 0062_secretevent_service_token.py │ │ ├── 0063_lockbox.py │ │ ├── 0064_alter_providercredentials_provider.py │ │ ├── 0065_alter_providercredentials_provider.py │ │ ├── 0066_alter_environmentsync_service.py │ │ ├── 0067_alter_providercredentials_provider.py │ │ ├── 0068_alter_environmentsync_service.py │ │ ├── 0069_activatedphaselicense.py │ │ ├── 0070_alter_providercredentials_provider.py │ │ ├── 0071_alter_environmentsync_service.py │ │ ├── 0072_alter_environment_env_type.py │ │ ├── 0073_environment_index.py │ │ ├── 0074_correct_set_index_values.py │ │ ├── 0075_organisation_stripe_customer_id_and_more.py │ │ ├── 0076_role_organisationmember_organisation_role.py │ │ ├── 0077_auto_20240910_1255.py │ │ ├── 0078_remove_organisationmember_role.py │ │ ├── 0079_rename_organisation_role_organisationmember_role.py │ │ ├── 0080_remove_organisationmemberinvite_role.py │ │ ├── 0081_alter_role_id.py │ │ ├── 0082_role_color.py │ │ ├── 0083_app_sse_enabled.py │ │ ├── 0084_auto_20241008_0708.py │ │ ├── 0085_alter_providercredentials_provider.py │ │ ├── 0085_serviceaccount_environmentkey_paths_and_more.py │ │ ├── 0086_alter_environmentsync_service.py │ │ ├── 0086_remove_servicetoken_service_account_and_more.py │ │ ├── 0087_alter_serviceaccount_apps.py │ │ ├── 0088_secretevent_service_account.py │ │ ├── 0089_alter_serviceaccounthandler_service_account.py │ │ ├── 0090_alter_serviceaccount_organisation.py │ │ ├── 0091_add_managed_manager_service_roles.py │ │ ├── 0092_secretevent_service_account_token.py │ │ ├── 0093_merge_20241116_0744.py │ │ ├── 0094_alter_app_organisation_alter_environment_app.py │ │ ├── 0095_alter_environmentsync_service.py │ │ ├── 0096_organisationmemberinvite_role.py │ │ ├── 0097_alter_secretfolder_unique_together_and_more.py │ │ ├── 0098_cleanup_duplicate_folders.py │ │ ├── 0099_remove_secretfolder_unique_secret_folder_and_more.py │ │ ├── 0100_networkaccesspolicy_and_more.py │ │ ├── 0101_networkaccesspolicy_updated_at.py │ │ ├── 0102_networkaccesspolicy_created_by_and_more.py │ │ └── __init__.py │ ├── models.py │ ├── serializers.py │ ├── services.py │ ├── tasks.py │ ├── templates │ │ ├── api │ │ │ ├── invite.html │ │ │ ├── login.html │ │ │ ├── user_joined_org.html │ │ │ └── welcome.html │ │ └── base.html │ ├── tests.py │ ├── urls.py │ ├── utils │ │ ├── access │ │ │ ├── middleware.py │ │ │ ├── permissions.py │ │ │ └── roles.py │ │ ├── audit_logging.py │ │ ├── crypto.py │ │ ├── organisations.py │ │ ├── rest.py │ │ ├── secrets.py │ │ └── syncing │ │ │ ├── auth.py │ │ │ ├── aws │ │ │ ├── auth.py │ │ │ └── secrets_manager.py │ │ │ ├── cloudflare │ │ │ ├── auth.py │ │ │ ├── pages.py │ │ │ └── workers.py │ │ │ ├── github │ │ │ └── actions.py │ │ │ ├── gitlab │ │ │ └── main.py │ │ │ ├── nomad │ │ │ └── main.py │ │ │ ├── railway │ │ │ └── main.py │ │ │ ├── secrets.py │ │ │ ├── vault │ │ │ └── main.py │ │ │ └── vercel │ │ │ └── main.py │ └── views │ │ ├── auth.py │ │ ├── graphql.py │ │ ├── kms.py │ │ ├── lockbox.py │ │ └── secrets.py ├── backend │ ├── __init__.py │ ├── api │ │ ├── kv.py │ │ └── notifier.py │ ├── asgi.py │ ├── exceptions.py │ ├── graphene │ │ ├── middleware.py │ │ ├── mutations │ │ │ ├── access.py │ │ │ ├── app.py │ │ │ ├── environment.py │ │ │ ├── lockbox.py │ │ │ ├── organisation.py │ │ │ ├── service_accounts.py │ │ │ └── syncing.py │ │ ├── queries │ │ │ ├── access.py │ │ │ ├── license.py │ │ │ ├── quotas.py │ │ │ ├── service_accounts.py │ │ │ └── syncing.py │ │ └── types.py │ ├── quotas.py │ ├── schema.py │ ├── settings.py │ ├── urls.py │ ├── utils │ │ └── secrets.py │ └── wsgi.py ├── constraints.txt ├── dev-requirements.txt ├── ee │ ├── LICENSE │ ├── access │ │ └── utils │ │ │ └── network.py │ ├── authentication │ │ └── sso │ │ │ ├── oauth │ │ │ └── github_enterprise │ │ │ │ ├── provider.py │ │ │ │ └── views.py │ │ │ └── oidc │ │ │ ├── __init__.py │ │ │ ├── entraid │ │ │ └── views.py │ │ │ └── util │ │ │ ├── __init__.py │ │ │ ├── generic │ │ │ ├── __init__.py │ │ │ ├── provider.py │ │ │ └── views.py │ │ │ ├── google │ │ │ ├── __init__.py │ │ │ ├── urls.py │ │ │ └── views.py │ │ │ └── jumpcloud │ │ │ ├── urls.py │ │ │ └── views.py │ ├── billing │ │ ├── graphene │ │ │ ├── mutations │ │ │ │ └── stripe.py │ │ │ ├── queries │ │ │ │ └── stripe.py │ │ │ └── types.py │ │ ├── stripe.py │ │ └── webhooks │ │ │ └── stripe.py │ └── licensing │ │ ├── jobs.py │ │ ├── utils.py │ │ └── verifier.py ├── logs │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── dynamodb_models.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_alter_kmslog_timestamp.py │ │ ├── 0003_alter_kmslog_id.py │ │ ├── 0004_rename_kmslog_kmsdblog.py │ │ ├── 0005_delete_kmslog.py │ │ ├── 0006_initial.py │ │ ├── 0007_alter_kmsdblog_asn_alter_kmsdblog_city_and_more.py │ │ ├── 0008_alter_kmsdblog_id.py │ │ └── __init__.py │ ├── models.py │ ├── queries.py │ ├── tests.py │ └── views.py ├── manage.py ├── requirements.txt ├── scripts │ └── start.sh ├── tests │ ├── __init__.py │ ├── conftest.py │ └── utils │ │ ├── syncing │ │ └── test_github_actions.py │ │ └── test_secret.py └── version.txt ├── dev-docker-compose.yml ├── docker-compose.yml ├── frontend ├── .eslintrc.json ├── .prettierrc.js ├── .vscode │ └── settings.json ├── @types │ └── gql.d.ts ├── Dockerfile ├── Dockerfile.dev ├── README.md ├── apollo │ ├── client.ts │ ├── fragment-masking.ts │ ├── gql.ts │ ├── graphql.ts │ ├── index.ts │ └── schema.graphql ├── app │ ├── [team] │ │ ├── access │ │ │ ├── authentication │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ ├── members │ │ │ │ ├── [memberId] │ │ │ │ │ └── page.tsx │ │ │ │ ├── _components │ │ │ │ │ ├── AddAppToMemberButton.tsx │ │ │ │ │ ├── DeleteMemberConfirmDialog.tsx │ │ │ │ │ ├── DeleteUserTokenDialog.tsx │ │ │ │ │ ├── InviteDialog.tsx │ │ │ │ │ └── RoleSelector.tsx │ │ │ │ └── page.tsx │ │ │ ├── network │ │ │ │ ├── _components │ │ │ │ │ ├── CreateNetworkPolicyDialog.tsx │ │ │ │ │ ├── DeleteNetworkPolicyDialog.tsx │ │ │ │ │ ├── IPChip.tsx │ │ │ │ │ ├── ManageOrgGlobalPolicies.tsx │ │ │ │ │ └── UpdateNetworkPolicyDialog.tsx │ │ │ │ └── page.tsx │ │ │ ├── roles │ │ │ │ └── page.tsx │ │ │ └── service-accounts │ │ │ │ ├── [account] │ │ │ │ ├── _components │ │ │ │ │ ├── AddAppsToServiceAccountsButton.tsx │ │ │ │ │ ├── CreateServiceAccountTokenDialog.tsx │ │ │ │ │ └── DeleteServiceAccountTokenDialog.tsx │ │ │ │ └── page.tsx │ │ │ │ ├── _components │ │ │ │ ├── CreateServiceAccountDialog.tsx │ │ │ │ ├── DeleteServiceAccountDialog.tsx │ │ │ │ └── RoleSelector.tsx │ │ │ │ └── page.tsx │ │ ├── apps │ │ │ ├── [app] │ │ │ │ ├── _components │ │ │ │ │ ├── AppEnvironments.tsx │ │ │ │ │ ├── AppSecretRow.tsx │ │ │ │ │ ├── AppSecrets.tsx │ │ │ │ │ └── SecretInfoLegend.tsx │ │ │ │ ├── _hooks │ │ │ │ │ └── useAppSecrets.ts │ │ │ │ ├── access │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── members │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── service-accounts │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── tokens │ │ │ │ │ │ └── page.tsx │ │ │ │ ├── environments │ │ │ │ │ └── [environment] │ │ │ │ │ │ └── [[...path]] │ │ │ │ │ │ └── page.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── logs │ │ │ │ │ └── page.tsx │ │ │ │ ├── page.tsx │ │ │ │ ├── settings │ │ │ │ │ └── page.tsx │ │ │ │ ├── syncing │ │ │ │ │ └── page.tsx │ │ │ │ └── types.ts │ │ │ ├── _components │ │ │ │ └── AppSortMenu.tsx │ │ │ └── page.tsx │ │ ├── integrations │ │ │ ├── credentials │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ └── syncs │ │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ ├── page.tsx │ │ ├── recovery │ │ │ └── page.tsx │ │ └── settings │ │ │ └── page.tsx │ ├── error.tsx │ ├── globals.css │ ├── invite │ │ └── [invite] │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ ├── ip-restricted │ │ └── page.tsx │ ├── layout.tsx │ ├── loading.tsx │ ├── lockbox │ │ └── [boxId] │ │ │ ├── error.tsx │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ ├── login │ │ └── page.tsx │ ├── page.tsx │ ├── providers.tsx │ ├── signup │ │ ├── head.tsx │ │ ├── layout.tsx │ │ └── page.tsx │ └── webauth │ │ └── [requestCode] │ │ └── page.tsx ├── codegen.ts ├── components │ ├── LoginButton.tsx │ ├── ReleaseInfo.tsx │ ├── UserMenu.tsx │ ├── VersionLabel.tsx │ ├── access │ │ ├── AccessTemplateSelector.tsx │ │ ├── CreateRoleDialog.tsx │ │ ├── DeleteRoleDialog.tsx │ │ ├── ManageRoleDialog.tsx │ │ ├── NetworkAccessPolicyForm.tsx │ │ ├── PermissionToggle.tsx │ │ └── UpdateAccountNetworkPolicies.tsx │ ├── apps │ │ ├── AppActivityChart.tsx │ │ ├── AppCard.tsx │ │ ├── AppCardSkeleton.tsx │ │ ├── AppsHomeCard.tsx │ │ ├── AppsView.tsx │ │ ├── DeleteAppDialog.tsx │ │ ├── EnableSSEDialog.tsx │ │ ├── EncryptionModeIndicator.tsx │ │ ├── NewAppDialog.tsx │ │ └── tokens │ │ │ ├── CreateServiceTokenDialog.tsx │ │ │ ├── CreateUserTokenDialog.tsx │ │ │ └── SecretTokens.tsx │ ├── auth │ │ ├── SignInButtons.tsx │ │ └── UnlockKeyringDialog.tsx │ ├── common │ │ ├── Accordion.tsx │ │ ├── Alert.tsx │ │ ├── Avatar.tsx │ │ ├── Button.tsx │ │ ├── Card.tsx │ │ ├── ColorPicker.tsx │ │ ├── CommandPalette.tsx │ │ ├── CopyButton.tsx │ │ ├── EmptyState.tsx │ │ ├── GenericDialog.tsx │ │ ├── GridPattern.tsx │ │ ├── HeroPattern.tsx │ │ ├── Input.tsx │ │ ├── LogoMark.tsx │ │ ├── LogoWordMark.tsx │ │ ├── ModeToggle.tsx │ │ ├── ProgressBar.tsx │ │ ├── Spinner.tsx │ │ ├── SplitButton.tsx │ │ ├── StatusIndicator.tsx │ │ ├── TextArea.tsx │ │ ├── Toast.tsx │ │ ├── ToggleSwitch.tsx │ │ └── logos │ │ │ ├── EntraIDLogo.tsx │ │ │ └── JumpCloudLogo.tsx │ ├── contextSnippets │ │ ├── ProgrammaticAccessMenu.tsx │ │ └── SecretsOneLiner.tsx │ ├── dashboard │ │ ├── CliCommand.tsx │ │ ├── CliInstallCommands.tsx │ │ └── GetStarted.tsx │ ├── environments │ │ ├── CreateEnvironmentDialog.tsx │ │ ├── ManageEnvironmentDialog.tsx │ │ ├── Tag.tsx │ │ ├── folders │ │ │ ├── DeleteDialog.tsx │ │ │ └── SecretFolderRow.tsx │ │ └── secrets │ │ │ ├── CommentDialog.tsx │ │ │ ├── DeleteDialog.tsx │ │ │ ├── DeployPreview.tsx │ │ │ ├── HistoryDialog.tsx │ │ │ ├── OverrideDialog.tsx │ │ │ ├── SecretPropertyDiffs.tsx │ │ │ ├── SecretRow.tsx │ │ │ ├── ShareSecretDialog.tsx │ │ │ ├── SortMenu.tsx │ │ │ ├── TagsDialog.tsx │ │ │ └── import │ │ │ ├── EnvFileDropZone.tsx │ │ │ ├── MultiEnvImportDialog.tsx │ │ │ └── SingleEnvImportDialog.tsx │ ├── forms │ │ └── UpgradeRequestForm.tsx │ ├── icons │ │ ├── BellIcon.jsx │ │ ├── BoltIcon.jsx │ │ ├── BookIcon.jsx │ │ ├── CalendarIcon.jsx │ │ ├── CartIcon.jsx │ │ ├── ChatBubbleIcon.jsx │ │ ├── CheckIcon.jsx │ │ ├── ChevronRightLeftIcon.jsx │ │ ├── ClipboardIcon.jsx │ │ ├── CogIcon.jsx │ │ ├── CopyIcon.jsx │ │ ├── DocumentIcon.jsx │ │ ├── EnvelopeIcon.jsx │ │ ├── FaceSmileIcon.jsx │ │ ├── FolderIcon.jsx │ │ ├── LinkIcon.jsx │ │ ├── ListIcon.jsx │ │ ├── MagnifyingGlassIcon.jsx │ │ ├── MapPinIcon.jsx │ │ ├── PackageIcon.jsx │ │ ├── PaperAirplaneIcon.jsx │ │ ├── PaperClipIcon.jsx │ │ ├── ShapesIcon.jsx │ │ ├── ShirtIcon.jsx │ │ ├── SquaresPlusIcon.jsx │ │ ├── TagIcon.jsx │ │ ├── UserIcon.jsx │ │ └── UsersIcon.jsx │ ├── layout │ │ ├── Navbar.tsx │ │ ├── OnboardingNavbar.tsx │ │ └── Sidebar.tsx │ ├── lockbox │ │ └── LockboxViewer.tsx │ ├── logs │ │ ├── KmsLogs.tsx │ │ └── SecretLogs.tsx │ ├── onboarding │ │ ├── AccountPassword.tsx │ │ ├── AccountRecovery.tsx │ │ ├── AccountSeedChecker.tsx │ │ ├── Stepper.tsx │ │ └── TeamName.tsx │ ├── settings │ │ ├── account │ │ │ ├── TrustedDeviceManager.tsx │ │ │ └── ViewRecoveryDialog.tsx │ │ └── organisation │ │ │ ├── PlanInfo.tsx │ │ │ ├── PlanLabel.tsx │ │ │ └── UpsellDialog.tsx │ ├── syncing │ │ ├── AWS │ │ │ ├── AWSRegionPicker.tsx │ │ │ └── CreateAWSSecretsSync.tsx │ │ ├── Cloudflare │ │ │ ├── CreateCloudflarePagesSync.tsx │ │ │ └── CreateCloudflareWorkersSync.tsx │ │ ├── CreateProviderCredentials.tsx │ │ ├── CreateProviderCredentialsDialog.tsx │ │ ├── CreateSyncDialog.tsx │ │ ├── DeleteProviderCredentialDialog.tsx │ │ ├── DeleteSyncDialog.tsx │ │ ├── EnvSyncStatus.tsx │ │ ├── GitHub │ │ │ ├── CreateGhActionsSync.tsx │ │ │ └── SetupGhAuth.tsx │ │ ├── GitLab │ │ │ └── CreateGitLabCISync.tsx │ │ ├── IntegrationsHomeCard.tsx │ │ ├── ManageSyncDialog.tsx │ │ ├── Nomad │ │ │ └── CreateNomadSync.tsx │ │ ├── ProviderCredentialCard.tsx │ │ ├── ProviderCredentialPicker.tsx │ │ ├── ProviderIcon.tsx │ │ ├── Railway │ │ │ └── CreateRailwaySync.tsx │ │ ├── ServiceInfo.tsx │ │ ├── SyncCard.tsx │ │ ├── SyncHistory.tsx │ │ ├── SyncManagement.tsx │ │ ├── SyncOptions.tsx │ │ ├── SyncStatusIndicator.tsx │ │ ├── UpdateProviderCredentials.tsx │ │ ├── Vault │ │ │ └── CreateVaultSync.tsx │ │ └── Vercel │ │ │ └── CreateVercelSync.tsx │ └── users │ │ ├── MembersHomeCard.tsx │ │ └── RoleLabel.tsx ├── constants │ └── index.ts ├── contexts │ ├── keyringContext.tsx │ ├── organisationContext.tsx │ ├── sidebarContext.tsx │ └── themeContext.tsx ├── ee │ ├── LICENSE │ ├── authentication │ │ └── sso │ │ │ └── oidc │ │ │ └── util │ │ │ ├── entraidProvider.ts │ │ │ ├── genericOIDCProvider.ts │ │ │ └── githubEnterpriseProvider.ts │ └── billing │ │ ├── AddPaymentMethodForm.tsx │ │ ├── License.tsx │ │ ├── ModifySubscriptionDialog.tsx │ │ ├── PostCheckoutScreen.tsx │ │ ├── StripeBillingInfo.tsx │ │ └── UpgradeDialog.tsx ├── graphql │ ├── mutations │ │ ├── access │ │ │ ├── createNetworkAccessPolicy.gql │ │ │ ├── createRole.gql │ │ │ ├── deleteNetworkAccessPolicy.gql │ │ │ ├── deleteRole.gql │ │ │ ├── updateAccountNetworkPolicies.gql │ │ │ ├── updateNetworkAccessPolicy.gql │ │ │ └── updateRole.gql │ │ ├── apps │ │ │ ├── addAppMember.gql │ │ │ ├── removeAppMember.gql │ │ │ ├── updateAppName.gql │ │ │ └── updateEnvScope.gql │ │ ├── billing │ │ │ ├── cancelProSubscription.gql │ │ │ ├── createStripeSetupIntent.gql │ │ │ ├── deletePaymentMethod.gql │ │ │ ├── initUpgradeCheckout.gql │ │ │ ├── modifySubscription.gql │ │ │ ├── resumeProSubscription.gql │ │ │ └── setDefaultPaymentMethod.gql │ │ ├── createApp.gql │ │ ├── createOrganisation.gql │ │ ├── deleteApp.gql │ │ ├── environments │ │ │ ├── bulkProcessSecrets.gql │ │ │ ├── createEnvironment.gql │ │ │ ├── createEnvironmentKey.gql │ │ │ ├── createEnvironmentToken.gql │ │ │ ├── createFolder.gql │ │ │ ├── createPersonalSecret.gql │ │ │ ├── createSecret.gql │ │ │ ├── createSecretTag.gql │ │ │ ├── createServiceToken.gql │ │ │ ├── deleteEnvironment.gql │ │ │ ├── deleteFolder.gql │ │ │ ├── deleteSecret.gql │ │ │ ├── deleteServiceToken.gql │ │ │ ├── editSecret.gql │ │ │ ├── initAppEnvironments.gql │ │ │ ├── readSecret.gql │ │ │ ├── removePersonalSecret.gql │ │ │ ├── renameEnvironment.gql │ │ │ ├── shareSecret.gql │ │ │ └── swapEnvironmentOrder.gql │ │ ├── organisation │ │ │ ├── acceptInvite.gql │ │ │ ├── deleteInvite.gql │ │ │ ├── deleteOrgMember.gql │ │ │ ├── inviteNewMember.gql │ │ │ ├── updateOrgMemberRole.gql │ │ │ └── updateUserWrappedSecrets.gql │ │ ├── rotateAppKeys.gql │ │ ├── service-accounts │ │ │ ├── createServiceAccount.gql │ │ │ ├── createServiceAccountToken.gql │ │ │ ├── deleteServiceAccount.gql │ │ │ ├── deleteServiceAccountToken.gql │ │ │ ├── updateHandlerKeys.gql │ │ │ └── updateServiceAccount.gql │ │ ├── syncing │ │ │ ├── aws │ │ │ │ └── CreateAwsSecretsSync.gql │ │ │ ├── cloudflare │ │ │ │ ├── CreateCfPagesSync.gql │ │ │ │ └── CreateCfWorkersSync.gql │ │ │ ├── deleteProviderCredentials.gql │ │ │ ├── deleteSync.gql │ │ │ ├── github │ │ │ │ └── CreateGhActionsSync.gql │ │ │ ├── gitlab │ │ │ │ └── createGitlabCISync.gql │ │ │ ├── initAppSync.gql │ │ │ ├── nomad │ │ │ │ └── createNomadSync.gql │ │ │ ├── railway │ │ │ │ └── createRailwayEnvironmentSync.gql │ │ │ ├── saveNewProviderCreds.gql │ │ │ ├── toggleSync.gql │ │ │ ├── triggerSync.gql │ │ │ ├── updateProviderCreds.gql │ │ │ ├── updateSyncAuthentication.gql │ │ │ ├── vault │ │ │ │ └── createVaultSync.gql │ │ │ └── vercel │ │ │ │ └── createVercelSync.gql │ │ └── users │ │ │ ├── createUserToken.gql │ │ │ └── deleteUserToken.gql │ └── queries │ │ ├── access │ │ ├── getClientIp.gql │ │ └── getNetworkPolicies.gql │ │ ├── apps │ │ ├── getAppAccounts.gql │ │ ├── getAppMembers.gql │ │ └── getAppServiceAccounts.gql │ │ ├── billing │ │ ├── getCheckoutDetails.gql │ │ └── getSubscriptionDetails.gql │ │ ├── getAppActivityChart.gql │ │ ├── getAppDetail.gql │ │ ├── getAppKmsLogs.gql │ │ ├── getApps.gql │ │ ├── getDashboard.gql │ │ ├── getOrganisations.gql │ │ ├── organisation │ │ ├── checkOrgNameAvailable.gql │ │ ├── getGlobalAccessUsers.gql │ │ ├── getInvites.gql │ │ ├── getLicense.gql │ │ ├── getOrganisationLicense.gql │ │ ├── getOrganisationMembers.gql │ │ ├── getOrganisationPlan.gql │ │ ├── getRoles.gql │ │ └── validateOrganisationInvite.gql │ │ ├── secrets │ │ ├── getAppEnvironments.gql │ │ ├── getAppSecrets.gql │ │ ├── getAppSecretsLogs.gql │ │ ├── getEnvironmentKey.gql │ │ ├── getEnvironmentTokens.gql │ │ ├── getFolders.gql │ │ ├── getSecretHistory.gql │ │ ├── getSecretKVs.gql │ │ ├── getSecretTags.gql │ │ ├── getSecrets.gql │ │ └── getServiceTokens.gql │ │ ├── service-accounts │ │ ├── getServiceAccountDetail.gql │ │ ├── getServiceAccountHandlers.gql │ │ └── getServiceAccounts.gql │ │ ├── syncing │ │ ├── GetOrgSyncs.gql │ │ ├── aws │ │ │ └── getSecrets.gql │ │ ├── cloudflare │ │ │ ├── getPages.gql │ │ │ └── getWorkers.gql │ │ ├── getAppSyncStatus.gql │ │ ├── getProviders.gql │ │ ├── getSavedCredentials.gql │ │ ├── getServerKey.gql │ │ ├── getServices.gql │ │ ├── github │ │ │ └── getRepos.gql │ │ ├── gitlab │ │ │ └── getResources.gql │ │ ├── nomad │ │ │ └── testAuth.gql │ │ ├── railway │ │ │ └── getProjects.gql │ │ ├── vault │ │ │ └── testAuth.gql │ │ └── vercel │ │ │ └── getProject.gql │ │ └── users │ │ └── getUserTokens.gql ├── hooks │ └── warnUnsavedChanges.ts ├── jest.config.js ├── middleware.ts ├── next.config.js ├── package-lock.json ├── package.json ├── pages │ └── api │ │ ├── auth │ │ └── [...nextauth].ts │ │ └── health.ts ├── postcss.config.js ├── public │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── assets │ │ └── images │ │ │ ├── logo.png │ │ │ └── logo.svg │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ └── favicon.svg ├── scripts │ ├── replace-variable.sh │ └── start.sh ├── tailwind.config.js ├── tests │ └── utils │ │ ├── crypto │ │ ├── app.test.ts │ │ ├── environments.test.ts │ │ ├── general.test.ts │ │ ├── secretSharding.test.ts │ │ └── users.test.ts │ │ ├── dataUnits.test.ts │ │ ├── recoveryKit.test.ts │ │ └── secretConfig.test.ts ├── tsconfig.json ├── utils │ ├── access │ │ ├── ip.ts │ │ └── permissions.ts │ ├── app.ts │ ├── appConfig.ts │ ├── auth.ts │ ├── clipboard.ts │ ├── contextSnippets.ts │ ├── copy.ts │ ├── crypto │ │ ├── app.ts │ │ ├── constants.ts │ │ ├── environments.ts │ │ ├── general.ts │ │ ├── index.ts │ │ ├── keyshares.ts │ │ ├── lockbox.ts │ │ ├── service-accounts.ts │ │ ├── types.ts │ │ └── users.ts │ ├── dataUnits.ts │ ├── environment.ts │ ├── localStorage.ts │ ├── lockbox.ts │ ├── logoAnimation.css │ ├── logo_b64.ts │ ├── meta.ts │ ├── posthog.ts │ ├── recovery.ts │ ├── secretConfig.ts │ ├── secrets.ts │ ├── syncing │ │ ├── aws.ts │ │ └── general.ts │ ├── tags.ts │ ├── time.ts │ ├── tokens.ts │ └── typography.js └── yarn.lock ├── img ├── aws.svg ├── azure.svg ├── console-ui.mp4 ├── console-ui.webp ├── do.svg ├── docker.svg ├── gcp.svg ├── kubernetes.svg ├── members.png ├── phase-cli-import-run.webp ├── phase-console-secrets.webp ├── phase-console-wordmark-dark.png ├── phase-lattice-logo.svg ├── secrets-overview.png ├── wordmark-dark.svg └── wordmark-light.svg ├── nginx ├── Dockerfile └── default.conf └── staging-docker-compose.yml /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: bug 6 | assignees: "" 7 | --- 8 | 9 | ### Describe the bug 10 | 11 | A clear and concise description of what the bug is. 12 | 13 | ### To Reproduce 14 | 15 | Steps to reproduce the behavior: 16 | 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | ### Expected behavior 23 | 24 | A clear and concise description of what you expected to happen. 25 | 26 | ### Screenshots 27 | 28 | If applicable, add screenshots to help explain your problem. 29 | 30 | ### Platform you are having the issue on: 31 | 32 | ### Additional context 33 | 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a feature for Phase 4 | labels: enhancement, feature 5 | 6 | --- 7 | 8 | ## Is your feature request related to a problem? 9 | 10 | *Please describe.* 11 | 12 | ## Describe the solution you'd like 13 | 14 | 15 | 16 | ## Describe alternatives you've considered 17 | 18 | 19 | 20 | ## Additional context 21 | 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported versions 4 | 5 | We always recommend using the latest version of the Phase Console to ensure you get all security updates. 6 | 7 | ## Reporting vulnerabilities 8 | 9 | Please do not file GitHub issues or post on our public forum for security vulnerabilities, as they are public! 10 | 11 | Phase takes security issues very seriously. If you have any concerns about Phase or believe you have uncovered a vulnerability, please get in touch via the e-mail address `security@phase.dev`. You can see our [security.txt](https://phase.dev/.well-known/security.txt) for GPG keys and to communicate securely with us. In the message, try to provide a description of the issue and ideally a way of reproducing it. The security team will get back to you as soon as possible. 12 | 13 | Note that this security address should be used only for undisclosed vulnerabilities. Please report any security problems to us before disclosing it publicly. 14 | -------------------------------------------------------------------------------- /backend/Dockerfile.dev: -------------------------------------------------------------------------------- 1 | FROM python:3.12.1-alpine3.19@sha256:28230397c48cf4e2619822beb834ae7e46ebcd255b8f7cef58eff932fd75d2ce 2 | 3 | ENV PYTHONUNBUFFERED 1 4 | 5 | WORKDIR /app 6 | 7 | # Install dependencies 8 | RUN apk update && apk add --no-cache \ 9 | postgresql-dev \ 10 | build-base \ 11 | gcc \ 12 | musl-dev \ 13 | jpeg-dev \ 14 | zlib-dev \ 15 | libffi-dev \ 16 | cairo-dev \ 17 | pango-dev \ 18 | gdk-pixbuf-dev \ 19 | mariadb-dev \ 20 | python3-dev 21 | 22 | COPY requirements.txt /app/requirements.txt 23 | 24 | # Install Python dependencies 25 | RUN pip install --upgrade pip && \ 26 | pip install -r requirements.txt 27 | 28 | COPY . /app 29 | 30 | EXPOSE 8000 31 | 32 | CMD sh -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000" 33 | -------------------------------------------------------------------------------- /backend/README.md: -------------------------------------------------------------------------------- 1 | # Phase Console - Backend 2 | 3 | Django + Graphene + DRF 4 | 5 | ### Generate graphql schema for frontend 6 | 7 | ```bash 8 | ./manage.py graphql_schema --schema backend.schema.schema --out ../frontend/apollo/schema.graphql 9 | ``` 10 | -------------------------------------------------------------------------------- /backend/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/backend/api/__init__.py -------------------------------------------------------------------------------- /backend/api/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from api.models import Organisation 3 | 4 | admin.site.register(Organisation) 5 | -------------------------------------------------------------------------------- /backend/api/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ApiConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'api' 7 | -------------------------------------------------------------------------------- /backend/api/config.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from django.apps import AppConfig 3 | from django.conf import settings 4 | from django.db.models.signals import post_migrate 5 | 6 | 7 | class APIConfig(AppConfig): 8 | name = "api" 9 | 10 | def ready(self): 11 | # Connect the post_migrate signal to a custom handler 12 | post_migrate.connect(self.validate_licenses_post_migrate, sender=self) 13 | 14 | def validate_licenses_post_migrate(self, **kwargs): 15 | 16 | CLOUD_HOSTED = settings.APP_HOST == "cloud" 17 | 18 | if not CLOUD_HOSTED: 19 | from ee.licensing.utils import activate_license 20 | from ee.licensing.jobs import init_license_checker 21 | 22 | init_license_checker() 23 | 24 | if settings.PHASE_LICENSE: 25 | try: 26 | activate_license(settings.PHASE_LICENSE) 27 | except Exception as e: 28 | logging.exception("Failed to activate license: %s", e) 29 | -------------------------------------------------------------------------------- /backend/api/content_negotiation.py: -------------------------------------------------------------------------------- 1 | from rest_framework.negotiation import DefaultContentNegotiation 2 | 3 | from djangorestframework_camel_case.render import ( 4 | CamelCaseJSONRenderer, 5 | ) 6 | 7 | 8 | class CamelCaseContentNegotiation(DefaultContentNegotiation): 9 | def select_renderer(self, request, renderers, format_suffix=None): 10 | 11 | # If the request has the custom header, prefer CamelCaseJSONRenderer 12 | if request.headers.get("X-Use-Camel-Case") == "true": 13 | for renderer in renderers: 14 | if isinstance(renderer, CamelCaseJSONRenderer): 15 | return renderer, renderer.media_type 16 | 17 | # Otherwise, fall back to default DRF behavior 18 | return super().select_renderer(request, renderers, format_suffix) 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0002_organisation.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.7 on 2023-03-08 07:54 2 | 3 | from django.db import migrations, models 4 | import uuid 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Organisation', 16 | fields=[ 17 | ('id', models.CharField(default=uuid.uuid4, editable=False, max_length=16, primary_key=True, serialize=False)), 18 | ], 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /backend/api/migrations/0003_organisation_owner.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.7 on 2023-03-08 07:57 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('api', '0002_organisation'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='organisation', 17 | name='owner', 18 | field=models.ForeignKey(default=' ', on_delete=django.db.models.deletion.CASCADE, related_name='organisation', to=settings.AUTH_USER_MODEL), 19 | preserve_default=False, 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /backend/api/migrations/0004_rename_created_on_customuser_created_at_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.7 on 2023-03-08 08:01 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0003_organisation_owner'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='customuser', 15 | old_name='created_on', 16 | new_name='created_at', 17 | ), 18 | migrations.AddField( 19 | model_name='organisation', 20 | name='created_at', 21 | field=models.DateTimeField(auto_now_add=True, null=True), 22 | ), 23 | migrations.AddField( 24 | model_name='organisation', 25 | name='updated_at', 26 | field=models.DateTimeField(auto_now=True), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /backend/api/migrations/0005_organisation_identity_key_organisation_name.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.7 on 2023-03-08 08:12 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0004_rename_created_on_customuser_created_at_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='organisation', 15 | name='identity_key', 16 | field=models.CharField(default=' ', max_length=256), 17 | preserve_default=False, 18 | ), 19 | migrations.AddField( 20 | model_name='organisation', 21 | name='name', 22 | field=models.CharField(default=' ', max_length=64), 23 | preserve_default=False, 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /backend/api/migrations/0006_app.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.7 on 2023-03-16 11:26 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | import uuid 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('api', '0005_organisation_identity_key_organisation_name'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='App', 17 | fields=[ 18 | ('id', models.CharField(default=uuid.uuid4, editable=False, max_length=16, primary_key=True, serialize=False)), 19 | ('name', models.CharField(max_length=64)), 20 | ('identity_key', models.CharField(max_length=256)), 21 | ('app_token', models.CharField(max_length=256)), 22 | ('wrapped_key_share', models.CharField(max_length=256)), 23 | ('created_at', models.DateTimeField(auto_now_add=True, null=True)), 24 | ('updated_at', models.DateTimeField(auto_now=True)), 25 | ('organisation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.organisation')), 26 | ], 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /backend/api/migrations/0007_alter_organisation_name.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.7 on 2023-03-20 15:18 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0006_app'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='organisation', 15 | name='name', 16 | field=models.CharField(max_length=64, unique=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0008_app_app_seed_alter_app_app_token_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.7 on 2023-03-24 08:52 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0007_alter_organisation_name'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='app', 15 | name='app_seed', 16 | field=models.CharField(default='', max_length=208), 17 | preserve_default=False, 18 | ), 19 | migrations.AlterField( 20 | model_name='app', 21 | name='app_token', 22 | field=models.CharField(max_length=64), 23 | ), 24 | migrations.AlterField( 25 | model_name='app', 26 | name='wrapped_key_share', 27 | field=models.CharField(max_length=406), 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /backend/api/migrations/0009_alter_app_id_alter_organisation_id.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.7 on 2023-03-25 06:51 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0008_app_app_seed_alter_app_app_token_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='app', 15 | name='id', 16 | field=models.CharField(editable=False, max_length=16, primary_key=True, serialize=False), 17 | ), 18 | migrations.AlterField( 19 | model_name='organisation', 20 | name='id', 21 | field=models.CharField(editable=False, max_length=16, primary_key=True, serialize=False), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /backend/api/migrations/0010_alter_customuser_username.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.7 on 2023-03-25 08:28 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0009_alter_app_id_alter_organisation_id'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='customuser', 15 | name='username', 16 | field=models.CharField(max_length=64, unique=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0011_alter_app_id_alter_customuser_userid_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.7 on 2023-03-25 08:40 2 | 3 | from django.db import migrations, models 4 | import uuid 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0010_alter_customuser_username'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='app', 16 | name='id', 17 | field=models.CharField(editable=False, max_length=32, primary_key=True, serialize=False), 18 | ), 19 | migrations.AlterField( 20 | model_name='customuser', 21 | name='userId', 22 | field=models.CharField(default=uuid.uuid4, editable=False, max_length=32, primary_key=True, serialize=False), 23 | ), 24 | migrations.AlterField( 25 | model_name='organisation', 26 | name='id', 27 | field=models.CharField(editable=False, max_length=32, primary_key=True, serialize=False), 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /backend/api/migrations/0012_alter_app_id_alter_customuser_userid_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.1.7 on 2023-03-25 08:45 2 | 3 | from django.db import migrations, models 4 | import uuid 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0011_alter_app_id_alter_customuser_userid_and_more'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='app', 16 | name='id', 17 | field=models.TextField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False), 18 | ), 19 | migrations.AlterField( 20 | model_name='customuser', 21 | name='userId', 22 | field=models.TextField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False), 23 | ), 24 | migrations.AlterField( 25 | model_name='organisation', 26 | name='id', 27 | field=models.TextField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False), 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /backend/api/migrations/0013_app_version.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2 on 2023-04-21 10:24 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0012_alter_app_id_alter_customuser_userid_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='app', 15 | name='version', 16 | field=models.IntegerField(default=1), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0014_rename_version_app_app_version.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2 on 2023-04-21 10:58 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0013_app_version'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='app', 15 | old_name='version', 16 | new_name='app_version', 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0015_app_deleted_at_app_is_deleted.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2 on 2023-04-23 14:26 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0014_rename_version_app_app_version'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='app', 15 | name='deleted_at', 16 | field=models.DateTimeField(blank=True, null=True), 17 | ), 18 | migrations.AddField( 19 | model_name='app', 20 | name='is_deleted', 21 | field=models.BooleanField(default=False), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /backend/api/migrations/0016_organisation_plan.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2 on 2023-04-23 15:37 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0015_app_deleted_at_app_is_deleted'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='organisation', 15 | name='plan', 16 | field=models.CharField(choices=[('FR', 'Free'), ('PR', 'Pro'), ('EN', 'Enterprise')], default='FR', max_length=2), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0019_remove_secret_user_remove_secretevent_collection_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-08-02 07:03 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0018_rename_environment_token_environmentsecret_name_and_more'), 11 | ] 12 | 13 | operations = [ 14 | migrations.RemoveField( 15 | model_name='secret', 16 | name='user', 17 | ), 18 | migrations.RemoveField( 19 | model_name='secretevent', 20 | name='collection', 21 | ), 22 | migrations.AddField( 23 | model_name='secretevent', 24 | name='folder', 25 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='api.secretfolder'), 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /backend/api/migrations/0021_remove_secretevent_timestamp.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-08-04 09:42 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0020_remove_organisation_owner_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='secretevent', 15 | name='timestamp', 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /backend/api/migrations/0022_secretevent_timestamp.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-08-04 09:54 2 | 3 | from django.db import migrations, models 4 | import django.utils.timezone 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0021_remove_secretevent_timestamp'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='secretevent', 16 | name='timestamp', 17 | field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), 18 | preserve_default=False, 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /backend/api/migrations/0023_environment_identity_key.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-08-09 13:23 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0022_secretevent_timestamp'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='environment', 15 | name='identity_key', 16 | field=models.CharField(default='', max_length=256), 17 | preserve_default=False, 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /backend/api/migrations/0024_alter_environment_wrapped_salt_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-08-12 09:16 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0023_environment_identity_key'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environment', 15 | name='wrapped_salt', 16 | field=models.CharField(max_length=256), 17 | ), 18 | migrations.AlterField( 19 | model_name='environment', 20 | name='wrapped_seed', 21 | field=models.CharField(max_length=256), 22 | ), 23 | migrations.AlterField( 24 | model_name='environmentkey', 25 | name='wrapped_salt', 26 | field=models.CharField(max_length=256), 27 | ), 28 | migrations.AlterField( 29 | model_name='environmentkey', 30 | name='wrapped_seed', 31 | field=models.CharField(max_length=256), 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /backend/api/migrations/0026_secretfolder_color_remove_secret_tags_secret_tags.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-08-29 08:21 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0025_rename_environmentsecret_environmenttoken_usertoken'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='secretfolder', 15 | name='color', 16 | field=models.CharField(default='', max_length=64), 17 | preserve_default=False, 18 | ), 19 | migrations.RemoveField( 20 | model_name='secret', 21 | name='tags', 22 | ), 23 | migrations.AddField( 24 | model_name='secret', 25 | name='tags', 26 | field=models.ManyToManyField(to='api.secrettag'), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /backend/api/migrations/0027_remove_secretfolder_color_secrettag_color.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-08-29 08:35 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0026_secretfolder_color_remove_secret_tags_secret_tags'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='secretfolder', 15 | name='color', 16 | ), 17 | migrations.AddField( 18 | model_name='secrettag', 19 | name='color', 20 | field=models.CharField(default='', max_length=64), 21 | preserve_default=False, 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /backend/api/migrations/0028_remove_secretevent_tags_secretevent_tags.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-08-29 08:42 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0027_remove_secretfolder_color_secrettag_color'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='secretevent', 15 | name='tags', 16 | ), 17 | migrations.AddField( 18 | model_name='secretevent', 19 | name='tags', 20 | field=models.ManyToManyField(to='api.secrettag'), 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /backend/api/migrations/0030_usertoken_expires_at.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-09-09 09:08 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0029_servicetoken'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='usertoken', 15 | name='expires_at', 16 | field=models.DateTimeField(null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0032_organisationmemberinvite_apps.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-09-12 13:04 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0031_organisationmemberinvite'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='organisationmemberinvite', 15 | name='apps', 16 | field=models.ManyToManyField(to='api.app'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0033_organisationmemberinvite_role.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-09-14 08:29 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0032_organisationmemberinvite_apps'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='organisationmemberinvite', 15 | name='role', 16 | field=models.CharField(choices=[('owner', 'Owner'), ('admin', 'Admin'), ('dev', 'Developer')], default='dev', max_length=5), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0034_organisationmember_apps.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-09-15 13:19 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | def set_org_member_apps(apps, schema_editor): 7 | OrgMemberModel = apps.get_model('api', 'OrganisationMember') 8 | AppModel = apps.get_model('api', 'App') 9 | 10 | for org_member in OrgMemberModel.objects.all(): 11 | org_apps = AppModel.objects.filter( 12 | organisation=org_member.organisation, is_deleted=False) 13 | org_member.apps.set(org_apps) 14 | 15 | 16 | class Migration(migrations.Migration): 17 | 18 | dependencies = [ 19 | ('api', '0033_organisationmemberinvite_role'), 20 | ] 21 | 22 | operations = [ 23 | migrations.AddField( 24 | model_name='organisationmember', 25 | name='apps', 26 | field=models.ManyToManyField(to='api.app'), 27 | ), 28 | migrations.RunPython(set_org_member_apps) 29 | ] 30 | -------------------------------------------------------------------------------- /backend/api/migrations/0035_alter_organisationmember_deleted_at.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-09-16 08:50 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | def reset_deleted_field(apps, schema_editor): 7 | OrgMemberModel = apps.get_model('api', 'OrganisationMember') 8 | 9 | for org_member in OrgMemberModel.objects.all(): 10 | org_member.deleted_at = None 11 | org_member.save() 12 | 13 | 14 | class Migration(migrations.Migration): 15 | 16 | dependencies = [ 17 | ('api', '0034_organisationmember_apps'), 18 | ] 19 | 20 | operations = [ 21 | migrations.AlterField( 22 | model_name='organisationmember', 23 | name='deleted_at', 24 | field=models.DateTimeField(blank=True, null=True), 25 | ), 26 | migrations.RunPython(reset_deleted_field) 27 | ] 28 | -------------------------------------------------------------------------------- /backend/api/migrations/0036_alter_organisationmember_apps.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-09-20 06:43 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0035_alter_organisationmember_deleted_at'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='organisationmember', 15 | name='apps', 16 | field=models.ManyToManyField(related_name='members', to='api.app'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0037_organisationmember_wrapped_recovery.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-09-27 08:01 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0036_alter_organisationmember_apps'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='organisationmember', 15 | name='wrapped_recovery', 16 | field=models.TextField(blank=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0038_secretevent_ip_address_secretevent_user_agent.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-10-05 15:31 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0037_organisationmember_wrapped_recovery'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='secretevent', 15 | name='ip_address', 16 | field=models.GenericIPAddressField(blank=True, null=True), 17 | ), 18 | migrations.AddField( 19 | model_name='secretevent', 20 | name='user_agent', 21 | field=models.TextField(blank=True, null=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /backend/api/migrations/0039_personalsecret.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-11-14 06:58 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | import uuid 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('api', '0038_secretevent_ip_address_secretevent_user_agent'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='PersonalSecret', 17 | fields=[ 18 | ('id', models.TextField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), 19 | ('value', models.TextField()), 20 | ('created_at', models.DateTimeField(auto_now_add=True, null=True)), 21 | ('updated_at', models.DateTimeField(auto_now=True)), 22 | ('deleted_at', models.DateTimeField(blank=True, null=True)), 23 | ('secret', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.secret')), 24 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.organisationmember')), 25 | ], 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /backend/api/migrations/0040_personalsecret_isactive_alter_personalsecret_value.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-11-16 05:46 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0039_personalsecret'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='personalsecret', 15 | name='isActive', 16 | field=models.BooleanField(default=True), 17 | ), 18 | migrations.AlterField( 19 | model_name='personalsecret', 20 | name='value', 21 | field=models.TextField(blank=True, null=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /backend/api/migrations/0041_rename_isactive_personalsecret_is_active.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.3 on 2023-11-16 05:53 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0040_personalsecret_isactive_alter_personalsecret_value'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='personalsecret', 15 | old_name='isActive', 16 | new_name='is_active', 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0042_serverenvironmentkey.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2023-11-22 08:22 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | import uuid 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('api', '0041_rename_isactive_personalsecret_is_active'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='ServerEnvironmentKey', 17 | fields=[ 18 | ('id', models.TextField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), 19 | ('identity_key', models.CharField(max_length=256)), 20 | ('wrapped_seed', models.CharField(max_length=256)), 21 | ('wrapped_salt', models.CharField(max_length=256)), 22 | ('created_at', models.DateTimeField(auto_now_add=True, null=True)), 23 | ('updated_at', models.DateTimeField(auto_now=True)), 24 | ('deleted_at', models.DateTimeField(blank=True, null=True)), 25 | ('environment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.environment')), 26 | ], 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /backend/api/migrations/0044_environmentsync_last_sync.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2023-11-29 07:03 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0043_environmentsync'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='environmentsync', 15 | name='last_sync', 16 | field=models.DateTimeField(blank=True, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0046_alter_environmentsyncevent_meta.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2023-11-30 09:14 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0045_alter_environmentsync_service_environmentsyncevent'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsyncevent', 15 | name='meta', 16 | field=models.JSONField(null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0047_environmentsync_status.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2023-12-01 14:19 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0046_alter_environmentsyncevent_meta'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='environmentsync', 15 | name='status', 16 | field=models.CharField(choices=[('in_progress', 'In progress'), ('completed', 'Completed'), ('failed', 'Failed')], default='in_progress', max_length=16), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0048_delete_existing_syncs.py: -------------------------------------------------------------------------------- 1 | from django.db import migrations, models 2 | 3 | 4 | def delete_existing_syncs(apps, schema_editor): 5 | EnvironmentSync = apps.get_model("api", "EnvironmentSync") 6 | # This will delete all rows in EnvironmentSync 7 | EnvironmentSync.objects.all().delete() 8 | 9 | 10 | class Migration(migrations.Migration): 11 | dependencies = [ 12 | ("api", "0047_environmentsync_status"), 13 | ] 14 | 15 | operations = [ 16 | migrations.RunPython(delete_existing_syncs), 17 | ] 18 | -------------------------------------------------------------------------------- /backend/api/migrations/0050_alter_environmentsync_status_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2023-12-27 09:36 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0049_alter_environmentsync_service_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsync', 15 | name='status', 16 | field=models.CharField(choices=[('in_progress', 'In progress'), ('completed', 'Completed'), ('cancelled', 'cancelled'), ('timed_out', 'Timed out'), ('failed', 'Failed')], default='in_progress', max_length=16), 17 | ), 18 | migrations.AlterField( 19 | model_name='environmentsyncevent', 20 | name='status', 21 | field=models.CharField(choices=[('in_progress', 'In progress'), ('completed', 'Completed'), ('cancelled', 'cancelled'), ('timed_out', 'Timed out'), ('failed', 'Failed')], default='in_progress', max_length=16), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /backend/api/migrations/0051_alter_environmentsync_service_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-01-02 14:46 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0050_alter_environmentsync_status_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsync', 15 | name='service', 16 | field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('cloudflare_workers', 'Cloudflare Workers')], max_length=50), 17 | ), 18 | migrations.AlterField( 19 | model_name='providercredentials', 20 | name='provider', 21 | field=models.CharField(choices=[('cloudflare', 'Cloudflare')], max_length=50), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /backend/api/migrations/0052_alter_environmentsync_service_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-01-05 06:24 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0051_alter_environmentsync_service_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsync', 15 | name='service', 16 | field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('cloudflare_workers', 'Cloudflare Workers'), ('aws_secrets_manager', 'AWS Secrets Manager')], max_length=50), 17 | ), 18 | migrations.AlterField( 19 | model_name='providercredentials', 20 | name='provider', 21 | field=models.CharField(choices=[('cloudflare', 'Cloudflare'), ('aws', 'AWS')], max_length=50), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /backend/api/migrations/0053_alter_environmentsync_service_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-01-09 08:30 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0052_alter_environmentsync_service_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsync', 15 | name='service', 16 | field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('cloudflare_workers', 'Cloudflare Workers'), ('aws_secrets_manager', 'AWS Secrets Manager'), ('gh_actions', 'GitHub Actions')], max_length=50), 17 | ), 18 | migrations.AlterField( 19 | model_name='providercredentials', 20 | name='provider', 21 | field=models.CharField(choices=[('cloudflare', 'Cloudflare'), ('aws', 'AWS'), ('github', 'GitHub')], max_length=50), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /backend/api/migrations/0054_alter_environmentsync_service.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-01-09 13:33 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0053_alter_environmentsync_service_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsync', 15 | name='service', 16 | field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('cloudflare_workers', 'Cloudflare Workers'), ('aws_secrets_manager', 'AWS Secrets Manager'), ('github_actions', 'GitHub Actions')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0055_alter_providercredentials_provider.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-01-11 09:28 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0054_alter_environmentsync_service'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='providercredentials', 15 | name='provider', 16 | field=models.CharField(choices=[('cloudflare', 'Cloudflare'), ('aws', 'AWS'), ('github', 'GitHub'), ('hashicorp_vault', 'Hashicorp Vault')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0056_alter_environmentsync_service.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-01-11 09:50 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0055_alter_providercredentials_provider'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsync', 15 | name='service', 16 | field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('cloudflare_workers', 'Cloudflare Workers'), ('aws_secrets_manager', 'AWS Secrets Manager'), ('github_actions', 'GitHub Actions'), ('hashicorp_vault', 'Hashicorp Vault')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0057_remove_secretfolder_parent_secret_path_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-02-10 07:58 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0056_alter_environmentsync_service'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='secretfolder', 15 | name='parent', 16 | ), 17 | migrations.AddField( 18 | model_name='secret', 19 | name='path', 20 | field=models.TextField(default='/'), 21 | ), 22 | migrations.AddField( 23 | model_name='secretfolder', 24 | name='path', 25 | field=models.TextField(default='/'), 26 | ), 27 | migrations.AlterField( 28 | model_name='environmentsync', 29 | name='service', 30 | field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('aws_secrets_manager', 'AWS Secrets Manager'), ('github_actions', 'GitHub Actions'), ('hashicorp_vault', 'Hashicorp Vault')], max_length=50), 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /backend/api/migrations/0058_secretevent_path.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-02-10 09:03 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0057_remove_secretfolder_parent_secret_path_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='secretevent', 15 | name='path', 16 | field=models.TextField(default='/'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0059_secretfolder_folder.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-02-13 08:22 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0058_secretevent_path'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='secretfolder', 16 | name='folder', 17 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='api.secretfolder'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /backend/api/migrations/0060_alter_secretfolder_unique_together.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-02-13 14:14 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0059_secretfolder_folder'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterUniqueTogether( 14 | name='secretfolder', 15 | unique_together={('environment', 'folder', 'name', 'path')}, 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /backend/api/migrations/0061_environmentsync_path.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-02-14 04:26 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0060_alter_secretfolder_unique_together'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='environmentsync', 15 | name='path', 16 | field=models.TextField(default='/'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0062_secretevent_service_token.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-02-16 10:23 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0061_environmentsync_path'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='secretevent', 16 | name='service_token', 17 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='api.servicetoken'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /backend/api/migrations/0063_lockbox.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-03-06 08:29 2 | 3 | from django.db import migrations, models 4 | import uuid 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0062_secretevent_service_token'), 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Lockbox', 16 | fields=[ 17 | ('id', models.TextField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), 18 | ('data', models.JSONField()), 19 | ('views', models.IntegerField(default=0)), 20 | ('created_at', models.DateTimeField(auto_now_add=True, null=True)), 21 | ('expires_at', models.DateTimeField(null=True)), 22 | ('allowed_views', models.IntegerField(null=True)), 23 | ], 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /backend/api/migrations/0064_alter_providercredentials_provider.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-05-13 09:16 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0063_lockbox'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='providercredentials', 15 | name='provider', 16 | field=models.CharField(choices=[('cloudflare', 'Cloudflare'), ('aws', 'AWS'), ('github', 'GitHub'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_domad', 'Hashicorp Nomad')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0065_alter_providercredentials_provider.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-05-13 09:19 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0064_alter_providercredentials_provider'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='providercredentials', 15 | name='provider', 16 | field=models.CharField(choices=[('cloudflare', 'Cloudflare'), ('aws', 'AWS'), ('github', 'GitHub'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_nomad', 'Hashicorp Nomad')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0066_alter_environmentsync_service.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-05-13 12:09 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0065_alter_providercredentials_provider'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsync', 15 | name='service', 16 | field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('aws_secrets_manager', 'AWS Secrets Manager'), ('github_actions', 'GitHub Actions'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_nomad', 'Hashicorp Nomad')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0067_alter_providercredentials_provider.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-05-21 07:55 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0066_alter_environmentsync_service'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='providercredentials', 15 | name='provider', 16 | field=models.CharField(choices=[('cloudflare', 'Cloudflare'), ('aws', 'AWS'), ('github', 'GitHub'), ('gitlab', 'GitLab'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_nomad', 'Hashicorp Nomad')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0068_alter_environmentsync_service.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-05-22 09:59 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0067_alter_providercredentials_provider'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsync', 15 | name='service', 16 | field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('aws_secrets_manager', 'AWS Secrets Manager'), ('github_actions', 'GitHub Actions'), ('gitlab_ci', 'GitLab CI'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_nomad', 'Hashicorp Nomad')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0070_alter_providercredentials_provider.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-07-16 07:05 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0069_activatedphaselicense'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='providercredentials', 15 | name='provider', 16 | field=models.CharField(choices=[('cloudflare', 'Cloudflare'), ('aws', 'AWS'), ('github', 'GitHub'), ('gitlab', 'GitLab'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_nomad', 'Hashicorp Nomad'), ('railway', 'Railway')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0071_alter_environmentsync_service.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-07-16 07:09 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0070_alter_providercredentials_provider'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsync', 15 | name='service', 16 | field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('aws_secrets_manager', 'AWS Secrets Manager'), ('github_actions', 'GitHub Actions'), ('gitlab_ci', 'GitLab CI'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_nomad', 'Hashicorp Nomad'), ('railway', 'Railway')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0072_alter_environment_env_type.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-07-23 05:40 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0071_alter_environmentsync_service'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environment', 15 | name='env_type', 16 | field=models.CharField(choices=[('dev', 'Development'), ('staging', 'Staging'), ('prod', 'Production'), ('custom', 'Custom')], default='dev', max_length=7), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0073_environment_index.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-07-23 12:17 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | def set_index_values(apps, schema_editor): 7 | Environment = apps.get_model("api", "Environment") 8 | for env in Environment.objects.all(): 9 | if env.env_type == "dev": 10 | env.index = 0 11 | elif env.env_type == "staging": 12 | env.index = 1 13 | elif env.env_type == "prod": 14 | env.index = 2 15 | env.save() 16 | 17 | 18 | class Migration(migrations.Migration): 19 | 20 | dependencies = [ 21 | ("api", "0072_alter_environment_env_type"), 22 | ] 23 | 24 | operations = [ 25 | migrations.AddField( 26 | model_name="environment", 27 | name="index", 28 | field=models.IntegerField(default=0), 29 | ), 30 | migrations.RunPython(set_index_values), 31 | ] 32 | -------------------------------------------------------------------------------- /backend/api/migrations/0074_correct_set_index_values.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-07-25 16:10 2 | from django.db import migrations 3 | 4 | 5 | def correct_set_index_values(apps, schema_editor): 6 | Environment = apps.get_model("api", "Environment") 7 | for env in Environment.objects.all(): 8 | if env.env_type.lower() == "dev": 9 | env.index = 0 10 | elif env.env_type.lower() == "staging": 11 | env.index = 1 12 | elif env.env_type.lower() == "prod": 13 | env.index = 2 14 | env.save() 15 | 16 | 17 | class Migration(migrations.Migration): 18 | 19 | dependencies = [ 20 | ("api", "0073_environment_index"), 21 | ] 22 | 23 | operations = [ 24 | migrations.RunPython(correct_set_index_values), 25 | ] 26 | -------------------------------------------------------------------------------- /backend/api/migrations/0075_organisation_stripe_customer_id_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.7 on 2024-07-30 10:08 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0074_correct_set_index_values'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='organisation', 15 | name='stripe_customer_id', 16 | field=models.CharField(blank=True, max_length=255, null=True), 17 | ), 18 | migrations.AddField( 19 | model_name='organisation', 20 | name='stripe_subscription_id', 21 | field=models.CharField(blank=True, max_length=255, null=True), 22 | ), 23 | migrations.AlterField( 24 | model_name='activatedphaselicense', 25 | name='seats', 26 | field=models.IntegerField(null=True), 27 | ), 28 | migrations.AlterField( 29 | model_name='activatedphaselicense', 30 | name='tokens', 31 | field=models.IntegerField(null=True), 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /backend/api/migrations/0078_remove_organisationmember_role.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-09-10 12:59 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0077_auto_20240910_1255'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='organisationmember', 15 | name='role', 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /backend/api/migrations/0079_rename_organisation_role_organisationmember_role.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-09-10 13:16 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0078_remove_organisationmember_role'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='organisationmember', 15 | old_name='organisation_role', 16 | new_name='role', 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0080_remove_organisationmemberinvite_role.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-09-11 15:44 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0079_rename_organisation_role_organisationmember_role'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='organisationmemberinvite', 15 | name='role', 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /backend/api/migrations/0081_alter_role_id.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-09-12 08:22 2 | 3 | from django.db import migrations, models 4 | import uuid 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0080_remove_organisationmemberinvite_role'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='role', 16 | name='id', 17 | field=models.TextField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /backend/api/migrations/0082_role_color.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-09-21 08:17 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0081_alter_role_id'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='role', 15 | name='color', 16 | field=models.CharField(blank=True, default='', max_length=7), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0083_app_sse_enabled.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-10-08 07:08 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0082_role_color'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='app', 15 | name='sse_enabled', 16 | field=models.BooleanField(default=False), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0084_auto_20241008_0708.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-10-08 07:08 2 | 3 | from django.db import migrations, models 4 | from django.conf import settings 5 | 6 | 7 | def set_sse_enabled(apps, schema_editor): 8 | App = apps.get_model("api", "App") 9 | Environment = apps.get_model("api", "Environment") 10 | ServerEnvironmentKey = apps.get_model("api", "ServerEnvironmentKey") 11 | 12 | apps = App.objects.all() 13 | for app in apps: 14 | app_envs = Environment.objects.filter(app=app).values_list("id") 15 | sse_enabled = ServerEnvironmentKey.objects.filter( 16 | environment_id__in=app_envs 17 | ).exists() 18 | app.sse_enabled = sse_enabled 19 | app.save() 20 | 21 | 22 | class Migration(migrations.Migration): 23 | 24 | dependencies = [ 25 | ("api", "0083_app_sse_enabled"), 26 | ] 27 | 28 | operations = [ 29 | migrations.RunPython(set_sse_enabled), 30 | ] 31 | -------------------------------------------------------------------------------- /backend/api/migrations/0085_alter_providercredentials_provider.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-11-11 14:31 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0084_auto_20241008_0708'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='providercredentials', 15 | name='provider', 16 | field=models.CharField(choices=[('cloudflare', 'Cloudflare'), ('aws', 'AWS'), ('github', 'GitHub'), ('gitlab', 'GitLab'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_nomad', 'Hashicorp Nomad'), ('railway', 'Railway'), ('vercel', 'Vercel')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0086_alter_environmentsync_service.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-11-11 14:36 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0085_alter_providercredentials_provider'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsync', 15 | name='service', 16 | field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('aws_secrets_manager', 'AWS Secrets Manager'), ('github_actions', 'GitHub Actions'), ('gitlab_ci', 'GitLab CI'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_nomad', 'Hashicorp Nomad'), ('railway', 'Railway'), ('vercel', 'Vercel')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0087_alter_serviceaccount_apps.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-10-24 12:31 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0086_remove_servicetoken_service_account_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='serviceaccount', 15 | name='apps', 16 | field=models.ManyToManyField(related_name='service_accounts', to='api.app'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0088_secretevent_service_account.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-10-28 08:43 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0087_alter_serviceaccount_apps'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='secretevent', 16 | name='service_account', 17 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='api.serviceaccount'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /backend/api/migrations/0089_alter_serviceaccounthandler_service_account.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-10-30 07:10 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0088_secretevent_service_account'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='serviceaccounthandler', 16 | name='service_account', 17 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='handlers', to='api.serviceaccount'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /backend/api/migrations/0090_alter_serviceaccount_organisation.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-10-30 07:11 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0089_alter_serviceaccounthandler_service_account'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='serviceaccount', 16 | name='organisation', 17 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='service_accounts', to='api.organisation'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /backend/api/migrations/0091_add_managed_manager_service_roles.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-11-04 08:36 2 | 3 | from django.db import migrations 4 | from api.utils.access.roles import default_roles 5 | 6 | 7 | def add_default_roles(apps, schema_editor): 8 | Organisation = apps.get_model("api", "Organisation") 9 | Role = apps.get_model("api", "Role") 10 | OrganisationMember = apps.get_model("api", "OrganisationMember") 11 | 12 | # Create default roles for each organisation 13 | for organisation in Organisation.objects.all(): 14 | for role_name, _ in default_roles.items(): 15 | Role.objects.get_or_create( 16 | name=role_name, 17 | organisation=organisation, 18 | is_default=True, 19 | ) 20 | 21 | 22 | class Migration(migrations.Migration): 23 | 24 | dependencies = [ 25 | ("api", "0090_alter_serviceaccount_organisation"), 26 | ] 27 | 28 | operations = [ 29 | migrations.RunPython(add_default_roles), 30 | ] 31 | -------------------------------------------------------------------------------- /backend/api/migrations/0092_secretevent_service_account_token.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-11-13 14:47 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0091_add_managed_manager_service_roles'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='secretevent', 16 | name='service_account_token', 17 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='api.serviceaccounttoken'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /backend/api/migrations/0093_merge_20241116_0744.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2024-11-16 07:44 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0086_alter_environmentsync_service'), 10 | ('api', '0092_secretevent_service_account_token'), 11 | ] 12 | 13 | operations = [ 14 | ] 15 | -------------------------------------------------------------------------------- /backend/api/migrations/0094_alter_app_organisation_alter_environment_app.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2025-01-25 08:18 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0093_merge_20241116_0744'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='app', 16 | name='organisation', 17 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='apps', to='api.organisation'), 18 | ), 19 | migrations.AlterField( 20 | model_name='environment', 21 | name='app', 22 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='environments', to='api.app'), 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /backend/api/migrations/0095_alter_environmentsync_service.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.15 on 2025-02-15 10:03 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0094_alter_app_organisation_alter_environment_app'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='environmentsync', 15 | name='service', 16 | field=models.CharField(choices=[('cloudflare_pages', 'Cloudflare Pages'), ('cloudflare_workers', 'Cloudflare Workers'), ('aws_secrets_manager', 'AWS Secrets Manager'), ('github_actions', 'GitHub Actions'), ('gitlab_ci', 'GitLab CI'), ('hashicorp_vault', 'Hashicorp Vault'), ('hashicorp_nomad', 'Hashicorp Nomad'), ('railway', 'Railway'), ('vercel', 'Vercel')], max_length=50), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0096_organisationmemberinvite_role.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.16 on 2025-03-14 14:46 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0095_alter_environmentsync_service'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='organisationmemberinvite', 16 | name='role', 17 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='api.role'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /backend/api/migrations/0097_alter_secretfolder_unique_together_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.16 on 2025-04-02 08:15 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ("api", "0096_organisationmemberinvite_role"), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterUniqueTogether( 14 | name="secretfolder", 15 | unique_together=set(), 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /backend/api/migrations/0099_remove_secretfolder_unique_secret_folder_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.16 on 2025-04-02 08:48 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ("api", "0098_cleanup_duplicate_folders"), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddConstraint( 14 | model_name="secretfolder", 15 | constraint=models.UniqueConstraint( 16 | condition=models.Q(("folder__isnull", False)), 17 | fields=("environment", "folder", "name", "path"), 18 | name="unique_secret_folder", 19 | ), 20 | ), 21 | migrations.AddConstraint( 22 | model_name="secretfolder", 23 | constraint=models.UniqueConstraint( 24 | condition=models.Q(("folder__isnull", True)), 25 | fields=("environment", "name", "path"), 26 | name="unique_root_folder", 27 | ), 28 | ), 29 | ] 30 | -------------------------------------------------------------------------------- /backend/api/migrations/0101_networkaccesspolicy_updated_at.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.16 on 2025-04-27 09:31 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('api', '0100_networkaccesspolicy_and_more'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='networkaccesspolicy', 15 | name='updated_at', 16 | field=models.DateTimeField(auto_now=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/api/migrations/0102_networkaccesspolicy_created_by_and_more.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2.16 on 2025-04-28 10:14 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('api', '0101_networkaccesspolicy_updated_at'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='networkaccesspolicy', 16 | name='created_by', 17 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='network_policies_created', to='api.organisationmember'), 18 | ), 19 | migrations.AddField( 20 | model_name='networkaccesspolicy', 21 | name='updated_by', 22 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='network_policies_updated', to='api.organisationmember'), 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /backend/api/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/backend/api/migrations/__init__.py -------------------------------------------------------------------------------- /backend/api/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /backend/api/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, include 2 | from .views.auth import ( 3 | GitHubEnterpriseLoginView, 4 | GoogleLoginView, 5 | GitHubLoginView, 6 | GitLabLoginView, 7 | OIDCLoginView, 8 | JumpCloudLoginView, 9 | EntraIDLoginView, 10 | ) 11 | 12 | urlpatterns = [ 13 | path("google/", GoogleLoginView.as_view(), name="google"), 14 | path("github/", GitHubLoginView.as_view(), name="github"), 15 | path( 16 | "github-enterprise/", 17 | GitHubEnterpriseLoginView.as_view(), 18 | name="github-enterprise", 19 | ), 20 | path("gitlab/", GitLabLoginView.as_view(), name="gitlab"), 21 | path("google-oidc/", OIDCLoginView.as_view(), name="google-oidc"), 22 | path("jumpcloud-oidc/", JumpCloudLoginView.as_view(), name="jumpcloud-oidc"), 23 | path("entra-id-oidc/", EntraIDLoginView.as_view(), name="microsoft"), 24 | ] 25 | -------------------------------------------------------------------------------- /backend/api/utils/organisations.py: -------------------------------------------------------------------------------- 1 | from api.models import OrganisationMember, OrganisationMemberInvite, ServiceAccount 2 | from django.utils import timezone 3 | 4 | 5 | def get_organisation_seats(organisation): 6 | seats = ( 7 | OrganisationMember.objects.filter( 8 | organisation=organisation, deleted_at=None 9 | ).count() 10 | + OrganisationMemberInvite.objects.filter( 11 | organisation=organisation, valid=True, expires_at__gte=timezone.now() 12 | ).count() 13 | + ServiceAccount.objects.filter( 14 | organisation=organisation, deleted_at=None 15 | ).count() 16 | ) 17 | 18 | return seats 19 | -------------------------------------------------------------------------------- /backend/api/utils/syncing/aws/auth.py: -------------------------------------------------------------------------------- 1 | from api.utils.crypto import decrypt_asymmetric, get_server_keypair 2 | import boto3 3 | 4 | 5 | def get_client(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, region): 6 | session = boto3.Session( 7 | aws_access_key_id=AWS_ACCESS_KEY_ID, 8 | aws_secret_access_key=AWS_SECRET_ACCESS_KEY, 9 | region_name=region, 10 | ) 11 | return session.client("secretsmanager") 12 | 13 | 14 | def get_aws_secrets_manager_credentials(environment_sync): 15 | pk, sk = get_server_keypair() 16 | 17 | access_key_id = decrypt_asymmetric( 18 | environment_sync.authentication.credentials["access_key_id"], sk.hex(), pk.hex() 19 | ) 20 | secret_access_key = decrypt_asymmetric( 21 | environment_sync.authentication.credentials["secret_access_key"], 22 | sk.hex(), 23 | pk.hex(), 24 | ) 25 | region = decrypt_asymmetric( 26 | environment_sync.authentication.credentials["region"], sk.hex(), pk.hex() 27 | ) 28 | 29 | return { 30 | "access_key_id": access_key_id, 31 | "secret_access_key": secret_access_key, 32 | "region": region, 33 | } 34 | -------------------------------------------------------------------------------- /backend/api/utils/syncing/cloudflare/auth.py: -------------------------------------------------------------------------------- 1 | CLOUDFLARE_API_BASE_URL = "https://api.cloudflare.com/client/v4" 2 | 3 | 4 | # A function to create headers for Cloudflare API requests. 5 | def get_cloudflare_headers(ACCESS_TOKEN): 6 | """Prepare headers for Cloudflare API requests.""" 7 | return { 8 | "Authorization": f"Bearer {ACCESS_TOKEN}", 9 | "Content-Type": "application/json", 10 | } 11 | -------------------------------------------------------------------------------- /backend/api/views/graphql.py: -------------------------------------------------------------------------------- 1 | from graphene_django.views import GraphQLView 2 | from django.contrib.auth.mixins import LoginRequiredMixin 3 | 4 | 5 | class PrivateGraphQLView(LoginRequiredMixin, GraphQLView): 6 | raise_exception = True 7 | pass 8 | -------------------------------------------------------------------------------- /backend/backend/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/backend/backend/__init__.py -------------------------------------------------------------------------------- /backend/backend/api/notifier.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from django.conf import settings 3 | 4 | 5 | def notify_slack(message): 6 | url = settings.SLACK_WEBHOOK_URI 7 | 8 | headers = { 9 | "Content-Type": "application/json", 10 | } 11 | 12 | payload = { 13 | "text": message 14 | } 15 | 16 | response = requests.request("POST", url, headers=headers, json=payload) 17 | 18 | if response.status_code == 200: 19 | return True 20 | print('Error pushing notification to Slack:', response) 21 | return False 22 | -------------------------------------------------------------------------------- /backend/backend/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for backend project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /backend/backend/graphene/mutations/lockbox.py: -------------------------------------------------------------------------------- 1 | from api.models import Lockbox 2 | from backend.graphene.types import LockboxType 3 | import graphene 4 | from datetime import datetime 5 | 6 | 7 | class LockboxInput(graphene.InputObjectType): 8 | data = graphene.JSONString() 9 | allowed_views = graphene.Int() 10 | expiry = graphene.BigInt(required=False) 11 | 12 | 13 | class CreateLockboxMutation(graphene.Mutation): 14 | class Arguments: 15 | input = LockboxInput(LockboxInput) 16 | 17 | lockbox = graphene.Field(LockboxType) 18 | 19 | @classmethod 20 | def mutate(cls, root, info, input): 21 | if input.expiry is not None: 22 | expires_at = datetime.fromtimestamp(input.expiry / 1000) 23 | else: 24 | expires_at = None 25 | 26 | lockbox = Lockbox.objects.create( 27 | data=input.data, expires_at=expires_at, allowed_views=input.allowed_views 28 | ) 29 | 30 | return CreateLockboxMutation(lockbox=lockbox) 31 | -------------------------------------------------------------------------------- /backend/backend/graphene/queries/license.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from api.models import ActivatedPhaseLicense 3 | from graphql import GraphQLError 4 | from api.utils.access.permissions import user_is_org_member 5 | 6 | 7 | def resolve_license(root, info): 8 | return settings.PHASE_LICENSE 9 | 10 | 11 | def resolve_organisation_license(root, info, organisation_id): 12 | if not user_is_org_member(info.context.user.userId, organisation_id): 13 | raise GraphQLError("You don't have access to this organisation") 14 | 15 | return ( 16 | ActivatedPhaseLicense.objects.filter(organisation__id=organisation_id) 17 | .order_by("-activated_at") 18 | .first() 19 | ) 20 | -------------------------------------------------------------------------------- /backend/backend/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for backend project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /backend/constraints.txt: -------------------------------------------------------------------------------- 1 | setuptools<72 2 | -------------------------------------------------------------------------------- /backend/dev-requirements.txt: -------------------------------------------------------------------------------- 1 | pytest==8.3.4 -------------------------------------------------------------------------------- /backend/ee/access/utils/network.py: -------------------------------------------------------------------------------- 1 | from ipaddress import ip_address, ip_network 2 | 3 | 4 | def ip_in_range(ip: str, cidr: str) -> bool: 5 | try: 6 | return ip_address(ip) in ip_network(cidr, strict=False) 7 | except ValueError: 8 | return False 9 | 10 | 11 | def is_ip_allowed(ip, policies): 12 | client_ip = ip_address(ip) 13 | 14 | for policy in policies: 15 | for allowed in policy.get_ip_list(): 16 | try: 17 | if "/" in allowed: 18 | if client_ip in ip_network(allowed, strict=False): 19 | return True 20 | elif client_ip == ip_address(allowed): 21 | return True 22 | except ValueError: 23 | continue # skip invalid IPs 24 | 25 | return False 26 | -------------------------------------------------------------------------------- /backend/ee/authentication/sso/oauth/github_enterprise/provider.py: -------------------------------------------------------------------------------- 1 | from allauth.socialaccount.providers.github.provider import GitHubProvider 2 | 3 | 4 | class GitHubEnterpriseProvider(GitHubProvider): 5 | id = "github-enterprise" 6 | name = "GitHub Enterprise" 7 | -------------------------------------------------------------------------------- /backend/ee/authentication/sso/oidc/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = "ee.authentication.sso.oidc.apps.OIDCProviderConfig" 2 | -------------------------------------------------------------------------------- /backend/ee/authentication/sso/oidc/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/backend/ee/authentication/sso/oidc/util/__init__.py -------------------------------------------------------------------------------- /backend/ee/authentication/sso/oidc/util/generic/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/backend/ee/authentication/sso/oidc/util/generic/__init__.py -------------------------------------------------------------------------------- /backend/ee/authentication/sso/oidc/util/generic/provider.py: -------------------------------------------------------------------------------- 1 | from allauth.socialaccount.providers.base import ProviderAccount 2 | from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider 3 | 4 | class OpenIDConnectAccount(ProviderAccount): 5 | def get_avatar_url(self): 6 | return self.account.extra_data.get('picture') 7 | 8 | def to_str(self): 9 | return self.account.extra_data.get('name', 10 | super(OpenIDConnectAccount, self).to_str()) 11 | 12 | class GenericOpenIDConnectProvider(OAuth2Provider): 13 | account_class = OpenIDConnectAccount 14 | 15 | def extract_uid(self, data): 16 | return str(data['sub']) 17 | 18 | def extract_common_fields(self, data): 19 | return { 20 | 'email': data.get('email'), 21 | 'username': data.get('email'), 22 | 'display_name': data.get('name'), 23 | } 24 | -------------------------------------------------------------------------------- /backend/ee/authentication/sso/oidc/util/google/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/backend/ee/authentication/sso/oidc/util/google/__init__.py -------------------------------------------------------------------------------- /backend/ee/authentication/sso/oidc/util/google/urls.py: -------------------------------------------------------------------------------- 1 | from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns 2 | 3 | from .views import GoogleOpenIDConnectProvider 4 | 5 | 6 | urlpatterns = default_urlpatterns(GoogleOpenIDConnectProvider) 7 | -------------------------------------------------------------------------------- /backend/ee/authentication/sso/oidc/util/jumpcloud/urls.py: -------------------------------------------------------------------------------- 1 | from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns 2 | 3 | from .views import JumpCloudOpenIDConnectProvider 4 | 5 | 6 | urlpatterns = default_urlpatterns(JumpCloudOpenIDConnectProvider) 7 | -------------------------------------------------------------------------------- /backend/ee/billing/graphene/types.py: -------------------------------------------------------------------------------- 1 | from graphene import Enum 2 | 3 | 4 | class PlanTypeEnum(Enum): 5 | PRO = "pro" 6 | ENTERPRISE = "enterprise" 7 | 8 | 9 | class BillingPeriodEnum(Enum): 10 | MONTHLY = "monthly" 11 | YEARLY = "yearly" 12 | -------------------------------------------------------------------------------- /backend/ee/licensing/jobs.py: -------------------------------------------------------------------------------- 1 | from .utils import check_existing_licenses 2 | import django_rq 3 | from datetime import timedelta 4 | from django.utils import timezone 5 | 6 | 7 | def init_license_checker(): 8 | interval = 60 * 60 * 24 # 24 hours 9 | scheduler = django_rq.get_scheduler("scheduled-jobs") 10 | 11 | scheduler.schedule( 12 | scheduled_time=timezone.now() 13 | + timedelta(seconds=15), # Time for first execution 14 | func=check_existing_licenses, 15 | interval=interval, # Run every 60 seconds 16 | repeat=None, # None means repeat indefinitely 17 | result_ttl=interval 18 | + 60, # TTL needs to be greater than the interval to make sure the next run is queued, so we add 60 seconds to the interval 19 | ) 20 | -------------------------------------------------------------------------------- /backend/logs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/backend/logs/__init__.py -------------------------------------------------------------------------------- /backend/logs/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | #admin.site.register(KMSLog) 4 | -------------------------------------------------------------------------------- /backend/logs/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class LogsConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'logs' 7 | -------------------------------------------------------------------------------- /backend/logs/migrations/0002_alter_kmslog_timestamp.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2 on 2023-04-08 10:43 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('logs', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='kmslog', 15 | name='timestamp', 16 | field=models.BigIntegerField(), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/logs/migrations/0003_alter_kmslog_id.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2 on 2023-04-08 10:47 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('logs', '0002_alter_kmslog_timestamp'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='kmslog', 15 | name='id', 16 | field=models.CharField(editable=False, max_length=36, primary_key=True, serialize=False), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/logs/migrations/0004_rename_kmslog_kmsdblog.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2 on 2023-06-06 06:33 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('logs', '0003_alter_kmslog_id'), 10 | ] 11 | 12 | operations = [ 13 | # migrations.RenameModel( 14 | # old_name='KMSLog', 15 | # new_name='KMSDBLog', 16 | # ), 17 | ] 18 | -------------------------------------------------------------------------------- /backend/logs/migrations/0005_delete_kmslog.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2 on 2023-06-06 06:42 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('logs', '0004_rename_kmslog_kmsdblog'), 10 | ] 11 | 12 | operations = [ 13 | migrations.DeleteModel( 14 | name='KMSLog', 15 | ), 16 | ] 17 | -------------------------------------------------------------------------------- /backend/logs/migrations/0008_alter_kmsdblog_id.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 4.2 on 2023-06-06 14:32 2 | 3 | from django.db import migrations, models 4 | import uuid 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('logs', '0007_alter_kmsdblog_asn_alter_kmsdblog_city_and_more'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='kmsdblog', 16 | name='id', 17 | field=models.CharField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /backend/logs/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/backend/logs/migrations/__init__.py -------------------------------------------------------------------------------- /backend/logs/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from uuid import uuid4 3 | 4 | class KMSDBLog(models.Model): 5 | """ 6 | DB model for Logs 7 | """ 8 | id = models.CharField(default=uuid4, primary_key=True, 9 | editable=False) 10 | timestamp = models.BigIntegerField(null=False, blank=False) 11 | app_id = models.TextField(null=False, blank=False) 12 | phase_node = models.TextField(null=False, blank=False) 13 | event_type = models.TextField(null=False, blank=False) 14 | ip_address = models.GenericIPAddressField(null=False, blank=False) 15 | ph_size = models.BigIntegerField(null=False, blank=False) 16 | asn = models.BigIntegerField(null=True) 17 | isp = models.TextField(null=True) 18 | edge_location = models.TextField(null=True) 19 | country = models.CharField(max_length=2, null=True) 20 | city = models.TextField(null=True) 21 | latitude = models.DecimalField(max_digits=9, decimal_places=5, null=True) 22 | longitude = models.DecimalField(max_digits=9, decimal_places=5, null=True) 23 | 24 | list_display = ('id', 'app_id', 'timestamp', 'event_type') 25 | 26 | def __str__(self): 27 | return self.id 28 | -------------------------------------------------------------------------------- /backend/logs/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /backend/logs/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /backend/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings") 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /backend/scripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "Checking migration configuration..." 5 | if [ "$EXTERNAL_MIGRATION" = "true" ]; then 6 | echo "EXTERNAL_MIGRATION flag is set to true. Skipping migrations as they will be handled externally." 7 | else 8 | echo "EXTERNAL_MIGRATION flag is not set. Running migrations locally..." 9 | python manage.py migrate 10 | fi 11 | 12 | echo "Starting gunicorn server..." 13 | exec gunicorn -b '[::]:8000' --workers 3 backend.wsgi:application 14 | -------------------------------------------------------------------------------- /backend/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/backend/tests/__init__.py -------------------------------------------------------------------------------- /backend/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from pathlib import Path 4 | 5 | # Add the project root directory to Python path 6 | project_root = Path(__file__).parent.parent 7 | sys.path.append(str(project_root)) 8 | -------------------------------------------------------------------------------- /backend/version.txt: -------------------------------------------------------------------------------- 1 | v2.44.0 2 | -------------------------------------------------------------------------------- /frontend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /frontend/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: false, 3 | trailingComma: 'es5', 4 | singleQuote: true, 5 | printWidth: 100, 6 | tabWidth: 2, 7 | useTabs: false, 8 | jsxBracketSameLine: false, 9 | bracketSpacing: true, 10 | } 11 | -------------------------------------------------------------------------------- /frontend/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "typescript.enablePromptUseWorkspaceTsdk": true 4 | } -------------------------------------------------------------------------------- /frontend/@types/gql.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.gql' 2 | -------------------------------------------------------------------------------- /frontend/Dockerfile.dev: -------------------------------------------------------------------------------- 1 | # Base layer 2 | FROM node:18-alpine 3 | 4 | # Set the working directory 5 | WORKDIR /app 6 | 7 | # Copy over package files 8 | COPY package.json ./ 9 | COPY yarn.lock ./ 10 | 11 | # Install dependencies 12 | RUN yarn install --frozen-lockfile --no-cache && yarn cache clean 13 | 14 | # Copy all files 15 | COPY . . 16 | 17 | CMD ["yarn", "dev"] -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # Phase Console - Frontend 2 | 3 | React + TS + Next.js 13 + Tailwind CSS 4 | 5 | ## Getting Started 6 | 7 | First, run the development server: 8 | 9 | ```bash 10 | npm run dev 11 | # or 12 | yarn dev 13 | # or 14 | pnpm dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. -------------------------------------------------------------------------------- /frontend/apollo/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./fragment-masking"; 2 | export * from "./gql"; -------------------------------------------------------------------------------- /frontend/app/[team]/access/network/_components/IPChip.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx' 2 | import { ReactNode } from 'react' 3 | 4 | export const IPChip = ({ ip, children }: { ip: string; children?: ReactNode }) => { 5 | const isCidr = ip.includes('/') 6 | return ( 7 |
16 | {ip} 17 | {children} 18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /frontend/app/[team]/apps/[app]/_components/SecretInfoLegend.tsx: -------------------------------------------------------------------------------- 1 | import { FaCheckCircle, FaCircle, FaTimesCircle } from 'react-icons/fa' 2 | 3 | export const SecretInfoLegend = () => ( 4 |
5 |
6 | Secret is present 7 |
8 |
9 | Secret is the same as Production 10 |
11 |
12 | Secret is blank 13 |
14 |
15 | Secret is missing 16 |
17 |
18 | ) 19 | -------------------------------------------------------------------------------- /frontend/app/[team]/apps/[app]/page.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from 'next' 2 | import { formatTitle } from '@/utils/meta' 3 | import { AppSecrets } from './_components/AppSecrets' 4 | import { AppEnvironments } from './_components/AppEnvironments' 5 | 6 | export async function generateMetadata({ 7 | params, 8 | }: { 9 | params: { team: string; app: string } 10 | }): Promise { 11 | return { 12 | title: formatTitle(`App Secrets`), 13 | description: `Manage app secrets and environments`, 14 | } 15 | } 16 | 17 | export default function AppSecretsView({ params }: { params: { team: string; app: string } }) { 18 | const { team, app } = params 19 | 20 | return ( 21 |
22 | 23 |
24 | 25 |
26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /frontend/app/[team]/apps/[app]/types.ts: -------------------------------------------------------------------------------- 1 | import { EnvironmentType, SecretType, SecretFolderType } from '@/apollo/graphql' 2 | 3 | export type EnvSecrets = { 4 | env: EnvironmentType 5 | secrets: SecretType[] 6 | } 7 | 8 | export type EnvFolders = { 9 | env: EnvironmentType 10 | folders: SecretFolderType[] 11 | } 12 | 13 | export type AppSecret = { 14 | id: string 15 | key: string 16 | isImported?: boolean 17 | envs: Array<{ 18 | env: Partial 19 | secret: SecretType | null 20 | }> 21 | } 22 | 23 | export type AppFolder = { 24 | name: string 25 | path: string 26 | envs: Array<{ 27 | env: Partial 28 | folder: SecretFolderType | null 29 | }> 30 | } 31 | -------------------------------------------------------------------------------- /frontend/app/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client' // Error components must be Client components 2 | 3 | import { Button } from '@/components/common/Button' 4 | import { HeroPattern } from '@/components/common/HeroPattern' 5 | import { useEffect } from 'react' 6 | 7 | export default function Error({ error, reset }: { error: Error; reset: () => void }) { 8 | useEffect(() => { 9 | // Log the error to an error reporting service 10 | console.error(error) 11 | }, [error]) 12 | 13 | return ( 14 |
15 | 16 |

Something went wrong!

17 | 26 |
27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /frontend/app/invite/[invite]/layout.tsx: -------------------------------------------------------------------------------- 1 | import '@/app/globals.css' 2 | import OnboardingNavbar from '@/components/layout/OnboardingNavbar' 3 | 4 | export default function RootLayout({ children }: { children: React.ReactNode }) { 5 | return ( 6 |
7 | 8 | {children} 9 |
10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /frontend/app/loading.tsx: -------------------------------------------------------------------------------- 1 | import Spinner from '@/components/common/Spinner' 2 | 3 | export default function Loading() { 4 | return ( 5 |
6 | 7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /frontend/app/lockbox/[boxId]/error.tsx: -------------------------------------------------------------------------------- 1 | 'use client' // Error components must be Client components 2 | 3 | import { useEffect } from 'react' 4 | import { FaBoxOpen } from 'react-icons/fa' 5 | 6 | export default function Error({ error, reset }: { error: Error; reset: () => void }) { 7 | useEffect(() => { 8 | console.error(error) 9 | }, [error]) 10 | 11 | return ( 12 |
13 |
14 |
15 | 16 | 17 |
Phase Lockbox
18 |
19 | This box has either expired or doesn't exist! 20 |
21 |
22 |
23 |
24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /frontend/app/lockbox/[boxId]/layout.tsx: -------------------------------------------------------------------------------- 1 | import { Metadata } from 'next' 2 | import { HeroPattern } from '@/components/common/HeroPattern' 3 | import OnboardingNavbar from '@/components/layout/OnboardingNavbar' 4 | 5 | export const metadata: Metadata = { 6 | title: 'Phase Lockbox', 7 | description: "You've recieved a secret via Phase Lockbox, secured with Zero-Trust encryption.", 8 | } 9 | 10 | export default function RootLayout({ children }: { children: React.ReactNode }) { 11 | return ( 12 | <> 13 | 14 | 15 | {children} 16 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /frontend/app/lockbox/[boxId]/page.tsx: -------------------------------------------------------------------------------- 1 | import { LockboxType } from '@/apollo/graphql' 2 | import { LockboxViewer } from '@/components/lockbox/LockboxViewer' 3 | import { getBox } from '@/utils/lockbox' 4 | 5 | export default async function Lockbox({ params }: { params: { boxId: string } }) { 6 | const box: LockboxType = await getBox(params.boxId) 7 | 8 | return ( 9 | <> 10 |
11 |
12 |
13 |
Phase Lockbox
14 |
15 | You've recieved a secret via Phase Lockbox, secured with Zero-Trust encryption. 16 | Click the View button to decrypt and view this secret. 17 |
18 |
19 | 20 |
21 | 22 |
23 |
24 |
25 | 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /frontend/app/login/page.tsx: -------------------------------------------------------------------------------- 1 | import { VersionLabel } from '@/components/VersionLabel' 2 | import SignInButtons from '@/components/auth/SignInButtons' 3 | import { HeroPattern } from '@/components/common/HeroPattern' 4 | 5 | export default async function Login() { 6 | return ( 7 | <> 8 |
9 | 10 |
11 | 12 |
13 | 14 |
15 | 16 |
17 |
18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /frontend/app/signup/head.tsx: -------------------------------------------------------------------------------- 1 | export default function Head() { 2 | return ( 3 | <> 4 | 5 | 6 | 7 | 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /frontend/app/signup/layout.tsx: -------------------------------------------------------------------------------- 1 | import '@/app/globals.css' 2 | import OnboardingNavbar from '@/components/layout/OnboardingNavbar' 3 | import UserMenu from '@/components/UserMenu' 4 | 5 | export default function RootLayout({ children }: { children: React.ReactNode }) { 6 | return ( 7 |
8 | 9 | {children} 10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /frontend/codegen.ts: -------------------------------------------------------------------------------- 1 | import type { CodegenConfig } from '@graphql-codegen/cli' 2 | 3 | const config: CodegenConfig = { 4 | overwrite: true, 5 | schema: 'apollo/schema.graphql', 6 | documents: ['graphql/**/*.gql'], 7 | generates: { 8 | 'apollo/': { 9 | preset: 'client', 10 | plugins: [], 11 | }, 12 | }, 13 | } 14 | 15 | export default config 16 | -------------------------------------------------------------------------------- /frontend/components/LoginButton.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useSession, signIn, signOut } from 'next-auth/react' 4 | import { Button } from './common/Button' 5 | 6 | export default function Component() { 7 | const { data: session } = useSession() 8 | if (session) { 9 | return ( 10 | <> 11 | Signed in as {session.user!.email}
12 | 15 | 16 | ) 17 | } 18 | return ( 19 | <> 20 | Not signed in
21 | 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /frontend/components/VersionLabel.tsx: -------------------------------------------------------------------------------- 1 | import { getHealth } from '@/utils/appConfig' 2 | import Link from 'next/link' 3 | 4 | export const VersionLabel = async () => { 5 | const healthData = await getHealth(process.env.BACKEND_API_BASE!) 6 | 7 | return ( 8 | 14 | Version {healthData.version} 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/access/PermissionToggle.tsx: -------------------------------------------------------------------------------- 1 | import { ToggleSwitch } from '../common/ToggleSwitch' 2 | 3 | export const PermissionToggle = ({ 4 | isActive, 5 | onToggle, 6 | disabled, 7 | }: { 8 | isActive: boolean 9 | onToggle: () => void 10 | disabled?: boolean 11 | }) => { 12 | return ( 13 | 14 | 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/common/EmptyState.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react' 2 | 3 | export const EmptyState = (props: { 4 | children: ReactNode 5 | title: string 6 | subtitle: ReactNode 7 | graphic?: ReactNode 8 | }) => { 9 | const { children, title, subtitle, graphic } = props 10 | 11 | return ( 12 |
13 | {graphic} 14 |
15 |
{title}
16 |
{subtitle}
17 |
18 | {children} 19 |
20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /frontend/components/common/LogoMark.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | interface LogoProps extends React.SVGProps {} 4 | 5 | export const LogoMark: React.FC = (props) => { 6 | return ( 7 | 8 | 13 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /frontend/components/common/logos/JumpCloudLogo.tsx: -------------------------------------------------------------------------------- 1 | export const JumpCloudLogo = () => ( 2 | 3 | 7 | 8 | ) 9 | -------------------------------------------------------------------------------- /frontend/components/environments/Tag.tsx: -------------------------------------------------------------------------------- 1 | import { SecretTagType } from '@/apollo/graphql' 2 | import { FaCircle } from 'react-icons/fa' 3 | import clsx from 'clsx' 4 | 5 | interface TagProps { 6 | tag: SecretTagType 7 | buttonVariant?: 'normal' | 'deleted' | 'added' 8 | } 9 | 10 | export const Tag = ({ tag, buttonVariant = 'normal' }: TagProps) => { 11 | const { name, color } = tag 12 | const variantStyles = { 13 | normal: "text-zinc-700 dark:text-zinc-200", 14 | deleted: "bg-red-200 dark:bg-red-950 text-red-500 ph-no-capture line-through rounded-full font-mono", 15 | added: "bg-emerald-100 dark:bg-emerald-950 text-emerald-500 ph-no-capture rounded-full font-mono", 16 | } 17 | 18 | const appliedVariantStyle = variantStyles[buttonVariant] 19 | 20 | return ( 21 |
22 |
23 | 24 |
25 | {name} 26 |
27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /frontend/components/icons/BellIcon.jsx: -------------------------------------------------------------------------------- 1 | export function BellIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/BoltIcon.jsx: -------------------------------------------------------------------------------- 1 | export function BoltIcon(props) { 2 | return ( 3 | 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /frontend/components/icons/BookIcon.jsx: -------------------------------------------------------------------------------- 1 | export function BookIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/CalendarIcon.jsx: -------------------------------------------------------------------------------- 1 | export function CalendarIcon(props) { 2 | return ( 3 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /frontend/components/icons/CartIcon.jsx: -------------------------------------------------------------------------------- 1 | export function CartIcon(props) { 2 | return ( 3 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /frontend/components/icons/ChatBubbleIcon.jsx: -------------------------------------------------------------------------------- 1 | export function ChatBubbleIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/CheckIcon.jsx: -------------------------------------------------------------------------------- 1 | export function CheckIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/ChevronRightLeftIcon.jsx: -------------------------------------------------------------------------------- 1 | export function ChevronRightLeftIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/ClipboardIcon.jsx: -------------------------------------------------------------------------------- 1 | export function ClipboardIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/CopyIcon.jsx: -------------------------------------------------------------------------------- 1 | export function CopyIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/DocumentIcon.jsx: -------------------------------------------------------------------------------- 1 | export function DocumentIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/EnvelopeIcon.jsx: -------------------------------------------------------------------------------- 1 | export function EnvelopeIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/FaceSmileIcon.jsx: -------------------------------------------------------------------------------- 1 | export function FaceSmileIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/FolderIcon.jsx: -------------------------------------------------------------------------------- 1 | export function FolderIcon(props) { 2 | return ( 3 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /frontend/components/icons/LinkIcon.jsx: -------------------------------------------------------------------------------- 1 | export function LinkIcon(props) { 2 | return ( 3 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /frontend/components/icons/ListIcon.jsx: -------------------------------------------------------------------------------- 1 | export function ListIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/MagnifyingGlassIcon.jsx: -------------------------------------------------------------------------------- 1 | export function MagnifyingGlassIcon(props) { 2 | return ( 3 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /frontend/components/icons/MapPinIcon.jsx: -------------------------------------------------------------------------------- 1 | export function MapPinIcon(props) { 2 | return ( 3 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /frontend/components/icons/PackageIcon.jsx: -------------------------------------------------------------------------------- 1 | export function PackageIcon(props) { 2 | return ( 3 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /frontend/components/icons/PaperAirplaneIcon.jsx: -------------------------------------------------------------------------------- 1 | export function PaperAirplaneIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/PaperClipIcon.jsx: -------------------------------------------------------------------------------- 1 | export function PaperClipIcon(props) { 2 | return ( 3 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /frontend/components/icons/ShapesIcon.jsx: -------------------------------------------------------------------------------- 1 | export function ShapesIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/ShirtIcon.jsx: -------------------------------------------------------------------------------- 1 | export function ShirtIcon(props) { 2 | return ( 3 | 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /frontend/components/icons/SquaresPlusIcon.jsx: -------------------------------------------------------------------------------- 1 | export function SquaresPlusIcon(props) { 2 | return ( 3 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/components/icons/TagIcon.jsx: -------------------------------------------------------------------------------- 1 | export function TagIcon(props) { 2 | return ( 3 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /frontend/components/icons/UserIcon.jsx: -------------------------------------------------------------------------------- 1 | export function UserIcon(props) { 2 | return ( 3 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/components/icons/UsersIcon.jsx: -------------------------------------------------------------------------------- 1 | export function UsersIcon(props) { 2 | return ( 3 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /frontend/components/layout/OnboardingNavbar.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | import UserMenu from '../UserMenu' 3 | import { LogoWordMark } from '../common/LogoWordMark' 4 | 5 | const OnboardingNavbar = () => { 6 | return ( 7 |
8 | 18 |
19 | ) 20 | } 21 | 22 | export default OnboardingNavbar 23 | -------------------------------------------------------------------------------- /frontend/constants/index.ts: -------------------------------------------------------------------------------- 1 | // max length for an input string 2 | export const MAX_INPUT_STRING_LENGTH=32 3 | -------------------------------------------------------------------------------- /frontend/contexts/keyringContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useContext, useEffect, useState } from 'react' 2 | import { organisationContext } from './organisationContext' 3 | import { OrganisationKeyring } from '@/utils/crypto' 4 | 5 | interface KeyringContextValue { 6 | keyring: OrganisationKeyring | null 7 | setKeyring: (keyring: OrganisationKeyring) => void 8 | } 9 | 10 | export const KeyringContext = createContext({ 11 | keyring: null, 12 | setKeyring: () => {}, 13 | }) 14 | 15 | interface KeyringProviderProps { 16 | children: React.ReactNode 17 | } 18 | 19 | export const KeyringProvider: React.FC = ({ children }) => { 20 | const [keyring, setKeyring] = useState(null) 21 | 22 | const { activeOrganisation } = useContext(organisationContext) 23 | 24 | useEffect(() => { 25 | setKeyring(null) 26 | }, [activeOrganisation?.id]) 27 | 28 | return ( 29 | {children} 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/access/createNetworkAccessPolicy.gql: -------------------------------------------------------------------------------- 1 | mutation CreateAccessPolicy( 2 | $name: String! 3 | $allowedIps: String! 4 | $isGlobal: Boolean! 5 | $organisationId: ID! 6 | ) { 7 | createNetworkAccessPolicy( 8 | name: $name 9 | allowedIps: $allowedIps 10 | isGlobal: $isGlobal 11 | organisationId: $organisationId 12 | ) { 13 | networkAccessPolicy { 14 | id 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/access/createRole.gql: -------------------------------------------------------------------------------- 1 | mutation CreateRole( 2 | $name: String! 3 | $description: String! 4 | $color: String! 5 | $permissions: JSONString! 6 | $organisationId: ID! 7 | ) { 8 | createCustomRole( 9 | name: $name 10 | description: $description 11 | color: $color 12 | permissions: $permissions 13 | organisationId: $organisationId 14 | ) { 15 | role { 16 | id 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/access/deleteNetworkAccessPolicy.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteAccessPolicy($id: ID!) { 2 | deleteNetworkAccessPolicy(id: $id) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/access/deleteRole.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteRole($id: ID!) { 2 | deleteCustomRole(id: $id) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/access/updateAccountNetworkPolicies.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateAccountNetworkPolicy($accounts: [AccountPolicyInput], $organisationId: ID!) { 2 | updateAccountNetworkAccessPolicies(accountInputs: $accounts, organisationId: $organisationId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/access/updateNetworkAccessPolicy.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateAccessPolicies($inputs: [UpdatePolicyInput]) { 2 | updateNetworkAccessPolicy(policyInputs: $inputs) { 3 | networkAccessPolicy { 4 | id 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/access/updateRole.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateRole( 2 | $id: ID! 3 | $name: String! 4 | $description: String! 5 | $color: String! 6 | $permissions: JSONString! 7 | ) { 8 | updateCustomRole( 9 | id: $id 10 | name: $name 11 | description: $description 12 | color: $color 13 | permissions: $permissions 14 | ) { 15 | role { 16 | id 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/apps/addAppMember.gql: -------------------------------------------------------------------------------- 1 | mutation AddMemberToApp( 2 | $memberId: ID! 3 | $memberType: MemberType 4 | $appId: ID! 5 | $envKeys: [EnvironmentKeyInput] 6 | ) { 7 | addAppMember(memberId: $memberId, memberType: $memberType, appId: $appId, envKeys: $envKeys) { 8 | app { 9 | id 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/apps/removeAppMember.gql: -------------------------------------------------------------------------------- 1 | mutation RemoveMemberFromApp($memberId: ID!, $memberType: MemberType, $appId: ID!) { 2 | removeAppMember(memberId: $memberId, memberType: $memberType, appId: $appId) { 3 | app { 4 | id 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/apps/updateAppName.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateAppNameOp($id: ID!, $name: String!) { 2 | updateAppName(id: $id, name: $name) { 3 | app { 4 | id 5 | name 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /frontend/graphql/mutations/apps/updateEnvScope.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateEnvScope( 2 | $memberId: ID! 3 | $memberType: MemberType 4 | $appId: ID! 5 | $envKeys: [EnvironmentKeyInput] 6 | ) { 7 | updateMemberEnvironmentScope( 8 | memberId: $memberId 9 | memberType: $memberType 10 | appId: $appId 11 | envKeys: $envKeys 12 | ) { 13 | app { 14 | id 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/billing/cancelProSubscription.gql: -------------------------------------------------------------------------------- 1 | mutation CancelStripeSubscription($organisationId: ID!, $subscriptionId: String!) { 2 | cancelSubscription(organisationId: $organisationId, subscriptionId: $subscriptionId) { 3 | success 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/billing/createStripeSetupIntent.gql: -------------------------------------------------------------------------------- 1 | mutation CreateStripeSetupIntentOp($organisationId: ID!) { 2 | createSetupIntent(organisationId: $organisationId) { 3 | clientSecret 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/billing/deletePaymentMethod.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteStripePaymentMethod($organisationId: ID!, $paymentMethodId: String!) { 2 | deletePaymentMethod(organisationId: $organisationId, paymentMethodId: $paymentMethodId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/billing/initUpgradeCheckout.gql: -------------------------------------------------------------------------------- 1 | mutation InitStripeUpgradeCheckout( 2 | $organisationId: ID! 3 | $planType: PlanTypeEnum! 4 | $billingPeriod: BillingPeriodEnum! 5 | ) { 6 | createSubscriptionCheckoutSession( 7 | organisationId: $organisationId 8 | planType: $planType 9 | billingPeriod: $billingPeriod 10 | ) { 11 | clientSecret 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/billing/modifySubscription.gql: -------------------------------------------------------------------------------- 1 | mutation ModifyStripeSubscription( 2 | $organisationId: ID! 3 | $subscriptionId: String! 4 | $planType: PlanTypeEnum! 5 | $billingPeriod: BillingPeriodEnum! 6 | ) { 7 | modifySubscription( 8 | organisationId: $organisationId 9 | subscriptionId: $subscriptionId 10 | planType: $planType 11 | billingPeriod: $billingPeriod 12 | ) { 13 | success 14 | message 15 | status 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/billing/resumeProSubscription.gql: -------------------------------------------------------------------------------- 1 | mutation ResumeStripeSubscription($organisationId: ID!, $subscriptionId: String!) { 2 | resumeSubscription(organisationId: $organisationId, subscriptionId: $subscriptionId) { 3 | success 4 | message 5 | cancelledAt 6 | status 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/billing/setDefaultPaymentMethod.gql: -------------------------------------------------------------------------------- 1 | mutation SetDefaultStripePaymentMethodOp($organisationId: ID!, $paymentMethodId: String!) { 2 | setDefaultPaymentMethod(organisationId: $organisationId, paymentMethodId: $paymentMethodId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/createApp.gql: -------------------------------------------------------------------------------- 1 | mutation CreateApplication( 2 | $id: ID! 3 | $organisationId: ID! 4 | $name: String! 5 | $identityKey: String! 6 | $appToken: String! 7 | $appSeed: String! 8 | $wrappedKeyShare: String! 9 | $appVersion: Int! 10 | ) { 11 | createApp( 12 | id: $id 13 | organisationId: $organisationId 14 | name: $name 15 | identityKey: $identityKey 16 | appToken: $appToken 17 | appSeed: $appSeed 18 | wrappedKeyShare: $wrappedKeyShare 19 | appVersion: $appVersion 20 | ) { 21 | app { 22 | id 23 | name 24 | identityKey 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/createOrganisation.gql: -------------------------------------------------------------------------------- 1 | mutation CreateOrg($id: ID!, $name: String!, $identityKey: String!, $wrappedKeyring: String!, $wrappedRecovery: String!) { 2 | createOrganisation(id: $id, name: $name, identityKey: $identityKey, wrappedKeyring: $wrappedKeyring, wrappedRecovery: $wrappedRecovery) { 3 | organisation { 4 | id 5 | name 6 | memberId 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/deleteApp.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteApplication($id: ID!) { 2 | deleteApp(id: $id) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/bulkProcessSecrets.gql: -------------------------------------------------------------------------------- 1 | mutation BulkProcessSecrets( 2 | $secretsToCreate: [SecretInput!]! 3 | $secretsToUpdate: [SecretInput!]! 4 | $secretsToDelete: [ID!]! 5 | ) { 6 | createSecrets(secretsData: $secretsToCreate) { 7 | secrets { 8 | id 9 | } 10 | } 11 | editSecrets(secretsData: $secretsToUpdate) { 12 | secrets { 13 | id 14 | } 15 | } 16 | deleteSecrets(ids: $secretsToDelete) { 17 | secrets { 18 | id 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/createEnvironment.gql: -------------------------------------------------------------------------------- 1 | mutation CreateEnv( 2 | $envInput: EnvironmentInput! 3 | $adminKeys: [EnvironmentKeyInput] 4 | $wrappedSeed: String 5 | $wrappedSalt: String 6 | ) { 7 | createEnvironment( 8 | environmentData: $envInput 9 | adminKeys: $adminKeys 10 | wrappedSeed: $wrappedSeed 11 | wrappedSalt: $wrappedSalt 12 | ) { 13 | environment { 14 | id 15 | name 16 | createdAt 17 | identityKey 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/createEnvironmentKey.gql: -------------------------------------------------------------------------------- 1 | mutation CreateEnvKey($envId: ID!, $userId: ID,$wrappedSeed: String!, $wrappedSalt: String!, $identityKey: String!) { 2 | createEnvironmentKey(envId: $envId, userId: $userId, wrappedSeed: $wrappedSeed, wrappedSalt: $wrappedSalt, identityKey: $identityKey) { 3 | environmentKey { 4 | id 5 | createdAt 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/createEnvironmentToken.gql: -------------------------------------------------------------------------------- 1 | mutation CreateEnvToken($envId: ID!, $name: String!, $identityKey: String!, $token: String!, $wrappedKeyShare: String!) { 2 | createEnvironmentToken(envId: $envId, name: $name, identityKey: $identityKey, token: $token, wrappedKeyShare: $wrappedKeyShare) { 3 | environmentToken { 4 | id 5 | createdAt 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/createFolder.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewSecretFolder($envId: ID!, $name: String!, $path: String!) { 2 | createSecretFolder(envId: $envId, name: $name, path: $path) { 3 | folder { 4 | id 5 | name 6 | path 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/createPersonalSecret.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewPersonalSecret($newPersonalSecret: PersonalSecretInput!) { 2 | createOverride(overrideData: $newPersonalSecret) { 3 | override { 4 | id 5 | secret { 6 | id 7 | } 8 | value 9 | isActive 10 | createdAt 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/createSecret.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewSecret($newSecret: SecretInput!) { 2 | createSecret(secretData: $newSecret) { 3 | secret { 4 | id 5 | key 6 | value 7 | createdAt 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/createSecretTag.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewSecretTag($orgId: ID!, $name: String!, $color: String!) { 2 | createSecretTag(orgId: $orgId, name: $name, color: $color) { 3 | tag { 4 | id 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/createServiceToken.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewServiceToken($appId: ID!, $environmentKeys: [EnvironmentKeyInput], $identityKey: String!, $token: String!, $wrappedKeyShare: String!, $name: String!, $expiry: BigInt) { 2 | createServiceToken(appId: $appId, environmentKeys: $environmentKeys, identityKey: $identityKey, token: $token, wrappedKeyShare: $wrappedKeyShare, name: $name, expiry: $expiry) { 3 | serviceToken { 4 | id 5 | createdAt 6 | expiresAt 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/deleteEnvironment.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteEnv($environmentId: ID!) { 2 | deleteEnvironment(environmentId: $environmentId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/deleteFolder.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteFolder($folderId: ID!) { 2 | deleteSecretFolder(folderId: $folderId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/deleteSecret.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteSecretOp($id: ID!) { 2 | deleteSecret(id: $id) { 3 | secret { 4 | id 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/deleteServiceToken.gql: -------------------------------------------------------------------------------- 1 | mutation RevokeServiceToken($tokenId: ID!) { 2 | deleteServiceToken(tokenId: $tokenId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/editSecret.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateSecret($id: ID!, $secretData: SecretInput!) { 2 | editSecret(id: $id, secretData: $secretData) { 3 | secret { 4 | id 5 | updatedAt 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/initAppEnvironments.gql: -------------------------------------------------------------------------------- 1 | mutation InitAppEnvironments( 2 | $devEnv: EnvironmentInput! 3 | $stagingEnv: EnvironmentInput! 4 | $prodEnv: EnvironmentInput! 5 | $devAdminKeys: [EnvironmentKeyInput], 6 | $stagAdminKeys: [EnvironmentKeyInput] 7 | $prodAdminKeys: [EnvironmentKeyInput] 8 | ) { 9 | devEnvironment: createEnvironment(environmentData: $devEnv, adminKeys: $devAdminKeys) { 10 | environment { 11 | id 12 | name 13 | createdAt 14 | identityKey 15 | } 16 | } 17 | stagingEnvironment: createEnvironment(environmentData: $stagingEnv, adminKeys: $stagAdminKeys) { 18 | environment { 19 | id 20 | name 21 | createdAt 22 | identityKey 23 | } 24 | } 25 | prodEnvironment: createEnvironment(environmentData: $prodEnv, adminKeys: $prodAdminKeys) { 26 | environment { 27 | id 28 | name 29 | createdAt 30 | identityKey 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/readSecret.gql: -------------------------------------------------------------------------------- 1 | mutation LogSecretReads($ids: [ID]!) { 2 | readSecret(ids: $ids) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/removePersonalSecret.gql: -------------------------------------------------------------------------------- 1 | mutation RemovePersonalSecret($secretId: ID!) { 2 | removeOverride(secretId: $secretId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/renameEnvironment.gql: -------------------------------------------------------------------------------- 1 | mutation RenameEnv($environmentId: ID!, $name: String!) { 2 | renameEnvironment(environmentId: $environmentId, name: $name) { 3 | environment { 4 | id 5 | name 6 | updatedAt 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/shareSecret.gql: -------------------------------------------------------------------------------- 1 | mutation CreateSharedSecret($input: LockboxInput!) { 2 | createLockbox(input: $input) { 3 | lockbox { 4 | id 5 | allowedViews 6 | expiresAt 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/environments/swapEnvironmentOrder.gql: -------------------------------------------------------------------------------- 1 | mutation SwapEnvOrder($environment1Id: ID!, $environment2Id: ID!) { 2 | swapEnvironmentOrder(environment1Id: $environment1Id, environment2Id: $environment2Id) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/organisation/acceptInvite.gql: -------------------------------------------------------------------------------- 1 | mutation AcceptOrganisationInvite( 2 | $orgId: ID! 3 | $identityKey: String! 4 | $wrappedKeyring: String! 5 | $wrappedRecovery: String! 6 | $inviteId: ID! 7 | ) { 8 | createOrganisationMember( 9 | orgId: $orgId 10 | identityKey: $identityKey 11 | wrappedKeyring: $wrappedKeyring 12 | wrappedRecovery: $wrappedRecovery 13 | inviteId: $inviteId 14 | ) { 15 | orgMember { 16 | id 17 | email 18 | createdAt 19 | role { 20 | name 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/organisation/deleteInvite.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteOrgInvite($inviteId: ID!) { 2 | deleteInvitation(inviteId: $inviteId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/organisation/deleteOrgMember.gql: -------------------------------------------------------------------------------- 1 | mutation RemoveMember($memberId: ID!) { 2 | deleteOrganisationMember(memberId: $memberId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/organisation/inviteNewMember.gql: -------------------------------------------------------------------------------- 1 | mutation InviteMember($orgId: ID!, $email: String!, $apps: [String], $roleId: ID!) { 2 | inviteOrganisationMember(orgId: $orgId, email: $email, apps: $apps, roleId: $roleId) { 3 | invite { 4 | id 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/organisation/updateOrgMemberRole.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateMemberRole($memberId: ID!, $roleId: ID!) { 2 | updateOrganisationMemberRole(memberId: $memberId, roleId: $roleId) { 3 | orgMember { 4 | id 5 | role { 6 | name 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/organisation/updateUserWrappedSecrets.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateWrappedSecrets($orgId: ID!, $wrappedKeyring: String!, $wrappedRecovery: String!) { 2 | updateMemberWrappedSecrets(orgId: $orgId, wrappedKeyring: $wrappedKeyring, wrappedRecovery: $wrappedRecovery) { 3 | orgMember { 4 | id 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/rotateAppKeys.gql: -------------------------------------------------------------------------------- 1 | mutation RotateAppKey($id: ID!, $appToken: String!, $wrappedKeyShare: String!) { 2 | rotateAppKeys(id: $id, appToken: $appToken, wrappedKeyShare: $wrappedKeyShare) { 3 | app { 4 | id 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/service-accounts/createServiceAccount.gql: -------------------------------------------------------------------------------- 1 | mutation CreateServiceAccountOp( 2 | $name: String! 3 | $orgId: ID! 4 | $roleId: ID! 5 | $identityKey: String! 6 | $handlers: [ServiceAccountHandlerInput] 7 | $serverWrappedKeyring: String 8 | $serverWrappedRecovery: String 9 | ) { 10 | createServiceAccount( 11 | name: $name 12 | organisationId: $orgId 13 | roleId: $roleId 14 | identityKey: $identityKey 15 | handlers: $handlers 16 | serverWrappedKeyring: $serverWrappedKeyring 17 | serverWrappedRecovery: $serverWrappedRecovery 18 | ) { 19 | serviceAccount { 20 | id 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/service-accounts/createServiceAccountToken.gql: -------------------------------------------------------------------------------- 1 | mutation CreateSAToken( 2 | $serviceAccountId: ID! 3 | $name: String! 4 | $identityKey: String! 5 | $token: String! 6 | $wrappedKeyShare: String! 7 | $expiry: BigInt 8 | ) { 9 | createServiceAccountToken( 10 | serviceAccountId: $serviceAccountId 11 | name: $name 12 | identityKey: $identityKey 13 | token: $token 14 | wrappedKeyShare: $wrappedKeyShare 15 | expiry: $expiry 16 | ) { 17 | token { 18 | id 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/service-accounts/deleteServiceAccount.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteServiceAccountOp($id: ID!) { 2 | deleteServiceAccount(serviceAccountId: $id) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/service-accounts/deleteServiceAccountToken.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteServiceAccountTokenOp($id: ID!) { 2 | deleteServiceAccountToken(tokenId: $id) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/service-accounts/updateHandlerKeys.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateServiceAccountHandlerKeys($orgId: ID!, $handlers: [ServiceAccountHandlerInput]) { 2 | updateServiceAccountHandlers(organisationId: $orgId, handlers: $handlers) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/service-accounts/updateServiceAccount.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateServiceAccountOp($serviceAccountId: ID!, $name: String!, $roleId: ID!) { 2 | updateServiceAccount(serviceAccountId: $serviceAccountId, name: $name, roleId: $roleId) { 3 | serviceAccount { 4 | id 5 | name 6 | role { 7 | id 8 | name 9 | description 10 | permissions 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/aws/CreateAwsSecretsSync.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewAWSSecretsSync($envId: ID!, $path: String!, $credentialId: ID!, $secretName: String!, $kmsId: String) { 2 | createAwsSecretSync(envId: $envId, path: $path, credentialId: $credentialId, secretName: $secretName, kmsId: $kmsId) { 3 | sync { 4 | id 5 | environment { 6 | id 7 | name 8 | envType 9 | } 10 | serviceInfo { 11 | name 12 | } 13 | isActive 14 | lastSync 15 | createdAt 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/cloudflare/CreateCfPagesSync.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewCfPagesSync($envId: ID!, $path: String!, $projectName: String!, $deploymentId: ID!, $projectEnv: String!, $credentialId: ID!) { 2 | createCloudflarePagesSync(envId: $envId, path: $path, projectName: $projectName, deploymentId: $deploymentId, projectEnv: $projectEnv, credentialId: $credentialId) { 3 | sync { 4 | id 5 | environment { 6 | id 7 | name 8 | envType 9 | } 10 | serviceInfo { 11 | id 12 | name 13 | } 14 | isActive 15 | lastSync 16 | createdAt 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/cloudflare/CreateCfWorkersSync.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewCfWorkersSync($envId: ID!, $path: String!, $workerName: String!, $credentialId: ID!) { 2 | createCloudflareWorkersSync(envId: $envId, path: $path, workerName: $workerName, credentialId: $credentialId) { 3 | sync { 4 | id 5 | environment { 6 | id 7 | name 8 | envType 9 | } 10 | serviceInfo { 11 | id 12 | name 13 | } 14 | isActive 15 | lastSync 16 | createdAt 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/deleteProviderCredentials.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteProviderCreds($credentialId: ID!) { 2 | deleteProviderCredentials(credentialId: $credentialId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/deleteSync.gql: -------------------------------------------------------------------------------- 1 | mutation DeleteSync($syncId: ID!) { 2 | deleteEnvSync(syncId: $syncId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/github/CreateGhActionsSync.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewGhActionsSync($envId: ID!, $path: String!, $repoName: String!, $owner: String!, $credentialId: ID!) { 2 | createGhActionsSync(envId: $envId, path: $path, repoName: $repoName, owner: $owner, credentialId: $credentialId) { 3 | sync { 4 | id 5 | environment { 6 | id 7 | name 8 | envType 9 | } 10 | serviceInfo { 11 | id 12 | name 13 | } 14 | isActive 15 | lastSync 16 | createdAt 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/gitlab/createGitlabCISync.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewGitlabCiSync($envId: ID!, $path: String!, $credentialId: ID! $resourcePath: String!, $resourceId: String!, $isGroup: Boolean!, $isMasked: Boolean!, $isProtected: Boolean! ) { 2 | createGitlabCiSync(envId: $envId, path: $path, credentialId: $credentialId, resourcePath: $resourcePath, resourceId: $resourceId, isGroup: $isGroup, masked: $isMasked, protected: $isProtected) { 3 | sync { 4 | id 5 | environment { 6 | id 7 | name 8 | envType 9 | } 10 | serviceInfo { 11 | id 12 | name 13 | } 14 | isActive 15 | lastSync 16 | createdAt 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/initAppSync.gql: -------------------------------------------------------------------------------- 1 | mutation InitAppSyncing($appId: ID!, $envKeys: [EnvironmentKeyInput]) { 2 | initEnvSync(appId: $appId, envKeys: $envKeys) { 3 | app { 4 | id 5 | sseEnabled 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/nomad/createNomadSync.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewNomadSync($envId: ID!, $path: String!, $nomadPath: String!, $nomadNamespace: String!, $credentialId: ID!) { 2 | createNomadSync(envId: $envId, path: $path, nomadPath: $nomadPath, nomadNamespace: $nomadNamespace, credentialId: $credentialId) { 3 | sync { 4 | id 5 | environment { 6 | id 7 | name 8 | envType 9 | } 10 | serviceInfo { 11 | id 12 | name 13 | } 14 | isActive 15 | lastSync 16 | createdAt 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/railway/createRailwayEnvironmentSync.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewRailwaySync( 2 | $envId: ID! 3 | $path: String! 4 | $credentialId: ID! 5 | $railwayProject: RailwayResourceInput! 6 | $railwayEnvironment: RailwayResourceInput! 7 | $railwayService: RailwayResourceInput 8 | ) { 9 | createRailwaySync( 10 | envId: $envId 11 | path: $path 12 | credentialId: $credentialId 13 | railwayProject: $railwayProject 14 | railwayEnvironment: $railwayEnvironment 15 | railwayService: $railwayService 16 | ) { 17 | sync { 18 | id 19 | environment { 20 | id 21 | name 22 | envType 23 | } 24 | serviceInfo { 25 | id 26 | name 27 | } 28 | isActive 29 | lastSync 30 | createdAt 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/saveNewProviderCreds.gql: -------------------------------------------------------------------------------- 1 | mutation SaveNewProviderCreds($orgId: ID!, $provider: String!, $name: String!, $credentials: JSONString!) { 2 | createProviderCredentials(orgId: $orgId, provider: $provider, name: $name, credentials: $credentials) { 3 | credential { 4 | id 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/toggleSync.gql: -------------------------------------------------------------------------------- 1 | mutation ToggleSync($syncId: ID!) { 2 | toggleSyncActive(syncId: $syncId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/triggerSync.gql: -------------------------------------------------------------------------------- 1 | mutation TriggerEnvSync($syncId: ID!) { 2 | triggerSync(syncId: $syncId) { 3 | sync { 4 | status 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/updateProviderCreds.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateProviderCreds($credentialId: ID!, $name: String!, $credentials: JSONString!) { 2 | updateProviderCredentials(credentialId: $credentialId,name: $name, credentials: $credentials) { 3 | credential { 4 | id 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/updateSyncAuthentication.gql: -------------------------------------------------------------------------------- 1 | mutation UpdateSyncAuth($syncId: ID!, $credentialId: ID!) { 2 | updateSyncAuthentication(syncId: $syncId, credentialId: $credentialId) { 3 | sync { 4 | id 5 | status 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/vault/createVaultSync.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewVaultSync($envId: ID!, $path: String! $engine: String!, $vaultPath: String!, $credentialId: ID!) { 2 | createVaultSync(envId: $envId, path: $path, engine: $engine, vaultPath: $vaultPath, credentialId: $credentialId) { 3 | sync { 4 | id 5 | environment { 6 | id 7 | name 8 | envType 9 | } 10 | serviceInfo { 11 | id 12 | name 13 | } 14 | isActive 15 | lastSync 16 | createdAt 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/syncing/vercel/createVercelSync.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewVercelSync( 2 | $envId: ID! 3 | $path: String! 4 | $credentialId: ID! 5 | $projectId: String! 6 | $projectName: String! 7 | $teamId: String! 8 | $teamName: String! 9 | $environment: String! 10 | $secretType: String! 11 | ) { 12 | createVercelSync( 13 | envId: $envId 14 | path: $path 15 | credentialId: $credentialId 16 | projectId: $projectId 17 | projectName: $projectName 18 | teamId: $teamId 19 | teamName: $teamName 20 | environment: $environment 21 | secretType: $secretType 22 | ) { 23 | sync { 24 | id 25 | environment { 26 | id 27 | name 28 | envType 29 | } 30 | serviceInfo { 31 | id 32 | name 33 | } 34 | isActive 35 | lastSync 36 | createdAt 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/users/createUserToken.gql: -------------------------------------------------------------------------------- 1 | mutation CreateNewUserToken($orgId: ID!, $name: String!, $identityKey: String!, $token: String!, $wrappedKeyShare: String!, $expiry: BigInt) { 2 | createUserToken(orgId: $orgId, name: $name, identityKey: $identityKey, token: $token, wrappedKeyShare: $wrappedKeyShare, expiry: $expiry) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/mutations/users/deleteUserToken.gql: -------------------------------------------------------------------------------- 1 | mutation RevokeUserToken($tokenId: ID!) { 2 | deleteUserToken(tokenId: $tokenId) { 3 | ok 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/graphql/queries/access/getClientIp.gql: -------------------------------------------------------------------------------- 1 | query GetIP { 2 | clientIp 3 | } 4 | -------------------------------------------------------------------------------- /frontend/graphql/queries/access/getNetworkPolicies.gql: -------------------------------------------------------------------------------- 1 | query GetNetworkPolicies($organisationId: ID!) { 2 | networkAccessPolicies(organisationId: $organisationId) { 3 | id 4 | name 5 | allowedIps 6 | isGlobal 7 | createdAt 8 | createdBy { 9 | fullName 10 | avatarUrl 11 | self 12 | } 13 | updatedAt 14 | updatedBy { 15 | fullName 16 | avatarUrl 17 | self 18 | } 19 | } 20 | clientIp 21 | } 22 | -------------------------------------------------------------------------------- /frontend/graphql/queries/apps/getAppAccounts.gql: -------------------------------------------------------------------------------- 1 | query GetAppAccounts($appId: ID!) { 2 | appUsers(appId: $appId) { 3 | id 4 | identityKey 5 | email 6 | fullName 7 | avatarUrl 8 | createdAt 9 | role { 10 | id 11 | name 12 | description 13 | permissions 14 | color 15 | } 16 | } 17 | appServiceAccounts(appId: $appId) { 18 | id 19 | identityKey 20 | name 21 | createdAt 22 | role { 23 | id 24 | name 25 | description 26 | permissions 27 | color 28 | } 29 | tokens { 30 | id 31 | name 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /frontend/graphql/queries/apps/getAppMembers.gql: -------------------------------------------------------------------------------- 1 | query GetAppMembers($appId: ID!) { 2 | appUsers(appId: $appId) { 3 | id 4 | identityKey 5 | email 6 | fullName 7 | avatarUrl 8 | createdAt 9 | role { 10 | id 11 | name 12 | description 13 | permissions 14 | color 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/graphql/queries/apps/getAppServiceAccounts.gql: -------------------------------------------------------------------------------- 1 | query GetAppServiceAccounts($appId: ID!) { 2 | appServiceAccounts(appId: $appId) { 3 | id 4 | identityKey 5 | name 6 | createdAt 7 | role { 8 | id 9 | name 10 | description 11 | permissions 12 | color 13 | } 14 | tokens { 15 | id 16 | name 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/graphql/queries/billing/getCheckoutDetails.gql: -------------------------------------------------------------------------------- 1 | query GetCheckoutDetails($stripeSessionId: String!) { 2 | stripeCheckoutDetails(stripeSessionId: $stripeSessionId) { 3 | paymentStatus 4 | customerEmail 5 | billingStartDate 6 | billingEndDate 7 | subscriptionId 8 | planName 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/graphql/queries/billing/getSubscriptionDetails.gql: -------------------------------------------------------------------------------- 1 | query GetSubscriptionDetails($organisationId: ID!) { 2 | stripeSubscriptionDetails(organisationId: $organisationId) { 3 | subscriptionId 4 | planName 5 | planType 6 | billingPeriod 7 | status 8 | nextPaymentAmount 9 | currentPeriodStart 10 | currentPeriodEnd 11 | renewalDate 12 | cancelAt 13 | cancelAtPeriodEnd 14 | paymentMethods { 15 | id 16 | brand 17 | last4 18 | expMonth 19 | expYear 20 | isDefault 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /frontend/graphql/queries/getAppActivityChart.gql: -------------------------------------------------------------------------------- 1 | query GetAppActivityChart($appId: ID!, $period: TimeRange) { 2 | appActivityChart(appId: $appId, period: $period) { 3 | index 4 | date 5 | data 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/queries/getAppDetail.gql: -------------------------------------------------------------------------------- 1 | query GetAppDetail($organisationId: ID!, $appId: ID!) { 2 | apps(organisationId: $organisationId, appId: $appId) { 3 | id 4 | name 5 | identityKey 6 | createdAt 7 | appToken 8 | appSeed 9 | appVersion 10 | sseEnabled 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /frontend/graphql/queries/getAppKmsLogs.gql: -------------------------------------------------------------------------------- 1 | query GetAppKmsLogs($appId: ID!, $start: BigInt, $end: BigInt) { 2 | kmsLogs(appId: $appId, start: $start, end: $end) { 3 | logs { 4 | id 5 | timestamp 6 | phaseNode 7 | eventType 8 | ipAddress 9 | country 10 | city 11 | phSize 12 | } 13 | count 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /frontend/graphql/queries/getApps.gql: -------------------------------------------------------------------------------- 1 | query GetApps($organisationId: ID!, $appId: ID) { 2 | apps(organisationId: $organisationId, appId: $appId) { 3 | id 4 | name 5 | identityKey 6 | createdAt 7 | updatedAt 8 | sseEnabled 9 | members { 10 | id 11 | email 12 | fullName 13 | avatarUrl 14 | } 15 | serviceAccounts { 16 | id 17 | name 18 | } 19 | environments { 20 | id 21 | name 22 | envType 23 | syncs { 24 | id 25 | serviceInfo { 26 | id 27 | name 28 | provider { 29 | id 30 | name 31 | } 32 | } 33 | status 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /frontend/graphql/queries/getDashboard.gql: -------------------------------------------------------------------------------- 1 | query GetDashboard($organisationId: ID!) { 2 | apps(organisationId: $organisationId) { 3 | id 4 | name 5 | sseEnabled 6 | } 7 | userTokens(organisationId: $organisationId) { 8 | id 9 | } 10 | organisationInvites(orgId: $organisationId) { 11 | id 12 | } 13 | organisationMembers(organisationId: $organisationId, role: null) { 14 | id 15 | } 16 | savedCredentials(orgId: $organisationId) { 17 | id 18 | } 19 | syncs(orgId: $organisationId) { 20 | id 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /frontend/graphql/queries/getOrganisations.gql: -------------------------------------------------------------------------------- 1 | query GetOrganisations { 2 | organisations { 3 | id 4 | name 5 | identityKey 6 | createdAt 7 | plan 8 | planDetail { 9 | name 10 | maxUsers 11 | maxApps 12 | maxEnvsPerApp 13 | seatsUsed { 14 | users 15 | serviceAccounts 16 | total 17 | } 18 | appCount 19 | } 20 | role { 21 | name 22 | description 23 | color 24 | permissions 25 | } 26 | memberId 27 | keyring 28 | recovery 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /frontend/graphql/queries/organisation/checkOrgNameAvailable.gql: -------------------------------------------------------------------------------- 1 | query CheckOrganisationNameAvailability($name: String!) { 2 | organisationNameAvailable(name: $name) 3 | } -------------------------------------------------------------------------------- /frontend/graphql/queries/organisation/getGlobalAccessUsers.gql: -------------------------------------------------------------------------------- 1 | query GetGlobalAccessUsers($organisationId: ID!) { 2 | organisationGlobalAccessUsers(organisationId: $organisationId) { 3 | id 4 | role { 5 | name 6 | permissions 7 | } 8 | identityKey 9 | self 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /frontend/graphql/queries/organisation/getInvites.gql: -------------------------------------------------------------------------------- 1 | query GetInvites($orgId: ID!) { 2 | organisationInvites(orgId: $orgId) { 3 | id 4 | createdAt 5 | expiresAt 6 | invitedBy { 7 | email 8 | fullName 9 | self 10 | } 11 | inviteeEmail 12 | role { 13 | id 14 | name 15 | description 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/graphql/queries/organisation/getLicense.gql: -------------------------------------------------------------------------------- 1 | query GetLicenseData { 2 | license { 3 | id 4 | customerName 5 | organisationName 6 | expiresAt 7 | plan 8 | seats 9 | isActivated 10 | organisationOwner { 11 | fullName 12 | email 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /frontend/graphql/queries/organisation/getOrganisationLicense.gql: -------------------------------------------------------------------------------- 1 | query GetOrgLicense($organisationId: ID!) { 2 | organisationLicense(organisationId: $organisationId) { 3 | id 4 | customerName 5 | issuedAt 6 | expiresAt 7 | activatedAt 8 | plan 9 | seats 10 | tokens 11 | } 12 | } -------------------------------------------------------------------------------- /frontend/graphql/queries/organisation/getOrganisationMembers.gql: -------------------------------------------------------------------------------- 1 | query GetOrganisationMembers($organisationId: ID!, $role: [String]) { 2 | organisationMembers(organisationId: $organisationId, role: $role) { 3 | id 4 | role { 5 | id 6 | name 7 | description 8 | permissions 9 | color 10 | } 11 | identityKey 12 | email 13 | fullName 14 | avatarUrl 15 | createdAt 16 | lastLogin 17 | self 18 | appMemberships { 19 | id 20 | name 21 | sseEnabled 22 | environments { 23 | id 24 | name 25 | } 26 | } 27 | tokens { 28 | id 29 | name 30 | createdAt 31 | expiresAt 32 | } 33 | networkPolicies { 34 | id 35 | name 36 | allowedIps 37 | isGlobal 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /frontend/graphql/queries/organisation/getOrganisationPlan.gql: -------------------------------------------------------------------------------- 1 | query GetOrganisationPlan($organisationId: ID!) { 2 | organisationPlan(organisationId: $organisationId) { 3 | name 4 | maxUsers 5 | maxApps 6 | maxEnvsPerApp 7 | seatsUsed { 8 | users 9 | serviceAccounts 10 | total 11 | } 12 | appCount 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/graphql/queries/organisation/getRoles.gql: -------------------------------------------------------------------------------- 1 | query GetRoles($orgId: ID!) { 2 | roles(orgId: $orgId) { 3 | id 4 | name 5 | description 6 | color 7 | permissions 8 | isDefault 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/graphql/queries/organisation/validateOrganisationInvite.gql: -------------------------------------------------------------------------------- 1 | query VerifyInvite($inviteId: ID!) { 2 | validateInvite(inviteId: $inviteId) { 3 | id 4 | organisation { 5 | id 6 | name 7 | } 8 | inviteeEmail 9 | invitedBy { 10 | fullName 11 | email 12 | } 13 | apps { 14 | id 15 | name 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/graphql/queries/secrets/getAppEnvironments.gql: -------------------------------------------------------------------------------- 1 | query GetAppEnvironments($appId: ID!, $memberId: ID, $memberType: MemberType) { 2 | appEnvironments( 3 | appId: $appId 4 | environmentId: null 5 | memberId: $memberId 6 | memberType: $memberType 7 | ) { 8 | id 9 | name 10 | envType 11 | identityKey 12 | wrappedSeed 13 | wrappedSalt 14 | createdAt 15 | app { 16 | name 17 | id 18 | } 19 | secretCount 20 | folderCount 21 | index 22 | members { 23 | email 24 | fullName 25 | avatarUrl 26 | } 27 | } 28 | sseEnabled(appId: $appId) 29 | serverPublicKey 30 | } 31 | -------------------------------------------------------------------------------- /frontend/graphql/queries/secrets/getAppSecrets.gql: -------------------------------------------------------------------------------- 1 | query GetAppSecrets($appId: ID!, $memberId: ID, $memberType: MemberType) { 2 | appEnvironments( 3 | appId: $appId 4 | environmentId: null 5 | memberId: $memberId 6 | memberType: $memberType 7 | ) { 8 | id 9 | name 10 | envType 11 | identityKey 12 | wrappedSeed 13 | wrappedSalt 14 | createdAt 15 | app { 16 | name 17 | id 18 | } 19 | secretCount 20 | folderCount 21 | index 22 | members { 23 | email 24 | fullName 25 | avatarUrl 26 | } 27 | folders { 28 | id 29 | name 30 | path 31 | } 32 | secrets { 33 | id 34 | key 35 | value 36 | comment 37 | path 38 | } 39 | } 40 | sseEnabled(appId: $appId) 41 | serverPublicKey 42 | } 43 | -------------------------------------------------------------------------------- /frontend/graphql/queries/secrets/getEnvironmentKey.gql: -------------------------------------------------------------------------------- 1 | query GetEnvironmentKey($envId: ID!, $appId: ID!) { 2 | environmentKeys(environmentId: $envId, appId: $appId) { 3 | id 4 | identityKey 5 | wrappedSeed 6 | wrappedSalt 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/graphql/queries/secrets/getEnvironmentTokens.gql: -------------------------------------------------------------------------------- 1 | query GetEnvironmentTokens($envId: ID!) { 2 | environmentTokens(environmentId: $envId) { 3 | id 4 | name 5 | wrappedKeyShare 6 | createdAt 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/graphql/queries/secrets/getFolders.gql: -------------------------------------------------------------------------------- 1 | query GetFolders($envId: ID!, $path: String) { 2 | folders(envId: $envId, path: $path) { 3 | id 4 | name 5 | path 6 | createdAt 7 | folderCount 8 | secretCount 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/graphql/queries/secrets/getSecretHistory.gql: -------------------------------------------------------------------------------- 1 | query GetSecretHistory($appId: ID!, $envId: ID!, $id: ID!) { 2 | secrets(envId: $envId, id: $id) { 3 | id 4 | history { 5 | id 6 | key 7 | value 8 | path 9 | tags { 10 | id 11 | name 12 | color 13 | } 14 | version 15 | comment 16 | timestamp 17 | ipAddress 18 | userAgent 19 | user { 20 | email 21 | username 22 | fullName 23 | avatarUrl 24 | } 25 | serviceToken { 26 | id 27 | name 28 | } 29 | serviceAccount { 30 | id 31 | name 32 | } 33 | eventType 34 | } 35 | } 36 | environmentKeys(appId: $appId, environmentId: $envId) { 37 | id 38 | identityKey 39 | wrappedSeed 40 | wrappedSalt 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /frontend/graphql/queries/secrets/getSecretKVs.gql: -------------------------------------------------------------------------------- 1 | query GetEnvSecretsKV($envId: ID!) { 2 | folders(envId: $envId, path: "/") { 3 | id 4 | name 5 | } 6 | secrets(envId: $envId, path: "/") { 7 | id 8 | key 9 | value 10 | comment 11 | path 12 | } 13 | environmentKeys(environmentId: $envId) { 14 | id 15 | identityKey 16 | wrappedSeed 17 | wrappedSalt 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/graphql/queries/secrets/getSecretTags.gql: -------------------------------------------------------------------------------- 1 | query GetSecretTags($orgId: ID!) { 2 | secretTags(orgId: $orgId) { 3 | id 4 | name 5 | color 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/queries/secrets/getServiceTokens.gql: -------------------------------------------------------------------------------- 1 | query GetServiceTokens($appId: ID!) { 2 | serviceTokens(appId: $appId) { 3 | id 4 | name 5 | createdAt 6 | createdBy { 7 | fullName 8 | avatarUrl 9 | self 10 | } 11 | expiresAt 12 | keys { 13 | id 14 | identityKey 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/graphql/queries/service-accounts/getServiceAccountDetail.gql: -------------------------------------------------------------------------------- 1 | query GetServiceAccountDetail($orgId: ID!, $id: ID) { 2 | serviceAccounts(orgId: $orgId, serviceAccountId: $id) { 3 | id 4 | name 5 | identityKey 6 | role { 7 | id 8 | name 9 | description 10 | color 11 | permissions 12 | } 13 | createdAt 14 | handlers { 15 | id 16 | wrappedKeyring 17 | wrappedRecovery 18 | user { 19 | self 20 | } 21 | } 22 | tokens { 23 | id 24 | name 25 | createdAt 26 | expiresAt 27 | createdBy { 28 | fullName 29 | avatarUrl 30 | self 31 | } 32 | lastUsed 33 | } 34 | appMemberships { 35 | id 36 | name 37 | environments { 38 | id 39 | name 40 | } 41 | sseEnabled 42 | } 43 | networkPolicies { 44 | id 45 | name 46 | allowedIps 47 | isGlobal 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /frontend/graphql/queries/service-accounts/getServiceAccountHandlers.gql: -------------------------------------------------------------------------------- 1 | query GetServiceAccountHandlers($orgId: ID!) { 2 | serviceAccountHandlers(orgId: $orgId) { 3 | id 4 | email 5 | role { 6 | name 7 | permissions 8 | } 9 | identityKey 10 | self 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /frontend/graphql/queries/service-accounts/getServiceAccounts.gql: -------------------------------------------------------------------------------- 1 | query GetServiceAccounts($orgId: ID!, $id: ID) { 2 | serviceAccounts(orgId: $orgId, serviceAccountId: $id) { 3 | id 4 | name 5 | identityKey 6 | role { 7 | id 8 | name 9 | description 10 | color 11 | } 12 | handlers { 13 | id 14 | wrappedKeyring 15 | wrappedRecovery 16 | user { 17 | self 18 | } 19 | } 20 | createdAt 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/aws/getSecrets.gql: -------------------------------------------------------------------------------- 1 | query GetAwsSecrets($credentialId: ID!) { 2 | awsSecrets(credentialId: $credentialId) { 3 | name 4 | arn 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/cloudflare/getPages.gql: -------------------------------------------------------------------------------- 1 | query GetCfPages($credentialId: ID!) { 2 | cloudflarePagesProjects(credentialId: $credentialId) { 3 | name 4 | deploymentId 5 | environments 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/cloudflare/getWorkers.gql: -------------------------------------------------------------------------------- 1 | query GetCfWorkers($credentialId: ID!) { 2 | cloudflareWorkers(credentialId: $credentialId) { 3 | name 4 | scriptId 5 | } 6 | } -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/getAppSyncStatus.gql: -------------------------------------------------------------------------------- 1 | query GetAppSyncStatus($appId: ID!) { 2 | sseEnabled(appId: $appId) 3 | syncs(appId: $appId) { 4 | id 5 | environment { 6 | id 7 | name 8 | envType 9 | app { 10 | id 11 | name 12 | } 13 | } 14 | path 15 | serviceInfo { 16 | id 17 | name 18 | provider { 19 | id 20 | } 21 | } 22 | options 23 | isActive 24 | lastSync 25 | status 26 | authentication { 27 | id 28 | name 29 | credentials 30 | } 31 | createdAt 32 | history { 33 | id 34 | status 35 | createdAt 36 | completedAt 37 | meta 38 | } 39 | } 40 | serverPublicKey 41 | } 42 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/getProviders.gql: -------------------------------------------------------------------------------- 1 | query GetProviderList { 2 | providers { 3 | id 4 | name 5 | expectedCredentials 6 | optionalCredentials 7 | authScheme 8 | } 9 | serverPublicKey 10 | } 11 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/getSavedCredentials.gql: -------------------------------------------------------------------------------- 1 | query GetSavedCredentials($orgId: ID!) { 2 | savedCredentials(orgId: $orgId) { 3 | id 4 | name 5 | credentials 6 | createdAt 7 | provider { 8 | id 9 | name 10 | expectedCredentials 11 | optionalCredentials 12 | } 13 | syncCount 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/getServerKey.gql: -------------------------------------------------------------------------------- 1 | query GetServerKey { 2 | serverPublicKey 3 | } 4 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/getServices.gql: -------------------------------------------------------------------------------- 1 | query GetServiceList { 2 | services { 3 | id 4 | name 5 | provider { 6 | id 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/github/getRepos.gql: -------------------------------------------------------------------------------- 1 | query GetGithubRepos($credentialId: ID!) { 2 | githubRepos(credentialId: $credentialId) { 3 | name 4 | owner 5 | type 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/gitlab/getResources.gql: -------------------------------------------------------------------------------- 1 | query GetGitLabResources($credentialId: ID!) { 2 | gitlabProjects(credentialId: $credentialId) { 3 | id 4 | name 5 | namespace { 6 | name 7 | fullPath 8 | } 9 | pathWithNamespace 10 | webUrl 11 | } 12 | gitlabGroups(credentialId: $credentialId) { 13 | id 14 | fullName 15 | fullPath 16 | webUrl 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/nomad/testAuth.gql: -------------------------------------------------------------------------------- 1 | query TestNomadAuth($credentialId: ID!) { 2 | testNomadCreds(credentialId: $credentialId) 3 | } 4 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/railway/getProjects.gql: -------------------------------------------------------------------------------- 1 | query GetRailwayProjects($credentialId: ID!) { 2 | railwayProjects(credentialId: $credentialId) { 3 | id 4 | name 5 | environments { 6 | id 7 | name 8 | } 9 | services { 10 | id 11 | name 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/vault/testAuth.gql: -------------------------------------------------------------------------------- 1 | query TestVaultAuth($credentialId: ID!) { 2 | testVaultCreds(credentialId: $credentialId) 3 | } 4 | -------------------------------------------------------------------------------- /frontend/graphql/queries/syncing/vercel/getProject.gql: -------------------------------------------------------------------------------- 1 | query GetVercelProjects($credentialId: ID!) { 2 | vercelProjects(credentialId: $credentialId) { 3 | id 4 | teamName 5 | projects { 6 | id 7 | name 8 | environment 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /frontend/graphql/queries/users/getUserTokens.gql: -------------------------------------------------------------------------------- 1 | query GetUserTokens($organisationId: ID!) { 2 | userTokens(organisationId: $organisationId) { 3 | id 4 | name 5 | wrappedKeyShare 6 | createdAt 7 | expiresAt 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /frontend/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'jsdom', 4 | roots: ['/tests'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest', 7 | }, 8 | testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$', 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 10 | moduleNameMapper: { 11 | "^@/(.*)$": "/$1" 12 | }, 13 | 14 | }; 15 | -------------------------------------------------------------------------------- /frontend/middleware.ts: -------------------------------------------------------------------------------- 1 | export { default } from 'next-auth/middleware' 2 | 3 | export const config = { 4 | matcher: [ 5 | /* 6 | * Match all request paths except for the ones starting with: 7 | * - api (API routes) 8 | * - _next/static (static files) 9 | * - _next/image (image optimization files) 10 | * - favicon.ico (favicon file) 11 | */ 12 | '/((?!api|_next/static|_next/image|favicon.ico|favicon.svg|login|lockbox|api/health).*)', 13 | ], 14 | } 15 | -------------------------------------------------------------------------------- /frontend/pages/api/health.ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest, NextApiResponse } from 'next' 2 | 3 | export default function handler(req: NextApiRequest, res: NextApiResponse) { 4 | res.status(200).json({ status: 'alive' }) 5 | } -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /frontend/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/frontend/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /frontend/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/frontend/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /frontend/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/frontend/public/apple-touch-icon.png -------------------------------------------------------------------------------- /frontend/public/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/frontend/public/assets/images/logo.png -------------------------------------------------------------------------------- /frontend/public/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /frontend/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/frontend/public/favicon-16x16.png -------------------------------------------------------------------------------- /frontend/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/frontend/public/favicon-32x32.png -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /frontend/scripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Set up runtime env vars and start next server 4 | bash scripts/replace-variable.sh && 5 | NODE_ENV=production HOSTNAME=:: PORT=3000 node server.js 6 | 7 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "baseUrl": ".", 23 | "paths": { 24 | "@/*": ["./*"] 25 | }, 26 | "types": ["jest"] 27 | }, 28 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "utils/typography.js"], 29 | "exclude": ["node_modules"] 30 | } 31 | -------------------------------------------------------------------------------- /frontend/utils/appConfig.ts: -------------------------------------------------------------------------------- 1 | export const isCloudHosted = () => { 2 | return ( 3 | process.env.NEXT_PUBLIC_APP_HOST?.trim() === 'cloud' || process.env.APP_HOST?.trim() === 'cloud' 4 | ) 5 | } 6 | 7 | export const getHostname = () => `${window.location.protocol}//${window.location.host}` 8 | 9 | export const getApiHost = () => { 10 | return isCloudHosted() ? 'https://api.phase.dev' : `${getHostname()}/service/public` 11 | } 12 | 13 | export const getHealth = async (baseUrl: string) => { 14 | const res = await fetch(`${baseUrl}/493c5048-99f9-4eac-ad0d-98c3740b491f/health`, { 15 | cache: 'no-store', 16 | }) 17 | 18 | if (!res.ok) { 19 | throw new Error('Failed to fetch data') 20 | } 21 | 22 | return res.json() 23 | } 24 | -------------------------------------------------------------------------------- /frontend/utils/auth.ts: -------------------------------------------------------------------------------- 1 | import _sodium from 'libsodium-wrappers-sumo' 2 | 3 | export namespace UrlUtils { 4 | export const makeUrl = (...endpoints: string[]) => { 5 | let url = endpoints.reduce((prevUrl, currentPath) => { 6 | if (prevUrl.length === 0) { 7 | return prevUrl + currentPath 8 | } 9 | 10 | return prevUrl.endsWith('/') ? prevUrl + currentPath + '/' : prevUrl + '/' + currentPath + '/' 11 | }, '') 12 | return url 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/utils/clipboard.ts: -------------------------------------------------------------------------------- 1 | export const copyToClipBoard = (text: string) => { 2 | return navigator.clipboard.writeText(text).then( 3 | () => true, 4 | () => false 5 | ) 6 | } 7 | -------------------------------------------------------------------------------- /frontend/utils/contextSnippets.ts: -------------------------------------------------------------------------------- 1 | import { getApiHost, getHostname } from './appConfig' 2 | 3 | export type CommandAuth = { 4 | cliToken: string 5 | apiToken: string 6 | expiry: number 7 | } 8 | 9 | export type CommandType = 'cli' | 'api' 10 | 11 | export const generateCommand = ( 12 | commandType: CommandType, 13 | authToken: string, 14 | appId: string, 15 | env?: string, 16 | path?: string, 17 | expiryText?: string, 18 | ) => 19 | commandType === 'cli' 20 | ? [ 21 | `export PHASE_HOST=${getHostname()} && export PHASE_SERVICE_TOKEN=${authToken} && echo "Note: This token will expire ${expiryText}"`, 22 | `phase secrets list --app-id ${appId}${env ? ` --env ${env}` : ''}${path !== '' ? ` --path ${path}` : ''}` 23 | ].join('\n') 24 | : [ 25 | `export PHASE_PAT='${authToken}' && echo "Note: This token will expire ${expiryText}"`, 26 | 'curl \\', 27 | ' --request GET \\', 28 | ` --url '${getApiHost()}/v1/secrets/?app_id=${appId}&env=${env}${path !== '' ? `&path=${path}` : ''}' \\`, 29 | ` --header "Authorization: Bearer $PHASE_PAT"` 30 | ].join('\n') 31 | -------------------------------------------------------------------------------- /frontend/utils/crypto/constants.ts: -------------------------------------------------------------------------------- 1 | export const VERSION = 1 2 | -------------------------------------------------------------------------------- /frontend/utils/crypto/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app' 2 | export * from './constants' 3 | export * from './environments' 4 | export * from './general' 5 | export * from './keyshares' 6 | export * from './lockbox' 7 | export * from './types' 8 | export * from './users' 9 | -------------------------------------------------------------------------------- /frontend/utils/crypto/types.ts: -------------------------------------------------------------------------------- 1 | export type OrganisationKeyring = { 2 | symmetricKey: string 3 | publicKey: string 4 | privateKey: string 5 | } 6 | 7 | export type AppKeyring = { 8 | publicKey: string 9 | privateKey: string 10 | } 11 | 12 | export type EnvKeyring = { 13 | privateKey: string 14 | publicKey: string 15 | salt: string 16 | } 17 | 18 | export type EnvKeypair = { 19 | publicKey: string 20 | privateKey: string 21 | } 22 | -------------------------------------------------------------------------------- /frontend/utils/environment.ts: -------------------------------------------------------------------------------- 1 | export const sanitizeInput = (value: string) => value.replace(/[^a-zA-Z0-9\-_]/g, '') 2 | -------------------------------------------------------------------------------- /frontend/utils/meta.ts: -------------------------------------------------------------------------------- 1 | export function formatTitle(title: string): string { 2 | return `${title} | Phase Console`; 3 | } -------------------------------------------------------------------------------- /frontend/utils/posthog.ts: -------------------------------------------------------------------------------- 1 | import posthog from 'posthog-js' 2 | 3 | export function initializePostHog() { 4 | if ( 5 | typeof window !== 'undefined' && 6 | !process.env.NEXT_PUBLIC_POSTHOG_KEY?.startsWith('BAKED_') && 7 | !process.env.NEXT_PUBLIC_POSTHOG_HOST?.startsWith('BAKED_') 8 | ) { 9 | posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, { 10 | api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || 'https://app.posthog.com', 11 | capture_pageview: true, 12 | session_recording: { 13 | maskInputOptions: { 14 | password: true, // Mask password inputs 15 | }, 16 | }, 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/utils/tags.ts: -------------------------------------------------------------------------------- 1 | import { SecretTagType } from '@/apollo/graphql' 2 | 3 | export const isTagSame = (tag1: SecretTagType, tag2: SecretTagType) => { 4 | return tag1.color === tag2.color && tag1.name === tag2.name 5 | } 6 | 7 | export const areTagsAreSame = (tags1: SecretTagType[], tags2: SecretTagType[]) => { 8 | if (tags1.length !== tags2.length) return false 9 | 10 | const sortedTags1 = [...tags1].sort((a, b) => a.id.localeCompare(b.id)) 11 | const sortedTags2 = [...tags2].sort((a, b) => a.id.localeCompare(b.id)) 12 | 13 | return sortedTags1.every((tag, index) => isTagSame(tag, sortedTags2[index])) 14 | } 15 | -------------------------------------------------------------------------------- /frontend/utils/tokens.ts: -------------------------------------------------------------------------------- 1 | import { getUnixTimeStampinFuture } from './time' 2 | 3 | export interface ExpiryOptionT { 4 | name: string 5 | getExpiry: () => number | null 6 | } 7 | 8 | export const tokenExpiryOptions: ExpiryOptionT[] = [ 9 | { 10 | name: 'Never', 11 | getExpiry: () => null, 12 | }, 13 | { 14 | name: '7 days', 15 | getExpiry: () => getUnixTimeStampinFuture(7), 16 | }, 17 | { 18 | name: '30 days', 19 | getExpiry: () => getUnixTimeStampinFuture(30), 20 | }, 21 | { 22 | name: '60 days', 23 | getExpiry: () => getUnixTimeStampinFuture(60), 24 | }, 25 | { 26 | name: '90 days', 27 | getExpiry: () => getUnixTimeStampinFuture(90), 28 | }, 29 | ] 30 | 31 | export const humanReadableExpiry = (expiryOption: ExpiryOptionT) => 32 | expiryOption.getExpiry() === null 33 | ? 'This token will never expire.' 34 | : `This token will expire on ${new Date(expiryOption.getExpiry()!).toLocaleDateString()}.` 35 | 36 | export const compareExpiryOptions = (a: ExpiryOptionT, b: ExpiryOptionT) => { 37 | return a.getExpiry() === b.getExpiry() 38 | } 39 | -------------------------------------------------------------------------------- /img/azure.svg: -------------------------------------------------------------------------------- 1 | Microsoft Azure -------------------------------------------------------------------------------- /img/console-ui.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/img/console-ui.mp4 -------------------------------------------------------------------------------- /img/console-ui.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/img/console-ui.webp -------------------------------------------------------------------------------- /img/gcp.svg: -------------------------------------------------------------------------------- 1 | Google Cloud -------------------------------------------------------------------------------- /img/members.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/img/members.png -------------------------------------------------------------------------------- /img/phase-cli-import-run.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/img/phase-cli-import-run.webp -------------------------------------------------------------------------------- /img/phase-console-secrets.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/img/phase-console-secrets.webp -------------------------------------------------------------------------------- /img/phase-console-wordmark-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/img/phase-console-wordmark-dark.png -------------------------------------------------------------------------------- /img/secrets-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phasehq/console/29be2cac75707e7be8c8a7780aa3930367fa2e91/img/secrets-overview.png -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | RUN apt-get update && \ 3 | apt-get install -y openssl && \ 4 | mkdir -p /etc/nginx/ssl && \ 5 | openssl ecparam -genkey -name secp384r1 | openssl ec -out /etc/nginx/ssl/nginx.key && \ 6 | openssl req -new -x509 -sha256 -key /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt -days 365 \ 7 | -subj "/C=SG/ST=Wordwideweb/L=The Cloud/CN=example.com" \ --------------------------------------------------------------------------------