Ctrl K
ComunidadGuías…

CONTRIBUTING.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Contributing to Intune Preflight

Thanks for your interest! Feedback, bug reports, and PRs are all welcome. See
[CHANGELOG.md](CHANGELOG.md) for what's shipped and [ROADMAP.md](ROADMAP.md) for where things
are headed.

## Reporting bugs

[Open an issue](https://github.com/kevinmalinoski/intune-preflight/issues/new/choose) using the
bug report template. Two things make a report easy to act on:

**Reproduce it in Demo mode if you can.** Demo mode runs the real engine over a bundled sample
tenant, so a repro there is one anyone can follow without access to your tenant — and it rules
out tenant-specific data as the cause. The [live demo](https://kevinmalinoski.github.io/intune-preflight/demo/)
works for this too; "select these groups, toggle that filter, this card is wrong" is a perfect
bug report.

**Include the server log** when the failure is in Graph fetching or auth:

```bash
docker compose logs server      # Docker
# or the terminal output from `npm run dev`
```

⚠️ **Never paste secrets.** Redact `TENANT_ID` / `CLIENT_ID` / `CLIENT_SECRET` and any tenant
identifiers. For security vulnerabilities, don't open an issue at all — see
[SECURITY.md](SECURITY.md).

## Dev setup

Requires Node.js 20+ (see [.nvmrc](.nvmrc)).

```bash
npm install
npm run dev               # server :4000, web :5173
```

**You don't need a tenant or an app registration to develop.** With no `.env` present the server
starts in **Demo** mode against the bundled sample tenant, which exercises every feature —
conflicts, overlaps, exclusions, Assignment Filters, dynamic Group Tag implication, unassigned
policies, and Autopilot V1 + V2. Most work can be done and tested entirely there.

To point it at a real tenant, add credentials and restart; the header's **Demo / Connected**
toggle unlocks once they're present:

```bash
cp .env.example .env      # fill in your app registration values
```

➡️ [Full setup guide — app registration, config, Docker](docs/SETUP.md)

Before opening a PR, make sure it builds, lints, formats and tests clean — the same four commands
CI runs:

```bash
npm run lint          # typecheck (tsc) + eslint
npm run format:check  # prettier, code only — docs are hand-wrapped and excluded
npm run build
npm test
```

`npm run lint:fix` and `npm run format` fix most of what those first two report.

## Tests

The engine is deliberately pure and unit-tested with [Vitest](https://vitest.dev) — assignment
resolution (include/exclude, filters, the assignment report), CSP normalization and the legacy
template → CSP crosswalk, cross-model conflict/overlap detection, dynamic-rule implication and
Group Tag / Autopilot rule evaluation, and platform classification. If you touch that logic,
please add or update a test — `npm run test:watch` while you work.

Rule parsing is where a test earns its keep most. The evaluator is **best-effort over the flat
clause shapes real tenants use**, not a full parser, so its tests double as the record of what is
and isn't claimed to work — if you extend it, the test is how that boundary moves.

Three test files exist to stop a specific regression rather than to check a feature, and are
worth reading before you touch what they guard: `packages/engine/src/purity.test.ts` (the
engine's browser-compatibility boundary), `packages/graph/src/purity.test.ts` (the same boundary
for the Graph reader) and `apps/web/src/endpointDevice.test.ts` (the simulator's state rules,
including the two bugs the old effect chain shipped).

## Project layout

```
apps/server/      Fastify API — app-only Graph auth, routes, config (the server shell)
apps/web/         React + Vite UI — endpoint simulator, assignment manifest, baseline drill-down
packages/graph/   The Graph reader — fetches a tenant into a TenantData, runs in Node AND the browser
packages/engine/  The simulation engine — pure, I/O-free, runs in Node AND the browser
packages/shared/  TypeScript types + rule helpers shared by everything
docs/             Setup guide, feature reference, screenshots
```

**The engine must stay I/O-free.** `packages/engine` takes a `TenantData` — the whole tenant's
configuration, already normalized — and computes everything from it, never fetching anything. That
is what lets the public demo (the same web app built with `VITE_STATIC_DEMO=1`) run the identical
code in the browser over the bundled sample tenant with no backend at all.

**`packages/graph` must stay browser-portable.** It *is* the I/O — it reads every
`deviceManagement` endpoint — but only over `fetch` and `AbortController`, which exist in Node and
in the browser alike. The two things that differ per host come in as parameters: the access token
(`createGraphClient({ getToken })`) and the cache the loaded tenant lives in. That is what will let
the whole app run in a tab against a delegated (user sign-in) token with no backend.

So: new analysis logic goes in `packages/engine`; new Graph reading goes in `packages/graph`; only
what genuinely needs the server — `process.env`, the MSAL confidential client, a request context —
goes in `apps/server`. A value import of a Node built-in or a server-only package from either
package fails its `purity.test.ts` and an ESLint rule, and CI also builds the demo
(`npm run build:demo`) so the browser path is proven end to end.

UI state that has *rules* — "this field resets that one", "turning this on selects those" — belongs
in a pure reducer next to its component rather than in a chain of `useEffect`s.
`apps/web/src/endpointDevice.ts` is the worked example and explains why; it's unit-tested like the
engine is.

## Guidelines

- Keep the tool **read-only** — it must never write to a tenant. All Graph permissions stay `*.Read.All`.
- Match the surrounding code style; keep comments focused on the *why*.
- Note any new Graph permission requirement in the README.
- Don't overclaim in the UI. Where analysis is heuristic — the rule evaluator, the cross-model
  crosswalk — say so in the interface rather than presenting a guess as fact.
- If you're changing rule-parsing or conflict/overlap logic, please describe how you tested it (a
  small reproduction against real rule shapes goes a long way).

## Code of conduct

Be kind and constructive. This is a community tool built to help fellow admins. See
[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).