feat(config): centralized configuration [IDE-1786]#1162
feat(config): centralized configuration [IDE-1786]#1162bastiandoetsch wants to merge 124 commits intomainfrom
Conversation
… [IDE-1786] Phase 2.2 of folder config refactoring: wire snyk-ls to use GAF ConfigResolver with prefix-key-based configuration. New files: - RegisterAllConfigurations: 31 settings with pflag annotations - MigrateSettingsToLocalFields: convert legacy Settings to LocalConfigField - ConfigResolver GAF delegation tests (FC-046 through FC-058) Key changes: - ConfigResolver delegates to GAF ConfigResolver when wired - SetGlobalSettings stores reference; SyncGlobalSettingsToConfiguration writes reconciled values after Config is updated - FolderConfig dual-writes UserOverrides to GAF prefix keys - LDX-Sync adapter dual-writes remote config to GAF prefix keys - clearLockedOverridesFromFolderConfigs clears GAF UserFolderKey - batchClearOrgScopedOverridesOnGlobalChange uses ModifyStoredConfig for atomic read-modify-write with mutex protection - processSingleLspFolderConfig sets fc.conf for dual-write - IsSnykSecretsEnabledForFolder delegates to isSettingEnabledForFolder - Compile-time ConfigResolverInterface satisfaction check - Remove enforced precedence from resolution (locked + regular only) - cmp.Equal uses cmpopts.IgnoreUnexported for FolderConfig
Replace builder.WriteString(fmt.Sprintf(...)) with fmt.Fprintf(&builder, ...) as suggested by golangci-lint.
This comment was marked as outdated.
This comment was marked as outdated.
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
…nners [IDE-1786] Phase 2.3 of folder config refactoring: inject ConfigResolver into scanner context via enrichContextAndLogger, and migrate all four scanners (OSS, Code, IaC, Secrets) to read ConfigResolver from context with fallback to struct field. - Add DepConfigResolver constant and context helpers (ConfigResolverFromContext, NewContextWithConfigResolver) in internal/context - Inject ConfigResolver into deps map in DelegatingConcurrentScanner - Add getConfigResolver(ctx) helper to each scanner with context-first fallback - Generate ConfigResolverInterface mock via gomock - Tests FC-060 through FC-068 cover injection, retrieval, and fallback paths
…786] Replace NullableField with *LocalConfigField in LSP wire protocol. Unify $/snyk.folderConfigs into $/snyk.configuration using map-based ConfigSetting for both global and per-folder settings. Refactor ConfigResolver to delegate to GAF resolver for all settings except folder metadata (AutoDeterminedOrg, LocalBranches) which are read directly from FolderMetadataKey. Remove legacy fallback paths. Update SyncToConfiguration to correctly write user-settable folder settings to UserFolderKey and LS-enriched metadata to FolderMetadataKey. Migrate scanners (base_scan, pre_scan_command, cli_scanner) to use ConfigResolver for all configurable values instead of direct struct field access.
…ve migration code [IDE-1786] - Move SastSettings from FolderConfig struct to GAF configuration with Get/SetSastSettings helpers - Replace hardcoded persistence lists with dynamic Set+PersistInStorage via SetFolderUserSetting and SetFolderMetadataSetting helpers - Remove all legacy migration code: legacyFolderConfigJSON, legacyStoredConfig, MigrateLegacyFolderConfig, RegisterFolderPersistence, getStoredConfigForMigration, MigrateFolderConfigOrgSettings, OrgMigratedFromGlobalConfig flag, settings_migration.go - Fix updateFolderOrgIfNeeded: check orgSettingsChanged before global org inheritance to prevent overwriting explicit user org changes - Rename tests and comments to remove stale migration references - Add precedence and scanner precedence smoke tests - Add config resolver delegation tests
Move cliPath, Insecure, AdditionalOssParameters, and ReleaseChannel fields from CliSettings struct directly into Config. Promote all CliSettings methods (Installed, IsPathDefined, Path, SetPath, DefaultBinaryInstallPath) to Config methods with Cli prefix. Remove CliSettings struct, NewCliSettings constructor, CliSettings() accessor, SetCliSettings() mutator, and the dedicated cliPathAccessMutex (Config's existing mutex provides thread safety). Update all ~80 call sites across 30 files from c.CliSettings().X() to c.X() pattern.
This comment was marked as outdated.
This comment was marked as outdated.
Document the complete configuration architecture including: - Configuration scopes (machine, org, folder) with prefix key storage - Flag registration via pflag.FlagSet with annotations - Precedence resolution rules per scope (locked > user > remote > default) - Effective organization resolution flow - LDX-Sync remote configuration with 4 sync triggers - Locked field enforcement (sync-time clearing + edit-time rejection) - IDE ↔ LS protocol with ConfigSetting wire type - FolderConfig thin wrapper architecture - Persistence via SetFolderUserSetting/SetFolderMetadataSetting helpers Include mermaid sequence diagrams for all major flows: - Machine and org scope precedence resolution - Effective org determination - LDX-Sync trigger lifecycle - Locked field enforcement - IDE→LS and LS→IDE configuration exchange
…n [IDE-1786] Migrate boolean, string, and integer Config struct fields to use GAF Configuration as the backing store via UserGlobalKey prefix keys. Config getters/setters now delegate to gafGetBool/gafGetString/gafGetInt helpers, removing the need for struct fields and mutex locking (GAF is thread-safe). Key changes: - Add gafConf/gafGetBool/gafSetBool/gafGetString/gafSetString/gafGetInt/gafSetInt helper methods on Config for type-safe GAF access - Register flags via RegisterAllConfigurations in newConfig() so defaults are available immediately after engine init - Migrate 16 boolean fields (product toggles, feature flags, proxy settings) - Migrate 6 string fields (cliBaseDownloadURL, proxy*, authenticationMethod, etc.) - Migrate 2 integer fields (hoverVerbosity, riskScoreThreshold) - Skip Phase 1 raw writes in processConfigSettings for migrated settings (apply functions write validated values via setters) - Update SetUpEngineMock to copy GAF settings when replacing engine - Replace MockConfiguration with real configuration.NewWithOpts() in tests for simpler, more robust test setup
…ated settings [IDE-1786] Now that boolean and int settings are backed by GAF UserGlobalKey, the ConfigResolver's fallback to ConfigProvider methods is redundant. GetValue already resolves through the full prefix key chain including UserGlobalKey defaults. Key changes: - Shrink ConfigProvider interface to only FilterSeverity + IssueViewOptions (composite types still on Config struct) - Replace isSettingEnabledForFolder(fallback) with GetBool delegation - Remove r.c nil guards from methods that no longer access ConfigProvider - Add DefaultConfigResolver test helper with proper prefix key wiring - Register pflag flags in SetUpEngineMock so GAF ConfigResolver has scope metadata for resolution - Update all defaultResolver functions in tests to use proper wiring - Replace MockConfiguration with real configuration.NewWithOpts() in tests
This comment was marked as outdated.
This comment was marked as outdated.
…age ordering, clean up dead code [IDE-1786]
- Define 27 new Setting* constants for all internal configuration keys
(device_id, offline, format, trusted_folders, etc.) in ldx_sync_config.go
- Replace all raw strings in UserGlobalKey("...") calls across 50+ files
with the corresponding types.Setting* constants
- Fix PersistInStorage ordering: must be called BEFORE Set, not after,
in all folder config write paths (5 files)
- Remove stale ConfigProvider mock expectations (FilterSeverity,
IssueViewOptions) after interface was emptied
- Remove dead StoredConfig struct, FolderConfigsParam, and related
serialization code from xdg.go
- Remove 125+ thin getter/setter wrapper methods from Config struct
- Extract 9 business logic methods into standalone package-level functions
- Increase test timeout from 45m to 60m for smoke test suite
This comment was marked as outdated.
This comment was marked as outdated.
…ckFileName, add engine/conf context helpers [IDE-1786] Phase 3.5 completion: - Inline SetConfigFile into main.go and ls_extension/main.go, remove method - Extract SetOrganization to standalone function, update ~35 callers across 17 files - Inline CLIDownloadLockFileName instance method, update 6 callers to use standalone Phase 3.6.1: - Add Engine and Configuration context helpers to internal/context (NewContextWithEngine/EngineFromContext, NewContextWithConfiguration/ConfigurationFromContext) - Add DepEngine and DepConfiguration dependency keys - Table-driven tests for all dependency-map context helpers (Workspace, Engine, Configuration)
…te NewConfigResolver signature [IDE-1786] Remove all references to LDXSyncConfigCache from test files across the codebase. Update all NewConfigResolver(cache, logger) calls to NewConfigResolver(logger). Replace cache-based org storage with GAF-native equivalents: - cache.SetOrgConfig -> WriteOrgConfigToConfiguration - cache.SetFolderOrg -> SetAutoDeterminedOrg - cache.GetOrgIdForFolder -> ReadFolderConfigSnapshot.AutoDeterminedOrg Fix Test_processResults_ShouldCountSeverityByProduct: create folder after SetUpEngineMock so f.conf and workspace storage use the same configuration. Update Test_RefreshConfigFromLdxSync_EmptyFolderPath: document that empty paths are skipped by ReadFolderConfigSnapshot (PathKey returns empty string leading to early return).
This comment was marked as outdated.
This comment was marked as outdated.
… smoke tests [IDE-1786] - Replace time.Sleep with require.Never in oss_test.go for Test_scheduleNewScanWithProductDisabled_NoScanRun and Test_scheduleNewScan_ContextCancelledAfterScanScheduled_NoScanRun - Replace time.Sleep with require.Never in precedence_smoke_test.go for Test_SmokeScanPrecedence_AllDisabled_NoScansRun and Test_SmokeScanPrecedence_UserOverrideDisablesProduct - Use TempDirWithRetry for storage directory in redirectConfigAndDataHome to prevent flaky TempDir cleanup failures when goroutines outlive tests - Call c.SetStorage(s) in redirectConfigAndDataHome so c.Storage() is non-nil, fixing nil pointer panic in NewOAuthProvider during OAuth smoke tests (Test_InvalidExpiredCredentialsSendMessageRequest)
…DE-1786] Phase 3.6.2: Update server.Start signature - Change Start(c *config.Config) -> Start(engine workflow.Engine) - Derive conf from engine.GetConfiguration() inside Start - Derive logger from engine.GetLogger() after ConfigureLogging sets it - Update jrpc2 ServerOptions logger closures to use engine.GetLogger() - Use config.CurrentConfig().ConfigureLogging(srv) as interim bridge until Phase 3.6.7 extracts token scrubbing from Config - Update main.go and ls_extension/main.go callers to pass c.Engine()
…ow.Engine [IDE-1786] Replace *config.Config parameter with workflow.Engine across multiple packages as part of Phase 3.6.6 of the config refactoring (remove LDXSyncConfigCache). Changes include: - infrastructure/code: migrate code_html.go, sarif_utils.go, ai_fix_handler.go, sast_local_engine.go, snyk_code_http_client.go, autofix.go, code.go - infrastructure/oss: migrate oss_html.go (NewHtmlRenderer) - infrastructure/secrets: migrate secrets_html.go (NewHtmlRenderer) - domain/ide/command: replace config.CurrentConfig() with cmd.engine in code_fix_apply_edit.go, code_fix_diffs.go, code_fix_feedback.go, navigate_to_range.go, generate_issue_description.go and all other command files - application/server/configuration.go: thread engine through updateFolderOrgIfNeeded - Update all callers and test files to pass engine/configuration instead of *config.Config
…ndant calls [IDE-1786] Introduce types.GetGlobalOrganization(conf) to enforce correct precedence (UserGlobalKey first, then configuration.ORGANIZATION fallback), replacing 16 direct conf.GetString(configuration.ORGANIZATION) reads across 9 files. Add types.SettingConfigFileLegacy constant to replace magic "configfile" string in main.go, ls_extension/main.go, and config.go. Eliminate redundant engine.GetConfiguration()/GetLogger() calls in ~27 locations by caching conf and logger at function entry and passing to helpers.
Create types.TokenService interface and TokenServiceImpl to encapsulate token lifecycle: writing to GAF configuration, adding scrub terms to the logger, and notifying change listeners. Update NewAuthenticationService and NewDelegatingScanner constructors to accept TokenService as a dependency. Auth service uses tokenService.SetToken() directly instead of config.SetToken(), and scanner uses tokenService.TokenChangesChannel() instead of config.TokenChangesChannel(). Config.SetToken/TokenChangesChannel now delegate to the internal TokenService; these will be removed when Config struct is deleted (3.6.8).
…alone functions [IDE-1786] Create SetupLogging(engine, tokenService, server) as standalone replacement for Config.ConfigureLogging(). Manage log file and scrubbing writer as package-level state instead of Config fields. Add types.IsDefaultEnvReady(conf) and types.WaitForDefaultEnv(ctx, conf) backed by a channel stored in GAF configuration under SettingDefaultEnvReadyChannel. Replace config.CurrentConfig().IsDefaultEnvReady() call in configuration.go with the standalone function. Add DisableFileLogging(conf, logger) as standalone replacement for Config.DisableLoggingToFile(). Remove unused logFile field from Config.
| key := configresolver.FolderMetadataKey(dst, name) | ||
| conf.PersistInStorage(key) | ||
| conf.Set(key, v) | ||
| } |
There was a problem hiding this comment.
why would we need to persist config for base scan ?
| for _, name := range userSettings { | ||
| if v := conf.Get(configresolver.UserFolderKey(src, name)); v != nil { | ||
| key := configresolver.UserFolderKey(dst, name) | ||
| conf.PersistInStorage(key) |
There was a problem hiding this comment.
Persist is now being called in many places, it should be centralized, it can be done on init and maybe when a folder is trusted
There was a problem hiding this comment.
PersistInStorage needs to be called once per field per configuration (if a field should be written to storage). If it's not called, the field is ephemeral.
| userSettings := []string{ | ||
| SettingBaseBranch, SettingReferenceBranch, SettingAdditionalParameters, | ||
| SettingAdditionalEnvironment, SettingReferenceFolder, SettingScanCommandConfig, | ||
| SettingPreferredOrg, SettingOrgSetByUser, | ||
| } |
There was a problem hiding this comment.
we shouldn't do this, instead load config names via scope and iterate through them
| gafConfiguration := conf | ||
|
|
||
| fs := pflag.NewFlagSet("snyk-ls-config", pflag.ContinueOnError) | ||
| types.RegisterAllConfigurations(fs) |
There was a problem hiding this comment.
this is also called when we create a new config so it's duplicated.
| logger.Debug().Err(err).Str("method", "clientSettingsFromEnv").Msgf("couldn't parse oss config %s", oss) | ||
| } | ||
| c.SetSnykOssEnabled(parseBool) | ||
| conf.Set(configresolver.UserGlobalKey(types.SettingSnykOssEnabled), parseBool) |
There was a problem hiding this comment.
The API to set a config is very confusing, when setting a configuration we must know the the scope which is pretty much error prone.
Instead we should simply just call Set and it will determine what the scope of this setting is based on what we already registered.
There was a problem hiding this comment.
Nitpick: Random swap for no reason.
| FormatMd = "md" | ||
| snykCodeTimeoutKey = "SNYK_CODE_TIMEOUT" // timeout as duration (number + unit), e.g. 10m | ||
| DefaultSnykApiUrl = "https://api.snyk.io" | ||
| DefaultSnykApiUrl = types.DefaultSnykApiUrl |
There was a problem hiding this comment.
Future refactor: Just use the original const everywhere.
| folderConfig, err := folderconfig.GetOrCreateFolderConfig(conf, path, logger) | ||
| if err != nil { | ||
| logger.Err(err).Msg("unable to get or create folder config") | ||
| folderConfig = &types.FolderConfig{FolderPath: path} |
There was a problem hiding this comment.
Now handled in GetFolderConfigWithOptions.
EDIT: Actually I will re-do a lot of it as the error paths just don't exist anymore.
| } | ||
|
|
||
| // BatchUpdateFolderConfigs validates folder configs for batch update. | ||
| func BatchUpdateFolderConfigs(conf configuration.Configuration, folderConfigs []*types.FolderConfig, logger *zerolog.Logger) error { |
There was a problem hiding this comment.
This function now does nothing, as ValidatePathForStorage is a literal no-op with no possible error path.
|
|
||
| // RegisterAllConfigurations registers all snyk-ls configuration flags with their annotations | ||
| // into the given FlagSet. Flags are annotated with config.scope, config.remoteKey, | ||
| // config.displayName, config.description, and config.ideKey for framework integration. |
There was a problem hiding this comment.
config.ideKey is no longer a thing.
| }) | ||
| registerFlag(fs, SettingRiskScoreThreshold, 0, "Risk score threshold (0-1000)", map[string][]string{ | ||
| configresolver.AnnotationScope: {folderScope}, | ||
| configresolver.AnnotationRemoteKey: {"risk_score_threshold"}, |
There was a problem hiding this comment.
Big nitpick code smell: Should be using string(v20241015.RiskScoreThreshold) or even better create a wrapper in GAF so we aren't having to update all these when we change to a different version of the API.
…ions (#1183) * fix(auth): use singleflight to deduplicate concurrent IsAuthenticated() calls Concurrent callers of IsAuthenticated() with the same token each independently called the auth provider and each sent a balloon notification on transient failure (e.g. 400 from /oauth2/token), resulting in duplicate popups in the IDE (observed 3x). With singleflight, only one in-flight API call is made per concurrent wave for the same token. All other callers share the result, so only one balloon notification is sent regardless of how many goroutines check simultaneously. Adds CheckAuthDelay to FakeAuthenticationProvider to allow concurrency testing, and a regression test that verifies exactly one notification is sent for 3 concurrent concurrent callers on transient auth failure. * fix(auth): address QA findings on singleflight dedup - Extract token once at start of isAuthenticated() — eliminates three redundant config.GetToken(conf) calls (cache check, empty-token guard, singleflight key) in favour of a single read - Make type assertion on singleflight result explicit with a panic on failure so a future type mismatch surfaces immediately as a programming error rather than silently returning unauthenticated - Apply CheckAuthDelay in both success and failure branches of FakeAuthenticationProvider.GetCheckAuthenticationFunction so the delay works for both positive and negative test scenarios - Add AuthCallCount (atomic int32) to FakeAuthenticationProvider to let tests assert how many times the check function was invoked - Add TestIsAuthenticated_ConcurrentCallsOnlyInvokeProviderOnce to cover the success-path: three concurrent callers on a cache-miss must invoke the provider exactly once - Add load-bearing comment explaining why the 50ms CheckAuthDelay is required for concurrency overlap in both concurrent tests * fix(cli): use full CPU count for CLI concurrency on CI On CI runners (2-4 vCPUs), the CLI semaphore was calculated as max(1, NumCPU-4) = 1, serializing all CLI calls. With ~40 CLI invocations across smoke tests (working dir + reference branch scans), this caused the application/server package to exceed its 60m timeout on Windows consistently. When the CI env var is set, use NumCPU directly (no reservation). The -4 reservation is kept for local development where CPUs should be left for the IDE. * fix(auth): replace singleflight with time-based notification dedup singleflight.Do deadlocks when the OAuth refresherFunc in auth_configuration.go calls IsAuthenticated() recursively with the same token key — the inner Do waits for the outer Do which waits for the refresh which waits for the inner Do. Replace with a 30-second time-based dedup on lastAuthFailNotification. The first caller within a 30s window sends the balloon notification; subsequent callers within that window skip it. This avoids the deadlock while still preventing duplicate popups from concurrent IsAuthenticated() callers on transient auth failure. Also removes the panic on type assertion failure (PR review feedback): a crash in the LS is worse than returning unauthenticated. * fix(test): return error instead of t.Fatalf in substituteDepGraphFlow callback The depgraph callback in substituteDepGraphFlow runs in a background scanner goroutine that can outlive the test. Since Go 1.24, calling t.Fatal from such a goroutine panics the entire test binary: panic: Fail in goroutine after TestX has completed Return the error through the workflow engine instead, which handles it gracefully via the scan error path. This fixes the flaky macOS CI failures in Test_SmokeWorkspaceScan. * fix(auth): use atomic.Int64 for lastAuthFailNotification to prevent data race lastAuthFailNotification (time.Time) was read and written in doAuthCheck without synchronization. Since IsAuthenticated() holds m.RLock (allowing concurrent readers), multiple goroutines could race on the struct field. Replace with atomic.Int64 storing UnixNano, which is safe for concurrent load/store without additional locking. * fix(auth): reset notification cooldown on credential change The 30-second lastAuthFailNotification cooldown was global — after a transient auth failure, no new notification would be shown for 30s even if the user changed their token or re-authenticated. This left users unaware of the result of their corrective actions. Reset the cooldown to zero in updateCredentials when the token changes, so the next IsAuthenticated check sends immediate feedback. * fix(auth): use CompareAndSwap for notification cooldown to prevent race The Load+check+Store sequence on lastAuthFailNotification was not atomic as a unit — multiple goroutines could all Load the stale value, pass the 30s check, and all proceed to send a notification. Use CompareAndSwap so exactly one goroutine wins per cooldown window. If another goroutine updated the value between Load and CAS, the CAS fails and that goroutine skips the notification. * fix(cli): cap CI concurrency limit at 8 to prevent resource exhaustion On high-core CI runners (32+ cores), spawning one CLI process per core could exhaust memory since each Snyk CLI process is heavyweight. Cap at 8 concurrent CLI processes on CI, which is sufficient for test parallelism without risking OOM. * fix(auth): make notification dedup message-aware The 30-second cooldown was global to all error messages — switching from a connectivity error to an invalid token error would be silenced if it happened within 30s of the previous notification. Replace the atomic timestamp with a mutex-protected struct that tracks both the last message and its send time. Different error messages are shown immediately; only identical messages are suppressed for 30s. This ensures the user always sees feedback when the error cause changes (e.g., after re-authenticating or switching configurations). * fix(test): skip substituteDepGraphFlow tests on Windows and macOS The depgraph CLI subprocess is unreliable on non-Linux CI runners: - macOS: OOM-killed (SIGKILL) by Jetsam on 7GB runners - Windows: exits with status 1 (path/environment issues) Add NotOnMacOS helper alongside the existing NotOnWindows, and call both inside substituteDepGraphFlow so every test that uses it is automatically skipped on those platforms. Ubuntu is unaffected. * chore: add CLAUDE.md * fix(test): skip TestUnifiedTestApiSmokeTest on macOS and Windows The test uses substituteDepGraphFlow which is OOM-killed on macOS CI runners (7GB RAM) and exits with status 1 on Windows. When subtests 1 and 2 are skipped via substituteDepGraphFlow, subtest 3 fails with "No diagnostics to compare" because no diagnostics were collected. Add NotOnMacOS and NotOnWindows guards at the top of the parent test so the entire test is skipped on those platforms, consistent with the existing approach in substituteDepGraphFlow. * chore: remove substitute depgraph on non-necessary smoke tests * chore: update osflows * fix(test): pin risk-score feature flags in precedence smoke tests Add Override(flag, value) to featureflag.Service so callers can pin specific flags to false after di.Init, before the LDX-sync scan starts. The precedence smoke tests were failing on CI because the test org had useExperimentalRiskScoreInCLI=true returned by the API, which switched the OSS scanner to the ostest path. That path fails with "failed to get dependency graph" since the test environment does not provide the required dep-graph infrastructure. Override is applied on top of API-fetched values inside PopulateFolderConfig, ensuring it always wins regardless of API response. * fix(auth): coalesce concurrent IsAuthenticated() API calls via singleflight Three or more concurrent IsAuthenticated() calls (each holding m.RLock) all raced to call the auth provider independently. This caused: - Redundant API round-trips on every burst of concurrent callers - The existing notification dedup only suppressed the balloon; the underlying API calls still multiplied authCheckGroup.Do(token, ...) now ensures that when multiple goroutines reach doAuthCheck with the same token, only one API call is in-flight at a time. All waiters share that single result. Add an AuthCallCount assertion to the concurrent test to verify that exactly one API call is made, not one per caller. * perf(logging): reduce lspWriter channel capacity and eliminate bootstrap allocation lspWriter.writeChan was sized at 1,000,000 elements, pre-allocating ~8MB per New() call. With 2-3 New() calls per test setup (InitEngine + SetupLogging), the smoke test suite was allocating 228MB (26% of total) in logging.New alone. - Reduce writeChan capacity from 1_000_000 to 10_000. An LSP session does not need to buffer 1M log messages in-flight; 10K is sufficient for any realistic burst. - Replace logging.New(nil) in InitEngine with os.Stderr directly. InitEngine creates a temporary bootstrap logger before an LSP server exists. Using lspWriter here spins up a goroutine and allocates the channel for a writer that SetupLogging immediately discards. Using os.Stderr avoids the wasted allocation entirely. These two changes together cut logging-related heap allocation from ~228MB (cumulative alloc_space) to ~1.4MB during the unified smoke test. * ci: upgrade macOS integration-test runner to macos-latest-large The 7GB macos-latest runner was OOM-killing the integration test job. Switching to macos-latest-large (14GB RAM) gives sufficient headroom for the depgraph CLI subprocess and the Go test process to coexist. * fix(auth): trigger logout on oauth2 invalid_grant wrapped in url.Error When an OAuth2 refresh token is invalid or expired, the token endpoint returns 400 invalid_grant. The SDK wraps this in a url.Error chain: Get /rest/self -> Post /oauth2/token -> "authentication failed" shouldCauseLogout was returning false because the outer url.Error check fired first, before any string matching. This caused the server to treat the permanent credential failure as transient, retrying the token refresh every ~600ms indefinitely. The config dialog timed out (10s) waiting for the HTML response, leaving the user unable to log out or reset the token. Fix: check for "authentication failed" before the transient-network guards. "authentication failed" only appears when the OAuth server explicitly rejects credentials — it cannot come from DNS/TCP/TLS failures. Also extract isTransientNetworkError() to keep shouldCauseLogout below the gocyclo limit. * chore: update .gitignore * fix(secrets): return nil instead of error when secrets feature flag is disabled When the SnykSecretsEnabled feature flag is not set, the scanner was returning an error ("feature flag not found") and logging at Error level. This caused a spurious balloon notification in the IDE ("feature flag not found") whenever secrets scanning is disabled — which is the normal state for users without the feature flag enabled. Change the behaviour to silently skip the scan (return empty issues, nil error) and log at Debug level, consistent with how other early-exit conditions are handled (e.g. product disabled, no token). * chore: update hyphens in build.yml * fix(logging,test): drop log messages when LSP write channel is full and fix smoke test flake lsp_logger: make WriteLevel non-blocking by using a select/default on the write channel. When the channel is full (e.g. under high-volume Trace logging or a slow client), the message is written to stderr instead of blocking the caller. This prevents the main LS goroutine from freezing the IDE extension. server_smoke_test: distinguish transient RPC errors from correctness violations in verifyQuickFixForIssue. Previously any network/unmarshal error caused the entire 138-issue loop to restart, making it race against the 2-minute assert.Eventually timeout before reaching line 25 (errorhandler). Now transient errors are skipped (soft no-op) while actual rule violations (wrong title format, >1 upgrade action) still fail the check immediately. * test: reduce maxIntegTestDuration from 45m to 15m * fix: macos CI * fix: don't log in debug mode * chore: revert to small macos runner * fix(test): disable binary search path walk in integ/smoke tests On main, all integration/smoke test helpers called WithBinarySearchPaths([]string{}) on the Config struct, preventing the env-defaults goroutine from walking directories like C:\Program Files when searching for mvn.exe or java.exe. After the IDE-1786 Config-struct removal, this safeguard was lost. prepareTestHelper (used by SmokeTestWithEngine and IntegTestWithEngine) now pre-seeds an empty SettingBinarySearchPaths into the GAF configuration before passing it to InitEngine, so the goroutine that calls DetermineJavaHome/MavenDefaults never performs an exhaustive directory walk. On Windows CI this walk took ~10 minutes per test setup (hundreds of thousands of files under C:\Program Files), causing the application/server package to hit the 60-minute go test timeout. This restores the behavior from main and brings Windows CI back in line. * chore: adjust num cpus * fix: add context to ScanProgress.Listen to prevent goroutine leaks ScanProgress.Listen previously blocked indefinitely on its select waiting for cancel or done signals. If a scan ended without calling SetDone or CancelScan (e.g. due to an error early return), the listener goroutine would leak and keep the WaitGroup in DelegatingConcurrentScanner from completing, causing subsequent tests or scans to hang until timeout. Adding ctx.Done() as a third select case ensures the goroutine always exits when the scan's context is canceled, which happens at the latest when the scan function returns via defer cancel(). * fix(lint): remove unnecessary int conversion in calcConcurrencyLimit runtime.NumCPU() already returns int, the conversion was redundant. * fix(test): initialize workflows on pre-configured engine in prepareTestHelper prepareTestHelper passes a pre-configured engine to InitEngine to avoid binary search path walks in CI. However, InitEngine only calls InitWorkflows and engine.Init when engine==nil, so integration and smoke tests were running without registered workflows. This caused: - Test_connectivityCheckCommand_Execute_integration to fail because the connectivity check workflow was never registered - Test_textDocumentInlineValues_InlineValues_IntegTest to fail because the CLI installer workflow was unavailable - Test_SmokeInstanceTest to fail for the same reason Also set EXECUTION_MODE_KEY and PersistInStorage on preConf to match what InitEngine does for nil engines. * fix(oss): defer SetDone() to mark scan progress done on all return paths Previously, ScanProgress.SetDone() was only called on the happy path in scanInternal, leaving isDone=false when legacyScan or ostestScan returned an error. The next scan on the same folder would call CancelScan() on the stale ScanProgress, hitting the 5-second channel timeout. Convert the explicit SetDone() call to a deferred function, matching the IAC scanner's existing pattern. SetDone() is safe to call repeatedly or after cancellation, so deferring it guarantees cleanup on all exit paths. Also adds a gomock-generated Executor mock and a regression test (Test_ScanError_ScanProgressIsMarkedDone) that verifies IsDone()==true after a scan error. * fix(scans): buffer done channel to prevent SetDone() blocking after ctx.Done() When Listen exits via ctx.Done(), the unbuffered done channel has no active reader. Any subsequent call to SetDone() (e.g. from a deferred cleanup in scanInternal or iac.Scan) would block for the full 5-second timeout before returning, effectively hanging the scan goroutine on every context-canceled completion. Changing done to a buffered channel (capacity 1) ensures SetDone() can always complete the send immediately: if Listen is still active it reads the value normally; if Listen has already exited the value sits harmlessly in the buffer until the ScanProgress is garbage-collected. Adds TestScanProgress_SetDone_DoesNotBlockAfterContextCanceled to reproduce the hang and confirm the fix, plus additional unit tests for the normal SetDone, CancelScan, and idempotent SetDone paths. * chore: update test timeout to 90m
* ci: run windows profiling in build workflow Add a dedicated windows-test-profile job to the Build workflow so profiling runs in parallel with integration-tests. The job splits JS and Go test phases, captures go test JSON output, generates slowest package/test and failure reports, uploads artifacts, and fails on non-zero phase exit codes. Remove the standalone windows-test-profile workflow file. * chore: add profiling workflow * chore: use windows-latest * fix: set search paths correctly in test setup * chore: better test setup * chore: use testhelper test setup where possible * chore: remove profiling job
chore: update go to 1.26.2 [IDE-1935] (#1206) * chore: update go to 1.26.2 * chore: update golangci-lint to 2.9.0 * chore: update contributing.md with new go version
…1189) fix: pass trusted folders through didChangeConfiguration [IDE-1786] The IDE-1786 refactoring moved TrustedFolders into InitializationOptions as init-only metadata, but on main it was updatable at runtime via writeSettings/updateTrustedFolders. This caused trusted folder changes sent via workspace/didChangeConfiguration to be silently dropped. Add TrustedFolders field to LspConfigurationParam (matching InitializationOptions) and wire it through handlePushModel and handlePullModel to applyTrustedFolders. Also add js-tests/fixtures/*.html to .gitignore as generated test artifacts. Co-authored-by: Abdelrahman Shawki Hassan <shawki.hassan@snyk.io>
#1196) * fix: persist and restore user folder config across restarts [IDE-1816] User folder overrides (additional params, env, org, base branch, etc.) were lost on restart because: 1. The user:folder: keys were never loaded from storage on startup 2. After JSON round-trip, values deserialized as map[string]interface{} instead of *configresolver.LocalConfigField, causing silent type assertion failures in all reader functions Add coerceToLocalConfigField to handle both in-memory and deserialized forms. Add RefreshByPrefix to load user:folder: keys from storage on startup. Handle []interface{} to []string conversion for slice values. * fix: require Changed flag in folder config setting readers [IDE-1816] getSettingValue, getStringSliceFromSetting, and getScanCommandConfigFromSetting were not checking the Changed flag on ConfigSetting. This caused unchanged settings sent by the IDE during initialization to overwrite persisted user values (e.g. org_set_by_user being reset to false on restart). * fix: use GAF Refresh for folder config keys, replace Changed gate with value comparison [IDE-1816] Replace RefreshByPrefix with KeysByPrefix + per-key Refresh calls in SetupStorage, following the same pattern as other storage refreshes. Remove Changed flag requirement from IDE setting readers (getSettingValue, getStringSliceFromSetting, getScanCommandConfigFromSetting, applyFolderScopeUpdates). Instead, use reflect.DeepEqual to skip no-op updates, preventing IDE defaults from overwriting persisted values without requiring the IDE to set Changed: true. Extract per-field apply helpers (applyBaseBranch, applyLocalBranches, applyStringField, applyStringSliceField, applyScanCommandConfig) for clarity and consistent value-comparison semantics. * fix: reduce cyclomatic complexity of ReadFolderConfigSnapshot [IDE-1816] Extract readScanCommandConfig and readUserOverrides helpers from ReadFolderConfigSnapshot, and reuse existing getStoredStringSlice and getStringSliceFromUserConfig for slice fields to bring complexity from 19 down to within the gocyclo threshold. * fix: sync proxy_insecure and cli_insecure bidirectionally [IDE-1816] proxy_insecure (IDE/LDX-Sync contract) and cli_insecure (internal CLI flag) were not kept in sync, causing the client to receive two different values for the same concept. - applyCliConfig now writes to both proxy_insecure and cli_insecure when the client sends proxy_insecure - LDX-Sync boolSettingDefs setter propagates proxy_insecure to cli_insecure so CLI picks up remote values - cli_insecure marked writeOnly so it is no longer sent to the client; only proxy_insecure is part of the IDE contract - processFolderConfigs: only send update notification when configs actually changed * fix: remove redundant cli_insecure setting, use proxy_insecure everywhere [IDE-1816] cli_insecure was a redundant mirror of proxy_insecure that had no RemoteMachineKey from LDX-Sync. The HTML settings page was reading cli_insecure instead of proxy_insecure, so the resolver never saw the locked remote value and returned the user override instead. - Remove SettingCliInsecure constant and flag registration - Update CLI and CLI auth provider to read SettingProxyInsecure - Update HTML settings construction to read SettingProxyInsecure - Remove sync/mirror logic from applyCliConfig and boolSettingDefs * fix: rename config dialog form fields from camelCase to snake_case [IDE-1816] Align HTML form field names and IDs with backend GAF config key naming convention. Updates config.html template, settings-fallback.html, all JS modules (validation, authentication, folders, form-handler, etc.), Go smoke/unit tests, and JS test fixtures. Also flattens issueViewOptions into individual fields and changes scanningMode values from "auto"/"manual" to "true"/"false". * fix(auth): always send IDE token to updateCredentials * fix: token check * fix: precedence tests --------- Co-authored-by: Abdelrahman Shawki Hassan <shawki.hassan@snyk.io>
These are user-specific Claude Code configuration files (agents, commands, settings). Each developer maintains their own locally. Tracking them caused skip-worktree hacks and checkout conflicts across branches.
…#1210) * fix: stop persisting delta base scan folder configs to disk [IDE-1905] CopyFolderConfigValues() was calling PersistInStorage() for every key copied to the destination folder. When the destination is a temp directory (delta/net-new base branch scan clone), all those keys get written to the on-disk config file and never cleaned up. Remove PersistInStorage() calls from CopyFolderConfigValues() — copied values remain in-memory for scan execution via conf.Set() but no longer pollute the storage file with hundreds of temp folder entries. * feat: migrate legacy folder config from JSON blob to individual GAF keys [IDE-1905] Old format stored all folder configs as a single JSON string under the INTERNAL_LS_CONFIG GAF key. New format uses individual prefix keys per field per folder (user:folder:<path>:<setting>). Without migration, users upgrading lose preferredOrg, orgSetByUser, additionalParameters, baseBranch, and other folder settings — causing scans to silently run against wrong org or with missing CLI args. Migration runs once in SetupStorage() when INTERNAL_LS_CONFIG has content, writes each folder's fields as individual GAF keys using existing helpers, then clears the old key to prevent re-migration. Migrated fields: baseBranch, additionalParameters, additionalEnv, referenceFolderPath, preferredOrg, orgSetByUser, autoDeterminedOrg. * fix: lint * fix: use Unset for legacy config cleanup, downgrade log level, fix Windows test compat Use conf.Unset instead of conf.Set("") to properly remove the legacy config key. Downgrade migration error log from Error to Debug since migration runs only once. Normalize fixture paths in tests using PathKey so assertions pass on Windows where filepath.Clean converts to backslashes.
- README: initializationOptions and didChangeConfiguration use ConfigSetting maps and pflag keys; Secrets product; login args; Go version pointer; scan product values. - configuration-dialog.md: actual JS modules, __ideExecuteCommand__ bridge, save JSON shape, checklists and mermaid. - configuration.md: fix diagram cross-reference. - tree-view/ui-rendering/manual_testing: Secrets product and links. - CONTRIBUTING.md: link to configuration architecture doc. Snyk MCP scans were not run (CLI auth required in this environment).
* fix: populate feature flags before auth notification [IDE-1901] Race condition: after login, IDE receives $/snyk.hasAuthenticated and triggers scan before SAST settings are cached → "Snyk Code not enabled". Fix: postCredentialUpdateHook runs populateAllFolderConfigs between credential storage and auth notification, ensuring feature flags and SAST settings are available before the IDE reacts. Review feedback addressed: - Use unenriched folder config (no git enrichment for feature flag fetch) - Loop only on trusted folders - Remove unnecessary Clone() - Set ConfigResolver on folder config so SetFeatureFlag persists to GAF - Make sendFolderConfigs synchronous in login command - Case-insensitive error string matching in shouldCauseLogout - Extract isTransientNetworkError to reduce cyclomatic complexity Includes regression test verifying feature flags populate before auth notification is sent (fails when hook is removed). * fix: harden postCredentialUpdateHook safety [IDE-1901] - Synchronize SetPostCredentialUpdateHook with a.m mutex to prevent data race - Skip hook when token is empty (logout path) to avoid wasteful API calls - Wrap hook invocation in recover() to prevent LSP server crash on panic * fix: populate feature flags for all workspace folders, not just trusted [IDE-1901] Reverts populateAllFolderConfigs to iterate ws.Folders() instead of ws.GetFolderTrust(). Fixes regression where newly trusted folders never had feature flags populated, leading to "Snyk Code is not enabled" errors. * fix: make sendFolderConfigs async in login to avoid UI blocking [IDE-1901] postCredentialUpdateHook already populates feature flags synchronously before auth notification, so sendFolderConfigs doesn't need to block. * fix: move trusted folders from top-level field to settings map [IDE-1901] Trusted folders were sent as a top-level field on LspConfigurationParam and InitializationOptions, bypassing the settings map processing pipeline. This caused a mismatch with IDEs that send it inside the settings map (e.g. VSCode pull model), resulting in trusted folder updates silently not reaching the LS after init. Move handling into processConfigSettings via applyTrustedFoldersFromSettings, using snake_case key (trusted_folders) consistent with other settings. Remove top-level TrustedFolders field from both Go structs.
chore: bump gaf to 359a47b
…leans [IDE-1816] (#1179) * feat: ldx-sunc provides product enablement and severity filter as booleans * chore: merge upstream code into dev branch * fix: smoke tests were not using the correct ldx-sync fields * fix: smoke tests were not using the correct ldx-sync fields * fix: align AnnotationRemoteKey values with LDX-Sync API spec [IDE-1902] The AnnotationRemoteKey annotations in register_configurations.go used incorrect keys that didn't match the actual LDX-Sync API field names. This caused the GAF ConfigResolver to fail mapping remote config keys. Changes: - severities -> removed (severities now handled via severityAPIKeys) - cwe -> cwe_ids - cve -> cve_ids - rule -> rule_ids - automatic -> scan_automatic - net_new -> scan_net_new - open_issues -> issue_view_open_issues - ignored_issues -> issue_view_ignored_issues - Added AnnotationRemoteKey for product settings (product_code_enabled, etc.) * refactor: split severity filters out into individual fields * fix: update test cound of settings now that severity filters are individual * fix: remove duplicated severity filter and issue view logic * fix: locked settings were not getting set correctly * refactor: revert changes to combined severityfilter object * refactor: remove unused container code, remove duplicate test setup logic * refactor: remove product container * fix: process severity filter updates individually to preserve unchanged values * fix: restore test * fix: update HTML template to use new fields, add extra test coverage --------- Co-authored-by: Nick Yasnohorodskyi <nikita.yasnohorodskyi@snyk.io>
User description
Summary
Phase 2 of the IDE-1786 configuration resolution refactor:
ConfigResolverto read settings from GAF prefix keys instead of struct fields. InjectConfigResolverinto context for scanner access.map[string]*ConfigSettingfor LSP configuration exchange. AddLspFolderConfigwith per-folder settings maps.SastSettingsfromFolderConfigstruct field to GAF configuration withGet/SetSastSettingshelpers.persistedUserFolderSettings,persistedFolderMetadataSettings) andRegisterFolderPersistence()withSetFolderUserSetting/SetFolderMetadataSettinghelpers that combineSet+PersistInStorage.legacyFolderConfigJSON,MigrateLegacyFolderConfig,MigrateFolderConfigOrgSettings,OrgMigratedFromGlobalConfig,settings_migration.go).CliSettingsstruct intoConfig, promoting all fields and methods directly. Remove back-pointer pattern and separate mutex.precedence_smoke_test.goandscanner_precedence_test.gofor config resolution precedence validation.Test plan
make lint— 0 issuesmake test— all unit tests passSMOKE_TESTS=1 make test— smoke tests pass (except pre-existingTest_InvalidExpiredCredentialsSendMessageRequestflake)INTEG_TESTS=1 make test— integration testsPR Type
Enhancement, Refactor
Description
Diagram Walkthrough
flowchart LR subgraph Previous System C["config.Config"] end subgraph New System GAF_Conf["configuration.Configuration (GAF)"] CR["ConfigResolver (types)"] LS["LS Core Services<br/>(codeaction, scanner, etc.)"] NewInterface["New Config Accessors"] end C -->|Data Loaded Into| GAF_Conf GAF_Conf -->|Resolution Logic| CR CR -->|Provides Unified Access| LS LS -->|Uses| NewInterface C -->|Removed| Deprecated ``` <details> <summary><h3> File Walkthrough</h3></summary> <table><thead><tr><th></th><th align="left">Relevant files</th></tr></thead><tbody><tr><td><strong>Additional files</strong></td><td><details><summary>101 files</summary><table> <tr> <td><strong>mcp.json</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-19eb5f2245594c429cc37560d082721fbabff68227984d8d40bad80fd3514b83">[link]</a> </td> </tr> <tr> <td><strong>coder.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-b89595e8329168380c8d0d806f10fe48e0c74d6480bdd36d5f52fb50e60b38e7">+112/-0</a> </td> </tr> <tr> <td><strong>planner.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-3da7d9f10c1d522c26d34593af5559179e560e5f132e48d11925d54bc7e3ae8c">+95/-0</a> </td> </tr> <tr> <td><strong>qa.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-4399ee622fcd198ee75d7ce0c8f8bf764146afab8534c4b73be17d1b0d2e83c4">+126/-0</a> </td> </tr> <tr> <td><strong>commit.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-8a7812887cf57f02817a41095c0bc96e39f12a86dcedc8b9c7717843fb9fecff">+217/-0</a> </td> </tr> <tr> <td><strong>create-implementation-plan.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-c1589a6ef920a2e344d943924041069ef37a00f0c35b10b665b908aa4c3fe12e">+126/-0</a> </td> </tr> <tr> <td><strong>implementation.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-b7db59ef37d8544cde3bd3cb4463d2753bbcd1ef3da3e4d743d6d469476ab938">+202/-0</a> </td> </tr> <tr> <td><strong>verification.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-e63ba9b85e4f0149745953751025c71f5b9b3afd6dfa43b55ece2d3b0bfa56e7">+270/-0</a> </td> </tr> <tr> <td><strong>upload-to-s3.sh</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-4ec24b2c614b7504e801da062ef7c0a0ea927a853af71949117f9be1416955bd">+0/-12</a> </td> </tr> <tr> <td><strong>.goreleaser.yaml</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-7326b55c062b0f46fe9e39aace0a25f4515cf206040fb91a6fd2cae839f5e826">+1/-4</a> </td> </tr> <tr> <td><strong>.tmp_ignore</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-3a301d08bc19d4e6a95a86d0f5f652932e70406c818acb7c1497c799dce6d2c7">[link]</a> </td> </tr> <tr> <td><strong>launch.json</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-bd5430ee7c51dc892a67b3f2829d1f5b6d223f0fd48b82322cfd45baf9f5e945">+0/-23</a> </td> </tr> <tr> <td><strong>tasks.json</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-7d76d7533653c23b753fc7ce638cf64bdb5e419927d276af836d3a03fdf1745a">+0/-24</a> </td> </tr> <tr> <td><strong>coder.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-54b2c28a8e7b934853b4ab315640e41e7d75915418749972b73660a73dd2b8b6">+71/-0</a> </td> </tr> <tr> <td><strong>planner.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-3de3f79204a2442206f81923eaf79f4784cd2a508dde3722261ae346b527b4ba">+70/-0</a> </td> </tr> <tr> <td><strong>qa.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-4b3ee0d066f86a40697b5a63f015144677bddd2e4afc190c20f1e5d4316b1dbd">+117/-0</a> </td> </tr> <tr> <td><strong>general.mdc</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-56f646b00fd9a6c0573b57c0974764abd7f601a2deb90984147b1f66f7b4e6af">+112/-0</a> </td> </tr> <tr> <td><strong>SKILL.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-3eee1259a01cb01a6e29a2472eefcf3975d16e88e4c4841d7cb954dcedc57bdb">+260/-0</a> </td> </tr> <tr> <td><strong>SKILL.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-1e09e3863ee46b9fdc6f65d71c688175b12b8a2e7f4b0a994925ce4f52095352">+116/-0</a> </td> </tr> <tr> <td><strong>SKILL.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-773a18b37f68a8d4a8d73eb1a67eb4a70fd56c90d24f00295e36778a199e53b3">+241/-0</a> </td> </tr> <tr> <td><strong>SKILL.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-01767e331487ad3b20729c5e0747a8f44b4395e7ffdf7038b2fb8eb622a23e9b">+333/-0</a> </td> </tr> <tr> <td><strong>CLAUDE.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-6ebdb617a8104a7756d0cf36578ab01103dc9f07e4dc6feb751296b9c402faf7">+114/-0</a> </td> </tr> <tr> <td><strong>Makefile</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-76ed074a9305c04054cdebb9e9aad2d818052b07091de1f20cad0bbac34ffb52">+2/-2</a> </td> </tr> <tr> <td><strong>README.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5">+26/-22</a> </td> </tr> <tr> <td><strong>helpers.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-939d219344d7e0ee2fabad9bd93cf499c569729779d098d7d7da97fefc181d15">+1/-15</a> </td> </tr> <tr> <td><strong>configuration_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-e141faafb3f0507956b85e92ac3b584c7c706bd96e7f428c7ef95d0d8b2df564">+752/-756</a></td> </tr> <tr> <td><strong>ldx_sync_smoke_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-e86bba96f063a23a5407b87f1d43156fbf47ff435cf44fc7324550746bc13305">+134/-61</a></td> </tr> <tr> <td><strong>scan_notifier.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-1b61c83cfc491251abf25e52610132617ca8ea6b0c1d9347b948fde580eaae42">+2/-5</a> </td> </tr> <tr> <td><strong>scan_notifier_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-5fdc92093964521489fec0d3eb3f9384994e19496fc0d274e0d6a3c3086a975d">+32/-24</a> </td> </tr> <tr> <td><strong>notification_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-09b80ca28f0c9f8db60c941c24e92dfc65ded48c06249e70e2004faec30b9891">+26/-25</a> </td> </tr> <tr> <td><strong>parallelization_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-dfb264976fa1c23451dc8d19b018920487af818f524aa24ea49211bd8b6326e9">+30/-24</a> </td> </tr> <tr> <td><strong>precedence_smoke_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-1c743b9b799604d498e5a5290961ffc135dec375c44150ad820cba81f3926d39">+1077/-0</a></td> </tr> <tr> <td><strong>secrets_smoke_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-c1510bd6a7151e3624d073a590787bd9af09d36b87a53a56067ffc0f3c8603fd">+24/-23</a> </td> </tr> <tr> <td><strong>server_smoke_treeview_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-abf8d4beebabcdeea5250f1698dc768bfbd744c22da6c343b552b5ed02908147">+11/-10</a> </td> </tr> <tr> <td><strong>server_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-165bad981a0cc202462a2fea7f236eab9ca3a72bd47fe8bae6b3adad801351fb">+272/-231</a></td> </tr> <tr> <td><strong>trust_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-e429a057cdac11e281a6ee8603bf8a5ab6dfaf0daedaec873982c47b28d7d431">+51/-49</a> </td> </tr> <tr> <td><strong>parser_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-56f8b9f576282024cef366a3d2024e23c393bc424bd1a7af8917142efcf913e0">+4/-4</a> </td> </tr> <tr> <td><strong>configuration.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-17ed18489a956f326ec0fe4040850c5bc9261d4631fb42da4c52891d74a59180">+712/-0</a> </td> </tr> <tr> <td><strong>configuration-effective-org.mmd</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-973fec236ae811f6a90a055f6b7d0da65dc4d11596911ce8ad89250223805426">+13/-0</a> </td> </tr> <tr> <td><strong>configuration-ide-to-ls.mmd</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-d96f7a3876e2a3103d4016e855aeed2eaf4e094231824ade00f1d15863ca2117">+29/-0</a> </td> </tr> <tr> <td><strong>configuration-ldx-sync-triggers.mmd</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-df333a4abf24cf3d87db395e0abe48a2faa721094e4c5c85350a3e539f7f5136">+39/-0</a> </td> </tr> <tr> <td><strong>configuration-locked-fields.mmd</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-38952676823280ad4b068d0c895c67c0793a9f12baa5fafbc4272e24b92e2188">+23/-0</a> </td> </tr> <tr> <td><strong>configuration-ls-to-ide.mmd</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-e87e10816f9abd36bfa4484439e3525b9094a79520d362815a983bfedd8f9587">+35/-0</a> </td> </tr> <tr> <td><strong>configuration-precedence-folder.mmd</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-cf55942689f0076c1c0d5e590504f623b7d4a2163177bf6a9c38b5fe2abc61e9">+43/-0</a> </td> </tr> <tr> <td><strong>configuration-precedence-machine.mmd</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-1a8c5dae9ef9700a8d68771cf78fe1053bd3a2b0d08b7dc6392ae9bce67ddcb8">+27/-0</a> </td> </tr> <tr> <td><strong>configuration-precedence-org.mmd</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-45c665222948a0e96307bcec7893b2c2eb30a1940831992d8bd16c015a7dca50">+31/-0</a> </td> </tr> <tr> <td><strong>tree-view.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-539534acc1cc1dac4c4790bdca3d442787d7e99ae04349bee000213f08300a28">+2/-2</a> </td> </tr> <tr> <td><strong>ui-rendering.md</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-c5a817d72c0cce20d0ef1e30f346d1533d38bf440472d1a0944fb0ad0c82f98a">+3/-3</a> </td> </tr> <tr> <td><strong>clear_cache_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-f59e398f3890e4a5979f96e46822865c12c0a1c24a04488066e1110e28f217ee">+12/-9</a> </td> </tr> <tr> <td><strong>code_fix_diffs_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-48255cf8a46398666fde50497322859b28c595de794ffd6670ece78b57ae7f75">+5/-7</a> </td> </tr> <tr> <td><strong>code_fix_feedback_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-9ecc2e3d8ac8d287a04858a39ff2b791deda6c161b005159f1df9cd201561be2">+24/-22</a> </td> </tr> <tr> <td><strong>code_fix_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-b6e42c27f7465637e31a6b441bb21a325b705c2e602cc5208182658553a53e71">+28/-18</a> </td> </tr> <tr> <td><strong>command_factory.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-b7c8bb6d3fa17d1b86a8de859670a7d849bdcedceb8d9a27f4e7f1a74b5d340d">+35/-31</a> </td> </tr> <tr> <td><strong>command_service.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-f91e9940ae7491a26a9708f682296ad692d4044fb82fad0d67811bc13f50fa0f">+12/-6</a> </td> </tr> <tr> <td><strong>command_service_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-4e5012d752e62ca48321ab14a65a40b32718552b72d0510af51c9eccfb981154">+4/-3</a> </td> </tr> <tr> <td><strong>configuration_command_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-4e6fcd9606a6e827d54cddeaf143ea61e51516a7e24ebcee13d0968284546bb0">+6/-5</a> </td> </tr> <tr> <td><strong>connectivity_check.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-bd2f39aac9325739fa4bc8f0086a9dbeee25ae8965cfaaebb59ebaf24bfc5892">+6/-7</a> </td> </tr> <tr> <td><strong>connectivity_check_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-d099e6ed42cac1be0e693600339935f0954b0ee310f46436ccb1fcc9b7264c46">+7/-7</a> </td> </tr> <tr> <td><strong>directory_diagnostics.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-c063651ad364c31d1c991853bd8e83c7c7dcde73b16f929e878721e11d1df8a5">+12/-6</a> </td> </tr> <tr> <td><strong>directory_diagnostics_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-cf8506645d2be31c6eb3d3f8ad413863197d6b1793829408240eced9782744cb">+17/-11</a> </td> </tr> <tr> <td><strong>folder_handler.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-85f453996002ebf21ce07aa3db62fcd3d18a1861f517804721583decb421a90d">+103/-199</a></td> </tr> <tr> <td><strong>folder_handler_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-657ad7fa06e97a16b4e8eb7cddc64cd5e53343e6513ef874563e83ffd694416b">+181/-344</a></td> </tr> <tr> <td><strong>generate_issue_description.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-20aaf0cdc220b7a600d894877440f647f93c34bbc4e4f023e33422b4f2e77ccf">+17/-15</a> </td> </tr> <tr> <td><strong>get_active_user_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-c5b8060a5d409b868500ca069b1916a9a35584924e1e61be677148d12a44064d">+18/-16</a> </td> </tr> <tr> <td><strong>get_feature_flag_status_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-29de3939a8441248dd44aa2f2eb09f23a57909cf126d85840d0a1519580e25f3">+11/-6</a> </td> </tr> <tr> <td><strong>get_tree_view_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-443abf9c8f12ff271e64a1eed61e5ddc426eca805d6d5be05cffab1a0e176166">+6/-6</a> </td> </tr> <tr> <td><strong>ignores_integration_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-79ebbec5beb7c426863a36683370db366beb6d364890c7e7155c4a8936527277">+25/-31</a> </td> </tr> <tr> <td><strong>ignores_request.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-06098845100f93443eaa531928a39a803862d1031ccea9ecccc83b8658a58b52">+61/-51</a> </td> </tr> <tr> <td><strong>ignores_request_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-592f7e7bcfc9e8bde581d845d4ae40f18b2f5c70aeb9d9f9481c92439c3f0e74">+35/-46</a> </td> </tr> <tr> <td><strong>ldx_sync_service.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-96079acff1e919961c5c93b80089075c62ed6b1f044fcf18fa0021dcf86fd30b">+149/-119</a></td> </tr> <tr> <td><strong>ldx_sync_service_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-aca1dc6a8fa97db48aa613e9fe3d8e075ff47071ab18848a1369c1217bf8863e">+438/-208</a></td> </tr> <tr> <td><strong>login.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-21b93267e7967e84d95e104e3b17f130b4b47b4a37ac176c5bba7dd4c35cee31">+10/-6</a> </td> </tr> <tr> <td><strong>logout.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-22e316f4a260c54802f276ff85692d92b3c1aba01d3dfd7d73f313c567fb5aab">+5/-3</a> </td> </tr> <tr> <td><strong>logout_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-e3d549e46654c52dd2506b8941fc83546f129917fb37045d8e1bb4c8eb4d1c91">+12/-8</a> </td> </tr> <tr> <td><strong>ldx_sync_service_mock.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-3c7bf69a15757a5bbe63c8758c6596bee98f8b3d7d7b6a9664fc7502ee05f7ed">+6/-5</a> </td> </tr> <tr> <td><strong>navigate_to_range_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-1cde128b3e8be4bc13c1ae238266409330a5bcef310bee386343660b932056b8">+12/-12</a> </td> </tr> <tr> <td><strong>report_analytics.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-62743cd3ce4566b6111230201a62f4d1fea670f1fd60c593265bde16353d8585">+10/-6</a> </td> </tr> <tr> <td><strong>report_analytics_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-20363c3fc3625f9eba95434b9eac8946f2aad36f0ca47165d56a412a78da766a">+29/-29</a> </td> </tr> <tr> <td><strong>sast_enabled.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-66bf16df3a0885d711b00264fad42f006b0346950036f8b48dc7ae6478dc6df4">+1/-1</a> </td> </tr> <tr> <td><strong>toggle_tree_filter_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-b68b006463ac72f1f5bd3786814cdcd0b103cac0245c1f3fdc0efbd0266c6b63">+25/-24</a> </td> </tr> <tr> <td><strong>update_folder_config.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-a05ebb1468908293f4d3cfe250b1748079a0b150076d62ba0df69156131ea8c7">+28/-17</a> </td> </tr> <tr> <td><strong>update_folder_config_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-ded99b4b398d892e849ca2c76051626e1fec77a62c3b6d777e532cf09653f049">+37/-33</a> </td> </tr> <tr> <td><strong>workspace_folder_scan.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-6cb7a834c5afbe811a8145bd6d12892ca661ae68a983846d9f8077beabd6e757">+10/-6</a> </td> </tr> <tr> <td><strong>workspace_scan.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-7815afb61f4ee4d064ffc994582c7306f6ba37d1014c9db5d44ee109dbdc6682">+5/-3</a> </td> </tr> <tr> <td><strong>initializer.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-549679250b6998b23ae6754c4684adc9c107201a71db89c46e227fcc2b6c3a9d">+5/-3</a> </td> </tr> <tr> <td><strong>tree_builder.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-13a01423d69e8880eef4d1b357edd592e256151c20fe2e708922ec9f369d258e">+7/-3</a> </td> </tr> <tr> <td><strong>tree_html.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-47c0b3a66e860f79eb96752b6c2d226c640efecc95340807757164ca16cf1f85">+8/-7</a> </td> </tr> <tr> <td><strong>tree_html_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-a05e59c0bf8dd60c31ffcd4d99f9c41b4e14113da3327539b810a53f4f99c00d">+56/-56</a> </td> </tr> <tr> <td><strong>tree_node_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-914f0695e35f0166328ffb0e48acb6527945999894fce96f1292a00f29fabc64">+1/-1</a> </td> </tr> <tr> <td><strong>tree_scan_emitter.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-c86a1bb522364b4f14326b1a2915a724532c1d4f10d39ed3a51ca4a648715456">+13/-8</a> </td> </tr> <tr> <td><strong>tree_scan_emitter_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-406a88e6d83f47e407cb1bd5a26bd0967e5866aa11529d659a54afd480d356f0">+23/-19</a> </td> </tr> <tr> <td><strong>folder_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-bb03ee76aabde8be49355b245229584151a114e49ec791407738dcaeb631acaf">+138/-162</a></td> </tr> <tr> <td><strong>workspace_trust_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-ac8e52aa69f3b6fb4fd604078ddeef7df2cfe4814df32258a855a7e2254d9af1">+4/-2</a> </td> </tr> <tr> <td><strong>scan_state_aggregator_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-dacb10414b37097b40d2960a603ee1a3ec84ee95c6d096386bceb1c5aa893b42">+65/-51</a> </td> </tr> <tr> <td><strong>summary_html_external_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-f9eb5dd6ed9a5462d93db22db8c10746d506824a6f2927b6ef59869a6f53b592">+15/-7</a> </td> </tr> <tr> <td><strong>issues.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-4bdec45b5c8738e4bf742694b67c57c1102cfa09083bd638e325bfa650f8362a">+0/-3</a> </td> </tr> <tr> <td><strong>git_persistence_provider_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-d11404eaca9a26e07e5b47c9a72b80378bfadb2ba02238363b7a445faf6ad955">+80/-79</a> </td> </tr> <tr> <td><strong>base_scan.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-f37e6aa696f750af79d9ed24805074033bcea09bd38405ca384d14e4c63135f4">+43/-20</a> </td> </tr> <tr> <td><strong>base_scan_test.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-29ac0a06174ae18093e1504044ee8b0ef1574ab063ca1a5c9210e28cba07b6ea">+47/-39</a> </td> </tr> <tr> <td><strong>pre_scan_command.go</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-eb3aa1acbc37cb13f25f84053ef3e81f4f48f558536a7d5e99a3fe429e4878f8">+10/-4</a> </td> </tr> <tr> <td><strong>Additional files not shown</strong></td> <td><a href="https://github.com/snyk/snyk-ls/pull/1162/changes#diff-2f328e4cd8dbe3ad193e49d92bcf045f47a6b72b1e9487d366f6b8288589b4ca"></a></td> </tr> </table></details></td></tr></tr></tbody></table> </details> ___