Skip to content

[pull] dev from KelvinTegelaar:dev - #126

Open
pull[bot] wants to merge 1516 commits into
covenanttechnologysolutions:devfrom
KelvinTegelaar:dev
Open

[pull] dev from KelvinTegelaar:dev#126
pull[bot] wants to merge 1516 commits into
covenanttechnologysolutions:devfrom
KelvinTegelaar:dev

Conversation

@pull

@pull pull Bot commented Apr 24, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

@pull pull Bot locked and limited conversation to collaborators Apr 24, 2026
@pull pull Bot added the ⤵️ pull label Apr 24, 2026
github-actions Bot added 28 commits August 5, 2026 11:49
…nRules schema

File-system detection omitted operator (notConfigured), and templates used returncode / string numerics that Graph rejects on create.

Synced from CyberDrain/CIPP@fcd9dac
Add AnyTenant to the Entrypoint functionality tag and fix indentation of the HttpResponseContext return block. This fixes issues where users with tenant restricted roles are unable to perform a HIBP lookup.

Synced from CyberDrain/CIPP@af849c3
Drops the unused metadata block from standard pushes while leaving execution behavior unchanged.

Synced from CyberDrain/CIPP@5cfcd0c
- Backend: evaluate TenantGroups cache expiry before checking the result cache so TTL is actually enforced instead of serving stale data forever.
- Frontend: pass `excludedTenants` into `validateDrift` and subtract them from conflict checks, and add `watchForm.excludedTenants` to the effect dependency array so drift validation re-runs when exclusions change.
fixes #78

Synced from CyberDrain/CIPP@98c170f
Add cross-tenant secure score summary/table and test results views for Identity, Devices, and Custom dashboards when AllTenants is selected.

- Extract suite-to-pattern map into Get-CippTestSuitePatterns (shared between collection and result labelling)
- Add SummaryOnly projection to Get-CIPPTestResultsTenants to drop large blob columns on list reads
- Add Suite label to stored test results via pattern matching
- Add AllTenantsSecureScore components (summary with trend/leaderboards, table with per-tenant links)
- Add AllTenantsTestResults component with lazy detail fetch per row
- Replace 'Not supported' placeholders on secure score pages with real AllTenants views
- Prevent live Graph calls in use-securescore.js when AllTenants is selected
- Refactor deriveSecureScoreSummary into a shared export for reuse across dashboard and full-page views

Synced from CyberDrain/CIPP@5368a2c
Replace full-table OData scans with per-partition queries to avoid estate-scale table scans. Add RowStatus, IncludeCounts, and AllowedTenantIds parameters to Get-CIPPTestResultsTenants so the API can return accurate aggregate counts without sending every row. Replace Add-Member loops with ordered hashtable construction for better performance.

On the frontend, default the AllTenants view to Failed/Investigate rows only with a toggle to show all, and derive tile stats from server-side counts rather than client-side row aggregation.

Synced from CyberDrain/CIPP@8413830
When SSO is provisioned at the ARM level during NG migration (outside the setup wizard), no migration table row is written. This causes the stats timer to incorrectly report SSO as incomplete.

Now checks the live EasyAuth environment variables when the migration row is missing or references a different app ID, reporting SSO as complete — consistent with Invoke-ExecSSOSetup's Status action.

Synced from CyberDrain/CIPP@506113b
When a directory role returns 404 during bulk assignment, it means the role template was never activated in the tenant. This change now activates the role from its template and then adds the service principal, instead of silently skipping it.

Synced from CyberDrain/CIPP@a6d3c71
Replace the legacy /directoryRoles endpoint with the unified RBAC API (roleManagement/directory) so all role definitions — including unactivated built-in and custom roles — are returned.

- ListRoles: fetch definitions + assignments separately, resolve principals via getByIds bulk call, group members by role definition
- ExecRemoveAdminRole: accept roleTemplateId and use directoryRoles(roleTemplateId='...') lookup when provided; add helpful error hint when role is not activated
- Frontend: pass roleTemplateId in remove action payload; hide remove button for custom roles (no templateId); expose isBuiltIn field in table and off-canvas

Synced from CyberDrain/CIPP@2c766b9
fix: update Recommended Roles doc links to maintaining-cipp path

Synced from CyberDrain/CIPP@08b6d60
Every client-facing PDF drew itself: six reports carried six covers, three
carried their own stylesheet, and four ignored the footer, watermark and cover
note entirely. A report now supplies its content and nothing else — ReportDocument
supplies the theme, styles, cover and page furniture.

Reports are content only. 3,097 lines net removed across the six. None of them
declares a stylesheet, a theme, a raw <Page>, or names a style; the report builder
keeps the sheet from context because it renders arbitrary Markdown.

Branding gained named colour roles. Charts, headings, body, subtitles, footer,
info cards, data tables, cover text, infographics and the watermark can each be
set, and each falls back to the brand colour — an install that set only a colour
renders exactly as before. Presets can be created, renamed, cloned and assigned
per report type, and a live preview renders the real reports against sample data.

Fixes found on the way:
- footer laid out to nothing (absolute box with no stated height)
- page numbers never painted (inherited lineHeight compounds across relayouts)
- watermark drawn under content, so chart cards hid it
- DataTable sized columns with flex, putting every row on its own grid
- long values overflowed their column; react-pdf's only mid-word break draws a
  hyphen, so they are now broken at a width measured against Helvetica's metrics
- a global "never hyphenate" registered by one report silently governed all of them

Page setup keeps only paper and branding. Cover, footer and watermark overrides
are gone from templates: they let a template contradict the preset it pointed at.
Stored keys are ignored rather than migrated.

Synced from CyberDrain/CIPP@31f2266
Adds build/tools/build-openapi.ps1 — a PowerShell AST-based OpenAPI 3.1 generator that replaces regex scanning. Key improvements:

- Correctly types fields read as `$Field.value` as LabelValue objects instead of plain strings (the root cause of silent null failures)
- Follows request bodies into downstream helpers (Set-CIPPUser etc.) to recover fields not visible in the entrypoint
- Adds Get-CippMcpSafePropertyName to rename OData options ($filter → odata_filter) so MCP client schemas stay valid
- Fixes Invoke-CippMcpApiRequest to unwrap { Results, Metadata } envelopes and reverse parameter aliases on dispatch
- Adds CI workflow to detect spec drift on PRs
- Adds openapi-overrides/ for endpoints whose contract cannot be statically derived
- Regenerates openapi.json from the new generator
- Adds Pester test suites for the generator, projection, and gateway

Synced from CyberDrain/CIPP@73cd6a9
Graph $batch returns HTTP 200 even when individual sub-requests fail (e.g. 429 throttling), silently dropping policy types from the collection. Previously this caused decided drift rows (Accepted, Denied*, CustomerSpecific) to be pruned and reappear as 'New' on the next run.

- IntunePoliciesCollected / CAPoliciesCollected are now false when any batch item returns ≥400
- Standards-type rows are only pruned when their Status is null or 'New'; decided rows are retained across transient key-enumeration drops
- Template-scoped runs never prune (they cannot see every valid key)
- Tests refactored to use a shared Get-CIPPAzDataTableEntity mock and extended to cover all new pruning rules

Synced from CyberDrain/CIPP@a5cd5d6
Stop emitting explicit `additionalProperties: true` in generated object response schemas so Swagger UI no longer invents `additionalProp1` fields in examples. Also add a diagnostic script that compares documented OpenAPI response fields against live `List*` endpoint output to catch casing and schema drift that static inference can miss.

Synced from CyberDrain/CIPP@7e56f6b
Replaces the legacy per-tenant activity trigger orchestration with a shared helper (Get-CIPPTenantAllowBlockListItems) that batches all four list types in a single ExoBulkRequest. Introduces Get-CIPPTenantAllowBlockListReport to serve cached results from the reporting DB. The HTTP endpoint now supports UseReportDB=true and routes AllTenants requests through the report DB by default. The frontend gains a ReportDB toggle via useCippReportDB, AllTenants layout support, and conditional Tenant column. Also fixes Select-Object property-casing bugs in ListMailboxes and ListMailboxCAS.

Synced from CyberDrain/CIPP@6e4c328
The user sync derived each user's auto-roles straight from the
AccessRoleGroups table without checking that the role still exists as a
base or custom role. When a role's group mapping survives but its
CustomRoles definition does not (e.g. carried across a platform
migration), the sync re-stamped that orphaned role onto every group
member each run. Test-CIPPAccess then denies the whole request for those
users - Get-CIPPRolePermissions throws for the missing role, so the
custom-role branch finds no permissions and returns the blanket "user
does not have the required permission", ignoring the valid base role.

Skip mappings whose role no longer exists (the same existence guard the
live path already applies in Test-CIPPAccessUserRole). Because auto-roles
are recomputed from scratch every run, the stale role now drops off every
affected user on the next pass. A failed CustomRoles lookup degrades to
pruning nothing rather than stripping every custom role from everyone,
and the run that prunes logs which roles it dropped.

Adds Pester coverage for the prune, the log line, and the safe-degrade
path.

Synced from CyberDrain/CIPP@82d7ef1
Correct compliance logic that was misreading effective policy state. The anti-phish standard now derives Enabled from the applied rule state for custom policies, CIS malware tests now accept compliant non-default policies (matching how CIPP standards are applied), and SharePoint CIS tests now normalize numeric cached enum values to friendly names before evaluation.

Synced from CyberDrain/CIPP@d54f94d
…arison

The Group Template standard loaded the template body straight from the
templates table and compared its displayName against the tenant's existing
groups. When the name contained a token such as %tenantname%, the comparison
used the raw token while the group is actually created through
New-GraphPostRequest, which substitutes the token first. The names never
matched, so remediation recreated the group on every run (2 -> 4 -> 6 ...)
and the report never showed compliant.

Resolve %variables% in the serialized template JSON via Get-CIPPTextReplacement
right after loading it, the same round trip Push-CIPPStandard already applies to
the settings, so every existence/compliance comparison and the creation all
operate on the resolved name. Names without variables are unaffected.

Synced from CyberDrain/CIPP@271bd32
The OutBoundSpamAlert standard and its baseline only set NotifyOutboundSpam, so
CIS 2.1.6 - which also requires BccSuspiciousOutboundMail plus a BCC recipient -
could never be satisfied through them. Add an opt-in "BCC suspicious outbound
mail" toggle and a separate recipient field to both the classic standard and the
declarative baseline. When enabled, remediation also sets BccSuspiciousOutboundMail
and BccSuspiciousOutboundAdditionalRecipients; when left off it is neither graded
nor written (the baseline uses omitWhenBlank to prune the keys), so existing
deployments are unaffected.

Synced from CyberDrain/CIPP@a140d97
…r bypass remediation

The Mailboxes report cache never collected the audit fields the CIS 6.1.2 test reads
(AuditOwner/AuditEnabled), so AuditOwner was always null and every user mailbox was
flagged regardless of configuration. Collect AuditEnabled, AuditOwner, AuditDelegate,
AuditAdmin and DefaultAuditSet in Set-CIPPDBCacheMailboxes and add them to the
test-data field manifest.

Grade CIS 6.1.2 on owner audit actions being configured (non-empty AuditOwner, or a
DefaultAuditSet that still covers the Owner sign-in type) rather than the AuditEnabled
flag - mailbox auditing on by default reports AuditEnabled as True and EXO REST can
return it as a string.

Repair EnableMailboxAuditing: the audit-bypass-disable block referenced $BypassMailboxes
and $Mailboxes whose assignments were commented out, so it issued an empty bulk request
and never disabled bypass. Fetch the bypass associations and disable them, and drop the
dead per-mailbox block (redundant with mailbox auditing on by default).

Synced from CyberDrain/CIPP@ba91cf1
…ms meeting policy

Adds AllowExternalNonTrustedMeetingChat (CIS 8.5.8) and AllowCloudRecording (CIS 8.5.9)
to the Teams Global Meeting Policy standard and its baseline, closing the gap where both
were detectable (CIS_8_5_8 / CIS_8_5_9 and already cached) but settable by no standard.

Both are opt-in (Off / On, or blank to keep the tenant's current value) rather than
enforced switches like the sibling settings, so existing deployments are never surprised
into disabling cloud recording; picking Off applies the CIS-recommended value. Confirmed
against the Teams admin ConfigApi: both properties are booleans and the merge-PUT payload
applies and reverts cleanly.

Synced from CyberDrain/CIPP@ef0b61d
Update the conditional access template edit page title logic so it shows "Loading..." while data is still being fetched, then falls back to "Unnamed Template" only when a loaded template has no display name. This avoids briefly showing an incorrect unnamed state during load.

Synced from CyberDrain/CIPP@649f259
The tenant-mapping table only offered a delete action, and the integration Sync
button always queued every mapped tenant. Add a Sync Now row action that queues
just the selected tenant via the existing ExecExtensionSync TenantID path,
passing the tenant domain so the queued run is tagged to that tenant in the
logbook.

Synced from CyberDrain/CIPP@55dbb4d
When a caller passes $top=1, Graph uses it as the page size, causing the full collection to be fetched one record per round trip. This change sets NoPagination=true automatically when $top=1 is detected, unless the caller explicitly overrides with NoPagination or manualPagination.

Synced from CyberDrain/CIPP@f15eabf
Make each assessment category row in `AssessmentCard` interactive and route to its matching dashboard tab (`identity`, `devices`, `custom`). Navigation now preserves the current `reportId` query so users land on the same test suite context, and includes keyboard support (`Enter`/`Space`) plus button semantics and hover affordances for accessibility.

Synced from CyberDrain/CIPP@b38b1c9
Invoke-ExecRefreshMyAccess returned TooManyRequests on its per-user cooldown
without logging it, unlike its success and error paths — the throttle was
invisible in the audit log. Write an Info line naming the user and the retry
hint on that path, and assert it in the cooldown test.

Synced from CyberDrain/CIPP@4af4d23
Add retryDelayWithRetryAfter to ApiGetCall and ApiGetCallWithPagination so that when the server returns a Retry-After header the client waits the indicated duration (capped at 60 s) instead of applying react-query's default exponential backoff. Falls back to exponential backoff when no header is present.

Also adds Vitest tests covering 503 recovery, persistent 503 exhaustion, no-retry on 500, and Retry-After delay honouring.

Synced from CyberDrain/CIPP@74c20c8
…lt-envelope

fix(scheduler): poorly formatted post-execution results

Synced from CyberDrain/CIPP@f23303d
feat(standards): add external compliance trust standard

Synced from CyberDrain/CIPP@2580cf8
…e-target

feat(halo): add psaTicketId field to wizards/api

Synced from CyberDrain/CIPP@cc1a16e
Closes a tenant-authorization gap where a scheduled task could carry a tenant-identifying parameter pointing to a different tenant than the authorized one.

- Strip tenant params (TenantFilter/Tenant/TenantId) from stored Parameters at creation time in Add-CIPPScheduledTask, logging an Error when the value mismatches the picked tenant
- Force-override any remaining tenant params to the authorized task tenant at execution time in Push-ExecScheduledCommand
- Expand orchestrator to inject the primary tenant param alongside TenantFilter
- Rename -Tenant to -TenantFilter (with Alias) in Set-CIPPAuthenticationPolicy and Set-CIPPRegistrationCampaign so the scheduler recognizes them as protected scope
- Hide Tenant/TenantId from the function-parameters UI so they are never user-editable
- Add Pester regression tests for both creation-time and execution-time defenses

Synced from CyberDrain/CIPP@1b5523c
A tenant group request ({type:'Group', value:<guid>}) previously resolved to a null $Tenant and fell through to an unconditional allow, letting restricted roles target groups they were never granted.

Fix authorizes group requests by matching the requested group GUID against the role's explicitly granted group entries. If not matched, the request is hard-denied. Member expansion is never performed for the access decision.

Adds regression tests covering allow, deny, and no-member-expansion cases.

Synced from CyberDrain/CIPP@6b66ff7
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants