diff options
| author | seth <[email protected]> | 2023-09-06 18:51:30 -0400 |
|---|---|---|
| committer | seth <[email protected]> | 2023-09-07 11:50:26 -0400 |
| commit | 0f3a367d27c909b803baf0185d0b6e0ade968c3a (patch) | |
| tree | 03b1b04127029289c1356bf2c0597b5aa8a37aec | |
| parent | 8d8dc0896fc8c7f0d2f10087db39cac4e3149c66 (diff) | |
flake: start using flake-parts + add vm test
| -rw-r--r-- | .github/dependabot.yml | 8 | ||||
| -rw-r--r-- | .github/workflows/ci.yaml | 18 | ||||
| -rw-r--r-- | .github/workflows/update-lock.yaml | 26 | ||||
| -rw-r--r-- | Dockerfile | 11 | ||||
| -rw-r--r-- | README.md | 14 | ||||
| -rw-r--r-- | flake.lock | 63 | ||||
| -rw-r--r-- | flake.nix | 97 | ||||
| -rw-r--r-- | nix/default.nix | 16 | ||||
| -rw-r--r-- | nix/derivation.nix | 21 | ||||
| -rw-r--r-- | nix/dev.nix | 41 | ||||
| -rw-r--r-- | nix/module.nix | 118 | ||||
| -rw-r--r-- | nix/packages.nix | 25 | ||||
| -rw-r--r-- | nix/server.nix | 6 | ||||
| -rw-r--r-- | nix/vm.nix | 42 | ||||
| -rw-r--r-- | requirements.txt | 19 |
15 files changed, 361 insertions, 164 deletions
diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..9cd57fa --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + commit-message: + prefix: "deps(python)" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..121e120 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,18 @@ +name: ci + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +jobs: + update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/magic-nix-cache-action@main + + - run: nix build -L .#tests.x86_64-linux.module diff --git a/.github/workflows/update-lock.yaml b/.github/workflows/update-lock.yaml new file mode 100644 index 0000000..6ab7eb7 --- /dev/null +++ b/.github/workflows/update-lock.yaml @@ -0,0 +1,26 @@ +name: update flake lock + +on: + schedule: + - cron: "0 0 * * 6" + workflow_dispatch: + +jobs: + update: + runs-on: ubuntu-latest + + permissions: + contents: write + pull-requests: write + + steps: + - uses: actions/checkout@v4 + - uses: DeterminateSystems/nix-installer-action@main + + - name: update lockfile + uses: DeterminateSystems/update-flake-lock@v20 + id: update + with: + commit-msg: "flake: update inputs" + pr-title: "flake: update inputs" + token: ${{ github.token }} diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index ffb35ef..0000000 --- a/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.11 - -WORKDIR /code - -COPY ./requirements.txt /code/requirements.txt - -RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt - -COPY ./src/guzzle_api /code/guzzle_api - -CMD [ "uvicorn", "guzzle_api.api:app", "--host", "0.0.0.0", "--port", "80"] @@ -3,18 +3,4 @@ fun little service powered by [fastAPI](https://github.com/tiangolo/fastapi) right now it only serves pics of teawie - -## how to host - -this is meant for my [website](https://guzzle.gay/), but it can be hosted anywhere with one edit in `src/guzzle_api/bot.py` :) - -on L7, change the `URL` constant to whatever domain you plan to host this on -```python -URL = "https://<yourdomainhere> -``` - -and to start running a docker (or podman) container: -```bash -docker build -t guzzle_api . -docker run -d --name api <your_desired_port>:80 guzzle_api ``` @@ -17,12 +17,15 @@ } }, "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", "owner": "numtide", "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", "type": "github" }, "original": { @@ -34,7 +37,7 @@ "gitignore": { "inputs": { "nixpkgs": [ - "pre-commit-hooks", + "pre-commit", "nixpkgs" ] }, @@ -54,11 +57,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1681920287, - "narHash": "sha256-+/d6XQQfhhXVfqfLROJoqj3TuG38CAeoT6jO1g9r1k0=", + "lastModified": 1693844670, + "narHash": "sha256-t69F2nBB8DNQUWHD809oJZJVE+23XBrth4QZuVd6IE0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "645bc49f34fa8eff95479f0345ff57e55b53437e", + "rev": "3c15feef7770eb5500a4b8792623e2d6f598c9c1", "type": "github" }, "original": { @@ -67,7 +70,27 @@ "type": "indirect" } }, - "pre-commit-hooks": { + "parts": { + "inputs": { + "nixpkgs-lib": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1693611461, + "narHash": "sha256-aPODl8vAgGQ0ZYFIRisxYG5MOGSkIczvu2Cd8Gb9+1Y=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "7f53fdb7bdc5bb237da7fefef12d099e4fd611ca", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "pre-commit": { "inputs": { "flake-compat": "flake-compat", "flake-utils": "flake-utils", @@ -80,11 +103,11 @@ ] }, "locked": { - "lastModified": 1681831107, - "narHash": "sha256-pXl3DPhhul9NztSetUJw2fcN+RI3sGOYgKu29xpgnqw=", + "lastModified": 1692274144, + "narHash": "sha256-BxTQuRUANQ81u8DJznQyPmRsg63t4Yc+0kcyq6OLz8s=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "b7ca8f6fff42f6af75c17f9438fed1686b7d855d", + "rev": "7e3517c03d46159fdbf8c0e5c97f82d5d4b0c8fa", "type": "github" }, "original": { @@ -96,7 +119,23 @@ "root": { "inputs": { "nixpkgs": "nixpkgs", - "pre-commit-hooks": "pre-commit-hooks" + "parts": "parts", + "pre-commit": "pre-commit" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" } } }, @@ -3,7 +3,11 @@ inputs = { nixpkgs.url = "nixpkgs/nixos-unstable"; - pre-commit-hooks = { + parts = { + url = "github:hercules-ci/flake-parts"; + inputs.nixpkgs-lib.follows = "nixpkgs"; + }; + pre-commit = { url = "github:cachix/pre-commit-hooks.nix"; inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs-stable.follows = "nixpkgs"; @@ -11,76 +15,27 @@ }; outputs = { + parts, + pre-commit, self, - nixpkgs, - pre-commit-hooks, - }: let - version = self.lastModifiedDate; - - systems = [ - "x86_64-linux" - "aarch64-linux" - "x86_64-darwin" - "aarch64-darwin" - ]; - - forAllSystems = nixpkgs.lib.genAttrs systems; - nixpkgsFor = forAllSystems (system: - import nixpkgs { - inherit system; - overlays = [self.overlays.default]; - }); - - packageFn = pkgs: let - inherit (pkgs) callPackage; - in { - guzzle-api = callPackage ./nix {inherit version;}; - guzzle-api-server = callPackage ./nix/server.nix {}; + ... + } @ inputs: + parts.lib.mkFlake {inherit inputs;} { + imports = [ + pre-commit.flakeModule + ./nix/dev.nix + ./nix/packages.nix + ]; + + systems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + + perSystem = p: {formatter = p.pkgs.alejandra;}; + + flake.nixosModules.default = import ./nix/module.nix self; }; - in { - checks = forAllSystems (system: let - pkgs = nixpkgsFor.${system}; - in { - pre-commit-check = pre-commit-hooks.lib.${system}.run { - src = ./.; - hooks = { - isort.enable = true; - pylint.enable = true; - yapf = { - enable = true; - name = "yapf"; - entry = "${pkgs.python311Packages.yapf}/bin/yapf -i"; - types = ["file" "python"]; - }; - }; - }; - }); - - devShells = forAllSystems (system: let - pkgs = nixpkgsFor.${system}; - inherit (pkgs) mkShell; - in { - default = mkShell { - inherit (self.checks.${system}.pre-commit-check) shellHook; - packages = with pkgs.python311Packages; [ - python - fastapi - httpx - pydantic - pylint - toml - uvicorn - yapf - ]; - }; - }); - - nixosModules.guzzle_api = import ./nix/module.nix; - - packages = forAllSystems (system: let - pkgs = nixpkgsFor.${system}; - in {inherit (pkgs) guzzle-api guzzle-api-server;}); - - overlays.default = final: _: packageFn final; - }; } diff --git a/nix/default.nix b/nix/default.nix deleted file mode 100644 index fca9993..0000000 --- a/nix/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - lib, - python311Packages, - version, -}: -python311Packages.buildPythonPackage { - pname = "guzzle-api"; - inherit version; - - src = lib.cleanSource ../.; - format = "flit"; - doCheck = false; - - propagatedBuildInputs = with python311Packages; [fastapi pydantic uvicorn]; - propagatedNativeBuildInputs = with python311Packages; [flit-core]; -} diff --git a/nix/derivation.nix b/nix/derivation.nix new file mode 100644 index 0000000..4e32095 --- /dev/null +++ b/nix/derivation.nix @@ -0,0 +1,21 @@ +{ + lib, + buildPythonPackage, + flit-core, + fastapi, + pydantic, + uvicorn, + self, + version, +}: +buildPythonPackage { + pname = "guzzle-api"; + inherit version; + + src = lib.cleanSource self; + format = "flit"; + doCheck = false; + + propagatedBuildInputs = [fastapi pydantic uvicorn]; + propagatedNativeBuildInputs = [flit-core]; +} diff --git a/nix/dev.nix b/nix/dev.nix new file mode 100644 index 0000000..b394c6c --- /dev/null +++ b/nix/dev.nix @@ -0,0 +1,41 @@ +{ + inputs, + self, + withSystem, + ... +}: { + perSystem = { + config, + pkgs, + ... + }: { + pre-commit = { + settings.hooks = { + isort.enable = true; + pylint.enable = true; + yapf = { + enable = true; + name = "yapf"; + entry = "${pkgs.python311Packages.yapf}/bin/yapf -i"; + types = ["file" "python"]; + }; + }; + }; + + devShells.default = pkgs.mkShell { + shellHook = config.pre-commit.installationScript; + packages = [ + (pkgs.python311.withPackages (p: with p; [isort yapf pylint])) + ]; + }; + }; + + flake.tests.x86_64-linux.module = withSystem "x86_64-linux" ({pkgs, ...}: + (import (inputs.nixpkgs + "/nixos/lib") {}).runTest { + imports = [./vm.nix]; + + hostPkgs = pkgs; + + _module.args = {inherit self;}; + }); +} diff --git a/nix/module.nix b/nix/module.nix index 4234e19..10f09c3 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -1,43 +1,125 @@ -{ +self: { config, lib, + modulesPath, pkgs, ... }: let cfg = config.services.guzzle-api; - inherit (lib) mkDefault mkEnableOption mkOption mkIf types; + inherit + (lib) + literalExpression + mkDefault + mkDoc + mkEnableOption + mkIf + mkMerge + mkOption + mkPackageOption + types + ; + + proto = "http${lib.optionalString cfg.nginx.addSSL "s"}"; + + hostPortSubmodule = { + options = { + host = mkOption { + description = mkDoc "the hostname"; + type = types.str; + }; + + port = mkOption { + description = mkDoc "the port"; + type = types.port; + }; + }; + }; in { options.services.guzzle-api = { - enable = mkEnableOption "enable guzzle-api"; - url = mkOption { - type = types.str; - default = ""; - description = "url string for guzzle-api"; + enable = mkEnableOption "guzzle-api"; + + listen = mkOption { + description = mkDoc "address and port to listen to"; + type = types.submodule hostPortSubmodule; + default = { + host = "localhost"; + port = 7240; + }; + defaultText = literalExpression '' + { + address = "localhost"; + port = 7240; + } + ''; }; - port = mkOption { + + domain = mkOption { + description = mkDoc "FQDN for guzzle_api endpoint"; type = types.str; - default = "8080"; - description = "port for guzzle-api"; }; - package = mkOption { - type = types.package; - default = pkgs.guzzle-api-server; - description = "package for guzzle-api wrapper"; + + nginx = mkOption { + description = mkDoc '' + With this option, you can customize an nginx virtual host which already has sensible defaults for Dolibarr. + Set to {} if you do not need any customization to the virtual host. + If enabled, then by default, the {option}`serverName` is + `''${domain}`, + If this is set to null (the default), no nginx virtualHost will be configured. + ''; + + type = types.nullOr (types.submodule ( + import (modulesPath + "/services/web-servers/nginx/vhost-options.nix") {inherit config lib;} + )); + + default = null; + example = literalExpression '' + { + enableACME = true; + forceSSL = true; + } + ''; }; + + package = mkPackageOption self.packages.${pkgs.stdenv.hostPlatform.system} "guzzle-api-server" {}; }; - config.systemd.services = mkIf cfg.enable { - guzzle-api = { + config = mkIf cfg.enable { + systemd.services.guzzle-api = { enable = mkDefault true; wantedBy = ["multi-user.target"]; after = ["network.target"]; script = '' - URL=${cfg.url} ${cfg.package}/bin/guzzle-api-server --host 0.0.0.0 --port "${cfg.port}" + URL="${proto}://${cfg.domain}" ${cfg.package}/bin/guzzle-api-server --host ${cfg.listen.host} --port ${toString cfg.listen.port} ''; serviceConfig = mkDefault { - Restart = "always"; Type = "simple"; + Restart = "always"; + + # hardening + DynamicUser = true; + PrivateTmp = true; + NoNewPrivileges = true; + RestrictNamespaces = "uts ipc pid user cgroup"; + ProtectSystem = "strict"; + ProtectHome = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + PrivateDevices = true; + RestrictSUIDSGID = true; }; }; + + services.nginx = mkIf (cfg.nginx != null) { + enable = true; + virtualHosts."${cfg.domain}" = mkMerge [ + { + locations."/" = { + proxyPass = "http://${cfg.listen.host}:${toString cfg.listen.port}"; + }; + } + cfg.nginx + ]; + }; }; } diff --git a/nix/packages.nix b/nix/packages.nix new file mode 100644 index 0000000..0adf42f --- /dev/null +++ b/nix/packages.nix @@ -0,0 +1,25 @@ +{self, ...}: let + version = builtins.substring 0 8 self.lastModifiedDate or "dirty"; + commonArgs = {inherit self version;}; +in { + perSystem = {pkgs, ...}: { + packages = rec { + guzzle-api = pkgs.python311Packages.callPackage ./derivation.nix commonArgs; + guzzle-api-server = pkgs.python311Packages.callPackage ./server.nix {inherit guzzle-api;}; + default = guzzle-api; + }; + }; + + flake.overlays.default = final: prev: { + python = prev.python.override { + packageOverrides = _: prev': { + guzzle-api = prev'.callPackage ./derivation.nix commonArgs; + }; + }; + + pythonPackages = final.python.pkgs; + + guzzle-api = final.pythonPackages.callPackage ./derivation.nix commonArgs; + guzzle-api-server = final.pythonPackages.callPackage ./server.nix {}; + }; +} diff --git a/nix/server.nix b/nix/server.nix index 18e4673..eaa3ead 100644 --- a/nix/server.nix +++ b/nix/server.nix @@ -1,12 +1,12 @@ { writeShellApplication, - python311, + python, + uvicorn, guzzle-api, - ... }: writeShellApplication { name = "guzzle-api-server"; - runtimeInputs = [(python311.withPackages (p: [p.uvicorn guzzle-api]))]; + runtimeInputs = [(python.withPackages (_: [uvicorn guzzle-api]))]; text = '' uvicorn guzzle_api.api:app "$@" ''; diff --git a/nix/vm.nix b/nix/vm.nix new file mode 100644 index 0000000..b4d1f8a --- /dev/null +++ b/nix/vm.nix @@ -0,0 +1,42 @@ +{self, ...}: { + name = "guzzle_api-test"; + + nodes.machine = _: { + imports = [self.nixosModules.default]; + + boot.loader.grub.enable = true; + virtualisation = { + memorySize = 2048; + writableStore = true; + }; + + services = { + nginx = { + enable = true; + + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + }; + + guzzle-api = { + enable = true; + domain = "test.com"; + listen = { + host = "0.0.0.0"; + port = 8080; + }; + nginx = {}; + }; + }; + }; + + testScript = _: '' + machine.start() + machine.wait_for_unit("nginx.service") + machine.wait_for_unit("guzzle-api.service") + machine.wait_for_open_port(8080) + machine.succeed("curl 0.0.0.0:8080/get_random_teawie | grep url") + ''; +} diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 89b3e3f..0000000 --- a/requirements.txt +++ /dev/null @@ -1,19 +0,0 @@ -anyio==3.6.2 -certifi==2023.7.22 -charset-normalizer==2.1.1 -click==8.1.3 -colorama==0.4.6 -docutils==0.19 -fastapi==0.89.1 -flit==3.8.0 -flit_core==3.8.0 -h11==0.14.0 -idna==3.4 -pydantic==1.10.4 -requests==2.31.0 -sniffio==1.3.0 -starlette==0.27.0 -tomli_w==1.0.0 -typing_extensions==4.4.0 -urllib3==1.26.13 -uvicorn==0.20.0 |
