Skip to content

Contract syntax

An admission contract is a YAML mapping validated as AdmissionPolicy. It extends the existing SpyModel structural fields with host runtime, dependency, and evidence policy. importspy check plugin.py uses plugin.importspy.yml when it exists; pass --contract policy.yml to select another file.

Unknown fields, unsupported schema versions, duplicate YAML keys, and Python object tags are rejected. Annotation text is never evaluated as Python.

Identity and structure

schema_version: 1
policy_id: payments-plugin
filename: plugin.py
version: "1.2.3"
variables:
  - name: MODE
    annotation: str
    value: production
functions:
  - name: process
    arguments:
      - name: amount
        annotation: int
      - name: currency
        value: EUR
    return_annotation: str
classes:
  - name: Plugin
    attributes:
      - name: kind
        type: class
        value: payments
    methods:
      - name: run
        arguments:
          - name: self
        return_annotation: str
    superclasses:
      - name: BasePlugin
Field Meaning
schema_version Contract schema, currently 1; defaults to 1.
policy_id Optional policy identity recorded in decisions.
filename Expected source basename, such as plugin.py.
version Expected module __version__ literal; unrelated to schema version.
variables Required module declarations, with optional annotation and scalar value.
functions Required function names, parameter names, annotations, and represented defaults.
classes Required classes, class attributes, methods, and lexical base references.

All variable, argument, function, class, and attribute entries require name. Attributes also require type: class or type: instance. Superclasses are mappings with a name, not bare strings.

These are requirement lists: extra declarations and parameters are allowed. Parameter kinds are recorded by inspection, but this schema does not express full signature equivalence or calling convention constraints. Annotations are compared as text, including strings such as list[User] | None; ImportSpy does not perform type checking or resolve annotation identities.

Supported contract values are strings, integers, floats, booleans, and null. Omitting a variable's value imposes no value constraint; setting it to null requires a known None value. Collection or computed values are not evaluated. Class instance attributes and inherited implementations require runtime facts; requesting them during static admission produces an unknown-fact denial.

A base requirement matches its written reference or final dotted name; it does not prove runtime inheritance identity. Decorators, conditional declarations, and explicit dynamic namespace operations can also make structure unknown. See static preflight for the complete boundary.

Host runtime

Host constraints do not execute the target:

runtime:
  python: ">=3.10,<4"
  os: [linux, darwin]
  architecture: [x86_64, arm64, aarch64]
  implementation: [CPython]
  environment:
    APP_MODE: production
    SERVICE_TOKEN: null

python is a PEP 440 version range. The list fields accept exact host identifiers; empty lists impose no restriction. os comes from lowercase platform.system(), architecture from lowercase platform.machine(), and implementation from platform.python_implementation().

Environment values are strings: APP_MODE must equal production. A null requirement checks presence only. Reports record whether the requirement passed, not the environment value. Do not place secret literal values in policy files; use presence checks or a trusted external validation mechanism.

Dependencies and origins

dependencies:
  requests:
    allowed: true
    required: true
    version: ">=2.32,<3"
    declared: true
  legacy-package:
    allowed: false
  internal-payment-sdk:
    origin:
      type: vcs
      repository: https://github.com/acme/payment-sdk
      commit: "0123456789abcdef"
    editable: false
  import:pickle:
    allowed: false
dependency_options:
  unresolved: deny
  undeclared: allow
  unlisted: allow

Distribution keys are normalized package names. import:<name> explicitly addresses a top-level import, including a stdlib import. Multiple namespace contributors are evaluated individually. An import allow rule does not replace a required distribution entry when unlisted: deny is enabled.

allowed defaults to true. required means observed in the source inventory, not merely installed. declared compares observed dependencies with supported project metadata. An allowed dependency is not automatically required.

The options shown above are defaults. They control unresolved imports, undeclared or unknown declarations, and external distributions missing a policy entry. Optional/conditional imports are still evaluated.

Origin fields include type, url, repository, and commit; editable is a separate dependency constraint. Missing metadata stays unknown. Credentials, queries, and fragments are removed from compared/reported origin URLs. These facts are metadata observations, not cryptographic provenance. See the dependency reference for resolution and declaration limits.

Evidence requirements

evidence_requirements:
  - kind: distribution.provenance
    subject: cryptography
    provider: trusted-verifier
    status: verified

Each requirement names an evidence kind and subject. Optional provider restricts the provider identity; status accepts verified (the default) or observed. The evidence must have a truthy observation. A verified observation also satisfies an observed requirement; unknown or unavailable evidence does not.

For an observed dependency, provenance: true or provenance: {required: true} is shorthand for required verified distribution.provenance evidence. It does not make an absent dependency required. No built-in cryptographic verifier is implied; select an appropriate trusted evidence provider.

Legacy deployment alternatives

Existing deployments remain supported alongside the newer runtime section:

deployments:
  - arch: x86_64
    systems:
      - os: linux
        environment:
          secrets: [SERVICE_TOKEN]
        pythons:
          - interpreter: CPython
            modules:
              - filename: plugin.py

arch, systems, os, pythons, and each Python entry's modules are required at their respective levels. A Python entry may also specify an exact, quoted version, such as "3.12.9". Nested module constraints apply to the inspected subject; they do not instruct ImportSpy to import additional modules.

Admission requires one matching legacy deployment/system/Python alternative. Top-level structure and the newer runtime requirements also apply. Prefer runtime.python for a range instead of encoding a partial version as an exact legacy version. Read migration before updating a 0.4 file.