Skip to the content.

Home · Agents · Reference · Design · Security

Security

What qex writes, and who can read it

Path Mode What it holds
~/.local/state/qex/jobs/<uuid>/ 0700 one job
spec.json 0600 the command, the directory, the claims and THE CAPTURED ENVIRONMENT
status.json 0600 the state, the exit code, the times and the measured use
stdout.log, stderr.log 0600 everything that the job wrote
~/.config/qex.toml your mode the configuration
/tmp/qex/u<uid>/ 0755 the claims of your coordinator, for the other users

The job directory and the files in it are for you only. No other user of the machine can read the environment of your job, or its output.

The environment

qex submit copies your environment by default, because a job must operate in the same way as a command that you type now. That environment goes to the disk in spec.json. A shell that holds a token gives that token to the file.

Three answers:

qex submit --env-capture minimal -- ...   # PATH, HOME, USER, LOGNAME, SHELL, LANG, TZ
qex submit --no-env-capture -- ...        # nothing at all
qex submit --env-capture all -- ...       # everything (the default)

qex status hides the environment, and qex status --json hides it as well. Add --show-env to see it. This is deliberate: an agent that writes the output of qex status --json into a log must not write your token into that log.

The command line is not hidden. qex list and qex status show the program and its arguments, and the directory. Put a secret in the environment or in a file, and never in an argument.

The several-user accounting

Each coordinator writes its claims to /tmp/qex/u<uid>/, and it reads the records of the other users before it starts a job.

This method is cooperative, and it is not a control. A different user can write an incorrect value, and qex will believe it. The threat model is a colleague or an agent that does not know about your work. It is not a person who wants to damage your work.

qex protects the method against the usual faults of a directory that everybody can write:

qex also tests the free memory of the machine before each start, so it finds a load that no coordinator reports.

Turn the method off with [peers] enabled = false.

The limits on a job

qex applies no memory limit by default. A claim controls the queue only.

Linux can apply a real limit with cgroup v2. Set [enforce] mode to soft or hard. The coordinator needs a cgroup that it owns, and a coordinator that starts from a login shell frequently does not have one.

qex never reports a limit that it did not apply. qex config show says NOT ACTIVE with the reason, and a job whose limit qex could not apply records that fact in its own status, where qex status shows it. A configuration file that qex cannot read gives the same treatment: the job continues with the default values, and the record says that no limit operates.

The coordinator and the version

A coordinator can operate for hours, and a new build can replace the program in that time. The CLI then holds options that the coordinator does not know, and a JSON field that a program does not know is IGNORED, in silence.

qex asks the coordinator what it can do, and it REFUSES a job that needs something the coordinator cannot obey. A user who writes --lock target against an earlier coordinator gets an error and a remedy, and not a job id for a job that would run with no lock.

Reporting a fault

Write to the security advisories of the repository, and not to a public issue.