Browse Source
Note in README and design that lossless restore makes revocation IdP-authoritative: a member revoked in the vault is re-activated on the next sync if the IdP still shows them active, and a leaked token can reinstate any previously-confirmed member. Document token-management audit events and the omitted-vs-empty members and externalId-uniqueness semantics. Add TODOS.md tracking the deferred follow-ups (config-gated denial tests, live Entra validation, coverage edges, perf backlog, upstream ip_constant lints). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>pull/7443/head
3 changed files with 195 additions and 6 deletions
@ -0,0 +1,134 @@ |
|||
# TODOS |
|||
|
|||
## SCIM |
|||
|
|||
### Config-gated denial tests (SCIM_ENABLED=false, ORG_GROUPS_ENABLED=false) |
|||
|
|||
**What:** Test the two config master switches from the denied side: a valid token |
|||
against `SCIM_ENABLED=false` must get the uniform 401, and any Groups route with |
|||
`ORG_GROUPS_ENABLED=false` must get the SCIM-enveloped 501. |
|||
|
|||
**Why:** These are the primary kill switches for the whole surface and the one |
|||
authz-matrix case the build plan promised that is still missing. |
|||
|
|||
**Context:** `CONFIG` is a process-global `LazyLock` pinned by the `test-support` |
|||
`#[ctor]` before main, so the disabled states cannot be tested in the same |
|||
process as the enabled suite. Needs either a second test binary with its own |
|||
ctor env, or an injectable check in `guard.rs` / `groups.rs`. See the |
|||
`plan-delivery-gap-scim-disabled-authz-case` learning. |
|||
|
|||
**Effort:** M |
|||
**Priority:** P1 |
|||
**Depends on:** None |
|||
|
|||
### Live Entra ID tenant validation |
|||
|
|||
**What:** Run the full lifecycle against a throwaway Entra tenant: Test |
|||
Connection, assign user, create/update/deprovision/restore, group sync, token |
|||
rotation. Follow docs/scim/README.md as written and fix any doc drift found. |
|||
|
|||
**Why:** Everything is verified against RFC 7643/7644 and observed Entra |
|||
behaviour, but no real Entra sync has run against this build yet. |
|||
|
|||
**Context:** User-driven (needs a tenant). Never production. The rate limiter |
|||
keys on `IP_HEADER` (`X-Real-IP`) - the deployment in front must set it. |
|||
|
|||
**Effort:** M |
|||
**Priority:** P1 |
|||
**Depends on:** Branch pushed and deployed somewhere TLS-fronted |
|||
|
|||
### Mail-enabled invite failure path, end to end |
|||
|
|||
**What:** An integration test that runs `post_user` with mail enabled and a |
|||
failing SMTP target, asserting the 500 plus the rollback outcome. |
|||
|
|||
**Why:** The rollback decision logic is unit-tested |
|||
(`provisioning_rollback_spares_preexisting_users`), but the branch that calls it |
|||
(send_invite failure inside `post_user`) still never executes under test. |
|||
|
|||
**Context:** Needs mail enabled in `CONFIG` (same process-global constraint as |
|||
above) plus a fast-failing SMTP endpoint; naive versions are slow or flaky. |
|||
Consider folding into the same second test binary as the config-gated tests. |
|||
|
|||
**Effort:** M |
|||
**Priority:** P2 |
|||
**Depends on:** Config-gated denial tests (shared harness) |
|||
|
|||
### Coverage: error-envelope edges and manage HTTP surface |
|||
|
|||
**What:** Tests for the remaining actionable gaps from the ship coverage audit |
|||
(82%): malformed-body 400 / oversized-body 413 envelopes, HTTP-level 429 |
|||
envelope, POST /Users missing/invalid email 400s, policy-blocked restore 400, |
|||
GroupPatch path-less object form (Entra sends this shape), externalId HTTP |
|||
filters, POST /Groups blank-name 400 and dup-externalId 409, and the manage |
|||
endpoints driven over HTTP with AdminHeaders. |
|||
|
|||
**Why:** These are the branches where a regression would surface to Entra as a |
|||
wrong status code or envelope, currently proven only by adjacent coverage. |
|||
|
|||
**Context:** All testable in the existing Rocket-local harness except the |
|||
manage endpoints, which need an AdminHeaders fixture. Coverage map in the |
|||
2026-07-19 ship PR body has the full gap list. |
|||
|
|||
**Effort:** M |
|||
**Priority:** P2 |
|||
**Depends on:** None |
|||
|
|||
### Performance backlog for large orgs |
|||
|
|||
**What:** SQL-side pagination for /Users and /Groups lists, batched group |
|||
member writes (resolve via `eq_any`, diff instead of delete-all+reinsert on |
|||
PUT), and secondary indexes on `users_organizations(org_uuid, external_id)` and |
|||
`groups(organizations_uuid, external_id)`. |
|||
|
|||
**Why:** Current implementation loads full member/group sets per list request |
|||
and issues ~4N queries for an N-member group write. Fine at self-host scale |
|||
(hundreds of members); wasteful for thousands. |
|||
|
|||
**Context:** Indexes diverge from upstream's no-secondary-index convention - |
|||
decide deliberately. Review findings from 2026-07-19 have the details. |
|||
|
|||
**Effort:** L |
|||
**Priority:** P3 |
|||
**Depends on:** None |
|||
|
|||
### Harden SCIM write edges surfaced by adversarial review |
|||
|
|||
**What:** Three lower-severity robustness gaps from the 2026-07-19 adversarial |
|||
pass: (1) externalId uniqueness is check-then-set with no backing DB unique |
|||
index, so concurrent writes could duplicate the correlation key; (2) a Group |
|||
displayName > 100 chars or externalId > 300 chars from Entra hits the MySQL |
|||
column limit and returns a 500 instead of a 400 invalidValue; (3) `scim_status` |
|||
returns key metadata behind only an AdminHeaders session with no password/OTP |
|||
re-auth, unlike generate/delete. |
|||
|
|||
**Why:** None are exploitable today (single Entra sync engine; strict-mode MySQL |
|||
only; admin session required), but each is an unenforced invariant or an |
|||
inconsistent guard that a future change could turn into a real bug. |
|||
|
|||
**Why not now:** (1) wants a migration adding a partial unique index across three |
|||
dialects - real schema work, deferrable; (2) wants length validation in the |
|||
Group handlers; (3) is a one-line guard tightening. Bundle them. |
|||
|
|||
**Effort:** M |
|||
**Priority:** P2 |
|||
**Depends on:** None |
|||
|
|||
## Upstream hygiene |
|||
|
|||
### ip_constant clippy lints in http_client.rs tests |
|||
|
|||
**What:** 9 pre-existing `clippy::ip_constant` errors in upstream |
|||
`src/http_client.rs` test code under `--all-targets` with the 1.96 toolchain. |
|||
|
|||
**Why:** Blocks running `cargo clippy --all-targets` clean locally; will bite |
|||
if CI ever lints test targets. |
|||
|
|||
**Context:** Upstream code, untouched per branch discipline. Fix as a separate |
|||
commit or PR upstream (`Ipv4Addr::LOCALHOST` instead of hand-coded addresses). |
|||
|
|||
**Effort:** S |
|||
**Priority:** P3 |
|||
**Depends on:** None |
|||
|
|||
## Completed |
|||
Loading…
Reference in new issue