Technical Guide

    Building a pre-commit hook that flags GPL, LGPL, and MPL-2.0 license matches in AI-written code

    A pre-commit hook for license detection scans only the staged diff, compares added code against a reference corpus at file and snippet level, classifies each match as GPL, LGPL, or MPL-2.0, and returns a non-zero exit code when a finding exceeds your policy threshold. Keep it fast, make exceptions explicit and reviewable, and treat it as an early-feedback control that CI and runtime enforcement back up.

    Hook architecture on the pre-commit framework

    1. Resolve staged hunks, not whole files
    2. Exclude vendored, generated, binary, and lockfile paths
    3. Match each hunk at file and snippet level
    4. Classify by license family and confidence
    5. Apply policy and return an exit code
    6. Cache by content hash to keep repeat runs fast

    Why dependency scanning misses this problem

    Dependency-level scanners read manifests and lock files. They report the licenses of packages you declare. They do not examine a function that an AI coding assistant wrote into your source tree, even if that function closely resembles code published under a copyleft license. The code arrives as ordinary first-party text, with no package record and no license header.

    The commit boundary is the earliest point where a platform team can inspect that text before it enters shared history. A hook at that boundary gives the developer feedback while the change is still local and cheap to rewrite. The design goal is narrow: detect likely copyleft matches in staged changes, explain what the match means, and offer a clear next step. It also has to be quick enough that nobody is tempted to skip it.

    How file-level and snippet-level matching differ

    File-level matching looks for license evidence inside the text: SPDX identifiers, copyright headers, and embedded license notices. It is fast and precise when the evidence is present, but code reproduced by an assistant often arrives without its original header, so absence of a notice proves little.

    Snippet-level matching compares normalized fragments of code against a reference corpus of known licensed code. Normalization usually strips whitespace and comments and may abstract identifiers so that trivial edits do not defeat the comparison. The output is typically a matched license, a reference location, and a similarity or confidence score. Short, idiomatic fragments will match many sources and produce noise, so set a minimum fragment size before a match counts.

    Choose a matching tool by testing it on your own repositories. Evaluate whether it supports snippet-level matching or only file-level detection, what confidence output it gives, how large its reference corpus is, and how long it takes on a representative large diff. Whatever you choose, remember that a match indicates similarity to licensed code. It is not a legal determination.

    Classifying findings by license family

    The hook should report the license family, because the obligations and the right response differ. The summary below is a working classification for engineering triage. Have counsel confirm the final policy against the license texts.

    • GPL (strong copyleft): Distributing a work that incorporates or derives from GPL code generally requires licensing the combined work under the GPL. Default action: block on high-confidence matches and require remediation or legal approval.
    • LGPL (library copyleft): Obligations center on the library itself and on how it is combined with other code, with linking terms that permit use in a larger work under conditions. Copied LGPL source inside first-party files is still a concern. Default action: warn at moderate confidence, block at high confidence in application code.
    • MPL-2.0 (file-level copyleft): Copyleft applies to the covered files and modifications to them, not to the entire program. Default action: warn and route to review, since the remedy often involves isolating or attributing the file.

    Thresholds, allowlists, and exception handling

    Start with two thresholds per license family: a warn threshold and a block threshold on match confidence. Begin conservatively, with block limited to high-confidence GPL matches, and tune using real findings. Record the false-positive rate for each threshold change so tuning stays evidence-based and not anecdotal.

    Allowlists should be narrow and expire. Key each entry to a content hash or a specific path and reference location, not to a whole directory or license name. Require a reason, an approver, and an expiry date. Store the allowlist in the repository so changes go through review, and compare its checksum against an approved value in CI so silent edits are detectable. Checksum comparison is a standard technique for detecting changes to files.

    On AI origin: a local hook usually cannot tell reliably which lines an assistant wrote. If your tooling records assistant use, for example through a commit trailer, you can apply stricter thresholds to those changes. Otherwise apply the same policy to every staged change. Uniform treatment is simpler and avoids a gap where unlabeled AI output escapes review.

    • Set warn and block thresholds per license family
    • Require a minimum fragment size before a match counts
    • Scope allowlist entries by hash or path, with owner and expiry
    • Review allowlist changes through normal code review
    • Apply stricter thresholds to labeled AI-origin changes if available
    • Output the family, confidence, matched location, and remediation steps

    Remediation, reporting, and bypass

    A finding is only useful if the developer knows what to do next. The report should offer three paths: rewrite the code independently, replace it with a dependency whose license is approved, or request an exception with the matched location attached. Escalate GPL blocks and any exception request to a named reviewer, such as an open source program office or legal contact, and keep the decision with the finding.

    Developer bypass is a design constraint, not an edge case. Git allows hooks to be skipped with the --no-verify flag, and hooks are not installed until a developer sets them up. Reduce the incentive by keeping runtime short, giving clear messages, and fixing noisy rules quickly. Then assume bypass will happen and re-run the same scan in CI against the pushed commits, using the same pinned scanner and policy file. A CI failure for a commit that skipped the local hook is the signal that closes the gap.

    • Keep typical runs to a few seconds on ordinary diffs
    • Show the remediation options in the failure message
    • Route GPL blocks and exceptions to a named reviewer
    • Run the identical scan in CI as a backstop
    • Retain findings, overrides, and approvals as records

    Where the local hook stops and runtime enforcement starts

    A pre-commit hook is a local, bypassable control. It sees code only after it has been written and only on machines where it is installed. It gives early feedback, and CI provides the enforceable backstop for what reaches the shared repository. Neither one observes what a coding assistant was permitted to do at the moment it generated the code.

    Trussed addresses that part. It enforces policy in the execution path of coding assistants, with actions that include allow, redact, block, and escalate for human approval, applied to individual interactions and tool calls. Its code provenance records the origin, licence and security context of code. Enforcement generates audit-ready evidence that a regulated enterprise can show to an auditor. Used alongside a commit-time hook and a CI scan, this gives platform teams feedback at the developer's desk, a repository-level gate, and enforcement at runtime.

    Commit-time license check

    Staged diff

    Only added and changed lines are scanned.

    Match

    File-level and snippet-level comparison against a reference corpus.

    Classify

    GPL, LGPL, or MPL-2.0 family with a confidence score.

    Decide

    Block, warn, or pass according to policy and allowlist.

    Add enforcement where AI-written code is generated

    Talk to our team about code provenance and policy enforcement in the execution path of coding assistants, and how a commit-time hook fits into a layered approach.

    Talk to an Expert
    Next step

    How does your AI governance program compare?

    See where your program has gaps in less than 2 minutes.