fix: enforce 0o600/0o700 permissions on all database and data files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jon Saad-Falcon
2026-03-28 21:20:01 -07:00
co-authored by Claude Sonnet 4.6
parent 9909dde780
commit 85fbd2bd8c
7 changed files with 30 additions and 5 deletions
+3 -1
View File
@@ -54,8 +54,10 @@ def setup_logging(
# File handler (verbose or explicit path)
if verbose or log_file is not None:
if log_file is None:
from openjarvis.security.file_utils import secure_mkdir
log_dir = Path.home() / ".openjarvis"
log_dir.mkdir(parents=True, exist_ok=True)
secure_mkdir(log_dir)
log_file = log_dir / "cli.log"
file_handler = RotatingFileHandler(
str(log_file),
@@ -54,7 +54,9 @@ class AttachmentStore:
base_dir = str(DEFAULT_CONFIG_DIR / "blobs")
self._base_dir = Path(base_dir)
self._base_dir.mkdir(parents=True, exist_ok=True)
from openjarvis.security.file_utils import secure_mkdir
secure_mkdir(self._base_dir)
db_path = self._base_dir / "attachments.db"
self._conn = sqlite3.connect(str(db_path), check_same_thread=False)
@@ -95,6 +97,9 @@ class AttachmentStore:
blob_path = blob_dir / sha
if not blob_path.exists():
blob_path.write_bytes(content)
import os
os.chmod(blob_path, 0o600)
# Upsert metadata row
existing = self._conn.execute(
+3 -1
View File
@@ -124,7 +124,9 @@ class KnowledgeStore(MemoryBackend):
self._db_path = str(db_path)
# Ensure the parent directory exists (skip for :memory:)
if self._db_path != ":memory:":
Path(self._db_path).parent.mkdir(parents=True, exist_ok=True)
from openjarvis.security.file_utils import secure_create
secure_create(Path(self._db_path))
self._conn = sqlite3.connect(self._db_path, check_same_thread=False)
self._conn.row_factory = sqlite3.Row
+8
View File
@@ -29,6 +29,13 @@ DEFAULT_CONFIG_DIR = Path.home() / ".openjarvis"
DEFAULT_CONFIG_PATH = DEFAULT_CONFIG_DIR / "config.toml"
def _ensure_config_dir() -> Path:
"""Ensure the config directory exists with restrictive permissions."""
from openjarvis.security.file_utils import secure_mkdir
return secure_mkdir(DEFAULT_CONFIG_DIR)
@dataclass(slots=True)
class GpuInfo:
"""Detected GPU metadata."""
@@ -1327,6 +1334,7 @@ def load_config(path: Optional[Path] = None) -> JarvisConfig:
Explicit config file. If not set, uses ``OPENJARVIS_CONFIG`` when set,
otherwise ``~/.openjarvis/config.toml``.
"""
_ensure_config_dir()
hw = detect_hardware()
cfg = JarvisConfig(hardware=hw)
cfg.engine.default = recommend_engine(hw)
+3 -1
View File
@@ -36,7 +36,9 @@ class AuditLogger:
bus: Optional[EventBus] = None,
) -> None:
self._db_path = Path(db_path)
self._db_path.parent.mkdir(parents=True, exist_ok=True)
from openjarvis.security.file_utils import secure_create
secure_create(self._db_path)
self._conn = sqlite3.connect(str(self._db_path))
self._conn.execute(
"""
+3 -1
View File
@@ -23,7 +23,9 @@ class SessionStore:
def __init__(self, db_path: str = "") -> None:
if not db_path:
db_path = str(Path.home() / ".openjarvis" / "sessions.db")
Path(db_path).parent.mkdir(parents=True, exist_ok=True)
from openjarvis.security.file_utils import secure_create
secure_create(Path(db_path))
self._db = sqlite3.connect(db_path, check_same_thread=False)
self._db.row_factory = sqlite3.Row
self._create_tables()
+4
View File
@@ -81,6 +81,10 @@ class TraceStore:
def __init__(self, db_path: str | Path) -> None:
self._db_path = str(db_path)
if self._db_path != ":memory:":
from openjarvis.security.file_utils import secure_create
secure_create(Path(self._db_path))
# check_same_thread=False is safe with WAL mode. The
# AgenticRunner dispatches agent work to a ThreadPoolExecutor
# (for Playwright compat), so trace writes may originate from