Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
139 commits
Select commit Hold shift + click to select a range
ee4a2cf
Dev to hotfix (#2032)
JohnDuprey Apr 28, 2026
5a13af0
Dev to hf (#2033)
KelvinTegelaar Apr 29, 2026
bd676d3
Dev to hotfix (#2036)
JohnDuprey May 2, 2026
6871d26
Dev to hotfix (#2047)
JohnDuprey May 8, 2026
7d02b0b
Major Update
DamienMatthys Jun 8, 2026
b68c93f
Update Push-CIPPDBCacheData.ps1
DamienMatthys Jun 8, 2026
4c020dd
Update Set-CIPPDBCacheDefenderCVEs.ps1
DamienMatthys Jun 8, 2026
4f8bc79
Dev to release (#2081)
KelvinTegelaar Jun 8, 2026
1434616
Dev to hotfix (#2085)
JohnDuprey Jun 9, 2026
85ef802
Delete Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneCveSyncT…
DamienMatthys Jun 10, 2026
7ae8fcd
Update Push-NinjaOneQueue.ps1
DamienMatthys Jun 10, 2026
7420db6
Update Invoke-NinjaOneTenantSync.ps1
DamienMatthys Jun 10, 2026
4998ffe
Merge branch 'dev' into dev
DamienMatthys Jun 10, 2026
5a0ddb2
Dev to hotfix (#2088)
JohnDuprey Jun 10, 2026
843ebfb
Fix mailcontact when values un-set
Zacgoose Jun 16, 2026
d2e54ee
SSO app password policy modification
Zacgoose Jun 16, 2026
d2655de
github template id sync fixes
Zacgoose Jun 16, 2026
8e21ee1
Fixes for when duplicate intune standards are applied to the same tenant
Zacgoose Jun 16, 2026
444a746
emit message when mailbox conversion might hit 50gb limit
Zacgoose Jun 16, 2026
e2b092b
update json from frontend
Zacgoose Jun 17, 2026
4939515
repair GDAP role mapping actions
Zacgoose Jun 17, 2026
2c63d31
Schema backed standards repair action, repaired standards are prefixe…
Zacgoose Jun 17, 2026
504c21a
fix: patch command for updating redirect uri
JohnDuprey Jun 17, 2026
1164290
remove incorrectly added permissions
KelvinTegelaar Jun 17, 2026
231e834
Merge branch 'dev' of https://github.com/KelvinTegelaar/CIPP-API into…
KelvinTegelaar Jun 17, 2026
a2c8a4a
Merge branch 'dev' of https://github.com/KelvinTegelaar/CIPP-API into…
JohnDuprey Jun 18, 2026
fa8a589
chore: add logging for onboarding
JohnDuprey Jun 18, 2026
942ff39
chore: consolidate graph log message
JohnDuprey Jun 18, 2026
920e3a1
user auth and sync logic
Zacgoose Jun 18, 2026
5e63541
Update standards.json
Zacgoose Jun 18, 2026
151ef46
SPO version cleanup job check
Zacgoose Jun 18, 2026
1a8b716
fixes for missing state on templates
Zacgoose Jun 18, 2026
5392acf
Sensitivity label fixes
Zacgoose Jun 18, 2026
ee92936
more drift logging and type casting
Zacgoose Jun 18, 2026
66ff8f5
ca template deployment logging for packages
Zacgoose Jun 18, 2026
4160b51
chore: add feature flag for copilot pages
JohnDuprey Jun 18, 2026
e4bd4be
chore: bump version to 10.5.3
JohnDuprey Jun 18, 2026
ed7c362
Dev to hotfix (#2099)
JohnDuprey Jun 18, 2026
edc7acb
Trail claim better info on error
Zacgoose Jun 19, 2026
83c7735
enable copilot after hotfix
Zacgoose Jun 19, 2026
10f2478
intune device app collection
Zacgoose Jun 19, 2026
f44ff88
feat: add allTenants support for shared mailbox enabled report
kris6673 Jun 19, 2026
69394ec
feat: Support room calendar processing options
kris6673 Jun 19, 2026
05096dc
feat: Add default calendar permission handling for rooms
kris6673 Jun 20, 2026
612f2f8
Update Get-CIPPStandards.ps1
chris-dewey-1991 Jun 20, 2026
62ff1c6
Update Start-UserTasksOrchestrator.ps1
Zacgoose Jun 22, 2026
176a05f
mailbox rule removal hardening for multiple mailboxes with the same a…
Zacgoose Jun 22, 2026
4f91849
Update CIPPCore.psd1
Zacgoose Jun 22, 2026
c750267
Custom Test Engine converted to a CLM runtime
Zacgoose Jun 22, 2026
f517937
API client RBAC checks before creation
Zacgoose Jun 22, 2026
0a3409a
Update FeatureFlags.json
Zacgoose Jun 22, 2026
a2dec42
Intune Policy sync fixes
Zacgoose Jun 22, 2026
351c7f3
fix: hardcode owner/repo in release notes api
JohnDuprey Jun 22, 2026
a8ac0bd
Merge branch 'dev' of https://github.com/KelvinTegelaar/CIPP-API into…
JohnDuprey Jun 22, 2026
9002cca
fix: throw on invalid nextLink url
JohnDuprey Jun 22, 2026
aefefda
chore: bump version to 10.5.4
JohnDuprey Jun 22, 2026
e8cd121
Dev to hotfix (#2106)
JohnDuprey Jun 22, 2026
5549d62
Table cleanup fixes
Zacgoose Jun 23, 2026
eac806c
IP lookup and Audit Log Processing improvements
Zacgoose Jun 24, 2026
f690b6d
More reliable RG name resolution
Zacgoose Jun 24, 2026
739d378
90 Day cache cleanup
Zacgoose Jun 24, 2026
b560d15
Move APISpec to config folder
Zacgoose Jun 24, 2026
850f6a2
New Licence Updates
Zacgoose Jun 24, 2026
4d112f5
User Offboarding task validation
Zacgoose Jun 24, 2026
05f5f1f
alert fixes for custom tests
Zacgoose Jun 24, 2026
0c3d4ba
Custom Test Alerting overhaul
Zacgoose Jun 24, 2026
a8143b4
feat(defender): add MTD role, realign iOS sync
kris6673 Jun 25, 2026
63e0b12
Feat/Fix: Add Mobile Threat Defense role and realign iOS sync (#2108)
Zacgoose Jun 25, 2026
7dea7f4
Requirements clarification
Zacgoose Jun 25, 2026
68595cc
feat: incident severity + resolving comment
kris6673 Jun 25, 2026
ac8f243
Language and Region fixes
Zacgoose Jun 25, 2026
6c62d78
Blank value fixes
Zacgoose Jun 25, 2026
dc8b3af
Update Set-CIPPStandardsCompareField.ps1
Zacgoose Jun 25, 2026
e21df9c
Update New-ExoRequest.ps1
Zacgoose Jun 25, 2026
158e973
Update Set-CIPPSAMAdminRoles.ps1
Zacgoose Jun 25, 2026
e6c0c93
Update Set-CIPPSAMAdminRoles.ps1
Zacgoose Jun 25, 2026
67856c4
Update New-ExoRequest.ps1
Zacgoose Jun 25, 2026
42087ae
feat: Add message trace retrieval to Push-BECRun function
MWG-Logan Jun 15, 2026
fe87252
Revert "Update New-ExoRequest.ps1"
Zacgoose Jun 26, 2026
ad7e409
Revert "Update Set-CIPPSAMAdminRoles.ps1"
Zacgoose Jun 26, 2026
b6b918e
permission repair improvements
Zacgoose Jun 26, 2026
e987ea4
Move NinjaOne Sync from BPA to Reporting DB
Zacgoose Jun 26, 2026
04b3e12
Disable App insights page when not needed
Zacgoose Jun 26, 2026
9deb458
Update Get-NinjaOneFieldMapping.ps1
Zacgoose Jun 26, 2026
428ebd3
Update Set-CIPPDBCacheRiskDetections.ps1
Zacgoose Jun 26, 2026
45b96d6
Fix contact template deployment to align with frontend changes
Zacgoose Jun 26, 2026
d2e88c5
Start job earlier
Zacgoose Jun 26, 2026
3204da3
Update Get-CIPPStandards.ps1 to fix Custom Quarantine Policy not repo…
Zacgoose Jun 26, 2026
6192717
Fixes for spam filter policy when using custom names
Zacgoose Jun 26, 2026
a9b3e40
Purview DLP Policy and Standard implementation and fixes
Zacgoose Jun 26, 2026
03ae94e
Add typed-response + operationId enrichment for openapi.json
tim-at-rewst Jun 26, 2026
40ca72e
chore: update version to 10.5.5
JohnDuprey Jun 26, 2026
2a7c7a7
Ignore mail.onmicrosoft domains for DMARC enablement
Zacgoose Jun 27, 2026
a2f29dd
feat: direction-scoped Intune group assignment
kris6673 Jun 27, 2026
dae979b
Fix Check extension alerts repeating on every run (watermark never ad…
matstocks Jun 27, 2026
9a88ec0
feat: add support for ExcludeGroupNames in assignment functions
kris6673 Jun 27, 2026
2f16223
Sensitivity Rule Templating and standard overhaul
Zacgoose Jun 27, 2026
d52ec9b
Resolve tenant variables in Win32 Custom App detection script
matstocks Jun 27, 2026
38b18bc
Audit log rework for better resilience
Zacgoose Jun 29, 2026
d358ae5
External Storage Account Backup Replication
Zacgoose Jun 29, 2026
1b8c0c1
Fixes for CA template editing dropping the package tag
Zacgoose Jun 29, 2026
b995698
Fix CA template list and table side filter when ID/GUID provided
Zacgoose Jun 29, 2026
20eb3d6
Remove standards rows from table when the template is deleted
Zacgoose Jun 29, 2026
bbd52dc
Permission update fixes
Zacgoose Jun 29, 2026
d24f333
fix: token timer secret cleanup
JohnDuprey Jun 29, 2026
d30b2f4
fix: remove execsamsetup, no longer used
JohnDuprey Jun 29, 2026
0b72ea5
Update Compare-CIPPIntuneObject.ps1
Zacgoose Jun 30, 2026
3ce368b
Manual Audit Log Search Fixes
Zacgoose Jun 30, 2026
034366b
Fixes for array value business phone number in templates
Zacgoose Jun 30, 2026
6089106
Fix for adding groups failing for sec groups
Zacgoose Jun 30, 2026
6205e97
fix: modernize and improve logging
kris6673 Jun 30, 2026
7313bd9
Update CIPPSharp
Zacgoose Jun 30, 2026
e718903
fix: rereun detection logic
JohnDuprey Jun 30, 2026
c5a732d
Update Invoke-AddSpamFilter.ps1
Zacgoose Jun 30, 2026
25445c6
Update Oauth standards with conflict information
Zacgoose Jun 30, 2026
e77de98
CIPP Rogue App List
Zacgoose Jun 30, 2026
0dcb4fb
fix: hudu sync
JohnDuprey Jun 30, 2026
7c0da88
feat: add featureflags to stats timer
JohnDuprey Jun 30, 2026
fc8756f
User Offboarding default settings fix
Zacgoose Jun 30, 2026
29e8e6c
Fixes for standards where deployment errors were hidden
Zacgoose Jun 30, 2026
eec5f69
Fix Check extension alerts repeating on every run (watermark never ad…
KelvinTegelaar Jun 30, 2026
c6c50d7
Resolve tenant variables in Win32 Custom App detection script (#2116)
KelvinTegelaar Jun 30, 2026
36fd9c0
Fix: Modernize GDAP relationship termination logging (#2117)
KelvinTegelaar Jun 30, 2026
3198c77
Enrich generated openapi.json with typed responses and operationIds (…
KelvinTegelaar Jun 30, 2026
a3c752d
feat: Add message trace retrieval to Push-BECRun function (#2098)
KelvinTegelaar Jun 30, 2026
24e7a06
Feat: Add Intune group assignment enhancements (#2115)
KelvinTegelaar Jun 30, 2026
5994a44
Feat: Add incident severity and resolving comments (#2109)
KelvinTegelaar Jun 30, 2026
0288227
Feat: Support room calendar processing options and default permission…
KelvinTegelaar Jun 30, 2026
e801464
Feat: Add allTenants support for shared mailbox enabled report (#2103)
KelvinTegelaar Jun 30, 2026
25b4110
Feat: CVE exception management page and NinjaOne CVE sync (#2080)
KelvinTegelaar Jun 30, 2026
f965afe
Implements #6214
KelvinTegelaar Jun 30, 2026
a0b263c
chore: update version to 10.5.6
JohnDuprey Jun 30, 2026
259770d
fix: revert rerun protection on scheduled tasks
JohnDuprey Jun 30, 2026
d17b33f
fix: add system32,osdrive
JohnDuprey Jul 1, 2026
52ce175
fix: exclude imAddresses from user backup/restore
JohnDuprey Jul 1, 2026
9cf8a3c
Reduce Verbose nop logging
Zacgoose Jul 1, 2026
103078a
JSON escaping fixes for intune policies
Zacgoose Jul 1, 2026
e164701
Bump AzBobbyTables version
Zacgoose Jul 1, 2026
f06ad2f
Table Read Retry
Zacgoose Jul 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
349 changes: 349 additions & 0 deletions .build/Add-OpenApiResponseSchemas.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,349 @@
#Requires -Version 7.0
<#
.SYNOPSIS
Enriches a CIPP openapi.json with typed 200 response schemas derived by static
analysis of the API and frontend repositories.

.DESCRIPTION
The generated CIPP spec types every request body but leaves every 200 response
as the generic StandardResults envelope. This stage fills typed per-endpoint
response schemas for the read surface, using two deterministic sources that are
already checked into the repositories (no live API calls):

1. Captured response shape baselines (CIPP/Tests/Shapes/*.json) - carry real
field types and nesting. Preferred when present.
2. Frontend table column declarations (simpleColumns in CIPP/src pages) -
carry field names only. Used when no baseline exists; fields are typed as
string and marked x-cipp-field-source: frontend so consumers know the type
is a name-only inference, not a verified type.

Endpoints with neither source keep the StandardResults envelope, which is the
correct shape for write/exec operations. Output is deterministic: the same input
repositories always produce a byte-identical spec.

.PARAMETER InputSpec
Path to the source openapi.json. Defaults to the repo-root spec relative to this
script (.build/.. ).

.PARAMETER OutputSpec
Path to write the enriched spec. Defaults to InputSpec (in-place rewrite).

.PARAMETER FrontendRepoPath
Path to a checkout of the CIPP frontend repository. Provides both the shape
baselines (Tests/Shapes) and the page column declarations (src).

.PARAMETER PassThru
Return the enriched spec object instead of only writing it. Used by tests.

.EXAMPLE
./Add-OpenApiResponseSchemas.ps1 -FrontendRepoPath ../CIPP

Rewrites the repo-root openapi.json in place with typed response schemas.
#>
[CmdletBinding()]
param(
[string]$InputSpec = (Join-Path $PSScriptRoot '..' 'openapi.json'),
[string]$OutputSpec,
[string]$FrontendRepoPath,
[switch]$PassThru
)

$ErrorActionPreference = 'Stop'

$script:CippHttpMethods = @('get', 'post', 'put', 'patch', 'delete')

function ConvertFrom-ShapeNode {
<#
.SYNOPSIS
Converts one node of a captured shape tree into an OpenAPI schema fragment.
#>
param($Node)

if ($Node -is [string]) {
switch ($Node) {
'string' { return @{ type = 'string' } }
'number' { return @{ type = 'number' } }
'bool' { return @{ type = 'boolean' } }
'datetime' { return [ordered]@{ type = 'string'; format = 'date-time' } }
# 'null' (captured as null at sample time) and 'truncated' (below the
# capture depth limit) carry no reliable type, so stay permissive.
default { return @{} }
}
}

if ($Node -is [System.Collections.IDictionary]) {
if ($Node['_type'] -eq 'array') {
return [ordered]@{ type = 'array'; items = (ConvertFrom-ShapeNode -Node $Node['_element']) }
}
$properties = [ordered]@{}
foreach ($key in ($Node.Keys | Sort-Object)) {
$properties[[string]$key] = ConvertFrom-ShapeNode -Node $Node[$key]
}
return [ordered]@{ type = 'object'; properties = $properties }
}

return @{}
}

function Get-ShapeBaselineMap {
<#
.SYNOPSIS
Maps endpoint name -> per-record OpenAPI schema, from captured shape baselines.
.DESCRIPTION
Reads only files carrying both _metadata and shape; the sibling
test-results.json and any non-baseline file is skipped. The per-record schema
is the baseline shape itself (the CIPP envelope's Results[] element).
#>
param([string]$ShapesDir)

$map = @{}
if (-not (Test-Path $ShapesDir)) {
Write-Warning "Shapes directory not found: $ShapesDir"
return $map
}

foreach ($file in (Get-ChildItem -Path $ShapesDir -Filter '*.json' | Sort-Object -Property FullName)) {
$doc = Get-Content -LiteralPath $file.FullName -Raw | ConvertFrom-Json -AsHashtable -Depth 100
if (-not ($doc -is [System.Collections.IDictionary] -and $doc.ContainsKey('_metadata') -and $doc.ContainsKey('shape'))) {
continue
}
$endpoint = $doc['_metadata']['endpoint']
if (-not $endpoint) { continue }
$map[$endpoint] = ConvertFrom-ShapeNode -Node $doc['shape']
}
return $map
}

function Get-FrontendColumnMap {
<#
.SYNOPSIS
Maps endpoint name -> sorted unique field names, from page simpleColumns.
.DESCRIPTION
Intent: skips conditional simpleColumns arrays to avoid non-column branch strings; false negatives beat junk fields.
Scans frontend page sources for files that pair an /api/<Endpoint> reference
with a simpleColumns array, and unions the declared column names per endpoint.
Field names are deterministic; their types are not, so callers type them as
string with a provenance marker.
#>
param([string]$SrcDir)

$map = @{}
if (-not (Test-Path $SrcDir)) {
Write-Warning "Frontend src directory not found: $SrcDir"
return $map
}

$endpointPattern = [regex]'/api/([A-Za-z0-9_]+)'
$columnsPattern = [regex]'(?s)\bsimpleColumns\s*(?:=|:)\s*(?:\{\s*)?\[(?<columns>[^\]]*)\]'
$stringPattern = [regex]'"([^"]+)"|''([^'']+)'''

$files = Get-ChildItem -Path $SrcDir -Recurse -File -Include '*.js', '*.jsx'
foreach ($file in $files) {
$text = Get-Content -LiteralPath $file.FullName -Raw
if ([string]::IsNullOrEmpty($text) -or $text -notmatch 'simpleColumns') { continue }

$endpoints = $endpointPattern.Matches($text) | ForEach-Object { $_.Groups[1].Value } | Sort-Object -Unique
if (-not $endpoints) { continue }

$columns = foreach ($colMatch in $columnsPattern.Matches($text)) {
foreach ($strMatch in $stringPattern.Matches($colMatch.Groups['columns'].Value)) {
$value = if ($strMatch.Groups[1].Success) { $strMatch.Groups[1].Value } else { $strMatch.Groups[2].Value }
if ($value) { $value }
}
}
if (-not $columns) { continue }

foreach ($endpoint in $endpoints) {
if (-not $map.ContainsKey($endpoint)) { $map[$endpoint] = [System.Collections.Generic.HashSet[string]]::new() }
foreach ($column in $columns) { [void]$map[$endpoint].Add($column) }
}
}
return $map
}

function ConvertTo-ColumnRecordSchema {
<#
.SYNOPSIS
Builds a per-record object schema from a set of frontend column names.
#>
param([System.Collections.Generic.HashSet[string]]$Columns)

$properties = [ordered]@{}
foreach ($column in ($Columns | Sort-Object)) {
$properties[$column] = [ordered]@{ type = 'string'; 'x-cipp-field-source' = 'frontend' }
}
return [ordered]@{ type = 'object'; properties = $properties }
}

function ConvertTo-ResponseEnvelopeSchema {
<#
.SYNOPSIS
Wraps a per-record schema in the CIPP { Results: [...], Metadata: {...} } envelope.
#>
param($RecordSchema)

return [ordered]@{
type = 'object'
properties = [ordered]@{
Results = [ordered]@{ type = 'array'; items = $RecordSchema }
Metadata = [ordered]@{ type = 'object' }
}
}
}


function Get-CippOperationId {
<#
.SYNOPSIS
Builds the deterministic operationId for one CIPP path and method.
.DESCRIPTION
Riftwing imports OpenAPI operations by operationId. CIPP upstream does not
currently emit operationIds, so this keeps importer keys stable without
depending on display labels or external data.
#>
param(
[Parameter(Mandatory)][string]$Path,
[Parameter(Mandatory)][string]$Method,
[Parameter(Mandatory)][string[]]$PathMethods
)

$endpointName = $Path -replace '^/api/', ''
if ($PathMethods.Count -eq 1) {
return $endpointName
}

$methodName = [System.Globalization.CultureInfo]::InvariantCulture.TextInfo.ToTitleCase($Method.ToLowerInvariant())
return "$methodName$endpointName"
}

function Add-CippOperationId {
<#
.SYNOPSIS
Injects missing operationIds and fails on duplicate operationIds.
.DESCRIPTION
Existing non-empty operationIds are preserved so this pass can retire itself
when upstream starts emitting operationIds. Duplicate operationIds are fatal
because importers commonly key operations by operationId.
#>
param([Parameter(Mandatory)][System.Collections.IDictionary]$Spec)

if (-not $Spec['paths']) { throw 'Spec has no paths.' }

$operationCount = 0
$injectedCount = 0
$operationIds = @{}

foreach ($pathEntry in $Spec['paths'].GetEnumerator()) {
$pathMethods = @($pathEntry.Value.Keys | Where-Object { $_ -in $script:CippHttpMethods })
foreach ($methodEntry in $pathEntry.Value.GetEnumerator()) {
if ($methodEntry.Key -notin $script:CippHttpMethods) { continue }

$operationCount++
$operation = $methodEntry.Value
$operationId = $operation['operationId']
if ([string]::IsNullOrWhiteSpace([string]$operationId)) {
$operationId = Get-CippOperationId -Path $pathEntry.Key -Method $methodEntry.Key -PathMethods $pathMethods
$operation['operationId'] = $operationId
$injectedCount++
}

if ($operationIds.ContainsKey($operationId)) {
throw "Duplicate operationId found: $operationId"
}
$operationIds[$operationId] = $true
}
}

return [pscustomobject]@{ Operations = $operationCount; Injected = $injectedCount; Unique = $operationIds.Count }
}

function Resolve-SpecResponse {
<#
.SYNOPSIS
Adds typed 200 response schemas to a parsed spec, in place, and returns counts.
.DESCRIPTION
The pure core of this stage: operates on an already-parsed spec hashtable and
the two endpoint maps, with no file or repository access, so it is unit
testable. Only existing 200 responses on get/post/put/patch/delete operations
are touched; everything else (including operations with no matching source) is
left exactly as found.
#>
param(
[Parameter(Mandatory)][System.Collections.IDictionary]$Spec,
[Parameter(Mandatory)][hashtable]$BaselineMap,
[Parameter(Mandatory)][hashtable]$ColumnMap
)

if (-not $Spec['paths']) { throw 'Spec has no paths.' }

$operationCount = 0
$typedCount = 0

foreach ($pathEntry in $Spec['paths'].GetEnumerator()) {
$endpoint = $pathEntry.Key -replace '^/api/', ''

$recordSchema = $null
if ($BaselineMap.ContainsKey($endpoint)) {
$recordSchema = $BaselineMap[$endpoint]
} elseif ($ColumnMap.ContainsKey($endpoint)) {
$recordSchema = ConvertTo-ColumnRecordSchema -Columns $ColumnMap[$endpoint]
}

foreach ($methodEntry in $pathEntry.Value.GetEnumerator()) {
if ($methodEntry.Key -notin $script:CippHttpMethods) { continue }
$operationCount++
if ($null -eq $recordSchema) { continue }

$responses = $methodEntry.Value['responses']
if ($null -eq $responses) { continue }

$okResponse = $responses['200']
if (-not $okResponse) { continue }

$okResponse['content'] = [ordered]@{
'application/json' = [ordered]@{ schema = (ConvertTo-ResponseEnvelopeSchema -RecordSchema $recordSchema) }
}
$typedCount++
}
}

return [pscustomobject]@{
Operations = $operationCount
Typed = $typedCount
}
}

function Add-CippResponseSchema {
<#
.SYNOPSIS
File-level orchestration: read spec + repo sources, enrich, write output.
#>
param(
[Parameter(Mandatory)][string]$InputSpec,
[Parameter(Mandatory)][string]$OutputSpec,
[Parameter(Mandatory)][string]$FrontendRepoPath,
[switch]$PassThru
)

if (-not (Test-Path $InputSpec)) { throw "Input spec not found: $InputSpec" }

$spec = Get-Content -LiteralPath $InputSpec -Raw | ConvertFrom-Json -AsHashtable -Depth 100
$baselineMap = Get-ShapeBaselineMap -ShapesDir (Join-Path $FrontendRepoPath 'Tests' 'Shapes')
$columnMap = Get-FrontendColumnMap -SrcDir (Join-Path $FrontendRepoPath 'src')

$operationIdResult = Add-CippOperationId -Spec $spec
$result = Resolve-SpecResponse -Spec $spec -BaselineMap $baselineMap -ColumnMap $columnMap
Write-Information "Operations: $($result.Operations) | typed responses added: $($result.Typed) | operationIds injected: $($operationIdResult.Injected) | unique operationIds: $($operationIdResult.Unique)" -InformationAction Continue

# Serialization is deterministic for the object this stage builds, but it does not globally canonicalize pre-existing spec keys.
[System.IO.File]::WriteAllText($OutputSpec, ($spec | ConvertTo-Json -Depth 100))

if ($PassThru) { return $spec }
}

# Run orchestration only when invoked as a script, not when dot-sourced for testing.
if ($MyInvocation.InvocationName -ne '.') {
if (-not $FrontendRepoPath) { throw 'FrontendRepoPath is required when running the script.' }
if (-not $OutputSpec) { $OutputSpec = $InputSpec }
Add-CippResponseSchema -InputSpec $InputSpec -OutputSpec $OutputSpec -FrontendRepoPath $FrontendRepoPath -PassThru:$PassThru
}
38 changes: 38 additions & 0 deletions .build/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# OpenAPI enrichment

`Add-OpenApiResponseSchemas.ps1` post-processes the generated CIPP `openapi.json`. It adds deterministic operationIds and typed `200` response schemas where response shape data can be derived from the CIPP frontend repository. It does not replace the upstream OpenAPI generator.

The enriched spec is published on each GitHub Release as the `openapi.enriched.json` release asset.

The PR check and release workflow strictly lint the CI-generated `openapi.enriched.json` with Redocly. The committed `.redocly.lint-ignore.yaml` baseline pins findings that already exist in the generated enriched spec because of upstream `openapi.json` issues. Any new Redocly error or warning that is not in the baseline fails CI.

To regenerate locally, check out the CIPP frontend repository and run:

```powershell
pwsh -NoProfile -File .build/Add-OpenApiResponseSchemas.ps1 `
-FrontendRepoPath <path-to-CIPP-frontend-checkout> `
-InputSpec ./openapi.json -OutputSpec ./openapi.enriched.json
```

If upstream `openapi.json` legitimately changes and the pinned Redocly findings must be refreshed, regenerate the enriched spec first, then regenerate the ignore baseline from that enriched output:

```powershell
pwsh -NoProfile -File .build/Add-OpenApiResponseSchemas.ps1 `
-FrontendRepoPath <path-to-CIPP-frontend-checkout> `
-InputSpec ./openapi.json -OutputSpec ./openapi.enriched.json
npx --yes @redocly/cli@2.35.1 lint ./openapi.enriched.json --generate-ignore-file
```

Do not generate the baseline from the base `openapi.json`. The lint subject is always the generated `openapi.enriched.json`.

## Known limitations

- Only `get`, `post`, `put`, `patch`, and `delete` operations are processed. `head`, `options`, and `trace` are not present in the current spec.
- Paths are assumed to start with `/api/`. All 580 current paths do.
- When a typed `200` response is added, it replaces the existing `200.content`. Today that content is only the generic `StandardResults` envelope.
- Conditional/ternary `simpleColumns` expressions are intentionally not parsed.

## Release workflow notes

- `openapi-enriched-release.yml` builds and uploads from the same tag. On `workflow_dispatch`, the `tag` input is checked out and used as the upload target. On `release: published`, the release tag is checked out and used as the upload target.
- `.github/workflows/` is gitignored in this repository, so the OpenAPI workflow files require `git add -f` when they are intentionally added or updated.
Loading