Extension Manifests

A manifest is a small TOML file that describes an extension to Gofer: which container image to run, which settings the extension takes, and which parameters pipelines pass when they subscribe to it. Every [[extensions.install]] entry in Gofer's config points at one.

The manifest is the only place Gofer learns about an extension; it never asks the running extension. That means:

  • Gofer can check your settings before starting anything, catching a typo, a missing required setting, or a raw secret where a reference belongs.
  • gofer extension reload can show exactly what will change before anything does.
  • gofer extension get shows an extension's settings and parameters whether or not it's running. An extension that failed to start is documented just as well as one that's up.

Format

image = "ghcr.io/clintjedwards/gofer/extensions/github:0.11.0"
documentation = "You can find more information on this extension at the official Gofer docs site: ..."

[[config_params]]
key = "app_id"
required = true
secret = false
default = ""
documentation = "The Github app's ID, shown on the app's settings page."

[[config_params]]
key = "app_key"
required = true
secret = true
default = ""
documentation = "The Github app's private key in PEM format, exactly as Github gives it to you."

[[pipeline_subscription_params]]
key = "repository"
required = true
secret = false
default = ""
documentation = "The repository the pipeline will be alerted for. The format is <organization>/<repository>"
fielddescription
imageThe container image Gofer runs for this extension. Pin it to an exact version so the manifest always means the same thing.
documentationFree text about the extension, usually a link to its docs.
config_paramsOne entry per setting the extension accepts, set by the operator in Gofer's config.
pipeline_subscription_paramsOne entry per parameter a pipeline passes when it subscribes, like gofer pipeline subscribe ... -s repository=org/repo.

Each [[config_params]] and [[pipeline_subscription_params]] entry has:

fielddescription
keyThe name, as written under settings in the [[extensions.install]] entry or passed with -s when subscribing.
requiredGofer refuses to start the extension if a required setting has no value and no default.
secretThe value must be a global secret reference like global_secret{{github-app-key}}. Gofer rejects raw values for these.
defaultUsed when the config doesn't set the key. Empty means there's no default.
documentationWhat it does. gofer extension manifest prints it as a comment next to the setting, and gofer extension get lists it.

Gofer checks config params itself. Pipeline subscription params are listed for documentation; the extension checks them when a pipeline subscribes.

Where manifests come from

The manifest field in an [[extensions.install]] entry can be:

  • An https:// URL. Gofer downloads it every time it starts or reloads. Plain http:// is refused: the manifest decides which image Gofer runs with the extension's API token, so it shouldn't be possible to tamper with it in transit.
  • A path on the Gofer server, like /etc/gofer/extensions/my_extension.toml. Relative paths are relative to the directory Gofer was started in.

Gofer's default extensions (cron and interval) don't need either: their manifests are built into Gofer, and Gofer serves them at /extensions/manifests/<name>.toml. An entry for one of them can leave manifest out. Gofer's optional extensions, like github, publish their manifests in the Gofer repository; see Gofer's extensions.

Generating a manifest

Manifests are generated by the extension's own code, so they can't drift away from the settings it actually reads. Extensions built with the Go or Rust SDK print theirs when run with the manifest argument:

./my_extension manifest --image ghcr.io/me/my_extension:1.2.0 > manifest.toml

See Writing Extensions for how that works, and publish the resulting file somewhere operators can reach it alongside your image.

When an extension doesn't publish a manifest

Any extension built with the Go or Rust SDK can print its own manifest, so you can make one yourself when the author didn't publish one. Always pass the exact image tag you're going to run; the manifest pins it, and a floating tag like latest can later point at a version whose settings don't match.

The quickest way is to ask the image itself. This works when the image's entrypoint is the extension binary, which is how the SDK examples and Gofer's own extensions are built:

docker run --rm ghcr.io/someone/their_extension:1.2.0 manifest --image ghcr.io/someone/their_extension:1.2.0 \
    > /etc/gofer/extensions/their_extension.toml

Otherwise, build the extension from its source at the matching version and run the binary:

git clone https://github.com/someone/their_extension && cd their_extension
git checkout v1.2.0
go run . manifest --image ghcr.io/someone/their_extension:1.2.0 > /etc/gofer/extensions/their_extension.toml
# or for a Rust extension: cargo run -- manifest --image ...

Then point the extension's [[extensions.install]] entry at the file on the Gofer server:

[[extensions.install]]
id = "their-extension"
manifest = "/etc/gofer/extensions/their_extension.toml"

Extensions that don't use either SDK won't have a manifest command. For those, write the file by hand using the format above.

Turning a manifest into config

gofer extension manifest reads a manifest and prints an [[extensions.install]] block to paste into Gofer's config, along with the commands to create the global secrets it refers to:

$ gofer extension manifest https://example.com/my_extension/manifest.toml --id my-extension
# Store the secret settings first; leave out '< <file>' to be prompted instead:
#   gofer secret global put my-extension-api-token < <file>

[[extensions.install]]
id = "my-extension"
manifest = "https://example.com/my_extension/manifest.toml"
[extensions.install.settings]

# The token used to call the example API.
# (required, secret; must be a global secret reference)
api_token = "global_secret{{my-extension-api-token}}"