BASE_REF is empty on pull_request_review events since github.base_ref
is only populated on pull_request events. The empty string hit the
case * wildcard and silently passed the promotion gate.
Add a fallback that fetches .base.ref from the PR API when BASE_REF
is empty but a PR_NUMBER is available.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The --json flag is not valid for gh pr create, only for read commands
like gh pr list and gh pr view. This was causing the release workflow
to fail with 'unknown flag: --json' in the Create PR step.
The PR number is correctly retrieved on the line after via gh pr list,
so no other change was needed.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Both the Update artifacthub-pkg.yml and Prepare release tarball steps now read PKG_NAME from artifacthub-pkg.yml when present, falling back to package.json with correct @org/ prefix stripping. This eliminates the archive-url/tarball name mismatch for 6 of 7 plugins.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
When pnpm-lock.yaml has overrides section, validate that lockfile is fresh before install. If stale (detected via CONFIG_MISMATCH/EBADLOCKFILE/ERR_PNPM_LOCKFILE), fail with clear error message suggesting 'pnpm install' to regenerate.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
When pnpm-lock.yaml has overrides section, validate that lockfile is fresh
before install. If stale (detected via CONFIG_MISMATCH), fail with clear
error message suggesting 'pnpm install' to regenerate.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Fix subdirectory matching: use prefix match for .github/* paths
instead of exact dirname match (fixes .github/workflows/ not matching)
- Upgrade tj-actions/changed-files from v44 to v47 (Node 24 support)
- Extract detection logic into scripts/detect-pipeline.sh for testability
- Add 22 automated tests in scripts/test-detect-pipeline.sh covering
infra-only, plugin code, mixed, and edge cases
- Add test-detection-logic CI job to run tests on every PR
- Update README.md to reference v47
cc @cpfarhood
Co-Authored-By: Paperclip <noreply@paperclip.ing>
New model: no review for dev PRs, QA gates uat, UAT gates main.
Replaces the old CTO+QA dual-approval check.
Co-authored-by: Chris Farhood <chris@farhood.org>
Co-authored-by: Paperclip <noreply@paperclip.ing>
When MERGE_STATE is BLOCKED or UNKNOWN, the workflow attempts --auto
first. If that fails due to autoMergeAllowed: false on the repo, it
falls back to --admin which merges using the GitHub App token and
bypasses branch protection rules.
Resolves: PRI-497
Co-authored-by: Chris Farhood <chris@farhood.org>
Documents available tools on runners and common patterns for GitHub Actions.
Notably, clarifies that gh CLI is not available and recommends using curl
with GitHub API instead.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Adds workflow that detects Pipeline A vs Pipeline B based on changed files
- Pipeline B (infra-only): .github/, *.md, .eslintrc*, .prettierrc*, renovate.json*, .gitignore, .editorconfig, LICENSE
- Pipeline A (default): any other file changes
- Sets PR label (pipeline-a or pipeline-b) for downstream routing
- Reusable workflow can be called from any PR
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The shared plugin-e2e.yaml workflow lacks a Get kubeconfig step. The
ARC runner (runners-privilegedescalation) has no static kubeconfig at
any expected path (/runner/config, ~/.kube/config). It DOES have an
in-cluster service account at /var/run/secrets/kubernetes.io/serviceaccount/token.
This fix adds the same three-tier kubeconfig detection used in
headlamp-polaris-plugin#144:
1. /runner/config (not present on this runner)
2. ~/.kube/config (not present on this runner)
3. Generate from in-cluster service account credentials
This unbreaks E2E for all plugins using the shared workflow:
- headlamp-argocd-plugin
- headlamp-kube-vip-plugin
- headlamp-tns-csi-plugin
Co-authored-by: Chris Farhood <chris@farhood.org>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Add --config ./audit-ci.jsonc to audit-ci step so plugin repos can
provide their own allowlist for inherited @kinvolk/headlamp-plugin
dev-dependency CVEs (CTO decision PRI-854).
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The workflow was failing on pull_request_review events when triggered by
non-PR actors (e.g. greptile-apps[bot] commenting). The dual-approval job
would attempt to call the reusable workflow with a null PR number,
causing the reusable workflow to fail since there was no valid PR to check.
Changes:
- Guard the PR number with explicit null check: [ -z "${PR_NUMBER}" ] || [ "${PR_NUMBER}" = "null" ]
- Add validation of the reviews response before processing
- Fix jq filter to handle null pipeline values explicitly
Fixes flapping Dual Approval (CTO + QA) checks across all plugin repos.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix(plugin-release): correct PR merge logic for BLOCKED state
Prior releases failed with 'Resource not accessible by integration' when
gh pr merge was called with a branch name on a BLOCKED PR. The root cause
is that --auto requires the PR to have a pending status check that can be
satistfied by auto-merge. Without --auto, gh attempts an immediate merge
but the BLOCKED state (from branch protection requiring status checks)
causes GitHub to reject the push.
Fix: always use --auto for BLOCKED PRs, and refactor the polling loop so
it properly loops until mergeStateStatus is no longer UNKNOWN (up to 3
retries with exponential back-off) before deciding whether to use
--auto or merge directly.
Also fix the case where gh pr create is called without --json output, so
OPEN_PR is always captured correctly regardless of whether we created a
new PR or found a pre-existing one.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix: restore MERGED check and use PR number in retry loop
- Restore idempotent exit 0 when PR is already MERGED (regression from prior fix)
- Use $OPEN_PR instead of hardcoded branch name in gh pr view retry loop
- Fallback to --auto when UNKNOWN persists after exhausting retries (safe: auto-merge waits for branch protection)
Fixes bugs reported by Regression Regina on PR #133.
---------
Co-authored-by: Chris Farhood <chris@farhood.org>
Co-authored-by: Paperclip <noreply@paperclip.ing>
PRI-459: Adds 3-attempt retry wrapper (5s backoff) around the Install
dependencies step in plugin-ci.yaml and plugin-release.yaml to handle
transient npm/pnpm registry failures.
Co-authored-by: Chris Farhood <chris@farhood.org>
headlamp-plugin package strips the @ scope prefix and replaces / with -
when naming tarballs (e.g. @privilegedescalation/headlamp-argocd-plugin
becomes privilegedescalation-headlamp-argocd-plugin). The workflow was
using the raw package.json name without this transformation, causing
the Prepare release tarball step to fail when it couldn't find the
expected tarball file.
Co-authored-by: Chris Farhood <chris@farhood.org>
* feat(release): add token permission pre-check
Detect missing write permissions early in the release pipeline rather
than failing late during git push with a cryptic 403 error (see PRI-348).
The new check-token-permissions job generates a GitHub App token and
attempts to create a test ref via the API. On 201 the token has write
permission (cleaned up immediately); on 403 the release job is skipped
with a clear error message. This saves CI time and provides actionable
diagnostics.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix: skip dual approval check gracefully on dismissed reviews
When a pull_request_review event is dismissed, the PR context is null and
PR_NUMBER is empty. Instead of exiting with an error, exit 0 (skip) since
dismissed reviews are not approvals and do not affect the approval state.
Fixes PRI-314.
---------
Co-authored-by: Chris Farhood <chris@farhood.org>
Co-authored-by: Paperclip <noreply@paperclip.ing>
In GitHub Actions, local branches don't exist - only remote branches
under refs/remotes/origin/. This fixes the branch scanning loop to
scan remote branches instead of local refs/heads.
Also fixes the merge-base check to use the full remote ref path.
- Add ::warning:: annotation for git push --delete failures
- Change dry_run input to type: boolean for proper validation
- Handle null dry_run in scheduled runs (default to false)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fixes two bugs in the auto-merge workflow PEM handling:
- echo may add trailing newline corrupting PEM content; use printf %s
- -binary flag in openssl dgst is unnecessary and removed
QA approved by privilegedescalation-qa (2026-04-21T20:24:46Z)
CTO approved by privilegedescalation-cto (2026-04-21T20:37:22Z)
Fixes PRI-173. Resolves PRI-179.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Replace pnpm audit and npm audit with audit-ci, which supports
the new npm bulk advisory endpoint (/-/npm/v1/security/advisories/bulk).
The old audit endpoints return HTTP 410 Gone.
Fixes: PRI-151
Co-authored-by: Test User <test@example.com>
Co-authored-by: Hugh Hackman <hugh@privilegedescalation.ai>
The pnpm audit endpoint returns HTTP 410 indicating it's retired.
Skip security audit for pnpm repos to unblock CI on plugin repos.
Co-authored-by: Paperclip <noreply@paperclip.ing>
After merging the release PR, verify that:
- The released tarball's SHA256 matches the tag's artifacthub-pkg.yml
- The released tarball's SHA256 matches main's artifacthub-pkg.yml
Fails loudly if they diverge so checksum drift is caught immediately.
Co-authored-by: privilegedescalation-ceo[bot] <269721483+privilegedescalation-ceo[bot]@users.noreply.github.com>
pnpm audit is available in pnpm v10+. The previous implementation
skipped the security audit for pnpm repos due to a retired endpoint,
which blocks all plugin releases that use pnpm.
gh CLI no longer supports --json mergeableState; the field is now
mergeStateStatus with uppercase enum values (BLOCKED, UNKNOWN, etc.)
Co-authored-by: privilegedescalation-ceo[bot] <269721483+privilegedescalation-ceo[bot]@users.noreply.github.com>
The 'Rebuild tarball' step caused a self-referential checksum failure:
1. 'Package plugin' runs headlamp-plugin package, which writes the tarball
checksum into artifacthub-pkg.yml on disk.
2. 'Rebuild tarball' ran headlamp-plugin package a second time. This second
tarball contains the updated artifacthub-pkg.yml (with the first checksum
embedded), so its SHA256 is different from what artifacthub-pkg.yml records.
3. The tool validates computed checksum vs artifacthub-pkg.yml and exits 1.
Fix: remove 'Rebuild tarball' and 'Validate rebuilt tarball' steps entirely.
The 'Package plugin' step already produces a correct tarball and checksum.
Co-authored-by: privilegedescalation-ceo[bot] <269721483+privilegedescalation-ceo[bot]@users.noreply.github.com>
The npm lockfile generation approach (npm install --package-lock-only) is
unreliable for pnpm repos that have a packageManager field: corepack
intercepts npm and the install fails, leaving no lockfile for npm audit.
Skip npm audit entirely for pnpm repos. The pnpm audit endpoint is retired
(HTTP 410) so there is no viable audit path for these repos anyway.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The previous fix (PR #92) added '2>/dev/null || true' to the npm install
command, silently swallowing failures. When npm install --package-lock-only
fails, no lockfile is created and npm audit fails with ENOLOCK.
Remove the silent suppression and --quiet flag so failures surface clearly.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Corepack requires Node to be set up first. The release job was failing
with 'corepack: command not found' because Setup pnpm (Corepack) ran
before Setup Node.
This aligns plugin-release.yaml with plugin-ci.yaml step ordering.
Fixes PRI-21
Co-authored-by: Pawla Abdul (Bot) <pawla@groombook.dev>
The pnpm registry audit endpoint is retired (HTTP 410).
Fix: for pnpm repos, run 'npm install --package-lock-only --ignore-scripts --quiet --no-audit'
to generate a package-lock.json from pnpm-lock.yaml metadata, then run npm audit.
For npm repos, continue using npm audit directly.
Use --audit-level=moderate to fail only on high/critical vulnerabilities,
not moderate ones, reducing noise from transitive dependencies.
Co-authored-by: Hugh Hackman <hugh@privilegedescalation>
Co-authored-by: Paperclip <noreply@paperclip.ing>
pnpm projects use pnpm-lock.yaml, not package-lock.json. The previous
fix switched from pnpm audit to npm audit but npm audit requires an
existing lockfile. Generate one first with npm install --package-lock-only.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Corepack is not pre-installed on runs-on: runners-privilegedescalation,
causing 'corepack: command not found' errors. Install it via
'npm install -g corepack' before using corepack commands.
Fixes PRI-51.