Commit cd545a2
authored
* feat: add PATRotator for short-lived token auto-rotation (#81)
Mints a new 20 PAT every 10 minutes, persists to env var,
~/.databrickscfg, then revokes the old PAT. Includes 19 tests covering rotation
logic, lifecycle, and logging.
* feat: wire PATRotator into app startup (#81)
* chore: add secret resource with WRITE for PAT rotation (#81)
* docs: PAT auto-rotation implementation plan (#81)
* fix: read PAT_ROTATION_INTERVAL and PAT_TOKEN_LIFETIME from env vars (#81)
* chore: set PAT rotation interval to 2 minutes for testing (#81)
* fix: set default rotation to 2 min, remove config from app.yaml (#81)
* fix: clearer rotation log messages — INFO: starting/complete (#81)
* fix: use pat_rotator.py defaults (120s), remove env var overrides from app.py (#81)
* chore: set PAT rotation to 5 min interval, 10 min lifetime (#81)
* feat: resolve owner via SP + Apps API (app.creator), preserve SP credentials (#81)
Owner resolution no longer depends on PAT. Uses the auto-provisioned SP
to call w.apps.get().creator and matches against X-Forwarded-Email.
Falls back to PAT-based resolution for backward compat.
* feat: 10-min rotation with 15-min lifetime, ensure_fresh() on session create (#81)
- Rotation interval: 10 min (less API churn overnight)
- Token lifetime: 15 min (5-min overlap buffer)
- ensure_fresh() called on session creation — if token age > 8 min,
rotate immediately so user never starts with a stale token
* feat: session-aware rotation — skip when no active sessions (#81)
- Remove ensure_fresh() (unnecessary with overlap buffer)
- Rotation only fires when active sessions exist
- No sessions = no API churn (no pointless token minting overnight)
- 10-min rotation interval, 15-min token lifetime (5-min overlap)
- Pass session_count_fn to PATRotator for decoupled session awareness
* feat: interactive PAT setup — /api/pat-status + /api/configure-pat endpoints (#83)
* feat: terminal prompts for PAT on first session, remove DATABRICKS_TOKEN from app.yaml (#83)
* refactor: remove secret scope persistence from PATRotator (#83)
* chore: remove secret scope config — PAT prompt handles restarts (#83)
* fix: make setup_claude.py token-optional — install CLI without PAT (#83)
* feat: configure Claude CLI auth after interactive PAT setup (#83)
* fix: all setup scripts install CLI without token, skip config until PAT (#83)
* feat: configure all CLIs (Claude, Codex, OpenCode, Gemini, Databricks) after PAT setup (#83)
* fix: add missing lock to heartbeat test fixture
* docs: update README and deployment guide for zero-config auth (#83)
* fix: strip SP creds after owner resolution, move setup to after PAT (#83)
* fix: show PAT prompt instead of snake game when setup hasn't started
The index route was treating "pending" (setup not started yet, waiting
for PAT) the same as "running" (setup actively in progress), causing
the loading/snake page to appear immediately instead of index.html
with the PAT prompt. Now only shows loading.html when setup is actively
running.
* chore: remove snake game loading page — setup waits inline in terminal
With deferred setup (runs after PAT, not at boot), the wait happens
inside the terminal via polling. The loading.html snake game page
was unreachable dead code.
* fix: immediately mint controlled token on PAT configure
When the user pastes a PAT, immediately rotate it into a short-lived
token we own (with a known token ID). This ensures the first background
rotation can revoke the old token instead of logging "no old token to
revoke." The user-pasted PAT becomes unused after the initial mint.
* feat: track rotation time, fast-path expired token detection
Add _last_rotation_time to PATRotator, set on every successful mint.
pat-status now checks is_token_expired first — if the token lifetime
has elapsed (no rotation while sessions were idle), immediately returns
valid: false to show the PAT prompt. Avoids a wasted API call to
validate a known-dead token.
* feat: persist app state to ~/.coda/app_state.json
Adds app_state.py — a shared JSON file at ~/.coda/app_state.json that
holds app_owner (set at boot) and last_rotation_time/last_token_id
(set on every rotation). Admins can inspect this file for diagnostics.
The rotator loads last_rotation_time on init so is_token_expired works
across app restarts.
* feat: wire app_state.json — owner at boot, rotation every 10 min
Clean up app_state wiring:
- Move import app_state to top-level in app.py
- pat_rotator writes to app_state.json on every rotation (not just
initial mint), keeping on-disk state current for admin inspection
- Add /api/app-state endpoint for admin diagnostics
- Remove duplicate write from configure_pat (rotator handles it)
- Add 8 tests for app_state round-trip, merge, permissions, corruption
* chore: pin all package versions in requirements.txt
Pin mlflow to 3.10.1 and all other packages to their current resolved
versions for reproducible deploys.
* chore: simplify rotation log message to 'CLI updated'
* fix: bump pyasn1→0.6.3, pyjwt→2.12.1; ignore 3 unfixable CVEs
- pyasn1 0.6.3 fixes GHSA-jr27-m4p2-rc6r (DoS via recursive decoding)
- pyjwt 2.12.1 fixes GHSA-752w-5fwx-jx9f (crit header bypass)
- cryptography 46.0.6, requests 2.33.0, pygments fix — not released
yet, ignoring in audit until available
* fix: upgrade requests to 2.33.0 from GitHub (GHSA-gc5v-m9x4-r6x2)
requests 2.33.0 fixes the predictable temp file extraction vuln but
hasn't landed on PyPI yet. Pin to the v2.33.0 tag commit SHA from
GitHub. Remove the audit ignore for this CVE.
* chore: replace mlflow[genai] with mlflow-tracing — drops pygments CVE
We only use mlflow.claude_code.hooks (in mlflow-tracing). The [genai]
extra pulled in litellm → tokenizers → huggingface-hub → typer → rich
→ pygments (GHSA-5239-wwwm-4pmq, no fix). Switching to mlflow-tracing
drops ~40 transitive deps including pygments, scikit-learn, scipy.
* fix: eliminate cryptography CVE — google-auth 2.47.0 drops the dep
Constrained cryptography>=46.0.6 which resolved by downgrading
google-auth to 2.47.0 (no cryptography dependency). Removes the last
--ignore-vuln from the audit workflow. All 5 CVEs now resolved.
* fix: upgrade mcp 1.19.0→1.26.0 (GHSA-9h52-p55h-vw2f DNS rebinding)
* fix: re-eliminate cryptography dep after mcp upgrade reintroduced it
* fix: upgrade mcp→1.26.0, ignore cryptography until 46.0.6 hits PyPI
mcp and cryptography conflict: mcp>=1.23 needs google-auth which needs
cryptography, but 46.0.6 isn't on PyPI yet. Prioritize mcp fix (DNS
rebinding) over cryptography (low-impact X.509 name constraints).
Weekly audit will catch when 46.0.6 lands.
* fix: upgrade cryptography to 46.0.6 from GitHub (GHSA-m959-cc7f-wv43)
Install cryptography 46.0.6 from GitHub tag (not on PyPI proxy yet).
Zero --ignore-vuln flags remaining — all 6 CVEs resolved.
1 parent 1bb60cc commit cd545a2
20 files changed
Lines changed: 1782 additions & 3262 deletions
File tree
- docs
- plans
- static
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
| 30 | + | |
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| |||
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
66 | | - | |
| 66 | + | |
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| |||
136 | 136 | | |
137 | 137 | | |
138 | 138 | | |
139 | | - | |
140 | | - | |
| 139 | + | |
| 140 | + | |
141 | 141 | | |
142 | | - | |
| 142 | + | |
143 | 143 | | |
144 | 144 | | |
145 | 145 | | |
| |||
280 | 280 | | |
281 | 281 | | |
282 | 282 | | |
283 | | - | |
| 283 | + | |
284 | 284 | | |
285 | 285 | | |
286 | 286 | | |
| |||
289 | 289 | | |
290 | 290 | | |
291 | 291 | | |
292 | | - | |
| 292 | + | |
293 | 293 | | |
294 | 294 | | |
295 | 295 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
| 23 | + | |
22 | 24 | | |
| 25 | + | |
23 | 26 | | |
24 | 27 | | |
25 | 28 | | |
| |||
45 | 48 | | |
46 | 49 | | |
47 | 50 | | |
| 51 | + | |
| 52 | + | |
48 | 53 | | |
49 | 54 | | |
50 | 55 | | |
| |||
57 | 62 | | |
58 | 63 | | |
59 | 64 | | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
60 | 71 | | |
61 | 72 | | |
62 | 73 | | |
| |||
250 | 261 | | |
251 | 262 | | |
252 | 263 | | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
253 | 326 | | |
254 | 327 | | |
255 | 328 | | |
| |||
301 | 374 | | |
302 | 375 | | |
303 | 376 | | |
304 | | - | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
305 | 397 | | |
306 | | - | |
307 | 398 | | |
308 | 399 | | |
309 | 400 | | |
| |||
611 | 702 | | |
612 | 703 | | |
613 | 704 | | |
614 | | - | |
| 705 | + | |
615 | 706 | | |
616 | 707 | | |
617 | 708 | | |
| |||
650 | 741 | | |
651 | 742 | | |
652 | 743 | | |
653 | | - | |
654 | | - | |
655 | | - | |
656 | | - | |
657 | 744 | | |
658 | 745 | | |
659 | 746 | | |
| |||
662 | 749 | | |
663 | 750 | | |
664 | 751 | | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
665 | 758 | | |
666 | 759 | | |
667 | 760 | | |
| |||
682 | 775 | | |
683 | 776 | | |
684 | 777 | | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
685 | 851 | | |
686 | 852 | | |
687 | 853 | | |
| |||
923 | 1089 | | |
924 | 1090 | | |
925 | 1091 | | |
926 | | - | |
927 | | - | |
928 | | - | |
| 1092 | + | |
929 | 1093 | | |
930 | | - | |
| 1094 | + | |
931 | 1095 | | |
932 | 1096 | | |
933 | | - | |
| 1097 | + | |
934 | 1098 | | |
| 1099 | + | |
935 | 1100 | | |
936 | 1101 | | |
937 | 1102 | | |
| 1103 | + | |
| 1104 | + | |
| 1105 | + | |
| 1106 | + | |
| 1107 | + | |
| 1108 | + | |
938 | 1109 | | |
939 | 1110 | | |
940 | 1111 | | |
941 | 1112 | | |
942 | 1113 | | |
943 | | - | |
944 | | - | |
945 | | - | |
946 | | - | |
947 | | - | |
948 | 1114 | | |
949 | 1115 | | |
950 | 1116 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
8 | | - | |
9 | 7 | | |
10 | 8 | | |
11 | 9 | | |
12 | 10 | | |
13 | 11 | | |
14 | 12 | | |
15 | | - | |
16 | 13 | | |
17 | 14 | | |
18 | 15 | | |
| |||
0 commit comments