Skip to content

feat: Add comprehensive start script to simplify setup and update processes. Closes #752#756

Merged
regulartim merged 26 commits intointelowlproject:developfrom
opbot-xd:feature/simplify-setup-752
Feb 4, 2026
Merged

feat: Add comprehensive start script to simplify setup and update processes. Closes #752#756
regulartim merged 26 commits intointelowlproject:developfrom
opbot-xd:feature/simplify-setup-752

Conversation

@opbot-xd
Copy link
Copy Markdown
Contributor

Description

This PR implements a comprehensive bash script that dramatically simplifies the GreedyBear setup, deployment, and update processes, addressing all requirements from issue #752.

Related issues

Closes #752

Key Features Implemented

1. Automated Setup Script (./start)

  • One-command initialization: Reduces setup from ~10 manual steps to 1-2 commands
  • Smart environment file management: Automatically creates and configures env_file, env_file_postgres, and .env from templates
  • Auto-generated secrets: Generates secure Django secret keys automatically
  • Dependency validation: Checks for Docker and Docker Compose with version requirements

2. Deployment Modes

  • Production (--prod): Standard production deployment with pre-built images
  • Development (--dev): Hot-reload enabled with local code mounting
  • Test (--test): Testing environment configuration

3. Feature Flags

  • --https: Enable HTTPS with custom certificates
  • --elastic: Enable Elasticsearch (with 16GB RAM requirement check)
  • --stag: Staging environment configuration
  • --use-version: Version-specific deployment
  • --project-name: Custom project naming
  • --version: Specify version to install

4. Comprehensive Commands

  • init: Initialize environment files and configuration
  • up/start: Start all services
  • down: Stop and remove services
  • stop: Stop services without removing
  • restart: Restart services
  • logs: View service logs (supports follow mode)
  • ps: List running services
  • update: One-command update to latest version
  • build: Build custom Docker images
  • pull: Pull latest images

5. Silent Mode (-s / --silent)

  • Non-interactive installation for automation
  • Perfect for CI/CD pipelines and Ansible playbooks
  • No prompts, uses sensible defaults

6. User Experience Enhancements

  • Color-coded logging (info, success, warning, error)
  • Clear feedback and progress messages
  • Comprehensive help documentation (--help)
  • System requirement checks (memory for Elasticsearch)
  • Automatic Docker installation offer (Ubuntu/Debian)

Examples

Quick Start

git clone https://github.com/intelowlproject/GreedyBear.git
cd GreedyBear
./start init --prod
./start up --prod

Development

./start up --dev --elastic

Updates

./start update --prod

Silent Installation (Ansible-ready)

./start init --prod --silent
./start up --prod

Documentation Updates

  • Updated README.md with quick start guide
  • Added common command examples
  • Documented all available commands and flags

Inspired By

This implementation is inspired by the IntelOwl project's start script, adapted specifically for GreedyBear's architecture and requirements.

Type of change

  • New feature (non-breaking change which adds functionality).

Checklist

  • I have read and understood the rules about how to Contribute to this project.
  • The pull request is for the branch develop.
  • I have added documentation of the new features.
  • Linter (Ruff) gave 0 errors. If you have correctly installed pre-commit, it does these checks and adjustments on your behalf.
  • All the tests (old ones) gave 0 errors.
  • If changes were made to an existing model/serializer/view, the docs were updated and regenerated (check CONTRIBUTE.md).
  • If the GUI has been modified:
    • I have a provided a screenshot of the result in the PR.
    • I have created new frontend tests for the new component or updated existing ones.

…ntelowlproject#752)

This commit implements a comprehensive bash script that streamlines the GreedyBear setup, deployment, and update processes.

Key Features:
- Automated environment setup (env_file, env_file_postgres, .env)
- Dependency checks for Docker and Docker Compose
- Smart Docker Compose orchestration with multiple override files
- Deployment modes: prod, dev, test
- One-command operations: init, up, down, update, logs, ps, etc.
- Silent mode (-s flag) for non-interactive installations
- Support for deployment flags: --https, --elastic, --stag, --use-version
- Automatic Django secret generation
- Color-coded logging for better UX
- Comprehensive help documentation

Benefits:
- Reduces setup from ~10 manual steps to 1-2 commands
- Simplifies updates with a single command
- Provides clear feedback and error messages
- Makes deployment more accessible and less error-prone
- Supports automated deployments (e.g., Ansible)

Updated README.md with quick start guide and common command examples.

Co-authored-by: IntelOwl team <intelowl@honeynet.org>
@opbot-xd
Copy link
Copy Markdown
Contributor Author

Questions for Maintainers

Hey! @regulartim @mlodic Before finalizing this PR, I have a few questions:

1.Re-running init

Right now ./start init skips existing env files. Should it offer to regenerate them, or keep it safe and skip like it does now?

2.Version Management

Do you want git tag checkout like IntelOwl (./start up --version 2.0.0), or just stick with Docker image versions?

3.Testing the Script

How should I test the bash script itself? Shell testing framework, integration tests, or just manual testing?

4.Docker Auto-Install

Currently it offers to install Docker on Ubuntu/Debian. Should I:

  • Add more distros?
  • Just check and show instructions?
  • Keep it as is?

5.Any Other Features?

  • ./start backup - Backup database and volumes
  • ./start restore - Restore from backup
  • ./start health - Health check all services
  • ./start clean - Remove all data and reset

Thank you!

@regulartim
Copy link
Copy Markdown
Collaborator

Hey @opbot-xd ! Looks great so far. 👍

Right now ./start init skips existing env files. Should it offer to regenerate them, or keep it safe and skip like it does now?

I think you should ask if they should be regenerated and override them in silent mode. Do you think that's sensible?

Do you want git tag checkout like IntelOwl (./start up --version 2.0.0), or just stick with Docker image versions?

Don't they have to align anyways? If the local files are on version 1.6.0 for example and you start the docker image 3.0.0, that might break things. So I would guess the safest think to do is to rely on both.

How should I test the bash script itself? Shell testing framework, integration tests, or just manual testing?

That's a great question, unfortunately I don't have an answer for that. It would be fine for me to rely on manual testing. If we have some kind of automated testing - great! If that means that we have to maintain a complicated testing framework, then I don't know if that's worth it.

Add more distros?

Yes, the more the better. Packet managers don't change much over time. So if we support a specific distro, after an initial test, it's should not be much work to maintain that support. In the best case we would match the distros supported by T-Pot: Alma, Debian, Fedora Server, OpenSUSE, Rocky, Ubuntu.

Any Other Features?

All the features you listed are nice to have in my opinion. So if you like them and think they provide value to users and/or developers, feel free to implement them! :)

@regulartim
Copy link
Copy Markdown
Collaborator

Also, the name of the script ("start") does not really reflect what it does. Can you think of a better name? I have some suggestions but I am open for your ideas: greedybear, gb, manage, ctl

… multi-distro support

- Add env file regeneration with backup in interactive mode
- Override env files in silent mode for automation
- Implement git tag checkout for version management (aligns code + Docker images)
- Add Docker installation support for Alma, Fedora, Rocky, OpenSUSE (matching T-Pot)
- Improve user experience with better prompts and feedback
- Avoid conflict with existing greedybear/ Django app directory
- Follow kubectl/systemctl naming convention
- Update all documentation and help text to use gb-ctl
- Cleaner name matching kubectl/systemctl convention
- Easier to type without hyphen
New commands:
- backup: Create timestamped PostgreSQL backups with gzip compression
- restore: Restore from backup with confirmation prompt
- health: Check all services status with visual indicators
- clean: Complete removal of all data and containers (with safety confirmation)

Enhances operational capabilities for production deployments.
@opbot-xd
Copy link
Copy Markdown
Contributor Author

Script Naming:
Initial startgbctl due to greedybear/ directory conflict. Follows kubectl/systemctl convention.

Quick Start:

./gbctl init --prod && ./gbctl up --prod

Also implemented:

  • Environment file regeneration (with backup in interactive mode, auto-override in silent mode)
  • Version management with git tag checkout (aligns code + Docker images)
  • Multi-distro Docker installation support (Alma, Fedora, Rocky, OpenSUSE - matching T-Pot
  • And features like health, backup, restore and clean.

@opbot-xd
Copy link
Copy Markdown
Contributor Author

Minimal Installation Support?

Hi @regulartim
You mentioned wanting the script to "not clone the whole repo but only the files that are necessary" for deployment. After reading and learning about Ansible playbook, I think this could really help with your automation goals.

Suggested approach:

Create a lightweight bootstrap.sh that can be downloaded and run standalone:

curl -sSL https://raw.githubusercontent.com/honeynet/GreedyBear/main/bootstrap.sh | bash

This bootstrap script would:

  1. Download only essential files via GitHub API or raw URLs:

    • gbctl (main management script)
    • docker/ directory (compose files, configs)
    • configuration/ directory
    • manage.py, pyproject.toml, requirements/
    • Template files (docker/env_file_template, etc.)
  2. Then automatically run ./gbctl init --prod --silent

Would this be valuable?
Thanks

@opbot-xd opbot-xd marked this pull request as ready for review January 30, 2026 16:14
Copilot AI review requested due to automatic review settings January 30, 2026 16:14
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new gbctl bash script intended to simplify GreedyBear setup/management and documents the new workflow in the README (closing #752).

Changes:

  • Introduces gbctl with commands for init/up/down/logs/update/backup/restore/health/clean plus env/feature flags.
  • Adds automated environment file creation from templates and basic dependency checks.
  • Updates README.md with a “Quick Start” and common gbctl command examples.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 18 comments.

File Description
gbctl New management script implementing setup, orchestration, and operational commands via Docker Compose.
README.md Documents the new gbctl workflow and common commands for setup and operations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@opbot-xd opbot-xd marked this pull request as draft January 30, 2026 16:31
@opbot-xd opbot-xd marked this pull request as ready for review January 30, 2026 23:17
Copilot AI review requested due to automatic review settings January 30, 2026 23:17
@opbot-xd opbot-xd marked this pull request as draft January 30, 2026 23:25
@opbot-xd opbot-xd marked this pull request as ready for review January 30, 2026 23:26
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 14 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@opbot-xd
Copy link
Copy Markdown
Contributor Author

@regulartim finally the PR is ready to review.
But I believe the gbctl script is getting huge. Can you please suggest some ways to refactor the code.
Thanks.

@regulartim
Copy link
Copy Markdown
Collaborator

Hey @opbot-xd ! I'm really excited to test this, but it might take a while. Will get back to you next week.

@regulartim
Copy link
Copy Markdown
Collaborator

Would this be valuable?

Yes, I think it would!

Copy link
Copy Markdown
Member

@mlodic mlodic left a comment

Choose a reason for hiding this comment

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

it is well done but at the same time maybe a little overkill...also we have no tests about this so we need that you can please try the most complex commands and show us that they work at least.

We will need to do some manual tests too as maintainers to feel how much this is helpful or not in practice.

README.md Outdated
To install it locally, Please refer to our [installation guide](https://intelowlproject.github.io/docs/GreedyBear/Installation/)
### Quick Start

GreedyBear now includes an automated setup script that simplifies installation and management:
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.

the readme must be kept simple and short. please revert this and create a PR for the docs repo instead

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sure! would revert back the changes in README.md

gbctl Outdated
if [ -f docker/env_file ]; then
if [ "$SILENT_MODE" = true ]; then
# Always create backup even in silent mode to protect user configs
local backup_name="docker/env_file.backup.$(date +%Y%m%d_%H%M%S)"
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.

these files should be added to gitignore

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Great point! Even I noticed some untracked files were created during the testing of the script but forgot them to add to .gitignore

gbctl Outdated
if [ -f docker/env_file_postgres ]; then
if [ "$SILENT_MODE" = true ]; then
# Always create backup even in silent mode to protect user configs
local backup_name="docker/env_file_postgres.backup.$(date +%Y%m%d_%H%M%S)"
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.

same for these

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Noted.

gbctl Outdated
fi

# Generate Django secret if needed
if grep -q "^DJANGO_SECRET=$" docker/env_file 2>/dev/null || grep -q "^DJANGO_SECRET=\"\"$" docker/env_file 2>/dev/null; then
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.

django secret is not necessary imho.
let django itself handle this automatically

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right, thanks for pointing this out! I'll remove the Django secret generation - Django handles this automatically. Will update the script.

gbctl Outdated
if [ "$ENABLE_HTTPS" = true ]; then
log_info "Access GreedyBear at: https://localhost"
else
log_info "Access GreedyBear at: http://localhost"
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.

if nginx has been configured differently, this would be wrong. I am from the phone now and I cant check further but I think we can have a better solution

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @mlodic Good point! The URL could be incorrect if nginx is configured with a custom domain/port. A few options:

  1. Remove the URL message entirely - users know where they deployed
  2. Make it generic: "GreedyBear services started successfully" without assuming the URL
  3. Read from config - parse the actual host from docker/env_file or nginx config (more complex)

I'd lean toward option 2 - just remove the URL assumption. Let me know what you prefer and I'll update it! Thanks.

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.

sure, thanks

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.

sure, thanks


local backup_dir="backups"
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_file="${backup_dir}/greedybear_backup_${timestamp}"
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.

backup
dir should be gitgignored

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes would update the .gitignore to fix this and other files also.

gbctl Outdated
shift
;;
--use-version)
# Deprecated: --version now implicitly enables version override
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.

I dont get where this code the AI got from? :P this script is new, it does not make sense to have deprecated commands

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Actually this was a suggestion given to me by Copilot PR review system and on reading the description I found it right so just clicked on commit suggestion. I did not notice the comments it added. Apologizes from my side, would be careful in implementing the suggestions next time.

gbctl Outdated
exit 1
fi
# Deprecated: PROJECT_NAME is fixed to the default to avoid conflicts
log_warning "--project-name is deprecated and has no effect (container names are hardcoded)"
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.

same

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

image

Would be careful next time.

@opbot-xd
Copy link
Copy Markdown
Contributor Author

opbot-xd commented Feb 1, 2026

Totally fair points! I agree the script grew larger than initially planned as I added features from the feedback.

Here's what I've verified works:

# Basic flow
./gbctl init --prod           ✓ Creates env files, prompts for regeneration
./gbctl init --prod --silent  ✓ Auto-backups and regenerates without prompts
./gbctl up --dev              ✓ Starts with [local.override.yml](http://_vscodecontentref_/0) (hot reload)
./gbctl health                ✓ Shows service status with visual indicators
./gbctl ps / logs             ✓ Passes through to docker compose

# Version management
./gbctl up --prod --version v1.2.0  ✓ Sets REACT_APP_INTELOWL_VERSION, includes version.override.yml

would test more commands as well.
Also I am concerned about the size of the script as well(900 lines). Any suggestions for that?

@mlodic
Copy link
Copy Markdown
Member

mlodic commented Feb 1, 2026

could you also provide some screenshots as a reference here?

If the code is well written and organized, imho it doesnt matter the size of the file, this is a standalone script so it is fine

Add dummy first_name and last_name values to create-admin command in silent mode to satisfy required fields of custom user model.
@opbot-xd
Copy link
Copy Markdown
Contributor Author

opbot-xd commented Feb 3, 2026

tim@ct-greedybear-test:~/GreedyBear$ ./gbctl create-admin --username tim --password tim --email tim@nothing.net
[INFO] Creating Django superuser...
[INFO] Creating superuser in non-interactive mode...
CommandError: You must use --first_name with --noinput.

Did I use it the wrong way?

Actually it was due to custom user model requirements! I missed that both first_name and last_name are required fields.

  1. Refined create-admin: I've updated the command to provide dummy values for both:
    • DJANGO_SUPERUSER_FIRST_NAME="admin"
    • DJANGO_SUPERUSER_LAST_NAME="user"

This satisfies all the REQUIRED_FIELDS for the custom user model (email, first_name, last_name).

I've tested it locally and verified it works!

Remove deletion of backups directory from cmd_clean to prevent accidental data loss.
@opbot-xd
Copy link
Copy Markdown
Contributor Author

opbot-xd commented Feb 3, 2026

I played around with the script and overall, it looks very solid. There are a few things that need further attention though:

1. The logs shown are not very informative, except for occasions where the application does not start correctly. The really interesting logs are somewhere else, e.g. `/var/lib/docker/volumes/greedybear_generic_logs/_data/django/greedybear.log`.

2. I find it a little confusing which switch belongs to what command. Is there a better way to do that?

3. The mechanisms of controlling the version of GreedyBear which gets started, looks not very solid to me. As I said, we need to make sure the version of the container that is starting corresponds to the git branch that is checked out.

4. I think setting the version (for example prod or stag) should be done via the `init` command, not via `up`. This to me would be a clearer separation of concerns: `init` prepares the environment and `up` only starts the app.

Thanks for the feedback! I agree these changes will significantly improve the CLI's usability. Here is my plan to address each point:

  1. Logs: I'll enhance the logs command.

    • By default, ./gbctl logs will show container stdout (like it does now).
    • I'll add a specific ./gbctl logs app command that execs into the container and tails the actual Django log file (/var/log/greedybear/django/greedybear.log), so you don't have to hunt for the volume on the host.
  2. Switch Confusion & 4. Init vs Up: I'll combine these by shifting configuration to the init phase.

    • init will become the single source of truth for configuration. It will save your choices (Prod/Dev, Elastic enabled/disabled, etc.) into a config file (e.g., .gbctl.conf).
    • up will essentially become flag-less (or just overrides). You'll just run ./gbctl up, and it will respect the configuration set during init.
    • This removes the confusion of "do I need --elastic here?" effectively solving point 2 by implementing point 4.
  3. Version Control:

    • I'll add a check in up that compares the requested version/tag with the currently checked-out git branch (if running from source).
    • If there's a mismatch (e.g., running latest container while on a feature branch), it will warn the user.

Does this approach sound good to you?

Copilot AI review requested due to automatic review settings February 3, 2026 16:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 2 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@regulartim
Copy link
Copy Markdown
Collaborator

Does this approach sound good to you?

Yeah, sounds good! :) I think after that we can merge and create separate issues if something else comes up.

This commit implements the agreed refactor:
- Configuration is now persisted in .gbctl.conf by 'init' and loaded by other commands.
- 'logs app' command tails internal Django logs.
- Version mismatch check warns if git branch doesn't match deployment mode.
- 'up' command is now idempotent and configuration-driven.
@opbot-xd
Copy link
Copy Markdown
Contributor Author

opbot-xd commented Feb 3, 2026

I have implemented the changes as planned!

  1. Configuration Persistence: gbctl init now saves your configuration (prod/dev, elastic, etc.) to .gbctl.conf. Subsequent commands like gbctl up automatically load this config, so you don't need to repeat flags.
  2. Logs App: Added gbctl logs app which tails the internal Django logs (/var/log/greedybear/django/greedybear.log) directly from the containe.
  3. Version Check: gbctl up now checks if your git branch matches your deployment mode (e.g., warns if you are running Prod on a feature branch), unless you pinned a specific version.
image image

Export REACT_APP_INTELOWL_VERSION whenever a specific version is requested, regardless of ENV_MODE, to ensure correct image tags in all modes.
Escape ampersand in ELASTIC_ENDPOINT to correctly handle URL parameters during sed replacement.
Wrap docker exec in if-condition to properly handle failures with set -e, and remove duplicate comment.
Set restricted permissions (0700) for backup directory and (0600) for backup files to prevent unauthorized access on shared systems.
Support GB_ADMIN_USERNAME, GB_ADMIN_PASSWORD, and GB_ADMIN_EMAIL for secure silent admin creation.
Copilot AI review requested due to automatic review settings February 3, 2026 22:33
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 2 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Prevent exposure of admin credentials in process list by exporting them first and passing by name to docker exec.
Always export REACT_APP_INTELOWL_VERSION when USE_VERSION is true to prevent empty variable errors in docker-compose, even for 'latest'.
Replace insecure source command with safe key-value parsing for .gbctl.conf to prevent arbitrary code execution.
… allowing the script to continue execution with limited functionality.
Copilot AI review requested due to automatic review settings February 3, 2026 23:07
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 2 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@regulartim
Copy link
Copy Markdown
Collaborator

If you think your PR is ready to get a final review, please click the "re-request review" on the top right, next to my profile picture.

@opbot-xd opbot-xd requested a review from regulartim February 4, 2026 12:44
Copy link
Copy Markdown
Collaborator

@regulartim regulartim left a comment

Choose a reason for hiding this comment

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

Hey @opbot-xd ! I really appreciate your work. I think this script is extremely valuable for the project. Thanks a lot!

I will test this in detail, but that will take some time. I do think however that this PR has good enough quality to be merged into develop. So will merge it and collect potential problems in a separate issue.

@regulartim regulartim merged commit ed67741 into intelowlproject:develop Feb 4, 2026
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants