fix(docker): include LICENSE in runtime image for Apache-2.0 attribution#1520
fix(docker): include LICENSE in runtime image for Apache-2.0 attribution#1520aenawi wants to merge 2 commits intoOWASP:masterfrom
Conversation
The multi-stage runtime image copies in the nettacker wheel and its
virtualenv, but does not preserve the project's LICENSE file. This
matters for downstream rebuilds (e.g. native linux/arm64 republishes
on Apple Silicon, where the official hub image is amd64-only today):
rebuilders have to add a separate COPY LICENSE layer on top to meet
Apache-2.0 section 4(c), which is awkward.
Adding 'COPY LICENSE ./' in the runtime stage puts the license text
at /usr/src/owaspnettacker/LICENSE inside every image. Downstream
rebuilds then inherit the attribution automatically — no extra
layer or post-build tweak needed.
Also attempted a cleaner fix via 'pyproject.toml' (so the wheel's
dist-info would carry LICENSE natively, benefiting every consumer
including 'pip install nettacker'). Both 'include = ["LICENSE"]'
and 'include = [{ path = "LICENSE", format = ["sdist", "wheel"] }]'
were tested with the current poetry-core: neither places the file
in the nettacker-*.dist-info/ directory. Making that work would
require migrating to PEP 621 '[project]' style with 'license-files'
or switching the build backend — a larger change that belongs in
its own PR. This one keeps the minimum viable compliance fix.
One line + one comment. Zero runtime behavior change. Image grows
by ~11KB (LICENSE file size).
Summary by CodeRabbit
WalkthroughAdded a single line to the Dockerfile that copies the repository Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~2 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Dockerfile`:
- Around line 50-52: The PR is missing the required template sections and the
commit 4b390d6f32ad is unsigned; update the PR description to include the three
required headers "Proposed change", "Type of change", and "Checklist" matching
.github/PULL_REQUEST_TEMPLATE.md exactly, then locally sign the offending commit
(or all commits if needed) and force-push: run git commit --amend -S --no-edit
(or git rebase --exec 'git commit --amend --no-edit -S' ... for multiple
commits) and git push --force-with-lease so the commit(s) are GPG-signed and the
PR body complies with the template.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
| ### Preserve Apache-2.0 license text in the final image for downstream attribution | ||
| COPY LICENSE ./ | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify PR template sections and commit signature status for PR 1520 (read-only)
set -euo pipefail
echo "== PR body =="
gh pr view 1520 --repo OWASP/Nettacker --json body,author,url \
--jq '.url + "\nAuthor: @" + .author.login + "\n\n" + .body'
echo
echo "== Template section presence check =="
gh pr view 1520 --repo OWASP/Nettacker --json body --jq '.body' | \
python - <<'PY'
import sys
body = sys.stdin.read()
required = ["Proposed change", "Type of change", "Checklist"]
missing = [s for s in required if s.lower() not in body.lower()]
if missing:
print("Missing sections:", ", ".join(missing))
else:
print("All required section headers detected.")
PY
echo
echo "== Commit signature verification =="
gh api repos/OWASP/Nettacker/pulls/1520/commits --paginate | \
jq -r '.[] | [.sha[0:12], .commit.verification.verified, (.commit.verification.reason // "unknown")] | `@tsv`'Repository: OWASP/Nettacker
Length of output: 4589
🏁 Script executed:
#!/bin/bash
# Retry commit signature verification for PR 1520 with timeout handling
timeout 30 gh api repos/OWASP/Nettacker/pulls/1520/commits --jq '.[] | {sha: .sha[0:12], author: .commit.author.name, verified: .commit.verification.verified, reason: .commit.verification.reason}'Repository: OWASP/Nettacker
Length of output: 106
🏁 Script executed:
#!/bin/bash
# Commit signature verification for PR 1520
gh api repos/OWASP/Nettacker/pulls/1520/commits --jq '.[] | {sha: .sha[0:12], author: .commit.author.name, verified: .commit.verification.verified, reason: .commit.verification.reason}' | head -50Repository: OWASP/Nettacker
Length of output: 146
PR template non-compliant and commit unsigned — blocks merge.
This PR is missing all three required template sections ("Proposed change", "Type of change", "Checklist"). The PR body uses custom headers instead of .github/PULL_REQUEST_TEMPLATE.md format.
Additionally, the commit (4b390d6 by Hashem Aldhaheri) is unsigned. All commits in this repository must be GPG signed. @aenawi, please:
- Rewrite the PR description to match the three required template sections.
- Sign the commit and force-push:
Or use
git commit --amend -S --no-edit git push --force-with-leasegit rebase --exec 'git commit --amend --no-edit -S' ...if multiple commits need signing.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Dockerfile` around lines 50 - 52, The PR is missing the required template
sections and the commit 4b390d6f32ad is unsigned; update the PR description to
include the three required headers "Proposed change", "Type of change", and
"Checklist" matching .github/PULL_REQUEST_TEMPLATE.md exactly, then locally sign
the offending commit (or all commits if needed) and force-push: run git commit
--amend -S --no-edit (or git rebase --exec 'git commit --amend --no-edit -S' ...
for multiple commits) and git push --force-with-lease so the commit(s) are
GPG-signed and the PR body complies with the template.
|
@aenawi PRs with unsigned commits and missing linked issue cannot be accepted. Please follow the contribution guidelines and the PR template (which you copy-pasted over with some AI-generated text!) and make sure to sign your commits |
Summary
Add
COPY LICENSE ./to the runtime stage of the Dockerfile so the Apache-2.0 license text lands inside every built image at/usr/src/owaspnettacker/LICENSE. One line + one comment + one blank line; zero runtime behavior change; ~11KB image size increase.Why
Apache-2.0 section 4(c) requires distributions of the work or derivative works to retain the license text. The multi-stage runtime image produced by the current Dockerfile ships the virtualenv and the
nettackerwheel — both clean — but no LICENSE file ends up at a visible path in the final image.Verified by building
masterlocally and inspecting:Seven files, no
LICENSE. Every other package in the venv (Flask, SQLAlchemy, cryptography, etc.) ships its LICENSE inside its owndist-info/— only nettacker's own wheel doesn't. So when a downstream distributor rebuilds the image (e.g. to produce a nativelinux/arm64variant for Apple Silicon, since the official hub image is amd64-only today), the rebuilder has to add a separateCOPY LICENSElayer on top to stay compliant. That's easy to forget and clumsy to explain.The change
Placed in the runtime stage (not the builder) so it lands in the final image without affecting the wheel build or the builder-stage cache layers.
Why Dockerfile and not pyproject.toml
Before writing this, I checked whether the cleaner fix would be to include LICENSE inside the wheel's
dist-info/— benefittingpip install nettackerconsumers too, not just Docker users. Tried two Poetryincludesyntaxes against currentpoetry-core:Neither placed
LICENSEintonettacker-*.dist-info/in the built wheel. Poetry'sincludedirective apparently copies into the wheel's top-level (next to the package directory) but not intodist-info/. The canonical fix at the packaging layer would require either migrating from legacy[tool.poetry]to PEP 621[project]+license-files = ["LICENSE"], or switching the build backend — a larger refactor than a compliance fix warrants.Happy to open a separate issue discussing the wheel-side fix if the maintainers would prefer that route long-term. This PR keeps scope to the minimum viable compliance improvement for the published Docker image.
Compatibility
docker cpordocker run --entrypoint shto inspect.docker-compose.yml, CI workflows, or any user-facing documented command.Test plan
docker build .succeeds on current masterdocker run --rm --entrypoint sh <image> -c 'ls -la /usr/src/owaspnettacker/LICENSE'shows the file present (11357 bytes, mode 644)head -3 /usr/src/owaspnettacker/LICENSEinside the image confirms it's the Apache-2.0 textdocker run --rm <image>(no args) anddocker run --rm <image> --helpboth behave identically to before (the CMD/ENTRYPOINT pair added in the recent multi-stage refactor is preserved unchanged)Context
Found this while building native multi-arch rebuilds for Apple Silicon workstations. The ENTRYPOINT fix I was also going to offer is already in master (thank you!) — this PR is just the remaining LICENSE piece. No strong opinion on final form; happy to iterate if the maintainers want the fix approached differently.