feat: Add blocking license standard asserting the copyright holder
Standard
license (new). Also touches presentation, which hands LICENSE over.
Change type
- Add new standard
- Modify existing standard's check.sh (add, remove, or change an assertion)
- Modify existing standard's templates
What does this MR do and why?
standards/license asserts two things: LICENSE exists at the repository root, and its copyright line names GitLab Inc. It ships blocking, at introduced.
LICENSE is the one file in a repository that is a legal instrument, and until now nothing in the estate read the holder named on it. presentation asserted check_file_exists LICENSE, which a LICENSE naming anyone at all satisfies, and it asserted it at the advisory tier because presentation's subject is house style.
The existence gate and templates/LICENSE move out of presentation in the same MR. Asserting one file in two standards at two tiers gives it two owners and two verdicts.
Failure mode this addresses
A LICENSE naming a party that does not hold the copyright, on a repository under gitlab-com/.
The copyright sweep of 2026-08-11 read every license-shaped file at its default branch across 144 projects in three namespaces and found 47 copyright lines naming someone other than GitLab Inc.: 19 name a private individual, 15 name GitLab Public Sector, 6 name GitLab demonstration, and the rest name GitLab B.V. (the Netherlands employing entity, not the code copyright holder since the 2015 rename) or a bare GitLab.
Two of those classes are not stylistic. A LICENSE naming a private individual on a gitlab-com/ repository asserts personal ownership of GitLab work product. GitLab Public Sector and GitLab demonstration are wordmarks, not incorporated bodies, so a grant from either comes from a party that cannot hold copyright. Fifteen repositories converged on the same non-entity independently, without copying from one another, which is what an unenforced string in a prose table produces. The correct string was already written down in standards/presentation/templates/wordmark.md, enforced by nothing.
This assertion is the estate's own worked example. .gitlab/merge_request_templates/Standard-Change.md has offered, since it was written, as the canonical illustration of an assertion delta:
- REMOVE: file-contains:LICENSE:^Copyright \(c\) Andrew Dunn$Someone imagined this exact assertion, wrote it into the template every future standard change would be modelled on, and never shipped it. The 47 lines accumulated in the interval. This MR ships it.
Assertion deltas
- ADD: file-exists:LICENSE (standards/license, via require_file)
- ADD: file-contains:LICENSE:^Copyright( \(c\)| \(C\)| ©)?( [0-9]{4}(-([0-9]{4}|[Pp]resent))?)? GitLab Inc\.$
- REMOVE: file-exists:LICENSE (standards/presentation)The estate gains one assertion and moves another. presentation goes from 14 to 13.
The regex leaves the copyright marker, the year, and the range form optional on purpose. Copyright (c) 2026 GitLab Inc., Copyright (c) 2011-present GitLab Inc. and the year-less Copyright GitLab Inc. all appear on correct gitlab-org LICENSE files, and none of those differences changes who owns the code. Pinning the year format would specify prose wording rather than a property, which the security-md relaxation earlier in this CHANGELOG established as the punitive shape. What the regex pins is the entity, anchored at both ends so a line naming a different holder cannot satisfy it by containing the right string somewhere else.
Control backing, and why this blocks
Tier follows control backing. compliance/unified.yaml gains one row:
| field | value |
|---|---|
id |
outbound-license |
standard |
license |
family |
Supply chain |
frameworks |
nist_800_53_r5: CM-10, ssdf_v1_1: PS.3.2 |
sectors |
dod, hipaa, finance, education |
enforced_by |
project: reference/standards/license/check.sh |
evidence |
path: LICENSE |
status |
measured |
measured is claimed under the schema's own definition: the enforcer cited under enforced_by exists today and produces the evidence cited under evidence. No framework was added to compliance/registry.yaml; both citations resolve against frameworks already declared there.
Status is introduced, because a new standard always ships at introduced first. Tier and status are separate axes. This is the provenance shape: introduced and blocking.
Scope, and what is left to the platform
The standard asserts existence and holder, and nothing below the copyright line. GitLab already detects the license type natively, reads the body against a license database, and reports the result on the project overview and through projects/:id?license=true as license.key and license.nickname. Re-deriving that in a regex would be a second, worse implementation of a platform feature. The division is stated in the SKILL.md scope section and named in front matter unasserted:, so it renders on the standard's card.
Also out of scope: whether the body is unmodified license text (a question for counsel), whether MIT was the right choice (a #legal consult, which is a process step and not a repository property), and prose licensing in a second file such as this repository's LICENSE-docs.
Consumer impact
Measured today against this exact regex, across the 58 non-archived projects in gitlab-com/public-sector:
| verdict | count |
|---|---|
| pass | 40 |
| fail on the holder assertion | 11 |
| fail on the presence gate | 7 |
The 11 holder failures: 7 × Copyright (c) 2026 GitLab Public Sector (all under lab/project-trustchain/ and lab/project-lattice/), 2 × GitLab B.V. (stig-analyzer, lab/version-gitlab-com-simulation), 1 × Copyright (c) 2026 Andrew G. Dunn / GitLab (lab/project-lattice/paper), 1 × kaniko (Apache-2.0, no discrete Copyright line).
The 7 presence failures ship no LICENSE at all: bulkhead, manifold-demo, lab/collaboration, lab/sh-clickhouse-iac, lab/implementation-tracker, lab/duo-null, lab/compare-p1-upstream.
Three are expected to register a .reference.yaml deviation instead of being rewritten, because a fork keeps its upstream's LICENSE byte-for-byte: kaniko (Apache-2.0 carries its notice in NOTICE), stig-analyzer, and lab/version-gitlab-com-simulation. A fourth fork, lab/project-trustchain/gitlab-patches, tracks upstream at Copyright (c) 2011-present GitLab Inc. and passes unchanged. Three registered deviations is the price of catching the rest. If that list grows past a handful, the assertion is wrong and belongs back in an MR here.
Remediating the failing projects is out of scope for this MR and does not gate it. The standard is at introduced, adoption_phase governs how strictly a consumer treats a FAIL, and landing the assertion first is what stops the sweep having to be run by hand again.
Cutover schedule
None proposed here. introduced -> enforcing is a separate, later decision with its own MR, target tag, and date, per AGENTS.md.
Test plan
-
just guardpasses:guard: 11 primitives, checked 20 file(s), 0 violation(s) -
PIPELINE_REPO=... just validatepasses,validate-bindingat 32 controls / 20 standards, binding intact -
just checkpasses against this repo:TOTAL: 20 standard(s) passed, 0 failed. This repository's ownLICENSEalready readCopyright (c) 2026 GitLab Inc.and needed no change. -
just shipgreen end to end (guard, validate, check-self, build, agent) -
just syncrun; the## Verifyblock is generated, not hand-written - Verified able to fail, not only able to pass. Ran
check.shagainst six real consumer trees fetched from their default branches:lab/project-lattice/paper,stig-analyzerandkanikofail the holder assertion,bulkheadfails the presence gate,lab/project-trustchain/metaandtachpass. - Template moved, not copied:
standards/presentation/templates/LICENSEis nowstandards/license/templates/LICENSE, and the one link to it is updated.
Reviewer checklist
- SKILL.md front matter is valid YAML (asserted by
validate-registry) -
check.shsources../../_lib.shand callsreport - Only closed-set primitives used (
require_file,check_file_contains). No primitive extension. -
templates/present,## Templateheading present - Standard appears in the README contracts table and in
standards/registry.yaml(Mandatory group) - Standard renders in the built site and the agent surface (
site/dist/standards/license/{index.md,check.sh,templates})
References
Motivating research: the copyright mis-attribution sweep of 2026-08-11, 144 projects across three namespaces, remote-verified at each project's default branch. Operator approved this addition on 2026-08-11.