Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
636d01d
Add PAM RBI file uploads/downloads and `pam connection edit --scrollb…
idimov-keeper May 27, 2026
fa8757a
KC-1260: Support combined folder search with multiple -c flags (#2084…
sshrushanth-ks May 28, 2026
1117f7a
Fix NSF CLI record updates, nested directory creation and Service Mod…
pvagare-ks May 29, 2026
fa82d64
Fix: Stop silently inheriting SSL_CERT_FILE from process env (#2094)
amangalampalli-ks May 29, 2026
a628515
Remove force_close escalation on workflow lease expiry; soft-close on…
idimov-keeper May 30, 2026
dc533fc
fix: limit enterprise object name lengths and change ei role column t…
amangalampalli-ks Jun 2, 2026
1830206
'epm scim' from AzureAD: use UPN as Username
sk-keeper Jun 2, 2026
34f7391
Update proto files
sk-keeper Jun 2, 2026
edcee4d
fix(tunnel): close and unregister tube on connection_state_changed=cl…
idimov-keeper Jun 2, 2026
94b49b8
Disable logging with silent flag (#2103)
lthievenaz-keeper Jun 3, 2026
70682db
KC-1261, KC-1267 & KC-1291: Fix: consistent JSON response across get,…
sshrushanth-ks Jun 3, 2026
bffc0de
Import users and teams in cyberark and download membership support fo…
pvagare-ks Jun 3, 2026
7abf62f
KC-1299: cloud secret import to keeper drive (#2107)
mfordkeeper Jun 3, 2026
163ea38
Fix circular KSM import (#2115)
lthievenaz-keeper Jun 3, 2026
0221d43
Re-apply DAG-migration local-only changes onto release base (per-grap…
idimov-keeper Jun 3, 2026
d6c1283
Merge DAG overlap onto release: keeper_dag parity+multi_sync, local-v…
idimov-keeper Jun 3, 2026
3820c71
sync: take release kcm_import + test (non-DAG; resolves Windows os.un…
idimov-keeper Jun 3, 2026
ce6f2ee
NSF folder data support for share-report command (#2116) (#2117)
pvagare-ks Jun 4, 2026
1a96f47
Release 18.0.5
sk-keeper Jun 4, 2026
2319a90
Improve manual for epm scim ad
lthievenaz-keeper Jun 3, 2026
90337fc
Fix: exempt /health from service-mode API rate limiting
maksimu Jun 2, 2026
781c424
Fix pam connection edit: connection settings + launch/admin credentials
idimov-keeper Jun 5, 2026
49afb76
Universal Secret Sync commands
m-afanasiuk Jun 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docker_ksm_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
records, including config processing, file upload/download, and monitoring.
"""

import importlib
import sys
import os
import argparse
Expand Down Expand Up @@ -70,7 +71,7 @@ def check_ksm_dependency():
bool: True if installed, False otherwise
"""
try:
import keeper_secrets_manager_core # noqa: F401
importlib.import_module('keeper_secrets_manager_core')
return True
except ImportError:
print("ERROR: keeper_secrets_manager_core is not installed")
Expand Down Expand Up @@ -180,7 +181,7 @@ def _decode_and_save_config(base64_input, config_path):
os.chmod(config_path, 0o600)
return True

except Exception as e:
except Exception:
print("ERROR: Failed to decode and save config")
return False

Expand Down Expand Up @@ -598,7 +599,7 @@ def monitor_config(ksm_config_path, ksm_token, record_identifier, config_file_pa
return
ksm_config_path = validated_ksm_config_path

print(f"Monitoring config file for changes")
print("Monitoring config file for changes")

last_hash = _get_secure_file_hash(config_file_path)
monitor_interval = 30 # Check every 30 seconds
Expand Down
2 changes: 1 addition & 1 deletion keepercommander/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
# Contact: commander@keepersecurity.com
#

__version__ = '18.0.4'
__version__ = '18.0.5'
80 changes: 8 additions & 72 deletions keepercommander/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,12 @@


import argparse
import certifi
import json
import logging
import os
import re
import shlex
import sys
import ssl
import platform

from pathlib import Path
from typing import Optional
Expand Down Expand Up @@ -119,6 +116,7 @@ def show_brief_help():
print(' --password, -kp PASSWORD Master password for the account')
print(' --config CONFIG Config file to use')
print(' --debug Turn on debug mode')
print(' --silent Turn off all logging statements')
print(' --batch-mode Run in batch/non-interactive mode')
print(' --proxy PROXY Proxy server')
print(' --new-login Force full login (bypass persistent login)')
Expand Down Expand Up @@ -152,6 +150,7 @@ def show_brief_help():
parser.add_argument('--version', dest='version', action='store_true', help='Display version')
parser.add_argument('--config', dest='config', action='store', help='Config file to use')
parser.add_argument('--debug', dest='debug', action='store_true', help='Turn on debug mode')
parser.add_argument('--silent', dest='silent', action='store_true', help='Turn off all logging statements')
parser.add_argument('--batch-mode', dest='batch_mode', action='store_true', help='Run commander in batch or basic UI mode.')
parser.add_argument('--launched-with-shortcut', '-lwsc', dest='launched_with_shortcut', action='store',
help='Indicates that the app was launched using a shortcut, for example using Mac App or from '
Expand All @@ -178,69 +177,6 @@ def handle_exceptions(exc_type, exc_value, exc_traceback):
sys.exit(-1)


def get_ssl_cert_file():
"""Get SSL certificate file path, preferring system CA store for corporate environments like Zscaler"""

# Allow user to override via environment variable
user_cert_file = os.getenv('KEEPER_SSL_CERT_FILE')
if user_cert_file:
if user_cert_file.lower() == 'system':
# User explicitly wants system certs
pass # Continue with system detection below
elif user_cert_file.lower() == 'certifi':
# User explicitly wants certifi
return certifi.where()
elif user_cert_file.lower() == 'none' or user_cert_file.lower() == 'false':
# User wants to disable SSL verification (not recommended)
return None
elif os.path.exists(user_cert_file):
# User provided specific cert file
return user_cert_file
else:
logging.warning(f"SSL cert file specified in KEEPER_SSL_CERT_FILE not found: {user_cert_file}")

# Try to use system CA store first for corporate environments
try:
# On macOS, try Homebrew certificates first (better for corporate environments like Zscaler)
if platform.system() == 'Darwin':
system_ca_paths = [
'/opt/homebrew/etc/ca-certificates/cert.pem', # Homebrew CA bundle (best for Zscaler)
'/usr/local/etc/ssl/cert.pem', # Homebrew SSL (older location)
'/etc/ssl/cert.pem', # macOS system CA bundle
]
for ca_path in system_ca_paths:
if os.path.exists(ca_path):
return ca_path

# On Linux/Unix systems
elif platform.system() == 'Linux':
system_ca_paths = [
'/etc/ssl/certs/ca-certificates.crt', # Debian/Ubuntu
'/etc/pki/tls/certs/ca-bundle.crt', # RHEL/CentOS
'/etc/ssl/ca-bundle.pem', # OpenSUSE
'/etc/ssl/cert.pem', # Generic
]
for ca_path in system_ca_paths:
if os.path.exists(ca_path):
return ca_path

# Try to get default SSL context locations
try:
default_locations = ssl.get_default_verify_paths()
if default_locations.cafile and os.path.exists(default_locations.cafile):
return default_locations.cafile
if default_locations.capath and os.path.exists(default_locations.capath):
return default_locations.capath
except:
pass

except Exception:
pass

# Fall back to certifi if system CA not available
return certifi.where()


def main(from_package=False):
if sys.platform == 'win32':
try:
Expand All @@ -253,15 +189,12 @@ def main(from_package=False):
if logger:
logger.name = 'keepercommander'

# Use system CA certificates when available (supports Zscaler), fallback to certifi
ssl_cert_file = get_ssl_cert_file()
ssl_cert_file = utils.get_ssl_cert_file()
if ssl_cert_file:
os.environ['SSL_CERT_FILE'] = ssl_cert_file
else:
# User explicitly disabled SSL verification
logging.warning("Warning: SSL certificate verification has been disabled. This is not recommended for production use.")
if 'SSL_CERT_FILE' in os.environ:
del os.environ['SSL_CERT_FILE']
os.environ.pop('SSL_CERT_FILE', None)

errno = 0

Expand Down Expand Up @@ -292,7 +225,7 @@ def main(from_package=False):
value_main_parser_args = ['--config', '--server', '--user', '--password',
'--launched-with-shortcut', '--proxy',
'--data-dir', '-ks', '-ku', '-kp', '-lwsc']
bool_main_parser_args = ['--version', '--debug', '--batch-mode',
bool_main_parser_args = ['--version', '--debug', '--silent', '--batch-mode',
'--unmask-all', '--fail-on-throttle',
'--new-login', '--config-file']
main_parser_args = value_main_parser_args + bool_main_parser_args
Expand All @@ -319,6 +252,9 @@ def main(from_package=False):
if opts.launched_with_shortcut:
os.chdir(Path.home())

if opts.silent:
logging.disable(logging.CRITICAL)

params = get_params_from_config(opts.config, opts.launched_with_shortcut, opts.data_dir)

if opts.batch_mode:
Expand Down
5 changes: 3 additions & 2 deletions keepercommander/biometric/utils/error_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"""
Centralized error handling utilities for biometric authentication
"""
import importlib
import logging

from ...error import CommandError
Expand Down Expand Up @@ -62,7 +63,7 @@ def handle_credential_creation_error(error: Exception, platform_name: str = "Bio
return Exception(f"{platform_name} registration cancelled")
elif ("object already exists" in error_msg or
("oserror" in error_msg and "22" in error_msg and "object already exists" in error_msg)):
return Exception(f"A biometric credential for this account already exists")
return Exception("A biometric credential for this account already exists")
elif "timeout" in error_msg:
return Exception(f"{platform_name} registration timed out")
elif "not available" in error_msg:
Expand Down Expand Up @@ -107,7 +108,7 @@ def validate_dependencies(required_modules: list, platform_name: str = "Platform
missing_modules = []
for module in required_modules:
try:
__import__(module)
importlib.import_module(module)
except ImportError:
missing_modules.append(module)

Expand Down
13 changes: 13 additions & 0 deletions keepercommander/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@
else:
logging.warning('Cannot change Keeper region while logged in')
else:
print(params.server)

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This expression logs
sensitive data (password)
as clear text.
This expression logs
sensitive data (password)
as clear text.
return

if command_line.startswith('ksm'):
Expand Down Expand Up @@ -796,6 +796,19 @@
# Mark that we're in the shell loop (used by supershell to know if it should start a shell on exit)
params._in_shell_loop = True

# NB! USE_LOCAL_DAG=TRUE should be used only for testing. Warn here — after the
# login/decrypt output, right before the first prompt — so the notice isn't buried:
# the local test DAG engine routes PAM/DAG/discovery commands to a local SQLite
# graph instead of the gateway/router, so they may fail or behave incorrectly
# until it is disabled or removed.
if not params.batch_mode and not skip_init:
from .utils import value_to_boolean
if value_to_boolean(os.environ.get('USE_LOCAL_DAG', False)):
logging.warning(
f"{Fore.YELLOW}USE_LOCAL_DAG=TRUE environment variable is enabled (local test DAG engine); "
f"some PAM/DAG commands may fail. Unset it or set it to false to use the live gateway.{Fore.RESET}"
)

while True:
if params.session_token:
ttk.TTK.update(params)
Expand Down
Loading
Loading