├── .github ├── CODEOWNERS ├── FUNDING.yml ├── dependabot.yaml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── dockerhub.yaml │ ├── publish.yaml │ ├── linter.yaml │ ├── autoupdate-drawio-desktop.yaml │ └── docker-drawio-desktop-headless.yaml ├── tests ├── expected │ ├── output-create-command.log │ ├── export-file1.log │ ├── export-file2.log │ ├── export-non-root.log │ ├── export-check-firstrun.log │ ├── export-check-secondrun.log │ ├── export-check-thirdrun.log │ ├── output-unknown-file.log │ ├── export-issue-20.log │ ├── fonts-chinese.png │ ├── uniq-output-electron-security-warning.log │ ├── uniq-output-unknown-file-electron-security-warning.log │ ├── issue-20-frame-bug-dark.svg │ └── issue-20-frame-bug-light.svg ├── fonts.bats ├── timeout.bats ├── error.bats ├── issues.bats ├── data │ ├── issue-20 │ │ ├── frame-bug-dark.drawio │ │ └── frame-bug-light.drawio │ ├── fonts │ │ └── chinese.drawio │ ├── file 2.drawio │ ├── file1.drawio │ ├── file3.drawio │ └── file4.drawio ├── export.bats └── base.bats ├── src ├── unwanted-update-logs.txt ├── unwanted-security-warnings.txt ├── runner.sh ├── runner_wrapper.sh └── entrypoint.sh ├── .gitignore ├── .editorconfig ├── SECURITY.md ├── LICENSE ├── DOCKER.md ├── CONTRIBUTING.md ├── Dockerfile ├── justfile ├── CODE_OF_CONDUCT.md └── README.adoc /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @rlespinasse 2 | -------------------------------------------------------------------------------- /tests/expected/output-create-command.log: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/expected/export-file1.log: -------------------------------------------------------------------------------- 1 | file1.drawio -> file1.pdf 2 | -------------------------------------------------------------------------------- /tests/expected/export-file2.log: -------------------------------------------------------------------------------- 1 | file 2.drawio -> file 2.pdf 2 | -------------------------------------------------------------------------------- /tests/expected/export-non-root.log: -------------------------------------------------------------------------------- 1 | file4.drawio -> file4.pdf 2 | -------------------------------------------------------------------------------- /tests/expected/export-check-firstrun.log: -------------------------------------------------------------------------------- 1 | file3.drawio -> file3.pdf 2 | -------------------------------------------------------------------------------- /tests/expected/export-check-secondrun.log: -------------------------------------------------------------------------------- 1 | file3.drawio -> file3-1.pdf 2 | -------------------------------------------------------------------------------- /tests/expected/export-check-thirdrun.log: -------------------------------------------------------------------------------- 1 | file3.drawio -> file3.pdf 2 | -------------------------------------------------------------------------------- /tests/expected/output-unknown-file.log: -------------------------------------------------------------------------------- 1 | Error: input file/directory not found 2 | -------------------------------------------------------------------------------- /tests/expected/export-issue-20.log: -------------------------------------------------------------------------------- 1 | issue-20/frame-bug.drawio -> issue-20/frame-bug.svg 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: rlespinasse 4 | -------------------------------------------------------------------------------- /src/unwanted-update-logs.txt: -------------------------------------------------------------------------------- 1 | Checking for beta autoupdate feature for deb/rpm distributions 2 | Found package-type: deb 3 | -------------------------------------------------------------------------------- /tests/expected/fonts-chinese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rlespinasse/docker-drawio-desktop-headless/HEAD/tests/expected/fonts-chinese.png -------------------------------------------------------------------------------- /src/unwanted-security-warnings.txt: -------------------------------------------------------------------------------- 1 | Failed to call 2 | Failed to connect 3 | Failed to post 4 | Floss manager service 5 | InitializeSandbox() called with 6 | dri3 extension not 7 | -------------------------------------------------------------------------------- /src/runner.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | if [[ "${SCRIPT_DEBUG_MODE:-false}" == "true" ]]; then 5 | set -x 6 | fi 7 | 8 | "${DRAWIO_DESKTOP_EXECUTABLE_PATH:?}" "$@" --no-sandbox --disable-gpu 9 | -------------------------------------------------------------------------------- /tests/fonts.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | # shellcheck source=/dev/null 4 | . tests/base.bats 5 | 6 | @test "Fonts chinese" { 7 | docker_test "" 0 "export-fonts-chinese" "tests/data" -x -f png fonts/chinese.drawio 8 | diff tests/expected/fonts-chinese.png tests/data/fonts/chinese.png 9 | } 10 | -------------------------------------------------------------------------------- /src/runner_wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | if [[ "${SCRIPT_DEBUG_MODE:-false}" == "true" ]]; then 5 | set -x 6 | fi 7 | 8 | # Run and filter output 9 | "${DRAWIO_DESKTOP_RUNNER_COMMAND_LINE:?}" "$@" 2>&1 | grep -Fvf "${DRAWIO_DESKTOP_SOURCE_FOLDER:?}/unwanted-lines.txt" 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # node 2 | node_modules/ 3 | package-lock.json 4 | 5 | # test runs 6 | output/ 7 | *.pdf 8 | *.svg 9 | *.png 10 | !tests/expected/*.svg 11 | !tests/expected/*.png 12 | 13 | # non-root user runs 14 | home 15 | .cache 16 | .config 17 | core 18 | 19 | # repository 20 | patch.diff 21 | package.json 22 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.log] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /tests/timeout.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | # shellcheck source=/dev/null 4 | . tests/base.bats 5 | 6 | @test "Timeout for using create command" { 7 | docker_test "-e DRAWIO_DESKTOP_COMMAND_TIMEOUT=2s" 1 "output-create-command" "tests/data" --create 8 | } 9 | 10 | @test "Timeout for using wrong command" { 11 | docker_test "-e DRAWIO_DESKTOP_COMMAND_TIMEOUT=2s" 1 "output-wrong-command" "tests/data" --wrong-command 12 | } 13 | -------------------------------------------------------------------------------- /tests/error.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | # shellcheck source=/dev/null 4 | . tests/base.bats 5 | 6 | @test "Output an error on unknown file" { 7 | docker_test "" 1 "output-unknown-file" "tests/data" -x unknown.drawio 8 | } 9 | 10 | @test "Output an error on unknown file with electron security warning" { 11 | docker_test "-e ELECTRON_DISABLE_SECURITY_WARNINGS=false" 0 "output-unknown-file-electron-security-warning" "tests/data" -x unknown.drawio 12 | } 13 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'docker' 4 | directory: '/' 5 | commit-message: 6 | prefix: 'feat: ' 7 | schedule: 8 | interval: 'weekly' 9 | day: 'monday' 10 | time: '00:00' 11 | labels: [] 12 | 13 | - package-ecosystem: 'github-actions' 14 | directory: '/' 15 | schedule: 16 | interval: 'weekly' 17 | groups: 18 | dependencies: 19 | patterns: 20 | - '*' 21 | labels: [] 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots** 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Additional context** 23 | Add any other context about the problem here. 24 | -------------------------------------------------------------------------------- /tests/expected/uniq-output-electron-security-warning.log: -------------------------------------------------------------------------------- 1 | Failed to call method: org.freedesktop.DBus.NameHasOwner: object_path= /org/freedesktop/DBus: unknown error type: 2 | Failed to connect to the bus: Could not parse server address: Unknown address type (examples of valid types are "tcp" and on UNIX "unix") 3 | Failed to connect to the bus: Failed to connect to socket /run/dbus/system_bus_socket: No such file or directory 4 | Floss manager service not available, cannot set Floss enable/disable. 5 | InitializeSandbox() called with multiple threads in process gpu-process. 6 | dri3 extension not supported. 7 | file1.drawio -> file1.pdf 8 | -------------------------------------------------------------------------------- /tests/expected/uniq-output-unknown-file-electron-security-warning.log: -------------------------------------------------------------------------------- 1 | Error: input file/directory not found 2 | Failed to call method: org.freedesktop.DBus.NameHasOwner: object_path= /org/freedesktop/DBus: unknown error type: 3 | Failed to connect to the bus: Could not parse server address: Unknown address type (examples of valid types are "tcp" and on UNIX "unix") 4 | Failed to connect to the bus: Failed to connect to socket /run/dbus/system_bus_socket: No such file or directory 5 | Floss manager service not available, cannot set Floss enable/disable. 6 | InitializeSandbox() called with multiple threads in process gpu-process. 7 | dri3 extension not supported. 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /tests/issues.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | # shellcheck source=/dev/null 4 | . tests/base.bats 5 | 6 | @test "Issue 20 : frame bug / svg :: theme=light" { 7 | docker_test "" 0 "export-issue-20-light" "tests/data" -x -f svg issue-20/frame-bug-light.drawio --svg-theme light 8 | diff <(xmllint --format tests/expected/issue-20-frame-bug-light.svg) <(xmllint --format tests/data/issue-20/frame-bug-light.svg) 9 | } 10 | 11 | @test "Issue 20 : frame bug / svg :: theme=dark" { 12 | docker_test "" 0 "export-issue-20-dark" "tests/data" -x -f svg issue-20/frame-bug-dark.drawio --svg-theme dark 13 | diff <(xmllint --format tests/expected/issue-20-frame-bug-dark.svg) <(xmllint --format tests/data/issue-20/frame-bug-dark.svg) 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/dockerhub.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Update Docker Hub information 3 | 4 | on: 5 | release: 6 | types: [published] 7 | push: 8 | branches: 9 | - v1.x 10 | paths: 11 | - DOCKER.md 12 | - .github/workflows/dockerhub.yaml 13 | 14 | permissions: read-all 15 | 16 | jobs: 17 | dockerHubDescription: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v6 22 | 23 | - name: Sync information on Docker Hub 24 | uses: peter-evans/dockerhub-description@v5 25 | with: 26 | username: rlespinasse 27 | password: ${{ secrets.DOCKER_PASSWORD }} 28 | repository: rlespinasse/drawio-desktop-headless 29 | readme-filepath: ./DOCKER.md 30 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions and Branches 4 | 5 | | Version | Supported | End of Support | Branch | 6 | | ------- | ------------------ | -------------- | ------ | 7 | | 1.x | :white_check_mark: | | v1.x | 8 | 9 | ### End of Life of a branch 10 | 11 | Since `2024-10-27`, when a new major version is released, 12 | 13 | - The previous one will continue to receive security patches for 3 months, 14 | - After the 3 months, the branch is deleted, and only the tags remain. 15 | 16 | ## Reporting a Vulnerability 17 | 18 | In this project, you can report a Vulnerability by creating a [draft security advisory](https://github.com/rlespinasse/docker-drawio-desktop-headless/security/advisories). 19 | 20 | If the vulnerability is confirmed, a fix will be produced and the advisory will be published. 21 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Publish to Registry 3 | 4 | on: 5 | release: 6 | types: [published] 7 | 8 | permissions: read-all 9 | 10 | jobs: 11 | update: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v6 15 | 16 | - uses: rlespinasse/github-slug-action@v5 17 | 18 | - name: Set up QEMU 19 | uses: docker/setup-qemu-action@v3 20 | with: 21 | platforms: "arm64,arm" 22 | 23 | - name: Set up Docker Buildx 24 | uses: docker/setup-buildx-action@v3 25 | 26 | - name: Publish to Registry 27 | uses: elgohr/Publish-Docker-Github-Action@v5 28 | with: 29 | name: rlespinasse/drawio-desktop-headless 30 | username: ${{ secrets.DOCKER_USERNAME }} 31 | password: ${{ secrets.DOCKER_PASSWORD }} 32 | tags: "latest,${{ env.GITHUB_REF_SLUG }}" 33 | platforms: linux/amd64,linux/arm64 34 | -------------------------------------------------------------------------------- /tests/data/issue-20/frame-bug-dark.drawio: -------------------------------------------------------------------------------- 1 | xZTbToQwEIafhstNoAi7XrpHo9GYrMbVG1NpOWhhsFsEfHrLthwqJsbEww2ZfjP8AzM/WO4irTYc5/EFEMosZJPKcpcWQlPfldcG1Ap4s5kCEU+IQk4Ptskb1dDWtEgI3RuFAoCJJDdhAFlGA2EwzDmUZlkIzOya44iOwDbAbExvEyJiRdHM7vkpTaJYd3aRTjzi4DniUGS6XQYZVZkUtyq6dB9jAuUAuSvLXXAAoaK0WlDWDLUd2PHT9f38YbfFDK+L25V9tirZRImtv3NL926cZuJnpdGx0n7FrNCTtJDPZJf5owyiJmhBCLK7HIOo9dD9lwLaxGR/sMSJLHBQXvXJVmUDQDpp/lFbPraSH+HBYyCjO5L7yJuwSNma41SG8zJOBN3mOGh4KY0uWSxSJk9Ok9bO8LyGt3bw7U79yxHrVbxSLmg1cJ4e+YZCSgWvZYnOHmnz1Oax7D3qewrFA3t2nxXWn0XUCfcbloFe8ucLd+0wu6zvyvPl1d1ucrPxQrLTHvmDfc8x+Z/lHtZpLjdMGFsAAy4BoSEuDv33gsMzHfPfsoLjm15wnLEZpvbYDNPve0Ee+//SITf467urdw== -------------------------------------------------------------------------------- /tests/data/issue-20/frame-bug-light.drawio: -------------------------------------------------------------------------------- 1 | xZTbToQwEIafhstNoAi7XrpHo9GYrMbVG1NpOWhhsFsEfHrLthwqJsbEww2ZfjP8AzM/WO4irTYc5/EFEMosZJPKcpcWQlPfldcG1Ap4s5kCEU+IQk4Ptskb1dDWtEgI3RuFAoCJJDdhAFlGA2EwzDmUZlkIzOya44iOwDbAbExvEyJiRdHM7vkpTaJYd3aRTjzi4DniUGS6XQYZVZkUtyq6dB9jAuUAuSvLXXAAoaK0WlDWDLUd2PHT9f38YbfFDK+L25V9tirZRImtv3NL926cZuJnpdGx0n7FrNCTtJDPZJf5owyiJmhBCLK7HIOo9dD9lwLaxGR/sMSJLHBQXvXJVmUDQDpp/lFbPraSH+HBYyCjO5L7yJuwSNma41SG8zJOBN3mOGh4KY0uWSxSJk9Ok9bO8LyGt3bw7U79yxHrVbxSLmg1cJ4e+YZCSgWvZYnOHmnz1Oax7D3qewrFA3t2nxXWn0XUCfcbloFe8ucLd+0wu6zvyvPl1d1ucrPxQrLTHvmDfc8x+Z/lHtZpLjdMGFsAAy4BoSEuDv33gsMzHfPfsoLjm15wnLEZpvbYDNPve0Ee+//SITf467urdw== -------------------------------------------------------------------------------- /.github/workflows/linter.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lint Code Base 3 | 4 | on: pull_request 5 | 6 | permissions: read-all 7 | 8 | jobs: 9 | lint: 10 | runs-on: ubuntu-latest 11 | 12 | permissions: 13 | contents: read 14 | packages: read 15 | statuses: write 16 | 17 | steps: 18 | - name: Checkout Code 19 | uses: actions/checkout@v6 20 | with: 21 | # Full git history is needed to get a proper 22 | # list of changed files within `super-linter` 23 | fetch-depth: 0 24 | 25 | - name: Lint Code Base 26 | uses: super-linter/super-linter@v8 27 | env: 28 | VALIDATE_ALL_CODEBASE: false 29 | VALIDATE_BIOME_FORMAT: false 30 | VALIDATE_BIOME_LINT: false 31 | VALIDATE_GITHUB_ACTIONS_ZIZMOR: false 32 | VALIDATE_TRIVY: false 33 | VALIDATE_YAML_PRETTIER: false 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | -------------------------------------------------------------------------------- /.github/workflows/autoupdate-drawio-desktop.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Autoupdate Drawio Desktop 3 | 4 | on: 5 | schedule: 6 | - cron: "0 0 * * 1" # Every Monday at midnight (UTC) 7 | workflow_dispatch: 8 | 9 | permissions: 10 | contents: write 11 | pull-requests: write 12 | 13 | concurrency: 14 | group: autoupdate-drawio-desktop 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | autoupdate: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v6 23 | 24 | - uses: taiki-e/install-action@just 25 | 26 | - run: just autoupdate-drawio-desktop 27 | id: autoupdate-drawio-desktop 28 | env: 29 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 30 | shell: bash 31 | 32 | - uses: peter-evans/create-pull-request@v7 33 | with: 34 | title: "feat: update to drawio-desktop ${{ steps.autoupdate-drawio-desktop.outputs.release_version }}" 35 | branch: autoupdate-drawio-desktop 36 | token: ${{ secrets.GH_TOKEN }} 37 | -------------------------------------------------------------------------------- /src/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | if [[ "${SCRIPT_DEBUG_MODE:-false}" == "true" ]]; then 5 | set -x 6 | fi 7 | 8 | # Prepare output cleaning 9 | touch "${DRAWIO_DESKTOP_SOURCE_FOLDER:?}/unwanted-lines.txt" 10 | if [[ "${ELECTRON_DISABLE_SECURITY_WARNINGS:?}" == "true" ]]; then 11 | cat "${DRAWIO_DESKTOP_SOURCE_FOLDER:?}/unwanted-security-warnings.txt" >>"${DRAWIO_DESKTOP_SOURCE_FOLDER:?}/unwanted-lines.txt" 12 | fi 13 | 14 | if [[ "${DRAWIO_DISABLE_UPDATE:?}" == "true" ]]; then 15 | # Remove 'deb support' logs 16 | # since 'autoUpdater.logger.transports.file.level' is set as 'info' on drawio-desktop 17 | cat "${DRAWIO_DESKTOP_SOURCE_FOLDER:?}/unwanted-update-logs.txt" >>"${DRAWIO_DESKTOP_SOURCE_FOLDER:?}/unwanted-lines.txt" 18 | fi 19 | 20 | # Start Xvfb 21 | export DISPLAY="${XVFB_DISPLAY:?}" 22 | # shellcheck disable=SC2086 23 | # shellcheck disable=SC2154 24 | Xvfb "${XVFB_DISPLAY:?}" ${XVFB_OPTIONS} & 25 | 26 | # Run 27 | 28 | timeout "${DRAWIO_DESKTOP_COMMAND_TIMEOUT:?}" "${DRAWIO_DESKTOP_SOURCE_FOLDER:?}/runner_wrapper.sh" "$@" 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Romain Lespinasse 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/export.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | # shellcheck source=/dev/null 4 | . tests/base.bats 5 | 6 | @test "Export a drawio file as pdf" { 7 | docker_test "" 0 "export-file1" "tests/data" -x file1.drawio 8 | } 9 | 10 | @test "Export a drawio file as pdf with electron security warning" { 11 | docker_test "-e ELECTRON_DISABLE_SECURITY_WARNINGS=false" 0 "output-electron-security-warning" "tests/data" -x file1.drawio 12 | } 13 | 14 | @test "Export a drawio file with space in its name" { 15 | docker_test "" 0 "export-file2" "tests/data" -x "file 2.drawio" 16 | } 17 | 18 | @test "Export as non-root" { 19 | docker_test "--user $(id --user):$(id --group) -v /etc/passwd:/etc/passwd --env HOME=/data/home" 0 "export-non-root" "tests/data" -x file4.drawio 20 | } 21 | 22 | @test "Export using unknown argument" { 23 | docker_test "" 0 "export-file1" "tests/data" --export file1.drawio --wrong-argument 24 | } 25 | 26 | @test "Export with check command" { 27 | docker_test "" 1 "export-check-firstrun" "tests/data" -export --check file3.drawio 28 | docker_test "" 1 "export-check-secondrun" "tests/data" -export --check file3.drawio 29 | docker_test "" 1 "export-check-thirdrun" "tests/data" -export file3.drawio 30 | } 31 | -------------------------------------------------------------------------------- /DOCKER.md: -------------------------------------------------------------------------------- 1 | # Draw.io Desktop Headless docker image 2 | 3 | [Dockerized headless][1] version of [Draw.io Desktop][2] 4 | 5 | ## What is does 6 | 7 | Draw.io Desktop expose a command-line client to allow us to create, check or export diagrams. 8 | 9 | Since Draw.io Desktop is an GUI application, we need an GUI environment to run it. 10 | And this prevent us to use it for automation in non-GUI environment such as CI tools. 11 | 12 | This [docker image][1] enable us to run the command-line client in a headless mode. 13 | 14 | ## Running 15 | 16 | ```bash 17 | docker run -it -v $(pwd):/data rlespinasse/drawio-desktop-headless 18 | ``` 19 | 20 | Read about [docker image configuration][3] 21 | 22 | ## License 23 | 24 | View [license information][4] for the software contained in this image. 25 | 26 | As for any pre-built image usage, it is the image user's responsibility to ensure that any use of this image complies with any relevant licenses for all software contained within. 27 | 28 | [1]: https://github.com/rlespinasse/docker-drawio-desktop-headless 29 | [2]: https://github.com/jgraph/drawio-desktop 30 | [3]: https://github.com/rlespinasse/docker-drawio-desktop-headless/blob/v1.x/README.adoc#configuration 31 | [4]: https://github.com/rlespinasse/docker-drawio-desktop-headless/blob/v1.x/LICENSE 32 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute to Docker Draw.io Desktop Headless 2 | 3 | ## Did you find a bug 4 | 5 | * **Do not open up a GitHub issue if the bug is a security vulnerability**, and instead to refer to our [security policy][1]. 6 | 7 | * **Ensure the bug was not already reported** by searching on GitHub under [Issues][2]. 8 | 9 | * If you're unable to find an open issue addressing the problem, [open a 'Bug' issue][4]. 10 | Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring. 11 | 12 | ## Did you write a patch that fixes a bug 13 | 14 | * Open a new GitHub pull request with the patch. 15 | 16 | * Ensure the PR description clearly describes the problem and solution. 17 | Include the relevant issue number if applicable. 18 | 19 | ## Do you intend to add a new feature or change an existing one 20 | 21 | * Suggest your change by [opening a 'Feature request' issue][5] 22 | 23 | ## Do you have questions about the source code 24 | 25 | * [open an issue][3] with your question. 26 | 27 | Thanks! 28 | 29 | [1]: https://github.com/rlespinasse/docker-drawio-desktop-headless/security/policy 30 | [2]: https://github.com/rlespinasse/docker-drawio-desktop-headless/issues 31 | [3]: https://github.com/rlespinasse/docker-drawio-desktop-headless/issues/new 32 | [4]: https://github.com/rlespinasse/docker-drawio-desktop-headless/issues/new?assignees=&labels=bug&template=bug_report.md&title= 33 | [5]: https://github.com/rlespinasse/docker-drawio-desktop-headless/issues/new?assignees=&labels=enhancement&template=feature_request.md&title= -------------------------------------------------------------------------------- /tests/base.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | docker_test() { 4 | # Get parameters 5 | local docker_opts=$1 6 | local status=$2 7 | local output_file=$3 8 | local data_folder=$4 9 | shift 10 | shift 11 | shift 12 | shift 13 | 14 | # Run command 15 | # shellcheck disable=SC2086 16 | echo docker container run -t $docker_opts -w /data -v "$(pwd)/${data_folder:-}":/data ${DOCKER_IMAGE} "$@" >>tests/output/$output_file-command.log 17 | # shellcheck disable=SC2086 18 | run docker container run -t $docker_opts -w /data -v "$(pwd)/${data_folder:-}":/data ${DOCKER_IMAGE} "$@" 19 | 20 | # Remove timed logging tags on electron logs by default. 21 | # shellcheck disable=SC2154 22 | echo "$output" | tee "tests/output/$output_file.log" | sed 's#\[.*:.*/.*\..*:.*:.*\(.*\)\] ##' >"tests/output/$output_file-comp.log" 23 | 24 | # Test status 25 | # shellcheck disable=SC2086 26 | [ "$status" -eq $status ] 27 | # Test output 28 | if [ -f "tests/expected/$output_file.log" ]; then 29 | diff -u --strip-trailing-cr "tests/expected/$output_file.log" "tests/output/$output_file-comp.log" >"tests/output/$output_file-diff.log" 30 | elif [ -f "tests/expected/uniq-$output_file.log" ]; then 31 | # For now, I remove sqlite_persistent_shared_dictionary_store logs from expected output since this line is inconsistent across runs 32 | diff -u --strip-trailing-cr "tests/expected/uniq-$output_file.log" <(LC_COLLATE=C sort -u "tests/output/$output_file-comp.log" | grep -v "sqlite_persistent_shared_dictionary_store") >"tests/output/$output_file-diff.log" 33 | fi 34 | if [ -f "tests/output/$output_file-diff.log" ]; then 35 | [ "$(cat "tests/output/$output_file-diff.log")" = "" ] 36 | fi 37 | } 38 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #checkov:skip=CKV_DOCKER_2 2 | #checkov:skip=CKV_DOCKER_3 3 | FROM debian:trixie 4 | ARG TARGETARCH 5 | 6 | WORKDIR "/opt/drawio-desktop" 7 | 8 | # hadolint ignore=DL3008,DL3015 9 | RUN < 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/data/file 2.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /tests/data/file1.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /tests/data/file3.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /tests/data/file4.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S just --justfile 2 | 3 | set quiet := true 4 | 5 | # Set default architecture based on machine type 6 | arch := if arch() == "aarch64" { "arm64" } else { "amd64" } 7 | 8 | # Default docker image name 9 | docker_image := env_var_or_default("DOCKER_IMAGE", "rlespinasse/drawio-desktop-headless:local") 10 | 11 | default: 12 | just --choose 13 | 14 | # Build the Docker image for current architecture 15 | [group('Development mode')] 16 | build: 17 | docker build --build-arg="TARGETARCH={{arch}}" -t {{docker_image}} . 18 | 19 | # Build the Docker image without cache 20 | [group('Development mode')] 21 | build-no-cache: 22 | docker build --build-arg="TARGETARCH={{arch}}" --no-cache --progress plain -t {{docker_image}} . 23 | 24 | # Build for multiple architectures 25 | [group('Development mode')] 26 | build-multiarch: 27 | docker buildx build --platform linux/amd64,linux/arm64 -t {{docker_image}} . 28 | 29 | # Clean up test artifacts 30 | [group('Development mode')] 31 | cleanup: 32 | rm -rf tests/output 33 | rm -rf tests/data/home 34 | find tests/data \( -name "*.pdf" -o -name "*.svg" -o -name "*.png" \) -delete 35 | 36 | # Run the Docker container 37 | [group('Development mode')] 38 | run *ARGS: 39 | docker run -t {{env_var_or_default("DOCKER_OPTIONS", "")}} -w /data -v {{invocation_directory()}}:/data {{docker_image}} {{ARGS}} 40 | 41 | # Run tests 42 | [group('Testing mode')] 43 | test: cleanup build test-ci 44 | 45 | # Setup CI test environment 46 | [group('Testing mode')] 47 | test-ci-setup: 48 | npm install bats 49 | sudo apt-get update 50 | sudo apt-get install -y libxml2-utils 51 | 52 | # Run CI tests 53 | [group('Testing mode')] 54 | test-ci: 55 | mkdir -p tests/output 56 | DOCKER_IMAGE={{docker_image}} npx bats --verbose-run -r tests 57 | 58 | # Auto-update drawio-desktop version 59 | [group('Maintenance mode')] 60 | autoupdate-drawio-desktop: 61 | #!/usr/bin/env bash 62 | DRAWIO_DESKTOP_RELEASE=$(gh release list --repo jgraph/drawio-desktop | grep "Latest" | cut -f1) 63 | sed -i 's/DRAWIO_VERSION=.*/DRAWIO_VERSION="'$DRAWIO_DESKTOP_RELEASE'"/' Dockerfile 64 | sed -i 's/Draw\.io Desktop v.*/Draw.io Desktop v'$DRAWIO_DESKTOP_RELEASE'\]/' README.adoc 65 | if [ -n "${GITHUB_OUTPUT}" ]; then 66 | echo "release_version=$DRAWIO_DESKTOP_RELEASE" >> "${GITHUB_OUTPUT}" 67 | fi 68 | echo "Updated to Draw.io Desktop version $DRAWIO_DESKTOP_RELEASE" 69 | 70 | [group('Maintenance mode')] 71 | patch: patch-unwanted-security-warnings patch-tests 72 | 73 | [private] 74 | patch-unwanted-security-warnings: 75 | #!/usr/bin/env bash 76 | cat tests/output/output-electron-security-warning-comp.log | \ 77 | # For now, I remove sqlite_persistent_shared_dictionary_store logs from expected output since this line is inconsistent across runs 78 | grep -v "sqlite_persistent_shared_dictionary_store" | \ 79 | LC_COLLATE=C sort -u > tests/expected/uniq-output-electron-security-warning.log 80 | cat tests/output/output-unknown-file-electron-security-warning-comp.log | \ 81 | # For now, I remove sqlite_persistent_shared_dictionary_store logs from expected output since this line is inconsistent across runs 82 | grep -v "sqlite_persistent_shared_dictionary_store" | \ 83 | LC_COLLATE=C sort -u > tests/expected/uniq-output-unknown-file-electron-security-warning.log 84 | 85 | echo 86 | { 87 | awk '{print $1, $2, $3}' tests/output/output-electron-security-warning-comp.log; 88 | awk '{print $1, $2, $3}' tests/output/output-unknown-file-electron-security-warning-comp.log; 89 | } | \ 90 | grep -v "file1.drawio" | \ 91 | grep -v "input file/directory" | \ 92 | LC_COLLATE=C sort -u > src/unwanted-security-warnings.txt 93 | git diff --exit-code src/unwanted-security-warnings.txt || \ 94 | echo "Unwanted Security Warnings have been updated. Please check the changes before committing." 95 | git diff --exit-code tests/expected/uniq-* || \ 96 | echo "Test files have been updated. Please check the changes before committing." 97 | 98 | [private] 99 | patch-tests: 100 | #!/usr/bin/env bash 101 | mv tests/data/issue-20/frame-bug-dark.svg tests/expected/issue-20-frame-bug-dark.svg 102 | mv tests/data/issue-20/frame-bug-light.svg tests/expected/issue-20-frame-bug-light.svg 103 | mv tests/data/fonts/chinese.png tests/expected/fonts-chinese.png 104 | git diff --exit-code tests/expected || \ 105 | echo "Test files have been updated. Please check the changes before committing." 106 | -------------------------------------------------------------------------------- /.github/workflows/docker-drawio-desktop-headless.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Build And Release 3 | 4 | on: 5 | pull_request: 6 | push: 7 | branches: 8 | - v1.x 9 | 10 | permissions: 11 | contents: read # Default to 'read' for security 12 | pull-requests: read 13 | id-token: write # Added for potential OIDC in release job (packages/registry login) 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | 19 | permissions: 20 | contents: write # For stefanzweifel/git-auto-commit-action 21 | pull-requests: write # For peter-evans/create-or-update-comment 22 | 23 | concurrency: 24 | group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} 25 | cancel-in-progress: true 26 | 27 | steps: 28 | - name: Checkout Source Branch 29 | uses: actions/checkout@v6 30 | with: 31 | fetch-depth: 0 32 | ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || '' }} 33 | token: ${{ secrets.GH_TOKEN }} 34 | 35 | - uses: rlespinasse/github-slug-action@v5 36 | 37 | - uses: taiki-e/install-action@v2 38 | with: 39 | tool: just 40 | 41 | - name: Build Docker Image 42 | run: just build 43 | env: 44 | DOCKER_IMAGE: ${{ github.repository }}:${{ env.GITHUB_REF_SLUG }} 45 | 46 | - name: Setup CI for test 47 | run: just test-ci-setup 48 | 49 | - name: Test Docker Image 50 | id: test_ci 51 | run: just test-ci 52 | env: 53 | DOCKER_IMAGE: ${{ github.repository }}:${{ env.GITHUB_REF_SLUG }} 54 | continue-on-error: true 55 | 56 | - name: Store Output Logs & Files 57 | if: steps.test_ci.outcome == 'failure' 58 | uses: actions/upload-artifact@v5 59 | with: 60 | name: test-artifacts 61 | path: | 62 | tests/output/*.log 63 | tests/data 64 | !tests/data/*.drawio 65 | !tests/data/*/*.drawio 66 | 67 | - name: Patch Code (if Test Failed) 68 | if: steps.test_ci.outcome == 'failure' 69 | run: just patch 70 | 71 | - name: Generate Patch Diff 72 | if: steps.test_ci.outcome == 'failure' 73 | id: patch_diff_step 74 | run: | 75 | git diff HEAD^ HEAD > patch.diff 76 | # Set output to be used by the comment action 77 | { 78 | echo "diff<> "$GITHUB_OUTPUT" 82 | 83 | - name: Comment Patch Diff on PR 84 | uses: peter-evans/create-or-update-comment@v5 85 | if: steps.test_ci.outcome == 'failure' && github.event_name == 'pull_request' && steps.patch_diff_step.outputs.diff != '' 86 | with: 87 | issue-number: ${{ github.event.pull_request.number }} 88 | body: | 89 | :warning: A patch has been applied following the tests failure. 90 | 91 |
92 | Display patch content 93 | 94 | ```diff 95 | ${{ steps.patch_diff_step.outputs.diff }} 96 | ``` 97 |
98 | continue-on-error: true 99 | 100 | - name: Commit and Push Patch (if needed) 101 | uses: stefanzweifel/git-auto-commit-action@v7 102 | if: steps.test_ci.outcome == 'failure' 103 | with: 104 | commit_message: "fix: apply automated patch after tests failure" 105 | branch: ${{ github.head_ref }} 106 | 107 | build-multiarch: 108 | runs-on: ubuntu-latest 109 | 110 | concurrency: 111 | group: ${{ github.workflow }}-${{ github.ref }}-multiarch-${{ github.event_name }} 112 | cancel-in-progress: true 113 | 114 | steps: 115 | - uses: actions/checkout@v6 116 | 117 | - uses: rlespinasse/github-slug-action@v5 118 | 119 | - name: Set up QEMU 120 | uses: docker/setup-qemu-action@v3 121 | with: 122 | platforms: "arm64,arm" 123 | 124 | - name: Set up Docker Buildx 125 | uses: docker/setup-buildx-action@v3 126 | 127 | - name: Cache Docker layers 128 | uses: actions/cache@v4 129 | with: 130 | path: /tmp/.buildx-cache 131 | key: ${{ runner.os }}-buildx-${{ github.sha }} 132 | restore-keys: | 133 | ${{ runner.os }}-buildx- 134 | 135 | - uses: taiki-e/install-action@v2 136 | with: 137 | tool: just 138 | 139 | - name: Build Docker Image 140 | run: just build-multiarch 141 | env: 142 | DOCKER_IMAGE: ${{ github.repository }}:${{ env.GITHUB_REF_SLUG }} 143 | 144 | release: 145 | runs-on: ubuntu-latest 146 | 147 | permissions: 148 | contents: write # Required for releases 149 | packages: write # Required to push packages/images to GHCR 150 | issues: write # If release-that creates issues 151 | 152 | needs: 153 | - build 154 | - build-multiarch 155 | 156 | # Concurrency is good here, but cancellation should be disabled so a push 157 | # doesn't cancel a running release. 158 | concurrency: 159 | group: ${{ github.workflow }}-${{ github.ref }}-release 160 | cancel-in-progress: false 161 | 162 | steps: 163 | - uses: actions/checkout@v6 164 | 165 | - name: Release this docker image 166 | uses: rlespinasse/release-that@v1 167 | with: 168 | github-token: ${{ secrets.GH_TOKEN }} 169 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official email address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Draw.io Desktop Headless docker image 2 | 3 | Dockerized headless version of https://github.com/jgraph/drawio-desktop[Draw.io Desktop v29.0.3] 4 | 5 | == What it does 6 | 7 | Draw.io Desktop exposes a command-line client to allow us to create, check or export diagrams. 8 | 9 | Since Draw.io Desktop is a GUI application, we need a GUI environment to run it. 10 | And this prevents us to use it for automation in non-GUI environments such as CI tools. 11 | 12 | This docker image enables us to run the command-line client in a headless mode by using a configurable **X** server. 13 | 14 | Other minor additions are available 15 | 16 | * Add timeout capability since the application can hang sometimes (due to user action needed in GUI mode) 17 | * Clear the output log from Electron Security Warning 18 | * Disable auto-update functionality to avoid unnecessary log 19 | * Multiple fonts from 20 | ** https://packages.debian.org/bullseye/fonts-liberation[fonts-liberation] 21 | ** https://packages.debian.org/bullseye/fonts-arphic-ukai[fonts-arphic-ukai] 22 | ** https://packages.debian.org/bullseye/fonts-arphic-uming[fonts-arphic-uming] 23 | ** https://packages.debian.org/bullseye/fonts-noto[fonts-noto] 24 | ** https://packages.debian.org/bullseye/fonts-noto-cjk[fonts-noto-cjk] 25 | ** https://packages.debian.org/bullseye/fonts-ipafont-mincho[fonts-ipafont-mincho] 26 | ** https://packages.debian.org/bullseye/fonts-ipafont-gothic[fonts-ipafont-gothic] 27 | ** https://packages.debian.org/bullseye/fonts-unfonts-core[fonts-unfonts-core] 28 | 29 | NOTE: Want a new font package, modify the `Dockerfile` to install the missing package. 30 | 31 | == Running 32 | 33 | .Default run 34 | [source,console] 35 | ---- 36 | $ docker run -it -w /data -v $(pwd):/data rlespinasse/drawio-desktop-headless 37 | Usage: drawio [options] [input file/folder] 38 | ... 39 | ---- 40 | 41 | .Run using non-root user 42 | [source,console] 43 | ---- 44 | $ docker run -it \ 45 | -u $(id -u):$(id -g) \ <1> 46 | -e HOME=/data/home -w /data \ <2> 47 | -v /etc/passwd:/etc/passwd \ <3> 48 | -v $(pwd):/data rlespinasse/drawio-desktop-headless 49 | Usage: drawio [options] [input file/folder] 50 | ... 51 | ---- 52 | <1> Enable non-root user 53 | <2> env HOME need to contains the path of the working directory (can be the same) 54 | + 55 | .What if env HOME is not set properly? 56 | [%collapsible] 57 | ==== 58 | [,console] 59 | ---- 60 | Fontconfig error: No writable cache directories 61 | A JavaScript error occurred in the main process 62 | Uncaught Exception: 63 | Error: Failed to get 'userData' path 64 | at initDataListener (/opt/drawio/resources/app.asar/node_modules/electron-store/index.js:15:19) 65 | at new ElectronStore (/opt/drawio/resources/app.asar/node_modules/electron-store/index.js:48:32) 66 | at Object. (/opt/drawio/resources/app.asar/src/main/electron.js:15:15) 67 | at Module._compile (node:internal/modules/cjs/loader:1271:14) 68 | at Module._extensions..js (node:internal/modules/cjs/loader:1326:10) 69 | at Module.load (node:internal/modules/cjs/loader:1126:32) 70 | at Module._load (node:internal/modules/cjs/loader:967:12) 71 | at l._load (node:electron/js2c/asar_bundle:2:13642) 72 | at node:electron/js2c/browser_init:2:120247 73 | at node:electron/js2c/browser_init:2:120456 74 | /opt/drawio-desktop/runner.sh: line 4: 15 Trace/breakpoint trap (core dumped) "${DRAWIO_DESKTOP_EXECUTABLE_PATH:?}" "$@" --no-sandbox --disable-gpu 75 | ---- 76 | ==== 77 | <3> Needed to run drawio as non-root since v24.4.6 78 | + 79 | .What if this volume is not set properly? 80 | [%collapsible] 81 | ==== 82 | [,console] 83 | ---- 84 | A JavaScript error occurred in the main process 85 | Uncaught Exception: 86 | SystemError [ERR_SYSTEM_ERROR]: A system error occurred: uv_os_get_passwd returned ENOENT (no such file or directory) 87 | at new SystemError (node:internal/errors:259:5) 88 | at new NodeError (node:internal/errors:370:7) 89 | at Object.userInfo (node:os:365:11) 90 | at file:///opt/drawio/resources/app.asar/node_modules/atomically/dist/constants.js:10:29 91 | at ModuleJob.run (node:internal/modules/esm/module_job:218:25) 92 | at async ModuleLoader.import (node:internal/modules/esm/loader:329:24) 93 | at async node:electron/js2c/browser_init:2:125628 94 | at async loadESM (node:internal/process/esm_loader:28:7) 95 | ---- 96 | ==== 97 | 98 | === Configuration 99 | 100 | [cols="2a,3a,1a",options="header"] 101 | |=== 102 | 103 | | Environment Variable 104 | | Description 105 | | Default Value 106 | 107 | | **DRAWIO_DESKTOP_COMMAND_TIMEOUT** 108 | | To prevent Draw.io Desktop process to hang indefinitely. 109 | 110 | The value is a floating point number with an optional suffix: 's' 111 | for seconds (the default), 'm' for minutes, 'h' for hours or 'd' 112 | for days. A duration of 0 disables the associated timeout. 113 | | `10s` 114 | 115 | | **XVFB_DISPLAY** 116 | | Screen Display setup for XVFB 117 | | `:42` 118 | 119 | | **XVFB_OPTIONS** 120 | | Options for Xvfb 121 | | `-nolisten unix` (enable non-root run) 122 | 123 | | **ELECTRON_DISABLE_SECURITY_WARNINGS** 124 | | Avoid printing https://github.com/electron/electron/blob/master/docs/tutorial/security.md#electron-security-warnings[electron warning] 125 | | `true` 126 | 127 | | **DRAWIO_DISABLE_UPDATE** 128 | | Disable auto-update of Draw.io Desktop 129 | | `true` 130 | 131 | | **SCRIPT_DEBUG_MODE** 132 | | Enable `set -x` in internal scripts for debugging purpose 133 | | `false` 134 | 135 | |=== 136 | 137 | == Use as docker base image 138 | 139 | This docker image can be used as the base image to build a higher-level tool upon it. 140 | 141 | In addition to running configuration, you have access to 142 | 143 | - `DRAWIO_DESKTOP_EXECUTABLE_PATH` to have access to the executable path of Draw.io Desktop. 144 | - `DRAWIO_DESKTOP_RUNNER_COMMAND_LINE` to run your script instead of the default one. 145 | 146 | === Used by 147 | 148 | * Docker image https://github.com/rlespinasse/drawio-export[**rlespinasse/drawio-export**] which enhance export capabilities of the **Draw.io Desktop Headless** docker image, 149 | ** And GitHub Action https://github.com/rlespinasse/drawio-export-action[**rlespinasse/drawio-export-action**] which is build on top of **drawio-export** docker image. 150 | 151 | == Thanks to 152 | 153 | Thanks for the community about https://github.com/jgraph/drawio-desktop/issues/127[the workaround docker-image based on Draw.io Desktop]. 154 | 155 | == Contributing 156 | 157 | Pull requests are welcome. 158 | For major changes, please open an issue first to discuss what you would like to change. 159 | 160 | Please make sure to update tests as appropriate. 161 | -------------------------------------------------------------------------------- /tests/expected/issue-20-frame-bug-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
Good
Bad
Text is not SVG - cannot display
-------------------------------------------------------------------------------- /tests/expected/issue-20-frame-bug-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
Good
Bad
Text is not SVG - cannot display
--------------------------------------------------------------------------------