- Add 429 retry with exponential backoff to register_client() (fixes CI
oauth matrix failures from parallel DCR requests)
- Make client_id, redirect_uri, and PKCE mandatory at token endpoint
- Add null-checks for discovery_url and OAuth credentials in proxy flows
- Add OIDC discovery document caching with 5-min TTL
- Add per-IP rate limiting on /oauth/register DCR proxy
- Discover DCR endpoint from OIDC discovery instead of hardcoding
- Extract extract_user_id_from_token to auth/token_utils.py (breaks
circular imports between server/ and auth/ layers)
- Add TTL scope cache in scope_authorization.py (avoids DB hit per tool)
- Add defense-in-depth scope validation in storage layer
- Broaden elicitation exception handling with graceful fallback
- Add idempotentHint to nc_auth_check_status, return "pending" status
after accepted elicitation, add polling interval to description
- Change ALL_SUPPORTED_SCOPES from tuple to frozenset for O(1) lookups
- Replace Optional[str] with str | None throughout config.py
- Use default_factory for ProxyCodeEntry/ASProxySession dataclasses
- Add proxy code/session cleanup to background loop
- Fix OIDC verification CI step to only run for oauth/login-flow modes
- Add unit tests for access.py REST endpoints (10 tests)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The GITHUB_ACTIONS skip was added before Playwright automation existed,
when tests required manual browser interaction. Now that Playwright
handles the OAuth flow programmatically, the skip is unnecessary —
GitHub Actions fully supports Playwright with localhost networking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add cross-product matrix (3 versions x 4 auth modes = 12 CI jobs)
- Parameterize Nextcloud image in docker-compose.yml via NEXTCLOUD_IMAGE env var
- Pin NC 31.0.8, 32.0.6, 33.0.0 with SHA digests in workflow
- Add Renovate customManagers to auto-update NC images in workflow
- Fix Astrolabe install hook to prefer volume mount over app store
- Bump Astrolabe submodule to support NC 33 (max-version 31→33)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix circular dependency in scope_authorization: auth tools requiring
only identity scopes (openid/profile/email) now bypass the login flow
provisioning check, so unprovisioned users can call provisioning tools
- Fix no-op detection in nc_auth_update_scopes: NULL scopes (legacy "all")
now correctly map to ALL_SUPPORTED_SCOPES instead of empty set
- Fix get_app_password_with_scopes swallowing exceptions: re-raise instead
of returning None, matching sibling methods
- Add missing audit logging to update_app_password_scopes,
delete_login_flow_session, and delete_expired_login_flow_sessions
- Pin setup-uv to v7.3.1 in CI unit-test job (was v7.3.0)
- Add FastMCP type annotation to register_auth_tools parameter
- Log warning when user accepts elicitation without checking acknowledged box
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Astrolabe tests moved to multi_user_basic markers use Playwright browser
automation, so the CI matrix entry needs needs-playwright: true.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consolidate three independent RefreshTokenStorage lazy singletons into a
single lock-protected get_shared_storage() function, eliminating race
conditions on concurrent first-access. Remove blanket try/except in
_get_stored_scopes so storage errors propagate as proper MCP errors
instead of silently triggering "please provision" messages. Handle
declined/cancelled elicitation results in Login Flow tools by cleaning up
sessions and returning clear status. Add update_app_password_scopes() to
avoid unnecessary decrypt/re-encrypt when only scopes change. Add
unprovisioned-user early exit and no-op detection to nc_auth_update_scopes.
Remove four dead config fields and misleading NEXTCLOUD_PASSWORD deprecation
warning. Add periodic login flow session cleanup task. Generate separate
Fernet keys per service. Add board cleanup in deck integration test. Gate
CI unit tests on linting and skip Astrolabe build for single-user profile.
Fix test markers from oauth to multi_user_basic for astrolabe integration
tests. Update login_flow.py docstrings to document outbound HTTP calls.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The dev OIDC app was mounted for all profiles but composer install only
ran for Playwright profiles, causing a missing vendor/autoload.php fatal
error that broke all /apps/* and /ocs/* routes. The hook script already
has app store fallback logic, so removing the dev mount is sufficient.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Nextcloud health check expected HTTP 401 from serverinfo, but NC 32
returns 200 — causing 5-minute timeouts. Switch to /status.php with
"installed":true check (matches Docker healthcheck). Also route the
correct MCP_SERVER_URL per CI matrix profile into the app container so
Astrolabe connects to the right service, and make the init script
gracefully skip when the var is unset.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PHP setup was gated behind needs-playwright but Astrolabe build needs
composer unconditionally. Add multi-user-basic CI matrix entry with
proper marker filtering. Upload Playwright screenshots and service logs
as artifacts on failure for easier debugging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix data loss in nc_auth_update_scopes: remove premature
delete_app_password call; old password stays valid until upsert
replaces it on successful re-provisioning
- Replace assert with proper error return in nc_auth_check_status
- Add lazy singleton for RefreshTokenStorage in auth_tools,
scope_authorization, and context to avoid per-call re-initialization
- Centralize _is_login_flow_mode() to get_settings().enable_login_flow
and remove duplicate definitions and per-call os.getenv reads
- Add dev-only comment to TOKEN_ENCRYPTION_KEY in docker-compose.yml
- Gate OIDC build steps in CI behind matrix.needs-playwright
- Add diagnostic step reporting Playwright skip count in CI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add @pytest.mark.oauth to OAuth-dependent tests in
test_scope_authorization.py so they're excluded from single-user job
- Add module-level pytestmark to test_introspection_authorization.py
- Fix single-user marker expression to also exclude oauth smoke tests
- Add --ignore paths for multi-user, qdrant, and RAG evaluation tests
- Uncomment GITHUB_ACTIONS skip in oauth_callback_server fixture
- Add GITHUB_ACTIONS skip to login_flow_oauth_token fixture
- Mount third_party/oidc volume in docker-compose.yml app service
- Add OIDC diagnostic step in CI for playwright jobs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Unit test fixes:
- test_userinfo_routes: patch nextcloud_httpx_client instead of httpx.AsyncClient
- test_instrument_tool: patch trace_operation in metrics module (where imported)
- test_management_app_password_endpoints: patch nextcloud_httpx_client and
get_settings at correct import locations
- test_management_status_endpoint: patch detect_auth_mode and get_settings at
correct import locations (api.management, not config/config_validators)
- test_token_exchange: fix TokenBrokerService constructor args (client_id/
client_secret instead of encryption_key)
CI:
- Add Node.js setup and astrolabe build step (composer + npm ci + npm run build)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The third_party volume mount is required for astrolabe/notes/oidc
development. Always checkout submodules and build the OIDC app in
all CI matrix jobs since the app container needs it.
Remove the docker-compose.oidc.yml override (no longer needed).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The third_party:/opt/apps volume was accidentally uncommented in
docker-compose.yml. Without submodules checked out, this empty mount
breaks the Notes app installation hook in CI.
Fix: keep the mount commented in docker-compose.yml and add a separate
docker-compose.oidc.yml override that's only used for OIDC-requiring
profiles (oauth, login-flow) in CI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Unit tests have pre-existing failures unrelated to deployment mode
testing. Run integration matrix after linting only so the matrix
can expand and test each profile independently.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the single integration-test job with a matrix that tests each
deployment mode independently using Docker Compose profiles:
- single-user: smoke + integration tests (port 8000)
- oauth: OAuth flow tests with Playwright (port 8001)
- login-flow: Login Flow v2 tests with Playwright (port 8004)
Unit tests run separately without Docker. OIDC app build and Playwright
install are conditional based on the mode. Service logs are captured on
failure for debugging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Renovate's helpers:pinGitHubActionDigestsToSemver preset reads version
comments to track updates. Major-only comments (e.g. # v6) produce
unhelpful changelog diffs like "v6 → v6". Full semver comments
(e.g. # v6.0.2) let Renovate show meaningful version changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>