collectors/hooks
Configure collector hooks in lunar-config.yml — triggers like CI commands, code events, or cron schedules that determine when collectors run.
lunar-config.yml -> collectors.<collector-index>.hookslunar-collector.yml -> collectors.<collector-index>.hooksType:
arrayForm:
hooks: - <hook-configuration> - <hook-configuration> - ...
Hooks defines when a collector should run.
Example hooks definition:
hooks:
- type: ci-before-command
binary:
name: go
args:
- value: build
- type: code
- type: cron
schedule: "0 2 * * *"Collector Hook
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>lunar-collector.yml -> collectors.<collector-index>.hooks.<hook-index>Type:
objectForm:
A collector hook defines a trigger point for when a collector should run. Collectors can be triggered by various events such as code changes, CI pipeline events, or cron schedules.
Different hooks will cause the collector to execute in different contexts. For example, ci-* hooks will execute the collector in the context of the CI pipeline, while code and cron hooks will execute on a Lunar runner.
A hook has different configuration options depending on the type of event it is triggered by.
type
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.typeType:
stringRequired
The type of hook. The available values are:
ci-before-job- triggers before a CI jobci-after-job- triggers after a CI jobci-before-step- triggers before a CI stepci-after-step- triggers after a CI stepci-before-command- triggers before a command is executedci-after-command- triggers after a command is executedcode- triggers when code changescron- triggers on a scheduleafter-json- triggers once a component's collection has settled, keyed on a Component JSON path
Hook Types
ci-before-job / ci-after-job
Form:
The ci-before-job type triggers the collector before a CI job is run. The ci-after-job type triggers the collector after a CI job is run. The collector will run if the job name matches the specified regex pattern.
If no pattern is specified, the collector will run before/after every job.
pattern
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.patternType:
stringOptional
Default:
.*
A regex pattern to match against the job name.
ci-before-step / ci-after-step
Form:
The ci-before-step type triggers the collector before a CI step is run. The ci-after-step type triggers the collector after a CI step is run. The collector will run if the step name matches the specified regex pattern.
If no pattern is specified, the collector will run before/after every step.
pattern
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.patternType:
stringOptional
Default:
.*
A regex pattern to match against the step name.
ci-before-command / ci-after-command
Forms:
Simple form:
Advanced form:
Pattern form (deprecated):
The ci-before-command type triggers the collector before a command is run in the CI pipeline. The ci-after-command type triggers the collector after a command is run.
The command can be any process within the CI pipeline even if it is wrapped in scripts or called from other commands.
There are two forms for matching commands: the Simple form provides a straightforward way to match commands for common use cases, while the Advanced form provides additional options for fine-grained control. The Simple form is a subset of the Advanced form. The Pattern form is deprecated and may be removed in a future release.
For the hook to trigger, all specified matchers (binary, args, envs) must match. This is an AND operation. To implement OR logic (e.g., matching both -f and --file flags), use regex patterns with alternation (e.g., flag_pattern: ^(-f|--file)$).
Matching Limitations
The argument matching algorithm operates on raw argument strings and does not have semantic knowledge of the command being executed. Specifically:
The
flag+valueconstruct matches consecutive arguments (e.g.,--file foo.txt) or arguments joined with=(e.g.,--file=foo.txt). It does not know whether a command's flag actually accepts a value.In ambiguous cases, incorrect matches may occur. For example, given
mycommand --file --verbose, a matcher withflag: --verbosewould match, even though--verbosemight actually be the value of--file(if--fileaccepts any string as its value).Positional argument matchers match in order but cannot distinguish between a true positional argument and a flag's value. For example,
value: buildwould match bothgo build ./...(wherebuildis a subcommand) andgo run ./cmd/mycmd.go --type build(wherebuildis the value of--type).
For most common CLI tools and usage patterns, these limitations do not cause issues. However, be aware of edge cases when matching commands with unusual argument structures.
For advanced edge cases, use args_pattern instead of args.
binary
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.binaryType:
objectOptional
Specifies how to match the command's binary. All specified fields must match for the binary to be considered a match.
name[_pattern]
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.binary.name[_pattern]Type:
stringOptional
Specifies how to match the binary name. Use name for an exact match, or name_pattern for a regex pattern. The two fields are mutually exclusive.
dir[_pattern]
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.binary.dir[_pattern]Type:
stringOptional
Specifies how to match the binary's directory. Use dir for an exact match, or dir_pattern for a regex pattern. The two fields are mutually exclusive with each other and with use_path_dirs. If none of dir, dir_pattern, or use_path_dirs is provided, the hook matches any directory.
use_path_dirs 🚧 Coming Soon
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.binary.use_path_dirsType:
booleanOptional
By default (if dir, dir_pattern or use_path_dirs are not provided), the hook matches any directory.
If this field is set to true, restricts matching to binaries located in directories that are present in the PATH environment variable. Mutually exclusive with dir and dir_pattern.
args
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.argsType:
arrayOptional
An array of argument matchers. All specified matchers must match for the hook to trigger.
Each argument matcher can specify a flag and/or a value. The flag and value fields work together to match arguments in both space-separated form (--foo bar) and equals form (--foo=bar).
Ordering rules:
Matchers with only
value(orvalue_pattern) and noflagare positional arguments and must be defined in the order they appear in the command.Matchers with
flag(orflag_pattern) can be defined in any order, regardless of where they appear in the actual command.
flag[_pattern]
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.args.<arg-index>.flag[_pattern]Type:
stringOptional
Specifies how to match the flag name. Use flag for an exact match (e.g., -t, --tag), or flag_pattern for a regex pattern (e.g., ^(-f|--file)$ to match both short and long forms). The two fields are mutually exclusive. Flag matchers can be defined in any order.
If neither flag nor flag_pattern is provided, the matcher is treated as a positional argument and only the value is matched. Positional matchers must be defined in the order they appear in the command.
Note: Only use flag for actual flags (arguments starting with - or --). For positional arguments like subcommands (e.g., get in kubectl get pod), use only value without flag.
For boolean flags (e.g., --verbose), provide only flag (or flag_pattern) without value or value_pattern. See the value[_pattern] documentation below for details on how boolean flags are matched.
value[_pattern]
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.args.<arg-index>.value[_pattern]Type:
stringOptional
Specifies how to match the argument value. Use value for an exact match, or value_pattern for a regex pattern. The two fields are mutually exclusive.
If neither
valuenorvalue_patternis provided, the matcher assumes this is a boolean flag (a flag that takes no value, such as--verbose). In this case,--flagmatches, but--flag=and--flag=anythingdo not match. Note that--flag anythingwould match becauseanythingis treated as a separate argument, not a value for--flag.If
valueis set to an empty string (""), matches arguments with an explicitly empty value (e.g.,--flag=), but not boolean flags without a value (e.g.,--flag).
args_pattern
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.args_patternType:
stringOptional
A regex pattern to match against all command arguments as a single space-concatenated string. This is an alternative to the args array for advanced matching scenarios where the structured args matchers are insufficient.
For example, if a command is invoked as mycommand --flag value arg1 arg2, the args_pattern would match against the string --flag value arg1 arg2.
The args array and args_pattern can be used together; both must match for the hook to trigger.
envs
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.envsType:
arrayOptional
An array of environment variable matchers. All specified matchers must match for the hook to trigger.
name[_pattern]
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.envs.<env-index>.name[_pattern]Type:
stringOptional
Specifies how to match the environment variable name. Use name for an exact match, or name_pattern for a regex pattern. The two fields are mutually exclusive.
value[_pattern]
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.envs.<env-index>.value[_pattern]Type:
stringOptional
Specifies how to match the environment variable value. Use value for an exact match, or value_pattern for a regex pattern. The two fields are mutually exclusive.
max_process_depth 🚧 Coming Soon
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.max_process_depthType:
integerOptional
Default: infinite
Defines the maximum depth of the process itself in the process tree for which the hook will trigger. For example, if set to 1, the hook will only trigger on top-level processes in the CI/CD pipeline.
include_children_depth 🚧 Coming Soon
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.include_children_depthType:
integerOptional
Default:
0
If set to a value greater than zero, the hook will also trigger on child processes of the matched command, up to the specified depth. By default (0), the hook only triggers on the matched command itself.
pattern (deprecated)
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.patternType:
stringRequired in Pattern form
Deprecated
A regex pattern to match against the full command line. This form is deprecated; use the Simple or Advanced form instead.
Examples
Match go build commands:
Match kubectl get pod (positional arguments in order):
Match docker build with any tag:
Match npm run, npm test, or npm build:
Match pytest with verbose flag:
Match commands with either -f or --file flag:
Match any Python binary in a specific directory:
Match go commands resolved via PATH:
Match commands with specific environment variable:
Match using args_pattern for advanced argument matching:
Match top-level make commands and their immediate children:
Match using pattern form (deprecated):
code
Form:
The code type triggers the collector when the code of the component changes (i.e. there are new commits).
cron
Form:
The cron type triggers the collector on a cron schedule. The collector will run according to the specified cron schedule.
schedule
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.scheduleType:
stringRequired
A cron expression specifying when the collector should run (e.g., "0 2 * * *" for daily at 2am).
clone-code
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.clone-codeType:
booleanOptional
Default:
false
If set to true, the collector will execute in the context of the code repository. This means that the collector will have access to a git clone of the code repository to interact with.
Running on pull requests
By default a cron collector runs only against the default branch: a collector whose only hook is cron defaults its runs_on to [default-branch]. To also run the collector against the head of every open pull request on each scheduled tick, opt in via runs_on:
runs_on: [default-branch]— default branch only (the default for a cron-only collector).runs_on: [prs]— open pull request heads only.runs_on: [prs, default-branch]— both.
Each pull-request run is recorded against that PR's head commit, so the PR's policy results refresh on the schedule. For example, a scheduled dependency check can begin failing a pull request after a vulnerability is disclosed for a dependency it already uses — even though the PR's code hasn't changed. The default-branch run is unaffected.
A collector that declares a cron hook and a CI/code hook keeps the global [prs, default-branch] default, so the CI/code hook's pull-request coverage is preserved; set runs_on explicitly to change it.
after-json
Form:
The after-json type triggers a collector once a component's collection has settled for a commit — after every other collector and CI workflow for that (component, commit) has finished. It never fires mid-collection. This lets a collector depend on data — a Component JSON path — rather than on a specific named upstream collector, so it reacts to whatever produced (or failed to produce) that data.
An after-json collector fires whether or not the declared path ended up populated:
Path present (enrich). Some collector or CI step wrote data at
path. The collector runs and can act on that data, regardless of which upstream produced it (Syft, Trivy, cdxgen, a CI trace, …).Path absent (fallback). Nothing wrote
path. The collector still runs, so it can supply the data itself — a fallback that only kicks in when no other source did.
The collector runs on an ephemeral runner and does not get a git checkout — there is no repository clone. It reads the component's accumulated data with lunar component get-json and writes results with lunar collect, and it can reach external resources such as container registries and APIs. Logic that needs the source tree belongs in a code or ci-* collector, not here.
path
lunar-config.yml -> collectors.<collector-index>.hooks.<hook-index>.pathType:
stringRequired
The Component JSON path the collector depends on, rooted at . (e.g. ".sbom", ".sca", ".containers.native.docker.cicd.cmds"). It must start with ..
path is only valid on after-json hooks — setting it on any other hook type is a configuration error. after-json is also a collector-only hook: it cannot be declared on a cataloger.
Firing
An
after-jsoncollector fires at most once per(component, commit)collection cycle, once the component's collection has settled. Multiple writes to the samepathdo not re-trigger it.Firing does not depend on whether
pathwas populated (see above). Thepathdeclares intent and future-proofs a present-only firing policy; today the collector fires in both the present and absent cases, so its script must be safe to run when the path is absent (check, then exit0when there is nothing to do).The component's checks stay
pendinguntil the fired collector's run finishes; policy then evaluates against the final Component JSON. A collector that fires but writes nothing still releases the gate — it can never leave checks pending forever.
Examples
Enrich SBOM data with vulnerability info, regardless of which tool produced the SBOM:
Scan the container image the component just shipped, as soon as it is published (the docker collector records CI docker commands at .containers.native.docker.cicd.cmds):
Last updated
