Skip to content

core.exec

← Module catalog

soul-sidesoulstack.execexec

Run a process directly via argv, without a shell — metacharacters are not interpreted.

core.exec runs cmd with args directly via exec(), without `sh -c`: pipes, redirects, glob, and substitutions do not work, and each args element is passed as a separate token. Shell injection is therefore impossible, but the binary name is still TRUSTED-ONLY. By default the step reports changed=true; you can lower it to a no-op with the creates / unless / onlyif guard parameters, and for a read-only probe with the changed_when: false key.

Requirements

  • Rootnot required
  • Sidesoul-side
  • Collectionsoulstack.exec
  • Categoryexec
Capabilitiesexec_subprocess

States

core.exec.run — Run cmd with args via exec(), without a shell.

Changes when

Always by default (the "run" verb).

Stays unchanged when

A guard creates / unless / onlyif that fired held the step at no-op; for a probe set changed_when: false.

Parameters

ParamTypeRequired / defaultDescription
cmdstringrequiredExecutable name (argv[0], no shell).
argslist<string>optionalArguments argv[1:].
cwdstringoptionalWorking directory of the process.
envmap<string>optionalAdditional environment variables (KEY: VALUE).
createsstringoptionalIdempotency: if the file exists, the step is skipped (changed=false).
unlessstringoptionalIdempotency: shell command; exit=0 → skip.
onlyifstringoptionalIdempotency: shell command; exit≠0 → skip.

Example — Read-only probe: argv without a shell, stdout into register

- name: Read kernel release
module: core.exec.run
register: kernel_release
changed_when: false
params:
cmd: uname
args: ["-r"]

Example — Guard creates: marker in place → no-op

- name: Initialize data dir once
module: core.exec.run
params:
cmd: /usr/local/bin/app
args: ["init", "--data-dir", "/var/lib/app"]
creates: /var/lib/app/.initialized

Output

FieldTypeDescription
stdoutstring
stderrstring
exit_codenumber

Notes

  • Guard parameters are checked in the order creates → unless → onlyif; the first one that fires skips the command (changed=false, output { skipped: true, reason }).
  • A non-zero exit of the main command does not by itself make the step failed — that is decided by failed_when: (for example, grep with exit 1 is normal).
  • The typical register: pattern is a read-only probe with changed_when: false and reading register.<name>.stdout in later where: / failed_when: / output:.

Security & defaults

  • The argv form without a shell: metacharacters ($, `, |, &, ;, >, *) in cmd/args are not interpreted — the value "x; rm -rf /" in args is a single literal argument, not a command.
  • TRUSTED-ONLY for the binary name: cmd (argv[0]) sets which file will be run, args can change the meaning of the operation; values from register.* / soulprint.* / input.* are acceptable only if the Destiny author trusts them.
  • The guards unless / onlyif are executed via `sh -c` — their strings fall under the same ban on untrusted interpolation as core.cmd; creates does not use a shell (only a path existence check).
  • The module does not declare run_as_root — the command runs with the soul agent process's privileges; creates reduces the side effects of repeats but only checks path existence, not the success of a previous run.

See also