From 895cf89167cebb5fd4f7a1a05d490d30b2282230 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 22 Jul 2026 01:15:15 +0200 Subject: [PATCH 1/4] update package.json --- frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/package.json b/frontend/package.json index a882176..a229a02 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,7 +12,7 @@ }, "repository": { "type": "git", - "url": "git@github.com:KelvinTegelaar/CIPP.git" + "url": "git@github.com:CyberDrain/CIPP.git" }, "scripts": { "dev": "next -H 127.0.0.1", From e8fffcd5ce671ce228f4c83e5a3eb7fe55a01fb8 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 22 Jul 2026 01:17:08 +0200 Subject: [PATCH 2/4] synctest backend --- backend/cspell.json | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/cspell.json b/backend/cspell.json index 42bdb4b..6b2ac5a 100644 --- a/backend/cspell.json +++ b/backend/cspell.json @@ -4,6 +4,7 @@ "dictionaryDefinitions": [], "dictionaries": [], "words": [ + "SyncTest", "adminapi", "ADMS", "AITM", From 6ca22540b919a0dc50df2db5120baba56b406437 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 22 Jul 2026 01:29:52 +0200 Subject: [PATCH 3/4] workflows and assign data --- .github/FUNDING.yml | 4 + .github/ISSUE_TEMPLATE/bug.yml | 92 ++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 9 ++ .github/ISSUE_TEMPLATE/feature.yml | 84 +++++++++++++ .github/agents/CIPP-Alert-Agent.md | 45 +++++++ .github/agents/CIPP-Frontend-Alert-Agent.md | 45 +++++++ .github/dependabot.yml | 17 +++ .github/pull.yml | 11 ++ .github/scripts/validate-json.mjs | 71 +++++++++++ .github/workflows/Assign_Issue_Volunteer.yml | 12 ++ .../workflows/Check_for_Version_Update.yml | 23 ++++ .github/workflows/Close_Stale_Issues.yml | 20 +++ .github/workflows/CodeQL_Analyser.yml | 36 ++++++ .github/workflows/Comment_on_Issues.yml | 22 ++++ .github/workflows/Conventional_Commits.yml | 65 ++++++++++ .github/workflows/Label_Issues.yml | 29 +++++ .github/workflows/Node_Project_Check.yml | 31 +++++ .github/workflows/Validate_JSON.yml | 117 ++++++++++++++++++ .github/workflows/auto_comments.yml | 83 +++++++++++++ .github/workflows/cipp_api_tests.yml | 67 ++++++++++ .github/workflows/cipp_dev_build.yml | 63 ++++++++++ .github/workflows/cipp_frontend_build.yml | 63 ++++++++++ .github/workflows/dependency-review.yml | 28 +++++ .github/workflows/dev_deploy.yml | 41 ++++++ .github/workflows/label_sponsor_requests.yml | 18 +++ .github/workflows/pr_check.yml | 44 ++++++- .github/workflows/zap-scan.yml | 55 ++++++++ 27 files changed, 1189 insertions(+), 6 deletions(-) create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/bug.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature.yml create mode 100644 .github/agents/CIPP-Alert-Agent.md create mode 100644 .github/agents/CIPP-Frontend-Alert-Agent.md create mode 100644 .github/dependabot.yml create mode 100644 .github/pull.yml create mode 100644 .github/scripts/validate-json.mjs create mode 100644 .github/workflows/Assign_Issue_Volunteer.yml create mode 100644 .github/workflows/Check_for_Version_Update.yml create mode 100644 .github/workflows/Close_Stale_Issues.yml create mode 100644 .github/workflows/CodeQL_Analyser.yml create mode 100644 .github/workflows/Comment_on_Issues.yml create mode 100644 .github/workflows/Conventional_Commits.yml create mode 100644 .github/workflows/Label_Issues.yml create mode 100644 .github/workflows/Node_Project_Check.yml create mode 100644 .github/workflows/Validate_JSON.yml create mode 100644 .github/workflows/auto_comments.yml create mode 100644 .github/workflows/cipp_api_tests.yml create mode 100644 .github/workflows/cipp_dev_build.yml create mode 100644 .github/workflows/cipp_frontend_build.yml create mode 100644 .github/workflows/dependency-review.yml create mode 100644 .github/workflows/dev_deploy.yml create mode 100644 .github/workflows/label_sponsor_requests.yml create mode 100644 .github/workflows/zap-scan.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..33cbb4b --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +--- +# These are supported funding model platforms + +github: [kelvintegelaar] diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..db613f4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,92 @@ +name: "🐞 Bug report" +description: "Report errors or unexpected behaviors for CIPP and CIPP-API" +title: "[Bug]: " +labels: + - "unconfirmed-by-user" + - "bug" + +body: + - type: markdown + attributes: + value: | + **Thank you for taking the time to report a potential bug for CIPP and CIPP-API!** + + Please follow the instructions below and provide as much detail as possible to help us understand and reproduce the issue. + + - type: checkboxes + id: confirmations + attributes: + label: "Required confirmations before submitting" + description: "Please check all boxes that apply." + options: + - label: "**I can reproduce this issue on the latest released versions** of both CIPP and CIPP-API." + required: true + - label: "**I have searched existing issues** (both open and closed) to avoid duplicates." + required: true + - label: "I am **not** requesting general support; this is an actual bug report." + required: true + + # 3) Description / Steps to reproduce + - type: textarea + id: description + attributes: + label: "Issue Description" + description: | + **Describe the issue clearly and provide step-by-step instructions to reproduce it.** + Screenshots can be attached by pasting them here. + + Example steps to reproduce: + 1. Go to **Settings** + 2. Click on a tenant in **Access Check** + 3. Click on the green pixel in the bottom-right corner + 4. Observe the unexpected behavior + validations: + required: true + + # 4) Environment type (Sponsored vs. Non-sponsored) + - type: dropdown + id: environment_type + attributes: + label: "Environment Type" + description: "Select whether you are using currently a paying user of the product, or if you are utilizing the free version" + options: + - "Sponsored (paying) user" + - "Non-sponsored user" + validations: + required: true + + # 5) Front End / Back End versions + - type: input + id: front_end_version + attributes: + label: "Front End Version" + description: "Please specify the front end version number (e.g., v1.2.3)." + validations: + required: true + + - type: input + id: back_end_version + attributes: + label: "Back End Version" + description: "Please specify the back end version number (e.g., v1.2.3)." + validations: + required: true + + # 7) Additional logs or trace (optional) + - type: textarea + id: logs + attributes: + label: "Relevant Logs / Stack Trace" + description: | + If available, please share any relevant logs or stack trace data. + Remove or redact any sensitive info before posting. + render: plaintext + validations: + required: false + + # 8) Closing note + - type: markdown + attributes: + value: | + Thank you for your submission! A maintainer will review your report. + Please watch the issue for follow-up questions or status updates. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..9fa3848 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,9 @@ +blank_issues_enabled: false +contact_links: + - name: Security Reports + url: https://github.com/KelvinTegelaar/CIPP/security/advisories + about: Please report security vulnerabilities here. + - name: Community Discord + url: https://discord.gg/cyberdrain + about: Join our discord community here. + diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 0000000..4978afe --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,84 @@ +name: "✨ Feature request" +description: "Suggest a new feature or improvement" +title: "[Feature Request]: " +labels: + - "enhancement" + - "no-priority" + +body: + # Introductory Markdown + - type: markdown + attributes: + value: | + **Thank you for suggesting a new feature or improvement for CIPP** + + Before creating a request, please: + + 1. Check that you have an active sponsorship, only users that are sponsoring CIPP at the $99,- sponsorship level can create feature requests. + 1. Search existing **open and closed** feature requests to avoid duplicates. + 2. Note that **repeat feature requests** are permitted if a previous request was closed more than 30 days ago. + 3. Consider implementing the feature yourself by reviewing the [development documentation](https://docs.cipp.app/dev-documentation/cipp-dev-guide/setting-up-for-local-development). + 4. Feature requests that lack sufficient detail or feasibility may be closed at any time. + 5. **This request will auto-close in 14 days** if no meaningful progress or collaboration occurs. + 6. If you would like to work on this feature, comment `"I'd like to work on this please!"` + 7. Any request that is detrimental to security or the product’s stability will be closed without notice. + + # Checkboxes for Confirmations + - type: checkboxes + id: confirmations + attributes: + label: "Please confirm:" + description: "Check all boxes that apply." + options: + - label: "**I have searched existing feature requests** (open and closed) and found no duplicates." + required: true + - label: "**me or my organization is currently an active sponsor of the product at the $99,- level." + required: true + + - type: textarea + id: problem-statement + attributes: + label: "Problem Statement" + description: | + **What problem does this feature solve or what gap does it fill?** + Provide a concise explanation. For example: + - "When I need to enable MFA for all users, it takes a lot of time to do it per user. I'd like to enable this for all users in button press" + - "To update a user property for exchange I need to go through 5 portals and 2 systems to be able to make a change." + validations: + required: true + + # Field 2: Benefits for MSPs + - type: textarea + id: msp-benefits + attributes: + label: "Benefits for MSPs" + description: | + **How would this feature help MSPs in their day-to-day tasks or overall operations?** + - Does it reduce manual work? + - Does it improve security or scalability? + - Does it offer clarity or automation to commonly repeated tasks? + validations: + required: true + + # Field 3: Value or Importance + - type: textarea + id: feature-value + attributes: + label: "Value or Importance" + description: | + **Why is this feature particularly valuable or important to add?** + - If it's critical, explain why. + - If it's optional or nice-to-have, describe how it still adds notable value. + validations: + required: true + + # Optional field for PowerShell commands + - type: textarea + id: powershell-commands + attributes: + label: "PowerShell Commands (Optional)" + description: | + If you currently achieve this functionality or a similar workaround using PowerShell, please share your scripts or snippets here. + This information helps contributors understand the existing workflow and aids in development. + validations: + required: false diff --git a/.github/agents/CIPP-Alert-Agent.md b/.github/agents/CIPP-Alert-Agent.md new file mode 100644 index 0000000..6b29ec1 --- /dev/null +++ b/.github/agents/CIPP-Alert-Agent.md @@ -0,0 +1,45 @@ +--- +name: CIPP Frontend Alert Registrar +description: > + Adds new alert entries to src/data/alerts.json in the CIPP frontend. + The agent must never modify any other file or perform any other change. +--- + +# CIPP Frontend Alert Registrar + +## Mission + +You are a **frontend alert registrar** responsible for updating the `src/data/alerts.json` file to include new alerts. + +Your role is **strictly limited** to adding a new JSON entry describing the alert’s metadata. +You do not touch or inspect any other part of the codebase. + +--- + +## Scope of Work + +This agent is used when a new alert must be surfaced to the frontend — for example, after a new backend `Get-CIPPAlert*.ps1` alert has been added. + +Tasks include: + +- Opening `src/data/alerts.json` +- Appending one new JSON object describing the new alert +- Preserving JSON structure, indentation, and trailing commas exactly as in the existing file +- Validating that the resulting JSON is syntactically correct + + +## Alert Format + +Each alert entry in `src/data/alerts.json` is a JSON object with the following structure: + +```json +{ + "name": "", + "label": "A nice label for the alert", + "requiresInput": true, + "inputType": "switch", + "inputLabel": "Exclude disabled users?", + "inputName": "InactiveLicensedUsersExcludeDisabled", + "recommendedRunInterval": "1d" +} +``` diff --git a/.github/agents/CIPP-Frontend-Alert-Agent.md b/.github/agents/CIPP-Frontend-Alert-Agent.md new file mode 100644 index 0000000..6b29ec1 --- /dev/null +++ b/.github/agents/CIPP-Frontend-Alert-Agent.md @@ -0,0 +1,45 @@ +--- +name: CIPP Frontend Alert Registrar +description: > + Adds new alert entries to src/data/alerts.json in the CIPP frontend. + The agent must never modify any other file or perform any other change. +--- + +# CIPP Frontend Alert Registrar + +## Mission + +You are a **frontend alert registrar** responsible for updating the `src/data/alerts.json` file to include new alerts. + +Your role is **strictly limited** to adding a new JSON entry describing the alert’s metadata. +You do not touch or inspect any other part of the codebase. + +--- + +## Scope of Work + +This agent is used when a new alert must be surfaced to the frontend — for example, after a new backend `Get-CIPPAlert*.ps1` alert has been added. + +Tasks include: + +- Opening `src/data/alerts.json` +- Appending one new JSON object describing the new alert +- Preserving JSON structure, indentation, and trailing commas exactly as in the existing file +- Validating that the resulting JSON is syntactically correct + + +## Alert Format + +Each alert entry in `src/data/alerts.json` is a JSON object with the following structure: + +```json +{ + "name": "", + "label": "A nice label for the alert", + "requiresInput": true, + "inputType": "switch", + "inputLabel": "Exclude disabled users?", + "inputName": "InactiveLicensedUsersExcludeDisabled", + "recommendedRunInterval": "1d" +} +``` diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..d6c9564 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + target-branch: "dev" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + target-branch: "dev" diff --git a/.github/pull.yml b/.github/pull.yml new file mode 100644 index 0000000..6ea67b8 --- /dev/null +++ b/.github/pull.yml @@ -0,0 +1,11 @@ +version: "1" +rules: + - base: main + upstream: KelvinTegelaar:main + mergeMethod: merge + - base: dev + upstream: KelvinTegelaar:dev + mergeMethod: none + - base: website + upstream: KelvinTegelaar:website + mergeMethod: merge diff --git a/.github/scripts/validate-json.mjs b/.github/scripts/validate-json.mjs new file mode 100644 index 0000000..0f626b1 --- /dev/null +++ b/.github/scripts/validate-json.mjs @@ -0,0 +1,71 @@ +import { readFile, readdir, writeFile, appendFile } from "node:fs/promises"; +import path from "node:path"; + +// Usage: node validate-json.mjs [--strip ] [dir...] +// --strip removes a leading path prefix from reported filenames, so a PR checked +// out into a subdirectory still reports repo-relative paths. +const argv = process.argv.slice(2); +let strip = ""; +const roots = []; +for (let i = 0; i < argv.length; i++) { + if (argv[i] === "--strip") { + strip = argv[++i] ?? ""; + } else { + roots.push(argv[i]); + } +} + +async function collect(dir) { + let entries; + try { + entries = await readdir(dir, { withFileTypes: true }); + } catch (error) { + if (error.code === "ENOENT") return []; + throw error; + } + const files = []; + for (const entry of entries) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + if (entry.name === "node_modules") continue; + files.push(...(await collect(full))); + } else if (entry.name.endsWith(".json")) { + files.push(full); + } + } + return files; +} + +const report = (file) => { + const normalised = file.split(path.sep).join("/"); + return strip && normalised.startsWith(strip) ? normalised.slice(strip.length) : normalised; +}; + +const failures = []; +let checked = 0; + +for (const root of roots) { + for (const file of await collect(root)) { + checked++; + const contents = await readFile(file, "utf8"); + try { + JSON.parse(contents); + } catch (error) { + failures.push({ file: report(file), message: error.message.replace(/\r?\n/g, " ") }); + } + } +} + +for (const { file, message } of failures) { + // Annotate the PR diff via a GitHub Actions error command. + console.log(`::error file=${file}::${message}`); +} +console.log(`Checked ${checked} JSON file(s), ${failures.length} invalid.`); + +// Hand the results to the workflow so it can comment on the PR. +if (process.env.GITHUB_OUTPUT) { + await appendFile(process.env.GITHUB_OUTPUT, `invalid_count=${failures.length}\n`); +} +await writeFile("json-validation-results.json", JSON.stringify(failures, null, 2)); + +process.exit(failures.length > 0 ? 1 : 0); diff --git a/.github/workflows/Assign_Issue_Volunteer.yml b/.github/workflows/Assign_Issue_Volunteer.yml new file mode 100644 index 0000000..d320a5b --- /dev/null +++ b/.github/workflows/Assign_Issue_Volunteer.yml @@ -0,0 +1,12 @@ +--- +name: "Issue volunteer assignment" +on: + issue_comment: + types: [created] +jobs: + volunteer: + runs-on: ubuntu-slim + steps: + - uses: kris6673/issue-volunteer@v0.2.0 + with: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/Check_for_Version_Update.yml b/.github/workflows/Check_for_Version_Update.yml new file mode 100644 index 0000000..de9156a --- /dev/null +++ b/.github/workflows/Check_for_Version_Update.yml @@ -0,0 +1,23 @@ +--- +name: Check for Version Update +on: + pull_request: + branches: [master, main] + workflow_dispatch: +jobs: + build: + if: github.repository_owner == 'KelvinTegelaar' + name: "Check for Version Update" + runs-on: ubuntu-slim + steps: + - name: Check for Changed Files + uses: brettcannon/check-for-changed-files@v1.2.1 + with: + file-pattern: public/version.json + failure-message: "You have not updated version.json. This is a required file to update at each PR. Please sync your latest changes and update the version number." + - name: Prevent changes to workflow files + uses: DovnarAlexander/github-action-file-detection@v0.3.0 + with: + wildcard: ".github/workflows/*.yml" + exit_code_found: 1 + exit_code_not_found: 0 diff --git a/.github/workflows/Close_Stale_Issues.yml b/.github/workflows/Close_Stale_Issues.yml new file mode 100644 index 0000000..ec88789 --- /dev/null +++ b/.github/workflows/Close_Stale_Issues.yml @@ -0,0 +1,20 @@ +--- +name: "Close stale issues" +on: + schedule: + - cron: "30 1 * * *" +jobs: + stale: + if: github.repository_owner == 'KelvinTegelaar' + runs-on: ubuntu-slim + steps: + - uses: actions/stale@v10 + with: + stale-issue-message: "This issue is stale because it has been open for 10 days with no activity. Please do not bump feature requests unless you are actively working on them, as bumps interfere with our triage process and make it harder to maintain a current list of feature requests. If you want this feature implemented, you can contribute it yourself; see https://docs.cipp.app/dev-documentation/contributing-to-the-code. Please notify the team if you are working on this." + close-issue-message: "This issue was closed because it has been stalled for 14 days without activity. We auto-close inactive feature requests to keep the backlog focused and actionable. If this request is still needed, you may submit it again after 30 days." + stale-issue-label: "no-activity" + exempt-issue-labels: "planned,bug,roadmap" + days-before-stale: 9 + days-before-close: 5 + days-before-pr-stale: -1 + days-before-pr-close: -1 diff --git a/.github/workflows/CodeQL_Analyser.yml b/.github/workflows/CodeQL_Analyser.yml new file mode 100644 index 0000000..027a7d5 --- /dev/null +++ b/.github/workflows/CodeQL_Analyser.yml @@ -0,0 +1,36 @@ +# OPTIONAL UPGRADE to the existing CodeQL_Analyser.yml (already deployed in CIPP). +# Changes vs. current: adds push trigger on main/dev, security-extended query suite, +# and javascript-typescript language alias. +name: "CodeQL" +on: + push: + branches: [main, dev] + pull_request: + branches: [master, main, dev, react] + schedule: + - cron: "26 17 * * 0" +jobs: + analyze: + if: github.repository_owner == 'KelvinTegelaar' + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: ["javascript-typescript"] + steps: + - name: Checkout Repository + uses: actions/checkout@v6 + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + queries: security-extended + - name: Autobuild + uses: github/codeql-action/autobuild@v4 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/Comment_on_Issues.yml b/.github/workflows/Comment_on_Issues.yml new file mode 100644 index 0000000..6a6014f --- /dev/null +++ b/.github/workflows/Comment_on_Issues.yml @@ -0,0 +1,22 @@ +--- +name: Add Comment +on: + issues: + types: + - labeled +jobs: + add-comment_bug: + if: github.repository_owner == 'KelvinTegelaar' && github.event.label.name == 'unconfirmed-by-user' + runs-on: ubuntu-slim + permissions: + issues: write + steps: + - name: Add Comment + uses: peter-evans/create-or-update-comment@v5 + with: + issue-number: ${{ github.event.issue.number }} + body: | + Thank you for reporting a potential bug. If you would like to work on this bug, please comment: + > I would like to work on this please! + + Thank you for helping us maintain the project! diff --git a/.github/workflows/Conventional_Commits.yml b/.github/workflows/Conventional_Commits.yml new file mode 100644 index 0000000..a5a669b --- /dev/null +++ b/.github/workflows/Conventional_Commits.yml @@ -0,0 +1,65 @@ +name: Conventional Commits Check + +on: + # Using pull_request_target instead of pull_request for secure handling of fork PRs + pull_request_target: + # Re-run on title edits so a corrected title clears the check + types: [opened, synchronize, reopened, edited] + # Only check PRs targeting the dev branch + branches: + - dev + +permissions: + pull-requests: write + issues: write + +jobs: + conventional-commits: + name: Validate Conventional Commits + runs-on: ubuntu-slim + steps: + - name: Validate PR title + uses: actions/github-script@v9 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const title = context.payload.pull_request.title || ''; + const pattern = /^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\(.+\))?!?: .+/i; + + if (pattern.test(title)) { + console.log(`✓ PR title follows Conventional Commits format: "${title}"`); + return; + } + + console.log(`❌ PR title does not follow Conventional Commits format: "${title}"`); + + const message = [ + '❌ **This PR title does not follow the [Conventional Commits](https://www.conventionalcommits.org/) format.**', + '', + 'Expected format: `type(scope)?: description`', + '', + 'Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `ci`, `build`, `revert`', + '', + 'Examples:', + '- `feat: add tenant filter to the user table`', + '- `fix(auth): handle expired refresh tokens`', + '- `docs: update self-hosting guide`', + '', + `Received: \`${title}\``, + '', + '🔒 This PR has been automatically closed. Please update the title to match the format above and reopen the PR.' + ].join('\n'); + + await github.rest.issues.createComment({ + ...context.repo, + issue_number: context.issue.number, + body: message + }); + + await github.rest.pulls.update({ + ...context.repo, + pull_number: context.issue.number, + state: 'closed' + }); + + core.setFailed(`PR title does not follow Conventional Commits format: "${title}"`); diff --git a/.github/workflows/Label_Issues.yml b/.github/workflows/Label_Issues.yml new file mode 100644 index 0000000..cc0032e --- /dev/null +++ b/.github/workflows/Label_Issues.yml @@ -0,0 +1,29 @@ +--- +name: Label Issues +on: + issues: + types: + - opened +jobs: + label_issues_bugs: + if: github.repository_owner == 'KelvinTegelaar' && contains(github.event.issue.title, 'Bug') + runs-on: ubuntu-slim + permissions: + issues: write + steps: + - name: Label Issues + uses: andymckay/labeler@e6c4322d0397f3240f0e7e30a33b5c5df2d39e90 + with: + add-labels: "not-assigned" + repo-token: ${{ secrets.GITHUB_TOKEN }} + label_issues_frs: + if: github.repository_owner == 'KelvinTegelaar' && contains(github.event.issue.title, 'Feature') + runs-on: ubuntu-slim + permissions: + issues: write + steps: + - name: Label Issues + uses: andymckay/labeler@e6c4322d0397f3240f0e7e30a33b5c5df2d39e90 + with: + add-labels: "enhancement, not-assigned" + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/Node_Project_Check.yml b/.github/workflows/Node_Project_Check.yml new file mode 100644 index 0000000..1d675b9 --- /dev/null +++ b/.github/workflows/Node_Project_Check.yml @@ -0,0 +1,31 @@ +--- +name: NodeJS Project Check +on: + pull_request: + branches: + - main + - dev +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }} + cancel-in-progress: false +jobs: + install-build: + if: github.repository_owner == 'KelvinTegelaar' + name: NPM Install and Build + runs-on: ubuntu-latest + strategy: + matrix: + node-version: ["22.13.0"] + os: [ubuntu-latest] + steps: + - uses: actions/checkout@v6 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v7.0.0 + with: + node-version: ${{ matrix.node-version }} + - name: Install and Build Test + run: | + npm install --legacy-peer-deps + npm run build + env: + CI: true diff --git a/.github/workflows/Validate_JSON.yml b/.github/workflows/Validate_JSON.yml new file mode 100644 index 0000000..9db12dd --- /dev/null +++ b/.github/workflows/Validate_JSON.yml @@ -0,0 +1,117 @@ +--- +name: Validate JSON +on: + # pull_request_target (not pull_request) so the token can comment on fork PRs. + # The PR's own code is never executed: it is checked out into ./pr as data only, + # and parsed by the validator script from the trusted base checkout. + pull_request_target: + types: [opened, synchronize, reopened] + branches: + - main + - dev + paths: + - "public/**/*.json" + - "src/data/**/*.json" + - ".github/workflows/Validate_JSON.yml" + - ".github/scripts/validate-json.mjs" + push: + branches: + - dev + paths: + - "public/**/*.json" + - "src/data/**/*.json" + - ".github/workflows/Validate_JSON.yml" + - ".github/scripts/validate-json.mjs" +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request_target' && github.event.pull_request.number || github.ref }} + cancel-in-progress: true +permissions: + contents: read + pull-requests: write +jobs: + validate: + name: Parse JSON in public and src/data + runs-on: ubuntu-latest + steps: + - name: Checkout base (trusted validator script) + uses: actions/checkout@v6 + + - name: Checkout PR head (untrusted, data only) + if: github.event_name == 'pull_request_target' + uses: actions/checkout@v6 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.sha }} + path: pr + persist-credentials: false + + - name: Validate JSON files + id: validate + continue-on-error: true + env: + ROOT: ${{ github.event_name == 'pull_request_target' && 'pr/' || '' }} + run: node .github/scripts/validate-json.mjs --strip "$ROOT" "${ROOT}public" "${ROOT}src/data" + + - name: Comment on PR + if: github.event_name == 'pull_request_target' + uses: actions/github-script@v9 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const marker = ''; + const resultsFile = 'json-validation-results.json'; + if (!fs.existsSync(resultsFile)) { + // The validator crashed before reporting; let its own error stand. + core.warning('No validation results found — skipping PR comment.'); + return; + } + const failures = JSON.parse(fs.readFileSync(resultsFile, 'utf8')); + + // Find a previous comment from this workflow so we update instead of piling up. + const { data: comments } = await github.rest.issues.listComments({ + ...context.repo, + issue_number: context.issue.number, + per_page: 100, + }); + const existing = comments.find( + (c) => c.user.type === 'Bot' && c.body.includes(marker) + ); + + let body; + if (failures.length > 0) { + const list = failures + .map(({ file, message }) => `- \`${file}\`\n > ${message}`) + .join('\n'); + body = + `${marker}\n### ⚠️ Invalid JSON detected\n\n` + + `${failures.length} JSON file(s) in this PR could not be parsed. ` + + `These files are loaded directly by CIPP, so a syntax error here breaks the app at runtime.\n\n` + + `${list}\n\n` + + `Please fix the syntax and push again — this comment will update automatically.`; + } else if (existing) { + body = `${marker}\n### ✅ JSON is valid\n\nAll JSON files in \`public\` and \`src/data\` parse correctly. Thanks for fixing it!`; + } else { + // Nothing was ever broken — stay quiet. + return; + } + + if (existing) { + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + ...context.repo, + issue_number: context.issue.number, + body, + }); + } + + - name: Fail if any JSON is invalid + if: steps.validate.outputs.invalid_count != '0' + run: | + echo "::error::${{ steps.validate.outputs.invalid_count }} invalid JSON file(s). See annotations above." + exit 1 diff --git a/.github/workflows/auto_comments.yml b/.github/workflows/auto_comments.yml new file mode 100644 index 0000000..89a9908 --- /dev/null +++ b/.github/workflows/auto_comments.yml @@ -0,0 +1,83 @@ +name: "Handle Comment Commands" + +on: + issue_comment: + types: + - created + +jobs: + handle_comment: + runs-on: ubuntu-slim + # We need permissions to modify issue comments. + # 'issues: write' is required for deleting comments. + permissions: + issues: write + + steps: + # 1) If the comment includes '!notasponsor', delete it using GitHub Script + - name: Delete !notasponsor comment + if: contains(github.event.comment.body, '!notasponsor') + uses: actions/github-script@v9 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + await github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id + }); + + # 2) Post a sponsor-specific reply + - name: Reply to !notasponsor + if: contains(github.event.comment.body, '!notasponsor') + uses: peter-evans/create-or-update-comment@v5 + with: + issue-number: ${{ github.event.issue.number }} + body: | + Hello, + + Thank you for your interest in improving CIPP! + To keep our development process focused and manageable, **feature requests are limited to paying users**. This policy helps us prioritize improvements that directly benefit those actively supporting CIPP and ensures we can sustain our development and support. + + When a sponsor makes a feature request, their support covers training, development, documentation, and security checks. Allowing non-sponsor requests could lead to a backlog that slows down updates and stretches resources thin, ultimately affecting the quality and sustainability of CIPP. + + While we’ve closed this request, we appreciate your input. You’re always welcome to participate in ongoing discussions or contribute to open issues. If you are a developer, feel free to open a PR that includes your feature request or comment "**I’d like to work on this!**" to assign the issue to yourself. + + **Did you get this notification in error?** Reply with a screenshot of your sponsorship payment and we’ll reopen the issue. + + _Thank you for understanding,_ + **The CIPP Team** + + # 3) If the comment includes '!support', classify as a support request + - name: Reply to !support + if: contains(github.event.comment.body, '!support') + uses: peter-evans/create-or-update-comment@v5 + with: + issue-number: ${{ github.event.issue.number }} + body: | + Hello, + + Thank you for reaching out! This report has been classified as a **support request** rather than a bug or feature request. To keep our development process focused, support requests are limited to paying users. This policy allows us to prioritize resources for those actively supporting CIPP, helping us maintain high-quality development and support. + + Sponsors can contact our helpdesk directly via email for assistance with any issues or questions. For non-sponsor support, please refer to our documentation and community discussions—many questions have been answered there. + + **Did you get this notification in error?** Reply with a screenshot of your sponsorship payment, and we’ll gladly reopen the request. + + _Thank you for your understanding,_ + **The CIPP Team** + + # 4) If the comment includes '!incomplete', note the bug or feature request is incomplete + - name: Reply to !incomplete + if: contains(github.event.comment.body, '!incomplete') + uses: peter-evans/create-or-update-comment@v5 + with: + issue-number: ${{ github.event.issue.number }} + body: | + Hello, + + Thank you for your submission! It appears this **bug report or feature request is incomplete**. We need a clear description, steps to reproduce (for bugs), or a comprehensive overview of the requested feature. + + Please submit a new request with all the necessary details. Without sufficient information, it’s difficult for contributors to triage or implement solutions. + + _Thank you!_ + **The CIPP Team** diff --git a/.github/workflows/cipp_api_tests.yml b/.github/workflows/cipp_api_tests.yml new file mode 100644 index 0000000..0ff94a0 --- /dev/null +++ b/.github/workflows/cipp_api_tests.yml @@ -0,0 +1,67 @@ +--- +name: CIPP API Tests +on: + pull_request: + branches: + - dev + - main +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }} + cancel-in-progress: true +jobs: + api-tests: + if: github.repository_owner == 'KelvinTegelaar' + name: API Shape & Integration Tests + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + + - name: Run Shape Tests + id: shape-tests + shell: pwsh + env: + CIPP_API_URL: ${{ secrets.CIPP_TEST_API_URL }} + CIPP_CLIENT_ID: ${{ secrets.CIPP_TEST_CLIENT_ID }} + CIPP_CLIENT_SECRET: ${{ secrets.CIPP_TEST_CLIENT_SECRET }} + CIPP_TENANT_ID: ${{ secrets.CIPP_TEST_TENANT_ID }} + CIPP_API_SCOPE: ${{ secrets.CIPP_TEST_API_SCOPE }} + CIPP_TENANT_FILTER: ${{ secrets.CIPP_TEST_TENANT_FILTER }} + run: | + ./Tools/Invoke-CippShapeTests.ps1 ` + -CippApiUrl $env:CIPP_API_URL ` + -CippClientId $env:CIPP_CLIENT_ID ` + -CippClientSecret $env:CIPP_CLIENT_SECRET ` + -CippTenantId $env:CIPP_TENANT_ID ` + -CippApiScope $env:CIPP_API_SCOPE ` + -TenantFilter $env:CIPP_TENANT_FILTER ` + -CI + + - name: Run Integration Tests + if: always() + id: integration-tests + shell: pwsh + env: + CIPP_API_URL: ${{ secrets.CIPP_TEST_API_URL }} + CIPP_CLIENT_ID: ${{ secrets.CIPP_TEST_CLIENT_ID }} + CIPP_CLIENT_SECRET: ${{ secrets.CIPP_TEST_CLIENT_SECRET }} + CIPP_TENANT_ID: ${{ secrets.CIPP_TEST_TENANT_ID }} + CIPP_API_SCOPE: ${{ secrets.CIPP_TEST_API_SCOPE }} + CIPP_TENANT_FILTER: ${{ secrets.CIPP_TEST_TENANT_FILTER }} + run: | + ./Tools/Invoke-CippIntegrationTests.ps1 ` + -CippApiUrl $env:CIPP_API_URL ` + -CippClientId $env:CIPP_CLIENT_ID ` + -CippClientSecret $env:CIPP_CLIENT_SECRET ` + -CippTenantId $env:CIPP_TENANT_ID ` + -CippApiScope $env:CIPP_API_SCOPE ` + -TenantFilter $env:CIPP_TENANT_FILTER ` + -CI + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v7 + with: + name: test-results + path: Tests/Shapes/test-results.json + retention-days: 30 diff --git a/.github/workflows/cipp_dev_build.yml b/.github/workflows/cipp_dev_build.yml new file mode 100644 index 0000000..39cd581 --- /dev/null +++ b/.github/workflows/cipp_dev_build.yml @@ -0,0 +1,63 @@ +name: CIPP Frontend Dev Build + +on: + push: + branches: + - dev + workflow_dispatch: + +jobs: + build: + if: github.event.repository.fork == false + name: Build and Upload CIPP Frontend + runs-on: ubuntu-latest + + steps: + # Checkout the repository + - name: Checkout Code + uses: actions/checkout@v6 + + # Set up Node.js + - name: Get Node version + id: get_node_version + run: | + node_raw_version=$(node -p "require('./package.json').engines.node") + node_sanitized_version=$(echo $node_raw_version | sed -E 's/[^0-9.]+//g') + echo "node_version=$node_sanitized_version" >> $GITHUB_OUTPUT + + - name: Set up Node.js + uses: actions/setup-node@v7.0.0 + with: + node-version: ${{ steps.get_node_version.outputs.node_version }} + + # Install dependencies + - name: Install Dependencies + run: yarn install + + # Build the project + - name: Build Project + run: npm run build + + # Update version.json with commit hash + - name: Update version.json + run: | + VERSION=$(jq -r '.version' public/version.json) + SHORT_SHA="${GITHUB_SHA::7}" + echo "{\"version\": \"${VERSION}\", \"commit\": \"${SHORT_SHA}\"}" > out/version.json + + # Create ZIP File in a New Source Directory + - name: Prepare and Zip Build Files + run: | + mkdir -p build + cp staticwebapp.config.json out/ + zip -r build/dev.zip out + + # Upload to Azure Blob Storage + - name: Azure Blob Upload + uses: LanceMcCarthy/Action-AzureBlobUpload@v3.15.0 + with: + connection_string: ${{ secrets.AZURE_CONNECTION_STRING }} + container_name: cipp + source_folder: build/ + destination_folder: / + delete_if_exists: true diff --git a/.github/workflows/cipp_frontend_build.yml b/.github/workflows/cipp_frontend_build.yml new file mode 100644 index 0000000..a09cc25 --- /dev/null +++ b/.github/workflows/cipp_frontend_build.yml @@ -0,0 +1,63 @@ +name: CIPP Frontend Build + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build: + if: github.event.repository.fork == false + name: Build and Upload CIPP Frontend + runs-on: ubuntu-latest + + steps: + # Checkout the repository + - name: Checkout Code + uses: actions/checkout@v6 + + # Set up Node.js + - name: Get Node version + id: get_node_version + run: | + node_raw_version=$(node -p "require('./package.json').engines.node") + node_sanitized_version=$(echo $node_raw_version | sed -E 's/[^0-9.]+//g') + echo "node_version=$node_sanitized_version" >> $GITHUB_OUTPUT + + - name: Set up Node.js + uses: actions/setup-node@v7.0.0 + with: + node-version: ${{ steps.get_node_version.outputs.node_version }} + + # Install dependencies + - name: Install Dependencies + run: yarn install + + # Build the project + - name: Build Project + run: npm run build + + # Update version.json with commit hash + - name: Update version.json + run: | + VERSION=$(jq -r '.version' public/version.json) + SHORT_SHA="${GITHUB_SHA::7}" + echo "{\"version\": \"${VERSION}\", \"commit\": \"${SHORT_SHA}\"}" > out/version.json + + # Create ZIP File in a New Source Directory + - name: Prepare and Zip Build Files + run: | + mkdir -p build + cp staticwebapp.config.json out/ + zip -r build/latest.zip out + + # Upload to Azure Blob Storage + - name: Azure Blob Upload + uses: LanceMcCarthy/Action-AzureBlobUpload@v3.15.0 + with: + connection_string: ${{ secrets.AZURE_CONNECTION_STRING }} + container_name: cipp + source_folder: build/ + destination_folder: / + delete_if_exists: true diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..770bfb5 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,28 @@ +# SCA: Fails PRs that introduce dependencies with known vulnerabilities +# ISO 27001:2022 A.8.28/8.29 evidence — Software Composition Analysis at merge time +name: Dependency Review +on: + pull_request: + branches: [main, dev] + +permissions: + contents: read + pull-requests: write + +jobs: + dependency-review: + if: github.repository_owner == 'KelvinTegelaar' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Dependency review + uses: actions/dependency-review-action@v5 + with: + # Block merge on known vulnerabilities of moderate severity or higher + fail-on-severity: moderate + # Surface results as a PR comment for contributor visibility + comment-summary-in-pr: on-failure + # Optional: block copyleft-incompatible licenses (adjust for AGPL-3.0 project policy) + # deny-licenses: GPL-1.0-only diff --git a/.github/workflows/dev_deploy.yml b/.github/workflows/dev_deploy.yml new file mode 100644 index 0000000..027b23b --- /dev/null +++ b/.github/workflows/dev_deploy.yml @@ -0,0 +1,41 @@ +name: CIPP Development Frontend CI/CD + +on: + push: + branches: + - dev + +jobs: + build_and_deploy_job: + if: github.event.repository.fork == false && github.event_name == 'push' + runs-on: ubuntu-latest + name: Build and Deploy Job + steps: + - uses: actions/checkout@v6 + with: + submodules: true + - name: Build And Deploy + id: builddeploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_MOSS_0A047A40F }} # change this to your repository secret name + repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) + action: 'upload' + ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### + # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig + app_location: '/' # App source code path + api_location: '' # Api source code path - optional + output_location: '/out' # Built app content directory - optional + ###### End of Repository/Build Configurations ###### + + close_pull_request_job: + if: github.event.repository.fork == false && github.event_name == 'pull_request' && github.event.action == 'closed' + runs-on: ubuntu-latest + name: Close Pull Request Job + steps: + - name: Close Pull Request + id: closepullrequest + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_MOSS_0A047A40F }} # change this to your repository secret name + action: 'close' diff --git a/.github/workflows/label_sponsor_requests.yml b/.github/workflows/label_sponsor_requests.yml new file mode 100644 index 0000000..28b84ea --- /dev/null +++ b/.github/workflows/label_sponsor_requests.yml @@ -0,0 +1,18 @@ +name: Label Issues +on: + issues: + types: + - opened +jobs: + label_issues_bugs: + if: github.repository_owner == 'KelvinTegelaar' && contains(github.event.issue.title, 'Bug') + runs-on: ubuntu-slim + permissions: + issues: write + steps: + - name: Sponsor Labels + uses: JasonEtco/is-sponsor-label-action@v2.0.0 + with: + label: "Sponsor Priority" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr_check.yml b/.github/workflows/pr_check.yml index 33da755..84555d0 100644 --- a/.github/workflows/pr_check.yml +++ b/.github/workflows/pr_check.yml @@ -16,7 +16,7 @@ permissions: jobs: check-branch: - runs-on: ubuntu-latest + runs-on: ubuntu-slim steps: - name: Check and Comment on PR # Only process fork PRs with specific branch conditions @@ -25,28 +25,60 @@ jobs: github.event.pull_request.head.repo.fork == true && ((github.event.pull_request.head.ref == 'main' || github.event.pull_request.head.ref == 'master') || (github.event.pull_request.base.ref == 'main' || github.event.pull_request.base.ref == 'master')) - uses: actions/github-script@v7 + uses: actions/github-script@v9 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | let message = ''; + // Check if the fork has open PRs (indicates pull bot or similar is active) + const forkOwner = context.payload.pull_request.head.repo.owner.login; + const forkRepo = context.payload.pull_request.head.repo.name; + const forkPullsUrl = context.payload.pull_request.head.repo.html_url + '/pulls'; + + let openPRs = []; + try { + const { data: prs } = await github.rest.pulls.list({ + owner: forkOwner, + repo: forkRepo, + state: 'open', + per_page: 5 + }); + openPRs = prs; + } catch (e) { + // Can't read fork PRs — skip + } + + message += '🔄 If you are attempting to update your CIPP 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.'; + + if (openPRs.length > 0) { + message += ` It looks like you may already have a pending update PR on your fork — check your [open pull requests](${forkPullsUrl}) to accept it.`; + } else { + 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.`; + } + message += '\n\n'; + + // Check if PR is targeting main/master if (context.payload.pull_request.base.ref === 'main' || context.payload.pull_request.base.ref === 'master') { - message += '⚠️ PRs cannot target the main branch directly. Please re-open your PR targeting the `dev` branch.\n\n'; + message += '⚠️ PRs cannot target the main branch directly. If you are attempting to contribute code please PR to the dev branch.\n\n'; } - if (context.payload.pull_request.head.ref === 'main' || context.payload.pull_request.head.ref === 'master') { - message += '⚠️ PRs cannot originate from your fork\'s main/master branch. Please create a feature branch and re-open the PR from there.\n\n'; + // Check if PR is from a fork's main/master branch + if (context.payload.pull_request.head.repo.fork && + (context.payload.pull_request.head.ref === 'main' || context.payload.pull_request.head.ref === 'master')) { + 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'; } - message += '🔒 This PR will now be automatically closed.'; + message += '🔒 This PR will now be automatically closed due to the above rules.'; + // Post the comment await github.rest.issues.createComment({ ...context.repo, issue_number: context.issue.number, body: message }); + // Close the PR await github.rest.pulls.update({ ...context.repo, pull_number: context.issue.number, diff --git a/.github/workflows/zap-scan.yml b/.github/workflows/zap-scan.yml new file mode 100644 index 0000000..e1dceb0 --- /dev/null +++ b/.github/workflows/zap-scan.yml @@ -0,0 +1,55 @@ +# DAST: OWASP ZAP scans against the CIPP staging deployment +# ISO 27001:2022 A.8.29 evidence — Dynamic Application Security Testing +# +# Prerequisites: +# - Repo variable STAGING_URL pointing at a staging deployment (test-tenant data only, never production) +# - Optional: .zap/rules.tsv to suppress documented false positives (annotate each with justification) +name: DAST - OWASP ZAP Scan +on: + schedule: + - cron: "0 4 * * 1" # Weekly, Monday 04:00 UTC + workflow_dispatch: # Run on demand before each versioned release + inputs: + full_scan: + description: "Run full (active) scan instead of baseline" + type: boolean + default: false + +permissions: + contents: read + issues: write # ZAP action files findings as GitHub issues + +jobs: + zap_baseline: + if: github.repository_owner == 'KelvinTegelaar' && (github.event_name == 'schedule' || !inputs.full_scan) + name: ZAP Baseline Scan (passive) + runs-on: ubuntu-latest + steps: + - name: Checkout (for .zap rules file) + uses: actions/checkout@v6 + + - name: ZAP baseline scan + uses: zaproxy/action-baseline@v0.15.0 + with: + target: ${{ vars.STAGING_URL }} + rules_file_name: ".zap/rules.tsv" + allow_issue_writing: true + issue_title: "ZAP baseline scan findings" + artifact_name: zap-baseline-report + + zap_full: + if: github.repository_owner == 'KelvinTegelaar' && github.event_name == 'workflow_dispatch' && inputs.full_scan + name: ZAP Full Scan (active, pre-release) + runs-on: ubuntu-latest + steps: + - name: Checkout (for .zap rules file) + uses: actions/checkout@v6 + + - name: ZAP full scan + uses: zaproxy/action-full-scan@v0.13.0 + with: + target: ${{ vars.STAGING_URL }} + rules_file_name: ".zap/rules.tsv" + allow_issue_writing: true + issue_title: "ZAP full scan findings (pre-release)" + artifact_name: zap-full-report From cd1d133e5ca22edcaf08735763cad8f3992a4c8b Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 22 Jul 2026 01:33:38 +0200 Subject: [PATCH 4/4] old workflows removed --- .github/workflows/Node_Project_Check.yml | 31 ---------- .github/workflows/cipp_api_tests.yml | 67 ---------------------- .github/workflows/cipp_dev_build.yml | 63 -------------------- .github/workflows/cipp_frontend_build.yml | 63 -------------------- .github/workflows/dev_deploy.yml | 41 ------------- .github/workflows/frontend_build_check.yml | 41 ------------- 6 files changed, 306 deletions(-) delete mode 100644 .github/workflows/Node_Project_Check.yml delete mode 100644 .github/workflows/cipp_api_tests.yml delete mode 100644 .github/workflows/cipp_dev_build.yml delete mode 100644 .github/workflows/cipp_frontend_build.yml delete mode 100644 .github/workflows/dev_deploy.yml delete mode 100644 .github/workflows/frontend_build_check.yml diff --git a/.github/workflows/Node_Project_Check.yml b/.github/workflows/Node_Project_Check.yml deleted file mode 100644 index 1d675b9..0000000 --- a/.github/workflows/Node_Project_Check.yml +++ /dev/null @@ -1,31 +0,0 @@ ---- -name: NodeJS Project Check -on: - pull_request: - branches: - - main - - dev -concurrency: - group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }} - cancel-in-progress: false -jobs: - install-build: - if: github.repository_owner == 'KelvinTegelaar' - name: NPM Install and Build - runs-on: ubuntu-latest - strategy: - matrix: - node-version: ["22.13.0"] - os: [ubuntu-latest] - steps: - - uses: actions/checkout@v6 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v7.0.0 - with: - node-version: ${{ matrix.node-version }} - - name: Install and Build Test - run: | - npm install --legacy-peer-deps - npm run build - env: - CI: true diff --git a/.github/workflows/cipp_api_tests.yml b/.github/workflows/cipp_api_tests.yml deleted file mode 100644 index 0ff94a0..0000000 --- a/.github/workflows/cipp_api_tests.yml +++ /dev/null @@ -1,67 +0,0 @@ ---- -name: CIPP API Tests -on: - pull_request: - branches: - - dev - - main -concurrency: - group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }} - cancel-in-progress: true -jobs: - api-tests: - if: github.repository_owner == 'KelvinTegelaar' - name: API Shape & Integration Tests - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v6 - - - name: Run Shape Tests - id: shape-tests - shell: pwsh - env: - CIPP_API_URL: ${{ secrets.CIPP_TEST_API_URL }} - CIPP_CLIENT_ID: ${{ secrets.CIPP_TEST_CLIENT_ID }} - CIPP_CLIENT_SECRET: ${{ secrets.CIPP_TEST_CLIENT_SECRET }} - CIPP_TENANT_ID: ${{ secrets.CIPP_TEST_TENANT_ID }} - CIPP_API_SCOPE: ${{ secrets.CIPP_TEST_API_SCOPE }} - CIPP_TENANT_FILTER: ${{ secrets.CIPP_TEST_TENANT_FILTER }} - run: | - ./Tools/Invoke-CippShapeTests.ps1 ` - -CippApiUrl $env:CIPP_API_URL ` - -CippClientId $env:CIPP_CLIENT_ID ` - -CippClientSecret $env:CIPP_CLIENT_SECRET ` - -CippTenantId $env:CIPP_TENANT_ID ` - -CippApiScope $env:CIPP_API_SCOPE ` - -TenantFilter $env:CIPP_TENANT_FILTER ` - -CI - - - name: Run Integration Tests - if: always() - id: integration-tests - shell: pwsh - env: - CIPP_API_URL: ${{ secrets.CIPP_TEST_API_URL }} - CIPP_CLIENT_ID: ${{ secrets.CIPP_TEST_CLIENT_ID }} - CIPP_CLIENT_SECRET: ${{ secrets.CIPP_TEST_CLIENT_SECRET }} - CIPP_TENANT_ID: ${{ secrets.CIPP_TEST_TENANT_ID }} - CIPP_API_SCOPE: ${{ secrets.CIPP_TEST_API_SCOPE }} - CIPP_TENANT_FILTER: ${{ secrets.CIPP_TEST_TENANT_FILTER }} - run: | - ./Tools/Invoke-CippIntegrationTests.ps1 ` - -CippApiUrl $env:CIPP_API_URL ` - -CippClientId $env:CIPP_CLIENT_ID ` - -CippClientSecret $env:CIPP_CLIENT_SECRET ` - -CippTenantId $env:CIPP_TENANT_ID ` - -CippApiScope $env:CIPP_API_SCOPE ` - -TenantFilter $env:CIPP_TENANT_FILTER ` - -CI - - - name: Upload Test Results - if: always() - uses: actions/upload-artifact@v7 - with: - name: test-results - path: Tests/Shapes/test-results.json - retention-days: 30 diff --git a/.github/workflows/cipp_dev_build.yml b/.github/workflows/cipp_dev_build.yml deleted file mode 100644 index 39cd581..0000000 --- a/.github/workflows/cipp_dev_build.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: CIPP Frontend Dev Build - -on: - push: - branches: - - dev - workflow_dispatch: - -jobs: - build: - if: github.event.repository.fork == false - name: Build and Upload CIPP Frontend - runs-on: ubuntu-latest - - steps: - # Checkout the repository - - name: Checkout Code - uses: actions/checkout@v6 - - # Set up Node.js - - name: Get Node version - id: get_node_version - run: | - node_raw_version=$(node -p "require('./package.json').engines.node") - node_sanitized_version=$(echo $node_raw_version | sed -E 's/[^0-9.]+//g') - echo "node_version=$node_sanitized_version" >> $GITHUB_OUTPUT - - - name: Set up Node.js - uses: actions/setup-node@v7.0.0 - with: - node-version: ${{ steps.get_node_version.outputs.node_version }} - - # Install dependencies - - name: Install Dependencies - run: yarn install - - # Build the project - - name: Build Project - run: npm run build - - # Update version.json with commit hash - - name: Update version.json - run: | - VERSION=$(jq -r '.version' public/version.json) - SHORT_SHA="${GITHUB_SHA::7}" - echo "{\"version\": \"${VERSION}\", \"commit\": \"${SHORT_SHA}\"}" > out/version.json - - # Create ZIP File in a New Source Directory - - name: Prepare and Zip Build Files - run: | - mkdir -p build - cp staticwebapp.config.json out/ - zip -r build/dev.zip out - - # Upload to Azure Blob Storage - - name: Azure Blob Upload - uses: LanceMcCarthy/Action-AzureBlobUpload@v3.15.0 - with: - connection_string: ${{ secrets.AZURE_CONNECTION_STRING }} - container_name: cipp - source_folder: build/ - destination_folder: / - delete_if_exists: true diff --git a/.github/workflows/cipp_frontend_build.yml b/.github/workflows/cipp_frontend_build.yml deleted file mode 100644 index a09cc25..0000000 --- a/.github/workflows/cipp_frontend_build.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: CIPP Frontend Build - -on: - push: - branches: - - main - workflow_dispatch: - -jobs: - build: - if: github.event.repository.fork == false - name: Build and Upload CIPP Frontend - runs-on: ubuntu-latest - - steps: - # Checkout the repository - - name: Checkout Code - uses: actions/checkout@v6 - - # Set up Node.js - - name: Get Node version - id: get_node_version - run: | - node_raw_version=$(node -p "require('./package.json').engines.node") - node_sanitized_version=$(echo $node_raw_version | sed -E 's/[^0-9.]+//g') - echo "node_version=$node_sanitized_version" >> $GITHUB_OUTPUT - - - name: Set up Node.js - uses: actions/setup-node@v7.0.0 - with: - node-version: ${{ steps.get_node_version.outputs.node_version }} - - # Install dependencies - - name: Install Dependencies - run: yarn install - - # Build the project - - name: Build Project - run: npm run build - - # Update version.json with commit hash - - name: Update version.json - run: | - VERSION=$(jq -r '.version' public/version.json) - SHORT_SHA="${GITHUB_SHA::7}" - echo "{\"version\": \"${VERSION}\", \"commit\": \"${SHORT_SHA}\"}" > out/version.json - - # Create ZIP File in a New Source Directory - - name: Prepare and Zip Build Files - run: | - mkdir -p build - cp staticwebapp.config.json out/ - zip -r build/latest.zip out - - # Upload to Azure Blob Storage - - name: Azure Blob Upload - uses: LanceMcCarthy/Action-AzureBlobUpload@v3.15.0 - with: - connection_string: ${{ secrets.AZURE_CONNECTION_STRING }} - container_name: cipp - source_folder: build/ - destination_folder: / - delete_if_exists: true diff --git a/.github/workflows/dev_deploy.yml b/.github/workflows/dev_deploy.yml deleted file mode 100644 index 027b23b..0000000 --- a/.github/workflows/dev_deploy.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: CIPP Development Frontend CI/CD - -on: - push: - branches: - - dev - -jobs: - build_and_deploy_job: - if: github.event.repository.fork == false && github.event_name == 'push' - runs-on: ubuntu-latest - name: Build and Deploy Job - steps: - - uses: actions/checkout@v6 - with: - submodules: true - - name: Build And Deploy - id: builddeploy - uses: Azure/static-web-apps-deploy@v1 - with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_MOSS_0A047A40F }} # change this to your repository secret name - repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) - action: 'upload' - ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### - # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig - app_location: '/' # App source code path - api_location: '' # Api source code path - optional - output_location: '/out' # Built app content directory - optional - ###### End of Repository/Build Configurations ###### - - close_pull_request_job: - if: github.event.repository.fork == false && github.event_name == 'pull_request' && github.event.action == 'closed' - runs-on: ubuntu-latest - name: Close Pull Request Job - steps: - - name: Close Pull Request - id: closepullrequest - uses: Azure/static-web-apps-deploy@v1 - with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_MOSS_0A047A40F }} # change this to your repository secret name - action: 'close' diff --git a/.github/workflows/frontend_build_check.yml b/.github/workflows/frontend_build_check.yml deleted file mode 100644 index 1f635dc..0000000 --- a/.github/workflows/frontend_build_check.yml +++ /dev/null @@ -1,41 +0,0 @@ ---- -name: Frontend Build Check -on: - pull_request: - branches: - - main - - dev - paths: - - 'frontend/**' -concurrency: - group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.ref }} - cancel-in-progress: true -jobs: - lint-and-build: - if: github.repository_owner == 'CyberDrain' - name: Lint and Build - runs-on: ubuntu-latest - defaults: - run: - working-directory: frontend - strategy: - matrix: - node-version: ["22.13.0"] - steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: 'yarn' - cache-dependency-path: frontend/yarn.lock - - name: Install dependencies - run: yarn install --frozen-lockfile - - name: Lint - run: yarn lint - env: - CI: true - - name: Build - run: yarn build - env: - CI: true