mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 08:36:25 +00:00
ci: add supply-chain guards - permission allowlist, gitignore rules, manifest checks, pinned actions
This template's threat model is unusual: it ships pre-approved Claude Code permissions (.claude/settings.json) and CLI code that every fork user executes via those permissions. A plausible-looking PR could therefore ship risk to every forker: widen a permission to Bash(*), weaken the personal-data gitignore rules, or smuggle code execution into bun install via a lifecycle script. Nothing checked for these mechanically. New job security-guards runs tools/security_guards.py (stdlib only): - settings.json: every permissions.allow entry must be in an exact, in-repo allowlist. The guard makes permission changes loud, not impossible - a PR that intentionally widens permissions must update the allowlist in the same diff, so the widening is explicit and reviewable - .gitignore: the personal-data rules (tracker, documents/**, cv/main_*, salary data, seen_jobs) must all still be present - the mirror image of the placeholder-integrity job - .agents/**/package.json: no lifecycle scripts (preinstall/install/ postinstall/prepare/prepack) and no trustedDependencies, which would execute arbitrary code during bun install on users' machines New job dependency-review (PRs only): actions/dependency-review-action flags newly introduced vulnerable or malicious dependencies, fail-on-severity high. Workflow hardening: explicit top-level permissions: contents: read (least-privilege token), and all actions pinned to commit SHAs resolved from the same major tags already in use (checkout v4, setup-python v5, setup-bun v2), with the tag recorded in a comment. Honest limit, recorded in the workflow header: a PR can edit this workflow itself, so these guards catch accidents and casual attempts, not a determined author. Branch protection with required checks and human review of workflow/settings diffs remain the real backstop. Verified locally: positive run passes; injecting Bash(*) into settings.json, deleting the tracker gitignore rule, and adding a postinstall script each fail the guard with the intended message, and reverting restores a clean pass.
This commit is contained in:
@@ -10,6 +10,16 @@
|
||||
# real portals (network-flaky, and the linkedin-search skill is personal-use
|
||||
# only per its own ToS warning - CI-automated requests would violate that).
|
||||
# CLIs get typechecked instead; live testing stays a local, on-demand step.
|
||||
#
|
||||
# Security posture: this template ships pre-approved Claude Code permissions
|
||||
# and CLI code that every fork user executes, so the security-guards job
|
||||
# fails PRs that widen settings.json permissions, weaken the personal-data
|
||||
# gitignore rules, or add package lifecycle scripts; dependency-review flags
|
||||
# newly introduced vulnerable/malicious dependencies. Honest limit: a PR can
|
||||
# edit this workflow itself, so these guards catch accidents and casual
|
||||
# attempts, not a determined author - branch protection with required checks
|
||||
# and human review of workflow/settings diffs remain the real backstop.
|
||||
# Actions are pinned to commit SHAs; the token is read-only.
|
||||
|
||||
name: CI
|
||||
|
||||
@@ -19,24 +29,47 @@ on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint skills, commands, settings
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- run: pip install pyyaml
|
||||
- run: python tools/lint_skills.py
|
||||
|
||||
security-guards:
|
||||
name: Security guards (permissions, gitignore, manifests)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- run: python tools/security_guards.py
|
||||
|
||||
dependency-review:
|
||||
name: Dependency review
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
|
||||
with:
|
||||
fail-on-severity: high
|
||||
|
||||
latex-smoke:
|
||||
name: Compile example CV and cover letter
|
||||
runs-on: ubuntu-latest
|
||||
container: texlive/texlive:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- name: Compile CV example (lualatex)
|
||||
run: |
|
||||
cd cv
|
||||
@@ -78,8 +111,8 @@ jobs:
|
||||
- jobnet-search
|
||||
- linkedin-search
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- run: bun install
|
||||
working-directory: .agents/skills/${{ matrix.tool }}/cli
|
||||
- run: bun run typecheck
|
||||
@@ -90,7 +123,7 @@ jobs:
|
||||
if: github.repository == 'MadsLorentzen/ai-job-search'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- name: Tracked template files must keep their placeholder tokens
|
||||
run: |
|
||||
fail=0
|
||||
|
||||
Reference in New Issue
Block a user