bcquality/.github/workflows/guard-custom-layer.yml
dependabot[bot] 455035432d
Some checks are pending
Validate knowledge index / validate-index (push) Waiting to run
Validate AL review fixtures / validate-review-fixtures (push) Waiting to run
Validate frontmatter and structure / validate (push) Waiting to run
Bump the github-actions group with 3 updates (#127)
Bumps the github-actions group with 3 updates: [actions/checkout](https://github.com/actions/checkout), [actions/github-script](https://github.com/actions/github-script) and [actions/setup-python](https://github.com/actions/setup-python).


Updates `actions/checkout` from 4.4.0 to 7.0.1
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](11d5960a32...3d3c42e5aa)

Updates `actions/github-script` from 7.1.0 to 9.0.0
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](f28e40c7f3...3a2844b7e9)

Updates `actions/setup-python` from 5.6.0 to 7.0.0
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](a26af69be9...5fda3b95a4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/github-script
  dependency-version: 9.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/setup-python
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-17 12:51:59 +02:00

88 lines
3.4 KiB
YAML

name: Guard custom layer
# The /custom/ layer is a template: in upstream microsoft/BCQuality it stays
# empty by default (README.md + .gitkeep placeholders only). Custom knowledge
# and skills are partner/customer-specific and belong in a fork, never upstream.
#
# This workflow auto-closes any PR that adds or changes content under /custom/
# (anything beyond the allowed template files). It runs only on the upstream
# repo, so forks that legitimately populate /custom/ are unaffected.
#
# pull_request_target is required so the workflow runs with a token that can
# comment on and close the PR (including PRs opened from forks). It only reads
# the PR's file LIST via the API and never checks out or executes PR code, so
# the elevated token is not exposed to untrusted content.
on:
pull_request_target:
types: [opened, reopened, synchronize]
permissions:
contents: read
pull-requests: write
issues: write
jobs:
guard:
# Never run on forks — a fork's /custom/ content is exactly what's supposed
# to live there.
if: github.repository == 'microsoft/BCQuality'
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
sparse-checkout: |
.github/custom-layer-autoclose.md
sparse-checkout-cone-mode: false
- name: Close PR if it touches the custom layer
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const fs = require('fs');
// Files under custom/ that ARE allowed to change (the template seed).
const ALLOWED = new Set([
'custom/README.md',
]);
// Any .gitkeep under custom/ is also allowed.
const isAllowed = (p) =>
ALLOWED.has(p) || /^custom\/.*\.gitkeep$/.test(p) || p === 'custom/.gitkeep';
const { owner, repo } = context.repo;
const prNumber = context.payload.pull_request.number;
const files = await github.paginate(github.rest.pulls.listFiles, {
owner, repo, pull_number: prNumber, per_page: 100,
});
// Offending = added/modified/renamed/copied/changed paths under custom/
// that are not template files. (We ignore pure deletions.)
const offending = files
.filter((f) => f.status !== 'removed')
.map((f) => f.filename)
.filter((p) => p.startsWith('custom/') && !isAllowed(p));
if (offending.length === 0) {
core.info('No disallowed /custom/ changes found. Nothing to do.');
return;
}
core.warning(`PR #${prNumber} touches the custom layer: ${offending.join(', ')}`);
const fileList = offending.map((p) => `- \`${p}\``).join('\n');
let body = fs.readFileSync('.github/custom-layer-autoclose.md', 'utf8');
body = body
.replace(/{{AUTHOR}}/g, context.payload.pull_request.user.login)
.replace(/{{FILES}}/g, fileList);
await github.rest.issues.createComment({
owner, repo, issue_number: prNumber, body,
});
await github.rest.pulls.update({
owner, repo, pull_number: prNumber, state: 'closed',
});
core.info(`Closed PR #${prNumber}.`);