lex-microsoft_teams 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -2
- data/CHANGELOG.md +34 -0
- data/CLAUDE.md +2 -2
- data/docs/plans/2026-03-19-teams-token-lifecycle-design.md +120 -0
- data/docs/plans/2026-03-19-teams-token-lifecycle-implementation.md +679 -0
- data/lib/legion/extensions/microsoft_teams/actors/auth_validator.rb +105 -0
- data/lib/legion/extensions/microsoft_teams/actors/cache_sync.rb +1 -5
- data/lib/legion/extensions/microsoft_teams/actors/direct_chat_poller.rb +2 -2
- data/lib/legion/extensions/microsoft_teams/actors/message_processor.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/actors/observed_chat_poller.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/actors/token_refresher.rb +103 -0
- data/lib/legion/extensions/microsoft_teams/client.rb +5 -2
- data/lib/legion/extensions/microsoft_teams/helpers/browser_auth.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/helpers/callback_server.rb +7 -2
- data/lib/legion/extensions/microsoft_teams/helpers/client.rb +4 -0
- data/lib/legion/extensions/microsoft_teams/helpers/prompt_resolver.rb +2 -5
- data/lib/legion/extensions/microsoft_teams/helpers/subscription_registry.rb +1 -0
- data/lib/legion/extensions/microsoft_teams/helpers/token_cache.rb +66 -3
- data/lib/legion/extensions/microsoft_teams/local_cache/extractor.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/local_cache/record_parser.rb +1 -1
- data/lib/legion/extensions/microsoft_teams/runners/bot.rb +4 -4
- data/lib/legion/extensions/microsoft_teams/runners/cache_ingest.rb +8 -9
- data/lib/legion/extensions/microsoft_teams/runners/channel_messages.rb +5 -5
- data/lib/legion/extensions/microsoft_teams/runners/channels.rb +6 -6
- data/lib/legion/extensions/microsoft_teams/runners/chats.rb +5 -5
- data/lib/legion/extensions/microsoft_teams/runners/meetings.rb +16 -16
- data/lib/legion/extensions/microsoft_teams/runners/messages.rb +5 -5
- data/lib/legion/extensions/microsoft_teams/runners/presence.rb +2 -2
- data/lib/legion/extensions/microsoft_teams/runners/subscriptions.rb +5 -5
- data/lib/legion/extensions/microsoft_teams/runners/teams.rb +3 -3
- data/lib/legion/extensions/microsoft_teams/runners/transcripts.rb +6 -6
- data/lib/legion/extensions/microsoft_teams/version.rb +1 -1
- metadata +5 -2
- data/lib/legion/extensions/microsoft_teams/transport.rb +0 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 050cf6a6703c4b6ee4d636980ee7843a3bc34b27c533d0d1cab0325c9903ca02
|
|
4
|
+
data.tar.gz: ffb0ca49267fc2f64b1a27c10f25e45099e2d2450839b3ddf8984efe21572d6b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9f93cdb1ff43c5ff3829f71de8aedca04086cf1a8efed385441a8d0920d39c7a429718e3de6035f734021921d3583ed2004648dc97bd47982cb75d6258baebc7
|
|
7
|
+
data.tar.gz: 50327854fc1dad382f923be114d6b2c413666070f2e8cffb14c35cd467d73519654bdc7bb372fb370ed743e834d438ea4ce25663b7826c0f56a0f6bdd1b6953f
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.4] - 2026-03-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `TokenCache#authenticated?` predicate for runtime delegated token state
|
|
7
|
+
- `TokenCache#previously_authenticated?` predicate for persistent auth history
|
|
8
|
+
- `AuthValidator` actor (Once): validates and restores delegated tokens on boot
|
|
9
|
+
- `TokenRefresher` actor (Every, 15min configurable): keeps delegated tokens fresh
|
|
10
|
+
- Automatic browser re-auth when previously authenticated user's token expires
|
|
11
|
+
- `refresh_interval` config key at `settings[:microsoft_teams][:auth][:delegated]`
|
|
12
|
+
|
|
13
|
+
## [0.5.3] - 2026-03-19
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- `user_path` helper in `Helpers::Client` for Graph API `/me/` vs `/users/{id}/` flexibility
|
|
17
|
+
- `user_id: 'me'` default on all meeting, transcript, presence, chat, and team runner methods
|
|
18
|
+
- `user_id:` parameter on `Client` constructor for application-permission workflows
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- RecordParser 3-byte varint decoding: added missing `& 0x7F` mask on third byte
|
|
22
|
+
- MessageProcessor actor namespace: `Actors` to `Actor` for consistency with all other actors
|
|
23
|
+
- `Client#authenticate!` nil guard preventing `NoMethodError` on failed token acquisition
|
|
24
|
+
- CallbackServer error handling: separate `IOError` (shutdown) from unexpected errors
|
|
25
|
+
- SubscriptionRegistry now calls `load` on initialization to restore persisted subscriptions
|
|
26
|
+
- Device code polling: collapsed duplicate case branches for cleaner error handling
|
|
27
|
+
|
|
28
|
+
### Removed
|
|
29
|
+
- Dead `transport.rb` file (never required by any code path)
|
|
30
|
+
- Dead `.tap` block in CacheSync `args` method
|
|
31
|
+
- Dead `conversation_overrides` TODO stub in PromptResolver (simplified to nil return)
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- `strip_html` in CacheIngest moved from public to private
|
|
35
|
+
- Token cache spec cleanup: atomic file operations, `Process.pid` over `$$`
|
|
36
|
+
|
|
3
37
|
## [0.5.2] - 2026-03-18
|
|
4
38
|
|
|
5
39
|
### Fixed
|
data/CLAUDE.md
CHANGED
|
@@ -10,7 +10,7 @@ Legion Extension that connects LegionIO to Microsoft Teams via Graph API and Bot
|
|
|
10
10
|
|
|
11
11
|
**GitHub**: https://github.com/LegionIO/lex-microsoft_teams
|
|
12
12
|
**License**: MIT
|
|
13
|
-
**Version**: 0.5.
|
|
13
|
+
**Version**: 0.5.2
|
|
14
14
|
|
|
15
15
|
## Architecture
|
|
16
16
|
|
|
@@ -197,7 +197,7 @@ Optional framework dependencies (guarded with `defined?`, not in gemspec):
|
|
|
197
197
|
|
|
198
198
|
```bash
|
|
199
199
|
bundle install
|
|
200
|
-
bundle exec rspec # 185 specs (as of v0.5.
|
|
200
|
+
bundle exec rspec # 185 specs (as of v0.5.2)
|
|
201
201
|
bundle exec rubocop # Clean
|
|
202
202
|
```
|
|
203
203
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Teams Token Lifecycle Design
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
Add automatic delegated token management to lex-microsoft_teams: validate on boot, refresh on a timer, and re-authenticate via browser when a previously authenticated user's token expires.
|
|
6
|
+
|
|
7
|
+
## Problem
|
|
8
|
+
|
|
9
|
+
Currently, delegated tokens require manual `legion auth teams` invocation. If a token expires between restarts (or the refresh token dies), nothing recovers it. Pollers silently fail because `cached_delegated_token` returns nil.
|
|
10
|
+
|
|
11
|
+
## Approach
|
|
12
|
+
|
|
13
|
+
Two new actors + TokenCache enhancements. Follows the existing actor conventions (CacheBulkIngest is Once, DirectChatPoller is Every).
|
|
14
|
+
|
|
15
|
+
## Components
|
|
16
|
+
|
|
17
|
+
### TokenCache Enhancements
|
|
18
|
+
|
|
19
|
+
Two new public methods on `Helpers::TokenCache`:
|
|
20
|
+
|
|
21
|
+
- `authenticated?` — returns true when `@delegated_cache` is non-nil (live token in memory)
|
|
22
|
+
- `previously_authenticated?` — returns true when the local token file exists on disk (user opted in before)
|
|
23
|
+
|
|
24
|
+
The distinction: `previously_authenticated?` means "user said yes before" (file exists). `authenticated?` means "we have a live token right now." This controls whether auto re-auth fires (only for returning users) vs staying silent (never-authenticated users).
|
|
25
|
+
|
|
26
|
+
### AuthValidator Actor (Once)
|
|
27
|
+
|
|
28
|
+
`Actor::AuthValidator < Legion::Extensions::Actors::Once`
|
|
29
|
+
|
|
30
|
+
Runs once on boot with a 2-second delay. Sequence:
|
|
31
|
+
|
|
32
|
+
1. Create TokenCache instance
|
|
33
|
+
2. Call `token_cache.load_from_vault` (tries Vault, falls back to local file)
|
|
34
|
+
3. If loaded: try `cached_delegated_token` (triggers internal refresh if expired)
|
|
35
|
+
- Refresh succeeds: log info "Teams delegated auth restored"
|
|
36
|
+
- Refresh fails + `previously_authenticated?`: log warning, fire BrowserAuth
|
|
37
|
+
- Refresh fails + not previously authenticated: silent (user never opted in)
|
|
38
|
+
4. If nothing loaded: check `previously_authenticated?`
|
|
39
|
+
- True: log warning, fire BrowserAuth (file corrupt or unloadable)
|
|
40
|
+
- False: log debug "No Teams delegated auth configured" — silent
|
|
41
|
+
|
|
42
|
+
Does NOT touch the app token (client_credentials). That is handled lazily by `cached_graph_token` in the pollers.
|
|
43
|
+
|
|
44
|
+
### TokenRefresher Actor (Every)
|
|
45
|
+
|
|
46
|
+
`Actor::TokenRefresher < Legion::Extensions::Actors::Every`
|
|
47
|
+
|
|
48
|
+
Runs every 15 minutes (configurable). Each tick:
|
|
49
|
+
|
|
50
|
+
1. Guard: `return unless token_cache.authenticated?`
|
|
51
|
+
2. Call `cached_delegated_token` (internally refreshes if within 60s of expiry)
|
|
52
|
+
3. If token returned: `save_to_vault` (persists to local file + optional Vault). Done.
|
|
53
|
+
4. If nil (refresh failed):
|
|
54
|
+
- `previously_authenticated?` true: log warning, fire BrowserAuth
|
|
55
|
+
- Otherwise: do nothing (delegated_cache already nil)
|
|
56
|
+
|
|
57
|
+
`run_now?` = false (AuthValidator handles the initial check).
|
|
58
|
+
|
|
59
|
+
### BrowserAuth Trigger
|
|
60
|
+
|
|
61
|
+
Both actors use the same private `attempt_browser_reauth` method:
|
|
62
|
+
|
|
63
|
+
1. Read tenant_id, client_id, scopes from settings
|
|
64
|
+
2. Log warning: "Delegated token expired, opening browser for re-authentication..."
|
|
65
|
+
3. Create `BrowserAuth.new(...)` and call `authenticate`
|
|
66
|
+
4. On success: `store_delegated_token` + `save_to_vault`
|
|
67
|
+
5. On failure: log error, return false
|
|
68
|
+
|
|
69
|
+
BrowserAuth already detects headless environments (no DISPLAY/WAYLAND) and falls back to device code flow. No special handling needed.
|
|
70
|
+
|
|
71
|
+
Both actors define this method privately. No shared module — it is ~20 lines, used in two places, and a premature abstraction would add complexity for no gain.
|
|
72
|
+
|
|
73
|
+
### Shared TokenCache Instance
|
|
74
|
+
|
|
75
|
+
AuthValidator and TokenRefresher each create their own TokenCache instance. This is fine because the local file is the source of truth. AuthValidator loads on boot, TokenRefresher refreshes and saves back to the file on each tick.
|
|
76
|
+
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
Settings path: `Legion::Settings[:microsoft_teams][:auth][:delegated]`
|
|
80
|
+
|
|
81
|
+
New key:
|
|
82
|
+
|
|
83
|
+
| Key | Type | Default | Purpose |
|
|
84
|
+
|-----|------|---------|---------|
|
|
85
|
+
| `refresh_interval` | Integer (seconds) | 900 | TokenRefresher polling interval |
|
|
86
|
+
|
|
87
|
+
Existing keys unchanged: `refresh_buffer`, `scopes`, `vault_path`, `local_token_path`.
|
|
88
|
+
|
|
89
|
+
## Testing
|
|
90
|
+
|
|
91
|
+
### TokenCache Specs
|
|
92
|
+
- `authenticated?` returns false with no cache, true after store
|
|
93
|
+
- `previously_authenticated?` returns false with no file, true after save_to_local
|
|
94
|
+
|
|
95
|
+
### AuthValidator Specs
|
|
96
|
+
- Loads token and refreshes successfully (log info)
|
|
97
|
+
- Loads token, refresh fails, previously authed -> triggers browser reauth
|
|
98
|
+
- Loads token, refresh fails, never authed -> silent
|
|
99
|
+
- No token file exists -> silent
|
|
100
|
+
|
|
101
|
+
### TokenRefresher Specs
|
|
102
|
+
- Skips when not authenticated
|
|
103
|
+
- Refreshes successfully and saves
|
|
104
|
+
- Refresh fails, previously authed -> triggers browser reauth
|
|
105
|
+
|
|
106
|
+
### Actor Patterns
|
|
107
|
+
- Stub base classes with `$LOADED_FEATURES` injection + `described_class.allocate`
|
|
108
|
+
- Stub TokenCache and BrowserAuth (no real network calls)
|
|
109
|
+
|
|
110
|
+
## Files Changed
|
|
111
|
+
|
|
112
|
+
| File | Change |
|
|
113
|
+
|------|--------|
|
|
114
|
+
| `helpers/token_cache.rb` | Add `authenticated?`, `previously_authenticated?` |
|
|
115
|
+
| `actors/auth_validator.rb` | New file |
|
|
116
|
+
| `actors/token_refresher.rb` | New file |
|
|
117
|
+
| `spec/.../helpers/token_cache_spec.rb` | Add 4 specs |
|
|
118
|
+
| `spec/.../actors/auth_validator_spec.rb` | New file |
|
|
119
|
+
| `spec/.../actors/token_refresher_spec.rb` | New file |
|
|
120
|
+
| `microsoft_teams.rb` | Require new actor files |
|