Skip to content

Fix last env variable not read when .env file has no trailing newline#4783

Open
SasinduDilshara wants to merge 1 commit intowso2:masterfrom
SasinduDilshara:fix-4234
Open

Fix last env variable not read when .env file has no trailing newline#4783
SasinduDilshara wants to merge 1 commit intowso2:masterfrom
SasinduDilshara:fix-4234

Conversation

@SasinduDilshara
Copy link
Copy Markdown

@SasinduDilshara SasinduDilshara commented Apr 3, 2026

Summary

Fixes #4234

  • The export_env_file() function in all startup scripts used while IFS='=' read -r key value; do, which skips the last line when the .env file has no trailing newline (bash read returns non-zero at EOF).
  • Changed to while IFS='=' read -r key value || [ -n "$key" ]; do so the loop body executes even when read hits EOF without a newline, as long as data was read into $key.
  • Applied to the primary shipped script (distribution/src/scripts/micro-integrator.sh) and all 14 integration-test copies.

Root Cause

The read builtin returns non-zero when it reaches EOF before finding \n. The while condition check on the return code causes the last key-value pair to be silently skipped.

Test plan

  • Create a .env file without a trailing newline (e.g. printf 'KEY=value') and start MI with --env-file; confirm the variable is exported and resolved.
  • Verify existing env-file tests still pass.
  • Edge cases: single variable no newline, comment on last line no newline, empty file.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed environment configuration file parsing to correctly handle final lines that lack trailing newlines. Environment variables from the last line of configuration files are now properly loaded even when the file doesn't end with a newline character. This improves reliability when loading configuration from externally-generated or edited configuration files.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

Warning

Rate limit exceeded

@SasinduDilshara has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 36 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 11 minutes and 36 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d8427faf-f0bf-4c99-9c90-1f6ddfe1450d

📥 Commits

Reviewing files that changed from the base of the PR and between ee7dccd and eb0ec59.

📒 Files selected for processing (2)
  • distribution/src/scripts/micro-integrator.sh
  • integration/mediation-tests/tests-other/src/test/java/org/wso2/carbon/esb/resource/test/api/ApiWithConfigurablePropertyTestCase.java

Walkthrough

Updated the .env parsing loop in export_env_file() across 15 shell script files to handle final lines without trailing newlines. The read condition now includes || [ -n "$key" ] to ensure the last key-value pair is processed even when the file doesn't end with a newline character.

Changes

Cohort / File(s) Summary
Distribution Scripts
distribution/src/scripts/micro-integrator.sh
Added fallback condition to read loop to capture final .env line when not newline-terminated.
Core Integration Test Scripts
integration/dataservice-hosting-tests/tests-integration/tests/src/test/resources/bin/integrator.sh, integration/mediation-tests/tests-mediator-1/src/test/resources/bin/integrator.sh, integration/mediation-tests/tests-mediator-2/src/test/resources/bin/integrator.sh
Applied same .env parsing fix to mediator and dataservice hosting test scripts.
Platform-Specific Integration Tests
integration/mediation-tests/tests-platform/tests-rabbitmq/src/test/resources/bin/integrator.sh, integration/mediation-tests/tests-platform/tests-userstore/src/test/resources/artifacts/ESB/server/bin/micro-integrator.sh, integration/mediation-tests/tests-platform/tests-wso2mb/src/test/resources/bin/integrator.sh
Updated .env parsing loop in platform-specific test environment scripts.
Patches Scenario Integration Tests
integration/mediation-tests/tests-patches/src/test/resources/artifacts/ESB/passthru/transport/enableCorrelation/micro-integrator.sh, integration/mediation-tests/tests-patches/src/test/resources/artifacts/ESB/vfs/micro-integrator.sh, integration/mediation-tests/tests-patches/src/test/resources/bin/integrator.sh
Applied fix to patch scenario test scripts with varied artifact paths.
Additional Scenario Integration Tests
integration/mediation-tests/tests-other/src/test/resources/artifacts/ESB/serviceCatalog/micro-integrator.sh, integration/mediation-tests/tests-patches-with-smb2/src/test/resources/bin/integrator.sh, integration/mediation-tests/tests-sample/src/test/resources/bin/integrator.sh, integration/mediation-tests/tests-service/src/test/resources/bin/integrator.sh, integration/mediation-tests/tests-transport/src/test/resources/bin/integrator.sh
Updated .env parsing in remaining test environment scripts (other, smb2, sample, service, transport scenarios).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A newline's absence caused a line to fade,
But now the last key-value makes the grade!
No $key left behind—we've read it through,
Environment variables, both old and new! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: fixing the issue where the last environment variable is not read when .env files lack trailing newlines.
Description check ✅ Passed The description provides a clear summary, references the linked issue, explains the root cause, details the implementation, and lists a test plan. However, it doesn't follow all sections of the provided template (e.g., Goals, Approach, Release notes, Documentation, Security checks, etc.).
Linked Issues check ✅ Passed The PR successfully addresses issue #4234 by fixing the export_env_file() function to handle .env files without trailing newlines, ensuring the last key/value pair is correctly read and exported as required.
Out of Scope Changes check ✅ Passed All changes are within scope: 15 shell script files have the same targeted fix applied to the export_env_file() function to handle missing trailing newlines, with no unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

When using --env-file, the POSIX `read` builtin returns non-zero on EOF
even when partial content is read, causing the last variable to be
silently dropped if the file has no trailing newline. Fix by adding
`|| [ -n "$key" ]` to handle the incomplete final line.

Adds integration test testConfigurablePropertyWithEnvFileNoTrailingNewline
to cover this scenario.

Fixes wso2#4234

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@SasinduDilshara
Copy link
Copy Markdown
Author

Claude Issue Analysis — [Issue #4234]: When there is no new line in the .env file, the last environmental variable value is not picked.

Classification

  • Type: Bug
  • Severity Assessment: Medium
  • Affected Component(s): product-micro-integrator — startup shell script (distribution/src/scripts/micro-integrator.sh)
  • Affected Feature(s): --env-file command-line argument for loading environment variables from a .env file during server startup

Reproducibility

  • Reproducible: Yes
  • Environment: MI 4.6.0-SNAPSHOT, macOS Darwin 24.0.0, zsh/bash, Java 21
  • Steps Executed:
    1. Created a .env file without a trailing newline:
      HR_SMTP_HOST=smtp.gmail.com
      HR_SMTP_PORT=465
      HR_SMTP_PASSWORD=werdrktoetkdmwl
      
      (file ends at l with no \n)
    2. Created a test CAR app (envTestApp_1.0.0.car) containing:
      • A config/property artifact with config.properties listing HR_SMTP_HOST, HR_SMTP_PORT, HR_SMTP_PASSWORD as string type
      • A REST API using ${configs.HR_SMTP_PASSWORD}
    3. Placed the CAR in wso2mi-4.6.0-SNAPSHOT/repository/deployment/server/carbonapps/
    4. Started the server: sh micro-integrator.sh --env-file=/tmp/test-no-newline.env
    5. Observed server logs during CAR deployment
  • Expected Behavior: All three env vars (HR_SMTP_HOST, HR_SMTP_PORT, HR_SMTP_PASSWORD) are exported and resolved correctly; no error logged.
  • Actual Behavior: HR_SMTP_PASSWORD is not exported (silently dropped by the shell's read loop), and the following error appears during CAR deployment:
    ERROR {ConfigDeployer} - The value of the key:[HR_SMTP_PASSWORD] is not found.
    
  • Logs/Evidence:
    [2026-04-06 06:10:17,210] ERROR {org.wso2.micro.integrator.initializer.deployment.config.deployer.ConfigDeployer} - The value of the key:[HR_SMTP_PASSWORD] is not found.
    [2026-04-06 06:10:17,210]  INFO {CappDeployer} - Successfully Deployed Carbon Application : envTestApp_1.0.0{super-tenant}
    
    Shell-level confirmation (direct test of the while IFS='=' read loop):
    === Without trailing newline ===
    HR_SMTP_HOST=smtp.gmail.com
    HR_SMTP_PORT=465
    HR_SMTP_PASSWORD=NOT SET      ← bug: last line not read
    
    === With trailing newline ===
    HR_SMTP_HOST=smtp.gmail.com
    HR_SMTP_PORT=465
    HR_SMTP_PASSWORD=werdrktoetkdmwl  ← works correctly
    

Root Cause Analysis

The bug is in export_env_file() in distribution/src/scripts/micro-integrator.sh (line 133):

while IFS='=' read -r key value; do
    ...
done < "$file_path"

The POSIX read builtin only returns a non-zero exit code (ending the loop) when it reads a complete line terminated by \n. If the last line of the file has no trailing newline, read reads the content but returns a non-zero exit code simultaneously — which causes the while condition to fail and the loop body to not execute for that final line. This is standard POSIX shell behavior.

The fix is to also process a partial line after the while loop ends, or to use a combined pattern:

# Option 1: handle last incomplete line after the loop
while IFS='=' read -r key value || [ -n "$key" ]; do

Adding || [ -n "$key" ] makes the loop body execute even when read returns non-zero (end-of-file) but has read non-empty content into key.

The VSCode extension is unaffected because it likely sets env vars through a different mechanism (process environment injection) that doesn't use the shell script's file-parsing loop.

Test Coverage Assessment

  • Existing tests covering this path:
    • integration/mediation-tests/tests-other/src/test/java/org/wso2/carbon/esb/resource/test/api/ApiWithConfigurablePropertyTestCase.javatestConfigurablePropertyWithEnvVariable() (line 86): tests --env-file but uses test.env which has a trailing newline (confirmed via xxd).
    • integration/mediation-tests/tests-other/src/test/java/org/wso2/carbon/esb/resource/test/endpoint/EndpointWithConfigurablePropertyTestCase.java — similar coverage, same gap.
  • Coverage gaps identified:
    • No test exercises the --env-file option with a .env file that lacks a trailing newline.
    • The existing test.env resource always ends with \n, so the parsing bug is never triggered by automated tests.
  • Proposed test plan:
    • Unit test (shell): Add a shell test that creates a .env without trailing newline, runs export_env_file, and asserts all variables are exported.
    • Integration test: Add a new test method testConfigurablePropertyWithEnvFileNoTrailingNewline() in ApiWithConfigurablePropertyTestCase that:
      1. Creates a temp .env file without trailing newline containing the vars expected by the CAR
      2. Restarts MI with --env-file=<path>
      3. Invokes the API and asserts the last variable's value is present in the response
    • Negative/edge cases:
      • .env file with only one variable and no trailing newline
      • .env file with Windows-style \r\n line endings where the last line has no \r\n
      • Empty .env file (zero bytes)

@SasinduDilshara
Copy link
Copy Markdown
Author

#Claude Fix Verification Report

Issue: #4234
Verdict: FIXED

Reproduction Steps Executed

  1. Created a .env file without a trailing newline containing two variables where msg=Hello is the last line (18 bytes, no \n at end):

    name=env
    msg=Hello
    

    (file ends at o — no trailing newline, confirmed via xxd)

  2. Deployed the test CAR app testApiWithConfigurationProperty_1.0.0.car which uses ${configs.name} and ${configs.msg} configurable properties.

  3. Extracted a fresh pack (wso2mi-4.6.0-SNAPSHOT.zip), applied the patched micro-integrator.sh script (which contains the fix: while IFS='=' read -r key value || [ -n "$key" ]; do).

  4. Started the server with sh micro-integrator.sh --env-file=/tmp/test-no-newline-issue4234.env.

  5. Invoked the API: GET http://localhost:8290/apiConfig/test_api

Result

The API returned HTTP 200 with both variables correctly resolved:

{
  "name": "env",
  "msg": "Hello"
}

msg=Hello (the last variable, with no trailing newline in the .env file) was successfully exported and resolved. No ConfigDeployer errors appeared in the logs.

Before the fix, this scenario produced:

ERROR {ConfigDeployer} - The value of the key:[msg] is not found.

Evidence

Shell script fix (line 133 of patched micro-integrator.sh):

while IFS='=" read -r key value || [ -n "$key" ]; do

Server log — no ConfigDeployer errors:

(no ConfigDeployer output — empty grep result)

Server log — CAR deployed successfully:

[2026-04-06 06:21:17,208]  INFO {CappDeployer} - Successfully Deployed Carbon Application : testApiWithConfigurationProperty_1.0.0{super-tenant}

Server log — server started cleanly:

[2026-04-06 06:21:17,337]  INFO {StartupFinalizer} - WSO2 Micro Integrator started in 2.77 seconds

HTTP response (curl):

HTTP 200
{"name": "env", "msg": "Hello"}

Both name and msg correctly resolved from a .env file with no trailing newline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When there is no new line in the .env file, the last environmental variable value is not picked.

1 participant