diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 1304b52..8257b78 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -1,6 +1,6 @@ # This workflow will install Python dependencies, run tests and lint with multiple versions of Python # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python -name: Python application +name: PyTest on: push: branches: [ "master", "develop" ] diff --git a/.gitignore b/.gitignore index bbfa9ef..b8b1412 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,10 @@ instance_config_override.py run.py migrations/ +# PyPi +.pypirc + + # PyCharm .idea/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d6a319f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,271 @@ +# Changelog + +All notable changes to ExaFS will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.1.6] - 2025-10-08 + +### Fixed +- Fixed problem with session overflow on too many rules id + +### Changed +- Updated `withdraw_expired` method to also delete expired rules +- Expiration threshold can now be set in config (default: 30 days) + +### Added +- New auth helpers to determine which rules a user can modify +- Functions `get_user_allowed_rule_ids` and `check_user_can_modify_rule` in auth module +- `EXPIRATION_THRESHOLD` config option +- PyPi package published +- Docker base image published +- updated docs + +## [1.1.5] - 2025-10-06 + +### Added +- Introduced instance config override +- Copy the sample to `instance_config_override.py` to customize dashboard menu items easily + +### Changed +- For normal installations, no override is needed +- Changed `MAX_COMMA_VALUES` constant to 5 as default value + +## [1.1.4] - 2025-08-20 + +### Fixed +- Minor bug fixes +- More robust function for filtering and splitting flowspec rules for user + +### Changed +- Code cleanup +- Updated filter rules action to be more robust + +## [1.1.3] - 2025-07-14 + +### Added +- Introduced configurable footer menu for links in bottom of the default template + +### Changed +- Removed debug print statements in update_set_org + +## [1.1.2] - 2025-07-02 + +### Security +- Minor security updates (removed unused JS files) + +### Changed +- `setup.py` now reads dependencies from `requirements.txt` + +### Fixed +- Fixed bugs for flowspec limit in various views + +## [1.1.1] - 2025-06-03 + +### Changed +- **Machine API Key rewritten** + - API keys for machines are now tied to one of the existing users + - If there is a need to have API access for machine, first create service user and set the access rights + - Then create machine key as Admin and assign it to this user + - Machine key now has user rights of the assigned user, not of admin + +## [1.1.0] - 2025-03-25 + +### Added +- **RTBH Whitelist Integration** + - System automatically evaluates new RTBH rules against existing whitelists + - Can automatically modify or block rules that conflict with whitelisted networks + - Automatically whitelist rules that exactly match or are contained within whitelisted networks + - Create subnet rules when RTBH rules are supersets of whitelisted networks + - Maintain rule cache that tracks relationships between rules and whitelists for proper cleanup +- Dedicated services layer for better separation of concerns + - `rule_service.py` for rule management operations + - `whitelist_service.py` for whitelist functionality + - `whitelist_common.py` for shared whitelist utilities + +### Changed +- **Major Architecture Refactoring** + - Significant architectural refactoring focused on better separation of concerns + - Improved maintainability through services layer + - Business logic extracted from view controllers +- **Models structure reorganization** + - Better separation into logical modules + - Rule models organized under `flowapp/models/rules/` + - Separate files for different rule types (`flowspec.py`, `rtbh.py`, `whitelist.py`) + - Backward compatibility maintained through main models `__init__.py` +- **Form handling improvements** + - Better organization under `flowapp/forms/` + - Enhanced validation logic + +## [1.0.2] - 2025-03-19 + +### Fixed +- Fixed bug in IPv6 Flowspec messages +- Fixed JSON output for route if ExaBGP process HTTP API is used +- Empty fragment in IPv6 messages should be empty string not None + +## [1.0.1] - 2025-01-09 + +### Fixed +- Minor bug fixes + +### Changed +- Application is now Flask 3 compliant (updated requirements) + +## [1.0.0] - 2024-10-15 + +### Added +- Limits for number of rules in the system + - Limits for rules per organization + - Overall limit for the installation +- Rules are now tied to organization + - Organization selection required after login for users belonging to multiple organizations +- Bulk import for users enabled for admin +- Swagger documentation for API on local system (available at `/apidocs` URL) +- New format of message for ExaAPI + - Now sends information about rule author (user) for logging purposes + +### Changed +- **Database schema changes** - migration required + - Existing rules need to be linked to organizations + - See [detailed migration documentation](./docs/DB_MIGRATIONS.md) +- ExaAPI and Guarda modules moved outside of the project + - ExaAPI now available as [pip package exabgp-process](https://pypi.org/project/exabgp-process/) + - ExaAPI has own [GitHub repository](https://github.com/CESNET/exabgp-process) +- Watch of ExaBGP restart can be done by guarda service or by override of the ExaBGP service settings + +## [0.8.1] - 2024-09-23 + +### Changed +- Application now uses Flask-Session stored in DB using SQL Alchemy driver +- Can be configured for other drivers +- Server-side session is required for proper application function + +## [0.8.0] - 2024-03-28 + +### Added +- API keys expiration date +- API keys readonly flag +- Admin can create special keys for certain machines + +### Changed +- **API keys update** - migration required +- Run migration scripts to update your database + +## [0.7.3] - 2023-11-03 + +### Added +- New possibility of external auth proxy +- Support for authentication using external proxy (expects HTTP header authentication) + +## [0.7.2] - 2023-07-12 + +### Added +- Dashboard and Main menu are now customizable in config + +### Changed +- App is ready to be packaged using `setup.py` + +## [0.7.0] - 2022-09-02 + +### Added +- ExaAPI now has two options: HTTP or RabbitMQ + +### Changed +- ExaAPI process has been renamed +- Update of ExaBGP process value is needed for this version + +## [0.6.2] - 2022-09-02 + +### Added +- External config for ExaAPI + +## [0.6.0] - 2022-04-29 + +### Changed +- Bootstrap 5 in UI + +## [0.5.5] - 2022-02-25 + +### Changed +- API v3: auth API key in cookie, not in URL + +## [0.5.4] - 2021-08-31 + +### Added +- Right click menu on address with Whois or Copy to clipboard functionality + +### Fixed +- Fixed `form.process()` bug + +## [0.5.3] - 2021-06-30 + +### Changed +- Dashboard update +- Forms with default action (no default action/community in forms) + +## [0.5.2] - 2021-04-16 + +### Changed +- API v2 with new keys + +## [0.5.1] - 2021-03-27 + +### Fixed +- Bug fixes + +### Added +- Urgent and push values for TCP FLAGS + +## [0.5.0] - 2021-03-09 + +### Changed +- **New format of LOG table in database** - migration required +- Run migration scripts to update your database +- Removed foreign key `user_id` +- Author email is stored directly to logs for faster grep text search + +## [0.4.8] - 2020 + +### Added +- Enhanced String Filtering + +## [0.4.7] - 2020 + +### Added +- Multi neighbor support enabled +- See config example and update your `config.py` + +## [0.4.6] - 2020 + +### Added +- Route Distinguisher for VRF now supported +- See config example and update your `config.py` + +[1.1.6]: https://github.com/CESNET/exafs/compare/v1.1.5...v1.1.6 +[1.1.5]: https://github.com/CESNET/exafs/compare/v1.1.4...v1.1.5 +[1.1.4]: https://github.com/CESNET/exafs/compare/v1.1.3...v1.1.4 +[1.1.3]: https://github.com/CESNET/exafs/compare/v1.1.2...v1.1.3 +[1.1.2]: https://github.com/CESNET/exafs/compare/v1.1.1...v1.1.2 +[1.1.1]: https://github.com/CESNET/exafs/compare/v1.1.0...v1.1.1 +[1.1.0]: https://github.com/CESNET/exafs/compare/v1.0.2...v1.1.0 +[1.0.2]: https://github.com/CESNET/exafs/compare/v1.0.1...v1.0.2 +[1.0.1]: https://github.com/CESNET/exafs/compare/v1.0.0...v1.0.1 +[1.0.0]: https://github.com/CESNET/exafs/compare/v0.8.1...v1.0.0 +[0.8.1]: https://github.com/CESNET/exafs/compare/v0.8.0...v0.8.1 +[0.8.0]: https://github.com/CESNET/exafs/compare/v0.7.3...v0.8.0 +[0.7.3]: https://github.com/CESNET/exafs/compare/v0.7.2...v0.7.3 +[0.7.2]: https://github.com/CESNET/exafs/compare/v0.7.0...v0.7.2 +[0.7.0]: https://github.com/CESNET/exafs/compare/v0.6.2...v0.7.0 +[0.6.2]: https://github.com/CESNET/exafs/compare/v0.6.0...v0.6.2 +[0.6.0]: https://github.com/CESNET/exafs/compare/v0.5.5...v0.6.0 +[0.5.5]: https://github.com/CESNET/exafs/compare/v0.5.4...v0.5.5 +[0.5.4]: https://github.com/CESNET/exafs/compare/v0.5.3...v0.5.4 +[0.5.3]: https://github.com/CESNET/exafs/compare/v0.5.2...v0.5.3 +[0.5.2]: https://github.com/CESNET/exafs/compare/v0.5.1...v0.5.2 +[0.5.1]: https://github.com/CESNET/exafs/compare/v0.5.0...v0.5.1 +[0.5.0]: https://github.com/CESNET/exafs/compare/v0.4.8...v0.5.0 +[0.4.8]: https://github.com/CESNET/exafs/compare/v0.4.7...v0.4.8 +[0.4.7]: https://github.com/CESNET/exafs/compare/v0.4.6...v0.4.7 +[0.4.6]: https://github.com/CESNET/exafs/releases/tag/v0.4.6 \ No newline at end of file diff --git a/README.md b/README.md index fcfa452..9b09b57 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,12 @@ # ExaFS + +[![PyPI version](https://badge.fury.io/py/exafs.svg)](https://badge.fury.io/py/exafs) +[![Docker Image](https://img.shields.io/docker/v/jirivrany/exafs-base?label=docker&logo=docker)](https://hub.docker.com/r/jirivrany/exafs-base) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![PyTest](https://github.com/CESNET/exafs/actions/workflows/python-app.yml/badge.svg)](https://github.com/CESNET/exafs/actions/workflows/python-app.yml) +[![CodeQL](https://github.com/CESNET/exafs/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/CESNET/exafs/actions/workflows/github-code-scanning/codeql) +[![Python Version](https://img.shields.io/pypi/pyversions/exafs.svg)](https://pypi.org/project/exafs/) + ExaFS brings new functionality to the environment of routing protocols configuration for backbone network hardware security. The tool extends network administrators toolset by adding an extra layer for configuration rules creation, validation, and authorization. With this new layer, a larger group of network administrators can safely create new @@ -51,52 +59,10 @@ It may also be necessary to monitor ExaBGP and re-announce rules after a restart ### Instalation related * [ExaFS Ansible deploy](https://github.com/CESNET/ExaFS-deploy) - repository with Ansbile playbook for deploying ExaFS with Docker Compose. * [Install notes](./docs/INSTALL.md) +* [using Docker Image](./docs/DockerImage.md) * [Database backup configuration](./docs/DB_BACKUP.md) * [Local database instalation notes](./docs/DB_LOCAL.md) ### API The REST API is documented using Swagger (OpenAPI). After installing and running the application, the API documentation is available locally at the /apidocs/ endpoint. This interactive documentation provides details about all available endpoints, request and response formats, and supported operations, making it easier to integrate and test the API. - - -## Change Log -- 1.1.6 - Fixed problem with session overflow on too much rules id. Updated withdraw_expired method to delete also expired rules. Expiration treshold can be set in config - default to 30 days. -- 1.1.5 - introduced instance config override. Copy the sample to instance_config_override.py and customize you dashboard menu items easily. For normal installations no override is needed. -- 1.1.4 - minor bug fixes and code cleanup -- 1.1.3 - introduced configurable footer menu for links in bottom of the default template -- 1.1.2 - minor security updates (removed unused JS files), setup.py now reads dependencies from requirements.txt -- 1.1.1 - Machine API Key rewrited. - - API keys for machines are now tied to one of the existing users. If there is a need to have API access for machine, first create service user, and set the access rights. Then create machine key as Admin and assign it to this user. -- 1.1.0 - Major Architecture Refactoring and Whitelist Integration - - Code Organization and Architecture Improvements. Significant architectural refactoring focused on better separation of concerns and improved maintainability. The most notable change is the introduction of a dedicated **services layer** that extracts business logic from view controllers. Key service modules include `rule_service.py` for rule management operations, `whitelist_service.py` for whitelist functionality, and `whitelist_common.py` for shared whitelist utilities. - - The **models structure** has been reorganized with better separation into logical modules. Rule models are now organized under `flowapp/models/rules/` with separate files for different rule types (`flowspec.py`, `rtbh.py`, `whitelist.py`), while maintaining backward compatibility through the main models `__init__.py`. Form handling has also been improved with better organization under `flowapp/forms/` and enhanced validation logic. - - **RTBH Whitelist Integration** This system automatically evaluates new RTBH rules against existing whitelists and can automatically modify or block rules that conflict with whitelisted networks. When an RTBH rule is created that intersects with a whitelist entry, the system can: - - **Automatically whitelist** rules that exactly match or are contained within whitelisted networks - - **Create subnet rules** when RTBH rules are supersets of whitelisted networks, automatically generating the non-whitelisted portions - - **Maintain rule cache** that tracks relationships between rules and whitelists for proper cleanup -- 1.0.2 - fixed bug in IPv6 Flowspec messages -- 1.0.1 . minor bug fixes -- 1.0.0 . Major changes - - Limits for nuber of rules in the system introduced. There are now limits for rules for organization and overall limit for the instalation. Database changed / migration is required. Migrating the database to version 1.0.x is a bit more complicated, you need to link existing rules to organizations. [A more detailed description is in a separate document](./docs/DB_MIGRATIONS.md). - - Rules are now tied to organization. If the user belongs to more than one organization, the organization for the session must be selected after login. - - Bulk import for users enabled for admin. - - Introduced Swagger docs for API on the local system. Just open /apidocs url. - - New format of message for ExaAPI - now sends information about author of rule (user) for logging purposes. - - ExaAPI and Guarda modules moved outside of the project. - - ExaAPI is now available as a [pip package exabgp-process](https://pypi.org/project/exabgp-process/), with own [github repostiory](https://github.com/CESNET/exabgp-process). - - Watch of exabgp restart can be still done by guarda service - see docs. Or it can be done by override of the exabgp service settings. -- 0.8.1 application is using Flask-Session stored in DB using SQL Alchemy driver. This can be configured for other drivers, however server side session is required for the application proper function. -- 0.8.0 - API keys update. **Run migration scripts to update your DB**. Keys can now have expiration date and readonly flag. Admin can create special keys for certain machinnes. -- 0.7.3 - New possibility of external auth proxy. -- 0.7.2 - Dashboard and Main menu are now customizable in config. App is ready to be packaged using setup.py. -- 0.7.0 - ExaAPI now have two options - HTTP or RabbitMQ. ExaAPI process has been renamed, update of ExaBGP process value is needed for this version. -- 0.6.2 - External config for ExaAPI -- 0.6.0 - Bootstrap 5 in UI -- 0.5.5 - API v3 - auth api key in cookie not in url -- 0.5.4 - Right click menu on adress / Whois or Copy to clipboard -- 0.5.3 - Dashboard update, forms with default action -- 0.5.2 - API v2 with new keys -- 0.5.1 - Bug fixes -- 0.5.0 - New format of LOG table in database. **Run migration scripts to update your DB**. Removed foreign key user_id, author email is stored directly to logs for faster grep text search. -- 0.4.8 - Enhanced String Filtering -- 0.4.7 - Multi neighbor support enabled. See config example and update your config.py. -- 0.4.6 - Route Distinguisher for VRF is now supported. See config example and update your config.py. +## [Change log](./CHANGELOG.md) \ No newline at end of file diff --git a/docs/DockerImage.md b/docs/DockerImage.md new file mode 100644 index 0000000..03562da --- /dev/null +++ b/docs/DockerImage.md @@ -0,0 +1,175 @@ +# ExaFS Docker Installation + +This guide explains how to create a Docker runtime image for ExaFS using the `jirivrany/exafs-base` base image. + +## Prerequisites + +- Docker installed on your system +- A running database instance +- ExaBGP service configured and running (see ExaBGP Setup section) +- Network connectivity between containers/services + +> **Note:** This guide focuses only on building the ExaFS Docker container. Database, ExaBGP, and other services are not included and must be set up separately. +> There is full stack deployment Ansible playbook in separate repository [ExaFS Ansible Deploy](https://github.com/CESNET/ExaFS-deploy) + +## Quick Start + +### 1. Create Project Structure + +Create a directory for your ExaFS Docker setup: + +```bash +mkdir exafs-docker +cd exafs-docker +``` + +### 2. Create Dockerfile + +Create a `Dockerfile` with the following content: + +```dockerfile +# Use the ExaFS base image +FROM jirivrany/exafs-base:latest + +# Set environment variables +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV USER_ID=1000 +ENV GROUP_ID=1000 +ENV USER_NAME=deploy +ENV GROUP_NAME=deploy +ENV FLASK_APP=run.py +ENV TZ="Europe/Prague" + +# Create a group and user +RUN addgroup -g $GROUP_ID $GROUP_NAME && \ + adduser --shell /sbin/nologin --disabled-password \ + --uid $USER_ID --ingroup $GROUP_NAME $USER_NAME + +# Create logs directory and set ownership BEFORE switching to deploy user +RUN mkdir -p /app/logs && chown -R $USER_NAME:$GROUP_NAME /app + +# Copy application files +COPY --chown=$USER_NAME:$GROUP_NAME ./run.py /app/run.py +COPY --chown=$USER_NAME:$GROUP_NAME ./config.py /app/config.py + +# Optional: Copy instance configuration override if needed +# COPY --chown=$USER_NAME:$GROUP_NAME ./instance_config_override.py /app/instance_config_override.py + +# Change to the deploy user +USER $USER_NAME + +# Set the working directory +WORKDIR /app + +# Add user bin to PATH +ENV PATH="/home/${USER_NAME}/.local/bin:${PATH}" + +# Expose the application port +EXPOSE 8000 + +# Command to run the application with Gunicorn +CMD ["gunicorn", "--bind", "0.0.0.0:8000", "run:app"] +``` + +### 3. Create Required Files + + +#### run.py + +Create a `run.py` file as the application entry point. Start from `run.example.py` in the repository and make customizations if needed. + +#### config.py + +Create a `config.py` file with your ExaFS configuration. Start from `config.example.py` in the repository and make customizations if needed. + +# You may need to add other configuration options, such as: +# - Database connection settings (host, port, user, password) +# - Logging configuration +# - Secret keys and API tokens (use environment variables for sensitive data) +# - Integration settings for external services (e.g., ExaBGP, monitoring) +# For a full list of available options, see the ExaFS documentation or config.example.py in the repository. +``` + +> **Important:** Always use environment variables for sensitive data like database passwords and secret keys. + +### 4. Build the Docker Image + +Build your ExaFS runtime image: + +```bash +docker build -t exafs:latest . +``` + +To build a specific version: + +```bash +docker build -t exafs:1.1.6 . +``` + +### 5. Run the Container + +Run the container with environment variables: + +```bash +docker run -d \ + --name exafs \ + -p 8000:8000 \ + -e DATABASE_URL="postgresql://user:password@db-host:5432/exafs" \ + -e SECRET_KEY="your-secret-key" \ + -e EXABGP_HOST="exabgp-host" \ + -e EXABGP_PORT="5000" \ + -v /path/to/logs:/app/logs \ + exafs:latest +``` + +## Configuration Options + +### Environment Variables + +You can customize the container using these environment variables: + +| Variable | Description | Default | +|----------|-------------|---------| +| `DATABASE_URL` | PostgreSQL connection string | - | +| `SECRET_KEY` | Flask secret key for sessions | - | +| `EXABGP_HOST` | ExaBGP service hostname | `exabgp` | +| `EXABGP_PORT` | ExaBGP service port | `5000` | +| `TZ` | Timezone | `Europe/Prague` | +| `FLASK_APP` | Flask application entry point | `run.py` | + +### Custom User and Group IDs + +If you need to match host user/group IDs, modify the Dockerfile: + +```dockerfile +ENV USER_ID=1001 +ENV GROUP_ID=1001 +``` + +### Instance Configuration Override + +For advanced customization, you can use `instance_config_override.py`: + +1. Uncomment the COPY line in the Dockerfile +2. Create `instance_config_override.py` with your custom settings +3. Rebuild the image + +## Volume Mounts + +Consider mounting these directories: + +```bash +docker run -d \ + --name exafs \ + -p 8000:8000 \ + -v /path/to/logs:/app/logs \ + -v /path/to/config.py:/app/config.py:ro \ + exafs:latest +``` + +## Further Reading + +- [ExaFS Ansible Deploy](https://github.com/CESNET/ExaFS-deploy) - Full deployment with Docker Compose +- [ExaFS Installation Guide](./INSTALL.md) - General installation instructions +- [Database Migrations](./DB_MIGRATIONS.md) - Database schema updates \ No newline at end of file diff --git a/flowapp/__about__.py b/flowapp/__about__.py index aaf9610..35407e8 100755 --- a/flowapp/__about__.py +++ b/flowapp/__about__.py @@ -1 +1,5 @@ __version__ = "1.1.6" +__title__ = "ExaFS" +__description__ = "Tool for creation, validation, and execution of ExaBGP messages." +__author__ = "CESNET / Jiri Vrany, Petr Adamec, Josef Verich, Jakub Man" +__license__ = "MIT" diff --git a/pyproject.toml b/pyproject.toml index 844b05c..5e2d3d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,15 +6,24 @@ build-backend = "setuptools.build_meta" name = "exafs" dynamic = ["version"] authors = [ - {name = "CESNET / Jiri Vrany, Petr Adamec, Josef Verich, Jakub Man"} + {name = "Jiri Vrany", email = "jiri.vrany@cesnet.cz"}, + {name = "Petr Adamec", email = "petr.adamec@cesnet.cz"}, + {name = "Josef Verich"}, + {name = "Jakub Man", email = "jakub.man@cesnet.cz"}, +] +maintainers = [ + {name = "Jiri Vrany", email = "jiri.vrany@cesnet.cz"} ] -description = "Tool for creation, validation, and execution of ExaBGP messages." -readme = "README.md" license = {text = "MIT"} +description = "Tool for creation, validation, and execution of ExaBGP messages for network security." +readme = "README.md" requires-python = ">=3.9" +keywords = ["bgp", "exabgp", "flowspec", "ddos", "network-security", "CESNET"] classifiers = [ "Development Status :: 4 - Beta", - "Intended Audience :: Developers", + "Intended Audience :: System Administrators", + "Intended Audience :: Telecommunications Industry", + "Operating System :: OS Independent", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.9", @@ -22,6 +31,9 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Topic :: System :: Networking", + "Topic :: Security", + "Framework :: Flask", ] dependencies = [ "Flask>=2.0.2", @@ -45,16 +57,14 @@ dependencies = [ [project.optional-dependencies] dev = [ "pytest>=7.0.0", - # Add other dev-only dependencies here if needed - # "black>=22.0", - # "mypy>=0.950", - # "flake8>=4.0", ] [project.urls] Homepage = "https://github.com/CESNET/exafs" Repository = "https://github.com/CESNET/exafs" +Documentation = "https://github.com/CESNET/exafs/blob/master/README.md" Issues = "https://github.com/CESNET/exafs/issues" +Changelog = "https://github.com/CESNET/exafs/blob/master/README.md" [tool.setuptools.dynamic] version = {attr = "flowapp.__about__.__version__"} @@ -63,4 +73,12 @@ version = {attr = "flowapp.__about__.__version__"} include = ["flowapp*"] [tool.setuptools.package-data] -"*" = ["*"] \ No newline at end of file +flowapp = [ + "static/*", + "static/js/*", + "templates/*", + "templates/errors/*", + "templates/forms/*", + "templates/layouts/*", + "templates/pages/*", +] \ No newline at end of file diff --git a/withdraw_expired b/withdraw_expired deleted file mode 100644 index 0519ecb..0000000 --- a/withdraw_expired +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file