Repository Structure
CONFIG365 uses four repository types in your self-hosted Gitea instance. Understanding how they relate to each other is essential for operating and extending the platform.
At a Glance
| Repository | Type |
|---|---|
| CONFIG365 | Scripts + pipeline templates |
| Tenant-template | Template for new tenants |
| baseline | Config-only (JSON files) |
| Tenant-{name} | Per-tenant repository |
Total repos after setup: 1 main + 1 template + 1 baseline + N tenants = 3 + N
Repositories
orchestrator Platform repository (config365 org) PowerShell scripts and reusable Gitea Actions workflow templates. Seeded automatically on first boot. Central reference for all MSP pipelines.
- –
.gitea/workflows/ — deploy-pipeline.yml, backup-pipeline.yml, maintenance-pipeline.yml - –
scripts/graph-configs/ — deployment PowerShell scripts - –
scripts/backup/ — backup PowerShell scripts - –
scripts/common/ — shared utilities (auth, token handling)
tenant-template Template repository (MSP org) Copy this repo to onboard a new tenant. Pre-configured Gitea Actions workflows that automatically load baseline configs.
- –
.gitea/workflows/ — pre-configured Gitea Actions workflows - –
.baseline-ignore — optional: exclude specific baseline policies
baseline Configuration-only repository (MSP org) Contains JSON policy files deployed to ALL tenants. No pipeline execution — purely configuration storage.
- –
baseline/ — configurations to CREATE or UPDATE - –
baseline-remove/ — configurations to DELETE from tenants - –
Subfolders: groups/, conditional-access/, intune/, exchange/, etc.
tenant-{slug} Tenant repository (one per tenant, MSP org) Created automatically by the CONFIG365 portal when onboarding a tenant. Each tenant gets its own repo with isolated workflows and backups.
- –
.gitea/workflows/ — tenant Gitea Actions workflows (calls orchestrator templates) - –
.baseline-ignore — optional: exclude specific baseline policies - –
backups/ — daily backups auto-committed here
How It All Works Together
Pipeline triggers on the Tenant-{name} repository
Pipeline checks out the baseline repository — reads all JSON policy files
Pipeline checks out the CONFIG365 repository — loads PowerShell scripts
PowerShell scripts read JSON files from baseline/baseline/
Scripts deploy configurations to the tenant via Microsoft Graph API
Scripts process baseline/baseline-remove/ to delete stale resources
Baseline Repository Structure
baseline/
├── baseline/ # Configurations to CREATE/UPDATE
│ ├── apps/
│ │ ├── chocolatey/ # Choco Win32 LOB app definitions
│ │ └── winget/ # WinGet Win32 LOB app definitions
│ ├── authentication-policies/
│ ├── conditional-access/
│ │ ├── named-locations/ # Named location JSON files
│ │ └── policies/ # CA policy JSON files
│ ├── custom-attributes/
│ │ ├── attribute-definitions/
│ │ └── attribute-sets/
│ ├── enterprise-apps/ # Entra ID service principal definitions
│ ├── entra-id-consentpermissions/
│ │ ├── permissionClassifications/
│ │ └── policies/
│ ├── entra-id-device-settings/
│ │ ├── device-registration-policy.json
│ │ └── entra-id-settings.json
│ ├── exchange/
│ │ ├── irm-configuration/
│ │ ├── ome-configuration/
│ │ └── transport-rules/
│ ├── groups/ # Security group JSON definitions
│ ├── information-protection/
│ │ ├── sensitivity-labels/
│ │ ├── label-policies/
│ │ ├── label-policy-rules/
│ │ ├── auto-label-policies/
│ │ ├── auto-label-rules/
│ │ ├── dlp-policies/
│ │ └── dlp-rules/
│ ├── intune/
│ │ ├── app-protection/
│ │ ├── autopilot/
│ │ ├── compliance-policies/
│ │ ├── device-configurations/
│ │ ├── endpoint-security/
│ │ ├── filters/
│ │ ├── mobile-apps/
│ │ ├── platform-scripts-powershell/ # Windows PowerShell scripts
│ │ │ ├── *.json # policy metadata (no base64)
│ │ │ ├── *.assignment.json # assignment data
│ │ │ └── *.ps1 # plain-text script (companion)
│ │ ├── platform-scripts-bash/ # macOS Shell scripts
│ │ │ ├── *.json # policy metadata (no base64)
│ │ │ ├── *.assignment.json # assignment data
│ │ │ └── *.sh # plain-text script (companion)
│ │ ├── settings-catalog/
│ │ ├── windows-feature-updates/
│ │ ├── windows-quality-updates/
│ │ └── windows-updates/
│ └── sharepoint-settings/
│ ├── sharepoint-tenant.json # Graph API tenant settings
│ └── tenant-configuration/ # One JSON per Set-SpoTenant property
│
└── baseline-remove/ # Configurations to DELETE
├── conditional-access/
├── groups/
├── intune/
└── custom-attributes/ Tenant Repository Structure
tenant-contoso/
├── .gitea/workflows/ # Gitea Actions workflow files
│ ├── deploy-pipeline.yml # Deploy workflow (calls orchestrator templates)
│ ├── backup-pipeline.yml # Backup workflow
│ └── maintenance-pipeline.yml # Maintenance workflow
├── .baseline-ignore # Optional: exclude specific baseline policies
└── backups/ # Daily backups (auto-committed by runner)
├── backup-manifest.json
├── authentication-policies/
├── conditional-access/
├── enterprise-apps/
├── entra-id-consentpermissions/
├── entra-id-device-settings/
├── exchange/
├── groups/
├── information-protection/
├── intune/
└── sharepoint-settings/
├── sharepoint-tenant.json
└── tenant-configuration/ Key Concepts
All M365 policies stored as individual JSON files in the baseline repo
Intune platform scripts stored as readable .ps1/.sh companion files alongside their JSON — base64 encoding happens at deploy time, never manually
All deployments go through Microsoft Graph API via PowerShell scripts in the orchestrator repo
Tenant Gitea Actions workflows clone the baseline repo at runtime via act_runner — no manual sync needed
Add a .baseline-ignore file in any tenant repo to exclude specific policies
Add CONFIG365:IGNORE to a resource description to prevent the automation from updating it