diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 21786339299..c14abd7cd86 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -119,9 +119,9 @@ jobs: run: cargo sort --workspace --check - name: Install cargo-deny - uses: taiki-e/install-action@v2 + uses: taiki-e/install-action@81ee1d48d9194cdcab880cbdc7d36e87d39874cb # v2.62.45 with: - tool: cargo-deny + tool: cargo-deny@0.18.5 - name: Run cargo deny working-directory: ./apps/desktop/desktop_native diff --git a/.github/workflows/sdk-breaking-change-check.yml b/.github/workflows/sdk-breaking-change-check.yml new file mode 100644 index 00000000000..49b91d2d1a1 --- /dev/null +++ b/.github/workflows/sdk-breaking-change-check.yml @@ -0,0 +1,167 @@ +# This workflow runs TypeScript compatibility checks when the SDK is updated. +# Triggered automatically by the SDK repository via repository_dispatch when SDK PRs are created/updated. +name: SDK Breaking Change Check +run-name: "SDK breaking change check (${{ github.event.client_payload.sdk_version }})" +on: + repository_dispatch: + types: [sdk-breaking-change-check] + +permissions: + contents: read + actions: read + id-token: write + +jobs: + type-check: + name: TypeScript compatibility check + runs-on: ubuntu-24.04 + timeout-minutes: 15 + env: + _SOURCE_REPO: ${{ github.event.client_payload.source_repo }} + _SDK_VERSION: ${{ github.event.client_payload.sdk_version }} + _ARTIFACTS_RUN_ID: ${{ github.event.client_payload.artifacts_info.run_id }} + _ARTIFACT_NAME: ${{ github.event.client_payload.artifacts_info.artifact_name }} + _CLIENT_LABEL: ${{ github.event.client_payload.client_label }} + + steps: + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main + with: + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-org-bitwarden + secrets: "BW-GHAPP-ID,BW-GHAPP-KEY" + + - name: Generate GH App token + uses: actions/create-github-app-token@30bf6253fa41bdc8d1501d202ad15287582246b4 # v2.0.3 + id: app-token + with: + app-id: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }} + private-key: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }} + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Validate inputs + run: | + echo "š Validating required client_payload fields..." + + if [ -z "${_SOURCE_REPO}" ] || [ -z "${_SDK_VERSION}" ] || [ -z "${_ARTIFACTS_RUN_ID}" ] || [ -z "${_ARTIFACT_NAME}" ]; then + echo "::error::Missing required client_payload fields" + echo "SOURCE_REPO: ${_SOURCE_REPO}" + echo "SDK_VERSION: ${_SDK_VERSION}" + echo "ARTIFACTS_RUN_ID: ${_ARTIFACTS_RUN_ID}" + echo "ARTIFACT_NAME: ${_ARTIFACT_NAME}" + echo "CLIENT_LABEL: ${_CLIENT_LABEL}" + exit 1 + fi + + echo "ā All required payload fields are present" + - name: Check out clients repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: Get Node Version + id: retrieve-node-version + run: | + NODE_NVMRC=$(cat .nvmrc) + NODE_VERSION=${NODE_NVMRC/v/''} + echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT" + + - name: Set up Node + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + with: + cache: 'npm' + cache-dependency-path: '**/package-lock.json' + node-version: ${{ steps.retrieve-node-version.outputs.node_version }} + + - name: Install Node dependencies + run: | + echo "š¦ Installing Node dependencies with retry logic..." + + RETRY_COUNT=0 + MAX_RETRIES=3 + while [ ${RETRY_COUNT} -lt ${MAX_RETRIES} ]; do + RETRY_COUNT=$((RETRY_COUNT + 1)) + echo "š npm ci attempt ${RETRY_COUNT} of ${MAX_RETRIES}..." + + if npm ci; then + echo "ā npm ci successful" + break + else + echo "ā npm ci attempt ${RETRY_COUNT} failed" + [ ${RETRY_COUNT} -lt ${MAX_RETRIES} ] && sleep 5 + fi + done + + if [ ${RETRY_COUNT} -eq ${MAX_RETRIES} ]; then + echo "::error::npm ci failed after ${MAX_RETRIES} attempts" + exit 1 + fi + + - name: Download SDK artifacts + uses: bitwarden/gh-actions/download-artifacts@main + with: + github_token: ${{ steps.app-token.outputs.token }} + workflow: build-wasm-internal.yml + workflow_conclusion: success + run_id: ${{ env._ARTIFACTS_RUN_ID }} + artifacts: ${{ env._ARTIFACT_NAME }} + repo: ${{ env._SOURCE_REPO }} + path: ./sdk-internal + if_no_artifact_found: fail + + - name: Override SDK using npm link + working-directory: ./ + run: | + echo "š§ Setting up SDK override using npm link..." + echo "š SDK Version: ${_SDK_VERSION}" + echo "š¦ Artifact Source: ${_SOURCE_REPO} run ${_ARTIFACTS_RUN_ID}" + + echo "š SDK package contents:" + ls -la ./sdk-internal/ + + echo "š Creating npm link to SDK package..." + if ! npm link ./sdk-internal; then + echo "::error::Failed to link SDK package" + exit 1 + fi + + - name: Run TypeScript compatibility check + run: | + + echo "š Running TypeScript type checking for ${_CLIENT_LABEL} client with SDK version: ${_SDK_VERSION}" + echo "šÆ Type checking command: npm run test:types" + + # Add GitHub Step Summary output + { + echo "## š TypeScript Compatibility Check (${_CLIENT_LABEL})" + echo "- **Client**: ${_CLIENT_LABEL}" + echo "- **SDK Version**: ${_SDK_VERSION}" + echo "- **Source Repository**: ${_SOURCE_REPO}" + echo "- **Artifacts Run ID**: ${_ARTIFACTS_RUN_ID}" + echo "" + } >> "$GITHUB_STEP_SUMMARY" + + + TYPE_CHECK_START=$(date +%s) + + # Run type check with timeout - exit code determines gh run watch result + if timeout 10m npm run test:types; then + TYPE_CHECK_END=$(date +%s) + TYPE_CHECK_DURATION=$((TYPE_CHECK_END - TYPE_CHECK_START)) + echo "ā TypeScript compilation successful for ${_CLIENT_LABEL} client (${TYPE_CHECK_DURATION}s)" + echo "ā **Result**: TypeScript compilation successful" >> "$GITHUB_STEP_SUMMARY" + echo "No breaking changes detected in ${_CLIENT_LABEL} client for SDK version ${_SDK_VERSION}" >> "$GITHUB_STEP_SUMMARY" + else + TYPE_CHECK_END=$(date +%s) + TYPE_CHECK_DURATION=$((TYPE_CHECK_END - TYPE_CHECK_START)) + echo "ā TypeScript compilation failed for ${_CLIENT_LABEL} client after ${TYPE_CHECK_DURATION}s - breaking changes detected" + echo "ā **Result**: TypeScript compilation failed" >> "$GITHUB_STEP_SUMMARY" + echo "Breaking changes detected in ${_CLIENT_LABEL} client for SDK version ${_SDK_VERSION}" >> "$GITHUB_STEP_SUMMARY" + exit 1 + fi \ No newline at end of file diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html new file mode 100644 index 00000000000..85b8b839182 --- /dev/null +++ b/.storybook/preview-head.html @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/apps/browser/package.json b/apps/browser/package.json index 744b53688b2..82d2ad7ab7a 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/browser", - "version": "2025.10.1", + "version": "2025.11.0", "scripts": { "build": "npm run build:chrome", "build:bit": "npm run build:bit:chrome", diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 50c629e87f6..a8743b0db68 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1523,12 +1523,6 @@ "enableAutoBiometricsPrompt": { "message": "Ask for biometrics on launch" }, - "premiumRequired": { - "message": "Premium required" - }, - "premiumRequiredDesc": { - "message": "A Premium membership is required to use this feature." - }, "authenticationTimeout": { "message": "Authentication timeout" }, @@ -4980,6 +4974,16 @@ } } }, + "defaultLabelWithValue": { + "message": "Default ( $VALUE$ )", + "description": "A label that indicates the default value for a field with the current default value in parentheses.", + "placeholders": { + "value": { + "content": "$1", + "example": "Base domain" + } + } + }, "showMatchDetection": { "message": "Show match detection $WEBSITE$", "placeholders": { @@ -5772,6 +5776,30 @@ "atRiskLoginsSecured": { "message": "Great job securing your at-risk logins!" }, + "upgradeNow": { + "message": "Upgrade now" + }, + "builtInAuthenticator": { + "message": "Built-in authenticator" + }, + "secureFileStorage": { + "message": "Secure file storage" + }, + "emergencyAccess": { + "message": "Emergency access" + }, + "breachMonitoring": { + "message": "Breach monitoring" + }, + "andMoreFeatures": { + "message": "And more!" + }, + "planDescPremium": { + "message": "Complete online security" + }, + "upgradeToPremium": { + "message": "Upgrade to Premium" + }, "settingDisabledByPolicy": { "message": "This setting is disabled by your organization's policy.", "description": "This hint text is displayed when a user setting is disabled due to an organization policy." diff --git a/apps/browser/src/autofill/content/components/buttons/action-button.ts b/apps/browser/src/autofill/content/components/buttons/action-button.ts index b43bed7f96b..73fc1e79ec5 100644 --- a/apps/browser/src/autofill/content/components/buttons/action-button.ts +++ b/apps/browser/src/autofill/content/components/buttons/action-button.ts @@ -68,7 +68,7 @@ const actionButtonStyles = ({ overflow: hidden; text-align: center; text-overflow: ellipsis; - font-weight: 700; + font-weight: 500; ${disabled || isLoading ? ` diff --git a/apps/browser/src/autofill/content/components/constants/styles.ts b/apps/browser/src/autofill/content/components/constants/styles.ts index 55130781808..c1d6228459a 100644 --- a/apps/browser/src/autofill/content/components/constants/styles.ts +++ b/apps/browser/src/autofill/content/components/constants/styles.ts @@ -144,17 +144,17 @@ export const border = { export const typography = { body1: ` line-height: 24px; - font-family: Roboto, sans-serif; + font-family: Inter, sans-serif; font-size: 16px; `, body2: ` line-height: 20px; - font-family: Roboto, sans-serif; + font-family: Inter, sans-serif; font-size: 14px; `, helperMedium: ` line-height: 16px; - font-family: Roboto, sans-serif; + font-family: Inter, sans-serif; font-size: 12px; `, }; diff --git a/apps/browser/src/autofill/content/components/notification/at-risk-password/message.ts b/apps/browser/src/autofill/content/components/notification/at-risk-password/message.ts index 42d4907711d..9c55c1e7e2b 100644 --- a/apps/browser/src/autofill/content/components/notification/at-risk-password/message.ts +++ b/apps/browser/src/autofill/content/components/notification/at-risk-password/message.ts @@ -29,7 +29,7 @@ const baseTextStyles = css` text-align: left; text-overflow: ellipsis; line-height: 24px; - font-family: Roboto, sans-serif; + font-family: Inter, sans-serif; font-size: 16px; `; diff --git a/apps/browser/src/autofill/content/components/notification/confirmation/message.ts b/apps/browser/src/autofill/content/components/notification/confirmation/message.ts index 7f15d882297..36ea9c1f9d6 100644 --- a/apps/browser/src/autofill/content/components/notification/confirmation/message.ts +++ b/apps/browser/src/autofill/content/components/notification/confirmation/message.ts @@ -84,7 +84,7 @@ const baseTextStyles = css` text-align: left; text-overflow: ellipsis; line-height: 24px; - font-family: Roboto, sans-serif; + font-family: Inter, sans-serif; font-size: 16px; `; @@ -115,7 +115,7 @@ const notificationConfirmationButtonTextStyles = (theme: Theme) => css` ${baseTextStyles} color: ${themes[theme].primary[600]}; - font-weight: 700; + font-weight: 500; cursor: pointer; `; diff --git a/apps/browser/src/autofill/content/components/notification/header-message.ts b/apps/browser/src/autofill/content/components/notification/header-message.ts index 47fe8cd2828..2e51d82dd07 100644 --- a/apps/browser/src/autofill/content/components/notification/header-message.ts +++ b/apps/browser/src/autofill/content/components/notification/header-message.ts @@ -19,7 +19,7 @@ const notificationHeaderMessageStyles = (theme: Theme) => css` line-height: 28px; white-space: nowrap; color: ${themes[theme].text.main}; - font-family: Roboto, sans-serif; + font-family: Inter, sans-serif; font-size: 18px; - font-weight: 600; + font-weight: 500; `; diff --git a/apps/browser/src/autofill/content/components/option-selection/option-items.ts b/apps/browser/src/autofill/content/components/option-selection/option-items.ts index ceb72905357..58216b6c1b2 100644 --- a/apps/browser/src/autofill/content/components/option-selection/option-items.ts +++ b/apps/browser/src/autofill/content/components/option-selection/option-items.ts @@ -94,7 +94,7 @@ const optionsLabelStyles = ({ theme }: { theme: Theme }) => css` user-select: none; padding: 0.375rem ${spacing["3"]}; color: ${themes[theme].text.muted}; - font-weight: 600; + font-weight: 500; `; export const optionsMenuItemMaxWidth = 260; diff --git a/apps/browser/src/autofill/content/components/rows/action-row.ts b/apps/browser/src/autofill/content/components/rows/action-row.ts index 0380f91012a..8f13b166156 100644 --- a/apps/browser/src/autofill/content/components/rows/action-row.ts +++ b/apps/browser/src/autofill/content/components/rows/action-row.ts @@ -34,7 +34,7 @@ const actionRowStyles = (theme: Theme) => css` min-height: 40px; text-align: left; color: ${themes[theme].primary["600"]}; - font-weight: 700; + font-weight: 500; > span { display: block; diff --git a/apps/browser/src/autofill/fido2/services/browser-fido2-user-interface.service.ts b/apps/browser/src/autofill/fido2/services/browser-fido2-user-interface.service.ts index 8de48a49a8e..5e523a1a48d 100644 --- a/apps/browser/src/autofill/fido2/services/browser-fido2-user-interface.service.ts +++ b/apps/browser/src/autofill/fido2/services/browser-fido2-user-interface.service.ts @@ -6,7 +6,7 @@ import { filter, firstValueFrom, fromEvent, - fromEventPattern, + map, merge, Observable, Subject, @@ -28,6 +28,7 @@ import { import { Utils } from "@bitwarden/common/platform/misc/utils"; import { BrowserApi } from "../../../platform/browser/browser-api"; +import { fromChromeEvent } from "../../../platform/browser/from-chrome-event"; // FIXME (PM-22628): Popup imports are forbidden in background // eslint-disable-next-line no-restricted-imports import { closeFido2Popout, openFido2Popout } from "../../../vault/popup/utils/vault-popout-window"; @@ -232,12 +233,8 @@ export class BrowserFido2UserInterfaceSession implements Fido2UserInterfaceSessi } }); - this.windowClosed$ = fromEventPattern( - // FIXME: Make sure that is does not cause a memory leak in Safari or use BrowserApi.AddListener - // and test that it doesn't break. Tracking Ticket: https://bitwarden.atlassian.net/browse/PM-4735 - // eslint-disable-next-line no-restricted-syntax - (handler: any) => chrome.windows.onRemoved.addListener(handler), - (handler: any) => chrome.windows.onRemoved.removeListener(handler), + this.windowClosed$ = fromChromeEvent(chrome.windows.onRemoved).pipe( + map(([windowId]) => windowId), ); BrowserFido2UserInterfaceSession.sendMessage({ diff --git a/apps/browser/src/autofill/notification/bar.html b/apps/browser/src/autofill/notification/bar.html index c0b57de612e..8934fe6a031 100644 --- a/apps/browser/src/autofill/notification/bar.html +++ b/apps/browser/src/autofill/notification/bar.html @@ -1,5 +1,4 @@ - - +