pnpm/action-setup@v4 errors when both the `version` input and a
`packageManager` field in package.json are specified. Detect the
packageManager field during the package-manager detection step and
conditionally omit `version: latest` when it is present.
Fixes CI failures on repos using Corepack-style pnpm version pinning
(e.g. headlamp-polaris-plugin PR #103).
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Previously the jq logic checked if *any* review from CTO/QA had
state == APPROVED. This allowed a PR to pass dual-approval even if
the reviewer subsequently requested changes — because the earlier
approval was still in the review history.
Fix: filter reviews by user, take the last one, and check its state.
This ensures a CHANGES_REQUESTED review after an approval correctly
blocks the check.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
pnpm/action-setup@v4 requires either a version input or a packageManager
field in package.json. Repos with pnpm-lock.yaml but no packageManager
field were failing with "No pnpm version is specified."
Adding version: latest as a fallback allows the action to install the
latest stable pnpm when packageManager is not set. Repos that do specify
packageManager in package.json continue to use their pinned version.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Adds a shared reusable workflow that plugin repos can call to enforce
the dual CTO+QA approval policy as a GitHub required status check.
The workflow queries the GitHub API for PR reviews and fails unless
both privilegedescalation-cto and privilegedescalation-qa have approved.
Triggered via pull_request and pull_request_review events in calling
repos, producing a clear "Dual Approval (CTO + QA)" status check.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The multi-line --body string had cc @cpfarhood at column 0, which
terminated the YAML literal block scalar prematurely and caused
actionlint to reject the workflow file. Use printf to construct
the body string without embedding a literal newline in the YAML.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
When pnpm-lock.yaml is present, use pnpm for install, lint, type-check,
format check, tests, and security audit instead of npm. Repos using npm
are unaffected (falls back to existing npm behavior).
This fixes the npm/pnpm inconsistency in headlamp-polaris-plugin where
local development uses pnpm but CI used npm, causing:
- Different transitive dependency resolution (TypeScript not hoisted)
- Different audit results (pnpm audit vs npm audit)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All PRs must include cc @cpfarhood. The automated release PR
body generated by plugin-release.yaml was missing this.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Exclude E2E Tests from CI failure count (keeps CI/CD noise separate)
- Add dedicated E2E warning line for main branch failures (PRI-494)
- Move Release failure warning outside the else block — always report it
- Update Release warning comment: graceful skip is now in place, so
failures are real errors not just missing-secrets noise
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The CI/CD health check uses GITHUB_TOKEN which only has access to
the .github repo. Listing workflow runs across the 6 plugin repos
requires org-wide access, causing all repos to show "WARNING: No
workflow runs found".
Fix: generate a GitHub App token (using RELEASE_APP_ID/RELEASE_APP_PRIVATE_KEY,
same as the release workflow) scoped to the org before running the
health check script. Falls back to GITHUB_TOKEN gracefully via
continue-on-error if the secrets are not yet configured.
Once RELEASE_APP_ID is configured as an org secret (tracked separately),
the health check will produce accurate cross-repo CI data.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Adds a check-secrets job that runs before any expensive work. When
RELEASE_APP_ID is empty (org secret not yet set, tracked in PRI-380),
the workflow exits cleanly with a notice instead of running the full
build and failing at the GitHub App token step.
Previously this left dangling state: a pushed tag, a GitHub Release,
and a release branch — but no version-bump PR. Now the workflow skips
all of that and exits clean.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Replace node -e JSON parsing with jq (available on our runners)
- Exclude Release workflow failures from FAIL count — these fail at
the post-release PR-creation step due to missing RELEASE_APP org
secrets (tracked in PRI-380), not actual CI breakage
- Demote Release failures to WARN so the health check exits 0 when
only Release is broken, giving clean signal for real CI problems
- Increase run limit from 5 to 10 for better intermittent failure detection
- Remove unnecessary Node.js setup step from the workflow
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix: skip duplicate release gracefully when tag already exists
Replace inline exit-1 tag check with a dedicated check-tag job that uses
the GitHub API. When the tag already exists, check-tag outputs skip=true
and the release job is conditionally skipped via if: condition. Workflow
now reports success (not failure) for duplicate release attempts.
Fixes#30 (partial) — resolves the tag-already-exists failure mode.
Co-Authored-By: Hugh Hackman <hugh@privilegedescalation.io>
* fix: use curl instead of gh CLI in check-tag job for portability
gh CLI may not be pre-installed on ARC runners. curl is always available
in container images. Avoids potential startup failure if gh binary is absent.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix: drop -f flag from curl in check-tag to avoid exit on 404
With -f, curl exits non-zero when the tag does not exist (404). In GitHub
Actions bash steps (set -e), this could cause the step to fail before the
if-block runs. Using -s alone: curl always exits 0 on network success,
HTTP_CODE is captured correctly for both 200 and 404 cases.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
---------
Co-authored-by: Hugh Hackman <hugh@privilegedescalation.io>
Co-authored-by: Paperclip <noreply@paperclip.ing>
The org blocks GITHUB_TOKEN from creating pull requests
("Write permissions for workflows are disabled by the organization").
Switch to a GitHub App installation token generated via
actions/create-github-app-token for the PR creation step.
Requires org-level secrets RELEASE_APP_ID and RELEASE_APP_PRIVATE_KEY
to be configured. Calling workflows must pass these secrets.
Closes#30
Co-authored-by: Hugh Hackman <hugh@privilegedescalation.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
ARC runner containers run as non-root, so `mv` to /usr/local/bin fails
with permission denied. Install to $HOME/.local/bin instead and add to
GITHUB_PATH.
Co-authored-by: Hugh Hackman [bot] <hugh-hackman[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
ARC runner scale set was recreated on 2026-03-19 with label
`runners-privilegedescalation` but all shared workflows still referenced
`local-ubuntu-latest`. This label mismatch caused startup_failure on
every Release workflow and queued CI jobs with no runner to pick them up.
Updates all 4 workflows and the actionlint config to match the current
ARC runner scale set label.
Closes#27
The self-hosted runner doesn't have xz installed, so extracting the
shellcheck tar.xz release fails. Use apt-get install instead.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The shellcheck step fails with "command not found" because shellcheck
is not installed on the runner. Install it from GitHub releases, same
pattern as the actionlint install step.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The runner doesn't have write access to /usr/local/bin. Install to
$HOME/.local/bin instead and add it to GITHUB_PATH.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The .github repo had no CI running on pull requests — PRs merged without
any validation. This adds actionlint for workflow YAML and shellcheck for
scripts in .github/scripts/, triggered on PRs to main.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
actions/checkout v6 was already adopted in headlamp-agent-skills.
This brings the org-level reusable workflows (plugin-ci, plugin-release,
ci-health-check) up to the same version. Affects all plugin repos that
call these shared workflows.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The apt-based gh CLI install requires sudo which is not available on our
self-hosted container runners. Replace with a direct binary download from
GitHub releases that works without elevated permissions.
Fixes the "gh: command not found" error in the release workflow's
"Create PR for version bump" step.
Co-authored-by: Hugh Hackman <hugh@privilegedescalation.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
The self-hosted runner (local-ubuntu-latest) does not have gh CLI
pre-installed, causing the PR creation step to fail with
"gh: command not found" after the release is published.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The release PR is just a version bump + checksum update. Enable
auto-merge with squash and delete the release branch after merge
to prevent branch accumulation.
The release workflow pushed directly to main which fails on repos
with branch protection enabled. This broke the polaris plugin v0.7.0
release.
Changes:
- Create release/vX.Y.Z branch instead of committing to main
- Push to the release branch + tags
- Create a PR to merge the version bump back to main
- Add pull-requests: write permission
Fail fast when a release tag already exists instead of running the
full build+package cycle only to fail at git push. Saves CI time on
duplicate workflow_dispatch triggers.
Adds a security audit step (npm audit --omit=dev) to catch known
vulnerabilities in production dependencies. Runs after tests so build
failures are reported before audit findings. Uses --omit=dev to focus
on production-facing risk.
This covers all 6 plugin repos that use the shared workflow.