From 72132aba9dff83d355e7a03fbe3e1f3e7da326ce Mon Sep 17 00:00:00 2001 From: indianbill007 Date: Wed, 8 Jul 2026 11:50:44 +0530 Subject: [PATCH 1/2] config: replace hardcoded owner email + vault path with config knobs The public build hardcoded a personal email (agents-owner fallback) and a production vault path (/opt/buildwithsumit/vault/auto). Read both from config instead so a fresh open-source deploy carries no personal or prod-specific defaults: - agents owner: AGENTS_OWNER_EMAIL, falling back to GLOBUS_FIRST_MEMBER_EMAIL (the seed member). If neither is set, owner-only agents stay locked. - vault auto-build dir: GLOBUS_VAULT_AUTO_DIR, default /opt/globus/vault/auto. Both knobs documented in config/.env.example. --- config/.env.example | 9 +++++++++ server/agents_runtime.py | 6 +++++- server/vault_stats.py | 11 +++++++---- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/config/.env.example b/config/.env.example index c616fc0..7d025d4 100644 --- a/config/.env.example +++ b/config/.env.example @@ -83,6 +83,15 @@ GLOBUS_VOICE_LLM_SECRET= GLOBUS_DAILY_CAP=500 # user messages per UTC day per member GLOBUS_MAX_CONNECTIONS_PER_MEMBER=10 GLOBUS_VAULT_MAX_CHARS=200000 +# Directory the offline vault auto-builder writes notes into (read by the +# vault-progress dashboard). Defaults to /opt/globus/vault/auto. +GLOBUS_VAULT_AUTO_DIR= + +# ---- Single-tenant owner (optional) ---- +# Email of the member who may trigger/read the Hermes background agents in +# a single-tenant deploy. Leave blank to fall back to GLOBUS_FIRST_MEMBER_EMAIL; +# if both are blank, owner-only agents stay locked until you set one. +AGENTS_OWNER_EMAIL= # ---- Docker compose helpers (only read by docker-compose.yml, # not by the app itself) ---- diff --git a/server/agents_runtime.py b/server/agents_runtime.py index 0fbade5..ddff834 100644 --- a/server/agents_runtime.py +++ b/server/agents_runtime.py @@ -56,8 +56,12 @@ # to trigger them, read their briefs, or see their live status. Once # per-member agent copies exist, this constant becomes per-row data. # (Sumit 2026-06-26.) +# Config-driven so the open-source build carries no personal default: +# set AGENTS_OWNER_EMAIL (or reuse GLOBUS_FIRST_MEMBER_EMAIL, the seed +# member) to nominate the single-tenant owner. If neither is set, no one +# is treated as owner — owner-only agents stay locked until configured. _AGENTS_OWNER_EMAIL = (cfg("AGENTS_OWNER_EMAIL", "") - or "indianbill007@gmail.com").lower() + or cfg("GLOBUS_FIRST_MEMBER_EMAIL", "")).lower() def _is_agents_owner(email): diff --git a/server/vault_stats.py b/server/vault_stats.py index 8679cf5..12a14a7 100644 --- a/server/vault_stats.py +++ b/server/vault_stats.py @@ -17,15 +17,16 @@ intermittent ElevenLabs 'upstream error' Sumit reported 2026-06-24). -Module deps: db_read (db_helpers). Reads /opt/buildwithsumit/vault/auto -directly for the notes-by-type count, defensive against perm errors +Module deps: db_read (db_helpers). Reads the vault auto-build dir +(GLOBUS_VAULT_AUTO_DIR, default /opt/globus/vault/auto) directly for the +notes-by-type count, defensive against perm errors (the auto-builder runs as root and can create subdirs blocked to www-data — we skip unreadable subdirs rather than 500'ing). """ from __future__ import annotations import os import time -from db_helpers import db_read +from db_helpers import db_read, cfg VAULT_SOURCE_META = { @@ -176,7 +177,9 @@ def _add(src_type, extracted, processed): # poll (the live page parses the response as JSON; an HTML 500 # error there breaks the whole dashboard). notes_by_type = {} - base = "/opt/buildwithsumit/vault/auto" + # Directory the offline vault auto-builder writes notes into. Config + # knob so the open-source build isn't pinned to a production path. + base = cfg("GLOBUS_VAULT_AUTO_DIR", "/opt/globus/vault/auto") try: subdirs = os.listdir(base) if os.path.isdir(base) else [] except OSError: From a5e752bf259efe31ad0a907d406f6a72e521f8d4 Mon Sep 17 00:00:00 2001 From: indianbill007 Date: Wed, 8 Jul 2026 11:50:44 +0530 Subject: [PATCH 2/2] ops: add gitleaks secret-scanning (CI + pre-commit) Guard against a credential ever landing in this public repo. - .github/workflows/gitleaks.yml: runs the gitleaks CLI via its official Docker image on every push and PR over full history. Uses the CLI (not gitleaks-action) because the Action requires a paid license for org-owned repos; the CLI is free. - .pre-commit-config.yaml: blocks leaks locally before commit. - .gitleaks.toml: extends the default ruleset, allowlists the sanitized example files + public identifiers to avoid false positives. - CONTRIBUTING.md: documents the never-commit-secrets rule + hook install. --- .github/workflows/gitleaks.yml | 37 ++++++++++++++++++++++++++++++++++ .gitleaks.toml | 31 ++++++++++++++++++++++++++++ .pre-commit-config.yaml | 19 +++++++++++++++++ CONTRIBUTING.md | 8 ++++++++ 4 files changed, 95 insertions(+) create mode 100644 .github/workflows/gitleaks.yml create mode 100644 .gitleaks.toml create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/gitleaks.yml b/.github/workflows/gitleaks.yml new file mode 100644 index 0000000..e95c271 --- /dev/null +++ b/.github/workflows/gitleaks.yml @@ -0,0 +1,37 @@ +name: gitleaks + +# Secret-scanning guard for this PUBLIC repo. Runs on every push and PR so a +# credential can never land in history unnoticed. Uses the gitleaks CLI via +# its official Docker image (license-free for org-owned repos, unlike the +# gitleaks-action, which requires a paid license for organizations). +# The local .pre-commit-config.yaml catches most leaks before they are even +# committed; this CI job is the enforced, unbypassable backstop. + +on: + push: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + gitleaks: + name: Scan for committed secrets + runs-on: ubuntu-latest + steps: + - name: Checkout (full history) + uses: actions/checkout@v4 + with: + fetch-depth: 0 # scan the entire commit history, not just HEAD + + - name: Run gitleaks + run: | + docker run --rm -v "${{ github.workspace }}:/repo" \ + ghcr.io/gitleaks/gitleaks:latest \ + detect \ + --source /repo \ + --config /repo/.gitleaks.toml \ + --redact \ + --verbose \ + --exit-code 1 diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000..a443866 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,31 @@ +# gitleaks configuration for Build-With-Sumit/globus +# +# Extends the built-in default ruleset (covers AWS, GCP, Stripe, OpenAI, +# GitHub, Slack, private keys, generic high-entropy assignments, etc.) and +# adds an allowlist so the deliberately-sanitized example files and public +# identifiers don't produce false positives. +# +# Used by both the CI job (.github/workflows/gitleaks.yml) and the local +# pre-commit hook (.pre-commit-config.yaml). + +title = "globus gitleaks config" + +[extend] +useDefault = true + +[allowlist] +description = "Sanitized examples + public identifiers are not secrets" + +# Example/template config files ship placeholder values by design. +paths = [ + '''config/\.env\.example''', + '''config/persona\.example\.md''', +] + +# Values that look secret-shaped but are public or are obvious placeholders. +regexes = [ + '''wDsJlOXPqcvIUKdLXjDs''', # public ElevenLabs library voice id ("Jarvis") + '''change-me(-root)?''', # placeholder DB passwords in .env.example + '''replace-with-32-byte-hex''', # placeholder SESSION_SECRET + '''your-[a-z-]+''', # generic "your-key-here" style placeholders +] diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..35aecfd --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,19 @@ +# Local secret-scanning guard. Blocks a commit if gitleaks finds a secret in +# the staged changes, so a credential never leaves your machine. +# +# One-time setup: +# pip install pre-commit +# pre-commit install +# +# Keep the pinned rev current with: pre-commit autoupdate +# +# NOTE: a local hook is bypassable (git commit --no-verify) and requires each +# contributor to install it. The authoritative, unbypassable scan is the +# gitleaks CI job in .github/workflows/gitleaks.yml, which re-scans the full +# history on every push and pull request. + +repos: + - repo: https://github.com/gitleaks/gitleaks + rev: v8.21.2 + hooks: + - id: gitleaks diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fe86195..3a2a44e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,6 +51,14 @@ the cheapest path for dev iteration (~$0.0001 per 1K tokens). ## House rules +- **Never commit secrets.** Real keys/tokens/passwords/connection strings + live only in your untracked `.env` (or the MySQL `config` table) — never + in a tracked file, not even a doc or an example. A gitleaks CI job + (`.github/workflows/gitleaks.yml`) scans every push and PR, and + `.pre-commit-config.yaml` blocks a leak locally — run + `pip install pre-commit && pre-commit install` once. If a secret does get + committed, rotate it (scrubbing history does not un-leak an exposed key) + and open an issue. - **Stdlib first.** New runtime deps need a reason in the PR description. - **No emoji in source code or comments** unless the PR is specifically about the user-facing UI text. They render inconsistently across