Restrict GITHUB_TOKEN permissions in build workflows - #499
Conversation
Add top-level contents: read, and grant packages: write on the jobs that call the reusable build/staging workflows (a callee cannot exceed what its calling job grants, which is what broke the earlier attempt in #488). Callee jobs now state contents: read explicitly. Addresses CodeQL actions/missing-workflow-permissions alerts 1-5 and 18. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
✅
|
| Descriptor | Linter | Files | Fixed | Errors | Max errors | Warnings | Elapsed time |
|---|---|---|---|---|---|---|---|
| ✅ ACTION | actionlint | 7 | 0 | 0 | 0.13s | ||
| zizmor | 7 | 1 | 0 | 0.34s | |||
| ✅ BASH | bash-exec | 2 | 0 | 0 | 0.01s | ||
| ✅ BASH | shellcheck | 2 | 0 | 0 | 0.18s | ||
| shfmt | 2 | 1 | 0 | 0.02s | |||
| cppcheck | 8 | 8 | 0 | 0.05s | |||
| cppcheck | 8 | 8 | 0 | 0.06s | |||
| ✅ JSON | npm-package-json-lint | yes | no | no | 0.58s | ||
| ✅ JSON | v8r | 17 | 0 | 0 | 9.79s | ||
| ✅ REPOSITORY | betterleaks | yes | no | no | 1.26s | ||
| ✅ REPOSITORY | git_diff | yes | no | no | 0.58s | ||
| ✅ REPOSITORY | grype | yes | no | no | 55.86s | ||
| ✅ REPOSITORY | osv-scanner | yes | no | no | 1.3s | ||
| ✅ REPOSITORY | secretlint | yes | no | no | 10.89s | ||
| ✅ REPOSITORY | syft | yes | no | no | 2.57s | ||
| ✅ REPOSITORY | trivy-sbom | yes | no | no | 1.72s | ||
| ✅ REPOSITORY | trufflehog | yes | no | no | 5.97s | ||
| ✅ TYPESCRIPT | ts-standard | 3 | 0 | 0 | 5.15s | ||
| ✅ XML | xmllint | 1 | 0 | 0 | 7.54s | ||
| ✅ YAML | v8r | 15 | 0 | 0 | 8.46s |
Detailed Issues
⚠️ C / cppcheck - 8 errors
Checking assets/2013-11-14-explorer-wall-avoider-kit/alternative_demo/DistanceSensor.h ...
assets/2013-11-14-explorer-wall-avoider-kit/alternative_demo/DistanceSensor.h:3:1: error: Code 'classSR04{' is invalid C code. [syntaxError]
class SR04 {
^
1/8 files checked 12% done
Checking assets/2013-11-14-explorer-wall-avoider-kit/alternative_demo/Motors.h ...
assets/2013-11-14-explorer-wall-avoider-kit/alternative_demo/Motors.h:3:1: error: Code 'classMotor{' is invalid C code. [syntaxError]
class Motor {
^
2/8 files checked 19% done
Checking assets/2013-11-14-explorer-wall-avoider-kit/demo_sketch/DistanceSensor.h ...
assets/2013-11-14-explorer-wall-avoider-kit/demo_sketch/DistanceSensor.h:3:1: error: Code 'classSR04{' is invalid C code. [syntaxError]
class SR04 {
^
3/8 files checked 31% done
Checking assets/2013-11-14-explorer-wall-avoider-kit/demo_sketch/TurtleMotors.h ...
assets/2013-11-14-explorer-wall-avoider-kit/demo_sketch/TurtleMotors.h:3:1: error: Code 'classMotor{' is invalid C code. [syntaxError]
class Motor {
^
4/8 files checked 49% done
Checking galleries/2013-11-14-explorer-wall-avoider-kit/alternative_demo/DistanceSensor.h ...
galleries/2013-11-14-explorer-wall-avoider-kit/alternative_demo/DistanceSensor.h:3:1: error: Code 'classSR04{' is invalid C code. [syntaxError]
class SR04 {
^
5/8 files checked 62% done
Checking galleries/2013-11-14-explorer-wall-avoider-kit/alternative_demo/Motors.h ...
galleries/2013-11-14-explorer-wall-avoider-kit/alternative_demo/Motors.h:3:1: error: Code 'classMotor{' is invalid C code. [syntaxError]
class Motor {
^
6/8 files checked 69% done
Checking galleries/2013-11-14-explorer-wall-avoider-kit/demo_sketch/DistanceSensor.h ...
galleries/2013-11-14-explorer-wall-avoider-kit/demo_sketch/DistanceSensor.h:3:1: error: Code 'classSR04{' is invalid C code. [syntaxError]
class SR04 {
^
7/8 files checked 81% done
Checking galleries/2013-11-14-explorer-wall-avoider-kit/demo_sketch/TurtleMotors.h ...
galleries/2013-11-14-explorer-wall-avoider-kit/demo_sketch/TurtleMotors.h:3:1: error: Code 'classMotor{' is invalid C code. [syntaxError]
class Motor {
^
8/8 files checked 100% done
⚠️ CPP / cppcheck - 8 errors
Checking assets/2013-11-14-explorer-wall-avoider-kit/alternative_demo/DistanceSensor.h ...
assets/2013-11-14-explorer-wall-avoider-kit/alternative_demo/DistanceSensor.h:3:1: error: Code 'classSR04{' is invalid C code. [syntaxError]
class SR04 {
^
1/8 files checked 12% done
Checking assets/2013-11-14-explorer-wall-avoider-kit/alternative_demo/Motors.h ...
assets/2013-11-14-explorer-wall-avoider-kit/alternative_demo/Motors.h:3:1: error: Code 'classMotor{' is invalid C code. [syntaxError]
class Motor {
^
2/8 files checked 19% done
Checking assets/2013-11-14-explorer-wall-avoider-kit/demo_sketch/DistanceSensor.h ...
assets/2013-11-14-explorer-wall-avoider-kit/demo_sketch/DistanceSensor.h:3:1: error: Code 'classSR04{' is invalid C code. [syntaxError]
class SR04 {
^
3/8 files checked 31% done
Checking assets/2013-11-14-explorer-wall-avoider-kit/demo_sketch/TurtleMotors.h ...
assets/2013-11-14-explorer-wall-avoider-kit/demo_sketch/TurtleMotors.h:3:1: error: Code 'classMotor{' is invalid C code. [syntaxError]
class Motor {
^
4/8 files checked 49% done
Checking galleries/2013-11-14-explorer-wall-avoider-kit/alternative_demo/DistanceSensor.h ...
galleries/2013-11-14-explorer-wall-avoider-kit/alternative_demo/DistanceSensor.h:3:1: error: Code 'classSR04{' is invalid C code. [syntaxError]
class SR04 {
^
5/8 files checked 62% done
Checking galleries/2013-11-14-explorer-wall-avoider-kit/alternative_demo/Motors.h ...
galleries/2013-11-14-explorer-wall-avoider-kit/alternative_demo/Motors.h:3:1: error: Code 'classMotor{' is invalid C code. [syntaxError]
class Motor {
^
6/8 files checked 69% done
Checking galleries/2013-11-14-explorer-wall-avoider-kit/demo_sketch/DistanceSensor.h ...
galleries/2013-11-14-explorer-wall-avoider-kit/demo_sketch/DistanceSensor.h:3:1: error: Code 'classSR04{' is invalid C code. [syntaxError]
class SR04 {
^
7/8 files checked 81% done
Checking galleries/2013-11-14-explorer-wall-avoider-kit/demo_sketch/TurtleMotors.h ...
galleries/2013-11-14-explorer-wall-avoider-kit/demo_sketch/TurtleMotors.h:3:1: error: Code 'classMotor{' is invalid C code. [syntaxError]
class Motor {
^
8/8 files checked 100% done
⚠️ BASH / shfmt - 1 error
diff .github/scripts/validate-local-build.sh.orig .github/scripts/validate-local-build.sh
--- .github/scripts/validate-local-build.sh.orig
+++ .github/scripts/validate-local-build.sh
@@ -30,9 +30,9 @@
echo ""
echo "=== Step 1: Checking http_serve is running ==="
if ! docker ps --format '{{.Names}}' | grep -q "^${HTTP_SERVE_CONTAINER}$"; then
- echo "ERROR: ${HTTP_SERVE_CONTAINER} is not running."
- echo "Start it with: docker compose --profile manual up -d http_serve"
- exit 1
+ echo "ERROR: ${HTTP_SERVE_CONTAINER} is not running."
+ echo "Start it with: docker compose --profile manual up -d http_serve"
+ exit 1
fi
# ─── Step 2: Quick HTTP smoke check from host ─────────────────────────────────
@@ -39,17 +39,17 @@
echo ""
echo "=== Step 2: HTTP smoke checks (host -> port ${HOST_PORT}) ==="
for path in "/" "/construction_guide.html" "/tags/arduino/"; do
- status=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${HOST_PORT}${path}")
- if [[ "$status" == "200" ]]; then
- echo " OK ${path} -> ${status}"
- else
- echo " FAIL ${path} -> ${status}"
- SMOKE_FAILED=1
- fi
+ status=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${HOST_PORT}${path}")
+ if [[ "$status" == "200" ]]; then
+ echo " OK ${path} -> ${status}"
+ else
+ echo " FAIL ${path} -> ${status}"
+ SMOKE_FAILED=1
+ fi
done
if [[ -n "${SMOKE_FAILED:-}" ]]; then
- echo "ERROR: Smoke checks failed."
- exit 1
+ echo "ERROR: Smoke checks failed."
+ exit 1
fi
# ─── Step 3: Verify AVIF images are generated ────────────────────────────────
@@ -62,8 +62,8 @@
echo " Post body WebP: ${webp_count}"
echo " Thumbnail AVIF: ${thumb_avif}"
if [[ "$avif_count" -eq 0 ]]; then
- echo "ERROR: No AVIF images found in _site/assets/images. Was the build run?"
- exit 1
+ echo "ERROR: No AVIF images found in _site/assets/images. Was the build run?"
+ exit 1
fi
# ─── Step 4: BDD tests ─────────────────────────────────────────────────────
@@ -71,14 +71,14 @@
echo "=== Step 4: BDD tests (via Docker, network: ${DOCKER_NETWORK}) ==="
docker run --rm \
- --network "${DOCKER_NETWORK}" \
- -e BASE_URL="${BASE_URL}" \
- -v "${PROJECT_ROOT}/tests:/app/src/tests" \
- -v "${PROJECT_ROOT}/package.json:/app/src/package.json" \
- -v "${PROJECT_ROOT}/package-lock.json:/app/src/package-lock.json" \
- -v "${PROJECT_ROOT}/cucumber.js:/app/src/cucumber.js" \
- "${TEST_IMAGE}" \
- npm run test:bdd
+ --network "${DOCKER_NETWORK}" \
+ -e BASE_URL="${BASE_URL}" \
+ -v "${PROJECT_ROOT}/tests:/app/src/tests" \
+ -v "${PROJECT_ROOT}/package.json:/app/src/package.json" \
+ -v "${PROJECT_ROOT}/package-lock.json:/app/src/package-lock.json" \
+ -v "${PROJECT_ROOT}/cucumber.js:/app/src/cucumber.js" \
+ "${TEST_IMAGE}" \
+ npm run test:bdd
echo ""
echo "=== Validation complete ==="
⚠️ ACTION / zizmor - 1 error
INFO zizmor: 🌈 zizmor v1.25.0
WARN audit:audit{input=Workflow(file://.github/workflows/on_call_build_site.yaml)}: zizmor::audit::unpinned_uses: failed to look up commit for docker/setup-buildx-action@v4.3.0: couldn't list branches for docker/setup-buildx-action
fatal: no audit was performed
'artipacked' audit failed on file://.github/workflows/on_call_build_site.yaml
Caused by:
0: error in 'artipacked' audit
1: couldn't list tags for actions/checkout
2: request error while accessing GitHub API
3: HTTP status client error (401 Unauthorized) for url (https://github.com/actions/checkout.git/git-upload-pack)
[ACTION_ZIZMOR_ERROR_GITHUB_API_UNREACHABLE] Zizmor could not access a repository referenced by a `uses:` clause via the GitHub API (missing token, insufficient scope, or cross-repo private access).
To allow zizmor to authenticate with GITHUB_TOKEN (or a PAT with `Contents: read-only`), whitelist the variable in your .mega-linter.yml:
ACTION_ZIZMOR_UNSECURED_ENV_VARIABLES:
- GITHUB_TOKEN
If the referenced workflow is in a private repo outside the current one, provide a PAT with cross-repo access instead of the default GITHUB_TOKEN, or run zizmor in offline mode.
Notices
REPOSITORY_KICS. See Removed linters to find their replacements.
See detailed reports in MegaLinter artifacts
You could have the same capabilities but better runtime performances if you use a MegaLinter flavor:
- oxsecurity/megalinter/flavors/dotnetweb@v10.1.0 (81 linters)
Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining FLAVOR_SUGGESTIONS: false)
- Documentation: Custom Flavors
- Command:
npx mega-linter-runner@10.1.0 --custom-flavor-setup --custom-flavor-linters ACTION_ACTIONLINT,ACTION_ZIZMOR,BASH_EXEC,BASH_SHELLCHECK,BASH_SHFMT,C_CPPCHECK,CPP_CPPCHECK,JSON_V8R,JSON_NPM_PACKAGE_JSON_LINT,REPOSITORY_GIT_DIFF,REPOSITORY_BETTERLEAKS,REPOSITORY_GRYPE,REPOSITORY_OSV_SCANNER,REPOSITORY_SECRETLINT,REPOSITORY_SYFT,REPOSITORY_TRIVY_SBOM,REPOSITORY_TRUFFLEHOG,TYPESCRIPT_STANDARD,XML_XMLLINT,YAML_V8R

Show us your support by starring ⭐ the repository
🐳 Docker Base Image AvailableA new base Docker image has been built and pushed for this PR: Image: How to use this image:# Pull the image
docker pull ghcr.io/orionrobots/orionrobots-site.base:499
# Run with the image
docker run -it ghcr.io/orionrobots/orionrobots-site.base:499 bashFor local development:You can use this image as a base for testing changes without rebuilding dependencies. This comment is automatically updated when the base image is rebuilt. |
Fixes CodeQL
actions/missing-workflow-permissionsalerts 1, 2, 3, 4, 5 and 18.permissions: contents: readinon_pr_test.yamlandon_push_to_master_test_and_deploy.yaml.on_call_build_site.yaml/on_call_staging_test.yamlgrantcontents: read, packages: write. A called workflow cannot exceed its caller's grant, which was the cause of the failure that led to reverting Revert "Potential fix for code scanning alert no. 5: Workflow does not contain permissions" #488 (via Retry: Potential fix for code scanning alert no. 5: Workflow does not contain permissions #489).contents: readalongsidepackages: write(a job-level block otherwise dropscontents).Verification:
actionlintclean;on_pr_test.yamlexercises the same caller→callee nesting so this PR's own checks validate it. The push workflow only runs on master, so I'll watch its run after merge.🤖 Generated with Claude Code