VYPR
Moderate severityNVD Advisory· Published Feb 9, 2026· Updated Feb 10, 2026

unity-cli Exposes Plaintext Credentials in Debug Logs (sign-package command)

CVE-2026-25918

Description

unity-cli is a command line utility for the Unity Game Engine. Prior to 1.8.2 , the sign-package command in @rage-against-the-pixel/unity-cli logs sensitive credentials in plaintext when the --verbose flag is used. Command-line arguments including --email and --password are output via JSON.stringify without sanitization, exposing secrets to shell history, CI/CD logs, and log aggregation systems. This vulnerability is fixed in 1.8.2.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

unity-cli prior to 1.8.2 logs plaintext credentials (email, password) via JSON.stringify when --verbose is used, exposing secrets in logs.

Vulnerability

Description

The sign-package command in @rage-against-the-pixel/unity-cli (versions prior to 1.8.2) logs sensitive command-line arguments in plaintext when the --verbose flag is enabled. The debug output uses JSON.stringify(options) without sanitization, which includes the --email and --password parameters [1][2]. This exposes credentials directly to the console, shell history, CI/CD pipeline logs, and any log aggregation systems that capture the output.

Exploitation

An attacker does not need network access to exploit this vulnerability; it is a local information disclosure issue. However, in CI/CD environments where verbose logging is enabled for debugging, the credentials become visible in build logs, which are often stored and accessible to anyone with read access to the CI system. The vulnerability is triggered simply by running the affected command with the --verbose flag [2].

Impact

An attacker who gains access to the logged credentials can authenticate to Unity services (e.g., license activation, package signing) as the victim. This could lead to unauthorized use of Unity licenses, access to private packages, or other actions tied to the compromised account. The severity is elevated in automated pipelines where logs are retained and shared across teams.

Mitigation

The vulnerability is fixed in version 1.8.2. The commit [3] replaces JSON.stringify(options) with a custom debugOptions method that masks credentials, and adds explicit masking for email, password, and serial fields. Users should update to the latest version and avoid enabling verbose logging in production CI/CD workflows unless necessary [4].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@rage-against-the-pixel/unity-clinpm
< 1.8.21.8.2

Affected products

1
  • RageAgainstThePixel/unity-cliv5
    Range: < 1.8.2

Patches

1
8d4d67b23d7c

unity-cli@v1.8.2 (#67)

https://github.com/RageAgainstThePixel/unity-cliStephen HodgsonFeb 8, 2026via ghsa
7 files changed · +875 327
  • package.json+5 5 modified
    @@ -1,6 +1,6 @@
     {
       "name": "@rage-against-the-pixel/unity-cli",
    -  "version": "1.8.1",
    +  "version": "1.8.2",
       "description": "A command line utility for the Unity Game Engine.",
       "author": "RageAgainstThePixel",
       "license": "MIT",
    @@ -50,17 +50,17 @@
       "dependencies": {
         "@electron/asar": "^4.0.1",
         "@rage-against-the-pixel/unity-releases-api": "^1.0.4",
    -    "commander": "^14.0.2",
    +    "commander": "^14.0.3",
         "glob": "^11.1.0",
    -    "semver": "^7.7.3",
    +    "semver": "^7.7.4",
         "source-map-support": "^0.5.21",
    -    "tar": "^7.5.2",
    +    "tar": "^7.5.7",
         "update-notifier": "^7.3.1",
         "yaml": "^2.8.2"
       },
       "devDependencies": {
         "@types/jest": "^30.0.0",
    -    "@types/node": "^24.10.4",
    +    "@types/node": "^24.10.12",
         "@types/semver": "^7.7.1",
         "@types/update-notifier": "^6.0.8",
         "jest": "^30.2.0",
    
  • package-lock.json+399 310 modified
    @@ -1,21 +1,21 @@
     {
       "name": "@rage-against-the-pixel/unity-cli",
    -  "version": "1.8.1",
    +  "version": "1.8.2",
       "lockfileVersion": 3,
       "requires": true,
       "packages": {
         "": {
           "name": "@rage-against-the-pixel/unity-cli",
    -      "version": "1.8.1",
    +      "version": "1.8.2",
           "license": "MIT",
           "dependencies": {
             "@electron/asar": "^4.0.1",
             "@rage-against-the-pixel/unity-releases-api": "^1.0.4",
    -        "commander": "^14.0.2",
    +        "commander": "^14.0.3",
             "glob": "^11.1.0",
    -        "semver": "^7.7.3",
    +        "semver": "^7.7.4",
             "source-map-support": "^0.5.21",
    -        "tar": "^7.5.2",
    +        "tar": "^7.5.7",
             "update-notifier": "^7.3.1",
             "yaml": "^2.8.2"
           },
    @@ -24,7 +24,7 @@
           },
           "devDependencies": {
             "@types/jest": "^30.0.0",
    -        "@types/node": "^24.10.4",
    +        "@types/node": "^24.10.12",
             "@types/semver": "^7.7.1",
             "@types/update-notifier": "^6.0.8",
             "jest": "^30.2.0",
    @@ -34,13 +34,13 @@
           }
         },
         "node_modules/@babel/code-frame": {
    -      "version": "7.27.1",
    -      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
    -      "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
    +      "version": "7.29.0",
    +      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
    +      "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/helper-validator-identifier": "^7.27.1",
    +        "@babel/helper-validator-identifier": "^7.28.5",
             "js-tokens": "^4.0.0",
             "picocolors": "^1.1.1"
           },
    @@ -49,31 +49,31 @@
           }
         },
         "node_modules/@babel/compat-data": {
    -      "version": "7.28.5",
    -      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz",
    -      "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==",
    +      "version": "7.29.0",
    +      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
    +      "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
           "dev": true,
           "license": "MIT",
           "engines": {
             "node": ">=6.9.0"
           }
         },
         "node_modules/@babel/core": {
    -      "version": "7.28.5",
    -      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
    -      "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
    +      "version": "7.29.0",
    +      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
    +      "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/code-frame": "^7.27.1",
    -        "@babel/generator": "^7.28.5",
    -        "@babel/helper-compilation-targets": "^7.27.2",
    -        "@babel/helper-module-transforms": "^7.28.3",
    -        "@babel/helpers": "^7.28.4",
    -        "@babel/parser": "^7.28.5",
    -        "@babel/template": "^7.27.2",
    -        "@babel/traverse": "^7.28.5",
    -        "@babel/types": "^7.28.5",
    +        "@babel/code-frame": "^7.29.0",
    +        "@babel/generator": "^7.29.0",
    +        "@babel/helper-compilation-targets": "^7.28.6",
    +        "@babel/helper-module-transforms": "^7.28.6",
    +        "@babel/helpers": "^7.28.6",
    +        "@babel/parser": "^7.29.0",
    +        "@babel/template": "^7.28.6",
    +        "@babel/traverse": "^7.29.0",
    +        "@babel/types": "^7.29.0",
             "@jridgewell/remapping": "^2.3.5",
             "convert-source-map": "^2.0.0",
             "debug": "^4.1.0",
    @@ -100,14 +100,14 @@
           }
         },
         "node_modules/@babel/generator": {
    -      "version": "7.28.5",
    -      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz",
    -      "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==",
    +      "version": "7.29.1",
    +      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
    +      "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/parser": "^7.28.5",
    -        "@babel/types": "^7.28.5",
    +        "@babel/parser": "^7.29.0",
    +        "@babel/types": "^7.29.0",
             "@jridgewell/gen-mapping": "^0.3.12",
             "@jridgewell/trace-mapping": "^0.3.28",
             "jsesc": "^3.0.2"
    @@ -117,13 +117,13 @@
           }
         },
         "node_modules/@babel/helper-compilation-targets": {
    -      "version": "7.27.2",
    -      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
    -      "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
    +      "version": "7.28.6",
    +      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
    +      "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/compat-data": "^7.27.2",
    +        "@babel/compat-data": "^7.28.6",
             "@babel/helper-validator-option": "^7.27.1",
             "browserslist": "^4.24.0",
             "lru-cache": "^5.1.1",
    @@ -154,29 +154,29 @@
           }
         },
         "node_modules/@babel/helper-module-imports": {
    -      "version": "7.27.1",
    -      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
    -      "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
    +      "version": "7.28.6",
    +      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
    +      "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/traverse": "^7.27.1",
    -        "@babel/types": "^7.27.1"
    +        "@babel/traverse": "^7.28.6",
    +        "@babel/types": "^7.28.6"
           },
           "engines": {
             "node": ">=6.9.0"
           }
         },
         "node_modules/@babel/helper-module-transforms": {
    -      "version": "7.28.3",
    -      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
    -      "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
    +      "version": "7.28.6",
    +      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
    +      "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/helper-module-imports": "^7.27.1",
    -        "@babel/helper-validator-identifier": "^7.27.1",
    -        "@babel/traverse": "^7.28.3"
    +        "@babel/helper-module-imports": "^7.28.6",
    +        "@babel/helper-validator-identifier": "^7.28.5",
    +        "@babel/traverse": "^7.28.6"
           },
           "engines": {
             "node": ">=6.9.0"
    @@ -186,9 +186,9 @@
           }
         },
         "node_modules/@babel/helper-plugin-utils": {
    -      "version": "7.27.1",
    -      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
    -      "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
    +      "version": "7.28.6",
    +      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
    +      "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
           "dev": true,
           "license": "MIT",
           "engines": {
    @@ -226,27 +226,27 @@
           }
         },
         "node_modules/@babel/helpers": {
    -      "version": "7.28.4",
    -      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
    -      "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
    +      "version": "7.28.6",
    +      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
    +      "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/template": "^7.27.2",
    -        "@babel/types": "^7.28.4"
    +        "@babel/template": "^7.28.6",
    +        "@babel/types": "^7.28.6"
           },
           "engines": {
             "node": ">=6.9.0"
           }
         },
         "node_modules/@babel/parser": {
    -      "version": "7.28.5",
    -      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
    -      "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
    +      "version": "7.29.0",
    +      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
    +      "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/types": "^7.28.5"
    +        "@babel/types": "^7.29.0"
           },
           "bin": {
             "parser": "bin/babel-parser.js"
    @@ -311,13 +311,13 @@
           }
         },
         "node_modules/@babel/plugin-syntax-import-attributes": {
    -      "version": "7.27.1",
    -      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz",
    -      "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==",
    +      "version": "7.28.6",
    +      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz",
    +      "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/helper-plugin-utils": "^7.27.1"
    +        "@babel/helper-plugin-utils": "^7.28.6"
           },
           "engines": {
             "node": ">=6.9.0"
    @@ -353,13 +353,13 @@
           }
         },
         "node_modules/@babel/plugin-syntax-jsx": {
    -      "version": "7.27.1",
    -      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz",
    -      "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==",
    +      "version": "7.28.6",
    +      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz",
    +      "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/helper-plugin-utils": "^7.27.1"
    +        "@babel/helper-plugin-utils": "^7.28.6"
           },
           "engines": {
             "node": ">=6.9.0"
    @@ -479,13 +479,13 @@
           }
         },
         "node_modules/@babel/plugin-syntax-typescript": {
    -      "version": "7.27.1",
    -      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz",
    -      "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==",
    +      "version": "7.28.6",
    +      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz",
    +      "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/helper-plugin-utils": "^7.27.1"
    +        "@babel/helper-plugin-utils": "^7.28.6"
           },
           "engines": {
             "node": ">=6.9.0"
    @@ -495,43 +495,43 @@
           }
         },
         "node_modules/@babel/template": {
    -      "version": "7.27.2",
    -      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
    -      "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
    +      "version": "7.28.6",
    +      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
    +      "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/code-frame": "^7.27.1",
    -        "@babel/parser": "^7.27.2",
    -        "@babel/types": "^7.27.1"
    +        "@babel/code-frame": "^7.28.6",
    +        "@babel/parser": "^7.28.6",
    +        "@babel/types": "^7.28.6"
           },
           "engines": {
             "node": ">=6.9.0"
           }
         },
         "node_modules/@babel/traverse": {
    -      "version": "7.28.5",
    -      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz",
    -      "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==",
    +      "version": "7.29.0",
    +      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
    +      "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    -        "@babel/code-frame": "^7.27.1",
    -        "@babel/generator": "^7.28.5",
    +        "@babel/code-frame": "^7.29.0",
    +        "@babel/generator": "^7.29.0",
             "@babel/helper-globals": "^7.28.0",
    -        "@babel/parser": "^7.28.5",
    -        "@babel/template": "^7.27.2",
    -        "@babel/types": "^7.28.5",
    +        "@babel/parser": "^7.29.0",
    +        "@babel/template": "^7.28.6",
    +        "@babel/types": "^7.29.0",
             "debug": "^4.3.1"
           },
           "engines": {
             "node": ">=6.9.0"
           }
         },
         "node_modules/@babel/types": {
    -      "version": "7.28.5",
    -      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
    -      "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
    +      "version": "7.29.0",
    +      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
    +      "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    @@ -600,9 +600,9 @@
           }
         },
         "node_modules/@emnapi/core": {
    -      "version": "1.7.1",
    -      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz",
    -      "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==",
    +      "version": "1.8.1",
    +      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz",
    +      "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==",
           "dev": true,
           "license": "MIT",
           "optional": true,
    @@ -612,9 +612,9 @@
           }
         },
         "node_modules/@emnapi/runtime": {
    -      "version": "1.7.1",
    -      "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz",
    -      "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==",
    +      "version": "1.8.1",
    +      "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
    +      "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
           "dev": true,
           "license": "MIT",
           "optional": true,
    @@ -643,9 +643,9 @@
           }
         },
         "node_modules/@isaacs/brace-expansion": {
    -      "version": "5.0.0",
    -      "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
    -      "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
    +      "version": "5.0.1",
    +      "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz",
    +      "integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==",
           "license": "MIT",
           "dependencies": {
             "@isaacs/balanced-match": "^4.0.1"
    @@ -655,20 +655,12 @@
           }
         },
         "node_modules/@isaacs/cliui": {
    -      "version": "8.0.2",
    -      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
    -      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
    -      "license": "ISC",
    -      "dependencies": {
    -        "string-width": "^5.1.2",
    -        "string-width-cjs": "npm:string-width@^4.2.0",
    -        "strip-ansi": "^7.0.1",
    -        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
    -        "wrap-ansi": "^8.1.0",
    -        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
    -      },
    +      "version": "9.0.0",
    +      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
    +      "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==",
    +      "license": "BlueOak-1.0.0",
           "engines": {
    -        "node": ">=12"
    +        "node": ">=18"
           }
         },
         "node_modules/@isaacs/fs-minipass": {
    @@ -1006,6 +998,37 @@
             }
           }
         },
    +    "node_modules/@jest/reporters/node_modules/@isaacs/cliui": {
    +      "version": "8.0.2",
    +      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
    +      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
    +      "dev": true,
    +      "license": "ISC",
    +      "dependencies": {
    +        "string-width": "^5.1.2",
    +        "string-width-cjs": "npm:string-width@^4.2.0",
    +        "strip-ansi": "^7.0.1",
    +        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
    +        "wrap-ansi": "^8.1.0",
    +        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
    +      },
    +      "engines": {
    +        "node": ">=12"
    +      }
    +    },
    +    "node_modules/@jest/reporters/node_modules/ansi-regex": {
    +      "version": "6.2.2",
    +      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
    +      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
    +      "dev": true,
    +      "license": "MIT",
    +      "engines": {
    +        "node": ">=12"
    +      },
    +      "funding": {
    +        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
    +      }
    +    },
         "node_modules/@jest/reporters/node_modules/ansi-styles": {
           "version": "4.3.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
    @@ -1043,6 +1066,7 @@
           "version": "10.5.0",
           "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
           "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
    +      "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
           "dev": true,
           "license": "ISC",
           "dependencies": {
    @@ -1116,6 +1140,22 @@
             "url": "https://github.com/sponsors/isaacs"
           }
         },
    +    "node_modules/@jest/reporters/node_modules/strip-ansi": {
    +      "version": "7.1.2",
    +      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
    +      "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
    +      "dev": true,
    +      "license": "MIT",
    +      "dependencies": {
    +        "ansi-regex": "^6.0.1"
    +      },
    +      "engines": {
    +        "node": ">=12"
    +      },
    +      "funding": {
    +        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
    +      }
    +    },
         "node_modules/@jest/schemas": {
           "version": "30.0.5",
           "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
    @@ -1452,9 +1492,9 @@
           "license": "ISC"
         },
         "node_modules/@pnpm/npm-conf": {
    -      "version": "2.3.1",
    -      "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz",
    -      "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==",
    +      "version": "3.0.2",
    +      "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.2.tgz",
    +      "integrity": "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA==",
           "license": "MIT",
           "dependencies": {
             "@pnpm/config.env-replace": "^1.1.0",
    @@ -1475,9 +1515,9 @@
           }
         },
         "node_modules/@sinclair/typebox": {
    -      "version": "0.34.41",
    -      "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz",
    -      "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==",
    +      "version": "0.34.48",
    +      "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz",
    +      "integrity": "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==",
           "dev": true,
           "license": "MIT"
         },
    @@ -1631,9 +1671,9 @@
           }
         },
         "node_modules/@types/node": {
    -      "version": "24.10.4",
    -      "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.4.tgz",
    -      "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==",
    +      "version": "24.10.12",
    +      "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.12.tgz",
    +      "integrity": "sha512-68e+T28EbdmLSTkPgs3+UacC6rzmqrcWFPQs1C8mwJhI/r5Uxr0yEuQotczNRROd1gq30NGxee+fo0rSIxpyAw==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    @@ -1993,15 +2033,6 @@
             "string-width": "^4.1.0"
           }
         },
    -    "node_modules/ansi-align/node_modules/ansi-regex": {
    -      "version": "5.0.1",
    -      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
    -      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
    -      "license": "MIT",
    -      "engines": {
    -        "node": ">=8"
    -      }
    -    },
         "node_modules/ansi-align/node_modules/emoji-regex": {
           "version": "8.0.0",
           "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
    @@ -2022,18 +2053,6 @@
             "node": ">=8"
           }
         },
    -    "node_modules/ansi-align/node_modules/strip-ansi": {
    -      "version": "6.0.1",
    -      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
    -      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
    -      "license": "MIT",
    -      "dependencies": {
    -        "ansi-regex": "^5.0.1"
    -      },
    -      "engines": {
    -        "node": ">=8"
    -      }
    -    },
         "node_modules/ansi-escapes": {
           "version": "4.3.2",
           "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
    @@ -2064,15 +2083,12 @@
           }
         },
         "node_modules/ansi-regex": {
    -      "version": "6.2.2",
    -      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
    -      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
    +      "version": "5.0.1",
    +      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
    +      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
           "license": "MIT",
           "engines": {
    -        "node": ">=12"
    -      },
    -      "funding": {
    -        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
    +        "node": ">=8"
           }
         },
         "node_modules/ansi-styles": {
    @@ -2269,9 +2285,9 @@
           "license": "MIT"
         },
         "node_modules/baseline-browser-mapping": {
    -      "version": "2.9.7",
    -      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.7.tgz",
    -      "integrity": "sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==",
    +      "version": "2.9.19",
    +      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz",
    +      "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==",
           "dev": true,
           "license": "Apache-2.0",
           "bin": {
    @@ -2411,9 +2427,9 @@
           }
         },
         "node_modules/caniuse-lite": {
    -      "version": "1.0.30001760",
    -      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz",
    -      "integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==",
    +      "version": "1.0.30001769",
    +      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz",
    +      "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==",
           "dev": true,
           "funding": [
             {
    @@ -2463,9 +2479,9 @@
           }
         },
         "node_modules/ci-info": {
    -      "version": "4.3.1",
    -      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz",
    -      "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==",
    +      "version": "4.4.0",
    +      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz",
    +      "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==",
           "dev": true,
           "funding": [
             {
    @@ -2479,9 +2495,9 @@
           }
         },
         "node_modules/cjs-module-lexer": {
    -      "version": "2.1.1",
    -      "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz",
    -      "integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==",
    +      "version": "2.2.0",
    +      "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz",
    +      "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==",
           "dev": true,
           "license": "MIT"
         },
    @@ -2512,16 +2528,6 @@
             "node": ">=12"
           }
         },
    -    "node_modules/cliui/node_modules/ansi-regex": {
    -      "version": "5.0.1",
    -      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
    -      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
    -      "dev": true,
    -      "license": "MIT",
    -      "engines": {
    -        "node": ">=8"
    -      }
    -    },
         "node_modules/cliui/node_modules/ansi-styles": {
           "version": "4.3.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
    @@ -2560,19 +2566,6 @@
             "node": ">=8"
           }
         },
    -    "node_modules/cliui/node_modules/strip-ansi": {
    -      "version": "6.0.1",
    -      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
    -      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "ansi-regex": "^5.0.1"
    -      },
    -      "engines": {
    -        "node": ">=8"
    -      }
    -    },
         "node_modules/cliui/node_modules/wrap-ansi": {
           "version": "7.0.0",
           "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
    @@ -2613,6 +2606,7 @@
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
           "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
    +      "dev": true,
           "license": "MIT",
           "dependencies": {
             "color-name": "~1.1.4"
    @@ -2625,12 +2619,13 @@
           "version": "1.1.4",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
           "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
    +      "dev": true,
           "license": "MIT"
         },
         "node_modules/commander": {
    -      "version": "14.0.2",
    -      "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz",
    -      "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==",
    +      "version": "14.0.3",
    +      "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
    +      "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
           "license": "MIT",
           "engines": {
             "node": ">=20"
    @@ -2724,9 +2719,9 @@
           }
         },
         "node_modules/dedent": {
    -      "version": "1.7.0",
    -      "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz",
    -      "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==",
    +      "version": "1.7.1",
    +      "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz",
    +      "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==",
           "dev": true,
           "license": "MIT",
           "peerDependencies": {
    @@ -2768,9 +2763,9 @@
           }
         },
         "node_modules/diff": {
    -      "version": "4.0.2",
    -      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
    -      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
    +      "version": "4.0.4",
    +      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz",
    +      "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==",
           "dev": true,
           "license": "BSD-3-Clause",
           "engines": {
    @@ -2808,12 +2803,13 @@
           "version": "0.2.0",
           "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
           "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
    +      "dev": true,
           "license": "MIT"
         },
         "node_modules/electron-to-chromium": {
    -      "version": "1.5.267",
    -      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz",
    -      "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==",
    +      "version": "1.5.286",
    +      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
    +      "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==",
           "dev": true,
           "license": "ISC"
         },
    @@ -2834,6 +2830,7 @@
           "version": "9.2.2",
           "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
           "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
    +      "dev": true,
           "license": "MIT"
         },
         "node_modules/error-ex": {
    @@ -3092,6 +3089,7 @@
           "version": "11.1.0",
           "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz",
           "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==",
    +      "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
           "license": "BlueOak-1.0.0",
           "dependencies": {
             "foreground-child": "^3.3.1",
    @@ -3421,12 +3419,12 @@
           }
         },
         "node_modules/jackspeak": {
    -      "version": "4.1.1",
    -      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz",
    -      "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==",
    +      "version": "4.2.3",
    +      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz",
    +      "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==",
           "license": "BlueOak-1.0.0",
           "dependencies": {
    -        "@isaacs/cliui": "^8.0.2"
    +        "@isaacs/cliui": "^9.0.0"
           },
           "engines": {
             "node": "20 || >=22"
    @@ -3660,6 +3658,37 @@
             }
           }
         },
    +    "node_modules/jest-config/node_modules/@isaacs/cliui": {
    +      "version": "8.0.2",
    +      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
    +      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
    +      "dev": true,
    +      "license": "ISC",
    +      "dependencies": {
    +        "string-width": "^5.1.2",
    +        "string-width-cjs": "npm:string-width@^4.2.0",
    +        "strip-ansi": "^7.0.1",
    +        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
    +        "wrap-ansi": "^8.1.0",
    +        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
    +      },
    +      "engines": {
    +        "node": ">=12"
    +      }
    +    },
    +    "node_modules/jest-config/node_modules/ansi-regex": {
    +      "version": "6.2.2",
    +      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
    +      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
    +      "dev": true,
    +      "license": "MIT",
    +      "engines": {
    +        "node": ">=12"
    +      },
    +      "funding": {
    +        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
    +      }
    +    },
         "node_modules/jest-config/node_modules/ansi-styles": {
           "version": "4.3.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
    @@ -3697,6 +3726,7 @@
           "version": "10.5.0",
           "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
           "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
    +      "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
           "dev": true,
           "license": "ISC",
           "dependencies": {
    @@ -3770,6 +3800,22 @@
             "url": "https://github.com/sponsors/isaacs"
           }
         },
    +    "node_modules/jest-config/node_modules/strip-ansi": {
    +      "version": "7.1.2",
    +      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
    +      "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
    +      "dev": true,
    +      "license": "MIT",
    +      "dependencies": {
    +        "ansi-regex": "^6.0.1"
    +      },
    +      "engines": {
    +        "node": ">=12"
    +      },
    +      "funding": {
    +        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
    +      }
    +    },
         "node_modules/jest-diff": {
           "version": "30.2.0",
           "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz",
    @@ -4265,6 +4311,37 @@
             "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
           }
         },
    +    "node_modules/jest-runtime/node_modules/@isaacs/cliui": {
    +      "version": "8.0.2",
    +      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
    +      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
    +      "dev": true,
    +      "license": "ISC",
    +      "dependencies": {
    +        "string-width": "^5.1.2",
    +        "string-width-cjs": "npm:string-width@^4.2.0",
    +        "strip-ansi": "^7.0.1",
    +        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
    +        "wrap-ansi": "^8.1.0",
    +        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
    +      },
    +      "engines": {
    +        "node": ">=12"
    +      }
    +    },
    +    "node_modules/jest-runtime/node_modules/ansi-regex": {
    +      "version": "6.2.2",
    +      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
    +      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
    +      "dev": true,
    +      "license": "MIT",
    +      "engines": {
    +        "node": ">=12"
    +      },
    +      "funding": {
    +        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
    +      }
    +    },
         "node_modules/jest-runtime/node_modules/ansi-styles": {
           "version": "4.3.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
    @@ -4302,6 +4379,7 @@
           "version": "10.5.0",
           "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
           "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
    +      "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
           "dev": true,
           "license": "ISC",
           "dependencies": {
    @@ -4375,6 +4453,22 @@
             "url": "https://github.com/sponsors/isaacs"
           }
         },
    +    "node_modules/jest-runtime/node_modules/strip-ansi": {
    +      "version": "7.1.2",
    +      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
    +      "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
    +      "dev": true,
    +      "license": "MIT",
    +      "dependencies": {
    +        "ansi-regex": "^6.0.1"
    +      },
    +      "engines": {
    +        "node": ">=12"
    +      },
    +      "funding": {
    +        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
    +      }
    +    },
         "node_modules/jest-snapshot": {
           "version": "30.2.0",
           "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz",
    @@ -4719,9 +4813,9 @@
           }
         },
         "node_modules/ky": {
    -      "version": "1.14.1",
    -      "resolved": "https://registry.npmjs.org/ky/-/ky-1.14.1.tgz",
    -      "integrity": "sha512-hYje4L9JCmpEQBtudo+v52X5X8tgWXUYyPcxKSuxQNboqufecl9VMWjGiucAFH060AwPXHZuH+WB2rrqfkmafw==",
    +      "version": "1.14.3",
    +      "resolved": "https://registry.npmjs.org/ky/-/ky-1.14.3.tgz",
    +      "integrity": "sha512-9zy9lkjac+TR1c2tG+mkNSVlyOpInnWdSMiue4F+kq8TwJSgv6o8jhLRg8Ho6SnZ9wOYUq/yozts9qQCfk7bIw==",
           "license": "MIT",
           "engines": {
             "node": ">=18"
    @@ -4857,12 +4951,12 @@
           }
         },
         "node_modules/minimatch": {
    -      "version": "10.1.1",
    -      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz",
    -      "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==",
    +      "version": "10.1.2",
    +      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz",
    +      "integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==",
           "license": "BlueOak-1.0.0",
           "dependencies": {
    -        "@isaacs/brace-expansion": "^5.0.0"
    +        "@isaacs/brace-expansion": "^5.0.1"
           },
           "engines": {
             "node": "20 || >=22"
    @@ -5145,9 +5239,9 @@
           }
         },
         "node_modules/path-scurry/node_modules/lru-cache": {
    -      "version": "11.2.4",
    -      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz",
    -      "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==",
    +      "version": "11.2.5",
    +      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz",
    +      "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==",
           "license": "BlueOak-1.0.0",
           "engines": {
             "node": "20 || >=22"
    @@ -5287,12 +5381,12 @@
           "license": "MIT"
         },
         "node_modules/registry-auth-token": {
    -      "version": "5.1.0",
    -      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz",
    -      "integrity": "sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==",
    +      "version": "5.1.1",
    +      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.1.tgz",
    +      "integrity": "sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q==",
           "license": "MIT",
           "dependencies": {
    -        "@pnpm/npm-conf": "^2.1.0"
    +        "@pnpm/npm-conf": "^3.0.2"
           },
           "engines": {
             "node": ">=14"
    @@ -5347,9 +5441,9 @@
           }
         },
         "node_modules/semver": {
    -      "version": "7.7.3",
    -      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
    -      "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
    +      "version": "7.7.4",
    +      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
    +      "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
           "license": "ISC",
           "bin": {
             "semver": "bin/semver.js"
    @@ -5454,33 +5548,11 @@
             "node": ">=10"
           }
         },
    -    "node_modules/string-length/node_modules/ansi-regex": {
    -      "version": "5.0.1",
    -      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
    -      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
    -      "dev": true,
    -      "license": "MIT",
    -      "engines": {
    -        "node": ">=8"
    -      }
    -    },
    -    "node_modules/string-length/node_modules/strip-ansi": {
    -      "version": "6.0.1",
    -      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
    -      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "ansi-regex": "^5.0.1"
    -      },
    -      "engines": {
    -        "node": ">=8"
    -      }
    -    },
         "node_modules/string-width": {
           "version": "5.1.2",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
           "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
    +      "dev": true,
           "license": "MIT",
           "dependencies": {
             "eastasianwidth": "^0.2.0",
    @@ -5499,6 +5571,7 @@
           "version": "4.2.3",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
           "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
    +      "dev": true,
           "license": "MIT",
           "dependencies": {
             "emoji-regex": "^8.0.0",
    @@ -5509,37 +5582,31 @@
             "node": ">=8"
           }
         },
    -    "node_modules/string-width-cjs/node_modules/ansi-regex": {
    -      "version": "5.0.1",
    -      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
    -      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
    -      "license": "MIT",
    -      "engines": {
    -        "node": ">=8"
    -      }
    -    },
         "node_modules/string-width-cjs/node_modules/emoji-regex": {
           "version": "8.0.0",
           "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
           "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
    +      "dev": true,
           "license": "MIT"
         },
    -    "node_modules/string-width-cjs/node_modules/strip-ansi": {
    -      "version": "6.0.1",
    -      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
    -      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
    +    "node_modules/string-width/node_modules/ansi-regex": {
    +      "version": "6.2.2",
    +      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
    +      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
    +      "dev": true,
           "license": "MIT",
    -      "dependencies": {
    -        "ansi-regex": "^5.0.1"
    -      },
           "engines": {
    -        "node": ">=8"
    +        "node": ">=12"
    +      },
    +      "funding": {
    +        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
           }
         },
    -    "node_modules/strip-ansi": {
    +    "node_modules/string-width/node_modules/strip-ansi": {
           "version": "7.1.2",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
           "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
    +      "dev": true,
           "license": "MIT",
           "dependencies": {
             "ansi-regex": "^6.0.1"
    @@ -5551,8 +5618,7 @@
             "url": "https://github.com/chalk/strip-ansi?sponsor=1"
           }
         },
    -    "node_modules/strip-ansi-cjs": {
    -      "name": "strip-ansi",
    +    "node_modules/strip-ansi": {
           "version": "6.0.1",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
           "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
    @@ -5564,11 +5630,16 @@
             "node": ">=8"
           }
         },
    -    "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
    -      "version": "5.0.1",
    -      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
    -      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
    +    "node_modules/strip-ansi-cjs": {
    +      "name": "strip-ansi",
    +      "version": "6.0.1",
    +      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
    +      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
    +      "dev": true,
           "license": "MIT",
    +      "dependencies": {
    +        "ansi-regex": "^5.0.1"
    +      },
           "engines": {
             "node": ">=8"
           }
    @@ -5635,9 +5706,9 @@
           }
         },
         "node_modules/synckit": {
    -      "version": "0.11.11",
    -      "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
    -      "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
    +      "version": "0.11.12",
    +      "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz",
    +      "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==",
           "dev": true,
           "license": "MIT",
           "dependencies": {
    @@ -5651,9 +5722,9 @@
           }
         },
         "node_modules/tar": {
    -      "version": "7.5.2",
    -      "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz",
    -      "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==",
    +      "version": "7.5.7",
    +      "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz",
    +      "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==",
           "license": "BlueOak-1.0.0",
           "dependencies": {
             "@isaacs/fs-minipass": "^4.0.0",
    @@ -5705,7 +5776,7 @@
           "version": "7.2.3",
           "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
           "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
    -      "deprecated": "Glob versions prior to v9 are no longer supported",
    +      "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
           "dev": true,
           "license": "ISC",
           "dependencies": {
    @@ -5968,9 +6039,9 @@
           }
         },
         "node_modules/update-browserslist-db": {
    -      "version": "1.2.2",
    -      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz",
    -      "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==",
    +      "version": "1.2.3",
    +      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
    +      "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
           "dev": true,
           "funding": [
             {
    @@ -6022,6 +6093,18 @@
             "url": "https://github.com/yeoman/update-notifier?sponsor=1"
           }
         },
    +    "node_modules/update-notifier/node_modules/ansi-regex": {
    +      "version": "6.2.2",
    +      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
    +      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
    +      "license": "MIT",
    +      "engines": {
    +        "node": ">=12"
    +      },
    +      "funding": {
    +        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
    +      }
    +    },
         "node_modules/update-notifier/node_modules/ansi-styles": {
           "version": "6.2.3",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
    @@ -6091,6 +6174,21 @@
             "url": "https://github.com/sponsors/sindresorhus"
           }
         },
    +    "node_modules/update-notifier/node_modules/strip-ansi": {
    +      "version": "7.1.2",
    +      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
    +      "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
    +      "license": "MIT",
    +      "dependencies": {
    +        "ansi-regex": "^6.0.1"
    +      },
    +      "engines": {
    +        "node": ">=12"
    +      },
    +      "funding": {
    +        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
    +      }
    +    },
         "node_modules/update-notifier/node_modules/type-fest": {
           "version": "4.41.0",
           "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
    @@ -6215,6 +6313,7 @@
           "version": "8.1.0",
           "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
           "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
    +      "dev": true,
           "license": "MIT",
           "dependencies": {
             "ansi-styles": "^6.1.0",
    @@ -6233,6 +6332,7 @@
           "version": "7.0.0",
           "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
           "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
    +      "dev": true,
           "license": "MIT",
           "dependencies": {
             "ansi-styles": "^4.0.0",
    @@ -6246,19 +6346,11 @@
             "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
           }
         },
    -    "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
    -      "version": "5.0.1",
    -      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
    -      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
    -      "license": "MIT",
    -      "engines": {
    -        "node": ">=8"
    -      }
    -    },
         "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
           "version": "4.3.0",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
           "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
    +      "dev": true,
           "license": "MIT",
           "dependencies": {
             "color-convert": "^2.0.1"
    @@ -6274,12 +6366,14 @@
           "version": "8.0.0",
           "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
           "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
    +      "dev": true,
           "license": "MIT"
         },
         "node_modules/wrap-ansi-cjs/node_modules/string-width": {
           "version": "4.2.3",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
           "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
    +      "dev": true,
           "license": "MIT",
           "dependencies": {
             "emoji-regex": "^8.0.0",
    @@ -6290,22 +6384,24 @@
             "node": ">=8"
           }
         },
    -    "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
    -      "version": "6.0.1",
    -      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
    -      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
    +    "node_modules/wrap-ansi/node_modules/ansi-regex": {
    +      "version": "6.2.2",
    +      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
    +      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
    +      "dev": true,
           "license": "MIT",
    -      "dependencies": {
    -        "ansi-regex": "^5.0.1"
    -      },
           "engines": {
    -        "node": ">=8"
    +        "node": ">=12"
    +      },
    +      "funding": {
    +        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
           }
         },
         "node_modules/wrap-ansi/node_modules/ansi-styles": {
           "version": "6.2.3",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
           "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
    +      "dev": true,
           "license": "MIT",
           "engines": {
             "node": ">=12"
    @@ -6314,6 +6410,22 @@
             "url": "https://github.com/chalk/ansi-styles?sponsor=1"
           }
         },
    +    "node_modules/wrap-ansi/node_modules/strip-ansi": {
    +      "version": "7.1.2",
    +      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
    +      "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
    +      "dev": true,
    +      "license": "MIT",
    +      "dependencies": {
    +        "ansi-regex": "^6.0.1"
    +      },
    +      "engines": {
    +        "node": ">=12"
    +      },
    +      "funding": {
    +        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
    +      }
    +    },
         "node_modules/wrappy": {
           "version": "1.0.2",
           "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
    @@ -6408,16 +6520,6 @@
             "node": ">=12"
           }
         },
    -    "node_modules/yargs/node_modules/ansi-regex": {
    -      "version": "5.0.1",
    -      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
    -      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
    -      "dev": true,
    -      "license": "MIT",
    -      "engines": {
    -        "node": ">=8"
    -      }
    -    },
         "node_modules/yargs/node_modules/emoji-regex": {
           "version": "8.0.0",
           "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
    @@ -6440,19 +6542,6 @@
             "node": ">=8"
           }
         },
    -    "node_modules/yargs/node_modules/strip-ansi": {
    -      "version": "6.0.1",
    -      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
    -      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "ansi-regex": "^5.0.1"
    -      },
    -      "engines": {
    -        "node": ">=8"
    -      }
    -    },
         "node_modules/yn": {
           "version": "3.1.1",
           "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
    
  • src/cli.ts+24 11 modified
    @@ -50,7 +50,7 @@ program.command('activate-license')
                 Logger.instance.logLevel = LogLevel.DEBUG;
             }
     
    -        Logger.instance.debug(JSON.stringify(options));
    +        Logger.instance.debugOptions(options);
     
             const client = new LicensingClient();
             const licenseStr: string = options.license?.toString()?.trim();
    @@ -79,6 +79,11 @@ program.command('activate-license')
                 if (licenseType === LicenseType.professional && !options.serial) {
                     options.serial = await PromptForSecretInput('Serial: ');
                 }
    +
    +            // Mask credentials in CI environments before any potential logging
    +            Logger.instance.maskCredential(options.email);
    +            Logger.instance.maskCredential(options.password);
    +            Logger.instance.maskCredential(options.serial);
             }
     
             const token = await client.Activate({
    @@ -106,7 +111,7 @@ program.command('return-license')
                 Logger.instance.logLevel = LogLevel.DEBUG;
             }
     
    -        Logger.instance.debug(JSON.stringify(options));
    +        Logger.instance.debugOptions(options);
     
             const client = new LicensingClient();
             const licenseStr: string = options.license?.toString()?.trim();
    @@ -134,6 +139,9 @@ program.command('return-license')
                     Logger.instance.error('Token is required when returning a floating license. Use -t or --token to specify it.');
                     process.exit(1);
                 }
    +
    +            // Mask token in CI environments before any potential logging
    +            Logger.instance.maskCredential(token);
             }
     
             await client.Deactivate(licenseType, token);
    @@ -220,7 +228,7 @@ program.command('hub-install')
                 Logger.instance.logLevel = LogLevel.DEBUG;
             }
     
    -        Logger.instance.debug(JSON.stringify(options));
    +        Logger.instance.debugOptions(options);
     
             if (options.autoUpdate === true && options.hubVersion) {
                 Logger.instance.error('Cannot use --auto-update with --hub-version.');
    @@ -252,7 +260,7 @@ program.command('hub')
                 Logger.instance.logLevel = LogLevel.DEBUG;
             }
     
    -        Logger.instance.debug(JSON.stringify({ args, options }));
    +        Logger.instance.debugOptions({ args, options });
     
             const unityHub = new UnityHub();
             const output = await unityHub.Exec(args, { silent: false, showCommand: Logger.instance.logLevel === LogLevel.DEBUG });
    @@ -280,7 +288,7 @@ program.command('setup-unity')
                 Logger.instance.logLevel = LogLevel.DEBUG;
             }
     
    -        Logger.instance.debug(JSON.stringify(options));
    +        Logger.instance.debugOptions(options);
     
             let unityProject: UnityProject | undefined;
     
    @@ -373,7 +381,7 @@ program.command('uninstall-unity')
                 Logger.instance.logLevel = LogLevel.DEBUG;
             }
     
    -        Logger.instance.debug(JSON.stringify(options));
    +        Logger.instance.debugOptions(options);
     
             let unityEditor: UnityEditor | undefined;
             const unityVersionStr = options.unityVersion?.toString()?.trim();
    @@ -472,7 +480,7 @@ program.command('run')
                 Logger.instance.logLevel = requestedLogLevel;
             }
     
    -        Logger.instance.debug(JSON.stringify({ options, args }));
    +        Logger.instance.debugOptions({ options, args });
     
             let unityEditor: UnityEditor | undefined;
             const editorPath = options.unityEditor?.toString()?.trim() || process.env.UNITY_EDITOR_PATH || undefined;
    @@ -540,7 +548,7 @@ program.command('list-project-templates')
                 Logger.instance.logLevel = LogLevel.DEBUG;
             }
     
    -        Logger.instance.debug(JSON.stringify(options));
    +        Logger.instance.debugOptions(options);
     
             const unityVersionStr = options.unityVersion?.toString()?.trim();
     
    @@ -593,7 +601,7 @@ program.command('create-project')
                 Logger.instance.logLevel = LogLevel.DEBUG;
             }
     
    -        Logger.instance.debug(JSON.stringify(options));
    +        Logger.instance.debugOptions(options);
     
             const unityVersionStr = options.unityVersion?.toString()?.trim();
     
    @@ -665,7 +673,7 @@ program.command('open-project')
                 Logger.instance.logLevel = LogLevel.DEBUG;
             }
     
    -        Logger.instance.debug(JSON.stringify(options));
    +        Logger.instance.debugOptions(options);
             const projectPath = options.unityProject?.toString()?.trim() || process.env.UNITY_PROJECT_PATH || undefined;
             const unityProject = await UnityProject.GetProject(projectPath);
     
    @@ -731,7 +739,7 @@ program.command('sign-package')
                 Logger.instance.logLevel = LogLevel.DEBUG;
             }
     
    -        Logger.instance.debug(JSON.stringify(options));
    +        Logger.instance.debugOptions(options);
     
             const packagePath = path.normalize(options.package?.toString()?.trim());
     
    @@ -796,6 +804,11 @@ program.command('sign-package')
                 process.exit(1);
             }
     
    +        // Mask credentials in CI environments before any potential logging
    +        Logger.instance.maskCredential(username);
    +        Logger.instance.maskCredential(password);
    +        Logger.instance.maskCredential(organization);
    +
             // must use a unity editor 6000.3 or newer
             const unityVersion = new UnityVersion('6000.3');
             const unityHub = new UnityHub();
    
  • src/logging.ts+81 0 modified
    @@ -225,6 +225,87 @@ export class Logger {
             }
         }
     
    +    /**
    +     * Masks a credential value in CI environments before it appears in logs.
    +     * This is a convenience wrapper around CI_mask for credential values.
    +     * @param value The credential value to mask.
    +     */
    +    public maskCredential(value: string | undefined): void {
    +        if (value && value.length > 0) {
    +            this.CI_mask(value);
    +        }
    +    }
    +
    +    /**
    +     * Logs command-line options with sensitive information scrubbed.
    +     * Automatically removes passwords, tokens, emails, and other credentials from the output.
    +     * @param options The options object to log (typically from commander.js).
    +     * @param optionalParams Additional parameters to log.
    +     */
    +    public debugOptions(options: any, ...optionalParams: any[]): void {
    +        // Avoid expensive scrubbing and stringification when debug logging is disabled.
    +        if (this.logLevel !== LogLevel.DEBUG) {
    +            return;
    +        }
    +        const scrubbed = this.scrubSensitiveData(options);
    +        this.debug(JSON.stringify(scrubbed), ...optionalParams);
    +    }
    +
    +    /**
    +     * List of sensitive option keys that should be scrubbed from debug output.
    +     */
    +    private readonly SENSITIVE_KEYS = [
    +        'password',
    +        'email',
    +        'serial',
    +        'token',
    +        'config',
    +        'organization',
    +        'username',
    +        'servicesConfig'
    +    ];
    +
    +    /**
    +     * Scrubs sensitive information from an object for safe logging.
    +     * Creates a deep clone of the object and replaces sensitive values with [REDACTED].
    +     * @param obj The object to scrub (typically command-line options).
    +     * @returns A new object with sensitive values replaced.
    +     */
    +    private scrubSensitiveData(obj: any): any {
    +        if (obj === null || obj === undefined) {
    +            return obj;
    +        }
    +
    +        if (typeof obj !== 'object') {
    +            return obj;
    +        }
    +
    +        if (Array.isArray(obj)) {
    +            return obj.map((item: any) => this.scrubSensitiveData(item));
    +        }
    +
    +        const scrubbedObj: any = {};
    +
    +        for (const key in obj) {
    +            if (obj.hasOwnProperty(key)) {
    +                const lowerKey = key.toLowerCase();
    +                const isSensitive = this.SENSITIVE_KEYS.some(
    +                    sensitiveKey => lowerKey.includes(sensitiveKey.toLowerCase())
    +                );
    +
    +                if (isSensitive) {
    +                    scrubbedObj[key] = '[REDACTED]';
    +                } else if (typeof obj[key] === 'object') {
    +                    scrubbedObj[key] = this.scrubSensitiveData(obj[key]);
    +                } else {
    +                    scrubbedObj[key] = obj[key];
    +                }
    +            }
    +        }
    +
    +        return scrubbedObj;
    +    }
    +
         /**
          * Sets an environment variable in CI environments that support it.
          * @param name The name of the environment variable.
    
  • src/unity-editor.ts+30 1 modified
    @@ -191,6 +191,32 @@ export class UnityEditor {
             return templates;
         }
     
    +    /**
    +     * Scrubs sensitive command-line arguments for safe logging.
    +     * Replaces values for sensitive flags like -username, -password, etc. with [REDACTED].
    +     * @param args The command-line arguments array.
    +     * @returns A new array with sensitive values redacted.
    +     */
    +    public scrubSensitiveArgs(args: string[]): string[] {
    +        const sensitiveFlags = ['-username', '-password', '-cloudOrganization', '-serial'];
    +        const scrubbedArgs: string[] = [];
    +        
    +        for (let i = 0; i < args.length; i++) {
    +            const arg = args[i];
    +            if (!arg) continue;
    +            
    +            scrubbedArgs.push(arg);
    +            
    +            // If this is a sensitive flag and the next item is its value
    +            if (sensitiveFlags.includes(arg) && i + 1 < args.length) {
    +                scrubbedArgs.push('[REDACTED]');
    +                i++; // Skip the next item (the actual value) since we've already added [REDACTED]
    +            }
    +        }
    +        
    +        return scrubbedArgs;
    +    }
    +
         /**
          * Run the Unity Editor with the specified command line arguments.
          * @param command The command containing arguments and optional project path.
    @@ -264,7 +290,10 @@ export class UnityEditor {
     
                 const logPath: string = GetArgumentValueAsString('-logFile', command.args);
                 logTail = TailLogFile(logPath, command.projectPath);
    -            const commandStr = `\x1b[34m${this.editorPath} ${command.args.join(' ')}\x1b[0m`;
    +            
    +            // Scrub sensitive arguments before logging
    +            const scrubbedArgs = this.scrubSensitiveArgs(command.args);
    +            const commandStr = `\x1b[34m${this.editorPath} ${scrubbedArgs.join(' ')}\x1b[0m`;
                 this.logger.startGroup(commandStr);
     
                 if (this.version.isLegacy() && process.platform === 'darwin' && process.arch === 'arm64') {
    
  • tests/credential-scrubbing.test.ts+218 0 added
    @@ -0,0 +1,218 @@
    +import { Logger, LogLevel } from '../src/logging';
    +
    +describe('Credential Scrubbing', () => {
    +    let writeSpy: jest.SpyInstance;
    +    let originalLogLevel: LogLevel;
    +
    +    beforeEach(() => {
    +        writeSpy = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
    +        originalLogLevel = Logger.instance.logLevel;
    +        Logger.instance.logLevel = LogLevel.DEBUG; // Ensure debug logging is enabled
    +    });
    +
    +    afterEach(() => {
    +        writeSpy.mockRestore();
    +        Logger.instance.logLevel = originalLogLevel; // Restore original log level
    +    });
    +
    +    describe('debugOptions', () => {
    +        it('should scrub password from options', () => {
    +            const options = {
    +                email: 'test@example.com',
    +                password: 'SuperSecret123',
    +                verbose: true
    +            };
    +
    +            Logger.instance.debugOptions(options);
    +
    +            const output = writeSpy.mock.calls.map((call: any[]) => call[0]).join('');
    +            expect(output).toContain('[REDACTED]');
    +            expect(output).not.toContain('SuperSecret123');
    +        });
    +
    +        it('should scrub email from options', () => {
    +            const options = {
    +                email: 'sensitive@example.com',
    +                package: './my-package',
    +                verbose: true
    +            };
    +
    +            Logger.instance.debugOptions(options);
    +
    +            const output = writeSpy.mock.calls.map((call: any[]) => call[0]).join('');
    +            expect(output).toContain('[REDACTED]');
    +            expect(output).not.toContain('sensitive@example.com');
    +        });
    +
    +        it('should scrub serial from options', () => {
    +            const options = {
    +                license: 'professional',
    +                serial: 'ABC-123-DEF-456',
    +                verbose: true
    +            };
    +
    +            Logger.instance.debugOptions(options);
    +
    +            const output = writeSpy.mock.calls.map((call: any[]) => call[0]).join('');
    +            expect(output).toContain('[REDACTED]');
    +            expect(output).not.toContain('ABC-123-DEF-456');
    +        });
    +
    +        it('should scrub token from options', () => {
    +            const options = {
    +                license: 'floating',
    +                token: 'secret-token-12345',
    +                verbose: true
    +            };
    +
    +            Logger.instance.debugOptions(options);
    +
    +            const output = writeSpy.mock.calls.map((call: any[]) => call[0]).join('');
    +            expect(output).toContain('[REDACTED]');
    +            expect(output).not.toContain('secret-token-12345');
    +        });
    +
    +        it('should scrub organization from options', () => {
    +            const options = {
    +                package: './package',
    +                organization: 'org-id-12345',
    +                verbose: true
    +            };
    +
    +            Logger.instance.debugOptions(options);
    +
    +            const output = writeSpy.mock.calls.map((call: any[]) => call[0]).join('');
    +            expect(output).toContain('[REDACTED]');
    +            expect(output).not.toContain('org-id-12345');
    +        });
    +
    +        it('should scrub config from options', () => {
    +            const options = {
    +                license: 'floating',
    +                config: '{"server":"license.example.com","port":8080}',
    +                verbose: true
    +            };
    +
    +            Logger.instance.debugOptions(options);
    +
    +            const output = writeSpy.mock.calls.map((call: any[]) => call[0]).join('');
    +            expect(output).toContain('[REDACTED]');
    +            expect(output).not.toContain('"server":"license.example.com"');
    +        });
    +
    +        it('should preserve non-sensitive options', () => {
    +            const options = {
    +                email: 'test@example.com',
    +                password: 'secret',
    +                verbose: true,
    +                package: './my-package',
    +                output: './output'
    +            };
    +
    +            Logger.instance.debugOptions(options);
    +
    +            const output = writeSpy.mock.calls.map((call: any[]) => call[0]).join('');
    +            expect(output).toContain('my-package');
    +            expect(output).toContain('./output');
    +            expect(output).toContain('true');
    +            expect(output).not.toContain('test@example.com');
    +            expect(output).not.toContain('secret');
    +        });
    +
    +        it('should scrub nested sensitive options', () => {
    +            const options = {
    +                credentials: {
    +                    email: 'nested@example.com',
    +                    password: 'nested-secret'
    +                },
    +                verbose: true
    +            };
    +
    +            Logger.instance.debugOptions(options);
    +
    +            const output = writeSpy.mock.calls.map((call: any[]) => call[0]).join('');
    +            expect(output).toContain('[REDACTED]');
    +            expect(output).not.toContain('nested@example.com');
    +            expect(output).not.toContain('nested-secret');
    +        });
    +
    +        it('should scrub sensitive options in arrays', () => {
    +            const options = {
    +                users: [
    +                    { email: 'user1@example.com', name: 'User 1' },
    +                    { email: 'user2@example.com', name: 'User 2' }
    +                ],
    +                verbose: true
    +            };
    +
    +            Logger.instance.debugOptions(options);
    +
    +            const output = writeSpy.mock.calls.map((call: any[]) => call[0]).join('');
    +            expect(output).toContain('[REDACTED]');
    +            expect(output).toContain('User 1');
    +            expect(output).toContain('User 2');
    +            expect(output).not.toContain('user1@example.com');
    +            expect(output).not.toContain('user2@example.com');
    +        });
    +
    +        it('should handle null and undefined values', () => {
    +            const options = {
    +                email: null,
    +                password: undefined,
    +                token: '',
    +                verbose: true
    +            };
    +
    +            Logger.instance.debugOptions(options);
    +
    +            const output = writeSpy.mock.calls.map((call: any[]) => call[0]).join('');
    +            expect(output).toBeDefined();
    +        });
    +
    +        it('should scrub all sensitive keys case-insensitively', () => {
    +            const options = {
    +                Password: 'secret1',
    +                EMAIL: 'test@example.com',
    +                Organization: 'org123',
    +                verbose: true
    +            };
    +
    +            Logger.instance.debugOptions(options);
    +
    +            const output = writeSpy.mock.calls.map((call: any[]) => call[0]).join('');
    +            expect(output).toContain('[REDACTED]');
    +            expect(output).not.toContain('secret1');
    +            expect(output).not.toContain('test@example.com');
    +            expect(output).not.toContain('org123');
    +        });
    +    });
    +
    +    describe('maskCredential', () => {
    +        it('should call CI_mask for non-empty credentials', () => {
    +            const maskSpy = jest.spyOn(Logger.instance, 'CI_mask');
    +
    +            Logger.instance.maskCredential('my-secret-password');
    +
    +            expect(maskSpy).toHaveBeenCalledWith('my-secret-password');
    +            maskSpy.mockRestore();
    +        });
    +
    +        it('should not call CI_mask for undefined credentials', () => {
    +            const maskSpy = jest.spyOn(Logger.instance, 'CI_mask');
    +
    +            Logger.instance.maskCredential(undefined);
    +
    +            expect(maskSpy).not.toHaveBeenCalled();
    +            maskSpy.mockRestore();
    +        });
    +
    +        it('should not call CI_mask for empty string credentials', () => {
    +            const maskSpy = jest.spyOn(Logger.instance, 'CI_mask');
    +
    +            Logger.instance.maskCredential('');
    +
    +            expect(maskSpy).not.toHaveBeenCalled();
    +            maskSpy.mockRestore();
    +        });
    +    });
    +});
    
  • tests/unity-editor.test.ts+118 0 modified
    @@ -37,4 +37,122 @@ describe('UnityEditor', () => {
                 expect(template).toBeDefined();
             }
         });
    +
    +        describe('scrubSensitiveArgs', () => {
    +            // Create a simple UnityEditor instance for testing scrubSensitiveArgs
    +            // We don't need a full editor setup since we're only testing a pure function
    +            let testEditor: UnityEditor;
    +
    +            beforeAll(() => {
    +                // Use the first available editor or create a mock-like one
    +                if (editors.length > 0) {
    +                    testEditor = editors[0];
    +                }
    +            });
    +
    +            it('should redact -username value', () => {
    +                if (!testEditor) {
    +                    // Skip if no editors available
    +                    return;
    +                }
    +
    +                const args = ['-batchmode', '-username', 'test@example.com', '-quit'];
    +                const scrubbedArgs = testEditor.scrubSensitiveArgs(args);
    +
    +                expect(scrubbedArgs).toContain('-username');
    +                expect(scrubbedArgs).toContain('[REDACTED]');
    +                expect(scrubbedArgs).not.toContain('test@example.com');
    +                expect(scrubbedArgs).toContain('-batchmode');
    +                expect(scrubbedArgs).toContain('-quit');
    +            });
    +
    +            it('should redact -password value', () => {
    +                if (!testEditor) return;
    +
    +                const args = ['-batchmode', '-password', 'SuperSecret123', '-quit'];
    +                const scrubbedArgs = testEditor.scrubSensitiveArgs(args);
    +
    +                expect(scrubbedArgs).toContain('-password');
    +                expect(scrubbedArgs).toContain('[REDACTED]');
    +                expect(scrubbedArgs).not.toContain('SuperSecret123');
    +            });
    +
    +            it('should redact -cloudOrganization value', () => {
    +                if (!testEditor) return;
    +
    +                const args = ['-batchmode', '-cloudOrganization', 'org-id-12345', '-quit'];
    +                const scrubbedArgs = testEditor.scrubSensitiveArgs(args);
    +
    +                expect(scrubbedArgs).toContain('-cloudOrganization');
    +                expect(scrubbedArgs).toContain('[REDACTED]');
    +                expect(scrubbedArgs).not.toContain('org-id-12345');
    +            });
    +
    +            it('should redact -serial value', () => {
    +                if (!testEditor) return;
    +
    +                const args = ['-batchmode', '-serial', 'ABC-123-DEF-456', '-quit'];
    +                const scrubbedArgs = testEditor.scrubSensitiveArgs(args);
    +
    +                expect(scrubbedArgs).toContain('-serial');
    +                expect(scrubbedArgs).toContain('[REDACTED]');
    +                expect(scrubbedArgs).not.toContain('ABC-123-DEF-456');
    +            });
    +
    +            it('should redact multiple sensitive values', () => {
    +                if (!testEditor) return;
    +
    +                const args = [
    +                    '-batchmode',
    +                    '-username', 'user@example.com',
    +                    '-password', 'MyPassword123',
    +                    '-cloudOrganization', 'org-xyz',
    +                    '-quit'
    +                ];
    +                const scrubbedArgs = testEditor.scrubSensitiveArgs(args);
    +
    +                expect(scrubbedArgs).toContain('[REDACTED]');
    +                expect(scrubbedArgs).not.toContain('user@example.com');
    +                expect(scrubbedArgs).not.toContain('MyPassword123');
    +                expect(scrubbedArgs).not.toContain('org-xyz');
    +                expect(scrubbedArgs).toContain('-batchmode');
    +                expect(scrubbedArgs).toContain('-quit');
    +            });
    +
    +            it('should preserve non-sensitive arguments', () => {
    +                if (!testEditor) return;
    +
    +                const args = [
    +                    '-batchmode',
    +                    '-projectPath', '/path/to/project',
    +                    '-buildTarget', 'StandaloneWindows64',
    +                    '-quit'
    +                ];
    +                const scrubbedArgs = testEditor.scrubSensitiveArgs(args);
    +
    +                expect(scrubbedArgs).toEqual(args);
    +                expect(scrubbedArgs).toContain('/path/to/project');
    +                expect(scrubbedArgs).toContain('StandaloneWindows64');
    +            });
    +
    +            it('should handle empty array', () => {
    +                if (!testEditor) return;
    +
    +                const args: string[] = [];
    +                const scrubbedArgs = testEditor.scrubSensitiveArgs(args);
    +
    +                expect(scrubbedArgs).toEqual([]);
    +            });
    +
    +            it('should handle sensitive flag at end of array without value', () => {
    +                if (!testEditor) return;
    +
    +                const args = ['-batchmode', '-quit', '-username'];
    +                const scrubbedArgs = testEditor.scrubSensitiveArgs(args);
    +
    +                // The flag is included but there's no value to redact
    +                expect(scrubbedArgs).toContain('-username');
    +                expect(scrubbedArgs).not.toContain('[REDACTED]');
    +            });
    +        });
     });
    \ No newline at end of file
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.