bigfix-actionscript-runner
Run the ActionScript in a BigFix .bes file (or a plain ActionScript file)
the way a BigFix client would, without a BigFix server, on this machine or on
a test machine over SSH. By default it is a dry run; --execute really runs
the action so its changes can be measured.
- Real relevance substitution: every
{expression}is evaluated byqnathrough bigfix-remote-client-relevance, on the machine the action runs on. - Runs on the target: with
--ssh USER@HOST, the sandbox, the file commands, the commands and the relevance all happen on that machine (macOS, Linux or Windows). Nothing has to be set up there beyond SSH andqna. - Only where it is relevant: like a client, the action runs only when
every one of the item's relevance clauses is True on the target;
--forceruns it anyway (handy for running it again while testing). - Preflight: relevance is checked first with bigfix-relevance-analyzer and the ActionScript with pre-commit-bigfix (never with auto-fix). Errors stop the run before anything happens; warnings never do (see Preflight).
- Baseline, then every step: every expression is evaluated once before line 1, and again at the step that uses it, because an earlier step can change the answer (an error before a prefetch can be a file name after it). The trace notes each value that changed since the baseline.
- A sandbox for the client folders: a dry run keeps every path in a
sandbox;
--executesandboxes only the client folders and lets every other path be real;--no-sandboxuses the real client's folders too (see Sandbox modes). - Real prefetches: prefetch statements and items are parsed, validated,
downloaded and compared with bigfix-prefetch
(size, SHA-1, SHA-256), then put in the target's
__Downloadand hashed again there.
It's on PyPI, so it
runs with
uvx bigfix-actionscript-runner "Scan for PHP Installs with YARA-X - macOS.bes".
To run your own changes, run it from a checkout:
uvx --from ~/Projects/bigfix-actionscript-runner bigfix-actionscript-runner path/to/task.bes
(uvx caches the build of a local checkout by version; after changing the
code, add --no-cache, or use uv run bigfix-actionscript-runner ... inside
the checkout.)
Verifying a release
Releases after 0.2.1 are signed three ways. 0.2.1 has the checksums only.
- Checksums: each GitHub release has a
SHA256SUMS.txt, also printed in its notes. Check the downloaded files withsha256sum -c SHA256SUMS.txt. - Build provenance: each wheel and sdist has a GitHub artifact
attestation, and its Sigstore bundle
(
bigfix_actionscript_runner-<version>.sigstore.json) is a release asset. Check a file withgh attestation verify <file> --repo jgstew/bigfix-actionscript-runner. - PyPI: the files on PyPI carry PEP 740 attestations from the same workflow, shown as provenance on each file's page.
Examples
# dry run here
bigfix-actionscript-runner task.bes
# dry run on a Mac test machine (qna needs root there)
bigfix-actionscript-runner task.bes --ssh admin@mac-test --become
# really run it on a Windows test machine; only the client folders are sandboxed
bigfix-actionscript-runner task.bes --ssh admin@win-test --execute
# really run it in the real client's folders for the site "My Site"
bigfix-actionscript-runner task.bes --ssh admin@linux-test --become --execute --no-sandbox --site "My Site"
Scan for PHP Installs with YARA-X - macOS [Action1]
Target: admin@mac-test
Sandbox (everything; dry run): /var/folders/.../bigfix-actionscript-runner-k2j3h4
Preflight: 24 relevance expression(s) checked, 0 error(s), 5 warning(s)
line 46: warning [non-unique-risk bigfix-relevance-analyzer] 'pathname' is written singular ...
Relevance:
True <= mac of operating system
True <= not exists files whose(name of it as lowercase starts with "yara_results_php.text" ...
Relevant on admin@mac-test
Baseline: 9 expression(s), 1 error(s) before line 1, 3 deferred (use parameters set later)
38 prefetched add prefetch item name=yara-x-v1.22.0-x86_64-apple-darwin.tar.gz sha1=... size=9476144 url=...
<sandbox>/site/__Download/yara-x-v1.22.0-x86_64-apple-darwin.tar.gz (verified size, sha1, sha256)
46 ok parameter "destination_folder" = "{pathname of folders "Logs" of folders "__Global" of data folders of client}"
-> parameter "destination_folder" = "<sandbox>/__BESData/__Global/Logs"
...
555 shown run /bin/bash "{parameter "temp_folder"}/run_scan.sh"
-> run /bin/bash "<sandbox>/__BESData/__Global/yara_php_scan/run_scan.sh"
not run
Completed
Options
| Option | |
|---|---|
--action ID |
Which action of a Fixlet/Task (default: the DefaultAction). |
--ssh USER@HOST |
Run on that machine over SSH: relevance, sandbox, file commands and commands. |
--become |
On a macOS/Linux --ssh target, run qna, file commands and commands under sudo -n (a client runs actions as root; macOS qna needs it). Needs passwordless sudo. Only with --ssh. |
--execute |
Really run the action: commands run, and paths outside the client folders are the real ones. |
--no-sandbox |
With --execute: use the real client's folders as well. Needs --site. |
--site NAME |
With --no-sandbox: the site whose client folder is "the current site". |
--param NAME=VALUE |
An action parameter's value (repeatable): for an action parameter query (otherwise its default is used), a secure parameter, or any parameter a console would set. A parameter line in the script still sets its own. |
--set 'EXPR=>VALUE' |
Fixed answer for an expression as written in the action (repeatable), e.g. for an inspector the target doesn't have. |
--exit-code N |
Exit code assumed for wait commands that aren't run (default 0). |
--force |
Run even when the item's relevance isn't True on the target (it is still evaluated and shown). |
--no-baseline |
Skip the up-front evaluation of every expression (each is still evaluated at its step). |
--no-download |
Placeholder files instead of downloading prefetches. |
--no-preflight |
Skip the preflight checks. |
--sandbox DIR |
Sandbox folder on the target (default: a new temporary folder there, kept afterwards). |
--json |
A JSON report instead of the text trace. |
--timeout S |
Seconds per relevance evaluation (default 60). |
Exit codes: 0 the action completed (or ran exit), 1 it failed (the
message names the line), 2 usage, load or connection error, 3 preflight
errors, 4 not relevant on the target, so not run (without --force). With --json, errors are JSON too: {"status": "error", "message": ...}.
Sandbox modes
Client folders (site folder, __Download, data folder of client) |
Every other path | Commands | |
|---|---|---|---|
| default (dry run) | sandbox | sandbox (fs/) |
shown, not run |
--execute |
sandbox | real | run |
--execute --no-sandbox --site NAME |
the real client's | real | run |
--execute changes the target for real: a copy to /usr/local/bin/x or
C:\Program Files\... happens, a delete deletes. Use test machines.
--no-sandbox writes into a real BigFix client's site folder, so the client
must be installed there; its folders are found with pathname of client folder of site "NAME" and pathname of data folder of client.
The sandbox's layout:
<sandbox>/
site/ the current site's client folder: relative paths, __createfile, __appendfile
site/__Download/ prefetched and downloaded files
__BESData/ data folder of client (__Global/Logs, ...)
fs/ dry run only: any other absolute path, /tmp/x -> fs/tmp/x, C:\x -> fs/C/x
Prefetch and download as names must be plain file names (no /, \,
: or ..): they come from the .bes file and land in __Download. On a
Windows target a rooted path such as \Temp\x is on the site folder's drive,
\\?\C:\x is C:\x, and a : inside a sandboxed path can't switch drives.
In a dry run, reads (the source of a copy) fall back to the real file when
the sandbox has no copy of it, so an action can copy real files in, and a
move of a real file copies it instead. The sandbox folder is kept
afterwards so it can be inspected; folder delete never removes the client
folders themselves.
SSH targets
Everything an action does goes over one SSH connection to the target:
- macOS and Linux: each operation is an
sh -ccommand (undersudo -nwith--become); prefetched files go over SFTP. - Windows: each operation is PowerShell, run as
powershell -EncodedCommandbecause Windows OpenSSH's login shell iscmd.exeunless changed. Commands are started withStart-Process, which hands their arguments to the program as one command line, like a client does. A Windows target is recognized byuname -sfailing, or answeringMSYS_NT/MINGW/CYGWIN(Git for Windows putsunameon PATH). - Relevance is evaluated by
qnaon the target through bigfix-remote-client-relevance; client folders point into the target's sandbox, so relevance sees what the action wrote. - Prefetches are downloaded and verified here (cached by SHA-256), put on the target, and their SHA-256 checked again there, much like a relay serving a client.
The SSH user's host keys and keys come from ~/.ssh as for the ssh command.
Preflight
| Checker | Checks | Blocks the run | Reported only |
|---|---|---|---|
| bigfix-relevance-analyzer | the item's relevance and every {...} |
parse and type errors | style/risk rules (non-unique-risk, plural-preferred, ...) |
pre-commit-bigfix (bes-actionscript-validate-script, -lint-schclass, -validate-prefetch) |
ActionScript structure, commands, prefetch lines | E-codes: things a client rejects or fails on (E500 unclosed if, E300 unknown command, E400 bad prefetch, ...) |
W-codes, and the convention-only E401 (no sha256), E402 (old unzip), E525 (unquoted folder create path), E304/E404 |
How relevance is evaluated
The item's own relevance clauses (a Fixlet's or Task's <Relevance>) are
evaluated first, on the target, with the same action context as the steps
(so client folder of current site is the sandbox's). The action runs only
if every clause is True, as on a client; an error counts as not relevant.
Otherwise nothing runs, a temporary sandbox is removed, and the exit code is
4. --force runs it anyway. A plain ActionScript file has no relevance and
always runs.
qna has no action context, so before an expression is evaluated:
parameter "x"becomes the parameter's value (a string literal);parameter "action issue date" of actionis the run's start time, in a client's format (Wed, 22 Oct 2026 05:00:00 +0000),exists parameter "x"becomestrueorfalse: whether it is set (by the script so far,--param, or a built-in),id of actionandexit code(s) of actionbecome numbers (the exit code of the lastwait, or--exit-codewhen commands aren't run), withof active actiontoo,data folder(s) of clientandclient folder(s) of current sitepoint at the sandbox's folders (or the real ones with--no-sandbox), anddownload folder/download file "x"at its__Downloadfolder.
These are rewritten on bigfix-relevance-analyzer's parse tree, so text in
string literals is never touched. Which inspectors need a running client is
recorded from real qna runs in tests/data/client_context/; refresh it with
scripts/probe_client_context.py.
Before line 1 every distinct expression is evaluated once (the baseline),
with action parameter query values already known (the operator answers
them before an action starts). Expressions that use a parameter set later by
a parameter line are deferred instead. Each expression is evaluated again at
its step, and the trace notes where the value differs from the baseline:
54 ok copy "__Download/{name of file whose(name of it starts with "yara-x-v") of folder "__Download" ...
{name of file whose(...)...}: baseline error (Singular expression refers to nonexistent object.) -> now "yara-x-v1.22.0-x86_64-apple-darwin.tar.gz"
Some inspectors exist only in a running BigFix client, so qna answers
"No inspector context" (for example computer id, last command time of client). Give such an expression an answer with --set, which matches the
whole expression as written in the action.
An action gets the answers of the machine it runs on: a Linux task run on a
Mac gets the Mac's answers (its Linux if conditions are false, so
top-level prefetches in those branches are downloaded but never placed in
__Download, and a prefetch block downloads nothing for them). Use --ssh to a matching machine, or
--set for individual expressions.
Prefetches with hashes are downloaded by bigfix-prefetch, whose download
doesn't check TLS certificates (the hashes are checked afterwards). A
download URL with no hashes is fetched with TLS verification instead.
What is run
| ActionScript | |
|---|---|
parameter, action parameter query |
Set; redefining a parameter fails, like on a client. |
createfile until, appendfile |
Written to the site folder, with {{ as an escaped {. |
copy, move, delete, folder create, folder delete |
At the paths the sandbox mode gives; copy/move fail if the source is missing or the destination exists. |
if/elseif/else/endif, continue if, exit, pause while |
Evaluated; pause while only warns. |
prefetch, add prefetch item, download, begin/end prefetch block |
Prefetch blocks run before line 1, including the ifs in them. Top-level prefetch/download statements are downloaded and verified before line 1, like a client's cache, and copied into __Download when the statement runs, so only taken branches place a file. download now at its line. In --json, staged lists the top-level prefetches downloaded before line 1 and prefetched the files placed in __Download. |
run, wait, waithidden, runhidden, rundetached, dos, script, override |
Shown, or run with --execute from the site folder (with the override timeout). On Windows the arguments are passed exactly as written, for the program to parse, and dos runs through cmd.exe /c. |
action uses wow64 redirection, action requires restart, setting, regset, regdelete, notify client, utility, ... |
Recorded, not performed. |
| Anything else | A warning; the action continues. |
Only ActionScript is run; actions in other script types (sh, AppleScript,
PowerShell) are refused. Keywords may be followed directly by a brace, as
clients accept (if{...}, continue if{...}, pause while{...}). A file is
read as BES XML by its content, so .bes.xml exports work too.
Development
uv sync
uv run pytest # unit tests; live_qna tests too when qna is installed
BFASR_NETWORK_TESTS=1 uv run pytest # + real downloads
BFASR_SSH_POSIX_HOST=<USER>@<MAC_OR_LINUX_TEST_HOST> BFASR_SSH_BECOME=1 \
BFASR_SSH_WINDOWS_HOST=<USER>@<WINDOWS_TEST_HOST> uv run pytest -m "ssh_posix or ssh_windows"
uv run ruff check . && uv run mypy src && uv run pyright
Unit tests use a fake relevance evaluator and downloader, and an "SSH
connection" that runs commands in a local shell, so the default test run
needs no qna, no network and no SSH target. The SSH tests change files on
the target (in a temp folder they remove), so only point them at test
machines.
Metadata
Release files for bigfix-actionscript-runner 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| bigfix_actionscript_runner-0.2.2.tar.gz | 100.8 kB | With provenance | Details for bigfix_actionscript_runner-0.2.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| bigfix_actionscript_runner-0.2.2-py3-none-any.whl | Python 3 | none | any | Details for bigfix_actionscript_runner-0.2.2-py3-none-any.whl |
Total release size: 148.1 kB
Release files / bigfix_actionscript_runner-0.2.2.tar.gz
| Download URL | bigfix_actionscript_runner-0.2.2.tar.gz |
|---|---|
| Size | 100.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e7cb6159fe36e1fb31d2c8bfa7e8e27b13c9fff305a7cd5272bf30d21f442dc1
|
|
BLAKE2b-256 checksum How to use checksums |
1a2c5e3e73ab19b5d368aba5a8fdda80cebab987f33a9fa0c547bae18b664ff0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logRelease files / bigfix_actionscript_runner-0.2.2-py3-none-any.whl
| Download URL | bigfix_actionscript_runner-0.2.2-py3-none-any.whl |
|---|---|
| Size | 47.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
373d325e3ede306cf24625caff4ee6b2d242eefb865358880ceba1832ec0da40
|
|
BLAKE2b-256 checksum How to use checksums |
3e2ca32fd4aea49a6ea16808b810dbeb443abb649cc8b492e6f2817f95f1230a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logSecurity for bigfix-actionscript-runner 0.2.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for bigfix_actionscript_runner-0.2.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.