A Contractor Code Provenance Checklist for CTOs

The first thing I ask for on a contractor code provenance audit is not the code. It's the metadata: the repository list, the master services agreement with every statement of work attached, and a full git log dump I can parse. Nine times out of ten the metadata tells me where the trouble is before I read a single function.

That's what a contractor code provenance audit is, in one sentence: can this company prove it owns, or has a clear right to use, every line in a repository it paid someone else to write. It's a legal question and an engineering question at the same time, and it never gets answered well by a one-off scan. Here's the five-gate process I've settled on after running these for about six years, and what it looked like on a real engagement last spring.

How a contractor code provenance audit actually starts

Benefits administration SaaS. About 40 people. Let's call them Meridian. Their MVP and first two releases were built by a nine-person dev shop split between Kraków and Lisbon over twenty months: roughly 340,000 lines across 14 repositories, mostly TypeScript and Python with one Go service for payroll integrations.

Meridian had already closed a Series B and was heading into a Series C. Diligence counsel sent over a 60-question IP questionnaire. Question 34 was the one that stalled things: "Identify all third-party code incorporated into the product and the license under which it is used." Nobody at Meridian could answer it. The dev shop had been paid out, and the SOW's IP assignment language said the deliverables were "work product," which sounds reassuring until you check whether it says anything about moral rights, pre-existing materials, or subcontractors.

The chain of custody breaks at the same three places every time: the contract, the editor, and the dependency manifest.

Gate one: authorship from git metadata, not interviews

Interviews are useless here. People misremember what they wrote two years ago, and contractors who've been paid out have no incentive to be careful. Commit metadata is boring and mostly accurate.

git log --format='%ae' --since='2022-01-01' \
  | sort | uniq -c | sort -rn | head -20

On Meridian that returned 11 distinct author emails across 3,900 commits. Three were generic addresses (dev@, build@, noreply@). Two people accounted for 61% of the commits. One email appeared in no HR record and no SOW contact list, and it turned out to be a subcontractor the shop had brought in without telling anyone. That's not a scandal. It's normal. It's also exactly the kind of thing an IP assignment clause needs to cover, and Meridian's didn't.

Run the same command with --format='%cn' and you'll sometimes find committer names that don't match author names, which usually means a repository was imported from somewhere else. git log --diff-filter=A on the oldest files will show you where the initial import came from.

Gate one takes half a day. It's the cheapest half-day in the whole audit.

Gate two: similarity against the web, GitHub, and the repos you already own

This is the gate people think of when they hear "plagiarism check," and it's the one where the tooling choice matters most. MOSS has been the academic default since 1994 and JPlag 5.x is a solid open-source alternative, but both were designed to compare student submissions against each other. MOSS does run a web corpus and indexes some GitHub content, though it's a batch service with no API you can schedule and no report you can hand to a lawyer.

What I needed on Meridian was four corpora in one pass: the 14 repos against each other, each repo against the open web, each repo against GitHub, and the whole set against anything else the client had shipped. I ran it through the source code plagiarism checker in Codequiry because it covers all four and outputs something a non-engineer can read. That last part matters more than it should. A diligence lawyer is not going to parse a MOSS HTML dump at 11pm.

The scan finished in a few hours. The output was about 2,900 flagged file pairs, which sounds terrifying and mostly isn't. The bulk of it was boilerplate: license headers, generated protobuf stubs, and a Vue component library the shop reused on every project.

Codequiry web results tracing copied code to GitHub repositories and other web sources with per-domain scores
Web results: every domain a submission matched, scored per source, from GitHub repos to tutorial sites.

The real findings were 41 files with verbatim matches to Stack Overflow answers, 12 files that matched an open GitHub repository with no attribution, and one Go file that was, charitably, inspired by a repository under AGPL-3.0. Someone had deleted the license header. They had not deleted the license text from the README two directories up. AGPL in a closed-source SaaS product isn't a paperwork problem, it's a distribution obligation, and Meridian's counsel ended up treating it as a real one.

The false positives deserve their own paragraph

About 260 of those flagged pairs came from a vendor SDK directory that the shop had checked in rather than pulled through a package manager. Every project that embeds the same SDK matches every other project that embeds the same SDK. You cannot tune your way out of this. You have to look at the match and make a call.

Codequiry evidence review with a synced diff of two Java files and a list of GitHub and web matches
Evidence review: a synced diff of the matched lines next to every peer, GitHub and web source for the submission.

Nine days of human review followed the automated pass. Roughly 40% of that went to the SDK directory and generated code. I've stopped pretending this step can be eliminated. Any vendor who tells you their tool gives you a clean yes-or-no on a 340,000-line codebase is selling you the demo, not the product.

Gate three: license headers and the files nobody trims

Separate from similarity, you want a license identification pass over every file. ScanCode Toolkit (32.x) is the workhorse here, FOSSology 4.4 is the other one people reach for, and both produce a file-by-file license inventory you can hand to counsel. Commercial SCA tools like Black Duck do this well too if you're already paying for one.

find . -name '*.py' -not -path './venv/*' \
  -not -path './node_modules/*' \
  -exec grep -L "SPDX-License-Identifier" {} + | wc -l

That one-liner tells you how many Python files lack an SPDX identifier. On Meridian it was 1,847 of 2,600. Not because anyone did anything wrong, but because the shop never added them and nobody asked. An SPDX header is a two-line change. The absence of one is what turns a routine diligence question into a six-week legal review, because now counsel has to reason about every file individually instead of trusting a manifest.

A caveat on the tooling. ScanCode is not reliable on minified bundles. I've seen it report 40 distinct licenses for a single webpack output file. Set a size floor and ignore anything under about 200 bytes, or you'll spend a morning reading matches that all say the same thing.

Gate four: AI-generated code is a provenance question, not a cheating question

Everyone frames AI detection as academic integrity. In a commercial audit it's a chain-of-custody issue, and it started showing up in my engagements around 2022.

Here's the problem. A contractor writing code in 2023 or 2024 is almost certainly using Copilot or an LLM assistant. Most MSAs written before 2021 say nothing about it. GitHub's own documentation notes that Copilot can reproduce public code verbatim, and their duplicate detection filter is a mitigation, not a guarantee. So the question isn't "did they cheat." It's "does your IP assignment clause cover output from a tool the contractor never disclosed." On Meridian, roughly 6% of the Python service came back flagged as likely machine-generated, with two files above 90%.

Codequiry AI code detection report with average AI score, highest file score and a risk distribution
AI code detection: probability scores per file, flagging submissions likely written by ChatGPT, Copilot, Claude or Gemini.

Calibration matters more than the raw score. A file with 40 lines of textbook FastAPI routing will score high on any statistical detector, because the correct way to write a FastAPI route looks the same as the way a model writes it. I treat anything under about 70% as noise and anything over 90% as worth reading in full. The interesting band is 75 to 90, and it's also the band where I trust the tools least. We've run a few thousand files through this, and the 85% bucket still includes a lot of perfectly ordinary human code.

I ran the same pass with the AI code detector in Codequiry, mostly because it sits next to the similarity results in the same report. Being able to show a lawyer "here is the copied code, here is the likely AI-generated code, here is the source it resembles" in one view is worth more than any individual number.

Gate five: the clause that decides everything

Every technical finding above is downstream of one paragraph in the MSA. The clause needs to say four things, and most say two:

  1. All work product is assigned to the client, including work by subcontractors the contractor brings in.
  2. The contractor warrants that no deliverable incorporates third-party code except as listed in an attached schedule.
  3. The contractor discloses AI coding assistants in use and assigns any output generated for the engagement.
  4. The contractor indemnifies for the first three.

Meridian's had number one and a vague version of number two. Adding three and four is cheap when you're negotiating the next SOW and expensive when you're doing it under a diligence deadline. I watched a company pay a contractor's lawyer $14,000 to paper over exactly this gap, six weeks before a close.

What it cost, and what Meridian changed

The whole audit came to about $9,400. Roughly $3,600 of that was tooling and compute, the rest was my hours across three weeks. The remediation was cheap. The AGPL file got rewritten. The Stack Overflow snippets were attributed or replaced. An orphan subcontractor signed an assignment, and a junior engineer added 1,847 SPDX headers with a script over a Friday afternoon.

What Meridian changed is more interesting than what they fixed. They added a provenance schedule to the SOW template. They started committing a machine-readable third-party inventory into each repository, regenerated at every release. They put the similarity and AI scan into the CI pipeline, so every merge request gets checked against the open web and against the company's other repositories. That's a short call against the Codequiry solutions API instead of a quarterly fire drill.

Codequiry API keys page with a masked key, signed webhook configuration and API resources
The API surface: an account key, signed webhooks for finished checks, and docs for wiring scans into CI.

And they wrote down a rule I've started recommending to every client: run the audit at the milestone, not at the raise. Doing it while the contractor is still under contract and still has incentive to fix things is a completely different negotiation than doing it after they've been paid out and you're answering question 34 on a diligence questionnaire.

If you're staring at a repository someone else wrote and you can't say where the code came from, start with the code plagiarism checker. Run the metadata pass first. It's cheap, and it usually tells you which of the other four gates you actually need.