Skip to content

Latest commit

 

History

History
107 lines (84 loc) · 3.61 KB

plugins.md

File metadata and controls

107 lines (84 loc) · 3.61 KB

Plugin authoring

Plugins implement policy logic that a declarative pack cannot express. A plugin is a local ESM module that exports an evaluate(changes, ctx) function.

A plugin executes code — treat it as trusted input

Flecto imports the module and runs it in its own process. It can read files, reach the network, and see every environment variable the run has, including GITHUB_TOKEN in CI. That is the point of a plugin, but it makes the source of a plugin path a security boundary.

Plugins declared in .flectorc are refused by default. A .flectorc can arrive in a pull request, so honouring it would let any contributor run code on your CI runner. Pass plugins on the command line instead:

flecto ci "config/**/*.yaml" --plugins ./policies/replica-limit.js

If the config file is genuinely trusted — your own repo, no untrusted pull requests — opt in with FLECTO_ALLOW_RC_PLUGINS=1. Even then, an rc-declared plugin must live inside the directory Flecto is running in.

Policy packs are declarative and are never executed, so prefer a pack when one can express the rule. See policy packs.

Run the complete example:

cd examples/plugin
node ../../index.js ci config.yaml --snapshot-file baseline.json --plugins ./replica-limit.js --fail-on policy

The command intentionally exits with status 1: the plugin reports a finding for the replica increase.

Plugin module

evaluate may be synchronous or async. It receives semantic change events and a context object, and must return an array of findings.

export function evaluate(changes, ctx) {
  return changes
    .filter((change) => change.type === 'changed' && change.path === 'service.replicas')
    .filter((change) => typeof change.after === 'number' && change.after > 5)
    .map((change) => ({
      id: 'replica-limit',
      severity: 'warn',
      path: change.path,
      message: `Replica count is ${change.after}; expected at most 5.`,
    }));
}

Register local plugins with a comma-separated list:

flecto ci config/prod.yaml --plugins ./plugins/replica-limit.js,./plugins/other.js

The same plugins array can be set in .flectorc defaults or profiles.

Inputs

Each item in changes has this shape:

{
  type: 'added' | 'removed' | 'changed',
  path: 'database.pool_size',
  before: 5,
  after: 20
}

before or after can be absent for added or removed keys. Their values retain the types produced by the config parser, so check types before applying numeric or boolean logic.

ctx contains:

{
  cwd,       // Flecto's current working directory
  file,      // absolute path to the file being evaluated
  profile,   // selected profile name, or null
  source,    // 'watch' | 'ci'
  packIds    // active policy-pack ids
}

Return findings

Each returned item should have id, severity, path, and message:

{
  id: 'replica-limit',
  severity: 'warn', // 'info', 'warn', or 'error'
  path: 'service.replicas',
  message: 'Replica count is 8; expected at most 5.',
  pack: 'my-plugin' // optional
}

If pack is omitted, Flecto labels it plugin:<configured path>. Findings with the same id and path are deduplicated, keeping the highest severity.

Plugin paths are resolved relative to Flecto's current working directory (unless absolute). Remote http: and https: plugin URLs are rejected. Let errors surface rather than swallowing them: a thrown plugin error fails the Flecto command.

For async plugins, pack/plugin finding merging, fail-closed loading, and reusable fixtures, see the plugin cookbook.