NAME
App::Actions::Docker::Variable - an environment variable for a container, kept off the command line
SYNOPSIS
Pass a variable to a container:
use App::Actions::Docker;
use App::Actions::Docker::Variable;
my $docker = App::Actions::Docker->new;
my $token = App::Actions::Docker::Variable->new('TOKEN', $secret);
# The client is started as "docker run --rm -e TOKEN alpine env", and
# TOKEN is set in its environment only.
$docker->run('run', '--rm', '-e', $token, 'alpine', 'env');
Read its parts:
print $token->name, "\n"; # TOKEN
print $token->value, "\n"; # the secret
Print it, for a log (redact secrets first):
print "$token\n"; # TOKEN=the secret
DESCRIPTION
A program's command line is public. Every user of the computer can read it, for example with ps or from /proc/PID/cmdline. So a command like docker run -e TOKEN=s3cret ... shows the secret to everybody.
A program's environment is private. Only the same user (and root) can read it. The docker client accepts -e TOKEN with no value: it then copies the value from its own environment.
This class is how a job variable says "give me to docker in the private way". Put one after -e in the arguments of an App::Actions::Docker method. When the command runs, App::Actions::Docker replaces it with the bare name and puts the value in the client's environment for that one command. See "Job variables" in App::Actions::Docker for the cases where the variable must stay on the command line instead.
Everywhere else, the object behaves like the string NAME=VALUE: when you print it, join it, or compare it with eq.
METHODS
new
my $variable = App::Actions::Docker::Variable->new($name, $value);
Makes a variable.
ARGUMENTS
$name- the variable's name, for exampleTOKEN.$value- its value.undefbecomes the empty string.
RETURNS
The new object.
SIDE EFFECTS
None.
EXAMPLE
my $home = App::Actions::Docker::Variable->new('HOME_DIR', '/home/runner');
API SPECIFICATION
INPUT
{
name => { type => 'string', min => 1 },
value => { type => 'string', optional => 1 },
}
OUTPUT
{ type => 'object', isa => 'App::Actions::Docker::Variable' }
MESSAGES
None.
name
my $name = $variable->name;
Returns the name given to "new".
API SPECIFICATION
INPUT
{}
OUTPUT
{ type => 'string' }
MESSAGES
None.
value
my $value = $variable->value;
Returns the value given to "new", or the empty string if it was undef.
API SPECIFICATION
INPUT
{}
OUTPUT
{ type => 'string' }
MESSAGES
None.
COMMON PITFALLS
Printing the object prints the secret.
"$variable"isNAME=VALUE. Pass anything you log through "redact" in App::Actions::Docker first. The Docker object's own verbose and dry-run output already does this.Only App::Actions::Docker hides the value. If you pass the object to
systemor to another module, it becomes the stringNAME=VALUEand is on the command line again.A plain string is never hidden.
'-e', 'TOKEN=s3cret'is passed as it is. Only an object of this class is moved to the environment.undef is not kept.
new('X', undef)->valueis the empty string, so a container cannot tell an undefined value from an empty one.
ENCODING
The name should be ASCII letters, digits and _, and must not start with a digit; any other name stays on the command line. The value may hold any text, including non-ASCII characters and emoji, but encode it to bytes (for example UTF-8 with Encode) before you pass it, because an environment and a command line hold bytes, not characters. A value with a NUL character cannot go in an environment, so it stays on the command line.
AUTHOR
Nigel Horne, njh@nigelhorne.com
FORMAL SPECIFICATION
This section describes each routine in the Z notation, a precise mathematical language for describing programs. You do not need to read it to use the module: everything here is also said in plain words in the sections above.
How to read it: a box names a routine. The lines above the middle rule declare the values it works with. A name ending in ? is an input, and a name ending in ! is an output. ΞVariable means the routine changes nothing. The lines below the rule are always true when the routine returns.
Variable ≙ [ name : seq CHAR; value : seq CHAR ]
new
┌─ New ─────────────────────────────────────────────
│ name? : seq CHAR
│ value? : optional seq CHAR
│ v! : Variable
├───────────────────────────────────────────────────
│ v!.name = name?
│ value? = ⊥ ⇒ v!.value = ⟨⟩
│ value? ≠ ⊥ ⇒ v!.value = value?
│ string(v!) = v!.name ⁀ ⟨'='⟩ ⁀ v!.value
└───────────────────────────────────────────────────
name
┌─ Name ────────────────────────────────────────────
│ ΞVariable
│ r! : seq CHAR
├───────────────────────────────────────────────────
│ r! = name
└───────────────────────────────────────────────────
value
┌─ Value ───────────────────────────────────────────
│ ΞVariable
│ r! : seq CHAR
├───────────────────────────────────────────────────
│ r! = value
└───────────────────────────────────────────────────
STATE DIAGRAM
A variable never changes after it is made. It has one state, and its only "transition" is how App::Actions::Docker uses it when a command runs:
new($name, $value)
|
v
+------------------+
| CREATED | name and value fixed for ever;
| (immutable) | "$v" reads as NAME=VALUE
+------------------+
|
| passed after -e to App::Actions::Docker->run/capture
v
+------------------+ hideable name? +-----------------------------+
| CHECKED BY |-------yes-------->| argv gets "NAME"; |
| _hide_variables | | %ENV{NAME} = value while the |
+------------------+ | client runs, then restored |
| +-----------------------------+
no (client variable, bad name,
| case clash or NUL in value)
v
+-----------------------------+
| argv gets "NAME=VALUE" |
| (visible to every user) |
+-----------------------------+
LICENSE AND COPYRIGHT
Copyright 2026 Nigel Horne.
This program is released under the GNU General Public License, version 2. See the LICENSE file that comes with this distribution. If you use it, please let me know.