Add API vault files
This commit is contained in:
67
SKILL.md
Normal file
67
SKILL.md
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
name: api-vault
|
||||
description: Look up API keys, tokens, and service credentials from the Notion APIs database via Maton CLI before asking the user. Also check existing Maton connections.
|
||||
---
|
||||
|
||||
# API Vault
|
||||
|
||||
## When to Use
|
||||
|
||||
Any time you need an API key, service token, OAuth credential, or connection secret — whether for installing a skill, configuring a service, calling an API, or setting up an integration.
|
||||
|
||||
## Lookup Priority
|
||||
|
||||
Always follow this order. Do not skip steps.
|
||||
|
||||
### 1. Notion APIs Database (source of truth)
|
||||
|
||||
Tony stores every API key in his **Notion "APIs" database** titled `APIs` (Database ID: `c7c74f00-3e35-4040-af9a-5caac7f2ca95`).
|
||||
|
||||
Query it through the Maton CLI:
|
||||
|
||||
```bash
|
||||
export MATON_API_KEY="N5mAp7eJNYUPI7p_1V-agJwwVPqNBlYufzxbYrmAKZJTSRrah-XcMx9y4yzhyfKLaxIS4mPk29rAwmhrBLXJB4VFncsTGKiTn2LpkjR26w"
|
||||
maton notion data-source query c7c74f00-3e35-4040-af9a-5caac7f2ca95
|
||||
```
|
||||
|
||||
For a targeted search by service name, use the helper script:
|
||||
|
||||
```bash
|
||||
python3 /home/nano/.nanobot/workspace/skills/api-vault/lookup.py "<service-name>"
|
||||
```
|
||||
|
||||
Or directly via Maton:
|
||||
|
||||
```bash
|
||||
maton notion search "<service-name>"
|
||||
```
|
||||
|
||||
The database has columns:
|
||||
- **Service** (title) — the service/provider name
|
||||
- **API** (rich_text) — the actual key/token
|
||||
- **notes** (rich_text) — context about the key
|
||||
|
||||
### 2. Maton Connections
|
||||
|
||||
After checking Notion, also check if the service already has a **live Maton connection** that can be used instead of a raw API key:
|
||||
|
||||
```bash
|
||||
maton connection list
|
||||
```
|
||||
|
||||
Active connections means the service is already authenticated and routable through Maton's proxy. This is often cleaner than using a raw API key.
|
||||
|
||||
### 3. Ask the User
|
||||
|
||||
Only ask Tony for a key if **both** Notion and Maton don't have it. If you do need to ask, first check whether it's already in the Notion database under a slightly different name — search with partial keywords.
|
||||
|
||||
## Helper Script
|
||||
|
||||
The `lookup.py` script provides a quick way to search the database. Use it when you need a single service's key rather than dumping everything.
|
||||
|
||||
## Key Facts
|
||||
|
||||
- Maton API key is set in `~/.bashrc` as `MATON_API_KEY`
|
||||
- Maton CLI is installed globally at `/usr/local/bin/maton`
|
||||
- Notion connection through Maton is OAuth2-authenticated and active
|
||||
- The APIs database is Tony's canonical key store — trust it
|
||||
109
lookup.py
Normal file
109
lookup.py
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
API Vault Lookup — search Tony's Notion APIs database for a specific service key.
|
||||
|
||||
Usage:
|
||||
python3 lookup.py <service-name>
|
||||
python3 lookup.py all # dump everything
|
||||
|
||||
Environment:
|
||||
MATON_API_KEY must be set (it's in ~/.bashrc)
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
MATON_API_KEY = os.environ.get("MATON_API_KEY")
|
||||
DATASOURCE_ID = "c7c74f00-3e35-4040-af9a-5caac7f2ca95"
|
||||
|
||||
if not MATON_API_KEY:
|
||||
print("ERROR: MATON_API_KEY not set in environment.")
|
||||
print("Run: source ~/.bashrc or export it directly.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def query_database() -> list[dict]:
|
||||
"""Query the full Notion APIs database and return all entries."""
|
||||
cmd = [
|
||||
"maton", "notion", "data-source", "query", DATASOURCE_ID,
|
||||
]
|
||||
env = {**os.environ, "MATON_API_KEY": MATON_API_KEY}
|
||||
try:
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, env=env, timeout=30)
|
||||
result.check_returncode()
|
||||
data = json.loads(result.stdout)
|
||||
except subprocess.TimeoutExpired:
|
||||
print("ERROR: Maton query timed out.")
|
||||
sys.exit(1)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"ERROR: Maton CLI failed:\n{e.stderr}")
|
||||
sys.exit(1)
|
||||
except json.JSONDecodeError:
|
||||
print(f"ERROR: Could not parse Maton output:\n{result.stdout[:500]}")
|
||||
sys.exit(1)
|
||||
|
||||
results = data.get("results", data.get("page_or_data_source", {}).get("results", []))
|
||||
entries = []
|
||||
for r in results:
|
||||
props = r.get("properties", {})
|
||||
svc = _get_text(props, "Service", "title")
|
||||
key = _get_text(props, "API", "rich_text")
|
||||
notes = _get_text(props, "notes", "rich_text")
|
||||
entries.append({"service": svc, "key": key, "notes": notes})
|
||||
return entries
|
||||
|
||||
|
||||
def _get_text(props: dict, field: str, field_type: str) -> str:
|
||||
"""Extract plain text from a Notion property."""
|
||||
if field not in props:
|
||||
return ""
|
||||
if field_type == "title":
|
||||
texts = props[field].get("title", [])
|
||||
else:
|
||||
texts = props[field].get("rich_text", [])
|
||||
if texts:
|
||||
return texts[0].get("plain_text", "")
|
||||
return ""
|
||||
|
||||
|
||||
def main():
|
||||
query = " ".join(sys.argv[1:]).lower().strip()
|
||||
if not query:
|
||||
print("Usage: python3 lookup.py <service-name>")
|
||||
print(" python3 lookup.py all")
|
||||
sys.exit(1)
|
||||
|
||||
entries = query_database()
|
||||
|
||||
if query == "all":
|
||||
for e in entries:
|
||||
_print_entry(e)
|
||||
return
|
||||
|
||||
# Filter by case-insensitive partial match on service name
|
||||
matches = [e for e in entries if query in e["service"].lower()]
|
||||
|
||||
if not matches:
|
||||
print(f"No entries found matching '{query}'.")
|
||||
print("Try: python3 lookup.py all (to see everything)")
|
||||
return
|
||||
|
||||
for e in matches:
|
||||
_print_entry(e)
|
||||
|
||||
|
||||
def _print_entry(e: dict):
|
||||
svc = e["service"] or "(unnamed)"
|
||||
key = e["key"] or "(no key)"
|
||||
notes = e["notes"]
|
||||
print(f"── {svc}")
|
||||
print(f" Key: {key}")
|
||||
if notes:
|
||||
print(f" Notes: {notes}")
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user