PR #640's only failing required check was Code scanning/CodeQL: 3 HIGH py/clear-text-logging-sensitive-data alerts where get-secret printed raw secret values to stdout. Research (OWASP, CodeQL rule source, secret-CLI survey) confirmed a real exposure — acute for AIPass since it runs inside Claude Code, which captures command stdout into model context, and the telegram skill shelled out to get-secret and parsed the token from stdout. @api (P1): - NEW apps/modules/secrets.py — in-process cross-branch door (get_secret, list_secrets) wrapping the auth handler; consumers import this, not the CLI. - get_secret_cmd rewritten: masked summary by default ('slug: set (N chars)'), --out FILE writes the raw value 0o600 and prints only the path, --list shows slug names via console.print. All 3 raw-value print() sinks removed. - bypass.json reasoning + README + help updated. @skills (P2): - telegram config._get_secret / list_bot_configs rewired from subprocess+stdout parse to the in-process aipass.api.apps.modules.secrets API; subprocess/json imports dropped. Tests + SKILL.md updated. Also: seedgo test_checkers_batch2.py — comment the synthetic sk-or-v1 fixture keys as FAKE (not real credentials). Verified: @api 504 tests + seedgo 100%; telegram 452/452; skills 252/252; no secret reaches stdout by any path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.4 KiB
5.4 KiB
API
Centralized external API gateway — authenticated service clients for all external APIs
Module: aipass.api | Role: api_gateway
Seedgo: 100% (37/37 at 100%) | Tests: 504 pass | Functions: 82 public (82 tested)
Last Updated: 2026-06-15
Invoke
drone @api <command> [args]
Commands
| Command | Description |
|---|---|
get-key [provider] |
Retrieve API key (default: openrouter) |
validate [provider] |
Validate API key (default: openrouter) |
validate google |
Validate Google OAuth2 credentials |
reauth google |
Re-authenticate Google OAuth2 |
get-secret <provider/slug> [--out FILE] [--json] [--list] |
Secret access (masked summary; --out writes to file) |
list-providers |
List available API providers |
init |
Initialize .env template at ~/.secrets/aipass/ |
test |
Test OpenRouter connection status |
models [--all] |
List available models (default: top 10) |
status |
Check OpenRouter client status (key, SDK, cache) |
call "prompt" --model MODEL |
Make API call to model |
track <gen_id> [caller] |
Track API usage for a generation |
stats |
Display overall usage statistics |
session |
Show current session usage |
caller-usage <caller> |
Show usage by caller module |
cleanup [days] |
Clean up data older than N days (default: 30) |
integrations list |
List registered contracts |
integrations call <contract> [args...] |
Call a registered contract |
Architecture
api/
├── apps/
│ ├── api.py # Entry point — module discovery, command routing
│ ├── modules/ # Orchestration layer (8 modules)
│ │ ├── api_key.py # Key retrieval, validation, provider listing
│ │ ├── secrets.py # Cross-branch secrets door (in-process API)
│ │ ├── openrouter_client.py # OpenRouter client — calls, models, status
│ │ ├── google_client.py # Google API services (Drive, Calendar, etc.)
│ │ ├── usage_tracker.py # Usage metrics — track, stats, cleanup
│ │ ├── bridge.py # Generic contract registry (register/resolve)
│ │ ├── integrations_manager.py # Contract dispatch — integrations list/call
│ │ └── registry.py # Driver auto-discovery (load_drivers)
│ ├── handlers/ # Business logic (7 packages, 15 files)
│ │ ├── auth/env.py, keys.py, secrets.py
│ │ ├── config/provider.py
│ │ ├── google/auth.py, service_factory.py, retry.py
│ │ ├── integrations/list.py, call.py
│ │ ├── json/json_handler.py
│ │ ├── openrouter/caller.py, client.py, models.py, provision.py
│ │ └── usage/aggregation.py, cleanup.py, tracking.py
│ └── integrations/ # Private driver space (gitignored)
│ └── {project}/driver.py
└── tests/ # 504 tests across 28 files
Three-tier: entry point routes to modules (orchestration), modules delegate to handlers (business logic). Modules auto-discovered from apps/modules/*.py via handle_command().
Cross-Branch API
from aipass.api.apps.modules.openrouter_client import get_response
response = get_response(prompt="...", model="anthropic/claude-3.5-sonnet", caller="flow")
from aipass.api.apps.modules.google_client import get_drive_service
service = get_drive_service() # Single-threaded
service = get_drive_service(thread_safe=True) # For concurrent workers
from aipass.api.apps.modules.google_client import get_google_service
service = get_google_service("calendar", "v3")
from aipass.api.apps.modules.secrets import get_secret, list_secrets
token = get_secret("telegram", "bot") # Returns bot_token string
config = get_secret("telegram", "bot", as_json=True) # Returns full dict
slugs = list_secrets("telegram") # Returns ["bot", "webhook", ...]
# CLI never prints raw values — use the Python API above for programmatic access
Integration Points
Depends On:
aipass.prax— structured logging viasystem_loggeraipass.cli— Rich console output formatting
Provides To:
- All branches — authenticated API clients (
get_response(),get_drive_service(),get_google_service()) - System-wide API key management and credential validation
Credentials (~/.secrets/aipass/, 0o700 dir, 0o600 files):
.env— API keys (OpenRouter, etc.)google_creds.json— Google OAuth2 tokensgoogle_client_secret.json— Google OAuth app config
Integration Contract System (DPLAN-0133)
Private drivers in apps/integrations/{project}/driver.py (gitignored) register named contracts via bridge.register(). Callers resolve by name — never referencing private projects directly. registry.py handles auto-discovery via importlib.
Known Issues
- Google auth libraries are optional deps — commands fail with install instructions if missing
- Backup branch credential migration pending (
~/.aipass/→~/.secrets/aipass/) - No rate limiting on OpenRouter calls (S117 finding)
Last Updated: 2026-05-16