Skip to content

ci(workflow-linter): look for SPDX in the leading comment block - #168

Merged
hyperpolymath merged 6 commits into
mainfrom
ci/spdx-header-check
Nov 5, 2026
Merged

hyperpolymath merged 6 commits into
mainfrom
ci/spdx-header-check

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

What was wrong

lint-workflows fails on main with ERROR: .github/workflows/<file>.yml missing SPDX header for all 38 workflows. The SPDX check reads only line 1. Dependabot's actions-lock bumps prepend # This workflow is managed by gh actions-lock. above the existing header, so every SPDX line is now on line 2 or later. Moving it back to the top would only last until the next bump.

Change

workflow-linter.yml: the "Check SPDX headers" step now accepts an SPDX-License-Identifier anywhere in the leading block of comment and blank lines, before the first YAML line. A file whose only SPDX line comes after YAML, or that has none, still fails.

Testing

I ran the step scripts locally against this branch:

  • SPDX check: exit 0.
  • Permissions check: exit 0.
  • Negative test: a file with no SPDX header and a file with SPDX after name: both fail.

Generated by Claude Code

The "Check SPDX headers" step only read line 1 of each workflow. Dependabot's
actions-lock bumps now prepend "# This workflow is managed by gh
actions-lock." above the existing header, so every workflow's SPDX line sits
on line 2 or later and lint-workflows fails on main ("missing SPDX header",
one error per file). Moving the SPDX line back to the top would last only
until the next Dependabot bump.

The check now accepts an SPDX-License-Identifier anywhere in the leading
block of comment and blank lines, before the first YAML line. A file whose
only SPDX line comes after YAML content, or that has none, still fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132Cdz3iwk2QGKv2sUhhsye
@coderabbitai

coderabbitai Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: f0e5e7bb-aaa2-4089-9cfc-7458896d2149
Commits

Reviewing files that changed from the base of the PR and between aee59c7 and c0617e4.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review

No actionable comments were generated in the recent review.

Summary

Summary by CodeRabbit

  • Bug Fixes
    • SPDX header checks now recognize identifiers that appear after leading blank lines or comments, rather than checking only the first line. This makes validation more consistent for files with introductory comments while still stopping the search at the first non-comment, non-blank line.

The workflow’s SPDX header check now searches leading comment lines for an SPDX identifier. It skips blank lines and stops at the first non-comment, non-blank line.

Changes: SPDX Header Check

Layer / File(s) Summary
Scan leading lines for SPDX identifier
.github/workflows/workflow-linter.yml
The check searches leading comment lines for an SPDX identifier, skipping blank lines and stopping at the first non-comment, non-blank line.

Estimated code review effort: 2 (Simple) | ~5 minutes

Change: Bug fix

Merge Risk: Minimal · previous review 4c02e

No actionable merge-blocking risk remains in this change.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title states the main change: the workflow linter's SPDX check now looks for the identifier in the leading comment block. The raw summary and objectives confirm this matches the single changed lin…
Description check Passed The description explains the problem (Dependabot's actions-lock bump prepends a comment, so SPDX headers move off line 1 and lint-workflows fails on all 38 workflows), the change (SPDX accepted anywhe…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title states the main change: the workflow linter's SPDX check now looks for the identifier in the leading comment block. The raw summary and objectives confirm this matches the single changed line in workflow-linter.yml. The title uses the 'ci(workflow-linter)' scope and is specific enough for a teammate scanning history.

Full details: Description check

Explanation

The description explains the problem (Dependabot's actions-lock bump prepends a comment, so SPDX headers move off line 1 and lint-workflows fails on all 38 workflows), the change (SPDX accepted anywhere in the leading comment and blank block), and the local testing. It directly relates to the changeset.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: e6a0e6e5-d40f-428e-9f7c-6622377d2eb1
Commits

Reviewing files that changed from the base of the PR and between e436fd4 and 4c02e81.

Files selected for processing: 1

  • .github/workflows/workflow-linter.yml

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Recent review details

Context from checks skipped due to timeout: 4

  • GitHub Check: CodeRabbit
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (actions)
  • GitHub Check: Analyze (rust)
CI failures not shown inline: 10

GitHub Actions: ClusterFuzzLite PR fuzzing / 0_PR (address).txt: ci(workflow-linter): look for SPDX in the leading comment block

Conclusion: failure

View job details

Current runner version: '2.338.2'
 ##[group]Runner Image Provisioner
 Hosted Compute Agent
 Version: 20261021.618
 Commit: 21505ad2541d5be6135ed84fc33697146cf75b8e
 Build Date:
 Worker ID: {83bbcc50-50c0-436b-b171-dfd89247f0d3}
 Region: westus
 Cloud: Azure
 ##[endgroup]
 ##[group]Operating System
 Ubuntu
 26.04.1
 LTS
 ##[endgroup]
 ##[group]Runner Image
 Image: ubuntu-26.04
 Version: 20261025.179.1
 Included Software: https://github.com/actions/runner-images/blob/ubuntu26/20261025.179/images/ubuntu/Ubuntu2604-Readme.md
 Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu26%2F20261025.179
 ##[endgroup]
 ##[group]GITHUB_TOKEN Permissions
 Contents: read
 Metadata: read
 ##[endgroup]
 Secret source: Actions
 Cache mode: write
 Using locked action versions from the workflow's lockfile
 Prepare workflow directory
 Prepare all required actions
 Getting action download info
 Download action repository 'google/clusterfuzzlite@v1' (SHA:884713a6c30a92e5e8544c39945cd7cb630abcd1)
 Complete job name: PR (address)
 ##[group]Pull down action image 'gcr.io/oss-fuzz-base/clusterfuzzlite-build-fuzzers:v1'
 ##[command]/usr/bin/docker pull gcr.io/oss-fuzz-base/clusterfuzzlite-build-fuzzers:v1
 v1: Pulling from oss-fuzz-base/clusterfuzzlite-build-fuzzers
 950ef7e48fca: Pulling fs layer
 cb9e3373af8a: Pulling fs layer
 69d134c64991: Pulling fs layer
 32b555f26cb4: Pulling fs layer
 b549f31133a9: Pulling fs layer
 4502bdf86b71: Pulling fs layer
 3147f52c9f08: Pulling fs layer
 3ecd4f7f0d9a: Pulling fs layer
 235a783691a7: Pulling fs layer
 394ab25c12f2: Pulling fs layer
 36679f7664a6: Pulling fs layer
 fed57ec86cd8: Pulling fs layer
 6ada203fdd7d: Pulling fs layer
 7b8acf34f499: Pulling fs layer
 d8217a274b75: Pulling fs layer
 6af0045a07ba: Pulling fs layer
 1436536fabd3: Pulling fs layer
 18651fb0283e: Pulling fs layer
 7ee342a497aa: Pulling fs layer
 5d5e23037571: Pulling fs layer
 a5278bcdbb63: Pulling fs layer
 6e467b1013b8: Pulling fs layer
 a4b94f4c448b...

GitHub Actions: ClusterFuzzLite PR fuzzing / PR (address): ci(workflow-linter): look for SPDX in the leading comment block

Conclusion: failure

View job details

##[group]Run google/clusterfuzzlite/actions/build_fuzzers@v1
 with:
   language: rust
   sanitizer: address
   dry-run: false
   bad-build-check: true
   keep-unaffected-fuzz-targets: false
   upload-build: false
 ##[endgroup]
 ##[command]/usr/bin/docker run --name gcrioossfuzzbaseclusterfuzzlitebuildfuzzersv1_94448b --label 6e3df6 --workdir /github/workspace --rm -e "INPUT_LANGUAGE" -e "INPUT_SANITIZER" -e "INPUT_DRY-RUN" -e "INPUT_ALLOWED-BROKEN-TARGETS-PERCENTAGE" -e "INPUT_PROJECT-SRC-PATH" -e "INPUT_BAD-BUILD-CHECK" -e "INPUT_KEEP-UNAFFECTED-FUZZ-TARGETS" -e "INPUT_STORAGE-REPO" -e "INPUT_STORAGE-REPO-BRANCH" -e "INPUT_STORAGE-REPO-BRANCH-COVERAGE" -e "INPUT_UPLOAD-BUILD" -e "INPUT_GITHUB-TOKEN" -e "ALLOWED_BROKEN_TARGETS_PERCENTAGE" -e "BAD_BUILD_CHECK" -e "UPLOAD_BUILD" -e "LANGUAGE" -e "DRY_RUN" -e "SANITIZER" -e "PROJECT_SRC_PATH" -e "GITHUB_TOKEN" -e "GIT_STORE_REPO" -e "GIT_STORE_BRANCH" -e "GIT_STORE_BRANCH_COVERAGE" -e "CFL_PLATFORM" -e "LOW_DISK_SPACE" -e "KEEP_UNAFFECTED_FUZZ_TARGETS" -e "HOME" -e "GITHUB_JOB" -e "GITHUB_REF" -e "GITHUB_SHA" -e "GITHUB_REPOSITORY" -e "GITHUB_REPOSITORY_OWNER" -e "GITHUB_REPOSITORY_OWNER_ID" -e "GITHUB_RUN_ID" -e "GITHUB_RUN_NUMBER" -e "GITHUB_RETENTION_DAYS" -e "GITHUB_RUN_ATTEMPT" -e "GITHUB_ACTOR_ID" -e "GITHUB_ACTOR" -e "GITHUB_WORKFLOW" -e "GITHUB_HEAD_REF" -e "GITHUB_BASE_REF" -e "GITHUB_EVENT_NAME" -e "GITHUB_SERVER_URL" -e "GITHUB_API_URL" -e "GITHUB_GRAPHQL_URL" -e "GITHUB_REF_NAME" -e "GITHUB_REF_PROTECTED" -e "GITHUB_REF_TYPE" -e "GITHUB_WORKFLOW_REF" -e "GITHUB_WORKFLOW_SHA" -e "GITHUB_REPOSITORY_ID" -e "GITHUB_TRIGGERING_ACTOR" -e "GITHUB_WORKSPACE" -e "GITHUB_ACTION" -e "GITHUB_EVENT_PATH" -e "GITHUB_ACTION_REPOSITORY" -e "GITHUB_ACTION_REF" -e "GITHUB_PATH" -e "GITHUB_ENV" -e "GITHUB_STEP_SUMMARY" -e "GITHUB_STATE" -e "GITHUB_OUTPUT" -e "GITHUB_ARTIFACTS" -e "GITHUB_ARTIFACTS_LIST" -e "RUNNER_OS" -e "RUNNER_ARCH" -e "RUNNER_NAME" -e "RUNNER_ENVIRONMENT" -e "RUNNER_TOOL_CACHE" -e "RUNNER_TEMP" -e "RUNN...

GitHub Actions: Dogfood Gate / 1_Validate K9 contracts.txt: ci(workflow-linter): look for SPDX in the leading comment block

Conclusion: failure

View job details

##[group]K9 Configuration Validation
 Scanning . for K9 files (.k9, .k9.ncl)...
 Found 10 K9 file(s)
   Validating: ./config/build.k9.ncl
 ##[error]Missing K9 format marker. A .k9.ncl file needs a magic_number = "K9!" field, a K9! preamble line, or a K9 pedigree schema import/application/merge
   Validating: ./config/rust-fmt.k9.ncl
 ##[error]Missing K9 format marker. A .k9.ncl file needs a magic_number = "K9!" field, a K9! preamble line, or a K9 pedigree schema import/application/merge
 ##[error]Pedigree block missing 'name' field (in pedigree.metadata.name or pedigree.name)
...
   Validating: ./contractiles/self-validating/examples/setup-repo.k9.ncl
   Validating: ./contractiles/self-validating/template-hunt.k9.ncl
   Validating: ./contractiles/self-validating/template-kennel.k9.ncl
   Validating: ./contractiles/self-validating/template-yard.k9.ncl
   Validating: ./setup-dev-env.k9.ncl
 ##[error]Hunt-level K9 file must include a 'signature' or 'signature_required' field
...
 Errors:        4
 Warnings:      0
 Strict mode:   false
 ────────────────────────────────────────
 ##[endgroup]
 ##[error]K9 validation failed with 4 error(s)
 ##[error]Process completed with exit code 1.

GitHub Actions: Dogfood Gate / Validate K9 contracts: ci(workflow-linter): look for SPDX in the leading comment block

Conclusion: failure

View job details

##[group]K9 Configuration Validation
 Scanning . for K9 files (.k9, .k9.ncl)...
 Found 10 K9 file(s)
   Validating: ./config/build.k9.ncl
 ##[error]Missing K9 format marker. A .k9.ncl file needs a magic_number = "K9!" field, a K9! preamble line, or a K9 pedigree schema import/application/merge
   Validating: ./config/rust-fmt.k9.ncl
 ##[error]Missing K9 format marker. A .k9.ncl file needs a magic_number = "K9!" field, a K9! preamble line, or a K9 pedigree schema import/application/merge
 ##[error]Pedigree block missing 'name' field (in pedigree.metadata.name or pedigree.name)
...
   Validating: ./contractiles/self-validating/examples/setup-repo.k9.ncl
   Validating: ./contractiles/self-validating/template-hunt.k9.ncl
   Validating: ./contractiles/self-validating/template-kennel.k9.ncl
   Validating: ./contractiles/self-validating/template-yard.k9.ncl
   Validating: ./setup-dev-env.k9.ncl
 ##[error]Hunt-level K9 file must include a 'signature' or 'signature_required' field
...
 Errors:        4
 Warnings:      0
 Strict mode:   false
 ────────────────────────────────────────
 ##[endgroup]
 ##[error]K9 validation failed with 4 error(s)
 ##[error]Process completed with exit code 1.

GitHub Actions: Dogfood Gate / 2_Empty-linter (invisible characters).txt: ci(workflow-linter): look for SPDX in the leading comment block

Conclusion: failure

View job details

##[group]Run # Inline invisible character detection (from empty-linter's core patterns).
 �[36;1m# Inline invisible character detection (from empty-linter's core patterns).�[0m
 �[36;1m# Checks for: zero-width spaces, zero-width joiners, BOM, soft hyphens,�[0m
 �[36;1m# non-breaking spaces, null bytes, and other invisible Unicode in source files.�[0m
 �[36;1mset +e�[0m
 �[36;1mPATTERNS='(*UTF)[\x00-\x08\x0B\x0C\x0E-\x1F\x{a0}\x{ad}\x{200b}-\x{200f}\x{202a}-\x{202f}\x{2060}\x{2066}-\x{2069}\x{feff}]'�[0m
 �[36;1mfind "$GITHUB_WORKSPACE" \�[0m
 �[36;1m  -not -path '*/.git/*' -not -path '*/node_modules/*' \�[0m
 �[36;1m  -not -path '*/.deno/*' -not -path '*/target/*' \�[0m
 �[36;1m  -not -path '*/_build/*' -not -path '*/deps/*' \�[0m
 �[36;1m  -not -path '*/external_corpora/*' -not -path '*/.lake/*' \�[0m
 �[36;1m  -type f \( -name '*.rs' -o -name '*.ex' -o -name '*.exs' -o -name '*.res' \�[0m
 �[36;1m    -o -name '*.js' -o -name '*.ts' -o -name '*.json' -o -name '*.toml' \�[0m
 �[36;1m    -o -name '*.yml' -o -name '*.yaml' -o -name '*.md' -o -name '*.adoc' \�[0m
 �[36;1m    -o -name '*.idr' -o -name '*.zig' -o -name '*.v' -o -name '*.jl' \�[0m
 �[36;1m    -o -name '*.gleam' -o -name '*.hs' -o -name '*.ml' -o -name '*.sh' \) \�[0m
 �[36;1m  -exec grep -aPrl "$PATTERNS" {} \; > /tmp/empty-lint-results.txt 2>/dev/null�[0m
 �[36;1mEL_EXIT=$?�[0m
 �[36;1mset -e�[0m
 �[36;1m�[0m
 �[36;1mFINDINGS=$(wc -l < /tmp/empty-lint-results.txt 2>/dev/null || echo 0)�[0m
 �[36;1mecho "findings=$FINDINGS" >> "$GITHUB_OUTPUT"�[0m
 �[36;1mecho "exit_code=$EL_EXIT" >> "$GITHUB_OUTPUT"�[0m
 �[36;1mecho "ready=true" >> "$GITHUB_OUTPUT"�[0m
 �[36;1m�[0m
 �[36;1m# Blocking subset: C0 controls and NUL only (owner ruling 2026-08-28).�[0m
 �[36;1m# Invisible Unicode (NBSP/BOM/zero-width) stays ADVISORY - about 2,100�[0m
 �[36;1m# estate files carry it as legitimate typography in prose.�[0m
 �[36;1mblocking=0�[0m
 �[36;1mwhile IFS= read -r bf; do�[0m
 �[36;1m  [ -z "$bf" ] && continue�[0m
 �[36...

GitHub Actions: Dogfood Gate / Empty-linter (invisible characters): ci(workflow-linter): look for SPDX in the leading comment block

Conclusion: failure

View job details

##[group]Run # Inline invisible character detection (from empty-linter's core patterns).
 �[36;1m# Inline invisible character detection (from empty-linter's core patterns).�[0m
 �[36;1m# Checks for: zero-width spaces, zero-width joiners, BOM, soft hyphens,�[0m
 �[36;1m# non-breaking spaces, null bytes, and other invisible Unicode in source files.�[0m
 �[36;1mset +e�[0m
 �[36;1mPATTERNS='(*UTF)[\x00-\x08\x0B\x0C\x0E-\x1F\x{a0}\x{ad}\x{200b}-\x{200f}\x{202a}-\x{202f}\x{2060}\x{2066}-\x{2069}\x{feff}]'�[0m
 �[36;1mfind "$GITHUB_WORKSPACE" \�[0m
 �[36;1m  -not -path '*/.git/*' -not -path '*/node_modules/*' \�[0m
 �[36;1m  -not -path '*/.deno/*' -not -path '*/target/*' \�[0m
 �[36;1m  -not -path '*/_build/*' -not -path '*/deps/*' \�[0m
 �[36;1m  -not -path '*/external_corpora/*' -not -path '*/.lake/*' \�[0m
 �[36;1m  -type f \( -name '*.rs' -o -name '*.ex' -o -name '*.exs' -o -name '*.res' \�[0m
 �[36;1m    -o -name '*.js' -o -name '*.ts' -o -name '*.json' -o -name '*.toml' \�[0m
 �[36;1m    -o -name '*.yml' -o -name '*.yaml' -o -name '*.md' -o -name '*.adoc' \�[0m
 �[36;1m    -o -name '*.idr' -o -name '*.zig' -o -name '*.v' -o -name '*.jl' \�[0m
 �[36;1m    -o -name '*.gleam' -o -name '*.hs' -o -name '*.ml' -o -name '*.sh' \) \�[0m
 �[36;1m  -exec grep -aPrl "$PATTERNS" {} \; > /tmp/empty-lint-results.txt 2>/dev/null�[0m
 �[36;1mEL_EXIT=$?�[0m
 �[36;1mset -e�[0m
 �[36;1m�[0m
 �[36;1mFINDINGS=$(wc -l < /tmp/empty-lint-results.txt 2>/dev/null || echo 0)�[0m
 �[36;1mecho "findings=$FINDINGS" >> "$GITHUB_OUTPUT"�[0m
 �[36;1mecho "exit_code=$EL_EXIT" >> "$GITHUB_OUTPUT"�[0m
 �[36;1mecho "ready=true" >> "$GITHUB_OUTPUT"�[0m
 �[36;1m�[0m
 �[36;1m# Blocking subset: C0 controls and NUL only (owner ruling 2026-08-28).�[0m
 �[36;1m# Invisible Unicode (NBSP/BOM/zero-width) stays ADVISORY - about 2,100�[0m
 �[36;1m# estate files carry it as legitimate typography in prose.�[0m
 �[36;1mblocking=0�[0m
 �[36;1mwhile IFS= read -r bf; do�[0m
 �[36;1m  [ -z "$bf" ] && continue�[0m
 �[36...

GitHub Actions: Dogfood Gate / 4_Validate eclexiaiser manifest.txt: ci(workflow-linter): look for SPDX in the leading comment block

Conclusion: failure

View job details

##[group]Run if [ ! -f "eclexiaiser.toml" ]; then
 �[36;1mif [ ! -f "eclexiaiser.toml" ]; then�[0m
 �[36;1m  # Check if repo has a Containerfile — if so, recommend eclexiaiser�[0m
 �[36;1m  if [ -f "Containerfile" ]; then�[0m
 �[36;1m    echo "::warning::Containerfile present but no eclexiaiser.toml. Run \`eclexiaiser init\` to scaffold energy/carbon budgets."�[0m
 �[36;1m  fi�[0m
 �[36;1m  echo "has_manifest=false" >> "$GITHUB_OUTPUT"�[0m
 �[36;1m  exit 0�[0m
 �[36;1mfi�[0m
 �[36;1m�[0m
 �[36;1mecho "has_manifest=true" >> "$GITHUB_OUTPUT"�[0m
 �[36;1m�[0m
 �[36;1m# Validate TOML structure using Python 3.11+ tomllib�[0m
 �[36;1mpython3 -c "�[0m
 �[36;1mimport tomllib, sys�[0m
 �[36;1mwith open('eclexiaiser.toml', 'rb') as f:�[0m
 �[36;1m    data = tomllib.load(f)�[0m
 �[36;1mproject = data.get('project', {})�[0m
 �[36;1mif not project.get('name', '').strip():�[0m
 �[36;1m    print('ERROR: project.name is required', file=sys.stderr)�[0m
 �[36;1m    sys.exit(1)�[0m
 �[36;1mfunctions = data.get('functions', [])�[0m
 �[36;1mif not functions:�[0m
 �[36;1m    print('ERROR: at least one [[functions]] entry is required', file=sys.stderr)�[0m
 �[36;1m    sys.exit(1)�[0m
 �[36;1mfor fn in functions:�[0m
 �[36;1m    if not fn.get('name', '').strip():�[0m
 �[36;1m        print('ERROR: function name cannot be empty', file=sys.stderr)�[0m
 �[36;1m        sys.exit(1)�[0m
 �[36;1m    if not fn.get('source', '').strip():�[0m
 �[36;1m        print(f'ERROR: function {fn[\"name\"]} has no source path', file=sys.stderr)�[0m
 �[36;1m        sys.exit(1)�[0m
 �[36;1mprint(f'Valid: {project[\"name\"]} ({len(functions)} function(s))')�[0m
 �[36;1m" || {�[0m
 �[36;1m  echo "::error file=eclexiaiser.toml::Invalid eclexiaiser.toml — see step output for details"�[0m

GitHub Actions: Dogfood Gate / Validate eclexiaiser manifest: ci(workflow-linter): look for SPDX in the leading comment block

Conclusion: failure

View job details

##[group]Run if [ ! -f "eclexiaiser.toml" ]; then
 �[36;1mif [ ! -f "eclexiaiser.toml" ]; then�[0m
 �[36;1m  # Check if repo has a Containerfile — if so, recommend eclexiaiser�[0m
 �[36;1m  if [ -f "Containerfile" ]; then�[0m
 �[36;1m    echo "::warning::Containerfile present but no eclexiaiser.toml. Run \`eclexiaiser init\` to scaffold energy/carbon budgets."�[0m
 �[36;1m  fi�[0m
 �[36;1m  echo "has_manifest=false" >> "$GITHUB_OUTPUT"�[0m
 �[36;1m  exit 0�[0m
 �[36;1mfi�[0m
 �[36;1m�[0m
 �[36;1mecho "has_manifest=true" >> "$GITHUB_OUTPUT"�[0m
 �[36;1m�[0m
 �[36;1m# Validate TOML structure using Python 3.11+ tomllib�[0m
 �[36;1mpython3 -c "�[0m
 �[36;1mimport tomllib, sys�[0m
 �[36;1mwith open('eclexiaiser.toml', 'rb') as f:�[0m
 �[36;1m    data = tomllib.load(f)�[0m
 �[36;1mproject = data.get('project', {})�[0m
 �[36;1mif not project.get('name', '').strip():�[0m
 �[36;1m    print('ERROR: project.name is required', file=sys.stderr)�[0m
 �[36;1m    sys.exit(1)�[0m
 �[36;1mfunctions = data.get('functions', [])�[0m
 �[36;1mif not functions:�[0m
 �[36;1m    print('ERROR: at least one [[functions]] entry is required', file=sys.stderr)�[0m
 �[36;1m    sys.exit(1)�[0m
 �[36;1mfor fn in functions:�[0m
 �[36;1m    if not fn.get('name', '').strip():�[0m
 �[36;1m        print('ERROR: function name cannot be empty', file=sys.stderr)�[0m
 �[36;1m        sys.exit(1)�[0m
 �[36;1m    if not fn.get('source', '').strip():�[0m
 �[36;1m        print(f'ERROR: function {fn[\"name\"]} has no source path', file=sys.stderr)�[0m
 �[36;1m        sys.exit(1)�[0m
 �[36;1mprint(f'Valid: {project[\"name\"]} ({len(functions)} function(s))')�[0m
 �[36;1m" || {�[0m
 �[36;1m  echo "::error file=eclexiaiser.toml::Invalid eclexiaiser.toml — see step output for details"�[0m

GitHub Actions: Dogfood Gate / 5_Groove manifest check.txt: ci(workflow-linter): look for SPDX in the leading comment block

Conclusion: failure

View job details

##[group]Run # Check for static or dynamic Groove endpoints
 �[36;1m# Check for static or dynamic Groove endpoints�[0m
 �[36;1mHAS_MANIFEST="false"�[0m
 �[36;1mHAS_GROOVE_CODE="false"�[0m
 �[36;1m�[0m
 �[36;1mif [ -f ".well-known/groove/manifest.json" ]; then�[0m
 �[36;1m  HAS_MANIFEST="true"�[0m
 �[36;1m  # Validate the manifest JSON�[0m
 �[36;1m  if ! jq empty .well-known/groove/manifest.json 2>/dev/null; then�[0m
 �[36;1m    echo "::error file=.well-known/groove/manifest.json::Invalid JSON in Groove manifest"�[0m

GitHub Actions: Dogfood Gate / Groove manifest check: ci(workflow-linter): look for SPDX in the leading comment block

Conclusion: failure

View job details

##[group]Run # Check for static or dynamic Groove endpoints
 �[36;1m# Check for static or dynamic Groove endpoints�[0m
 �[36;1mHAS_MANIFEST="false"�[0m
 �[36;1mHAS_GROOVE_CODE="false"�[0m
 �[36;1m�[0m
 �[36;1mif [ -f ".well-known/groove/manifest.json" ]; then�[0m
 �[36;1m  HAS_MANIFEST="true"�[0m
 �[36;1m  # Validate the manifest JSON�[0m
 �[36;1m  if ! jq empty .well-known/groove/manifest.json 2>/dev/null; then�[0m
 �[36;1m    echo "::error file=.well-known/groove/manifest.json::Invalid JSON in Groove manifest"�[0m
Additional comments: 1

.github/workflows/workflow-linter.yml: 1

30-30: LGTM!

@linear-code
linear-code Bot marked this pull request as ready for review November 4, 2026 23:51
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-05T01:23:04.848640Z 0d5dbbb New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

The Dogfood Gate's "Validate K9 contracts" job (k9-ecosystem/validate-action)
fails on main with four errors:

- config/build.k9.ncl, config/rust-fmt.k9.ncl: "Missing K9 format marker".
  The K9! preamble sat on line 2, under the SPDX comment; the validator
  requires it as the first non-empty line, which is how the contractiles
  templates lay it out. K9! now comes first, SPDX second.
- config/rust-fmt.k9.ncl: "Pedigree block missing 'name' field". Both config
  contracts now carry a pedigree name.
- setup-dev-env.k9.ncl: "Hunt-level K9 file must include a 'signature' or
  'signature_required' field". It is a Hunt component (it runs installers
  and shell commands), so its pedigree now declares signature_required =
  true, as contractiles/self-validating/template-hunt.k9.ncl does.

The validator now reports 10 files scanned, 0 errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132Cdz3iwk2QGKv2sUhhsye
(cherry picked from commit a94f3ea)
… build

ClusterFuzzLite fails in build_fuzzers on every PR, for three reasons:

- It runs `docker build -f .clusterfuzzlite/Dockerfile`, but the directory
  only had a Containerfile. Add a Dockerfile that mirrors it (same pinned
  base-builder-rust digest). The Containerfile stays for podman-first
  local builds.
- build.sh copied targets from ./target/..., but cargo-fuzz writes them
  to ./fuzz/target/x86_64-unknown-linux-gnu/release/. The copy failed with
  "cannot stat".
- Once built, fuzz_parser reported a leak on its first input (a single
  newline). The leak comes from nickel-lang-parser, which allocates AST
  nodes in a bumpalo arena that never runs destructors, so strings in
  those nodes always leak. Add fuzz_parser.options turning off leak
  detection for libFuzzer and ASan, and have build.sh copy each target's
  .options file to $OUT. ASan still reports memory-safety errors.

Verified locally with the same base image:
- The compile finishes and $OUT contains fuzz_parser.
- A 90-second fuzz run (615 executions) produced no crashes.
- With both leak switches off, the run exits 0 with no artifacts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132Cdz3iwk2QGKv2sUhhsye
(cherry picked from commit 3f5120d)
SonarCloud failed this PR on a D security rating for new code:
- Dockerfile:10 "Copying recursively might inadvertently add sensitive
  data to the container." `COPY . $SRC/bunsenite` sent the whole
  checkout, .git included, into the build image.
- build.sh:13 "Use '[[' instead of '['".

The image now copies only what the fuzz build reads:
- Cargo.toml and Cargo.lock
- src/
- benches/ (declared as [[bench]] targets)
- crates/ (the patched nickel-lang-vector)
- fuzz/
- .clusterfuzzlite/ (build.sh reads the per-target .options from there)

The Containerfile gets the same change, to stay in sync. Nothing in
these paths uses include_str!/include_bytes! on files outside them, and
`cargo metadata` resolves both manifests from that subset.

The "runs as root" warning stays as it is: the OSS-Fuzz base-builder
image needs root.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0132Cdz3iwk2QGKv2sUhhsye
(cherry picked from commit bb33a7e)

Copy link
Copy Markdown
Owner Author

Two checks fail here for reasons unrelated to this PR, and both also fail on main:

  • Validate K9 contracts. #169 fixes it. I've ported its commit as 122982c, and the K9 validator passes locally on this tree.
  • ClusterFuzzLite PR (address). #170 fixes it, and its fuzz job is green. I've ported its two commits as fbe5a56 and 0d5dbbb.

Git will drop the duplicate changes whichever PR merges first.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

SonarCloud (B security rating). The cause is a single hotspot that arrived with the ported ClusterFuzzLite commits: .clusterfuzzlite/Dockerfile:8, "might run with root". It is the same item already explained on #170. The OSS-Fuzz base-builder-rust image compiles into $OUT as root, so adding a USER line would break the fuzz build. The hotspot needs a maintainer to mark it "Safe" in SonarCloud. Once it is marked on #170, the same hotspot here and on #169 should clear too.


Generated by Claude Code

hyperpolymath added a commit that referenced this pull request Nov 5, 2026
… build (#170)

## Summary

**ClusterFuzzLite PR fuzzing / PR (address)** fails on every PR,
including [#168](#168).
This PR fixes the three causes, in the order they surface.

## Changes

- **`.clusterfuzzlite/Dockerfile` (new).** `build_fuzzers` runs `docker
build -f .clusterfuzzlite/Dockerfile`, but the directory only had a
`Containerfile`.
- The new file mirrors the Containerfile, using the same pinned
`base-builder-rust` digest. This is the estate convention betlang and
jtv-lang already follow.
  - The Containerfile stays for podman-first local builds.
- **`.clusterfuzzlite/build.sh`.**
- Copies the targets from
`./fuzz/target/x86_64-unknown-linux-gnu/release/`, where cargo-fuzz
writes them. The old path `./target/...` failed with `cannot stat`.
  - Also copies each target's `.options` file to `$OUT`.
- **`.clusterfuzzlite/fuzz_parser.options` (new).** Turns off leak
detection for libFuzzer and ASan.
- Once built, `fuzz_parser` reported a leak on its first input, a single
newline.
- The leak comes from `nickel-lang-parser` 0.4.0. It allocates AST nodes
in a `bumpalo` arena, which never runs destructors (see the `AstAlloc`
docs in `src/ast/alloc.rs`), so strings in parsed literals always leak.
- Without this file, every fuzz run would report that upstream leak as a
crash. AddressSanitizer still reports memory-safety errors.

## Testing

I ran the compile locally in the same base image with
`FUZZING_LANGUAGE=rust` and `SANITIZER=address`:

- The build finished and `$OUT` contained `fuzz_parser`.
- A 90-second fuzz run (615 executions, about 13.4k coverage edges)
produced no crashes.
- With both leak switches off, the run exited 0 and wrote no artifacts.
- `bash -n build.sh` passes, and the options file parses as INI.

One thing to watch: the PR job has a 15-minute timeout. Locally the
compile took about 6 minutes and the run step fuzzes for 300 seconds, so
the margin is small.

---
_Generated by [Claude
Code](https://claude.ai/code/session_0132Cdz3iwk2QGKv2sUhhsye)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
@hyperpolymath
hyperpolymath enabled auto-merge (squash) November 5, 2026 15:58
@sonarqubecloud

sonarqubecloud Bot commented Nov 5, 2026

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath merged commit d93324a into main Nov 5, 2026
16 checks passed
@hyperpolymath
hyperpolymath deleted the ci/spdx-header-check branch November 5, 2026 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants