## Summary <!-- Kurz: Was ändert sich und warum? --> ## Spec-Driven Development (SDD) - [ ] Es gibt eine Spec unter `specs/<NNN>-<feature>/` - [ ] Enthaltene Dateien: `plan.md`, `tasks.md`, `spec.md` - [ ] Spec beschreibt Verhalten/Acceptance Criteria (nicht nur Implementation) - [ ] Wenn sich Anforderungen während der Umsetzung geändert haben: Spec/Plan/Tasks wurden aktualisiert ## Implementation - [ ] Implementierung entspricht der Spec - [ ] Edge cases / Fehlerfälle berücksichtigt - [ ] Keine unbeabsichtigten Änderungen außerhalb des Scopes ## Tests - [ ] Tests ergänzt/aktualisiert (Pest/PHPUnit) - [ ] Relevante Tests lokal ausgeführt (`./vendor/bin/sail artisan test` oder `php artisan test`) ## Migration / Config / Ops (falls relevant) - [ ] Migration(en) enthalten und getestet - [ ] Rollback bedacht (rückwärts kompatibel, sichere Migration) - [ ] Neue Env Vars dokumentiert (`.env.example` / Doku) - [ ] Queue/cron/storage Auswirkungen geprüft ## UI (Filament/Livewire) (falls relevant) - [ ] UI-Flows geprüft - [ ] Screenshots/Notizen hinzugefügt ## Notes <!-- Links, Screenshots, Follow-ups, offene Punkte --> Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box> Reviewed-on: #78
163 lines
9.5 KiB
Markdown
163 lines
9.5 KiB
Markdown
<!--
|
|
Sync Impact Report
|
|
|
|
- Version change: 1.4.0 → 1.5.0
|
|
- Modified principles:
|
|
- Tenant Isolation is Non-negotiable (added deny-as-not-found requirement)
|
|
- Added sections:
|
|
- RBAC Standard (RBAC-001..RBAC-009)
|
|
- Removed sections: None
|
|
- Templates requiring updates:
|
|
- ✅ .specify/templates/plan-template.md
|
|
- ✅ .specify/templates/spec-template.md
|
|
- ✅ .specify/templates/tasks-template.md
|
|
- N/A: .specify/templates/commands/ (directory not present)
|
|
- Follow-up TODOs: None
|
|
-->
|
|
|
|
# TenantPilot Constitution
|
|
|
|
## Core Principles
|
|
|
|
### Inventory-first, Snapshots-second
|
|
- All modules MUST operate primarily on Inventory as “last observed” state.
|
|
- Inventory is the source of truth for what TenantPilot last observed; Microsoft Intune remains the external truth.
|
|
- Snapshots/Backups MUST be explicit actions (manual or scheduled) and MUST remain immutable.
|
|
|
|
### Read/Write Separation by Default
|
|
- Analysis, reporting, and monitoring features MUST be read-only by default.
|
|
- Any write/change function (restore, remediation, promotion) MUST include preview/dry-run, explicit confirmation, audit logging, and tests.
|
|
- High-risk policy types default to `preview-only` restore unless explicitly enabled by a feature spec + tests.
|
|
|
|
### Single Contract Path to Graph
|
|
- All Microsoft Graph calls MUST go through `GraphClientInterface`.
|
|
- Object types and endpoints MUST be modeled first in the contract registry (`config/graph_contracts.php`).
|
|
- Feature code MUST NOT hardcode “quick endpoints” or bypass contracts.
|
|
- Unknown/missing policy types MUST fail safe (preview-only / no Graph calls) rather than guessing endpoints.
|
|
|
|
### Deterministic Capabilities
|
|
- Backup/restore/risk/support flags MUST be derived deterministically from config/contracts via a Capabilities Resolver.
|
|
- The resolver output MUST be programmatically testable (snapshot/golden tests) so config changes cannot silently break behavior.
|
|
|
|
### Tenant Isolation is Non-negotiable
|
|
- Every read/write MUST be tenant-scoped.
|
|
- Cross-tenant views (MSP/Platform) MUST be explicit, access-checked, and aggregation-based (no ID-based shortcuts).
|
|
- Prefer least-privilege roles/scopes; surface warnings when higher privileges are selected.
|
|
- A non-member attempting to access a tenant route MUST be deny-as-not-found (404).
|
|
|
|
### RBAC Standard (RBAC-001)
|
|
|
|
RBAC-001 Two Planes
|
|
- The platform MUST maintain two strictly separated authorization planes:
|
|
- Tenant plane (`/admin/t/{tenant}`): authenticated Entra users (`users`), authorization is tenant-scoped.
|
|
- Platform plane (`/system`): authenticated platform users (`platform_users`), authorization is platform-scoped.
|
|
- Cross-plane access MUST be deny-as-not-found (404) (not 403) to avoid route enumeration.
|
|
|
|
RBAC-002 Capabilities-first Authorization
|
|
- Feature code MUST NOT check raw roles directly (e.g. string role comparisons).
|
|
- Feature code MUST check capabilities via Gates/Policies only.
|
|
- A canonical capability registry MUST exist as the single source of truth (e.g. `TenantCapabilities` / `PlatformCapabilities`).
|
|
- Role → capability mapping MUST reference only registry entries.
|
|
|
|
RBAC-003 Least Privilege Role Semantics
|
|
- Tenant roles MUST follow least-privilege semantics:
|
|
- Readonly: view-only; MUST NOT start operations and MUST NOT mutate data.
|
|
- Operator: MAY start allowed tenant operations; MUST NOT manage credentials, settings, members, or perform destructive actions.
|
|
- Manager: MAY manage tenant configuration and start operations; MUST NOT manage tenant memberships (Owner-only).
|
|
- Owner: MAY manage memberships and all tenant configuration; Owner-only “danger zone” actions MUST remain Owner-only.
|
|
|
|
RBAC-004 UI is not Security
|
|
- Hiding UI elements is NOT sufficient.
|
|
- Every mutation endpoint and action MUST enforce authorization server-side (Policy/Gate).
|
|
|
|
RBAC-005 Destructive Actions Gate
|
|
- All destructive actions (delete / force delete / irreversible operations) MUST:
|
|
- require an explicit confirmation (e.g., `requiresConfirmation()` or equivalent),
|
|
- be protected by a Policy/Gate,
|
|
- have at least one regression test asserting the action is forbidden for non-authorized roles.
|
|
|
|
RBAC-006 Membership Safety Rule
|
|
- The system MUST prevent removing or demoting the last remaining Owner of a tenant.
|
|
|
|
RBAC-007 Tenant Isolation
|
|
- All tenant-plane queries MUST be tenant-scoped.
|
|
- A non-member attempting to access a tenant route MUST be deny-as-not-found (404).
|
|
|
|
RBAC-008 Auditing
|
|
- All access-control relevant changes MUST write `AuditLog` entries with stable action IDs, including:
|
|
- membership add / role change / remove
|
|
- provider credential rotation / connection disable
|
|
- break-glass enter / exit / expire (platform plane)
|
|
- `AuditLog` entries MUST be redacted (no secrets/tokens, minimal identity fields).
|
|
|
|
RBAC-009 Testability Gate
|
|
- Any new feature that introduces or changes authorization MUST include:
|
|
- at least one positive test (authorized user can do it),
|
|
- at least one negative test (unauthorized user cannot do it),
|
|
- and MUST NOT introduce role-string checks outside the central mapping/registry.
|
|
|
|
### Operations / Run Observability Standard
|
|
- Every long-running or operationally relevant action MUST be observable, deduplicated, and auditable via Monitoring → Operations.
|
|
- An action MUST create/reuse a canonical `OperationRun` and execute asynchronously when any of the following applies:
|
|
1. It can take > 2 seconds under normal conditions.
|
|
2. It performs remote/external calls (e.g., Microsoft Graph).
|
|
3. It is queued or scheduled.
|
|
4. It is operationally relevant for troubleshooting/audit (“what ran, who started it, did it succeed, what failed?”).
|
|
- Actions that are DB-only and typically complete in < 2 seconds MAY skip `OperationRun`.
|
|
- OPS-EX-AUTH-001 — Auth Handshake Exception:
|
|
- OIDC/SAML login handshakes MAY perform synchronous outbound HTTP (e.g., token exchange) without an `OperationRun`.
|
|
- Rationale: interactive, session-critical, and not a tenant-operational “background job”.
|
|
- Guardrail: outbound HTTP for auth handshakes is allowed only on `/auth/*` endpoints and MUST NOT occur on Monitoring/Operations pages.
|
|
- If an action is security-relevant or affects operational behavior (e.g., “Ignore policy”), it MUST write an `AuditLog` entry
|
|
including actor, tenant, action, target, before/after, and timestamp.
|
|
- The `OperationRun` record is the canonical source of truth for Monitoring (status, timestamps, counts, failures),
|
|
even if implemented by multiple jobs/steps (“umbrella run”).
|
|
- “Single-row” runs MUST still use consistent counters (e.g., `total=1`, `processed=0|1`) and outcome derived from success/failure.
|
|
- Monitoring pages MUST be DB-only at render time (no external calls).
|
|
- Start surfaces MUST NOT perform remote work inline; they only: authorize, create/reuse run (dedupe), enqueue work,
|
|
confirm + “View run”.
|
|
- Active-run dedupe MUST be enforced at DB level (partial unique index/constraint for active states).
|
|
- Failures MUST be stored as stable reason codes + sanitized messages; never persist secrets/tokens/PII/raw payload dumps
|
|
in failures or notifications.
|
|
- Graph calls are allowed only via explicit user interaction and only when delegated auth is present; never as a render side-effect (restore group mapping is intentionally DB-only).
|
|
- Monitoring → Operations is reserved for `OperationRun`-tracked operations.
|
|
- Scheduled/queued operations MUST use locks + idempotency (no duplicates).
|
|
- Graph throttling and transient failures MUST be handled with backoff + jitter (e.g., 429/503).
|
|
|
|
### Data Minimization & Safe Logging
|
|
- Inventory MUST store only metadata + whitelisted `meta_jsonb`.
|
|
- Payload-heavy content belongs in immutable snapshots/backup storage, not Inventory.
|
|
- Logs MUST not contain secrets/tokens; monitoring MUST rely on run records + error codes (not log parsing).
|
|
|
|
### Badge Semantics Are Centralized (BADGE-001)
|
|
- Status-like badges (status/outcome/severity/risk/availability/boolean signals) MUST render via `BadgeCatalog` / `BadgeRenderer`.
|
|
- Filament resources/pages/widgets/views MUST NOT introduce ad-hoc status-like badge mappings (use a `BadgeDomain` instead).
|
|
- Introducing or changing a status-like value MUST include updating the relevant badge mapper and adding/updating tests for the mapping.
|
|
- Tag/category chips (e.g., type/platform/environment) are not status-like and are not governed by BADGE-001.
|
|
|
|
### Spec-First Workflow
|
|
- For any feature that changes runtime behavior, include or update `specs/<NNN>-<slug>/` with `spec.md`, `plan.md`, `tasks.md`, and `checklists/requirements.md`.
|
|
- New work branches from `dev` using `feat/<NNN>-<slug>` (spec + code in the same PR).
|
|
|
|
## Quality Gates
|
|
- Changes MUST be programmatically tested (Pest) and run via targeted `php artisan test ...`.
|
|
- Run `./vendor/bin/pint --dirty` before finalizing.
|
|
|
|
## Governance
|
|
|
|
### Scope & Compliance
|
|
- This constitution applies across the repo. Feature specs may add stricter constraints but not weaker ones.
|
|
- Restore semantics changes require: spec update, checklist update (if applicable), and tests proving safety.
|
|
|
|
### Amendment Procedure
|
|
- Propose changes as a PR that updates `.specify/memory/constitution.md`.
|
|
- The PR MUST include a short rationale and list of impacted templates/specs.
|
|
- Amendments MUST update **Last Amended** date.
|
|
|
|
### Versioning Policy (SemVer)
|
|
- **PATCH**: clarifications/typos/non-semantic refinements.
|
|
- **MINOR**: new principle/section or materially expanded guidance.
|
|
- **MAJOR**: removing/redefining principles in a backward-incompatible way.
|
|
|
|
**Version**: 1.5.0 | **Ratified**: 2026-01-03 | **Last Amended**: 2026-01-27
|