Skip to content

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.

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.

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 (crossenv for cross-env, l0dash for lodash). Names that differ only in digits, such as symfony/polyfill-php80 and -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 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.

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:

  1. 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.
  2. The pipeline consents. Set the CI variable MOPOKE_GATE to enforce where 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 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.

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.json and 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.