Skip to content

[fix] Make __openwisp_version__ dynamic to eliminate staleness #570#603

Open
CodingWithSaksham wants to merge 18 commits into
openwisp:masterfrom
CodingWithSaksham:issues/570-fix-openwisp-version-stale
Open

[fix] Make __openwisp_version__ dynamic to eliminate staleness #570#603
CodingWithSaksham wants to merge 18 commits into
openwisp:masterfrom
CodingWithSaksham:issues/570-fix-openwisp-version-stale

Conversation

@CodingWithSaksham
Copy link
Copy Markdown

@CodingWithSaksham CodingWithSaksham commented May 19, 2026

The hardcoded __openwisp_version__ in openwisp/__init__.py was never updated during the release process, causing it to report an outdated version (e.g., 25.10.0 while the actual image was 25.10.2).

This change makes the version dynamic by reading it from the OPENWISP_VERSION environment variable, which is set at Docker build time and baked into the image. This ensures __openwisp_version__ always reflects the actual image version without manual updates.

Checklist

  • I have read the OpenWISP Contributing Guidelines.
  • I have manually tested the changes proposed in this pull request.
  • I have written new test cases for new code and/or updated existing tests for changes to existing code.
  • I have updated the documentation.

Reference to Existing Issue

Closes #570 .

Description of Changes

  • images/openwisp_base/Dockerfile: Create a /opt/openwisp/OPENWISP_VERSION file that is immutable to any writes (after final build) and write build version into this
  • Makefile: Change docker target flags to correctly match build stage in images/openwisp_base/Dockerfile and add a build arg in the last docker build to pass OPENWISP_VERSION into the image.
  • images/common/openwisp/__init__.py: Replace hardcoded "25.10.0" with a _read_version() function that reads /opt/openwisp/OPENWISP_VESRION to read the version dynamically.

Screenshot

N/A

…sp#570

Closes openwisp#570
The hardcoded __openwisp_version__ in openwisp/__init__.py was never
updated during the release process, causing it to report an outdated
version (e.g., 25.10.0 while the actual image was 25.10.2).

This change makes the version dynamic by reading it from the OPENWISP_VERSION
environment variable, which is set at Docker build time and baked into the
image. This ensures __openwisp_version__ always reflects the actual image
version without manual updates.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

build.py gains commands to generate a version module (images/common/openwisp/_version.py) and to update RELEASE_VERSION in the Makefile. The Makefile calls python build.py generate-version $(OPENWISP_VERSION) and passes OPENWISP_VERSION as a --build-arg to the openwisp-base docker build; intermediate Docker build --target names were adjusted. images/common/openwisp/init.py now imports version as openwisp_version and exports it. .gitignore ignores the generated _version.py. Dockerfile edits are formatting-only.

Sequence Diagram(s)

sequenceDiagram
  participant DevMachine
  participant build_py
  participant Makefile
  participant DockerBuild
  participant openwisp_base_Dockerfile
  participant FinalImage
  DevMachine->>build_py: python build.py generate-version <version>
  build_py->>DevMachine: write images/common/openwisp/_version.py
  DevMachine->>Makefile: run base-build (calls generator then docker build)
  Makefile->>DockerBuild: docker build --build-arg OPENWISP_VERSION=<version>
  DockerBuild->>openwisp_base_Dockerfile: provide ARG OPENWISP_VERSION
  openwisp_base_Dockerfile->>FinalImage: build image (no behavioral changes)
  FinalImage->>DevMachine: image contains code that imports generated _version.py
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • nemesifier
  • pandafy

Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (2 errors, 1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ❌ Error The Dockerfile contains unrelated reformatting changes (line continuations, indentation) that were introduced by code formatter qa-format and are not part of the core fix for dynamic versioning. Remove the unrelated Dockerfile formatting changes to keep the PR focused on the version staleness fix. Revert formatting-only modifications in images/openwisp_base/Dockerfile.
Bug Fixes ❌ Error No regression tests included for the version generation and import mechanism, which is required by the bug fix check and is practical to implement. Add unit/integration tests to verify _version.py generation, proper import of openwisp_version, and end-to-end version functionality.
Description check ❓ Inconclusive The PR description addresses the core problem and solution but deviates from the template structure and does not mention test updates or contain clear issue references. Clarify whether tests should be added for dynamic version reading; verify the implementation matches the described approach of reading from OPENWISP_VERSION; ensure consistency between PR description and actual file changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the fix (dynamic version) and references the linked issue #570, following the required format of [fix] Descriptive title.
Linked Issues check ✅ Passed The PR addresses issue #570 by implementing dynamic version reading from OPENWISP_VERSION, eliminating the hardcoded stale version and making version retrieval dynamic from build metadata.
✨ 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.

@kilo-code-bot
Copy link
Copy Markdown

kilo-code-bot Bot commented May 19, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Incremental Review (Changes since 1555c0c)

Files Changed:

  1. images/openwisp_base/Dockerfile - ✅ FIXED: Previous duplicate content issue resolved. File is now clean at 178 lines.
  2. Makefile - Correctly adds version generation and fixes Docker target names
  3. build.py - New version generation functions look correct
  4. images/common/openwisp/__init__.py - Properly imports version from generated module
  5. .gitignore - Added _version.py to ignore generated file

Analysis:

  • The critical Dockerfile duplication bug has been fixed
  • Version generation is properly integrated into the build process
  • All changes align with the PR intent to make image version discoverable
Files Reviewed (5 files)
  • images/openwisp_base/Dockerfile - Previous CRITICAL issue FIXED
  • Makefile - Added version generation, fixed target names
  • build.py - New update_makefile_version() and generate_version_module() functions
  • images/common/openwisp/__init__.py - Imports openwisp_version from _version module
  • .gitignore - Added _version.py

Reviewed by kimi-k2.5 · incremental review


Reviewed by gpt-5.4-20260305 · 19,949 tokens

@CodingWithSaksham
Copy link
Copy Markdown
Author

CodingWithSaksham commented May 19, 2026

I am not sure if unit tests should be added for this kind of bug. If we add unit tests we will have to update the version in the unit tests as well which defeats the point of this PR.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@images/openwisp_base/Dockerfile`:
- Around line 51-53: The pip install RUN lines use unquoted build-arg expansions
which can break parsing and be unsafe; update each pip install invocation that
references OPENWISP_IPAM_SOURCE, OPENWISP_CONTROLLER_SOURCE,
OPENWISP_NOTIFICATION_SOURCE, OPENWISP_USERS_SOURCE and DJANGO_X509_SOURCE to
wrap the expansions in double quotes (e.g. "${OPENWISP_IPAM_SOURCE}") so the
shell treats them as single arguments and prevents word-splitting or injection;
apply the same quoting to every similar invocation in the Dockerfile (the pip
install lines around the shown RUN and the other occurrences noted).
- Line 142: Remove the hardcoded DJANGO_SECRET_KEY default from the Dockerfile
by eliminating the literal assignment "DJANGO_SECRET_KEY=DEFAULT_BAD_KEY" and
instead accept the secret via build/run-time environment variable or Docker
secret; update the Dockerfile's environment handling where DJANGO_SECRET_KEY is
referenced so it no longer sets a default value, and document that the runtime
must supply DJANGO_SECRET_KEY (e.g., via ENV passed at docker run,
docker-compose environment, or from a secrets manager) so the image does not
contain a shipped SECRET_KEY.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3f51ddd5-e2b3-4b50-96e5-426178df75c6

📥 Commits

Reviewing files that changed from the base of the PR and between 6d4019d and bf97708.

📒 Files selected for processing (2)
  • images/common/openwisp/__init__.py
  • images/openwisp_base/Dockerfile
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CI Build
  • GitHub Check: Kilo Code Review
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{py,html}

📄 CodeRabbit inference engine (Custom checks)

For Django pull requests, ensure all user-facing strings are marked as translatable using the Django i18n framework

Files:

  • images/common/openwisp/__init__.py
🪛 Checkov (3.2.529)
images/openwisp_base/Dockerfile

[low] 1-182: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)

🪛 Trivy (0.69.3)
images/openwisp_base/Dockerfile

[error] 105-182: Secrets passed via build-args or envs or copied secret files

Possible exposure of secret env "DJANGO_SECRET_KEY" in ENV

Rule: DS-0031

Learn more

(IaC/Dockerfile)


[error] 105-182: Secrets passed via build-args or envs or copied secret files

Possible exposure of secret env "EMAIL_HOST_PASSWORD" in ENV

Rule: DS-0031

Learn more

(IaC/Dockerfile)


[error] 105-182: Secrets passed via build-args or envs or copied secret files

Possible exposure of secret env "SSH_PRIVATE_KEY_PATH" in ENV

Rule: DS-0031

Learn more

(IaC/Dockerfile)

🔇 Additional comments (2)
images/common/openwisp/__init__.py (1)

3-8: LGTM!

images/openwisp_base/Dockerfile (1)

9-23: LGTM!

Also applies to: 72-73, 86-93, 97-101, 105-141, 143-182

Comment thread images/openwisp_base/Dockerfile Outdated
Comment thread images/openwisp_base/Dockerfile Outdated
Wrap build-arg variable expansions in double quotes to
prevent shell word-splitting and malformed requirement
parsing during pip install execution.
Copy link
Copy Markdown
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR contains changes that are totally unrelated to the fix. Please clean it up and don't send PRs for review before having double checked and cleaned your work.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@images/openwisp_base/Dockerfile`:
- Line 88: The ARG OPENWISP_VERSION declared outside the openwisp_python stage
is unused because ARGs do not cross FROM boundaries; remove the stray ARG
declaration or move/re-declare ARG OPENWISP_VERSION inside the openwisp_python
stage so the build stage that needs OPENWISP_VERSION actually receives it—search
for the openwisp_python stage and the duplicate ARG OPENWISP_VERSION and keep
only the declaration inside the stage that consumes it (or delete the unused
one).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d2cf0d3d-20e0-4746-be56-0d538781fc96

📥 Commits

Reviewing files that changed from the base of the PR and between bf97708 and 6c8f5c6.

📒 Files selected for processing (1)
  • images/openwisp_base/Dockerfile
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CI Build
🧰 Additional context used
🪛 Checkov (3.2.529)
images/openwisp_base/Dockerfile

[low] 1-182: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)

🪛 Trivy (0.69.3)
images/openwisp_base/Dockerfile

[error] 105-182: Secrets passed via build-args or envs or copied secret files

Possible exposure of secret env "DJANGO_SECRET_KEY" in ENV

Rule: DS-0031

Learn more

(IaC/Dockerfile)


[error] 105-182: Secrets passed via build-args or envs or copied secret files

Possible exposure of secret env "EMAIL_HOST_PASSWORD" in ENV

Rule: DS-0031

Learn more

(IaC/Dockerfile)


[error] 105-182: Secrets passed via build-args or envs or copied secret files

Possible exposure of secret env "SSH_PRIVATE_KEY_PATH" in ENV

Rule: DS-0031

Learn more

(IaC/Dockerfile)

🔇 Additional comments (9)
images/openwisp_base/Dockerfile (9)

8-12: LGTM!


14-17: LGTM!


19-22: LGTM!


35-44: LGTM!


51-78: LGTM!


82-82: LGTM!

Also applies to: 86-86


91-93: LGTM!


96-102: LGTM!


105-182: LGTM!

Comment thread images/openwisp_base/Dockerfile Outdated
@CodingWithSaksham
Copy link
Copy Markdown
Author

This PR contains changes that are totally unrelated to the fix. Please clean it up and don't send PRs for review before having double checked and cleaned your work.

I am really sorry about the unrelated changes. I should have cleaned up the PR properly before sending it for review, and I will be more careful about that going forward.

In this case, the unrelated changes were caused by the qa-format formatting the Dockerfile while I was making the actual fix. So I ended up leaving those formatting changes in the PR.

I will clean up the branch and update the PR with only the intended changes.

Comment thread images/openwisp_base/Dockerfile Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@images/openwisp_base/Dockerfile`:
- Around line 88-89: The final build stage starting at the FROM system line uses
ENV OPENWISP_VERSION="${OPENWISP_VERSION}" but does not re-declare the build ARG
across the stage boundary; add an ARG OPENWISP_VERSION declaration immediately
after the FROM system line so that the build-time variable OPENWISP_VERSION is
available and correctly expands into ENV OPENWISP_VERSION in that stage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 78d79a4d-4f40-4946-afb4-a0121167d21b

📥 Commits

Reviewing files that changed from the base of the PR and between 6c8f5c6 and b66007c.

📒 Files selected for processing (1)
  • images/openwisp_base/Dockerfile
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CI Build
  • GitHub Check: Kilo Code Review

Comment thread images/openwisp_base/Dockerfile Outdated
Copy link
Copy Markdown
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach is OK, but not complete yet: the base image build path still does not pass the version into the Dockerfile, so release images can still bake the default value. Left the important bits inline.

Comment thread images/openwisp_base/Dockerfile Outdated
Comment thread images/openwisp_base/Dockerfile Outdated
Comment thread images/common/openwisp/__init__.py Outdated
Comment thread images/common/openwisp/__init__.py Outdated
The base-build target was not passing --build-arg OPENWISP_VERSION to the
final docker build command, causing openwisp-base to always be built with
OPENWISP_VERSION=edge regardless of the RELEASE_VERSION set in the Makefile.

This meant that `make release` could build and tag images as
`openwisp-base:25.10.3` while the container internally reported version "edge",
causing version mismatch and confusion in support scenarios.
@coderabbitai coderabbitai Bot added the bug Something isn't working label May 20, 2026
@CodingWithSaksham
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@images/common/openwisp/__init__.py`:
- Around line 8-12: The file duplicates the environment lookup for
__openwisp_version__; remove the redundant assignment so there is a single
assignment to __openwisp_version__ via os.environ.get("OPENWISP_VERSION") placed
before the subsequent guard that checks if __openwisp_version__ is None or
"unknown", leaving __openwisp_installation_method__ untouched.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 97b192ed-71e9-465c-93e1-33481d0f574f

📥 Commits

Reviewing files that changed from the base of the PR and between b66007c and a495a8f.

📒 Files selected for processing (3)
  • Makefile
  • images/common/openwisp/__init__.py
  • images/openwisp_base/Dockerfile
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{py,html}

📄 CodeRabbit inference engine (Custom checks)

For Django pull requests, ensure all user-facing strings are marked as translatable using the Django i18n framework

Files:

  • images/common/openwisp/__init__.py
🧠 Learnings (1)
📚 Learning: 2026-02-17T16:59:39.027Z
Learnt from: atif09
Repo: openwisp/docker-openwisp PR: 555
File: Makefile:4-5
Timestamp: 2026-02-17T16:59:39.027Z
Learning: In all Makefiles, prefer 'include' (not '-include') for critical config files like .env. If the file is missing, the build should fail explicitly rather than silently proceed with empty values. This ensures configurations are present and avoids dangerous silent failures. Consider adding a clear comment near the line and validation steps in CI to verify .env presence.

Applied to files:

  • Makefile
🪛 GitHub Actions: Merge Tests / 0_CI Build.txt
images/openwisp_base/Dockerfile

[warning] 104-104: SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "EMAIL_HOST_PASSWORD") (line 104)


[warning] 104-104: SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "DJANGO_SECRET_KEY") (line 104)


[warning] 104-104: SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "SSH_PRIVATE_KEY_PATH") (line 104)

Makefile

[error] 71-71: Command failed: "make develop-pythontests && make stop". make: *** [Makefile:71: develop-pythontests] Error 1

🪛 GitHub Actions: Merge Tests / CI Build
Makefile

[error] 71-71: make develop-pythontests failed with exit code 1 after test_forgot_password error (FAILED (errors=1)).

🔇 Additional comments (2)
Makefile (1)

52-53: LGTM!

images/openwisp_base/Dockerfile (1)

89-91: LGTM!

Comment thread images/common/openwisp/__init__.py Outdated
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/openwisp/docker-openwisp/issues/comments/4485076663","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- review_stack_entry_start -->\n\n[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/openwisp/docker-openwisp/pull/603?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)\n\n<!-- review_stack_entry_end -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> <details>\n> <summary>⚙️ Run configuration</summary>\n> \n> **Configuration used**: Organization UI\n> \n> **Review profile**: ASSERTIVE\n> \n> **Plan**: Pro\n> \n> **Run ID**: `c0bcc34a-3f63-46fe-8fdd-3921be4794a4`\n> \n> </details>\n> \n> <details>\n> <summary>📥 Commits</summary>\n> \n> Reviewing files that changed from the base of the PR and between a495a8fab5e347d94ddd36402ec96ceabbe83f13 and dd0de63afff680f8a9c1a217920f854967babc5e.\n> \n> </details>\n> \n> <details>\n> <summary>📒 Files selected for processing (2)</summary>\n> \n> * `Makefile`\n> * `images/common/openwisp/__init__.py`\n> \n> </details>\n> \n> ```ascii\n>  _____________________________________________\n> < Because, bugs shouldn't outnumber features. >\n>  ---------------------------------------------\n>   \\\n>    \\   \\\n>         \\ /\\\n>         ( )\n>       .( o ).\n> ```\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nThe PR makes __openwisp_version__ read from the OPENWISP_VERSION environment variable and adds a runtime guard that raises RuntimeError if the value is unset or \"unknown\". It also ensures OPENWISP_VERSION is passed as a build-arg from the Makefile and exported as ENV in the final openwisp_base Dockerfile stage.\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n  participant ComponentA\n  participant ComponentB\n  ComponentA->>ComponentB: observable interaction\n```\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Possibly related PRs\n\n- [openwisp/docker-openwisp#555](https://github.com/openwisp/docker-openwisp/pull/555): Also wires OPENWISP_VERSION into the Docker/Makefile build workflow and compose tagging.\n\n## Suggested labels\n\n`bug`\n\n## Suggested reviewers\n\n- pandafy\n- nemesifier\n\n</details>\n\n<!-- walkthrough_end -->\n<!-- pre_merge_checks_walkthrough_start -->\n\n---\n\n<!-- pre_merge_checks_override_start -->\n> [!CAUTION]\n> ## Pre-merge checks failed\n> \n> Please resolve all errors before merging. Addressing warnings is optional.\n> \n> - [ ] <!-- {\"checkboxId\": \"override-pre-merge-checks\"} --> Ignore\n<!-- pre_merge_checks_override_end -->\n\n### ❌ Failed checks (1 error)\n\n| Check name | Status  | Explanation                                                                                                                                                                          | Resolution                                                                                                                                 |\n| :--------: | :------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------- |\n|  Bug Fixes | ❌ Error | PR fixes root cause (dynamic version reading) but lacks regression tests. Author noted unit tests would need version updates, defeating PR's goal, but provided no alternative test. | Add regression test verifying OPENWISP_VERSION is read correctly and RuntimeError raised when missing. Fix duplicate assignment on line 8. |\n\n<details>\n<summary>✅ Passed checks (4 passed)</summary>\n\n|         Check name         | Status   | Explanation                                                                                                                                                                            |\n| :------------------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|         Title check        | ✅ Passed | The title uses the required [fix] prefix, clearly describes the main change (making __openwisp_version__ dynamic), and references the linked issue `#570`.                               |\n|      Description check     | ✅ Passed | The description includes the required template sections, explains the problem and solution clearly, provides details on file changes, and maintains the issue reference (Closes `#570`). |\n|     Linked Issues check    | ✅ Passed | The PR fully addresses issue `#570` by making __openwisp_version__ dynamic via OPENWISP_VERSION environment variable, eliminating the need for manual updates during release.            |\n| Out of Scope Changes check | ✅ Passed | All changes (Dockerfile ENV/ARG addition, Makefile build-arg pass-through, and __init__.py version logic) are directly related to fixing the stale version issue and are within scope. |\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=openwisp/docker-openwisp&utm_content=603)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"signal":{},"retries":3,"retryAfter":16}}}

Copy link
Copy Markdown
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing the first round, this is definitely moving in the right direction. I tested the build/runtime path locally and there is still one important correctness issue: the version is baked correctly, but compose can override it at runtime via .env, so __openwisp_version__ can still report the wrong value. I think the clean fix is to bake the version into an immutable file/module during the image build and read that from Python.

Comment thread images/common/openwisp/__init__.py Outdated

__all__ = ["celery_app"]
__openwisp_version__ = "25.10.0"
__openwisp_version__ = os.environ.get("OPENWISP_VERSION")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still reads the mutable runtime env, so compose can override the value baked into the image. I tested with make compose-build OPENWISP_VERSION=26.06a and then OPENWISP_VERSION=26.06a docker compose run --rm --no-deps --entrypoint python dashboard -c 'import openwisp, os; print(os.environ.get("OPENWISP_VERSION")); print(openwisp.__openwisp_version__)'. Expected: 26.06a / 26.06a. Actual: edge / edge, because .env contains OPENWISP_VERSION=edge and env_file wins at runtime. Please bake the build arg into an immutable file/module and read that instead.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also want to set OPENWISP_VERSION as an environment variable in the Dockerfile for the user, or is setting only __openwisp_version__ to the correct version sufficient?

Comment thread images/common/openwisp/__init__.py Outdated
__openwisp_version__ = os.environ.get("OPENWISP_VERSION")
__openwisp_installation_method__ = "docker-openwisp"

if __openwisp_version__ is None or __openwisp_version__ == "unknown":
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raising from openwisp/__init__.py makes every package import fail if the env is missing or set unexpectedly. If the version is baked into a file/module at build time, this import-time guard should not be needed; if we keep a guard, I would put it in a narrower build/test verification path.

Comment thread Makefile Outdated
@@ -48,8 +48,10 @@ base-build:
--target PYTHON ./images/ \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While testing make compose-build OPENWISP_VERSION=26.06a, this stage printed ERROR: failed to solve: target stage "PYTHON" could not be found but the recipe continued and built the final images. Expected behavior: fail immediately on any failed Docker build step, or use a valid target and print no error. This may be pre-existing, but this PR now relies on this build path for version correctness.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears

	docker build --tag openwisp/openwisp-base:intermedia-system \
	             --file ./images/openwisp_base/Dockerfile \
	             --target SYSTEM ./images/; \

was pointing to the wrong path as well, I will be adding a fix for both of these in this PR only.
I wonder how this issue went under the radar for so long 🤔

@CodingWithSaksham
Copy link
Copy Markdown
Author

I am not sure why the CI keeps failing, whenever its re-run the CI passes.

Copy link
Copy Markdown
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the approach we had before was not bad, the problem is that it could be overridden with an env var which is wrong.

Any way, if you can't think of a better way to do this give me some more time to try this and come to a conclusion.

@nemesifier
Copy link
Copy Markdown
Member

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@images/common/openwisp/__init__.py`:
- Around line 12-28: The import-time RuntimeError comes from _read_version()
raising when _VERSION_FILE is missing or unreadable; change _read_version() so
that if os.path.exists(_VERSION_FILE) is False or an OSError occurs it returns a
sensible fallback string (e.g. "0+unknown" or "dev") instead of raising, and set
__openwisp_version__ to that fallback; update the error message to log a warning
if desired but ensure importing the module never raises by handling errors in
_read_version().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a49dd15c-bd6c-4e05-a458-d78469a7e3a4

📥 Commits

Reviewing files that changed from the base of the PR and between 8e3c12a and 7e9b729.

📒 Files selected for processing (3)
  • Makefile
  • images/common/openwisp/__init__.py
  • images/openwisp_base/Dockerfile
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{py,html}

📄 CodeRabbit inference engine (Custom checks)

For Django pull requests, ensure all user-facing strings are marked as translatable using the Django i18n framework

Files:

  • images/common/openwisp/__init__.py
🧠 Learnings (1)
📚 Learning: 2026-02-17T16:59:39.027Z
Learnt from: atif09
Repo: openwisp/docker-openwisp PR: 555
File: Makefile:4-5
Timestamp: 2026-02-17T16:59:39.027Z
Learning: In all Makefiles, prefer 'include' (not '-include') for critical config files like .env. If the file is missing, the build should fail explicitly rather than silently proceed with empty values. This ensures configurations are present and avoids dangerous silent failures. Consider adding a clear comment near the line and validation steps in CI to verify .env presence.

Applied to files:

  • Makefile
🪛 GitHub Actions: Merge Tests / 0_CI Build.txt
Makefile

[error] 72-72: make develop-pythontests failed (Error 1). Test run did not succeed.

🔇 Additional comments (4)
Makefile (2)

45-45: LGTM!

Also applies to: 48-48


50-54: LGTM!

images/openwisp_base/Dockerfile (2)

90-91: LGTM!


98-99: LGTM!

Comment thread images/common/openwisp/__init__.py Outdated
@CodingWithSaksham CodingWithSaksham marked this pull request as draft May 21, 2026 05:51
@CodingWithSaksham
Copy link
Copy Markdown
Author

I think the approach we had before was not bad, the problem is that it could be overridden with an env var which is wrong.

Any way, if you can't think of a better way to do this give me some more time to try this and come to a conclusion.

Lets discuss the approach for this first, for now I have converted the PR to a draft PR, once we agree on a final approach I'll make it ready for review

Multiple approaches do come to my mind

  1. To manually substituting __openwisp_version__ at runtime when we build the docker image. This can be done by substituting the previous value with the new value via regex substitution (maybe through build.py).
  2. At build time, generate a images/common/openwisp/_version.py file containing just __version__ = "26.01a". __init__.py imports from it.
  3. Package the app properly with setup.cfg or pyproject.toml and read version via importlib.metadata.version("openwisp").

And honestly? The 2nd option seems more promising to me as I have seen libraries like numpy and pandas do the same, it is similar to our current approach but less flaky.

@CodingWithSaksham CodingWithSaksham marked this pull request as ready for review May 22, 2026 03:35
@CodingWithSaksham
Copy link
Copy Markdown
Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
images/common/openwisp/__init__.py (1)

3-6: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a safe fallback when generated _version.py is unavailable.

Direct import from a generated module can break import openwisp in non-build contexts.

🔧 Proposed fix
-from ._version import __version__ as __openwisp_version__
+try:
+    from ._version import __version__ as __openwisp_version__
+except ModuleNotFoundError:
+    __openwisp_version__ = "unknown"
#!/bin/bash
# Verify whether the generated module is tracked and whether __init__ has a fallback.
git ls-files | rg -n '^images/common/openwisp/_version\.py$' || true
sed -n '1,40p' images/common/openwisp/__init__.py
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@images/common/openwisp/__init__.py` around lines 3 - 6, The direct import of
__openwisp_version__ from the generated _version.py can fail in non-build
contexts; update images/common/openwisp/__init__.py to import ._version within a
try/except ImportError (or ModuleNotFoundError), set a safe fallback value for
__openwisp_version__ (e.g., "0+unknown" or None) when the import fails, and keep
celery_app import and __all__ unchanged so import openwisp never raises if
_version.py is absent.
images/openwisp_base/Dockerfile (1)

51-78: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Quote build-arg expansions in conditional pip install commands.

These expansions are still unquoted, so build-arg values can be split into multiple arguments or interpreted unexpectedly by the shell.

🔧 Proposed fix
 RUN if [ "$OPENWISP_IPAM_SOURCE" != "default" ] ; then \
-  pip install --no-cache-dir --user --upgrade ${OPENWISP_IPAM_SOURCE}; \
+  pip install --no-cache-dir --user --upgrade "${OPENWISP_IPAM_SOURCE}"; \
   fi
@@
 RUN if [ "$OPENWISP_CONTROLLER_SOURCE" != "default" ] ; then \
-  pip install --no-cache-dir --user --upgrade ${OPENWISP_CONTROLLER_SOURCE}; \
+  pip install --no-cache-dir --user --upgrade "${OPENWISP_CONTROLLER_SOURCE}"; \
   fi
@@
 RUN if [ "$OPENWISP_NOTIFICATION_SOURCE" != "default" ] ; then \
-  pip install --no-cache-dir --user --upgrade ${OPENWISP_NOTIFICATION_SOURCE}; \
+  pip install --no-cache-dir --user --upgrade "${OPENWISP_NOTIFICATION_SOURCE}"; \
   fi
@@
 RUN if [ "$OPENWISP_USERS_SOURCE" != "default" ] ; then \
-  pip install --no-cache-dir --user --upgrade --force-reinstall ${OPENWISP_USERS_SOURCE}; \
+  pip install --no-cache-dir --user --upgrade --force-reinstall "${OPENWISP_USERS_SOURCE}"; \
   fi
@@
 RUN if [ "$DJANGO_X509_SOURCE" != "default" ]; then \
-  pip install --no-cache-dir --user --upgrade --force-reinstall ${DJANGO_X509_SOURCE}; \
+  pip install --no-cache-dir --user --upgrade --force-reinstall "${DJANGO_X509_SOURCE}"; \
   fi
#!/bin/bash
# Verify remaining unquoted variable expansions in pip install lines.
rg -nP 'pip install[^\n]*\$\{(OPENWISP_IPAM_SOURCE|OPENWISP_CONTROLLER_SOURCE|OPENWISP_NOTIFICATION_SOURCE|OPENWISP_USERS_SOURCE|DJANGO_X509_SOURCE)\}' images/openwisp_base/Dockerfile
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@images/openwisp_base/Dockerfile` around lines 51 - 78, The pip install
command invocations use unquoted build-arg expansions (e.g.
OPENWISP_IPAM_SOURCE, OPENWISP_CONTROLLER_SOURCE, OPENWISP_NOTIFICATION_SOURCE,
OPENWISP_USERS_SOURCE, OPENWISP_UTILS_SOURCE, DJANGO_X509_SOURCE) which can be
split or misinterpreted by the shell; update each RUN ... pip install ... ${VAR}
to quote the expansion (use "${VAR}") in the RUN blocks so each build-arg is
passed as a single argument (preserve existing flags like --no-cache-dir,
--user, --upgrade, --force-reinstall).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.gitignore:
- Line 86: The .gitignore currently ignores any file named "_version.py"
(pattern "_version.py"), which is too broad; update the rule to scope it to the
generated OpenWISP file path by replacing the global pattern with the exact
relative path to the generated file (for example "openwisp/_version.py" or the
actual generated module path used in the project) so only that generated file is
ignored and unrelated "_version.py" files are not hidden.

In `@build.py`:
- Around line 47-52: The current branch where updated == content silently
returns and leaves stale RELEASE_VERSION; instead fail fast: when updated ==
content (i.e., no RELEASE_VERSION found in makefile_path), write an error to
stderr (including makefile_path and that RELEASE_VERSION was not found) and exit
with a non-zero status (e.g., call sys.exit(1) or raise a RuntimeError) so the
process fails CI/packaging; update the block that references updated, content,
and makefile_path to perform this error print+nonzero exit instead of returning.
- Around line 62-66: The generated _version.py writes raw version into the
Python source (variable content built in build.py), which can break if version
contains quotes/newlines; change the string injection to emit a properly escaped
Python string literal (use repr(version) or json.dumps(version)) when building
content so __version__ is assigned a safe quoted/escaped value, updating the
content construction in build.py where content is created and ensuring any
needed import (json) is added.

---

Duplicate comments:
In `@images/common/openwisp/__init__.py`:
- Around line 3-6: The direct import of __openwisp_version__ from the generated
_version.py can fail in non-build contexts; update
images/common/openwisp/__init__.py to import ._version within a try/except
ImportError (or ModuleNotFoundError), set a safe fallback value for
__openwisp_version__ (e.g., "0+unknown" or None) when the import fails, and keep
celery_app import and __all__ unchanged so import openwisp never raises if
_version.py is absent.

In `@images/openwisp_base/Dockerfile`:
- Around line 51-78: The pip install command invocations use unquoted build-arg
expansions (e.g. OPENWISP_IPAM_SOURCE, OPENWISP_CONTROLLER_SOURCE,
OPENWISP_NOTIFICATION_SOURCE, OPENWISP_USERS_SOURCE, OPENWISP_UTILS_SOURCE,
DJANGO_X509_SOURCE) which can be split or misinterpreted by the shell; update
each RUN ... pip install ... ${VAR} to quote the expansion (use "${VAR}") in the
RUN blocks so each build-arg is passed as a single argument (preserve existing
flags like --no-cache-dir, --user, --upgrade, --force-reinstall).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 83c027d8-3d83-4b9f-a43a-a24e0bfa61be

📥 Commits

Reviewing files that changed from the base of the PR and between 8e3c12a and b12260a.

📒 Files selected for processing (5)
  • .gitignore
  • Makefile
  • build.py
  • images/common/openwisp/__init__.py
  • images/openwisp_base/Dockerfile
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{py,html}

📄 CodeRabbit inference engine (Custom checks)

For Django pull requests, ensure all user-facing strings are marked as translatable using the Django i18n framework

Files:

  • images/common/openwisp/__init__.py
  • build.py
🧠 Learnings (1)
📚 Learning: 2026-02-17T16:59:39.027Z
Learnt from: atif09
Repo: openwisp/docker-openwisp PR: 555
File: Makefile:4-5
Timestamp: 2026-02-17T16:59:39.027Z
Learning: In all Makefiles, prefer 'include' (not '-include') for critical config files like .env. If the file is missing, the build should fail explicitly rather than silently proceed with empty values. This ensures configurations are present and avoids dangerous silent failures. Consider adding a clear comment near the line and validation steps in CI to verify .env presence.

Applied to files:

  • Makefile
🪛 Checkov (3.2.529)
images/openwisp_base/Dockerfile

[low] 1-179: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)

🪛 Trivy (0.69.3)
images/openwisp_base/Dockerfile

[error] 102-179: Secrets passed via build-args or envs or copied secret files

Possible exposure of secret env "DJANGO_SECRET_KEY" in ENV

Rule: DS-0031

Learn more

(IaC/Dockerfile)


[error] 102-179: Secrets passed via build-args or envs or copied secret files

Possible exposure of secret env "EMAIL_HOST_PASSWORD" in ENV

Rule: DS-0031

Learn more

(IaC/Dockerfile)


[error] 102-179: Secrets passed via build-args or envs or copied secret files

Possible exposure of secret env "SSH_PRIVATE_KEY_PATH" in ENV

Rule: DS-0031

Learn more

(IaC/Dockerfile)

🔇 Additional comments (1)
Makefile (1)

39-54: LGTM!

Comment thread .gitignore Outdated
Comment thread build.py Outdated
Comment thread build.py Outdated
Comment on lines +62 to +66
content = (
"# This file is auto-generated at Docker image build time.\n"
"# Do not edit manually.\n"
f'__version__ = "{version}"\n'
)
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify why raw interpolation is unsafe for Python source generation.
python - <<'PY'
import ast
cases = ["26.06a", '26.06a"rc1', "26.06a\nnext"]
for v in cases:
    raw = f'__version__ = "{v}"\n'
    safe = f"__version__ = {v!r}\n"
    for label, src in [("raw", raw), ("safe", safe)]:
        try:
            ast.parse(src)
            ok = True
        except SyntaxError:
            ok = False
        print(f"{v!r:18} {label:4} -> parse_ok={ok}")
PY

Repository: openwisp/docker-openwisp

Length of output: 316


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Inspect build.py around the referenced lines to confirm the exact interpolation.
nl -ba build.py | sed -n '45,90p'

Repository: openwisp/docker-openwisp

Length of output: 111


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Show build.py with line numbers without using `nl`
awk '{printf "%d\t%s\n", NR, $0}' build.py | sed -n '55,75p'

Repository: openwisp/docker-openwisp

Length of output: 688


Escape version when generating images/common/openwisp/_version.py (build.py lines 62-66).
f'__version__ = "{version}"\n' writes raw version into Python source; if version contains quotes or newlines, the generated _version.py can become syntactically invalid and fail module parsing.

🔧 Proposed fix
     content = (
         "# This file is auto-generated at Docker image build time.\n"
         "# Do not edit manually.\n"
-        f'__version__ = "{version}"\n'
+        f"__version__ = {version!r}\n"
     )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build.py` around lines 62 - 66, The generated _version.py writes raw version
into the Python source (variable content built in build.py), which can break if
version contains quotes/newlines; change the string injection to emit a properly
escaped Python string literal (use repr(version) or json.dumps(version)) when
building content so __version__ is assigned a safe quoted/escaped value,
updating the content construction in build.py where content is created and
ensuring any needed import (json) is added.

Copy link
Copy Markdown
Member

@nemesifier nemesifier May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This becomes less important if we stop generating Python source during base-build, which I think we should. The better fix is to keep images/common/openwisp/_version.py tracked in the repo and update it through make update-version VERSION=.... If the helper writes that file, it should still use a safe Python literal such as {version!r} and fail if the update did not happen.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nemesifier, agreed — using !r ensures the version string is always a valid Python string literal regardless of its content. Here's the change:

  • Apply the one-line fix in build.py to use {version!r} instead of "{version}" when generating _version.py

Failed to handle agent chat message. Please try again.

Copy link
Copy Markdown
Member

@nemesifier nemesifier May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is stale after my updated comment above. Please do not keep generating this file during base-build. The requested approach is a tracked images/common/openwisp/_version.py, updated by a Makefile target and documented in the release/developer docs.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Resolve the stale build-time generation comment from CodeRabbit on this PR.
# First find the comment ID to resolve it.
gh api graphql -f query='
{
  repository(owner: "openwisp", name: "docker-openwisp") {
    pullRequest(number: 603) {
      reviewThreads(first: 50) {
        nodes {
          id
          isResolved
          comments(first: 5) {
            nodes {
              author { login }
              body
              url
            }
          }
        }
      }
    }
  }
}'

Length of output: 39519



@nemesifier, understood and apologies for the repeated stale reply. I'll drop the build-time generation framing entirely. To summarise the correct approach:

  1. images/common/openwisp/_version.py is a tracked repository file (not generated, not gitignored).
  2. A single make update-version VERSION=<x.y.z> Makefile target calls the build.py helper, which updates both RELEASE_VERSION in Makefile and __version__ in images/common/openwisp/_version.py. The helper should still use {version!r} when writing the Python file to produce a valid literal, and should fail hard if either file cannot be updated.
  3. The Docker build only copies the tracked file into the image; it does not generate anything.
  4. The make update-version target is documented in the release/developer docs.

The generate_version_module function in build.py is therefore repurposed (or renamed) to be used only by that Makefile target at release time, not during base-build. The generate-version call in base-build (Makefile) should be removed.


✏️ Learnings added
Learnt from: nemesifier
Repo: openwisp/docker-openwisp PR: 603
File: build.py:61-65
Timestamp: 2026-05-29T15:14:20.076Z
Learning: In docker-openwisp (repo: openwisp/docker-openwisp), `images/common/openwisp/_version.py` must be a **tracked** repository file — never generated at build time or gitignored. The correct approach: a `make update-version VERSION=<x.y.z>` Makefile target invokes a `build.py` helper that updates both `RELEASE_VERSION` in `Makefile` and `__version__` in `images/common/openwisp/_version.py` in one step, using `{version!r}` for safe Python literal generation, and fails hard if either file is not found. The Docker build only copies the tracked file. The target must be documented in the release/developer docs.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

… unit tests

While running unit tests, there was a chance that the initial _version.py was not generated, so in the Makefile, we add a method to generate _version.py with a default 'edge' value so that import errors don't happen
# 3. openwisp-monitoring: fping gdal-bin
# hadolint ignore=DL3008
RUN apt-get update && \
apt-get install --yes --no-install-recommends \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid unrelated changes

Comment thread images/openwisp_base/Dockerfile Outdated
@openwisp-companion
Copy link
Copy Markdown

Multiple Test Failures Detected

Hello @CodingWithSaksham,
(Analysis for commit cf68d21)

The CI build failed due to multiple test failures. Here's a breakdown:

1. Test Failures:

  • test_forgot_password: The expected success message was not found in the rendered HTML.

  • Fix: Review the test_forgot_password test and the corresponding HTML output to identify why the message is not being displayed or asserted correctly.

  • test_add_superuser: This test failed with a TimeoutException and StaleElementReferenceException, indicating that the test could not find or interact with elements on the page within the expected time, or that the element became stale. This often points to issues with page loading, element visibility, or changes in the DOM during the test.

  • Fix: Examine the test_add_superuser test and the associated Selenium interactions. Ensure that waits are correctly implemented for elements to become visible and interactable. The StaleElementReferenceException suggests that the element might have been found initially but then disappeared or changed before an action was performed on it.

  • test_radius_user_registration: The test expected a 201 status code but received a 400.

  • Fix: Investigate the test_radius_user_registration test. The 400 status code typically indicates a bad request. Check the request payload and the API endpoint's expected input to ensure they match.

These failures indicate issues with the application's functionality or the test suite's robustness. Please address these test failures to ensure the application behaves as expected and the tests are reliable.

@openwisp-companion
Copy link
Copy Markdown

Test Failures in CI

Hello @CodingWithSaksham,
(Analysis for commit 76f23cf)

The CI build failed due to the following test failures:

  1. test_add_superuser Failure:
    The test test_add_superuser in TestServices failed with a TimeoutException. This indicates that the Selenium driver could not find the expected "success" element within the given timeout. This might be due to a change in the UI or a timing issue during the test execution.
  • Fix: Investigate the UI changes in the admin interface for user creation and update the test_add_superuser test accordingly. If the "success" message is no longer present or has changed, adjust the assertion or the element locator.
  1. test_radius_user_registration Failure:
    The test test_radius_user_registration failed with an AssertionError: 400 != 201. This means that the API call to register a RADIUS user returned a 400 Bad Request status code instead of the expected 201 Created.
  • Fix: Examine the request payload sent in test_radius_user_registration and the server's response to understand why a 400 error is being returned. The issue might be with the data sent (e.g., incorrect password format, missing fields) or a change in the API's validation logic.
  1. test_add_superuser Failure (Retry):
    The test_add_superuser test failed again on retry with a TimeoutException, specifically when trying to find the "success" element. This reinforces the idea that the issue is likely related to the UI or test timing.
  • Fix: As mentioned above, review the UI for user creation success messages and adjust the test's element locator or add a more robust wait condition.
  1. test_radius_user_registration Failure (Retry):
    The test_radius_user_registration test failed again with AssertionError: 400 != 201. This indicates the underlying issue with the RADIUS user registration API call persists.
  • Fix: Re-evaluate the request payload and server response for the RADIUS user registration API. Ensure the password format and other fields meet the API's requirements.
  1. test_add_superuser Failure (Final Attempt):
    The test_add_superuser test failed for the third time with a TimeoutException.
  • Fix: Similar to the previous attempts, focus on the UI element locator and potential timing issues.
  1. test_radius_user_registration Failure (Final Attempt):
    The test_radius_user_registration test failed for the third time with AssertionError: 400 != 201.
  • Fix: The persistent failure suggests a more fundamental issue with the API endpoint or its interaction with the test setup. Debugging the API call and its response is crucial.

Note: The TimeoutError: timed out observed during the tearDownClass method in the initial logs suggests a potential network or service availability issue during cleanup, but the primary failures are the test assertions.

Copy link
Copy Markdown
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think the current generated ignored _version.py approach is the right solution. The version should be stored in a tracked file in the repo, updated by a Makefile target, and documented in the release/developer docs. Otherwise a clean checkout can fail to import openwisp, the source of truth is not reviewable, and the release output depends on a local generated artifact.


# This is autogenerated by Docker when running
# make base-build or make runtests
from ._version import __version__ as __openwisp_version__
Copy link
Copy Markdown
Member

@nemesifier nemesifier May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking this through, I do not think the generated ignored _version.py approach is acceptable. The version must be part of the repository, not an untracked build artifact. Otherwise a clean checkout cannot import openwisp, code review cannot see the source of truth, and the release process can silently build whatever happened to be generated locally.

Please change the approach to a tracked file, for example:

# images/common/openwisp/_version.py
__version__ = "25.10.0"

Then __init__.py can import it directly. Add a Makefile target such as make update-version VERSION=25.10.3 which updates both RELEASE_VERSION in Makefile and images/common/openwisp/_version.py in the same command. Document that target in the developer or release docs. The Docker build should only copy the tracked file into the image, not generate an ignored module at build time.

Comment thread build.py
return keygen


def update_makefile_version(new_version: str):
Copy link
Copy Markdown
Member

@nemesifier nemesifier May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper points in the right direction, but the implementation is incomplete. Updating only RELEASE_VERSION still leaves the Python version as a separate value, which is exactly the duplication this issue is about. It is also not wired to any Makefile target, so it is dead code in the current PR.

Please make this the single version update path instead: a Makefile target like make update-version VERSION=25.10.3 should call this helper, and the helper should update both RELEASE_VERSION in Makefile and the tracked images/common/openwisp/_version.py. It should fail if either file cannot be updated. Then document this target in the release/developer docs so maintainers know how to bump the version.

@openwisp-companion
Copy link
Copy Markdown

Test Failures in CI

Hello @CodingWithSaksham and @nemesifier,
(Analysis for commit 95c5edd)

There are multiple test failures in the CI logs:

  1. test_add_superuser failure: The test is failing with a TimeoutException because it cannot find the element with the class name "success". This indicates that the success message is not appearing as expected after the superuser creation.
  • Fix: Investigate why the "success" element is not found. This might be due to a change in the UI or a timing issue. Ensure the create_superuser method in tests/utils.py correctly handles the creation and waits for the success message.
  1. test_radius_user_registration failure: This test fails with an AssertionError because the status code returned is 400 instead of the expected 201. This suggests an issue with the RADIUS user registration API endpoint.
  • Fix: Examine the test_radius_user_registration method in tests/runtests.py and the corresponding API endpoint in the backend. The API might be returning a 400 Bad Request due to invalid data or a server-side error. Check the request payload and the server logs for more details.

These failures are preventing the tests from completing successfully. Please address these issues and push a new commit.

@openwisp-companion
Copy link
Copy Markdown

Commit Message and Test Failures

Hello @CodingWithSaksham,
(Analysis for commit c77811d)

The CI build failed due to two distinct issues:

  1. Commit Message Style: The commit message does not follow the required format. It is missing a prefix (e.g., [feature], [fix]) in the short description.

Correct Format Example:

[fix] Short descriptive title #123

A more detailed explanation of the changes made,
why they were made, and any other relevant information.
  1. Test Failures:
  • test_add_superuser: This test is failing with a TimeoutException and an AssertionError indicating that the element with class "success" was not visible. This suggests a potential issue with the UI element not appearing or the test waiting too long for it.
  • test_radius_user_registration: This test is failing with an AssertionError where the expected status code 201 was not received, and instead, 400 was returned. This indicates an issue with the API endpoint for user registration.

Please address the commit message format and investigate the test failures.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Duplication of __openwisp_version__ leads to stale info

2 participants