Publishing Plugins
Share your plugin with the AiSOC community via the marketplace.
Steps
- Build and test your plugin locally.
- Sign the plugin with an Ed25519 key (see Signing below). Production AiSOC deployments default to
PLUGIN_TRUST_MODE=strictand refuse to load unsigned code. - Publish to PyPI / pkg.go.dev (or host on GitHub).
- Add an entry to
marketplace/index.json:
{
"id": "myorg.virustotal",
"name": "VirusTotal Enricher",
"type": "plugin",
"description": "Enriches IPs, domains and hashes via VirusTotal API.",
"author": "My Org",
"version": "1.0.0",
"tags": ["threat-intel", "enrichment"],
"url": "https://github.com/myorg/aisoc-virustotal",
"install": "pip install aisoc-plugin-virustotal",
"signing_key_id": "myorg-prod"
}
- Open a PR — CI validates the JSON schema, verifies your
plugin.sigagainst the registeredsigning_key_id, and the marketplace bot posts a preview. - Merge — your plugin appears on the
/marketplacepage.
Signing
AiSOC verifies plugins with Ed25519 before executing any code from plugin.py. The signing flow is deliberately mechanical so it slots into CI:
1. Generate a publisher keypair (once)
aisoc plugin keygen --out ./keys/myorg
# writes keys/myorg.pem (public, share this) and keys/myorg.key (private, keep secret)
The private key never leaves your release pipeline. Store it in your CI secret manager (GitHub Actions encrypted secrets, AWS Secrets Manager, Vault, etc.).
2. Sign the plugin directory
aisoc plugin sign \
--plugin-dir ./my-enricher \
--private-key $AISOC_PUBLISHER_KEY \
--out ./my-enricher/plugin.sig
The signer hashes a canonical JSON document containing:
- the manifest (
plugin.yamloraisoc-plugin.json) with thesignatureandtrustkeys stripped, and - a sorted
{relative_path: sha256_hex}map of every*.pyfile in the plugin directory tree.
The resulting Ed25519 signature is written to plugin.sig as a hex string. Any change to the manifest or any source file invalidates the signature, so an attacker cannot swap out plugin.py after publishing.
3. Register your public key with the operator
Operators install your keys/myorg.pem into PLUGIN_TRUSTED_KEYS_DIR (defaults to /opt/aisoc/plugin-keys). Multiple PEM files can live there — every key is tried, and a single match is enough to trust the plugin.
# operator side
cp myorg.pem /opt/aisoc/plugin-keys/
sudo systemctl restart aisoc-api
4. Choose a trust mode
The PLUGIN_TRUST_MODE setting controls what the loader does on signature failure:
| Mode | Behaviour | When to use |
|---|---|---|
strict (default) | Refuse to load unsigned, invalid, or untrusted-key plugins. | Production. |
warn | Load anyway but tag the plugin record with signature_status="unsigned" or "invalid" and emit a structured warning log. | Bootstrapping a key-rotation programme, when you need to flush the warnings out of audit logs before flipping back to strict. |
disabled | Skip the signature check entirely. signature_status="skipped". | Throwaway dev sandboxes only. Never production. |
The signature_status value is exposed on GET /api/v1/plugins so operators can spot unsigned plugins in their marketplace UI.
Plugin Quality Guidelines
- Include a
README.mdwith installation and configuration instructions. - Write tests with ≥ 80% coverage.
- Follow the AiSOC Code of Conduct.
- Pin dependency versions for reproducibility.
- Never log or store credentials in plain text.
- Ship a signed
plugin.sig. Unsigned plugins are refused in production.