Creating Plugins
Build your own plugins to extend Crow CI with custom functionality.
Plugin Architecture
Section titled “Plugin Architecture”A Crow CI plugin is a container image that:
- Receives configuration via
PLUGIN_*environment variables - Executes a fixed set of commands via
ENTRYPOINT - Cannot have its
CMDoverridden by users
This architecture ensures plugins execute predictably, making them safe for handling secrets.
Quick Start
Section titled “Quick Start”Here’s a minimal plugin structure:
Settings Reference
Section titled “Settings Reference”How Settings Work
Section titled “How Settings Work”When a user configures a plugin:
Crow transforms settings into environment variables:
| Setting | Environment Variable |
|---|---|
server | PLUGIN_SERVER |
message | PLUGIN_MESSAGE |
retry_count | PLUGIN_RETRY_COUNT |
Naming Rules
Section titled “Naming Rules”- Settings are uppercased:
myValue→PLUGIN_MYVALUE - Dashes become underscores:
my-setting→PLUGIN_MY_SETTING - Nested objects become JSON strings
Complex Values
Section titled “Complex Values”How a setting is encoded depends on its type:
| Setting type | Encoding |
|---|---|
| Object (map) | JSON |
| Array containing objects or nested arrays | JSON |
| Array of plain values (strings, numbers, booleans) | Comma-separated |
Results in:
PLUGIN_TARGETS='production,staging'PLUGIN_CONFIG='{"retries":3,"timeout":30}'PLUGIN_REGISTRIES='[{"registry":"https://codeberg.org","username":"crow"}]'
An array of plain values is never JSON-encoded, regardless of how many elements it has.
A single-element array such as targets: [production] becomes PLUGIN_TARGETS='production', and an empty array becomes an empty string.
Numbers and booleans keep their type inside JSON output, so retries: 3 becomes 3 and not "3".
Parse these in your plugin:
Lists Containing Commas
Section titled “Lists Containing Commas”The comma-separated encoding exists because most plugins are written in Go using urfave/cli, whose slice flags split environment variables on commas by default.
PLUGIN_TARGETS=production,staging therefore arrives as a ready-made []string without any parsing code in the plugin.
That splitting has no escape mechanism, so a value that itself contains a comma cannot be represented in an array of plain values. Nest the array inside an object to have it encoded as JSON instead:
Results in PLUGIN_FILES='{"paths":["file,with,commas.txt","CHANGELOG.md"]}'.
A Go plugin reading this must turn off the default splitting, which would otherwise split the JSON on its own commas:
The setting then arrives as a single string, ready to decode with encoding/json.
Security Best Practices
Section titled “Security Best Practices”No Environment Key
Section titled “No Environment Key”Crow prohibits using environment: with plugins for security. All inputs must come through settings:.
Secret Handling
Section titled “Secret Handling”Your plugin receives secrets as regular environment variables. Best practices:
- Never log secrets - Avoid echoing sensitive values
- Document required secrets - Clearly list what credentials are needed
- Minimize secret scope - Only request what’s necessary
Validate Inputs
Section titled “Validate Inputs”Always validate and sanitize inputs:
Language Examples
Section titled “Language Examples”Go Plugin
Section titled “Go Plugin”Go is ideal for plugins due to single-binary output:
Python Plugin
Section titled “Python Plugin”Node.js Plugin
Section titled “Node.js Plugin”Testing Plugins
Section titled “Testing Plugins”Local Testing
Section titled “Local Testing”Test your plugin locally by setting environment variables:
Integration Testing
Section titled “Integration Testing”Create a test pipeline:
Publishing Plugins
Section titled “Publishing Plugins”Container Registry
Section titled “Container Registry”Push your plugin to a container registry:
Documentation
Section titled “Documentation”Create a README.md with:
- Description - What the plugin does
- Settings - All available settings with types and defaults
- Secrets - Required credentials
- Examples - Working pipeline configurations
- Changelog - Version history
Versioning
Section titled “Versioning”Use semantic versioning for plugin releases:
1.0.0- Initial stable release1.1.0- New features, backwards compatible2.0.0- Breaking changes
Tag your images with both specific versions and major version aliases:
Getting Listed
Section titled “Getting Listed”To add your plugin to the available plugins page, open a pull request to the Crow CI repository.