summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/dependabot.yml8
-rw-r--r--.github/workflows/ci.yaml18
-rw-r--r--.github/workflows/update-lock.yaml26
-rw-r--r--Dockerfile11
-rw-r--r--README.md14
-rw-r--r--flake.lock63
-rw-r--r--flake.nix97
-rw-r--r--nix/default.nix16
-rw-r--r--nix/derivation.nix21
-rw-r--r--nix/dev.nix41
-rw-r--r--nix/module.nix118
-rw-r--r--nix/packages.nix25
-rw-r--r--nix/server.nix6
-rw-r--r--nix/vm.nix42
-rw-r--r--requirements.txt19
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"]
diff --git a/README.md b/README.md
index 6d5ca6f..9bd83ce 100644
--- a/README.md
+++ b/README.md
@@ -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
```
diff --git a/flake.lock b/flake.lock
index 12afb25..4015c72 100644
--- a/flake.lock
+++ b/flake.lock
@@ -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"
}
}
},
diff --git a/flake.nix b/flake.nix
index fa387cf..28a1bde 100644
--- a/flake.nix
+++ b/flake.nix
@@ -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