Enforcing a no-copyleft policy on Claude Code in CI pipelines
Treat the policy as a layered control. Write it as version-controlled policy-as-code that names the licences it covers and how unknown licences are handled. Enforce it where Claude Code generates code and again at the CI merge gate. Retain a record of each decision: policy version, outcome, code origin and licence context, and the approver for any exception. No single check is enough, because dependency scanners see declared dependencies and not where generated code came from.
Evidence to retain for each decision
- Policy identifier and version in force at the time of the decision
- Decision outcome: allow, redact, block, or escalate
- Code origin and licence context used to reach the decision
- The change, commit or pull request the decision applied to
- Approver identity, scope, reason and expiry for any exception
- Claude Code version and pipeline role under which the change was produced
Define the policy in enforceable terms
A policy that says "no copyleft" cannot be enforced until it is translated into a list and a set of rules. The underlying distinction is simple. A copyleft licence requires derivative works to carry the same licence, and the GNU General Public License is the canonical example. A permissive licence has no such clause. Some licences also require anyone who releases a modified program to release its source code alongside it.
Beyond that distinction, the scope is a decision for your legal and platform teams. Work through the families one at a time: GPL, LGPL, AGPL, MPL and any others present in your estate. For each, record whether the policy blocks it, escalates it or allows it, and why. Many organisations separate strong copyleft from weak copyleft in this list. Counsel should decide where each family sits, and the reasoning should be written next to the entry so reviewers can see it.
Then specify the cases that cause the most friction. Decide what happens when a licence is unknown, when a snippet matches more than one licence, and when a change touches a file that already carries a copyleft header. The safest default is that unknown or ambiguous status escalates to a human instead of passing silently. Store the result as policy-as-code in version control, so every decision can cite the exact policy version in force.
Where enforcement can sit, and what each point can detect
Each enforcement point sees different information. The table below describes what each can and cannot establish for AI-assisted changes, based on how these tools generally work. Verify the specifics against the tooling you actually run.
- Assistant session (execution path): Can act on each interaction and tool call before code is written or committed, using origin and licence context where available. Cannot see changes made outside the session.
- Pre-commit checks: Catch changes before they leave the developer machine. Depend on local configuration that developers can bypass or skip.
- Dependency scan and SBOM in CI: Read manifests and lockfiles to identify declared dependencies and their licences. Do not show where generated or modified source code originated.
- Snippet matching in CI: Can flag code that resembles known licensed code. Cannot flag code absent from its reference data, and a match shows similarity, not obligation.
- Merge gate with human approval: Enforces the final decision and records approvers. Is only as informed as the evidence the earlier layers pass to it.
Design the CI gate for AI-assisted changes
Start by making AI-assisted changes identifiable. If the pipeline cannot tell which commits or pull requests involved the assistant, it cannot apply a stricter gate to them. Use a consistent marker, such as a commit trailer or a pull request label set by the pipeline, not by the author.
The gate then runs three checks against the policy version in force: declared dependencies and SBOM against the licence list, snippet matching on the changed files, and a check that the assistant-level decision record is present for the change. A missing record is a failure, not a warning.
Failure handling should be explicit. A confirmed match to a blocked licence fails the build and cannot be overridden by the author. An ambiguous or unknown result moves the change to a pending state that needs approval from a named role. Define who holds that role before the gate goes live, following the general practice of assigning roles and granular authorisations to pipeline actors, including who may generate, commit and approve code.
Exceptions should be narrow and recorded. Each one should name the approver, the scope (file, change or dependency), the reason, and an expiry date. An exception without an expiry becomes a standing hole in the policy.
- 1. Identify: Mark AI-assisted changes with a pipeline-set label or trailer.
- 2. Check: Run dependency, SBOM and snippet checks against the current policy version.
- 3. Decide: Pass, fail, or hold for approval when licence status is ambiguous.
- 4. Approve or block: A named role approves exceptions with scope and expiry.
- 5. Record: Write the decision record before the merge completes.
Constrain Claude Code itself in pipelines
Do not treat the assistant's own confirmation prompts as the enforcement boundary, particularly in unattended CI. Public vulnerability records show why. Claude Code versions before 1.0.111 could run project code before the startup trust dialog was accepted if started in an untrusted directory. Before 2.0.72, a command-parsing error allowed the confirmation prompt to be bypassed for commands run through find, when untrusted content was in the context window. For versions from 0.2.54 up to but not including 2.1.163, injected untrusted content could direct WebFetch requests to exfiltrate files, environment variables or command output.
Three practices follow. First, pin the Claude Code version in pipelines and fail the job if it is below the highest fixed version, currently 2.1.163. Second, avoid running the assistant in untrusted directories or with untrusted content in its context, since each of these issues depended on such conditions. Third, limit outbound fetch capability and the secrets visible to the assistant in CI. Give it a defined pipeline role that is allowed to generate code, and keep commit and approval rights with separate roles.
Where runtime enforcement complements CI
CI checks run after code has been written. Enforcement in the assistant's execution path acts earlier, on individual interactions and tool calls, so a blocked licence never reaches the branch. The two layers cover each other's gaps: the session layer supplies origin and licence context that CI scanners lack, and the CI layer catches changes that bypassed the session.
Trussed enforces policy in the execution path for coding assistants. It applies allow, redact, block or escalation for human approval, and it provides code provenance covering the origin, licence and security context of code. Because enforcement is applied at runtime, not reviewed after the fact, each decision produces audit-ready evidence. It can be deployed self-managed in the customer cloud, with configurable retention and data residency. Whatever tooling you choose, the design above holds: one versioned policy, two enforcement points, and a decision record that survives review.
Four layers of a no-copyleft control
Define
Policy-as-code listing covered licences and the rule for unknown status.
Enforce in session
Decisions applied where the assistant generates or modifies code.
Verify in CI
A merge gate for AI-assisted changes with defined failure and exception paths.
Retain evidence
A decision record an auditor or legal reviewer can check.
Apply the policy where code is generated
Talk to our team about enforcing licence policy in the execution path of your coding assistants and producing audit-ready evidence.
Talk to an Expert