Skip to content

Give every 51Degrees environment variable the underscore name - #100

Closed
jwrosewell wants to merge 1 commit into
rcfrom
fix/environment-variable-names
Closed

jwrosewell wants to merge 1 commit into
rcfrom
fix/environment-variable-names

Conversation

@jwrosewell

Copy link
Copy Markdown
Contributor

The problem

A POSIX shell rejects an environment variable name that starts with a digit,
so several of the names this repository documented could not be set the way it
told a developer to set them. Measured in bash:

$ export 51DEGREES_DD_PATH=/data/TAC-HashV41.hash
bash: export: `51DEGREES_DD_PATH=/data/TAC-HashV41.hash': not a valid identifier
$ 51DEGREES_IPI_PATH=/data/file.ipi java -cp ... GettingStartedOnPrem
bash: 51DEGREES_IPI_PATH=/data/file.ipi: command not found

That covered 51DEGREES_RESOURCE_KEY, 51DEGREES_DD_PATH and
51DEGREES_IPI_PATH. The repository had also grown a second,
underscore-prefixed name beside the resource key one, so two constants held
what was meant to be the same thing, and the on-premise web example's pipeline
configuration carried the shell default form
${51DEGREES_DD_PATH:-${TestDataFile:-...}}, which a shell can never fill in.

What the specification says

POSIX.1-2024 (IEEE Std 1003.1-2024),
Base Definitions section 8.1, Environment Variable Definition:

Environment variable names used by the utilities in the Shell and Utilities
volume of POSIX.1-2024 consist solely of uppercase letters, digits, and the
<underscore> ('_') from the characters defined in Portable Character Set and
do not begin with a digit. Other characters, and byte sequences that do not
form valid characters, may be permitted by an implementation; applications
shall tolerate the presence of such names.

Base Definitions 3.216, Name,
which is what export and a variable assignment take:

In the shell command language, a word consisting solely of underscores,
digits, and alphabetics from the portable character set. The first character
of a name is not a digit.

So a process may receive a digit-initial name, but a shell can never set one.

The decision

James Rosewell decided, in his words, "Just use the version that works
everywhere all the time with no fallback." Every name becomes
_51DEGREES_<NAME>, and the name without the leading underscore is not read
anywhere. This follows
51degrees-rust#378 and
51degrees-dotnet#131,
which made the same change in those languages, so the names match across the
three repositories. All three use _51DEGREES_RESOURCE_KEY,
_51DEGREES_DD_PATH and _51DEGREES_IPI_PATH.

What changed

Twenty-two places in fifteen files, which the guard test below counted.

What stays, and why

The legacy names that do not start with a digit stay, because a shell can
set them and nothing about them is broken.
51degrees-rust#378 and
51degrees-dotnet#131
kept their equivalents for the same reason. In this repository those are
TestResourceKey and SuperResourceKey for the resource key, and
TestDataFile for the data file paths. Each is still checked after the
_51DEGREES_* name. Removing them is a separate decision, because it would
break callers who have set a name that works today.

Nothing with a 51D_ prefix was touched, because those are cookie prefixes
and evidence keys in the Share Usage, geolocation and 51Did code rather than
environment variables, and the 51Degrees-... names are file names. The guard
test below matches only the 51DEGREES_ form, so it leaves both alone.

The guard test

pipeline/pipeline.common/src/test/java/fiftyone/common/testhelpers/EnvironmentVariableNamesTest.java
is a port of
the Rust test.
It walks up from the working directory to the folder that holds .git, lists
the files with git ls-files -z so build output and the submodules are left
out, skips a tracked path that is not a file, and fails on any name that
starts with the digit, naming the file, the line and the name. It builds the
text it looks for as "5" + "1DEGREES_" so the test file does not match
itself. theNameMatcherFindsOnlyNamesThatStartWithTheDigit proves the matcher
finds 51DEGREES_DD_PATH and does not match _51DEGREES_DD_PATH or
X51DEGREES_DD_PATH.

It sits in
pipeline.common,
whose only dependencies are slf4j, logback and junit, so it needs no data file,
no resource key and no native library and the normal unit test run executes it
on every platform. It reads bytes rather than text, so a file in any encoding
is scanned and a file that is not text cannot throw.

Runs

Red, on
f6784e13,
which is rc at d39b6af with only the guard test and the temporary workflow
added and no rename:

  • Run 42931564351,
    failing on both Java 8 and Java 21 with
    noFileNamesAVariableThatStartsWithADigit ... FAILURE! and
    "22 names start with a digit, which a POSIX shell cannot set, so each must
    start with an underscore". theNameMatcherFindsOnlyNamesThatStartWithTheDigit
    passed in the same run, so the matcher was working and the 22 were real. The
    job reports failure, because the temporary workflow does not set
    -Dmaven.test.failure.ignore.

Green, on
ca83cdb2,
which is this branch's head with the same temporary workflow on top:

  • Run 42932279460,
    Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 on both Java 8 and Java 21,
    so both the scan and the matcher test pass with the rename in place.

Full build:

macOS was left out of this draft's full build under the 9 November decision. The rc head is built with macOS before it merges into main.

What this changes for callers

These names stop being read. Anyone who set one must set the
_51DEGREES_ name instead, and this belongs in the release note.

Name that stops working Set this instead
51DEGREES_RESOURCE_KEY _51DEGREES_RESOURCE_KEY
51DEGREES_DD_PATH _51DEGREES_DD_PATH
51DEGREES_IPI_PATH _51DEGREES_IPI_PATH

No published Maven artifact reads any of them. Every one is in the examples,
the test helpers, a CI script and the documentation, so no consumer of a
published package is affected. A developer or a CI definition that set an old
name gets the default behaviour until the name is changed, which for a data
file path means the example searches for the file and downloads the free one
instead, and for the resource key means the cloud example reports that no key
is set.

The non-digit legacy names listed above are unaffected and still work, so
anyone setting TestResourceKey, SuperResourceKey or TestDataFile needs
to do nothing.

One Java constant changed its name as well as its value, which matters to
anyone who compiled against the examples. KeyHelper.RESOURCE_KEY_ENV_VAR in
fiftyone.ipintelligence.examples.shared no longer exists, and
KeyHelper.SHARED_RESOURCE_KEY_NAMES.get(0) holds the aligned name in its
place. That class is in an example module rather than a published engine, so
nothing on Maven Central refers to it.

What remains

  • The cxx submodule's own C and C++ examples read the data file paths under
    the old names. That is changed in that repository, and this one takes it
    with the next submodule update. Nothing here runs those examples, and the
    guard test leaves a submodule out because git ls-files reports it as a
    directory rather than a file.
  • The tmp/envnames-red and tmp/envnames-green branches, and the temporary
    workflow file on each, exist only to show the red and green runs above. Both
    are deleted once this is reviewed.

A POSIX shell cannot set a name that starts with a digit, so every name
becomes _51DEGREES_<NAME> and the digit form is not read anywhere. The
duplicate constants that held the two spellings of the resource key are
reduced to one, and the guard test fails on any name in the digit form.
@jwrosewell

Copy link
Copy Markdown
Contributor Author

Closed in favour of #105, which makes the same rename to the 51DEGREES names more fully.

@jwrosewell jwrosewell closed this Nov 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant