Merge gate
Every merge request (or pull request) pipeline that runs the MopokeHQ scan is checked against the branch it targets. MopokeHQ works out what the change adds and fixes, and the merge gate decides: pass, warn or fail.
The gate judges a merge request only on what it adds. Problems already on the target branch are existing work on the Now list, not this change’s fault, so adding MopokeHQ never blocks every merge on day one.
What gets checked
Section titled “What gets checked”The merge request’s SBOM is compared with a base: the SBOM of the commit the merge request branched from, when the target branch was scanned there, or else the latest SBOM of the default branch.
- Advisories it adds: an advisory that affects a package version in the merge request and no version of that package in the base.
- Advisories it fixes: the other way round.
- An upgrade that is still affected by the same advisory is neither.
- New packages: package names the base doesn’t have. A new version of a package you already use is not new.
- New secrets: credentials the secrets scanner finds in the merge request, including in its own commits.
When the target branch has never been scanned there is nothing to compare with: nothing is called new, and the gate warns no_baseline. The next default-branch pipeline sets the baseline.
New package checks
Section titled “New package checks”Each new npm or Packagist package is checked against the public registry while the job waits:
- Unknown package: the registry has never heard of it. Fine for a private package; otherwise a misspelling, or a package an AI assistant made up.
- Lookalike name: one edit away from a popular package (a letter added, dropped, changed or two swapped), or the same once separators and lookalike characters are folded (
crossenvforcross-env,l0dashforlodash). Names that differ only in digits, such assymfony/polyfill-php80and-php81, are not flagged. - Young package: the version was published fewer than 7 days ago.
The checks are bounded so they never hold up a pipeline: up to 60 new packages per scan, 8 seconds in all. Anything not answered in time is marked “not checked” and never fails the gate. Packages from other ecosystems get the advisory comparison but not these checks.
The gate policy
Section titled “The gate policy”The policy is set per organisation under Merge gate policy on the Projects page (Settings, Projects). Owners and admins change it; everyone can read it. Each rule is fail, warn or off.
| Rule | Default | Triggered when the merge request adds |
|---|---|---|
new_malicious |
fail | a package with a known malicious advisory |
new_kev |
fail | an advisory on CISA’s Known Exploited Vulnerabilities list (attackers are using it) |
new_critical |
fail | a critical advisory |
new_secret |
fail | a secret |
new_high |
warn | a high advisory |
new_advisory |
warn | a medium, low or unrated advisory |
unknown_package |
warn | a package the public registry doesn’t have |
typosquat |
warn | a package named like a popular one |
young_package |
warn | a version published in the last 7 days (the number of days is part of the policy) |
no_baseline |
warn | (nothing to compare with on the target branch) |
The result is the worst level any rule reaches. Only your changes from the defaults are stored, so a later improvement to a default reaches you unless you changed that rule. Every policy change and every gate decision is recorded in the evidence log.
Warn or enforce
Section titled “Warn or enforce”By default a failing gate only warns: the job log says the merge request would fail, and nothing breaks. To make it block, two settings must agree:
- The project says Enforce. On the Projects page, set the project’s merge gate to Enforce. Owners, admins and the project’s owners can change it.
- The pipeline consents. Set the CI variable
MOPOKE_GATEtoenforcewhere pipelines should fail.
The CLI then exits with code 3 on a failed gate, and the templates fail the job on exit 3 and nothing else. Enforce is the project’s decision; MOPOKE_GATE is the pipeline’s consent. Switching the project back to Warn stops every pipeline failing at once, without touching CI variables.
To stop merges, make the scan job a required check: in GitLab, Pipelines must succeed; in GitHub, Gitea and Forgejo, a required status check in the branch protection rules.
Where the result shows
Section titled “Where the result shows”| Where | What you see |
|---|---|
| The scan job’s log (every platform) | The gate result and its reasons, after the upload line |
| GitLab merge request | One MopokeHQ comment, edited in place on every push: what the change adds and fixes, new packages with their age and any lookalike match, the gate’s reasons, and a link to the detail in MopokeHQ. Posted by your fix runner within 15 minutes of the pipeline. |
| GitHub pull request | Coming soon with the GitHub App: the same comment, and a MopokeHQ gate check that fails, goes neutral or passes with the gate. |
| MopokeHQ | Settings, Projects: each project’s ten most recently checked merge requests, with the gate, the comment and the review status. |
Code review
Section titled “Code review”On GitLab, projects can also have Lilly review the merge request’s diff: security problems, and quality signals such as tests that assert nothing or mock the thing they test, duplicated helpers, swallowed errors, comments that narrate the code, needless abstraction and plain bugs.
- Off unless the project has it on. Internal projects start with it on; client projects start with it off. A project owner, owner or admin turns it on for a client project after confirming the client’s contract allows code diffs to be sent, and that confirmation is logged.
- The organisation’s AI switch wins. With AI off, no code goes anywhere, whatever the project says.
- Only the diff. The fix runner fetches the diff from GitLab and sends it to MopokeHQ. Files that hold secrets by convention (
.env*, keys,.npmrc,auth.jsonand similar) are dropped, anything that looks like a credential is redacted, and lockfiles, vendored, built and generated files are left out. No repository, project or customer names are sent with it. The diff is deleted once the review is done. - Few, checked comments. At most five comments on changed lines plus a summary, each checked a second time for whether it is correct and worth a reviewer’s time, and none repeating an earlier review of the same merge request.
- Never blocks. Review comments are labelled as quality signals from Lilly and never fail the gate or say who or what wrote the code.
More on what Lilly sees and never does: Lilly.