Config Snapshots
Point-in-time backups of a tenant's configuration, section by section, diffable against each other and optionally mirrored into a real git repository. This is a visibility and drift-detection layer, deliberately separate from the Deploy wizard and known-fix Workflows that actually change a tenant -- see "What this deliberately doesn't do" below.
Sections
A snapshot captures every registered section in one run. Today:
| Section | Category | Graph resource |
|---|---|---|
| Conditional Access Policies | Identity | /identity/conditionalAccess/policies |
| Named Locations | Identity | /identity/conditionalAccess/namedLocations |
| Device Compliance Policies | Devices | /deviceManagement/deviceCompliancePolicies |
Each captures the full object, minus createdDateTime/modifiedDateTime-style
timestamps (they change on every edit regardless of whether anything meaningful did, which would
otherwise show up as permanent noise in every diff). Adding a section is a new
IConfigSection implementation registered through DI -- same pattern as adding a
known-fix Workflow -- with no controller or diff-engine change needed.
Diffing
Any two snapshot runs can be diffed, either one section at a time or across the whole tenant.
Each item is matched by its Graph id; the diff reports items added, removed, or
modified (with the specific top-level fields that changed). A run's history is the backup: taking
a new snapshot before a risky change gives you a known-good point to diff back against afterward.
Workbooks: export and import
A single run, or a diff between two runs, can be exported as a portable file -- a run exports as
JSON, a diff exports as readable patch-style text (*.patch) suitable for pasting
into a ticket. An exported run can be re-imported (on this instance or a different one) to create
a new snapshot record from already-captured data, purely for comparison.
Git sync (optional)
Set GitSync:RepoUrl and every successful capture also gets committed and pushed to a
real git repository -- GitHub or any host that speaks standard HTTPS git. Each section becomes
one file under tenants/{tenant}/{section}.json; a capture with no changes since the
last one makes no commit. This turns tenant configuration into real version-controlled history:
diffable and blameable with any git tool, browsable on GitHub, not just inside the app.
Implemented by shelling out to the git CLI (the same out-of-process pattern
PwshRunner uses for Exchange Online), not a native git library -- one well-known
tool already in the container image, not a new native-binary compatibility surface. The auth
token is sent as a per-request HTTP header and never written to the working copy's git config or
embedded in the remote URL, so it never touches disk.
| Key | Notes |
|---|---|
GitSync:RepoUrl | e.g. https://github.com/your-org/tenant-config-history.git. Unset = disabled (default). |
GitSync:Branch | Default main. |
GitSync:Token | Secret. A token with push access (a GitHub PAT with repo scope, or equivalent). |
GitSync:CommitterName / CommitterEmail | Attribution on the commits this app makes. |
GitSync:LocalPath | Working copy on disk. Default /git-sync -- mount a persistent volume there in production, same as /keys and /packages. |
Access control
Follows the same per-tenant roles as everything else (see Authentication): Viewer can list runs and view/export diffs; Operator can also take a new snapshot or import a workbook. There is no separate permission model for this feature.