Files
santifer--career-ops/.github/workflows/no-user-data.yml
T
wehub-resource-sync d083df1fdb
CodeQL Analysis / Analyze (javascript-typescript) (push) Failing after 2s
Web CI / web typecheck + build (push) Failing after 1s
Release Please / release-please (push) Failing after 1s
CodeQL Analysis / Analyze (go) (push) Failing after 16s
chore: import upstream snapshot with attribution
2026-07-13 12:02:43 +08:00

65 lines
2.4 KiB
YAML

name: No user data in PRs
# Hard-blocks any PR that adds or modifies user-layer (private data) files.
# These live ONLY on the candidate's machine per DATA_CONTRACT.md and must never
# enter the repo — they are personal job-search data. Sample/fixture data belongs
# under examples/. Tracked scaffolding (.gitkeep keepers, dir READMEs) is exempt.
# Paths mirror USER_PATHS in update-system.mjs. Uses the API (listFiles) so it
# works for fork PRs too.
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: read
jobs:
guard:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v9
with:
script: |
const { owner, repo } = context.repo;
const pull_number = context.payload.pull_request.number;
const files = await github.paginate(github.rest.pulls.listFiles, {
owner, repo, pull_number, per_page: 100,
});
// User-layer paths from DATA_CONTRACT.md and update-system.mjs.
// voice-dna.md is omitted on purpose: it ships as a populated
// system default, so edits to it are legit.
const USER_PATHS = [
/^cv\.md$/,
/^config\/profile\.yml$/,
/^modes\/_profile\.md$/,
/^modes\/_custom\.md$/,
/^portals\.yml$/,
/^article-digest\.md$/,
/^interview-prep\//,
/^data\//,
/^reports\//,
/^output\//,
/^jds\//,
/^writing-samples\//,
];
// Tracked scaffolding that legitimately lives under those dirs.
const isScaffold = (f) => /(^|\/)\.gitkeep$/.test(f) || /(^|\/)README\.md$/.test(f);
const bad = files
.filter((f) => f.status !== 'removed')
.map((f) => f.filename)
.filter((f) => USER_PATHS.some((re) => re.test(f)) && !isScaffold(f));
if (bad.length) {
core.setFailed(
'This PR adds/modifies user-layer (private data) files. These live ONLY on your ' +
'machine per DATA_CONTRACT.md and must never be committed — use examples/ for ' +
'sample data.\nOffending files:\n ' + bad.join('\n ')
);
} else {
core.info('OK — no user-layer (private data) files touched.');
}