Project: certificate-usage · Branch: FHIR-1996_track-ecc-rsa-certificate-usage · Mode: · Model: claude-haiku-4-5-20251001 Stats: 1 user messages, 22 tool calls, tools used: Glob, Bash, Read, Grep. Conversation Turn 1 — User I need to understand the current certificate tracking implementation to plan a simplification where we log the raw JWA string instead of mapping it. Please explore and document: 1. JWSUtils.deriveJWAFromCertificate in src/modules/gematik-crypto: - What does this function return? (e.g., "BP256R1", "RS256", "ES256") - Where is it implemented? 2. CertificateAnalyzer usage: - Where is CertificateAnalyzer.analyzeCertificate currently called? - What does the caller expect to receive? - Check both production code and tests 3. JWAMapper dependencies: - Is JWAMapper imported or used anywhere else besides adapter.ts? - Are there any other references to the CertificateInfo type? 4. Datadog tracking data format: - In src/modules/kbv-ti-connect/main/ti-connect.ts, how is the certificate data sent to Datadog? - What fields are currently logged? (certificateType, curveName, etc.) Focus on understanding the current flow and what needs to change. Be thorough - check imports, exports, and test files. Turn 1 — Assistant I'll explore the codebase to understand the certificate tracking implementation. Let me start with a comprehensive search. Tools used: - Glob: src/modules/gematik-crypto//.ts Tools used: - Glob: src/modules/kbv-ti-connect//.ts Tools used: - Bash: find /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage -type f -name ".ts" | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/tools/cli-modules/vitest.config.ts /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/tools/cli-modules/src/types.ts /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/tools/cli-modules/src/__tests__/setup.test.ts /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/tools/cli-modules/src/ddv-modules.ts /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-cert …(truncated, 1758 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/constants/events.ts /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/constants/module.ts /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/index.ts /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/main/__tests__/cryptoEngine.test.ts /Users/USER/wor …(truncated, 10443 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/constants/events.ts /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/constants/module.ts /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/constants/types.ts /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/helpers/__tests__/cardBinaryParser.test.t …(truncated, 13539 more chars) Now let me search for the specific files and functions mentioned: Tools used: - Read: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/node/jose/JWSUtils.ts Tool results: → result (ok): 1→import { Certificate } from 'pkijs' 2→import as Asn1 from 'asn1js' 3→ 4→enum JWAlgorithms { 5→ HMAC = 'HS', // There is no MAC expected, so keeping here for the compatibility 6→ 'RSASSA-PKCS1-v1_5' = 'RS', 7→ ECDSA = 'ES', 8→ 'RSASSA-PSS' = 'PS', 9→} 10→ 11→type JWSAlgorithms = 'HMAC' | 'RSASSA-PKCS1-v1_5' | 'ECDSA' | 'RSASSA-PSS' 12→export class JWSUtils { 13→ static concatenateECDSASignature(signature: string, outputLength: numbe …(truncated, 5381 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/utils/jwaMapper.ts Tool results: → result (ok): 1→/ 2→ Maps JWA (JSON Web Algorithm) strings to certificate tracking format 3→ Used to convert JWSUtils output to Datadog tracking events 4→ / 5→/ 6→ Certificate information extracted from JWA algorithm 7→ @property certificateType - The type of certificate: ECC (Elliptic Curve Cryptography) or RSA 8→ @property curveName - The elliptic curve name (e.g., 'brainpoolP256r1', 'P-256'). 9→ Only present for ECC certificates …(truncated, 2162 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/main/ti-connect.ts Tool results: → result (ok): 1→import { ipcManager } from '@core/ipc-manager' 2→import { sendPreferences } from '@core/app/main/helpers/preferences-helper' 3→import { TrackingEvent } from '@core/monitoring' 4→ 5→import { CertificateAnalyzer } from '@module/gematik-crypto' 6→import { TiEnvRepository } from '@module/gematik-ti-environment/services/tiEnvRepository' 7→import { kbvTiConnectLogger } from '@module/kbv-ti-connect/services/logger' 8→import tiConnect from '@module/kbv-ti-connect/ser …(truncated, 9718 more chars) Now let me search for CertificateAnalyzer and where it's used: Tools used: - Grep: class CertificateAnalyzer in /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto Tools used: - Grep: CertificateAnalyzer in /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto Tool results: → result (ok): Found 1 file src/modules/gematik-crypto/services/crypto-adapter/adapter.ts Tool results: → result (ok): Found 1 file src/modules/gematik-crypto/services/crypto-adapter/adapter.ts Tools used: - Grep: JWAMapper in /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules Tool results: → result (ok): Found 4 files src/modules/gematik-crypto/services/utils/__tests__/jwaMapper.test.ts src/modules/gematik-crypto/services/utils/jwaMapper.ts src/modules/gematik-crypto/services/crypto-adapter/adapter.ts src/modules/gematik-crypto/index.ts Let me read the adapter file to see the CertificateAnalyzer implementation: Tools used: - Read: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/crypto-adapter/adapter.ts Tool results: → result (ok): 1→import { X509Certificate } from 'node:crypto' 2→import { JWE, JWS as NodeJWS } from '@doctolib/node-jose' 3→import { IOptions } from 'soap' 4→ 5→import { CryptoEngine } from '@module/gematik-crypto/services/crypto-adapter/crypto-engine' 6→import { CustomSoapClientOptions } from '@module/gematik-crypto/services/node/tls/customSoapClientOptions' 7→import { HttpsFetch as DoctoCryptHttpsFetch } from '@module/gematik-crypto/services/docto-crypt/tls/httpsFetch' 8→i …(truncated, 7958 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/index.ts Tool results: → result (ok): 1→export { DoctoCryptExecutor } from './services/docto-crypt' 2→ 3→export from './services/crypto-adapter' 4→export { Pkcs12Adapter as Pkcs12 } from '@module/gematik-crypto/services/crypto-adapter/pkcs12Adapter' 5→export { KeystoreFile, type DialogOptionProperties } from '@module/gematik-crypto/services/node/keystore/keystoreFile' 6→export { 7→ LdapAdapter as LdapClient, 8→ type SearchOptions, 9→} from '@module/gematik-crypto/services/crypto-adapter/ld …(truncated, 528 more chars) Now let me check the tests to understand usage better: Tools used: - Read: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/utils/__tests__/jwaMapper.test.ts Tool results: → result (ok): 1→import { describe, expect, it } from 'vitest' 2→ 3→import { JWAMapper } from '../jwaMapper' 4→ 5→describe('JWAMapper', () => { 6→ describe('.mapJWAToCertificateInfo', () => { 7→ it('identifies RSA algorithms (RS family)', () => { 8→ expect(JWAMapper.mapJWAToCertificateInfo('RS256')).toEqual({ 9→ certificateType: 'RSA', 10→ }) 11→ expect(JWAMapper.mapJWAToCertificateInfo('RS384')).toEqual({ 12→ certificateType: …(truncated, 2173 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/node/jose/__tests_electron__/JWSUtils.test.ts Tool results: → result (ok): 1→import { JWSUtils } from '@module/gematik-crypto/services/node/jose/JWSUtils' 2→ 3→describe('JWSUtils', () => { 4→ afterEach(() => { 5→ vi.clearAllMocks() 6→ }) 7→ 8→ const rsaCertificate = 9→ 'MIIEljCCA36gAwIBAgIHAWMLSsvZvzANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UE' + 10→ 'BhMCREUxHzAdBgNVBAoMFmdlbWF0aWsgR21iSCBOT1QtVkFMSUQxMjAwBgNVBAsM' + 11→ 'KUtvbXBvbmVudGVuLUNBIGRlciBUZWxlbWF0aWtpbmZyYXN0cnVrdHVyMSAwHgYD' + 12→ 'VQQDDBdHRU0uS09 …(truncated, 13415 more chars) Now let me check where JWAMapper is imported and used: Tools used: - Bash: grep -r "JWAMapper\|CertificateInfo" /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src --include=".ts" | grep -v test | grep -v ".test.ts" Tools used: - Bash: grep -r "CertificateAnalyzer" /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src --include=".ts" | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/core/network/main/debug-menu/helpers/electron-helpers.ts:import { CertificateInfo } from '../../../services/network-environment-diagnostic' /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/core/network/main/debug-menu/helpers/electron-helpers.ts: getPeerCertificate?: () => CertificateInfo | undefined /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/core/network/ma …(truncated, 1863 more chars) Tool results: → result (ok): /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/main/__tests__/ti-connect.test.ts:import { CertificateAnalyzer } from '@module/gematik-crypto' /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/main/__tests__/ti-connect.test.ts: CertificateAnalyzer: { /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/main/__tests__/ti-connect.test.ts: mockAnal …(truncated, 614 more chars) Let me check the test file to see how CertificateAnalyzer is used: Tools used: - Read: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/main/__tests__/ti-connect.test.ts (1–150) Tool results: → result (ok): 1→import { Mock } from 'vitest' 2→ 3→import { ipcManager } from '@core/ipc-manager' 4→import { sendPreferences } from '@core/app/main/helpers/preferences-helper' 5→import { sendCustomTrackingEventToObservability, TrackingEvent } from '@core/monitoring' 6→ 7→import { CertificateAnalyzer } from '@module/gematik-crypto' 8→import { TiEnvRepository } from '@module/gematik-ti-environment/services/tiEnvRepository' 9→import { TiEnvValueSet } from '@module/gematik- …(truncated, 5664 more chars) Let me continue reading the test file: Tools used: - Read: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/main/__tests__/ti-connect.test.ts (150–400) Tool results: → result (ok): 150→ mockSendPreferences = vi.mocked(sendPreferences) 151→ mockTiConnectCallApi = vi.mocked(tiConnect.callApi) 152→ mockDecryptKeyStore = vi.mocked(decryptKeyStore) 153→ mockGetNewKeyStore = vi.mocked(getNewKeyStore) 154→ mockReadKeyStoreFromFile = vi.mocked(readKeyStoreFromFile) 155→ mockExtraLogParser = vi.mocked(extraLogParser) 156→ mockGetNestedKeys = vi.mocked(getNestedKeys) 157→ mockSendCustomTrackingEventToObservability = vi.mocked(sendCustomTr …(truncated, 11217 more chars) Let me continue and look for the test that uses CertificateAnalyzer: Tools used: - Read: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/main/__tests__/ti-connect.test.ts (400–600) Tool results: → result (ok): 400→ 401→ expect(TiConnectRepository.settings?.useConnectorContextFromElectronSettings).toBe(true) 402→ expect(mockSendPreferences).toHaveBeenCalled() 403→ 404→ expect(kbvTiConnectLogger.info).toHaveBeenCalledWith('TiConnectModule', { 405→ extra: 'mocked-log-string', 406→ }) 407→ expect(mockExtraLogParser).toHaveBeenCalledWith({ 408→ traceId: 'unknown', 409→ functionName: 'onTiConnectChangeModeListener', 410→ oper …(truncated, 9095 more chars) Let me search for any other references to understand the data flow better: Tools used: - Bash: grep -r "deriveJWAFromCertificate\|getJWA" /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src --include=".ts" | grep -v test Tool results: → result (ok): /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-idp-authentication/services/IdpChallenge.ts: const alg = await JWSUtils.getJWA( /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/crypto-adapter/adapter.ts: const jwa = await JWSUtils.deriveJWAFromCertificate(certificate) /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/node/jose/J …(truncated, 622 more chars) Tools used: - Bash: grep -r "mapJWAToCertificateInfo" /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src --include=".ts" | grep -v test Tool results: → result (ok): /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/utils/jwaMapper.ts: static mapJWAToCertificateInfo(jwa: string): CertificateInfo { /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/crypto-adapter/adapter.ts: return JWAMapper.mapJWAToCertificateInfo(jwa) Let me check the IdpChallenge to see how getJWA is used: Tools used: - Read: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-idp-authentication/services/IdpChallenge.ts (1–100) Tool results: → result (ok): 1→import { createHash, randomBytes } from 'node:crypto' 2→ 3→import ConfigurationService from '@module/kbv-ti-connect/services/configuration-service' 4→import { SIG_TYPE_ECC } from '@module/kbv-ti-connect/services/types' 5→import { signWithCardCertificate, readCardCertificate } from '@module/gematik-idp-authentication/services/connector' 6→import type { 7→ ChallengeJwt, 8→ CodeVerifierAndChallenge, 9→ SignatureVerificationAndEncryptionKey, 10→} from …(truncated, 4456 more chars) Perfect! Now let me create a comprehensive document summarizing the findings. Let me also check the recent commits to see what was changed: Tools used: - Bash: git log --oneline -15 Tool results: → result (ok): 5e9eb7ad9 refactor(FHIR-1996): Fix PR review issues for safe error handling and RSA certificate mapping 8c23f5c41 Merge branch 'master' of https://github.com/doctolib/doctolib-pro-desktop into FHIR-1996_track-ecc-rsa-certificate-usage bb10862aa refactor(FHIR-1996): Remove unused TiCertificateConfigured tracking event 78da4fa09 refactor(FHIR-1996): Fix import consistency and enhance test coverage e7aa76c8a feat(DITTO-4078): logging with lazy initialization and error aggregation (#6980) 9e54598a3 …(truncated, 853 more chars) Perfect! Now I have all the information needed. Let me create a comprehensive exploration report. Certificate Tracking Implementation - Comprehensive Exploration Report Based on my thorough exploration of the codebase, here's the complete understanding of the current certificate tracking implementation: --- 1. JWSUtils.deriveJWAFromCertificate - Location & Output File: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/node/jose/JWSUtils.ts Function Signature: static async deriveJWAFromCertificate(certificate: string): Promise What it returns: The function returns a JWA (JSON Web Algorithm) string representing the algorithm used by the certificate: - RSA algorithms: 'RS256', 'RS384', 'RS512', 'PS256', 'PS384', 'PS512' - ECC/ECDSA algorithms: 'ES256', 'ES384', 'ES512' - German TI standard (Brainpool): 'BP256R1' - Fallback: 'none' (when parsing fails or no algorithm found) Implementation Details (lines 83-118): - Uses pkijs library to parse base64-encoded X.509 certificates - Analyzes the public key algorithm from the certificate - For RSA keys: calls selectJWA with algorithm name and hash function (e.g., "SHA-256" → "256") - For ECC keys: calls selectJWA with algorithm name and named curve - Has special handling for BrainpoolP256R1 curve (OID 1.3.36.3.3.2.8.1.1.7) due to unsupported algorithm exception - Pure JavaScript implementation using pkijs (independent of crypto engine choice) --- 2. CertificateAnalyzer Usage File: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/crypto-adapter/adapter.ts Implementation (lines 156-171): export class CertificateAnalyzer { static async analyzeCertificate(certificate: string): Promise { const jwa = await JWSUtils.deriveJWAFromCertificate(certificate) return JWAMapper.mapJWAToCertificateInfo(jwa) } } Where it's called: 1. Production Code - Main Usage: - /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/main/ti-connect.ts (lines 104-137) - Called in trackCertificateType() function after keystore decryption - Fire-and-forget pattern - wrapped in try-catch that logs errors without throwing 2. Test Code: - /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/main/__tests__/ti-connect.test.ts - Mocked for testing certificate tracking behavior - Tests verify certificate info is sent to Datadog observability What the caller expects to receive: interface CertificateInfo { certificateType: 'ECC' | 'RSA' curveName?: string // Only present for ECC certificates } Example returns: - ECC: { certificateType: 'ECC', curveName: 'brainpoolP256r1' } - RSA: { certificateType: 'RSA' } (no curve) --- 3. JWAMapper Dependencies & Usage File: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/services/utils/jwaMapper.ts Imports/Exports in the codebase: 1. Exported from: - /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/gematik-crypto/index.ts (line 10) export { JWAMapper, type CertificateInfo as CertificateInfoType } from './services/utils/jwaMapper' 2. Used in: - adapter.ts - CertificateAnalyzer uses JWAMapper.mapJWAToCertificateInfo() - Test file: jwaMapper.test.ts - comprehensive unit tests 3. CertificateInfo type references: - adapter.ts: imported as CertificateInfoType - jwaMapper.ts: defined as CertificateInfo - index.ts: re-exported as CertificateInfoType - ti-connect.ts: implicitly used (returns from CertificateAnalyzer) Key characteristic: JWAMapper is ONLY used internally within the crypto-adapter module. It's NOT imported or used anywhere else in the codebase besides: - adapter.ts (where CertificateAnalyzer uses it) - index.ts (for re-export) - Test files --- 4. Datadog Tracking Data Format File: /Users/USER/workspace/doctolib/FHIR-1996_track-ecc-rsa-certificate-usage/src/modules/kbv-ti-connect/main/ti-connect.ts Location: trackCertificateType() function (lines 104-137) Current data sent to Datadog: // Success case (lines 114-119) { certificateType: certificateInfo.certificateType, // "ECC" or "RSA" curveName: certificateInfo.curveName, // e.g., "brainpoolP256r1" or undefined tiEnvironment: tiEnvironment, // e.g., "RU", "PU", "UNKNOWN" } // Error case (lines 129-135) { tiEnvironment: tiEnvironment, error: true, errorMessage: error.message, errorName: error.name, } Observability Context: - Sent via tiConnectEventObservability.send() - Event type: TrackingEvent.KbvTiConnect - Wrapped in extra metadata: { traceId: string, functionName: 'onTiConnectDecryptKeyStoreListener', operation: 'read', direction: 'output', data: JSON.stringify({...}) } Test Verification (lines 515-585): Tests confirm that: - CertificateAnalyzer.analyzeCertificate() is called with the decrypted certificate - Certificate info (type and curve) is tracked - Different TI environments are included - Errors are tracked with error details - RSA certificates log without curveName --- 5. Call Flow Diagram onTiConnectDecryptKeyStoreListener (ti-connect.ts:139) ↓ readKeyStoreFromFile() + decryptKeyStore() ↓ trackCertificateType(cert, traceId) (ti-connect.ts:104) ↓ CertificateAnalyzer.analyzeCertificate(cert) (adapter.ts:167) ↓ JWSUtils.deriveJWAFromCertificate(cert) (JWSUtils.ts:83) ↓ Returns: JWA string ("RS256", "ES256", "BP256R1", "none", etc.) ↓ JWAMapper.mapJWAToCertificateInfo(jwa) (jwaMapper.ts:22) ↓ Returns: { certificateType: 'ECC'|'RSA', curveName?: string } ↓ tiConnectEventObservability.send(data) → Datadog --- 6. Key Dependencies & Imports CertificateAnalyzer needs: - JWSUtils (JWA derivation) - JWAMapper (JWA → CertificateInfo conversion) - pkijs library (for X.509 cert parsing) TiConnect tracking needs: - CertificateAnalyzer (from @module/gematik-crypto) - TiEnvRepository (for TI environment info) - TrackingEvent (from @core/monitoring) - tiConnectEventObservability (observability helper) --- 7. Simplification Implications Current approach: 1. Derive JWA string from certificate 2. Map JWA to structured CertificateInfo (certificateType + curveName) 3. Send structured data to Datadog Simplification (log raw JWA string): - Remove JWAMapper entirely - CertificateAnalyzer would return the JWA string directly - Datadog would receive: { jwa: "RS256" } or { jwa: "BP256R1" } instead of { certificateType: "RSA" } - Impact: - Removes one layer of mapping/abstraction - Changes what's logged to Datadog (raw algorithm vs semantic meaning) - JWA strings are already standardized (RFC 7518) - Loses the semantic "certificateType" and "curveName" distinction --- Summary Table | Component | Location | Returns | Current Behavior | |-----------|----------|---------|------------------| | JWSUtils.deriveJWAFromCertificate | JWSUtils.ts:83 | JWA string ("RS256", "ES256", "BP256R1", "none") | Parses X.509 cert using pkijs | | JWAMapper.mapJWAToCertificateInfo | jwaMapper.ts:22 | {certificateType: 'ECC'\|'RSA', curveName?: string} | Maps JWA to semantic info | | CertificateAnalyzer.analyzeCertificate | adapter.ts:167 | {certificateType, curveName?} | Combines JWSUtils + JWAMapper | | trackCertificateType | ti-connect.ts:104 | void (sends to Datadog) | Fire-and-forget with error handling | This should give you everyth …(truncated, 40 more chars)