Changelog
Changelog
1.3.3 (2026-11-07)
Bug Fixes
1.3.2 (2026-11-07)
Documentation
AGENTS.md canonical, CLAUDE.md symlink (#421 ) (82e74d7 )
1.3.1 (2026-11-02)
Bug Fixes
1.3.0 (2026-10-04)
Features
Bug Fixes
bump anyio>=4.14.2 to resolve CVE-2026-63374 and CVE-2026-64847 (#375 ) (#376 ) (4a92718 )
request immutable ids for outbox drafts (#378 ) (bde2bb2 )
scope outbox receipts, save the token cache atomically (cece5ad )
skip German system folders in mail auto-discovery (#391 ) (4a8c454 )
1.2.5 (2026-09-21)
Bug Fixes
replace N+1 DB query patterns in worker and admin state (#361 ) (#368 ) (2ee15d3 )
1.2.4 (2026-09-09)
Bug Fixes
bump mkdocs-material to >=9.7.7 for CVE-2026-73295 (#349 ) (#352 ) (2f95ccd )
use is_relative_to instead of startswith for path-traversal guard (#341 ) (#343 ) (8c35fbf )
1.2.3 (2026-08-27)
Bug Fixes
close four recurring sync failures and an unretryable-draft path (#311 ) (b85200f )
retry token-transport faults and bound MSAL calls with a timeout (#309 ) (fd95a72 )
token acquisition never prompts (#312 ) (d3cdb2c )
1.2.2 (2026-08-21)
Bug Fixes
add missing return type annotations in commands and config_loader (#303 ) (#306 ) (a4733bf )
1.2.1 (2026-08-19)
Bug Fixes
enforce attachment_root boundary in resolve_attachment (#299 ) (#300 ) (4b8d8b6 )
1.2.0 (2026-08-10)
Features
consolidate five units into m365-brain (4d7eb21 )
file catalogue, three silent-config fixes, and publication readiness (b349830 )
knowledge layer, Graph transport, and the vault path contract (2f587f6 )
make the file catalogue real, close three silent-config defects, and scrub for publication (1968fbd )
one config root covering every knob the port needs (83c0a68 )
runtime, CLI, and the three bundled skills (bf1401a )
the typed outbox, Graph file writes, and auth profiles (dcaa3a1 )
Bug Fixes
$top on a delta query is the item budget, not a page size (#264 ) (81912ca )
bump pypdf lower bound to 6.15.0 for CVE-2026-71852 and CVE-2026-71870 (#277 ) (#281 ) (3cbe17d )
drop email lookback_days, a window Graph never applied (#266 ) (df0a98f )
keep logs off stdout in every verb, not just two (cf242d9 )
make a capped answer say it was capped (a319694 )
make a contact's address resolvable by ops links (ce90a00 )
make a contact's address resolvable by ops links (70e92e7 )
make a Teams chat's participants countable by ops tiers (a94be26 )
make a Teams chat's participants countable by ops tiers (b64ebd7 )
make every config knob bind, or take it out (e7ea191 )
resolve every printed path, and accept one back (36cdb69 )
scope the prune to the roots a run actually walked (26b8294 )
separate two status vocabularies, give relations spellable types (#265 ) (83081a4 )
stop answering three different questions with exit 3 (d13236b )
stop four words from carrying two vocabularies each (a076ba6 )
Documentation
add INTENT.md, CONTRACTS.md, and ADRs 0001-0012 (b335ef0 )
author the deferred backlog (51d05fd )
bring in the knowledge-layer design docs and split the test tree (215fd50 )
stop the shipped documents describing a CLI that is not there (347f01f )
task for an application-permission auth profile (4d59fe2 )
1.1.1 (2026-08-04)
Bug Fixes
add leading dot to svc.ms in SSRF domain allowlist (#182 ) (d0c5cb7 )
catch GraphApiError instead of dead httpx.HTTPStatusError in _file_helpers.py (#184 ) (a65f640 )
consume OAuth CSRF state token after verification to prevent replay (#245 ) (219b89d )
eliminate TOCTOU race in token cache file permissions (#239 ) (d10aa75 )
remove type: ignore suppressions in _teams_ingest.py with assert narrowing (#256 ) (897d39c )
replace type: ignore with sqlalchemy.desc() in admin_state.py (#189 ) (05ca1b4 )
store OAuth CSRF state as per-token files (#244 ) (951bfea )
update stale test call sites for consolidated refactors (a75a0e5 )
1.1.0 (2026-06-16)
Features
adopt obsidian-import 1.2.0 public API and extraction isolation (8773a1d )
merge-based incremental Teams sync with whole-history retention (e0d9378 )
skip non-file Teams attachment types and stop retrying permanent download failures (912396a )
teams_chats: download file attachments and inline images (6eae19c )
Bug Fixes
add missing teams_chats attachment fields to admin config test fixtures (fcd8bb0 )
add missing teams_chats attachment fields to test config fixtures (8638edf )
escape single quotes in OData folder filter to prevent injection (#214 ) (a967321 )
re-raise unexpected exceptions in worker instead of swallowing (#207 ) (d22f9cc )
remove unused _access_token state var storing raw bearer token (#215 ) (48ab25f )
validate user_id as UUID before filesystem path construction (#216 ) (26ecb6f )
1.0.0 (2026-05-14)
⚠ BREAKING CHANGES
EmailExtractorConfig.folders is replaced by a mailboxes list. Each entry has address (use "me" for /me/ endpoints, or a UPN for /users/{address}/ endpoints), folders (list or null for auto-discovery), and output_subdir (storage namespace under emails/).
Features
support multiple mailboxes in email extractor (d65700f )
Bug Fixes
add server-side admin authorization to AdminState handlers (#169 ) (4064034 )
align tests with module split and apply ruff format/imports (16f95c4 )
email: drop wellKnownName from auto-discover (v1.0 incompatible) (953b6c8 )
email: drop wellKnownName from auto-discover select (v1.0) (ccea9fc )
narrow SSRF allowlist by replacing .windows.net with specific CDN domains (#171 ) (e4bd3d9 )
pin pillow >=12.2.0 to remediate CVE-2026-40192 (#127 ) (509ab6d )
sanitize attachment filename to basename to prevent path traversal (#170 ) (f8ad054 )
0.3.0 (2026-04-13)
Features
add Alembic DB migrations - WP4 (cb7793e )
add config.deploy.yaml for Azure Blob storage in production (74a7ea5 )
add email attachment download + dedup to m365-extract (620b587 )
add observability (WP3) + type converters config (WP2e) (5e01da6 )
add sync type and pagination transparency logging for email (a09cda0 )
add truncation indicator to teams chat frontmatter (4460228 )
enable onedrive, sharepoint, contacts extractors (55bf9c6 )
harden continuous mode with auth failure recovery and heartbeat logging (f5d8ea6 )
implement contacts and directory extractors (79c9149 )
implement contacts and directory extractors (4666ef0 ), closes #16
include attendee email and status in calendar events (0c35526 )
merge daemon into web app (WP8) + constitution fixes (b06f67c )
per-user storage isolation in daemon (8a16324 )
Sub-phase 4A — TokenStore, UserManager, WebConfig (9bf5c3c )
Sub-phase 4B — auth code flow + web token provider (c649172 )
Sub-phase 4C — FastAPI app shell with auth, sync, health endpoints (da325e8 )
Sub-phase 4D — scheduler + admin routes (758bec4 )
unify deployment config — single config.deploy.yaml for both services (d7b848d )
Bug Fixes
add missing email config fields and fix token expiry buffer in tests (5874b96 )
add missing email config fields to test fixtures and fix token expiry buffer (1588b7f )
add missing graph config fields to admin config loader test fixtures (e02a30a )
add missing graph config fields to admin config loader test fixtures (5d515d7 )
add missing graph config fields to admin config loader tests (e525471 )
add missing graph config fields to admin test fixtures (903b35b )
add missing graph config fields to admin test fixtures (b283168 )
add missing graph config fields to admin test fixtures (6b3478f )
add missing graph config fields to admin test fixtures (832b5c5 )
align test_returns_cached_token_when_valid expires_at with token buffer (#98 ) (63a887b )
auto-fix CI failures (attempt 1) (3771c6d )
auto-fix CI failures (attempt 1) (fd878e5 )
auto-fix CI failures (attempt 1) (ea1ae0b )
auto-fix CI failures (attempt 1) (9a049d4 )
auto-fix CI failures (attempt 1) (7c6d081 )
auto-fix CI failures (attempt 1) (bd4ef3a )
auto-fix CI failures (attempt 1) (08726ff )
auto-fix CI failures (attempt 1) (18a492c )
auto-fix CI failures (attempt 1) (72c16bd )
create writable state dir for daemon in Docker (043270a )
enable WebSockets + upgrade Actions to Node.js 24 (773374f )
Graph API compatibility for teams_channels, contacts, and null sender (e6d4b21 )
narrow broad except Exception to specific types in email extractor (#94 ) (9156710 )
pin pypdf >=6.9.2 to mitigate CVE-2026-33699 infinite loop DoS (#91 ) (5cc359d )
populate items_synced in SyncRecord from extractor counts (181e813 )
remove magic number and duplicated config fallback in worker.py (#95 ) (cfd4896 )
serialize ConvertersConfig to dict before passing to extractors (#44 ) (5b9c1e0 )
use JSON params files instead of .bicepparam for Bicep deploy (9c7c567 )
validate and cap Retry-After header in graph client (#70 ) (81311e6 )
validate download URL domains and sanitize SAS tokens from logs (#41 ) (c5cb8b5 )
web app must use config.web.yaml (no blob storage env vars) (264358c )
Documentation
update MATURITY.md and roadmap.md to reflect dark factory progress (5bd1bab )
[Unreleased]
Breaking Changes
m365_extract.frontmatter builders now take a single dataclass argument instead of keyword arguments. Replace build_email_frontmatter(subject=..., message_id=..., ...) with build_email_frontmatter(EmailData(subject=..., message_id=..., ...)). Same shape for build_calendar_frontmatter / CalendarEventData, build_contact_frontmatter / ContactData, build_directory_user_frontmatter / DirectoryUserData, build_onedrive_frontmatter / OneDriveFileData, build_sharepoint_frontmatter / SharePointFileData, build_teams_chat_frontmatter / TeamsChatData, and build_teams_channel_frontmatter / TeamsChannelData. All dataclass fields are required — callers must pass every field explicitly.
Security
Pin pyopenssl>=26.0,<27 to fix CVE-2026-27448 (TLS callback bypass) and CVE-2026-27459 (buffer overflow)
Upgrade pypdf from 6.9.2 to 6.10.0 to fix CVE-2026-40260 (memory DoS via crafted PDF XMP metadata, GHSA-3crg-w4f6-42mx)
Track CVE-2026-3219 (pip ZIP/tar archive confusion, GHSA-58qw-9mgm-455v, MODERATE) — no fix released yet; pin will be narrowed when a patched pip version is available
Features
worker refactor : replaced monolithic daemon thread with independent sync worker (m365_extract/worker.py)
Per-(user, extractor) jobs via ThreadPoolExecutor with configurable concurrency
PostgreSQL advisory locks prevent duplicate job runs
ExtractorStatus model replaces SyncRecord (single row per user+extractor pair)
New CLI command m365-extract worker for standalone multi-user sync
start_worker_thread() bridge for single-container deployment
Per-extractor state files eliminate concurrent write races
Dashboard shows per-extractor status grid
WorkerConfig section added to config schema
docker-compose updated with separate worker service
Alembic migration: syncrecord → extractorstatus
Breaking Changes
CLI sync --continuous removed (replaced by worker command)
SyncRecord model replaced by ExtractorStatus
daemon.py, daemon_runner.py, continuous.py deleted
0.2.2 (2026-03-20)
Bug Fixes
log warning instead of silently swallowing exceptions in teams_chats.py (#15 ) (2792534 )
replace bare RuntimeError with GraphApiError in graph_client.py (#17 ) (f64cb90 )
resolve merge conflicts with main (deb79e8 )
0.2.1 (2026-03-18)
Bug Fixes
add path traversal protection to LocalBackend (3e8a1f3 )
add path traversal protection to LocalBackend (d670501 ), closes #3
auto-fix CI failures (attempt 1) (eae79af )
format local.py to pass ruff format check (68102b5 )
set restrictive permissions (0600) on MSAL token cache file (ae73ff0 )
set restrictive permissions (0600) on MSAL token cache file (a41314a ), closes #4
0.2.0 (2026-03-17)
Features
initial release with full packaging infrastructure (7ab5361 )
Bug Fixes
disable --locked for setup-pixi in release lockfile update job (4b8a5cc )
use docker run with --skipApiVersionCheck for Azurite in CI (470b82a )
[0.1.0] - 2026-03-17
Added
Core Graph API client with delta sync, pagination, retry, rate limiting
MSAL device code authentication with token caching
6 extractors: email, calendar, teams_chats, teams_channels, onedrive, sharepoint
Local filesystem storage backend
Azure Blob Storage backend with Azurite dev workflow
Document conversion via obsidian-import integration
CLI: m365-extract auth login, sync --once, sync --continuous
Frozen dataclass config with strict validation and env var expansion
Bicep IaC templates for Azure Storage (dev/prod)
Docker images (Dockerfile.web, Dockerfile.daemon — multi-stage, non-root)
Docker Compose with Azurite emulator (profile)
158 unit tests + 9 Azurite integration tests
Back to top