Skip to content

feat(policy): add custom_checks for arbitrary subprocess validation in apm-policy.yml #519

@danielmeppiel

Description

@danielmeppiel

Why

APM's policy system (apm-policy.yml) enforces governance over dependencies, MCP servers, compilation targets, and manifest fields. But enterprise teams need to enforce rules beyond what APM natively checks — readiness thresholds, quality evaluation, license compliance, custom org validators.

Today there is no extension point. The check list is hardcoded in run_policy_checks(). Adding a custom_checks section lets governance teams plug in any tool via subprocess commands, keeping APM tool-agnostic (like npm never hardcodes ESLint).

What

A new custom_checks field in apm-policy.yml that defines arbitrary subprocess commands. Each runs during apm audit --ci --policy, returns pass/fail via exit code, and integrates into the existing JSON/SARIF audit output.

Policy YAML format

name: contoso-org-policy
version: "1.0.0"
enforcement: block

custom_checks:
  - name: agentrc-readiness
    description: "Repo must meet AI readiness level 3"
    command: "agentrc readiness --json --fail-level 3"
    timeout: 60
    on_failure: warn

  - name: license-check
    description: "All dependencies must have OSS licenses"
    command: "./scripts/check-licenses.sh"
    timeout: 30
    on_failure: block

Execution model

During apm audit --ci --policy org:

  1. Baseline checks run (lockfile, integrity, Unicode) — unchanged
  2. Policy checks run (allowlist, denylist, required) — unchanged
  3. Custom checks run — NEW: for each entry, run command as subprocess with timeout. Exit 0 = pass, non-zero = fail. Results appear alongside built-in checks in JSON/SARIF.

Result format

Uses existing CheckResult model — no new output format:

{
  "name": "custom:agentrc-readiness",
  "passed": false,
  "message": "Repo must meet AI readiness level 3",
  "details": ["exit code 1: achieved level 2, required 3"]
}

How

~150 lines across 4 files:

  • schema.pyCustomCheck dataclass + field on ApmPolicy
  • parser.py — parse custom_checks from YAML
  • policy_checks.py_run_custom_checks() with subprocess + CheckResult
  • Tests

Design principles

  • APM stays tool-agnostic — any command works (agentrc, scripts, scanners)
  • No library coupling — subprocess execution across language boundaries
  • Inherits enforcementon_failure defaults to top-level enforcement
  • Safe — timeout prevents hangs; missing commands handled gracefully

Use cases

Check Command Value
AI readiness agentrc readiness --json --fail-level 3 Gate on maturity
License compliance ./scripts/check-licenses.sh Legal requirements
Secret scanning gitleaks detect --no-banner -q Security hygiene
Doc coverage test -f README.md Documentation standards

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/audit-policyapm-policy.yml schema, custom_checks, install-time enforcement.area/docs-sitedocs/src/content (Starlight), README, doc generation.area/enterpriseAir-gapped/GHE configurability, registry proxy, rulesets, adoption playbook.enhancementDeprecated: use type/feature. Kept for issue history; will be removed in milestone 0.10.0.status/needs-designDirection approved, design discussion required before code.status/triagedInitial agentic triage complete; pending maintainer ratification (silence = approval).theme/governanceGoverned by policy. apm-policy, audit, enforcement, enterprise rollout.type/featureNew capability, new flag, new primitive.

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions