CheeseSec Plugin Handbook

This handbook includes contracts and planned capabilities. Examples do not authorize plugin installation. Capability status remains as described in each page and its acceptance evidence.

CRP Development Handbook (Contract)

This page separates the executable CRP v1 format from future extensions. Do not put planned fields in a v1 package or use them as a current Get Started step until the corresponding parser, tests, and stage evidence exist.

Executable v1 archive layout

CheeseWAF/internal/crp.ParseArchive currently accepts exactly three logical entry types in the ZIP archive:

PathRequirement
manifest.jsonexactly one strict JSON document
artifact/<file>exactly one regular file; artifact.name may constrain its basename
signatures/manifest.jsonexactly one JSON array

The parser rejects unknown entries, provenance/, directories, symlinks, duplicate paths, traversal paths, and entries over the configured size limits. provenance/ is not part of v1. Keep source evidence, SBOMs, or build records as external evidence, or wait for the v2 contract.

v1 manifest fields

The manifest uses crp.cheesewaf.io/v1. The current parser accepts these fields:

FieldRule
api_versionoptional; when present, must be crp.cheesewaf.io/v1
kindoptional; when present, must be CheeseWAFResourcePackage
name, plugin_idat least one is required; producers should keep both consistent
versionrequired SemVer text
namespacemust use a supported form such as official/<plugin> or enterprise/<org>/<plugin>
publisheroptional publisher identifier
sourceoptional for syntax-only parsing; Import requires a registered source
source_rootrequired stable source-root identifier
release_sequencenumeric; an initial package may use 0, but a non-zero installed sequence cannot be replaced by 0
digeststop-level compatibility field, or artifact.digests; if both are present they must match exactly
artifactoptional object; when present, its name, size, and digests are checked; digests may also be top-level
artifact.nameoptional artifact basename constraint
artifact.sizeoptional in standalone validation; required to match the archive file size
artifact.digestslowercase hexadecimal MD5, SHA-1, and SHA-256 values

MD5 and SHA-1 are transport-integrity and resume checks only. SHA-256 is the content identity. Missing or mismatched digests are hard failures and cannot be overridden by an administrator.

signatures/manifest.json contains the current Signature fields: key_id, algorithm, value, source_root, trust_level, release_sequence, manifest_sha256, signed_at, and expires_at. The example carries two verifiable official Ed25519 signatures. A real Import still requires local trust-root, threshold, validity-window, and revocation checks.

See the minimal parseable, non-installable example in examples/crp-v1/.

Namespace and signatures

  • Official: official/<plugin>;
  • Enterprise: enterprise/<org>/<plugin>;
  • Other classes: <class>/<publisher>/<plugin>.

Source roots, signers, and transport sources are verified separately. Official and enterprise packages use at least 2-of-3 for normal releases and 3-of-5 for high-risk operations. Enterprise roots are independent and cannot lower the platform minimum. Community, personal, test, and development roots require administrator confirmation by default and do not grant high privilege. Key lifetimes are capped at 1 year, 1 year, 30 days, and 7 days respectively; official and enterprise keys are capped at 3 years.

An unknown root or key, a revoked or expired key, a bad signature, or an unmet threshold is always rejected by current v1. A registered community, personal, test, development, or untrusted root returns needs_confirmation. When an upper-layer UI or CLI permits continuation, it must show the warning, wait 10 seconds, collect password plus second and third confirmations, and write the decision to the audit log.

Runtime and release

Plugins run as sidecars and use asynchronous interfaces. They must not block a WAF request thread or access secrets, tokens, cookies, Authorization headers, administrator sessions, or raw request bodies. External egress is denied by default; temporary connectivity requires a short-lived Socket Lease.

Release order is build → test → sign → publish → observe → staged → canary → promote. The target lifecycle creates a new control-plane revision for rollback rather than replaying an old package. The current CheeseWAF code exposes only the local RuntimeStore staged/promote/rollback contract; the separate control plane is not wired. See the Standalone Control Runtime page for the current cheesewaf-control command, probes, and fail-closed startup boundary; that entry does not provide plugin installation, OTA, CWEDP, or hot-load execution. CheeseWAF must record executable evidence for installation, OTA, CWEDP, and hot loading before this handbook describes those capabilities as available.

v2 and extension planning

The following are not v1 manifest fields and must not appear in the current Get Started example:

  • package_id, class, target CheeseWAF/extension API, platform/architecture, minimum audit-event version, and permission declarations;
  • a provenance/ directory containing SBOMs, build records, or publisher statements;
  • DuckDB-specific fields, host-version matrices, and analysis-data constraints;
  • notifier provider packs (crp.cheesewaf.io/notifier/v1). They only describe a delivery format for the core notifier and carry no executable or plugin egress.

These items require a new schema, parser, signature coverage, migration notes, and regression tests. Until then, keep them in the planned v2, DuckDB, or notifier provider contract and do not describe them as current runtime behavior.

A notifier provider is not a sidecar capability. The current sidecar allows only observe, candidate_snapshot, hint, and health, and fixes egress to deny; only the core notifier may deliver messages. See the Notifier Provider Pack Contract.