diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 11e79590f2..aa868cd1b5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -66,6 +66,7 @@ src/Admin/Views/Tools @bitwarden/team-billing-dev # Platform team .github/workflows/build.yml @bitwarden/team-platform-dev +.github/workflows/build_target.yml @bitwarden/team-platform-dev .github/workflows/cleanup-after-pr.yml @bitwarden/team-platform-dev .github/workflows/cleanup-rc-branch.yml @bitwarden/team-platform-dev .github/workflows/repository-management.yml @bitwarden/team-platform-dev diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f125b7811..f0df238b34 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,22 +7,18 @@ on: - "main" - "rc" - "hotfix-rc" - pull_request_target: + pull_request: types: [opened, synchronize] + workflow_call: + inputs: {} env: _AZ_REGISTRY: "bitwardenprod.azurecr.io" jobs: - check-run: - name: Check PR run - uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main - lint: name: Lint runs-on: ubuntu-22.04 - needs: - - check-run steps: - name: Check out repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -40,6 +36,8 @@ jobs: runs-on: ubuntu-22.04 needs: - lint + outputs: + has_secrets: ${{ steps.check-secrets.outputs.has_secrets }} strategy: fail-fast: false matrix: @@ -75,6 +73,14 @@ jobs: base_path: ./bitwarden_license/src node: true steps: + - name: Check secrets + id: check-secrets + env: + AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + run: | + has_secrets=${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL != '' }} + echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT + - name: Check out repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: @@ -134,6 +140,7 @@ jobs: id-token: write needs: - build-artifacts + if: ${{ needs.build-artifacts.outputs.has_secrets == 'true' }} strategy: fail-fast: false matrix: @@ -227,7 +234,7 @@ jobs: - name: Generate Docker image tag id: tag run: | - if [[ "${GITHUB_EVENT_NAME}" == "pull_request_target" ]]; then + if [[ "${GITHUB_EVENT_NAME}" == "pull_request" ]]; then IMAGE_TAG=$(echo "${GITHUB_HEAD_REF}" | sed "s#/#-#g") else IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g") @@ -289,11 +296,11 @@ jobs: "GH_PAT=${{ steps.retrieve-secret-pat.outputs.github-pat-bitwarden-devops-bot-repo-scope }}" - name: Install Cosign - if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 - name: Sign image with Cosign - if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' env: DIGEST: ${{ steps.build-docker.outputs.digest }} TAGS: ${{ steps.image-tags.outputs.tags }} @@ -343,7 +350,7 @@ jobs: - name: Make Docker stubs if: | - github.event_name != 'pull_request_target' + github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc') run: | # Set proper setup image based on branch @@ -385,7 +392,7 @@ jobs: - name: Make Docker stub checksums if: | - github.event_name != 'pull_request_target' + github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc') run: | sha256sum docker-stub-US.zip > docker-stub-US-sha256.txt @@ -393,7 +400,7 @@ jobs: - name: Upload Docker stub US artifact if: | - github.event_name != 'pull_request_target' + github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc') uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: @@ -403,7 +410,7 @@ jobs: - name: Upload Docker stub EU artifact if: | - github.event_name != 'pull_request_target' + github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc') uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: @@ -413,7 +420,7 @@ jobs: - name: Upload Docker stub US checksum artifact if: | - github.event_name != 'pull_request_target' + github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc') uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: @@ -423,7 +430,7 @@ jobs: - name: Upload Docker stub EU checksum artifact if: | - github.event_name != 'pull_request_target' + github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc') uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: @@ -552,7 +559,7 @@ jobs: self-host-build: name: Trigger self-host build if: | - github.event_name != 'pull_request_target' + github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc') runs-on: ubuntu-22.04 needs: @@ -587,7 +594,7 @@ jobs: trigger-k8s-deploy: name: Trigger k8s deploy - if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' runs-on: ubuntu-22.04 needs: - build-docker @@ -623,7 +630,8 @@ jobs: trigger-ee-updates: name: Trigger Ephemeral Environment updates if: | - github.event_name == 'pull_request_target' + needs.build-artifacts.outputs.has_secrets == 'true' + && github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'ephemeral-environment') runs-on: ubuntu-24.04 needs: @@ -660,7 +668,8 @@ jobs: name: Trigger Ephemeral Environment Sync needs: trigger-ee-updates if: | - github.event_name == 'pull_request_target' + needs.build-artifacts.outputs.has_secrets == 'true' + && github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'ephemeral-environment') uses: bitwarden/gh-actions/.github/workflows/_ephemeral_environment_manager.yml@main with: @@ -670,7 +679,6 @@ jobs: pull_request_number: ${{ github.event.number }} secrets: inherit - check-failures: name: Check for failures if: always() @@ -686,7 +694,7 @@ jobs: steps: - name: Check if any job failed if: | - github.event_name != 'pull_request_target' + github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc') && contains(needs.*.result, 'failure') run: exit 1 diff --git a/.github/workflows/build_target.yml b/.github/workflows/build_target.yml new file mode 100644 index 0000000000..313446c949 --- /dev/null +++ b/.github/workflows/build_target.yml @@ -0,0 +1,21 @@ +name: Build on PR Target + +on: + pull_request_target: + types: [opened, synchronize] + +defaults: + run: + shell: bash + +jobs: + check-run: + name: Check PR run + uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main + + run-workflow: + name: Run Build on PR Target + needs: check-run + if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} + uses: ./.github/workflows/build.yml + secrets: inherit diff --git a/perf/load/sync.js b/perf/load/sync.js new file mode 100644 index 0000000000..5624803e84 --- /dev/null +++ b/perf/load/sync.js @@ -0,0 +1,90 @@ +import http from "k6/http"; +import { check, fail } from "k6"; +import { authenticate } from "./helpers/auth.js"; + +const IDENTITY_URL = __ENV.IDENTITY_URL; +const API_URL = __ENV.API_URL; +const CLIENT_ID = __ENV.CLIENT_ID; +const AUTH_USERNAME = __ENV.AUTH_USER_EMAIL; +const AUTH_PASSWORD = __ENV.AUTH_USER_PASSWORD_HASH; + +export const options = { + ext: { + loadimpact: { + projectID: 3639465, + name: "Sync", + }, + }, + scenarios: { + constant_load: { + executor: "constant-arrival-rate", + rate: 30, + timeUnit: "1m", // 0.5 requests / second + duration: "10m", + preAllocatedVUs: 5, + }, + ramping_load: { + executor: "ramping-arrival-rate", + startRate: 30, + timeUnit: "1m", // 0.5 requests / second to start + stages: [ + { duration: "30s", target: 30 }, + { duration: "2m", target: 75 }, + { duration: "1m", target: 60 }, + { duration: "2m", target: 100 }, + { duration: "2m", target: 90 }, + { duration: "1m", target: 120 }, + { duration: "30s", target: 150 }, + { duration: "30s", target: 60 }, + { duration: "30s", target: 0 }, + ], + preAllocatedVUs: 20, + }, + }, + thresholds: { + http_req_failed: ["rate<0.01"], + http_req_duration: ["p(95)<1200"], + }, +}; + +export function setup() { + return authenticate(IDENTITY_URL, CLIENT_ID, AUTH_USERNAME, AUTH_PASSWORD); +} + +export default function (data) { + const params = { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + Authorization: `Bearer ${data.access_token}`, + "X-ClientId": CLIENT_ID, + }, + tags: { name: "Sync" }, + }; + + const excludeDomains = Math.random() > 0.5; + + const syncRes = http.get(`${API_URL}/sync?excludeDomains=${excludeDomains}`, params); + if ( + !check(syncRes, { + "sync status is 200": (r) => r.status === 200, + }) + ) { + console.error(`Sync failed with status ${syncRes.status}: ${syncRes.body}`); + fail("sync status code was *not* 200"); + } + + if (syncRes.status === 200) { + const syncJson = syncRes.json(); + + check(syncJson, { + "sync response has profile": (j) => j.profile !== undefined, + "sync response has folders": (j) => Array.isArray(j.folders), + "sync response has collections": (j) => Array.isArray(j.collections), + "sync response has ciphers": (j) => Array.isArray(j.ciphers), + "sync response has policies": (j) => Array.isArray(j.policies), + "sync response has sends": (j) => Array.isArray(j.sends), + "sync response has correct object type": (j) => j.object === "sync" + }); + } +} diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index 3a4d3b2e13..ea360eb744 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -110,12 +110,79 @@ public static class FeatureFlagKeys public const string PolicyRequirements = "pm-14439-policy-requirements"; public const string SsoExternalIdVisibility = "pm-18630-sso-external-id-visibility"; + /* Auth Team */ + public const string PM9112DeviceApprovalPersistence = "pm-9112-device-approval-persistence"; + public const string DuoRedirect = "duo-redirect"; + public const string EmailVerification = "email-verification"; + public const string EmailVerificationDisableTimingDelays = "email-verification-disable-timing-delays"; + public const string DeviceTrustLogging = "pm-8285-device-trust-logging"; + public const string AuthenticatorTwoFactorToken = "authenticator-2fa-token"; + public const string UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh"; + public const string NewDeviceVerification = "new-device-verification"; + public const string SetInitialPasswordRefactor = "pm-16117-set-initial-password-refactor"; + public const string ChangeExistingPasswordRefactor = "pm-16117-change-existing-password-refactor"; + public const string RecoveryCodeLogin = "pm-17128-recovery-code-login"; + + /* Autofill Team */ + public const string IdpAutoSubmitLogin = "idp-auto-submit-login"; + public const string UseTreeWalkerApiForPageDetailsCollection = "use-tree-walker-api-for-page-details-collection"; + public const string InlineMenuFieldQualification = "inline-menu-field-qualification"; + public const string InlineMenuPositioningImprovements = "inline-menu-positioning-improvements"; + public const string SSHAgent = "ssh-agent"; + public const string SSHVersionCheckQAOverride = "ssh-version-check-qa-override"; + public const string GenerateIdentityFillScriptRefactor = "generate-identity-fill-script-refactor"; + public const string DelayFido2PageScriptInitWithinMv2 = "delay-fido2-page-script-init-within-mv2"; + public const string NotificationBarAddLoginImprovements = "notification-bar-add-login-improvements"; + public const string BlockBrowserInjectionsByDomain = "block-browser-injections-by-domain"; + public const string NotificationRefresh = "notification-refresh"; + public const string EnableNewCardCombinedExpiryAutofill = "enable-new-card-combined-expiry-autofill"; + public const string MacOsNativeCredentialSync = "macos-native-credential-sync"; + public const string InlineMenuTotp = "inline-menu-totp"; + + /* Billing Team */ + public const string AC2101UpdateTrialInitiationEmail = "AC-2101-update-trial-initiation-email"; + public const string TrialPayment = "PM-8163-trial-payment"; + public const string ResellerManagedOrgAlert = "PM-15814-alert-owners-of-reseller-managed-orgs"; + public const string UsePricingService = "use-pricing-service"; + public const string P15179_AddExistingOrgsFromProviderPortal = "pm-15179-add-existing-orgs-from-provider-portal"; + public const string PM12276Breadcrumbing = "pm-12276-breadcrumbing-for-business-features"; + public const string PM18794_ProviderPaymentMethod = "pm-18794-provider-payment-method"; + + /* Key Management Team */ + public const string ReturnErrorOnExistingKeypair = "return-error-on-existing-keypair"; + public const string PM4154BulkEncryptionService = "PM-4154-bulk-encryption-service"; + public const string PrivateKeyRegeneration = "pm-12241-private-key-regeneration"; + public const string Argon2Default = "argon2-default"; + public const string UserkeyRotationV2 = "userkey-rotation-v2"; + public const string SSHKeyItemVaultItem = "ssh-key-vault-item"; + + /* Mobile Team */ + public const string NativeCarouselFlow = "native-carousel-flow"; + public const string NativeCreateAccountFlow = "native-create-account-flow"; + public const string AndroidImportLoginsFlow = "import-logins-flow"; + public const string AppReviewPrompt = "app-review-prompt"; + public const string EnablePasswordManagerSyncAndroid = "enable-password-manager-sync-android"; + public const string EnablePasswordManagerSynciOS = "enable-password-manager-sync-ios"; + public const string AndroidMutualTls = "mutual-tls"; + public const string SingleTapPasskeyCreation = "single-tap-passkey-creation"; + public const string SingleTapPasskeyAuthentication = "single-tap-passkey-authentication"; + public const string EnablePMAuthenticatorSync = "enable-pm-bwa-sync"; + public const string PM3503_MobileAnonAddySelfHostAlias = "anon-addy-self-host-alias"; + public const string PM3553_MobileSimpleLoginSelfHostAlias = "simple-login-self-host-alias"; + + /* Platform Team */ + public const string PersistPopupView = "persist-popup-view"; + public const string StorageReseedRefactor = "storage-reseed-refactor"; + public const string WebPush = "web-push"; + public const string RecordInstallationLastActivityDate = "installation-last-activity-date"; + /* Tools Team */ public const string ItemShare = "item-share"; public const string RiskInsightsCriticalApplication = "pm-14466-risk-insights-critical-application"; public const string EnableRiskInsightsNotifications = "enable-risk-insights-notifications"; public const string DesktopSendUIRefresh = "desktop-send-ui-refresh"; public const string ExportAttachments = "export-attachments"; + public const string GeneratorToolsModernization = "generator-tools-modernization"; /* Vault Team */ public const string PM8851_BrowserOnboardingNudge = "pm-8851-browser-onboarding-nudge"; @@ -125,70 +192,7 @@ public static class FeatureFlagKeys public const string VaultBulkManagementAction = "vault-bulk-management-action"; public const string RestrictProviderAccess = "restrict-provider-access"; public const string SecurityTasks = "security-tasks"; - - /* Auth Team */ - public const string PM9112DeviceApprovalPersistence = "pm-9112-device-approval-persistence"; - - /* Key Management Team */ - public const string SSHKeyItemVaultItem = "ssh-key-vault-item"; - public const string SSHAgent = "ssh-agent"; - public const string SSHVersionCheckQAOverride = "ssh-version-check-qa-override"; - public const string Argon2Default = "argon2-default"; - public const string PM4154BulkEncryptionService = "PM-4154-bulk-encryption-service"; - public const string PrivateKeyRegeneration = "pm-12241-private-key-regeneration"; - public const string UserkeyRotationV2 = "userkey-rotation-v2"; - - /* Unsorted */ - public const string ReturnErrorOnExistingKeypair = "return-error-on-existing-keypair"; - public const string UseTreeWalkerApiForPageDetailsCollection = "use-tree-walker-api-for-page-details-collection"; - public const string DuoRedirect = "duo-redirect"; - public const string AC2101UpdateTrialInitiationEmail = "AC-2101-update-trial-initiation-email"; - public const string EmailVerification = "email-verification"; - public const string EmailVerificationDisableTimingDelays = "email-verification-disable-timing-delays"; - public const string InlineMenuFieldQualification = "inline-menu-field-qualification"; - public const string InlineMenuPositioningImprovements = "inline-menu-positioning-improvements"; - public const string DeviceTrustLogging = "pm-8285-device-trust-logging"; - public const string AuthenticatorTwoFactorToken = "authenticator-2fa-token"; - public const string IdpAutoSubmitLogin = "idp-auto-submit-login"; - public const string UnauthenticatedExtensionUIRefresh = "unauth-ui-refresh"; - public const string GenerateIdentityFillScriptRefactor = "generate-identity-fill-script-refactor"; - public const string DelayFido2PageScriptInitWithinMv2 = "delay-fido2-page-script-init-within-mv2"; - public const string NativeCarouselFlow = "native-carousel-flow"; - public const string NativeCreateAccountFlow = "native-create-account-flow"; - public const string NotificationBarAddLoginImprovements = "notification-bar-add-login-improvements"; - public const string BlockBrowserInjectionsByDomain = "block-browser-injections-by-domain"; - public const string NotificationRefresh = "notification-refresh"; - public const string PersistPopupView = "persist-popup-view"; public const string CipherKeyEncryption = "cipher-key-encryption"; - public const string EnableNewCardCombinedExpiryAutofill = "enable-new-card-combined-expiry-autofill"; - public const string StorageReseedRefactor = "storage-reseed-refactor"; - public const string TrialPayment = "PM-8163-trial-payment"; - public const string RemoveServerVersionHeader = "remove-server-version-header"; - public const string GeneratorToolsModernization = "generator-tools-modernization"; - public const string NewDeviceVerification = "new-device-verification"; - public const string MacOsNativeCredentialSync = "macos-native-credential-sync"; - public const string InlineMenuTotp = "inline-menu-totp"; - public const string AppReviewPrompt = "app-review-prompt"; - public const string ResellerManagedOrgAlert = "PM-15814-alert-owners-of-reseller-managed-orgs"; - public const string UsePricingService = "use-pricing-service"; - public const string RecordInstallationLastActivityDate = "installation-last-activity-date"; - public const string EnablePasswordManagerSyncAndroid = "enable-password-manager-sync-android"; - public const string EnablePasswordManagerSynciOS = "enable-password-manager-sync-ios"; - public const string AccountDeprovisioningBanner = "pm-17120-account-deprovisioning-admin-console-banner"; - public const string SingleTapPasskeyCreation = "single-tap-passkey-creation"; - public const string SingleTapPasskeyAuthentication = "single-tap-passkey-authentication"; - public const string EnablePMAuthenticatorSync = "enable-pm-bwa-sync"; - public const string P15179_AddExistingOrgsFromProviderPortal = "pm-15179-add-existing-orgs-from-provider-portal"; - public const string AndroidMutualTls = "mutual-tls"; - public const string RecoveryCodeLogin = "pm-17128-recovery-code-login"; - public const string PM3503_MobileAnonAddySelfHostAlias = "anon-addy-self-host-alias"; - public const string WebPush = "web-push"; - public const string AndroidImportLoginsFlow = "import-logins-flow"; - public const string PM12276Breadcrumbing = "pm-12276-breadcrumbing-for-business-features"; - public const string PM18794_ProviderPaymentMethod = "pm-18794-provider-payment-method"; - public const string PM3553_MobileSimpleLoginSelfHostAlias = "simple-login-self-host-alias"; - public const string SetInitialPasswordRefactor = "pm-16117-set-initial-password-refactor"; - public const string ChangeExistingPasswordRefactor = "pm-16117-change-existing-password-refactor"; public static List GetAllKeys() { diff --git a/src/SharedWeb/Utilities/RequestLoggingMiddleware.cs b/src/SharedWeb/Utilities/RequestLoggingMiddleware.cs index 77efdbfcf0..7f2db27eec 100644 --- a/src/SharedWeb/Utilities/RequestLoggingMiddleware.cs +++ b/src/SharedWeb/Utilities/RequestLoggingMiddleware.cs @@ -1,5 +1,4 @@ using System.Collections; -using Bit.Core; using Bit.Core.Services; using Bit.Core.Settings; using Bit.Core.Utilities; @@ -25,15 +24,6 @@ public sealed class RequestLoggingMiddleware public Task Invoke(HttpContext context, IFeatureService featureService) { - if (!featureService.IsEnabled(FeatureFlagKeys.RemoveServerVersionHeader)) - { - context.Response.OnStarting(() => - { - context.Response.Headers.Append("Server-Version", AssemblyHelpers.GetVersion()); - return Task.CompletedTask; - }); - } - using (_logger.BeginScope( new RequestLogScope(context.GetIpAddress(_globalSettings), GetHeaderValue(context, "user-agent"),