Skip to content

feat(TEA-71): implement automated SPDX header management#36

Merged
Mohamed-Elshesheny merged 3 commits intomainfrom
feat/automate-spdx-license-headers
Apr 16, 2026
Merged

feat(TEA-71): implement automated SPDX header management#36
Mohamed-Elshesheny merged 3 commits intomainfrom
feat/automate-spdx-license-headers

Conversation

@Mohamed-Elshesheny
Copy link
Copy Markdown
Contributor

@Mohamed-Elshesheny Mohamed-Elshesheny commented Apr 16, 2026

SPDX Header Automation

Executive Summary

This change introduces automated SPDX license-header enforcement across the monorepo, with pre-commit auto-remediation and CI verification.

The goal is to eliminate manual header policing during review and make compliance deterministic for all applicable source files.

Problem Statement

SPDX coverage was previously a manual convention documented in CONTRIBUTING.md, which created drift risk:

  • new files could be introduced without headers,
  • reviewer memory determined compliance quality,
  • local formatting hooks did not enforce legal-header policy.

Objectives

  • Automatically add SPDX headers to applicable files before commit.
  • Verify header presence in CI to catch bypassed local hooks.
  • Preserve existing compliant headers without unnecessary rewrites.
  • Exclude generated/non-meaningful targets (e.g. config scripts, binary assets).

Final Scope (Intentionally Narrowed)

SPDX automation applies to source files under:

  • apps/**/src/**/*.{ts,tsx,js,jsx}
  • packages/**/src/**/*.{ts,tsx,js,jsx}

Explicitly excluded:

  • *.mjs, *.cjs
  • config/tooling files (e.g. drizzle.config.ts, ESLint config files)
  • *.d.ts
  • *.gen.ts
  • output/cache/vendor paths (node_modules, dist, .turbo, coverage)

Architecture and Control Flow

Tooling

  • Primary engine: license-check-and-add
  • Canonical SPDX template: .license-header.txt
  • Base formatter config: .license-check-and-add.base.json
  • Wrapper entrypoint: scripts/spdx-license-cli.mjs

Why a Wrapper Exists

The wrapper provides a stable monorepo command interface and enforces project-specific targeting rules:

  • supports full-repo and staged-file modes through one command contract,
  • includes both tracked and untracked files in full checks,
  • enforces repository scope rules consistently,
  • prevents accidental processing of excluded file classes.

Pre-commit Sequence

Configured in lefthook.yml:

  1. spdx-fix (pnpm license:fix:staged {staged_files})
  2. format (pnpm format {staged_files})
  3. spdx-check (pnpm license:check:staged {staged_files})

stage_fixed: true ensures auto-added headers are re-staged automatically.

Key Deliverables

  • Added root scripts in package.json:
    • license:fix
    • license:check
    • license:fix:staged
    • license:check:staged
  • Added CI workflow: .github/workflows/license-header.yml
    • executes pnpm license:check on pull_request and push to main
  • Updated contribution policy in CONTRIBUTING.md to document:
    • automated behavior,
    • enforced scope,
    • exclusions,
    • manual commands.

Verification Evidence

Validated during implementation:

  • pnpm license:check passes.
  • staged mode works for included files.
  • untracked source files are detected in full-repo check mode.
  • excluded mjs and config files are ignored by staged/full commands.
  • no residual SPDX headers remain in excluded mjs/cjs classes.

Performance Characteristics

Measured locally:

  • full check: ~4.7s
  • staged single-file check: ~0.66s

This keeps pre-commit overhead low while preserving enforcement guarantees.

Summary by CodeRabbit

  • New Features

    • CI and pre-commit automation to check and apply SPDX license headers.
    • Developer-facing scripts to add or verify SPDX headers locally.
  • Documentation

    • CONTRIBUTING updated with automated SPDX guidance, applicability rules, and commands.
  • Chores

    • Added license header template and configuration for per-language handling.
    • Added license management tooling dependency and applied headers to source files.

…ense-check workflow

- Introduced a new script for managing SPDX license headers across source files.
- Added configuration files for license checking and formatting.
- Updated CONTRIBUTING.md to reflect automated license management processes.
- Integrated pre-commit hooks for automatic header addition and checks.
- Created a GitHub Actions workflow to verify SPDX headers on push and pull requests.
- Added SPDX headers to relevant source files to ensure compliance.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 16, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e2104947-415d-4249-bf68-8d7e33dd5d7e

📥 Commits

Reviewing files that changed from the base of the PR and between 6974cc7 and 704ca12.

📒 Files selected for processing (1)
  • CONTRIBUTING.md

📝 Walkthrough

Walkthrough

Adds repository-wide SPDX header tooling: a GitHub Actions workflow, pre-commit hooks, a config/template, package scripts, a Node CLI that filters applicable source files and invokes license-check-and-add, and inserted headers into several source files. Documentation updated with applicability and exclusions.

Changes

Cohort / File(s) Summary
GitHub Actions & config
\.github/workflows/license-header.yml, \.license-check-and-add.base.json, \.license-header.txt
New CI workflow "SPDX Header Check" (runs on PR and push to main); base config for license-check-and-add with per-language header styles; two-line SPDX header template (TeamCoderz Ltd, AGPL-3.0-or-later).
Local & CI automation scripts
lefthook.yml, scripts/spdx-license-cli.mjs, package.json
Added lefthook pre-commit jobs to run pnpm license:fix and pnpm license:check on staged TS/JS files (auto-stage fixes). New Node CLI scripts/spdx-license-cli.mjs to resolve targets (git ls-files or args), filter to apps/**/src and packages/**/src JS/TS sources, create temp config/ignore, and run license-check-and-add in add/check mode. Added npm scripts and license-check-and-add devDependency.
Documentation
CONTRIBUTING.md
Reworked SPDX guidance to describe automated pre-commit and CI checks, detailed coverage rules (apps/packages src paths, TS/JS extensions), explicit exclusion rules, and documented pnpm license:fix / pnpm license:check behavior including full-repo mode.
Source file headers
apps/web/src/components/Layout/tabs/useTabMetadata.ts, packages/ui/src/components/hover-card.tsx, apps/backend/src/scripts/run-migrations.mjs
Inserted SPDX header comment blocks at top of files; no functional changes.

Sequence Diagram(s)

sequenceDiagram
    actor Dev as Developer
    participant Git as Git
    participant Hook as Pre-commit Hook
    participant CLI as spdx-license-cli
    participant Tool as license-check-and-add
    participant CI as GitHub Actions

    Dev->>Git: git add (staged files)
    Git->>Hook: trigger pre-commit
    Hook->>CLI: run license:fix {staged_files}
    CLI->>CLI: resolve targets (args or git ls-files) and filter by path/extension/excludes
    CLI->>Tool: run add mode with temp config/ignore
    Tool-->>CLI: modify files / exit status
    CLI->>Git: stage fixed files (if any)
    Hook->>CLI: run license:check {staged_files}
    CLI->>Tool: run check mode
    Tool-->>Hook: report success/failure
    alt commit allowed
        Dev->>Git: commit & push
        Git->>CI: trigger license-header workflow (push/PR)
        CI->>CLI: run pnpm license:check (full-repo)
        CLI->>Tool: verify repository files
        Tool-->>CI: report compliance
    else commit blocked
        Hook-->>Dev: block commit (fix required)
    end
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I scurried through the code tonight,

Leaves of headers tucked in tight,
Pre-commit nudges, CI in view,
AGPL stitched clean and true,
Hop—every file now wears its right!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: implementing automated SPDX header management across the monorepo with pre-commit hooks and CI verification.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/automate-spdx-license-headers

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/backend/src/utils/test.ts`:
- Around line 5-6: The file apps/backend/src/utils/test.ts contains temporary
debug/demo code (the constant x and console.log) that should not be in the
backend source; remove the file or relocate it to a test fixtures folder (e.g.,
tests/fixtures) if it's intentionally required, and delete the lines defining
the constant x and the console.log('x', x) call to keep production code clean.

In `@CONTRIBUTING.md`:
- Around line 87-88: Update the wording for the two npm scripts pnpm license:fix
and pnpm license:check to clarify they operate on both tracked and untracked
applicable files when running full-repo mode; replace the phrase "tracked
applicable files" with "tracked and untracked applicable files (full-repo mode
uses git ls-files --cached --others --exclude-standard)" so contributors
understand untracked files are included.

In `@scripts/spdx-license-cli.mjs`:
- Around line 54-63: The current target filter computes isSourceFile using
SOURCE_ROOTS, "/src/" presence, and hasSupportedExtension(filePath) but doesn't
exclude config/tooling filenames (e.g., drizzle.config.ts), so add an explicit
negative check before returning isSourceFile: detect filenames matching common
config/tooling patterns (for example filePath matching /\.config\.(t|j)sx?$/ or
known tooling names like /^drizzle\.config\./, and other dot-config patterns
such as /\.rc\.(t|j)sx?$/) and return false for those; update the logic around
filePath and isSourceFile so config/tooling files are filtered out even if under
apps/**/src or packages/**/src and have a supported extension.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 62533bc1-e6ca-443e-89f8-629cff086205

📥 Commits

Reviewing files that changed from the base of the PR and between d29dacf and a3bf2c5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • .github/workflows/license-header.yml
  • .license-check-and-add.base.json
  • .license-header.txt
  • CONTRIBUTING.md
  • apps/backend/src/scripts/run-migrations.mjs
  • apps/backend/src/utils/test.ts
  • apps/web/src/components/Layout/tabs/useTabMetadata.ts
  • lefthook.yml
  • package.json
  • packages/ui/src/components/hover-card.tsx
  • scripts/spdx-license-cli.mjs

Comment thread apps/backend/src/utils/test.ts Outdated
Comment thread CONTRIBUTING.md Outdated
Comment thread scripts/spdx-license-cli.mjs
…g config handling

- Modified CONTRIBUTING.md to clarify that license commands now operate on both tracked and untracked files.
- Updated lefthook.yml to remove staged-only flags from license commands for broader application.
- Removed outdated staged license commands from package.json.
- Enhanced spdx-license-cli.mjs to exclude tooling configuration files from license checks.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
CONTRIBUTING.md (1)

70-82: Consider clarifying the config file exclusion patterns.

Line 80 mentions "tool/config files such as drizzle.config.ts" but the implementation excludes several common patterns (based on TOOLING_CONFIG_PATTERNS in context snippet 2):

  • *.config.ts/js/tsx/jsx (e.g., vite.config.ts, tailwind.config.js)
  • *.rc.ts/js/tsx/jsx (e.g., foo.rc.ts)
  • .foorc.ts/js/tsx/jsx (e.g., .eslintrc.ts)

Contributors might be confused if their vite.config.ts or .eslintrc.ts files are skipped without being mentioned.

📝 Suggested clarification
-- `*.mjs`, `*.cjs`, and tool/config files such as `drizzle.config.ts`
+- `*.mjs`, `*.cjs`, and tool/config files (e.g., `drizzle.config.ts`, `*.config.{ts,js,tsx,jsx}`, `*.rc.{ts,js,tsx,jsx}`, `.eslintrc.*`)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CONTRIBUTING.md` around lines 70 - 82, Update the "Coverage and exclusions"
section to explicitly list the config/tooling filename patterns that are skipped
(use the same patterns as TOOLING_CONFIG_PATTERNS): include glob patterns like
*.config.{ts,js,tsx,jsx}, *.rc.{ts,js,tsx,jsx}, and dot-prefixed forms like
.*.rc.{ts,js,tsx,jsx} (examples: vite.config.ts, tailwind.config.js, foo.rc.ts,
.eslintrc.ts) so contributors understand why those files are excluded; keep the
wording concise and add a parenthetical note that these mirror the
TOOLING_CONFIG_PATTERNS used by the automation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@CONTRIBUTING.md`:
- Around line 70-82: Update the "Coverage and exclusions" section to explicitly
list the config/tooling filename patterns that are skipped (use the same
patterns as TOOLING_CONFIG_PATTERNS): include glob patterns like
*.config.{ts,js,tsx,jsx}, *.rc.{ts,js,tsx,jsx}, and dot-prefixed forms like
.*.rc.{ts,js,tsx,jsx} (examples: vite.config.ts, tailwind.config.js, foo.rc.ts,
.eslintrc.ts) so contributors understand why those files are excluded; keep the
wording concise and add a parenthetical note that these mirror the
TOOLING_CONFIG_PATTERNS used by the automation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 331fc463-9cba-4207-bb6c-0338976e5615

📥 Commits

Reviewing files that changed from the base of the PR and between a3bf2c5 and 6974cc7.

📒 Files selected for processing (5)
  • CONTRIBUTING.md
  • apps/backend/src/scripts/run-migrations.mjs
  • lefthook.yml
  • package.json
  • scripts/spdx-license-cli.mjs
✅ Files skipped from review due to trivial changes (3)
  • apps/backend/src/scripts/run-migrations.mjs
  • lefthook.yml
  • scripts/spdx-license-cli.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json

… automation

- Clarified the list of excluded tooling/config filename patterns in CONTRIBUTING.md to enhance understanding of the SPDX automation process.
@Mohamed-Elshesheny Mohamed-Elshesheny merged commit 4b8cda0 into main Apr 16, 2026
2 of 3 checks passed
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.

1 participant