mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-22 00:31:17 +00:00
* Initial plan * chore(security): harden workflow permissions and pin Docker base image digests Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/2ddc8f2b-7355-48cf-9a0b-c06df66c3f47 * fix(security): restore permissions: {} on publish + release-candidate workflows These two release-publishing workflows had permissions: {} (the strictest valid form) before PR #1454, which replaced it with permissions: read-all. Every job in both files already declares its own permissions block, so the workflow-level default is only the safety net for future jobs added without one — read-all weakens that net for no benefit. Restore {} and the explanatory comment. Scorecard's TokenPermissions check accepts both forms, so this preserves U9 compliance. * fix(security): narrow permissions: read-all to contents: read on 13 workflows PR #1454 added permissions: read-all to 13 workflows that previously had no top-level permissions block. read-all is Scorecard-compliant but unnecessarily broad — every job in scope only needs contents:read at the workflow level (job-level blocks already grant the writes that any job actually performs). Snapshot of every job in the 13 workflows confirms contents:read is sufficient: - ci.yml: quality/tests/scope-parity have explicit contents:read job blocks; save-pr-meta uses upload-artifact only (no token scopes needed); ci-status is pure shell. - ci-e2e.yml, ci-quality.yml, ci-scope-parity.yml, ci-tests.yml: all jobs do checkout + npm + tsc/vitest/playwright/upload-artifact only; no API token scopes required. - claude.yml, codeql.yml, dependency-review.yml, docker.yml, gitleaks.yml, pr-labeler.yml, trivy.yml, workflow-lint.yml: all jobs already declare their own job-level blocks (security-events:write, pull-requests:write, packages:write, etc.) so the workflow-level default does not gate them. zizmor (--min-severity high) is clean on the resulting tree. Pre-existing medium findings (secrets-inherit, artipacked) are in unrelated workflows and untouched by this commit. scorecard.yml also uses read-all but pre-existed PR #1454 and is deferred to a follow-up PR per the plan's scope boundary. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
116 lines
4.9 KiB
YAML
116 lines
4.9 KiB
YAML
name: PR Conventional Labeler
|
|
|
|
# Two workflows in one file with different triggers, matched to the minimum
|
|
# privilege each needs:
|
|
#
|
|
# validate-title (on: pull_request)
|
|
# Fork-safe. Runs with the PR-head's read-only GITHUB_TOKEN. Uses
|
|
# `amannn/action-semantic-pull-request` to fail the check when the PR
|
|
# title doesn't follow the conventional-commit format. Because the
|
|
# action only reads the event payload, no fork-controlled code runs.
|
|
#
|
|
# autolabel (on: pull_request_target)
|
|
# Needs `pull-requests: write` to apply labels, so must be
|
|
# pull_request_target. Uses `release-drafter/release-drafter` with
|
|
# `dry-run: true` to only run the autolabeler against the
|
|
# `.github/release-drafter.yml` config from the BASE ref (release-
|
|
# drafter reads the config from the repository's default branch, NOT
|
|
# the PR head — verify with `gh api repos/release-drafter/release-drafter/contents/...`
|
|
# or a fork-test PR before merging if the repo is high-value).
|
|
# `sync-labels: true` in the config removes managed autolabels that no
|
|
# longer match (e.g. when `!` or `BREAKING CHANGE:` is dropped).
|
|
#
|
|
# Title format: <type>[(scope)][!]: <subject>
|
|
# Allowed types: feat, fix, perf, refactor, docs, test, ci, build, chore, revert, deps
|
|
# Trailing `!` on the type marks a breaking change.
|
|
# See CONTRIBUTING.md → "Pull request titles".
|
|
|
|
on:
|
|
pull_request:
|
|
# Title-only changes fire `edited`. `opened` and `reopened` cover creation.
|
|
# `synchronize` (push to the PR branch) is intentionally excluded — titles
|
|
# don't change on push, so it only wastes CI minutes and broadens the
|
|
# privileged-token exposure window on the autolabel job.
|
|
types: [opened, edited, reopened]
|
|
pull_request_target:
|
|
types: [opened, edited, reopened]
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
# Concurrency convention: see CONTRIBUTING.md → "GitHub Actions — Concurrency Convention".
|
|
# Include `github.event_name` so `pull_request` (validate-title) and
|
|
# `pull_request_target` (autolabel) runs for the same PR do NOT share a slot
|
|
# and therefore cannot cancel each other — a cancelled required-check would
|
|
# permanently block merge until the next title edit.
|
|
# Within each trigger the latest title edit still supersedes the prior run.
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
validate-title:
|
|
# Fork-safe job — only runs on `pull_request` (not `pull_request_target`).
|
|
# Token is read-only; writes a commit status that branch protection can
|
|
# require before merge.
|
|
name: Validate PR title
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
permissions:
|
|
pull-requests: read
|
|
steps:
|
|
# Pinned to v6.1.1. Verify SHA via:
|
|
# gh api repos/amannn/action-semantic-pull-request/git/refs/tags/v6.1.1
|
|
- uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
with:
|
|
types: |
|
|
feat
|
|
fix
|
|
perf
|
|
refactor
|
|
docs
|
|
test
|
|
ci
|
|
build
|
|
chore
|
|
revert
|
|
deps
|
|
requireScope: false
|
|
# Subject must be non-empty. We DO allow capitalized proper nouns
|
|
# (MCP, GitHub, API, etc.) — the old `^(?![A-Z]).+$` pattern
|
|
# rejected legitimate titles like `fix: MCP tool schema`.
|
|
subjectPattern: ^\S.{2,}$
|
|
subjectPatternError: |
|
|
The subject "{subject}" in PR title "{title}" is invalid.
|
|
Subjects must be at least 3 characters and must not start with whitespace.
|
|
wip: false
|
|
|
|
autolabel:
|
|
# Privileged job — runs only on `pull_request_target` so it can write labels.
|
|
# Never checks out fork code, never executes fork-controlled input; only
|
|
# reads the PR metadata (title, body, labels) and calls the GitHub API.
|
|
name: Apply conventional label
|
|
if: github.event_name == 'pull_request_target'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
permissions:
|
|
# `contents: read` is required — release-drafter's context.config() reads
|
|
# `.github/release-drafter.yml` from the repo's default branch via the
|
|
# repo-contents API. Without it the job silently 403s and no labels are
|
|
# applied. Job-level permissions nullify all unlisted scopes, so an
|
|
# explicit grant is necessary here.
|
|
contents: read
|
|
pull-requests: write
|
|
steps:
|
|
# Pinned to v7.2.0. Verify SHA via:
|
|
# gh api repos/release-drafter/release-drafter/git/refs/tags/v7.2.0
|
|
# v7 removed `disable-releaser`; use `dry-run: true` to only autolabel.
|
|
- uses: release-drafter/release-drafter@563bf132657a13ded0b01fcb723c5a58cdd824e2 # v7.2.1
|
|
with:
|
|
config-name: release-drafter.yml
|
|
dry-run: true
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|