fix(gates): waive lockfile-exists for a package, which is not an install root

plugins/onedev is the first plugin package to declare a real dependency, and that arms a
check every previous plugin left vacuous. apm treats any directory holding both apm.yml
and apm.lock.yaml as an install root; a package is not one, so there is no green state for
it. Without a package lockfile, lockfile-exists fails outright. With one, it passes and
thereby arms the other nine checks, where drift then demands the dependency's skills be
deployed inside the package and apm lock leaves an apm_modules/ tree behind.

scripts/apm-audit-ci.sh replaces the inline bash -c loop and waives that single check for a
non-root manifest. It fails closed on three axes: the root is never waived; the failing
check must be lockfile-exists and no other, asserted by matching "1 of 1 check(s) failed";
and unrecognised output fails.

Dropping --ci for package directories was the smaller change and is wrong. Verified on apm
0.28.0 against a scratch package whose dependency entry carried no git/path/registry field:
apm audit --ci exits 1 naming it, while plain apm audit exits 0 and says nothing.
Malformed-dependency detection is the reason gates.md gives for auditing packages at all,
and a package with dependencies is the only kind that can carry a malformed dependency
entry.

The waiver matches on apm's stdout, so an apm upgrade rewording either line turns it off.
That fails the push rather than hiding a defect.

Also records the onedev entry in apm.lock.yaml, which PR #136 could not carry because the
plugin was not yet resolvable from the remote's main.

ADR: 0026

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwD8Egs5r4ndqeFLmhusX2
This commit is contained in:
2026-09-20 20:04:33 +00:00
parent 34f2df3547
commit fbd030c7ea
6 changed files with 1200 additions and 1295 deletions

View File

@@ -97,8 +97,8 @@ repos:
- id: apm-audit-ci
name: apm audit --ci
description: Run apm's producer-side CI gate over the root manifest AND each of the six plugin packages. On the root manifest it runs ten checks -- lockfile-exists, ref-consistency, deployment-ledger-owners, deployed-files-present, no-orphaned-packages, skill-subset-consistency, config-consistency, content-integrity, includes-consent, drift -- so it is both a hidden-Unicode scan and a drift gate that replays the install and diffs it. In a plugin package it runs one, lockfile-exists. It does NOT enforce an org policy; see the comment below for why. Reference:plugins/kyberforge/.apm/skills/apm-workflow/references/audit.md
entry: bash -c 'for d in . plugins/*/; do (cd "$d" && apm audit --ci) || { echo "apm audit --ci failed in $d" >&2; exit 1; }; done'
description: Run apm's producer-side CI gate over the root manifest AND each plugin package, via scripts/apm-audit-ci.sh. On the root manifest it runs ten checks -- lockfile-exists, ref-consistency, deployment-ledger-owners, deployed-files-present, no-orphaned-packages, skill-subset-consistency, config-consistency, content-integrity, includes-consent, drift -- so it is both a hidden-Unicode scan and a drift gate that replays the install and diffs it. In a plugin package it runs one, lockfile-exists, which the script waives when that package declares dependencies, because a package is not an install root (ADR-0026). The waiver never applies to the root and never covers a second failing check. It does NOT enforce an org policy; see the comment below for why. Reference:plugins/kyberforge/.apm/skills/apm-workflow/references/audit.md
entry: scripts/apm-audit-ci.sh
language: system
stages: [pre-push]
pass_filenames: false
@@ -121,9 +121,20 @@ repos:
# does not (verified by adding a git dependency to
# plugins/lint/apm.yml). Everything else above is root-only, because
# only the root install has a lockfile, a deployment ledger and
# deployed files to check. Running the six plugin packages is what
# deployed files to check. Running every plugin package is what
# makes lockfile-exists reachable for them at all -- the root-only
# invocation audits the root manifest and nothing else.
# THAT ARMING NOW HAPPENS: plugins/onedev declares a real dependency,
# and there is no green state for it -- without a package lockfile
# lockfile-exists fails, and with one it passes and arms the other
# nine, where drift then demands the dependency's skills be deployed
# INSIDE the package. A package is not an install root, so
# scripts/apm-audit-ci.sh waives that single check for a package and
# nothing else (ADR-0026). Dropping --ci for packages would have been
# smaller and is wrong: verified on apm 0.28.0, plain `apm audit`
# exits 0 on a dependency entry missing its git/path/registry field
# while --ci exits 1 naming it, and malformed-dependency detection is
# the whole reason packages are audited.
# * HIDDEN CONTENT IS COVERED. content-integrity is that scan; it
# reports `No critical hidden Unicode or hash drift detected`. An
# earlier revision of this comment said the hook does NOT scan for