Skip to content

Commit daa8d24

Browse files
Merge pull request #95 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 131a95a + 3702c85 commit daa8d24

2,064 files changed

Lines changed: 16033 additions & 278357 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/agents/CIPP-Standards-Agent.md

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,41 +30,41 @@ For detailed scaffolding patterns, the three action modes (remediate/alert/repor
3030

3131
Use this agent when a task involves:
3232

33-
- Adding a new standard (e.g. implement a standard to enable the audit log)
33+
- Adding a new standard (e.g. "implement a standard to enable the audit log")
3434

3535
You **do not** make broad architectural changes. Keep changes focused and minimal.
3636

3737
---
3838

3939
## Key Directories & Patterns
4040

41-
When working on alerts, you should:
41+
When working on standards, you should:
4242

43-
1. **Discover existing alerts and patterns**
43+
1. **Discover existing standards and patterns**
4444
- Use shell commands to explore:
45-
- `Modules/CIPPCore/Public/Standards/`
46-
- Inspect several existing alert files, e.g.:
47-
- `\Modules\CIPPCore\Public\Standards\Invoke-CIPPStandardAddDKIM.ps1`
48-
- `\Modules\CIPPCore\Public\Standards\Invoke-CIPPStandardlaps.ps1`
49-
- `\Modules\CIPPCore\Public\Standards\Invoke-CIPPStandardOutBoundSpamAlert.ps1`
45+
- `Modules/CIPPStandards/Public/Standards/`
46+
- Inspect several existing standard files, e.g.:
47+
- `Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1`
48+
- `Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardlaps.ps1`
49+
- `Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1`
5050
- Other `Invoke-CIPPStandard*.ps1` files
51-
- Understand how alerts are **named, parameterized, and how they call Graph / Exo and helper functions**.
51+
- Understand how standards are **named, parameterized, and how they call Graph / Exo and helper functions**.
5252

53-
2. **Follow the standard alert pattern**
54-
- Alert functions live in:
55-
`Modules/CIPPCore/Public/Standardss/`
56-
- Alert functions are named:
57-
`Invoke-CIPPStandardAddDKIM.ps1`
53+
2. **Follow the standard pattern**
54+
- Standard functions live in:
55+
`Modules/CIPPStandards/Public/Standards/`
56+
- Standard functions are named:
57+
`Invoke-CIPPStandard<Name>.ps1`
5858
- Typical characteristics:
5959
- Standard parameter set, including `Tenant` and `Settings` which can be a complex object with subsettings, and similar common params.
6060
- Uses CIPP helper functions like:
61-
- `New-GraphGetRequest` for any graph requests
62-
- `New-ExoReques` for creating exo requests
61+
- `New-GraphGetRequest` for any Graph requests
62+
- `New-ExoRequest` for Exchange Online requests
6363
- Uses CIPP logging and error-handling patterns (try/catch, consistent message formatting).
64-
- Each standard requires a Remediate, alert, and report section.
64+
- Each standard requires a Remediate, Alert, and Report section.
6565

6666
3. **Rely on existing module loading**
67-
- The CIPP module auto-loads `Public` functions recursively.
67+
- The CIPPStandards module auto-loads `Public` functions recursively.
6868
- **Do not** modify module manifest or loader behavior just to pick up your new standard.
6969

7070
---
@@ -73,9 +73,9 @@ When working on alerts, you should:
7373

7474
You **must** respect all of these:
7575

76-
### 1. Always follow existing CIPP alert patterns
76+
### 1. Always follow existing CIPP standard patterns
7777

78-
When adding or modifying alerts:
78+
When adding or modifying standards:
7979

8080
- Use the **same structure** as existing `Invoke-CIPPStandard*.ps1` files:
8181
- Similar function signatures

.github/instructions/auth-model.instructions.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ New-GraphGetRequest / New-ExoRequest / New-TeamsRequest / etc.
3030
3131
Get-GraphToken($tenantid, $scope, $AsApp)
3232
33-
├─ Check in-memory cache: $script:AccessTokens["{tenantid}-{scope}-{asApp}"]
33+
├─ Check process-wide .NET cache: [CIPP.CIPPTokenCache]::Lookup(key, 120)
3434
│ └─ Hit + not expired → return cached token
3535
3636
├─ Determine grant type:
@@ -43,7 +43,7 @@ New-GraphGetRequest / New-ExoRequest / New-TeamsRequest / etc.
4343
4444
└─ POST to login.microsoftonline.com/{tenantid}/oauth2/v2.0/token
4545
46-
└─ Cache result in $script:AccessTokens with expires_on
46+
└─ Cache result via [CIPP.CIPPTokenCache]::Store(key, json, expiresOn)
4747
```
4848

4949
The `-tenantid` parameter **drives token acquisition**, not just filtering. It determines which customer tenant the token is issued for.
@@ -116,10 +116,11 @@ Customer provides their own refresh token, stored in Key Vault per-tenant (keyed
116116

117117
## Token caching
118118

119-
Tokens are cached in `$script:AccessTokens` — a synchronized hashtable keyed by `{tenantid}-{scope}-{asApp}`.
119+
Tokens are cached in `[CIPP.CIPPTokenCache]` — a process-wide `ConcurrentDictionary` backed by a static .NET class in `Shared/CIPPSharp/CIPPRestClient.cs`.
120120

121-
- **Per-runspace**: Not shared across Azure Functions instances
122-
- **Expiry-aware**: Checks `expires_on` (Unix timestamp) before returning cached token
121+
- **Process-wide**: Shared across all runspaces in the worker process (unlike the old `$script:AccessTokens` which was per-runspace)
122+
- **Cache key**: Built via `[CIPP.CIPPTokenCache]::BuildKey($tenantid, $scope, $asApp, $clientId, $grantType)`
123+
- **Expiry-aware**: `Lookup()` accepts a buffer (seconds) and returns `$false` for expired or soon-to-expire tokens
123124
- **Auto-refresh**: Expired tokens trigger automatic re-acquisition — no manual refresh needed
124125
- **Skip cache**: Pass `-SkipCache $true` to force a fresh token (rare, for debugging)
125126

.github/instructions/cippdb.instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ Search-CIPPDbData -TenantFilter $Tenant -SearchTerms @('john', 'admin') -Types @
119119

120120
## Cache types
121121

122-
Available types are defined in `CIPPDBCacheTypes.json`. Each type maps to a `Set-CIPPDBCache*` writer function. Check that file for the current type list — it covers identity, Exchange, security, Intune, compliance, and usage data.
122+
Available types are defined in `Config\CIPPDBCacheTypes.json`. Each type maps to a `Set-CIPPDBCache*` writer function. Check that file for the current type list — it covers identity, Exchange, security, Intune, compliance, and usage data.
123123

124124
## Writing a new Set-CIPPDBCache* function
125125

.github/instructions/standards.instructions.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
---
2-
applyTo: "Modules/CIPPCore/Public/Standards/**"
2+
applyTo: "Modules/CIPPStandards/Public/Standards/**"
33
description: "Use when creating, modifying, or reviewing CIPP standard functions (Invoke-CIPPStandard*). Contains scaffolding patterns, the three action modes (remediate/alert/report), $Settings conventions, API call patterns, and frontend JSON payloads."
44
---
55

66
# CIPP Standard Functions
77

8-
Standard functions live in `Modules/CIPPCore/Public/Standards/` and are auto-loaded by the CIPPCore module. No manifest changes needed.
8+
Standard functions live in `Modules/CIPPStandards/Public/Standards/` and are auto-loaded by the CIPPStandards module. No manifest changes needed.
99

1010
## Naming
1111

@@ -51,6 +51,11 @@ function Invoke-CIPPStandard<Name> {
5151
True
5252
DISABLEDFEATURES
5353
{"report":false,"warn":false,"remediate":false}
54+
REQUIREDCAPABILITIES
55+
"CAPABILITY_1"
56+
"CAPABILITY_2"
57+
UPDATECOMMENTBLOCK
58+
Run the Tools\Update-StandardsComments.ps1 script to update this comment block
5459
.LINK
5560
https://docs.cipp.app/user-documentation/tenant/standards/list-standards
5661
#>
@@ -332,6 +337,8 @@ The comment-based help `.NOTES` block drives the frontend UI. Each field maps to
332337
| `RECOMMENDEDBY` | `recommendedBy` | `"CIS"`, `"CIPP"`, etc. |
333338
| `MULTIPLE` | `multiple` | `True` for template-based standards (can have multiple instances) |
334339
| `DISABLEDFEATURES` | `disabledFeatures` | JSON object disabling specific action modes |
340+
| `REQUIREDCAPABILITIES` | *(discovery only)* | One capability string per line; parsed for standards metadata/JSON generation. The explicit `Test-CIPPStandardLicense` call in the function body still performs the actual runtime license check. |
341+
| `UPDATECOMMENTBLOCK` | *(tooling only)* | Always include with the literal value `Run the Tools\Update-StandardsComments.ps1 script to update this comment block`. Signals the comment-update tooling to regenerate this block. |
335342

336343
### Valid CAT values
337344

@@ -388,7 +395,7 @@ Impact colour mapping: `Low Impact` → `info`, `Medium Impact` → `warning`, `
388395

389396
## Checklist for new standards
390397

391-
1. Create `Modules/CIPPCore/Public/Standards/Invoke-CIPPStandard<Name>.ps1`
398+
1. Create `Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandard<Name>.ps1`
392399
2. Include the full `.NOTES` metadata block (CAT, TAG, IMPACT, ADDEDCOMPONENT, etc.)
393400
3. Implement all three modes: remediate, alert, report
394401
4. Add license gating if the data source requires a specific SKU

.github/workflows/PR_Branch_Check.yml

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,46 @@ permissions:
1616

1717
jobs:
1818
check-branch:
19-
runs-on: ubuntu-latest
19+
runs-on: ubuntu-slim
2020
steps:
2121
- name: Check and Comment on PR
2222
# Only process fork PRs with specific branch conditions
2323
# Must be a fork AND (source is main/master OR target is main/master)
2424
if: |
25-
github.event.pull_request.head.repo.fork == true &&
25+
github.event.pull_request.head.repo.fork == true &&
2626
((github.event.pull_request.head.ref == 'main' || github.event.pull_request.head.ref == 'master') ||
2727
(github.event.pull_request.base.ref == 'main' || github.event.pull_request.base.ref == 'master'))
28-
uses: actions/github-script@v7
28+
uses: actions/github-script@v9
2929
with:
3030
github-token: ${{ secrets.GITHUB_TOKEN }}
3131
script: |
3232
let message = '';
3333
34-
message += '🔄 If you are attempting to update your CIPP repo please follow the instructions at: https://docs.cipp.app/setup/self-hosting-guide/updating ';
34+
// Check if the fork has open PRs (indicates pull bot or similar is active)
35+
const forkOwner = context.payload.pull_request.head.repo.owner.login;
36+
const forkRepo = context.payload.pull_request.head.repo.name;
37+
const forkPullsUrl = context.payload.pull_request.head.repo.html_url + '/pulls';
38+
39+
let openPRs = [];
40+
try {
41+
const { data: prs } = await github.rest.pulls.list({
42+
owner: forkOwner,
43+
repo: forkRepo,
44+
state: 'open',
45+
per_page: 5
46+
});
47+
openPRs = prs;
48+
} catch (e) {
49+
// Can't read fork PRs — skip
50+
}
51+
52+
message += '🔄 If you are attempting to update your CIPP-API repo please follow the instructions at: https://docs.cipp.app/setup/self-hosting-guide/updating. Are you a sponsor? Contact the helpdesk for direct assistance with updating to the latest version.';
53+
54+
if (openPRs.length > 0) {
55+
message += ` It looks like you may already have a pending update PR on your fork — check your [open pull requests](${forkPullsUrl}) to accept it.`;
56+
} else {
57+
message += ` You can enable [Pull Bot](https://github.com/apps/pull) or [Repo Sync](https://github.com/apps/repo-sync) to automatically keep your fork up to date.`;
58+
}
3559
message += '\n\n';
3660
3761
// Check if PR is targeting main/master
@@ -40,20 +64,20 @@ jobs:
4064
}
4165
4266
// Check if PR is from a fork's main/master branch
43-
if (context.payload.pull_request.head.repo.fork &&
67+
if (context.payload.pull_request.head.repo.fork &&
4468
(context.payload.pull_request.head.ref === 'main' || context.payload.pull_request.head.ref === 'master')) {
4569
message += '⚠️ This PR cannot be merged because it originates from your fork\'s main/master branch. If you are attempting to contribute code please PR from your dev branch or another non-main/master branch.\n\n';
4670
}
4771
48-
message += '🔒 This PR will now be automatically closed due to the above violation(s).';
49-
72+
message += '🔒 This PR will now be automatically closed due to the above rules.';
73+
5074
// Post the comment
5175
await github.rest.issues.createComment({
5276
...context.repo,
5377
issue_number: context.issue.number,
5478
body: message
5579
});
56-
80+
5781
// Close the PR
5882
await github.rest.pulls.update({
5983
...context.repo,

.github/workflows/dev_api.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ jobs:
3333
tenant-id: ${{ secrets.DEV_TENANTID }}
3434
subscription-id: ${{ secrets.DEV_SUBSCRIPTIONID }}
3535

36+
- name: Build and stage modules
37+
shell: pwsh
38+
run: ./Tools/Build-DevApiModules.ps1
39+
3640
- name: "Run Azure Functions Action"
3741
uses: Azure/functions-action@v1
3842
id: fa

.github/workflows/publish_release.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ jobs:
9595
env:
9696
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
9797

98+
# Create version.json with version and commit hash
99+
- name: Create version.json
100+
run: |
101+
VERSION=$(cat version_latest.txt | tr -d '[:space:]')
102+
SHORT_SHA="${GITHUB_SHA::7}"
103+
echo "{\"version\": \"${VERSION}\", \"commit\": \"${SHORT_SHA}\"}" > version.json
104+
105+
- name: Build and stage modules
106+
shell: pwsh
107+
run: ./Tools/Build-DevApiModules.ps1
108+
98109
# Create ZIP File in a New Source Directory
99110
- name: Prepare and Zip Release Files
100111
if: env.tag_exists == 'false'

.github/workflows/upload_dev.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@ jobs:
2121
# Create version.json with version and commit hash
2222
- name: Create version.json
2323
run: |
24-
VERSION=$(cat version_latest.txt | tr -d '[:space:]')
24+
VERSION=$(cat ./version_latest.txt | tr -d '[:space:]')
2525
SHORT_SHA="${GITHUB_SHA::7}"
2626
echo "{\"version\": \"${VERSION}\", \"commit\": \"${SHORT_SHA}\"}" > version.json
2727
28+
- name: Build and stage modules
29+
shell: pwsh
30+
run: ./Tools/Build-DevApiModules.ps1
31+
2832
# Create ZIP File in a New Source Directory
2933
- name: Prepare and Zip Release Files
3034
run: |

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ SendNotifications/config.json
1313
Output/
1414
node_modules/.yarn-integrity
1515
yarn.lock
16+
Shared/CIPPSharp/obj/
1617

1718
# Cursor IDE
1819
.cursor/rules
File renamed without changes.

0 commit comments

Comments
 (0)