From f5e2b657ed64fde88a44cc8c48b1628b6dd52bf2 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Wed, 11 Nov 2026 11:09:59 +0000 Subject: [PATCH 1/6] Add the environment variable name check, red before the rename Reads every tracked file and fails on a name that starts with the digit, which a POSIX shell cannot set, and on an old name that is still read where each variable has one name. Pester tests give the check one line at a time and a workflow runs both on every pull request. This commit is the check alone, so it fails over the repository as it stands and names every place the next commit changes. --- .../workflows/environment-variable-names.yml | 30 +++++ ci/check-environment-variable-names.Tests.ps1 | 78 ++++++++++++ ci/check-environment-variable-names.ps1 | 116 ++++++++++++++++++ 3 files changed, 224 insertions(+) create mode 100644 .github/workflows/environment-variable-names.yml create mode 100644 ci/check-environment-variable-names.Tests.ps1 create mode 100644 ci/check-environment-variable-names.ps1 diff --git a/.github/workflows/environment-variable-names.yml b/.github/workflows/environment-variable-names.yml new file mode 100644 index 00000000..f5b3abd5 --- /dev/null +++ b/.github/workflows/environment-variable-names.yml @@ -0,0 +1,30 @@ +name: Environment variable names + +on: + pull_request: + push: + branches: + - main + - rc + workflow_dispatch: + +permissions: + contents: read + +jobs: + environment-variable-names: + name: No tracked file names a variable starting with a digit or an old name + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Test the check + shell: pwsh + run: Invoke-Pester -Path ./ci/check-environment-variable-names.Tests.ps1 -CI + + - name: Check the names + shell: pwsh + run: ./ci/check-environment-variable-names.ps1 diff --git a/ci/check-environment-variable-names.Tests.ps1 b/ci/check-environment-variable-names.Tests.ps1 new file mode 100644 index 00000000..4a45aaf2 --- /dev/null +++ b/ci/check-environment-variable-names.Tests.ps1 @@ -0,0 +1,78 @@ +# Tests for ci/check-environment-variable-names.ps1. +# +# Each case is one line of text and what the check must make of it. The +# digit-initial name is matched in any case, because Windows reads an +# environment variable name in any case, so a lower case old name is still +# the old name there. The old names keep their case, for the reason the check +# gives. + +BeforeAll { + $script:Check = Join-Path $PSScriptRoot 'check-environment-variable-names.ps1' + . $script:Check + + function Get-Kind([string]$Line) { + @(Find-EnvironmentNameProblem $Line | ForEach-Object { $_.Kind }) + } +} + +Describe 'Find-EnvironmentNameProblem' { + + It 'finds the digit-initial name ' -ForEach @( + @{ Line = 'System.getenv("51DEGREES_IPI_PATH")' } + @{ Line = 'public static final String IPI = "51DEGREES_IPI_PATH";' } + @{ Line = '${51DEGREES_DD_PATH:-lite.hash}' } + @{ Line = "'51DEGREES_DD_PATH' = (Resolve-Path `$file).Path" } + @{ Line = 'System.getenv("51degrees_ipi_path")' } + @{ Line = '$env:51Degrees_Resource_Key = "key"' } + ) { + Get-Kind $Line | Should -Contain 'digit' + } + + It 'finds the old name ' -ForEach @( + @{ Line = 'System.getenv("RESOURCE_KEY")' } + @{ Line = 'env("_51DEGREES_RESOURCE_KEY", "RESOURCE_KEY");' } + @{ Line = 'env("_51DEGREES_LICENSE_KEY", "LICENSE_KEY");' } + @{ Line = 'public static final String FOD = "FOD_CLOUD_API_URL";' } + @{ Line = '$env:LICENSE_KEY = $Keys.TestResourceKey' } + @{ Line = '${FOD_CLOUD_API_URL}' } + @{ Line = 'Constants.LEGACY_ENV_VARS' } + ) { + Get-Kind $Line | Should -Contain 'fallback' + } + + # The cloud request engine's tests name the query string parameter + # resource_key, which is on the wire and not in the environment, so the + # old names keep their case. + It 'leaves alone' -ForEach @( + @{ Line = 'assertEquals("resource_key=" + key, query);' } + @{ Line = 'System.getenv("_51DEGREES_RESOURCE_KEY")' } + @{ Line = 'System.getenv("_51DEGREES_CLOUD_ENDPOINT")' } + @{ Line = '$env:_51DEGREES_DD_PATH = "file.hash"' } + @{ Line = '$env:_51degrees_dd_path = "file.hash"' } + @{ Line = 'System.getenv("SUPER_RESOURCE_KEY")' } + @{ Line = 'Set the key with !!YOUR_RESOURCE_KEY!! in the readme.' } + ) { + Get-Kind $Line | Should -BeNullOrEmpty + } +} + +Describe 'the check over a repository' { + + # git quotes a path holding a non-ASCII character unless told not to, + # and a quoted path is not found on disk. + It 'reads a file whose name is not ASCII' { + $repo = Join-Path ([IO.Path]::GetTempPath()) ([Guid]::NewGuid()) + New-Item -ItemType Directory $repo | Out-Null + try { + git -C $repo init -q + $name = 'Donn' + [char]0xE9 + 'es.java' + Set-Content -LiteralPath (Join-Path $repo $name) ` + -Value 'System.getenv("51DEGREES_DD_PATH");' + git -C $repo add -A + { & $script:Check -RepoRoot $repo } | + Should -Throw '1 names start with a digit*' + } finally { + Remove-Item -Recurse -Force $repo + } + } +} diff --git a/ci/check-environment-variable-names.ps1 b/ci/check-environment-variable-names.ps1 new file mode 100644 index 00000000..c6266799 --- /dev/null +++ b/ci/check-environment-variable-names.ps1 @@ -0,0 +1,116 @@ +# Every 51Degrees environment variable name in this repository starts with an +# underscore, because a POSIX shell cannot set a name that starts with a digit, +# and each variable has one name with nothing read in its place. This reads +# every file git tracks, which leaves out build output and the submodules, and +# fails on any name that starts with the digit and on any old name that is +# still read. +# +# Dot-sourcing the script defines Find-EnvironmentNameProblem without reading +# the repository, which is how its tests use it. + +[CmdletBinding()] +param( + # The root of the checkout to read. The default is the repository this + # script lives in. + [string]$RepoRoot = (Join-Path $PSScriptRoot '..') +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +# The start of a name a shell cannot set, split so this file does not match +# itself. +$digitInitial = '5' + '1DEGREES_' + +# A name is not matched when a name character comes before it, so a name with +# a leading underscore is left alone. It is matched in any case, because +# Windows reads an environment variable name in any case, so a lower case +# name that starts with the digit is still one a shell cannot set. +$script:DigitInitialPattern = [regex]::new( + "(? Date: Wed, 11 Nov 2026 11:13:59 +0000 Subject: [PATCH 2/6] Give every environment variable one _51DEGREES_ name A POSIX shell cannot set a name that starts with a digit, so the three names that did move to the leading underscore, and the names read behind a _51DEGREES_ one are no longer read at all. 51DEGREES_IPI_PATH, 51DEGREES_DD_PATH and 51DEGREES_RESOURCE_KEY become _51DEGREES_IPI_PATH, _51DEGREES_DD_PATH and _51DEGREES_RESOURCE_KEY. FOD_CLOUD_API_URL becomes _51DEGREES_CLOUD_ENDPOINT, which is the name the Rust library already reads, and the constant holding it is renamed with it. The RESOURCE_KEY and LICENSE_KEY reads behind the _51DEGREES_ names in the 51Did and cloud engine examples and the live 51Did tests are removed. --- AGENTS.md | 4 ++-- ci/run-integration-tests.ps1 | 2 +- examples/device-detection/README.md | 2 +- .../examples/web/GettingStartedWebOnPrem.java | 2 +- .../main/webapp/WEB-INF/51Degrees-OnPrem.xml | 4 ++-- .../web/OnPremDataFileOptionTest.java | 4 ++-- examples/ip-intelligence/README.md | 6 +++--- .../examples/console/OfflineProcessing.java | 2 +- .../examples/shared/DataFileHelper.java | 2 +- .../examples/shared/KeyHelper.java | 2 +- .../examples/shared/KeyHelperTest.java | 2 +- ip-intelligence/README.md | 4 ++-- .../shared/testhelpers/FileUtils.java | 2 +- .../shared/testhelpers/KeyUtils.java | 2 +- .../CountryTranslationIntegrationTest.java | 4 ++-- pipeline/README.md | 4 ++-- .../CloudRequestEngineBuilder.java | 4 ++-- .../flowelements/Constants.java | 2 +- .../developerexamples/cloudengine/Main.java | 15 ++++++-------- .../README.md | 8 ++++---- .../fodid/CreatorContextDemoServer.java | 20 +++++++++---------- pipeline/pipeline.did/README.md | 2 +- .../java/fiftyone/pipeline/did/DidClient.java | 2 +- .../pipeline/did/DidClientLiveTests.java | 11 +++++----- 24 files changed, 54 insertions(+), 58 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 971eb5d0..7a0e7b92 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -125,7 +125,7 @@ java -cp examples/ip-intelligence/console/target/ip-intelligence-java-examples.c ``` The example downloads the Lite file first when it is not there. In place of -the argument, the `51DEGREES_IPI_PATH` environment variable or system property +the argument, the `_51DEGREES_IPI_PATH` environment variable or system property can give the absolute path of a data file that is already there. On Java 24 or later, add `--enable-native-access=ALL-UNNAMED` before the class @@ -183,7 +183,7 @@ java -cp examples/device-detection/console/target/device-detection-java-examples It prints the same `Input values:` and `Results:` blocks as the on-premise example. The IP Intelligence cloud examples read their key from -`51DEGREES_RESOURCE_KEY` first and `TestResourceKey` second, and +`_51DEGREES_RESOURCE_KEY` first and `TestResourceKey` second, and `examples/ip-intelligence/README.md` gives the keys to create for them. ### Pitfalls diff --git a/ci/run-integration-tests.ps1 b/ci/run-integration-tests.ps1 index 99621cbd..1eb386b2 100644 --- a/ci/run-integration-tests.ps1 +++ b/ci/run-integration-tests.ps1 @@ -162,7 +162,7 @@ if (-not $TestResourceKey) { Module = 'web/getting-started.onprem' Port = 8098 ExampleEnv = @{ - '51DEGREES_DD_PATH' = (Resolve-Path "$RepoName/cxx/data/device-detection/TAC-HashV41.hash").Path + '_51DEGREES_DD_PATH' = (Resolve-Path "$RepoName/cxx/data/device-detection/TAC-HashV41.hash").Path } } ) diff --git a/examples/device-detection/README.md b/examples/device-detection/README.md index d908ca13..e3eee76d 100644 --- a/examples/device-detection/README.md +++ b/examples/device-detection/README.md @@ -122,7 +122,7 @@ case the example runs until the process is stopped: PORT=8100 java -jar ./web/getting-started.onprem/target/device-detection-java-examples.web.getting-started.onprem-4.4.20-jar-with-dependencies.jar ``` -The on-premise web example takes its data file from the `51DEGREES_DD_PATH` +The on-premise web example takes its data file from the `_51DEGREES_DD_PATH` environment variable, then from `TestDataFile`, and otherwise uses the free Lite file in `cxx/data/device-detection`, which it downloads before the server starts if it is missing. diff --git a/examples/device-detection/web/getting-started.onprem/src/main/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPrem.java b/examples/device-detection/web/getting-started.onprem/src/main/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPrem.java index 8387720c..1ed15190 100644 --- a/examples/device-detection/web/getting-started.onprem/src/main/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPrem.java +++ b/examples/device-detection/web/getting-started.onprem/src/main/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPrem.java @@ -48,7 +48,7 @@ *

* The configuration file for the pipeline is at src/main/webapp/WEB-INF/51Degrees-OnPrem.xml *

- * The data file is taken from the 51DEGREES_DD_PATH environment variable, then + * The data file is taken from the _51DEGREES_DD_PATH environment variable, then * from TestDataFile (an environment variable or system property), and otherwise * the free Lite file in cxx/data/device-detection is used, which is downloaded * before the server starts if it is missing. diff --git a/examples/device-detection/web/getting-started.onprem/src/main/webapp/WEB-INF/51Degrees-OnPrem.xml b/examples/device-detection/web/getting-started.onprem/src/main/webapp/WEB-INF/51Degrees-OnPrem.xml index bba6dd60..d3e90a76 100644 --- a/examples/device-detection/web/getting-started.onprem/src/main/webapp/WEB-INF/51Degrees-OnPrem.xml +++ b/examples/device-detection/web/getting-started.onprem/src/main/webapp/WEB-INF/51Degrees-OnPrem.xml @@ -28,11 +28,11 @@ false false - ${51DEGREES_DD_PATH:-${TestDataFile:-cxx/data/device-detection/51Degrees-LiteV4.1.hash}} + ${_51DEGREES_DD_PATH:-${TestDataFile:-cxx/data/device-detection/51Degrees-LiteV4.1.hash}} LowMemory DeviceDetectionHashEngine diff --git a/examples/device-detection/web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/OnPremDataFileOptionTest.java b/examples/device-detection/web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/OnPremDataFileOptionTest.java index 108fbd61..c77110b9 100644 --- a/examples/device-detection/web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/OnPremDataFileOptionTest.java +++ b/examples/device-detection/web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/OnPremDataFileOptionTest.java @@ -35,12 +35,12 @@ /** * Checks the order in which the on-premise web example picks its data file, - * being 51DEGREES_DD_PATH first, then TestDataFile, then the Lite file. + * being _51DEGREES_DD_PATH first, then TestDataFile, then the Lite file. * System properties stand in for the environment variables, because the * lookup reads either and a test cannot set an environment variable. */ public class OnPremDataFileOptionTest { - private static final String DD_PATH = "51DEGREES_DD_PATH"; + private static final String DD_PATH = "_51DEGREES_DD_PATH"; private static final String TEST_DATA_FILE = "TestDataFile"; private static final String LITE = "cxx/data/device-detection/51Degrees-LiteV4.1.hash"; diff --git a/examples/ip-intelligence/README.md b/examples/ip-intelligence/README.md index 1c39b245..21e41d4b 100644 --- a/examples/ip-intelligence/README.md +++ b/examples/ip-intelligence/README.md @@ -28,7 +28,7 @@ gives a link to ask for a copy. The Compare, Metrics and Suspicious examples nee properties, so with a free data file they say which they need and stop. [Contact us](https://51degrees.com/contact-us?utm_source=github&utm_medium=readme&utm_campaign=51degrees-java&utm_content=readme.md&utm_term=enterprise-data-file) for a copy of the Enterprise data file. To use it, place it in `cxx/data/ip-intelligence` and pass its path -as the first argument, or set the `51DEGREES_IPI_PATH` environment variable or system +as the first argument, or set the `_51DEGREES_IPI_PATH` environment variable or system property to its path. The Enterprise data file is over 6 GB, and the MaxPerformance profile loads all of it into @@ -61,7 +61,7 @@ Compare and Suspicious examples with the Enterprise data file are skipped. The examples locate the data file in the following order: -1. The `51DEGREES_IPI_PATH` environment variable or system property, which can +1. The `_51DEGREES_IPI_PATH` environment variable or system property, which can be set to an explicit path to the data file. It is used in place of any file named without a full path. 2. The path given as the first argument, or the free file the example uses @@ -104,7 +104,7 @@ environment variable or system property. | MetadataCloud | How to access the meta-data that relates to the properties available from the cloud IP intelligence service. | Cloud examples need a resource key. The key is read from the -`51DEGREES_RESOURCE_KEY` environment variable or system property first. The +`_51DEGREES_RESOURCE_KEY` environment variable or system property first. The legacy `TestResourceKey` name is still supported and is checked second. The cloud property tiers changed in May 2026. The examples and this diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/OfflineProcessing.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/OfflineProcessing.java index c800a3d3..8bb5ea91 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/OfflineProcessing.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/OfflineProcessing.java @@ -184,7 +184,7 @@ public static void run(String dataFile, InputStream is, OutputStream os) throws // We use the low memory profile, which reads the data file // from disk as it is needed, because this example may be // given the Enterprise data file, which is over 6 GB, through - // its first argument or 51DEGREES_IPI_PATH. MaxPerformance + // its first argument or _51DEGREES_IPI_PATH. MaxPerformance // loads the whole data file into memory, which makes each // lookup faster where there is memory to hold it. .setPerformanceProfile(Constants.PerformanceProfiles.LowMemory) diff --git a/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/DataFileHelper.java b/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/DataFileHelper.java index 19c44616..66e118cd 100644 --- a/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/DataFileHelper.java +++ b/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/DataFileHelper.java @@ -133,7 +133,7 @@ public static String findAvailableDataFile(String... candidates) { * hold an explicit path to the IP Intelligence data file. This name is * checked first, before any search of the project space. */ - public static final String IPI_PATH_ENV_VAR = "51DEGREES_IPI_PATH"; + public static final String IPI_PATH_ENV_VAR = "_51DEGREES_IPI_PATH"; public static class DatafileInfo { FiftyOneDataFile fileInfo; diff --git a/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/KeyHelper.java b/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/KeyHelper.java index 846c714f..acb4fcf7 100644 --- a/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/KeyHelper.java +++ b/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/KeyHelper.java @@ -35,7 +35,7 @@ public class KeyHelper { * hold the resource key. This name is checked first, before the legacy * {@link #TEST_RESOURCE_KEY} name. */ - public static final String RESOURCE_KEY_ENV_VAR = "51DEGREES_RESOURCE_KEY"; + public static final String RESOURCE_KEY_ENV_VAR = "_51DEGREES_RESOURCE_KEY"; public static final String TEST_RESOURCE_KEY = "TestResourceKey"; static Logger logger = LoggerFactory.getLogger(KeyHelper.class); diff --git a/examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/KeyHelperTest.java b/examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/KeyHelperTest.java index 67b2660c..809b7382 100644 --- a/examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/KeyHelperTest.java +++ b/examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/KeyHelperTest.java @@ -88,7 +88,7 @@ public void requireResourceKey_NoKey_FailsNamingEveryName() { assertEquals("This test calls the live 51Degrees cloud service, so " + "it needs a resource key and there is nothing to fall back " + "on. None of _51DEGREES_RESOURCE_KEY, " + - "_51DEGREES_RESOURCE_KEY_BESPOKE, 51DEGREES_RESOURCE_KEY, " + + "_51DEGREES_RESOURCE_KEY_BESPOKE, _51DEGREES_RESOURCE_KEY, " + "TestResourceKey is set, as an environment variable or as a " + "system property, tried in that order. The key has to carry " + "the ip and device products, because the test asks the " + diff --git a/ip-intelligence/README.md b/ip-intelligence/README.md index 8f4534ed..22fc5c65 100644 --- a/ip-intelligence/README.md +++ b/ip-intelligence/README.md @@ -36,7 +36,7 @@ data file. The free 'Lite' and Asn data files come from the [data](https://github.com/51Degrees/data) repository, which is the `cxx/data` folder of this repository. Run `cxx/data/get-data-files.sh ip-intelligence` from the root of this repository to download them, or `cxx\data\get-data-files.ps1 ip-intelligence` in PowerShell on Windows. Otherwise [contact us](https://51degrees.com/contact-us?utm_source=github&utm_medium=readme&utm_campaign=51degrees-java&utm_content=readme.md&utm_term=on-premise) to obtain an 'Enterprise' data file. For tests, the data file can be supplied explicitly by setting the -`51DEGREES_IPI_PATH` environment variable or system property to the path of +`_51DEGREES_IPI_PATH` environment variable or system property to the path of the .ipi file. When it is not set, the project space is searched for the expected file name, with the free 'Lite' file expected in `cxx/data/ip-intelligence`. @@ -113,7 +113,7 @@ You will need [resource keys](https://51degrees.com/documentation/_services__clo The tests look for a resource key in the following order: -1. The aligned `51DEGREES_RESOURCE_KEY` name, set as an environment variable +1. The aligned `_51DEGREES_RESOURCE_KEY` name, set as an environment variable or as a system property. 2. The legacy `TestResourceKey` name, which is still supported and is checked after the aligned name. diff --git a/ip-intelligence/ip-intelligence.shared/src/main/java/fiftyone/ipintelligence/shared/testhelpers/FileUtils.java b/ip-intelligence/ip-intelligence.shared/src/main/java/fiftyone/ipintelligence/shared/testhelpers/FileUtils.java index a39dd6b8..d3db631e 100644 --- a/ip-intelligence/ip-intelligence.shared/src/main/java/fiftyone/ipintelligence/shared/testhelpers/FileUtils.java +++ b/ip-intelligence/ip-intelligence.shared/src/main/java/fiftyone/ipintelligence/shared/testhelpers/FileUtils.java @@ -43,7 +43,7 @@ public class FileUtils { * supply an explicit path to the IPI data file. When set and the file * exists it is used in preference to searching the project space. */ - public static final String IPI_PATH_ENV_VAR = "51DEGREES_IPI_PATH"; + public static final String IPI_PATH_ENV_VAR = "_51DEGREES_IPI_PATH"; public static final String ENTERPRISE_IPI_DATA_FILE_NAME = "Enterprise-IpIntelligenceV41.ipi"; diff --git a/ip-intelligence/ip-intelligence.shared/src/main/java/fiftyone/ipintelligence/shared/testhelpers/KeyUtils.java b/ip-intelligence/ip-intelligence.shared/src/main/java/fiftyone/ipintelligence/shared/testhelpers/KeyUtils.java index cabb6648..8c6b1f22 100644 --- a/ip-intelligence/ip-intelligence.shared/src/main/java/fiftyone/ipintelligence/shared/testhelpers/KeyUtils.java +++ b/ip-intelligence/ip-intelligence.shared/src/main/java/fiftyone/ipintelligence/shared/testhelpers/KeyUtils.java @@ -33,7 +33,7 @@ public class KeyUtils { * Name of the aligned environment variable or system property which * supplies the resource key. This name is checked before any legacy name. */ - public static final String RESOURCE_KEY_ENV_VAR = "51DEGREES_RESOURCE_KEY"; + public static final String RESOURCE_KEY_ENV_VAR = "_51DEGREES_RESOURCE_KEY"; /** * Obtain a resource key from an environment variable or a system property. diff --git a/ip-intelligence/ip-intelligence.translation/src/test/java/fiftyone/ipintelligence/translation/CountryTranslationIntegrationTest.java b/ip-intelligence/ip-intelligence.translation/src/test/java/fiftyone/ipintelligence/translation/CountryTranslationIntegrationTest.java index a5eb58df..028bec97 100644 --- a/ip-intelligence/ip-intelligence.translation/src/test/java/fiftyone/ipintelligence/translation/CountryTranslationIntegrationTest.java +++ b/ip-intelligence/ip-intelligence.translation/src/test/java/fiftyone/ipintelligence/translation/CountryTranslationIntegrationTest.java @@ -50,7 +50,7 @@ * complete, localized, ordered country dropdown is produced. *

* The data file is resolved from the {@code TestDataFile} system property, the - * {@code 51DEGREES_IPI_PATH} environment variable, or a few well known + * {@code _51DEGREES_IPI_PATH} environment variable, or a few well known * locations, and the test is skipped if none is found. *

* The IP Intelligence element data key has differed between engine versions @@ -66,7 +66,7 @@ public class CountryTranslationIntegrationTest { private static String resolveDataFile() { String[] candidates = { System.getProperty("TestDataFile"), - System.getenv("51DEGREES_IPI_PATH"), + System.getenv("_51DEGREES_IPI_PATH"), "51Degrees-IPIV4EnterpriseIpiV41.ipi", "../51Degrees-IPIV4EnterpriseIpiV41.ipi", "../../51Degrees-IPIV4EnterpriseIpiV41.ipi", diff --git a/pipeline/README.md b/pipeline/README.md index 8370cc09..c9058b0a 100644 --- a/pipeline/README.md +++ b/pipeline/README.md @@ -131,13 +131,13 @@ and on our [website](https://51degrees.com/documentation/_device_detection__exam | pipeline.developer-examples.onpremise-engine | Shows how to modify SimpleFlowElement to make use of the 'engine' functionality and use a custom data file to map dates to star signs rather than relying on hard coded data. | | pipeline.developer-examples.clientside-element | Shows how to modify SimpleFlowElement to request the data of birth from the user using client-side JavaScript. | | pipeline.developer-examples.clientside-element-mvc | An example project showing how to use the code from SimpleClientSideElement in a Java web application using the Model-View-Controller Pattern. | -| pipeline.developer-examples.cloud-engine | Shows how to modify SimpleFlowElement to perform the star sign lookup via a cloud service rather than locally. The endpoint and resource key come from `FOD_CLOUD_API_URL` and `_51DEGREES_RESOURCE_KEY` when set, otherwise the star sign service the example was written for. | +| pipeline.developer-examples.cloud-engine | Shows how to modify SimpleFlowElement to perform the star sign lookup via a cloud service rather than locally. The endpoint and resource key come from `_51DEGREES_CLOUD_ENDPOINT` and `_51DEGREES_RESOURCE_KEY` when set, otherwise the star sign service the example was written for. | | pipeline.developer-examples.usage-sharing | Shows how to share usage with 51Degrees. This helps us to keep our products up to date and accurate. | | pipeline.developer-examples.fodid | Shows how to read a 51Did, and, in a web demo, how a browser creates and verifies one against the 51Degrees cloud and the server redeems the encrypted result, so that the creator context proves the identifier is being presented by the browser it was created on. The module README describes the flow, the environment variables, what a run costs and the redeem call to copy into your own server. | ### Pointing the cloud examples at another host -Every example that calls the 51Degrees cloud takes its endpoint from the `FOD_CLOUD_API_URL` environment variable, which is the cloud API base including the `/api/v4/` segment and defaults to `https://cloud.51degrees.com/api/v4/` (the cloud-engine example defaults to the star sign service it was written for, as its row above says). This is the same variable the cloud request engine in this repository honours, so setting it once points every example, and any pipeline built with the engine, at the same place. The resource key comes from `_51DEGREES_RESOURCE_KEY`, or the older `RESOURCE_KEY`. +Every example that calls the 51Degrees cloud takes its endpoint from the `_51DEGREES_CLOUD_ENDPOINT` environment variable, which is the cloud API base including the `/api/v4/` segment and defaults to `https://cloud.51degrees.com/api/v4/` (the cloud-engine example defaults to the star sign service it was written for, as its row above says). This is the same variable the cloud request engine in this repository honours, so setting it once points every example, and any pipeline built with the engine, at the same place. The resource key comes from `_51DEGREES_RESOURCE_KEY`. A host other than cloud.51degrees.com would be used to (a) use an on premise web server, or (b) use a privately hosted version of the 51Degrees cloud for performance reasons. This is the private hosting option of the cloud service. Both run the same service, so the examples work unchanged. diff --git a/pipeline/pipeline.cloudrequestengine/src/main/java/fiftyone/pipeline/cloudrequestengine/flowelements/CloudRequestEngineBuilder.java b/pipeline/pipeline.cloudrequestengine/src/main/java/fiftyone/pipeline/cloudrequestengine/flowelements/CloudRequestEngineBuilder.java index b0d420a0..29c27b96 100644 --- a/pipeline/pipeline.cloudrequestengine/src/main/java/fiftyone/pipeline/cloudrequestengine/flowelements/CloudRequestEngineBuilder.java +++ b/pipeline/pipeline.cloudrequestengine/src/main/java/fiftyone/pipeline/cloudrequestengine/flowelements/CloudRequestEngineBuilder.java @@ -87,12 +87,12 @@ protected CloudRequestEngine newEngine(List properties) throws Exception /* * Check if endPoint has been explicitly set via setEndpoint. - * If not check for environment variable FOD_CLOUD_API_URL. + * If not check for environment variable _51DEGREES_CLOUD_ENDPOINT. * If nothing else is set, use default value. */ if (endPoint == null || endPoint.isEmpty()) { String envVarEndPoint = getEnvVar.apply( - Constants.FOD_CLOUD_API_URL); + Constants.CLOUD_ENDPOINT_VARIABLE); if (envVarEndPoint == null || envVarEndPoint.isEmpty()) { setEndpoint(Constants.END_POINT_DEFAULT); } diff --git a/pipeline/pipeline.cloudrequestengine/src/main/java/fiftyone/pipeline/cloudrequestengine/flowelements/Constants.java b/pipeline/pipeline.cloudrequestengine/src/main/java/fiftyone/pipeline/cloudrequestengine/flowelements/Constants.java index b9b26c6a..1a77c353 100644 --- a/pipeline/pipeline.cloudrequestengine/src/main/java/fiftyone/pipeline/cloudrequestengine/flowelements/Constants.java +++ b/pipeline/pipeline.cloudrequestengine/src/main/java/fiftyone/pipeline/cloudrequestengine/flowelements/Constants.java @@ -27,7 +27,7 @@ public class Constants { public static final String END_POINT_DEFAULT = "https://cloud.51degrees.com/api/v4"; // Environment variable name to set end point - public static final String FOD_CLOUD_API_URL = "FOD_CLOUD_API_URL"; + public static final String CLOUD_ENDPOINT_VARIABLE = "_51DEGREES_CLOUD_ENDPOINT"; // Default timeout for each request to the cloud service, as the // specification's Configuration options table gives. public static final int DEFAULT_TIMEOUT_MILLIS = 2000; diff --git a/pipeline/pipeline.developer-examples/pipeline.developer-examples.cloud-engine/src/main/java/pipeline/developerexamples/cloudengine/Main.java b/pipeline/pipeline.developer-examples/pipeline.developer-examples.cloud-engine/src/main/java/pipeline/developerexamples/cloudengine/Main.java index 5b7c1b32..362da463 100644 --- a/pipeline/pipeline.developer-examples/pipeline.developer-examples.cloud-engine/src/main/java/pipeline/developerexamples/cloudengine/Main.java +++ b/pipeline/pipeline.developer-examples/pipeline.developer-examples.cloud-engine/src/main/java/pipeline/developerexamples/cloudengine/Main.java @@ -47,7 +47,7 @@ public class Main { private static final String STAR_SIGN_RESOURCE_KEY = "cloudexample"; /** - * The cloud endpoint, taken from FOD_CLOUD_API_URL when that is set, + * The cloud endpoint, taken from _51DEGREES_CLOUD_ENDPOINT when that is set, * which is the variable every 51Degrees cloud example honours and the * one the cloud request engine builder reads by itself when no * endpoint is given. A host other than cloud.51degrees.com would be @@ -59,7 +59,7 @@ public class Main { * directly. */ static String endpoint() { - String value = env("FOD_CLOUD_API_URL"); + String value = env("_51DEGREES_CLOUD_ENDPOINT"); if (value == null) { return STAR_SIGN_ENDPOINT; } @@ -70,15 +70,12 @@ static String endpoint() { } /** - * The resource key from _51DEGREES_RESOURCE_KEY, or the older - * RESOURCE_KEY, so the example can be pointed at a host whose keys - * are its own. Otherwise the key of the star sign service. + * The resource key from _51DEGREES_RESOURCE_KEY, so the example can be + * pointed at a host whose keys are its own. Otherwise the key of the + * star sign service. */ static String resourceKey() { String value = env("_51DEGREES_RESOURCE_KEY"); - if (value == null) { - value = env("RESOURCE_KEY"); - } return value == null ? STAR_SIGN_RESOURCE_KEY : value; } @@ -90,7 +87,7 @@ static String env(String name) { public static class Example { public void run() throws Exception { //! [usage] - // The endpoint comes from FOD_CLOUD_API_URL when it is set, so + // The endpoint comes from _51DEGREES_CLOUD_ENDPOINT when it is set, so // the example can be pointed at an on premise web server or a // privately hosted version of the 51Degrees cloud, and // otherwise at the star sign service it was written for. diff --git a/pipeline/pipeline.developer-examples/pipeline.developer-examples.fodid/README.md b/pipeline/pipeline.developer-examples/pipeline.developer-examples.fodid/README.md index 58655616..73ab80af 100644 --- a/pipeline/pipeline.developer-examples/pipeline.developer-examples.fodid/README.md +++ b/pipeline/pipeline.developer-examples/pipeline.developer-examples.fodid/README.md @@ -51,7 +51,7 @@ The only server-side part of the flow is the redeem call, which adds the licence key the browser never sees. The `redeem` method in `CreatorContextDemoServer.java` is that call, and these are its essential lines. `DidClient` is built once at start-up from the -resource key and the licence key (it reads `FOD_CLOUD_API_URL` itself +resource key and the licence key (it reads `_51DEGREES_CLOUD_ENDPOINT` itself and falls back to the public cloud), and `did`, `result` and `challenge` are what the page passed on from `verify-full`: @@ -90,9 +90,9 @@ scope. | Variable | Meaning | | --- | --- | -| `_51DEGREES_RESOURCE_KEY` | Required. The resource key of the page, public by nature. The older name `RESOURCE_KEY` is read when this one is not set. | -| `_51DEGREES_LICENSE_KEY` | Optional. A licence key of the same account, server side only. The older name `LICENSE_KEY` is read when this one is not set. Only an account that holds licence keys needs one to redeem, because the licence key is what keeps redemption to the acting party's own servers, so an account holding none redeems without one. | -| `FOD_CLOUD_API_URL` | Optional. The cloud API base including the `/api/v4/` segment, defaulting to `https://cloud.51degrees.com/api/v4/`. This is the same variable the cloud request engine in this repository honours, so setting it once points every 51Degrees example at the same place. A trailing slash is added where missing. A host other than cloud.51degrees.com would be used to (a) use an on premise web server, or (b) use a privately hosted version of the 51Degrees cloud for performance reasons, which is the private hosting option of the cloud service. Both run the same service, so the examples work unchanged. | +| `_51DEGREES_RESOURCE_KEY` | Required. The resource key of the page, public by nature. | +| `_51DEGREES_LICENSE_KEY` | Optional. A licence key of the same account, server side only. Only an account that holds licence keys needs one to redeem, because the licence key is what keeps redemption to the acting party's own servers, so an account holding none redeems without one. | +| `_51DEGREES_CLOUD_ENDPOINT` | Optional. The cloud API base including the `/api/v4/` segment, defaulting to `https://cloud.51degrees.com/api/v4/`. This is the same variable the cloud request engine in this repository honours, so setting it once points every 51Degrees example at the same place. A trailing slash is added where missing. A host other than cloud.51degrees.com would be used to (a) use an on premise web server, or (b) use a privately hosted version of the 51Degrees cloud for performance reasons, which is the private hosting option of the cloud service. Both run the same service, so the examples work unchanged. | | `PORT` | The port to listen on, defaulting to `5100`. | ### How to run diff --git a/pipeline/pipeline.developer-examples/pipeline.developer-examples.fodid/src/main/java/pipeline/developerexamples/fodid/CreatorContextDemoServer.java b/pipeline/pipeline.developer-examples/pipeline.developer-examples.fodid/src/main/java/pipeline/developerexamples/fodid/CreatorContextDemoServer.java index 02c7e832..1057eb48 100644 --- a/pipeline/pipeline.developer-examples/pipeline.developer-examples.fodid/src/main/java/pipeline/developerexamples/fodid/CreatorContextDemoServer.java +++ b/pipeline/pipeline.developer-examples/pipeline.developer-examples.fodid/src/main/java/pipeline/developerexamples/fodid/CreatorContextDemoServer.java @@ -101,11 +101,11 @@ * {@code fodid/creator-context/} in this module's resources. Environment * variables: *

    - *
  • {@code _51DEGREES_RESOURCE_KEY}, or the older {@code RESOURCE_KEY}, - * required. The resource key of the page, public by nature.
  • - *
  • {@code _51DEGREES_LICENSE_KEY}, or the older {@code LICENSE_KEY}, - * optional. A licence key of the same account, server side only.
  • - *
  • {@code FOD_CLOUD_API_URL}, optional. The cloud API base including + *
  • {@code _51DEGREES_RESOURCE_KEY}, required. The resource key of the + * page, public by nature.
  • + *
  • {@code _51DEGREES_LICENSE_KEY}, optional. A licence key of the same + * account, server side only.
  • + *
  • {@code _51DEGREES_CLOUD_ENDPOINT}, optional. The cloud API base including * the {@code /api/v4/} segment, defaulting to * {@code https://cloud.51degrees.com/api/v4/}. This is the same variable * the cloud request engine of this package honours.
  • @@ -119,9 +119,9 @@ public class CreatorContextDemoServer { static final String RESOURCES = "/fodid/creator-context/"; static final String RESOURCE = - env("_51DEGREES_RESOURCE_KEY", "RESOURCE_KEY"); + env("_51DEGREES_RESOURCE_KEY"); static final String LICENCE = - env("_51DEGREES_LICENSE_KEY", "LICENSE_KEY"); + env("_51DEGREES_LICENSE_KEY"); /** * The one client, built at start-up and shared by every request, @@ -131,8 +131,8 @@ public class CreatorContextDemoServer { public static void main(String[] args) throws Exception { if (RESOURCE == null) { - System.err.println("Set _51DEGREES_RESOURCE_KEY (or the older " - + "RESOURCE_KEY) to the resource key of the page."); + System.err.println( + "Set _51DEGREES_RESOURCE_KEY to the resource key of the page."); System.exit(1); } if (LICENCE == null) { @@ -149,7 +149,7 @@ public static void main(String[] args) throws Exception { + "will report the context unreadable where it holds " + "some."); } - // The client reads FOD_CLOUD_API_URL itself when no endpoint is + // The client reads _51DEGREES_CLOUD_ENDPOINT itself when no endpoint is // given, and falls back to the public cloud. A host other than // cloud.51degrees.com would be used to (a) use an on premise web // server, or (b) use a privately hosted version of the 51Degrees diff --git a/pipeline/pipeline.did/README.md b/pipeline/pipeline.did/README.md index 8784643a..2b5fdea0 100644 --- a/pipeline/pipeline.did/README.md +++ b/pipeline/pipeline.did/README.md @@ -357,7 +357,7 @@ import fiftyone.pipeline.did.RedeemResult; // The resource key is the page's and public by nature. The licence key is // server side only and is needed to redeem where the account holds licence // keys. The endpoint defaults to https://cloud.51degrees.com/api/v4/, or -// the FOD_CLOUD_API_URL environment variable where that is set. +// the _51DEGREES_CLOUD_ENDPOINT environment variable where that is set. DidClient client = new DidClient(resourceKey, licenceKey); ``` diff --git a/pipeline/pipeline.did/src/main/java/fiftyone/pipeline/did/DidClient.java b/pipeline/pipeline.did/src/main/java/fiftyone/pipeline/did/DidClient.java index 9afb29af..cc4e28b9 100644 --- a/pipeline/pipeline.did/src/main/java/fiftyone/pipeline/did/DidClient.java +++ b/pipeline/pipeline.did/src/main/java/fiftyone/pipeline/did/DidClient.java @@ -114,7 +114,7 @@ public final class DidClient { * The environment variable read for the API base when the constructor * is given none, the same one the cloud request engine honours. */ - public static final String ENDPOINT_VARIABLE = "FOD_CLOUD_API_URL"; + public static final String ENDPOINT_VARIABLE = "_51DEGREES_CLOUD_ENDPOINT"; /** * How old the whole held key list may be before a request for a key diff --git a/pipeline/pipeline.did/src/test/java/fiftyone/pipeline/did/DidClientLiveTests.java b/pipeline/pipeline.did/src/test/java/fiftyone/pipeline/did/DidClientLiveTests.java index 6ea863aa..c31e99e9 100644 --- a/pipeline/pipeline.did/src/test/java/fiftyone/pipeline/did/DidClientLiveTests.java +++ b/pipeline/pipeline.did/src/test/java/fiftyone/pipeline/did/DidClientLiveTests.java @@ -44,10 +44,9 @@ /** * Tests against the live cloud, skipped unless {@code _51DEGREES_RESOURCE_KEY} - * (or the older {@code RESOURCE_KEY}) is set. {@code FOD_CLOUD_API_URL} - * points them at another host, and {@code _51DEGREES_LICENSE_KEY} (or - * {@code LICENSE_KEY}) supplies the licence key where the account holds - * one. Each test creates a 51Did through the cloud {@code json} endpoint, + * is set. {@code _51DEGREES_CLOUD_ENDPOINT} points them at another host, and + * {@code _51DEGREES_LICENSE_KEY} supplies the licence key where the account + * holds one. Each test creates a 51Did through the cloud {@code json} endpoint, * which is one use against the resource key, plus one for each cloud call * it then makes. */ @@ -59,11 +58,11 @@ public class DidClientLiveTests { @Before public void init() { - resourceKey = env("_51DEGREES_RESOURCE_KEY", "RESOURCE_KEY"); + resourceKey = env("_51DEGREES_RESOURCE_KEY"); Assume.assumeTrue( "Set _51DEGREES_RESOURCE_KEY to run the live 51Did cloud tests.", resourceKey != null); - licenceKey = env("_51DEGREES_LICENSE_KEY", "LICENSE_KEY"); + licenceKey = env("_51DEGREES_LICENSE_KEY"); client = new DidClient(resourceKey, licenceKey); } From c885993ec9dff66e068e4e4b3dd3f93c27c3fd5d Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Wed, 11 Nov 2026 12:20:40 +0000 Subject: [PATCH 3/6] See an old name declared as a key The old-name half needed a quote, a dollar sign, a brace or a getenv call in front of the name, so it could not see one declared as a key in a workflow env: block or listed at the start of a line in a readme. A name at the start of a line, past any spaces, tabs and a list dash, now counts. The tests state it, with a workflow line whose key is an old name, a readme list entry and a shell assignment on the failing side, and a workflow line whose key is not an old name, and a longer name that ends in one of these words, on the passing side. --- ci/check-environment-variable-names.Tests.ps1 | 5 +++++ ci/check-environment-variable-names.ps1 | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ci/check-environment-variable-names.Tests.ps1 b/ci/check-environment-variable-names.Tests.ps1 index 4a45aaf2..30a2a59d 100644 --- a/ci/check-environment-variable-names.Tests.ps1 +++ b/ci/check-environment-variable-names.Tests.ps1 @@ -36,6 +36,9 @@ Describe 'Find-EnvironmentNameProblem' { @{ Line = '$env:LICENSE_KEY = $Keys.TestResourceKey' } @{ Line = '${FOD_CLOUD_API_URL}' } @{ Line = 'Constants.LEGACY_ENV_VARS' } + @{ Line = ' LICENSE_KEY: ${{ secrets.DEVICE_DETECTION_KEY }}' } + @{ Line = '- RESOURCE_KEY names the resource key' } + @{ Line = 'RESOURCE_KEY=my-key mvn test' } ) { Get-Kind $Line | Should -Contain 'fallback' } @@ -45,6 +48,8 @@ Describe 'Find-EnvironmentNameProblem' { # old names keep their case. It 'leaves alone' -ForEach @( @{ Line = 'assertEquals("resource_key=" + key, query);' } + @{ Line = ' DeviceDetection: ${{ secrets.DEVICE_DETECTION_KEY }}' } + @{ Line = ' PAID_RESOURCE_KEY: ${{ secrets.X }}' } @{ Line = 'System.getenv("_51DEGREES_RESOURCE_KEY")' } @{ Line = 'System.getenv("_51DEGREES_CLOUD_ENDPOINT")' } @{ Line = '$env:_51DEGREES_DD_PATH = "file.hash"' } diff --git a/ci/check-environment-variable-names.ps1 b/ci/check-environment-variable-names.ps1 index c6266799..4fa4f3c6 100644 --- a/ci/check-environment-variable-names.ps1 +++ b/ci/check-environment-variable-names.ps1 @@ -33,7 +33,9 @@ $script:DigitInitialPattern = [regex]::new( # An old name read or set as an environment variable, or held in a constant to # fall back to. A Java read takes the name as a string, so a quoted bare name # is matched, along with the PowerShell and config forms the CI scripts and the -# web example use. +# web example use, and a name at the start of a line past any spaces and a +# list dash, which is how a workflow declares one as a key in an env: block +# and how a readme lists one. # # These keep their case. The cloud request engine's tests name the query string # parameter resource_key, which differs from RESOURCE_KEY only by case, and a @@ -41,7 +43,7 @@ $script:DigitInitialPattern = [regex]::new( # matching in any case would fail on a name that is not an environment # variable at all. $script:FallbackPattern = [regex]::new( - '(?:["'']|\$env:|\$\{|getenv\(\s*["''])' + + '(?:["'']|\$env:|\$\{|getenv\(\s*["'']|^[\t\- ]*)' + '(?:RESOURCE_KEY|LICENSE_KEY|FOD_CLOUD_API_URL)(?![A-Za-z0-9_])|' + '\bLEGACY_[A-Z_]*ENV_VARS?\b') From d82ff33850b03981645e287ba41ef1810d55c1f2 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Wed, 11 Nov 2026 17:17:16 +0000 Subject: [PATCH 4/6] See an old name braced as a PowerShell or lookup variable The check misses an old name written as ${env:NAME}, as $ENV:NAME, as Env:\NAME or as ${{ env.NAME }}, because its prefix set wants the dollar and the env: adjacent, and its brace branch wants the name straight after the brace. Both the CI scripts and the pipeline config lookup write the braced form, so an old name can come back through the file types the check watches. These cases fail until the prefix set takes the env token on its own. --- ci/check-environment-variable-names.Tests.ps1 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ci/check-environment-variable-names.Tests.ps1 b/ci/check-environment-variable-names.Tests.ps1 index 30a2a59d..7b9273d8 100644 --- a/ci/check-environment-variable-names.Tests.ps1 +++ b/ci/check-environment-variable-names.Tests.ps1 @@ -34,6 +34,12 @@ Describe 'Find-EnvironmentNameProblem' { @{ Line = 'env("_51DEGREES_LICENSE_KEY", "LICENSE_KEY");' } @{ Line = 'public static final String FOD = "FOD_CLOUD_API_URL";' } @{ Line = '$env:LICENSE_KEY = $Keys.TestResourceKey' } + @{ Line = '${env:LICENSE_KEY} = $Keys.TestResourceKey' } + @{ Line = '${Env:RESOURCE_KEY}' } + @{ Line = '$ENV:RESOURCE_KEY = "key"' } + @{ Line = 'Remove-Item Env:\LICENSE_KEY' } + @{ Line = '${env:FOD_CLOUD_API_URL}' } + @{ Line = ' url: ${{ env.FOD_CLOUD_API_URL }}' } @{ Line = '${FOD_CLOUD_API_URL}' } @{ Line = 'Constants.LEGACY_ENV_VARS' } @{ Line = ' LICENSE_KEY: ${{ secrets.DEVICE_DETECTION_KEY }}' } @@ -54,6 +60,9 @@ Describe 'Find-EnvironmentNameProblem' { @{ Line = 'System.getenv("_51DEGREES_CLOUD_ENDPOINT")' } @{ Line = '$env:_51DEGREES_DD_PATH = "file.hash"' } @{ Line = '$env:_51degrees_dd_path = "file.hash"' } + @{ Line = '${env:_51DEGREES_LICENSE_KEY} = $Keys.TestResourceKey' } + @{ Line = 'assertEquals("${env:user.home}", substitutor.replace(line));' } + @{ Line = ' PAID_RESOURCE_KEY: ${{ env.PAID_RESOURCE_KEY }}' } @{ Line = 'System.getenv("SUPER_RESOURCE_KEY")' } @{ Line = 'Set the key with !!YOUR_RESOURCE_KEY!! in the readme.' } ) { From 7ebe2822558e8e6987ecced40cd43b9352b1466b Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Wed, 11 Nov 2026 17:31:02 +0000 Subject: [PATCH 5/6] Match the env token on its own, so a braced old name is seen The prefix set wanted the dollar and the env token adjacent, and its brace branch wanted the name straight after the brace, so ${env:NAME}, $ENV:NAME, Env:\NAME and a workflow ${{ env.NAME }} all went past. Matching the token on its own, in any case and with a following backslash allowed, closes all four, which is what the Go check already does. --- ci/check-environment-variable-names.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ci/check-environment-variable-names.ps1 b/ci/check-environment-variable-names.ps1 index 4fa4f3c6..6fa467c2 100644 --- a/ci/check-environment-variable-names.ps1 +++ b/ci/check-environment-variable-names.ps1 @@ -37,13 +37,19 @@ $script:DigitInitialPattern = [regex]::new( # list dash, which is how a workflow declares one as a key in an env: block # and how a readme lists one. # +# The env token is matched on its own, in any case and with a following +# backslash allowed, because PowerShell braces a name as well as prefixing +# it, reads one through the Env: drive, and because the pipeline config +# lookup and a workflow expression both brace one too. Wanting the dollar +# and the token adjacent misses every braced form. +# # These keep their case. The cloud request engine's tests name the query string # parameter resource_key, which differs from RESOURCE_KEY only by case, and a # query string parameter is on the wire rather than in the environment, so # matching in any case would fail on a name that is not an environment # variable at all. $script:FallbackPattern = [regex]::new( - '(?:["'']|\$env:|\$\{|getenv\(\s*["'']|^[\t\- ]*)' + + '(?:["'']|(?i:env)[:.]\\?|\$\{|getenv\(\s*["'']|^[\t\- ]*)' + '(?:RESOURCE_KEY|LICENSE_KEY|FOD_CLOUD_API_URL)(?![A-Za-z0-9_])|' + '\bLEGACY_[A-Z_]*ENV_VARS?\b') From 1db46a9e8cc64cd320105472cf7c1766ca5fdeab Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Wed, 11 Nov 2026 17:44:26 +0000 Subject: [PATCH 6/6] Wrap the endpoint comment on a whole phrase --- .../java/pipeline/developerexamples/cloudengine/Main.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pipeline/pipeline.developer-examples/pipeline.developer-examples.cloud-engine/src/main/java/pipeline/developerexamples/cloudengine/Main.java b/pipeline/pipeline.developer-examples/pipeline.developer-examples.cloud-engine/src/main/java/pipeline/developerexamples/cloudengine/Main.java index 08218323..4b039d94 100644 --- a/pipeline/pipeline.developer-examples/pipeline.developer-examples.cloud-engine/src/main/java/pipeline/developerexamples/cloudengine/Main.java +++ b/pipeline/pipeline.developer-examples/pipeline.developer-examples.cloud-engine/src/main/java/pipeline/developerexamples/cloudengine/Main.java @@ -54,10 +54,9 @@ public class Main { "https://cloud.51degrees.com/api/v4/"; /** - * The cloud endpoint, taken from _51DEGREES_CLOUD_ENDPOINT when that - * is set, - * which is the variable every 51Degrees cloud example honours and the - * one the cloud request engine builder reads by itself when no + * The cloud endpoint, taken from _51DEGREES_CLOUD_ENDPOINT when that is + * set, which is the variable every 51Degrees cloud example honours and + * the one the cloud request engine builder reads by itself when no * endpoint is given. A host other than cloud.51degrees.com would be * used to (a) use an on premise web server, or (b) use a privately * hosted version of the 51Degrees cloud for performance reasons,