From 7474f01193ff127f7aaec7d8cbc61bf26c24faee Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Sat, 15 Jun 2024 13:41:51 +0200 Subject: [PATCH 1/2] Inventory: init draft ideas --- flake.nix | 2 + inventory/.envrc | 5 ++ inventory/.vscode/settings.json | 6 ++ inventory/README.md | 57 +++++++++++++ inventory/example_flake.nix | 119 ++++++++++++++++++++++++++++ inventory/flake-module.nix | 18 +++++ inventory/inventory.json | 34 ++++++++ inventory/src/cue.mod/module.cue | 2 + inventory/src/machines/machines.cue | 8 ++ inventory/src/root.cue | 28 +++++++ inventory/src/services/services.cue | 21 +++++ inventory/src/users/users.cue | 9 +++ 12 files changed, 309 insertions(+) create mode 100644 inventory/.envrc create mode 100644 inventory/.vscode/settings.json create mode 100644 inventory/README.md create mode 100644 inventory/example_flake.nix create mode 100644 inventory/flake-module.nix create mode 100644 inventory/inventory.json create mode 100644 inventory/src/cue.mod/module.cue create mode 100644 inventory/src/machines/machines.cue create mode 100644 inventory/src/root.cue create mode 100644 inventory/src/services/services.cue create mode 100644 inventory/src/users/users.cue diff --git a/flake.nix b/flake.nix index be6a1db8..341c5b84 100644 --- a/flake.nix +++ b/flake.nix @@ -53,6 +53,8 @@ ./nixosModules/flake-module.nix ./pkgs/flake-module.nix ./templates/flake-module.nix + + ./inventory/flake-module.nix ]; } ); diff --git a/inventory/.envrc b/inventory/.envrc new file mode 100644 index 00000000..8d1c6842 --- /dev/null +++ b/inventory/.envrc @@ -0,0 +1,5 @@ +source_up + +watch_file flake-module.nix + +use flake .#inventory-schema --builders '' diff --git a/inventory/.vscode/settings.json b/inventory/.vscode/settings.json new file mode 100644 index 00000000..82a476e3 --- /dev/null +++ b/inventory/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "cue.toolsPath": "/nix/store/x9471mp522cdi4c9gc8dchvyx6v01b3f-cue-0.8.2/bin/cue", + "[cue]": { + "editor.formatOnSave": false + } +} \ No newline at end of file diff --git a/inventory/README.md b/inventory/README.md new file mode 100644 index 00000000..318d1bf0 --- /dev/null +++ b/inventory/README.md @@ -0,0 +1,57 @@ +# Inventory + +This part provides a specification for the inventory. + +It is used for design phase and as validation helper. + +> Cue is less verbose and easier to understand and maintain than json-schema. +> Json-schema, if needed can be easily generated on-the fly. + +## Checking validity + +Directly check a json against the schema + +`cue vet inventory.json root.cue -d '#Root'` + +## Json schema + +Export the json-schema i.e. for usage in python / javascript / nix + +`cue export --out openapi root.cue` + +## Usage + +Comments are rendered as descriptions in the json schema. + +```cue +// A name of the clan (primarily shown by the UI) +name: string +``` + +Cue open sets. In the following `foo = {...}` means that the key `foo` can contain any arbitrary json object. + +```cue +foo: { ... } +``` + +Cue dynamic keys. + +```cue +[string]: { + attr: string +} +``` + +This is the schema of + +```json +{ + "a": { + "attr": "foo" + }, + "b": { + "attr": "bar" + } + // ... Indefinitely more dynamic keys of type "string" +} +``` diff --git a/inventory/example_flake.nix b/inventory/example_flake.nix new file mode 100644 index 00000000..b6f7fca6 --- /dev/null +++ b/inventory/example_flake.nix @@ -0,0 +1,119 @@ +{ + description = ""; + + inputs.clan-core.url = "https://git.clan.lol/clan/clan-core/archive/main.tar.gz"; + + outputs = + { clan-core, ... }: + let + pkgs = clan-core.inputs.nixpkgs.legacyPackages.${system}; + # Usage see: https://docs.clan.lol + + # nice_flake_interface -> buildClan() -> inventory -> buildClanFromInventory() -> nixosConfigurations + + system = "x86_64-linux"; + + clan = + clan-core.lib.buildClanFromInventory [ + # Inventory 0 (loads the json file managed by the Python API) + (builtins.fromJSON (builtins.readFile ./inventory.json)) + # -> + # { + # services."backups_1".autoIncludeMachines = true; + # services."backups_1".module = "borgbackup"; + # ... etc. + # } + ] + ++ buildInventory { + clanName = "nice_flake_interface"; + description = "A nice flake interface"; + icon = "assets/icon.png"; + machines = { + jon = { + # Just regular nixos/clan configuration ? + # config = { + # imports = [ + # ./modules/shared.nix + # ./machines/jon/configuration.nix + # ]; + # nixpkgs.hostPlatform = system; + # # Set this for clan commands use ssh i.e. `clan machines update` + # # If you change the hostname, you need to update this line to root@ + # # This only works however if you have avahi running on your admin machine else use IP + # clan.networking.targetHost = pkgs.lib.mkDefault "root@jon"; + # # ssh root@flash-installer.local lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT + # disko.devices.disk.main = { + # device = "/dev/disk/by-id/__CHANGE_ME__"; + # }; + # # IMPORTANT! Add your SSH key here + # # e.g. > cat ~/.ssh/id_ed25519.pub + # users.users.root.openssh.authorizedKeys.keys = throw '' + # Don't forget to add your SSH key here! + # users.users.root.openssh.authorizedKeys.keys = [ "" ] + # ''; + # # Zerotier needs one controller to accept new nodes. Once accepted + # # the controller can be offline and routing still works. + # clan.networking.zerotier.controller.enable = true; + # }; + }; + }; + } + ++ [ + # Low level inventory overrides (comes at the end) + { + services."backups_2".autoIncludeMachines = true; + services."backups_2".module = "borgbackup"; + } + ]; + + /* + # Type + + buildInventory :: { + clanName :: string + machines :: { + ${name} :: { + config :: { + # NixOS configuration + }; + }; + }; + # ... More mapped inventory options + # i.e. shared config for all machines + } -> Inventory + */ + buildInventory = + options: + let + # TODO: Map over machines + name = "jon"; + inventory = { + # Set the clan meta + meta.name = options.clanName; + meta.description = options.description; + meta.icon = options.icon; + # Declare the services + # This "nixos" module simply provides the usual NixOS configuration options. + services."nixos".module = "nixos"; + services."nixos".machineConfig.${name}.config = options.machines.${name}.config; + + # Declare the machines + machines.${name} = { + name = options.machines.${name}.meta.name; + description = options.machines.${name}.meta.description; + icon = options.machines.${name}.meta.icon; + system = options.machines.${name}.config.nixpkgs.hostPlatform; + }; + }; + in + inventory; + in + { + # all machines managed by Clan + inherit (clan) nixosConfigurations clanInternals; + # add the Clan cli tool to the dev shell + devShells.${system}.default = pkgs.mkShell { + packages = [ clan-core.packages.${system}.clan-cli ]; + }; + }; +} diff --git a/inventory/flake-module.nix b/inventory/flake-module.nix new file mode 100644 index 00000000..4519f8e2 --- /dev/null +++ b/inventory/flake-module.nix @@ -0,0 +1,18 @@ +{ ... }: +{ + perSystem = + { pkgs, config, ... }: + { + packages.inventory-schema = pkgs.stdenv.mkDerivation { + name = "inventory-schema"; + src = ./src; + + buildInputs = [ pkgs.cue ]; + + installPhase = '' + mkdir -p $out + ''; + }; + devShells.inventory-schema = pkgs.mkShell { inputsFrom = [ config.packages.inventory-schema ]; }; + }; +} diff --git a/inventory/inventory.json b/inventory/inventory.json new file mode 100644 index 00000000..0ee272e7 --- /dev/null +++ b/inventory/inventory.json @@ -0,0 +1,34 @@ +{ + "meta": { + "name": "My clan", + "description": "My clan description", + "icon": "assets/clan-icon.png" + }, + "services": { + "service_ref": { + "meta": { + "name": "backup" + }, + "autoIncludeMachines": true, + "module": "core" + } + }, + "machines": { + "jon_machine": { + "name": "jon_machine", + "description": "Jon's machine", + "icon": "assets/icon.png", + "system": "x86_64-linux" + } + }, + "users": { + "mic": { + "autoInclude": false, + "schemas": ["ssh-user"], + "config": { + "sshKey": "...", + "username": "mic92" + } + } + } +} diff --git a/inventory/src/cue.mod/module.cue b/inventory/src/cue.mod/module.cue new file mode 100644 index 00000000..773cae9d --- /dev/null +++ b/inventory/src/cue.mod/module.cue @@ -0,0 +1,2 @@ +module: "clan.lol/inventory" +language: version: "v0.8.2" \ No newline at end of file diff --git a/inventory/src/machines/machines.cue b/inventory/src/machines/machines.cue new file mode 100644 index 00000000..36d77e37 --- /dev/null +++ b/inventory/src/machines/machines.cue @@ -0,0 +1,8 @@ +package machines + +#machine: machines: [string]: { + "name": string, + "description": string, + "icon": string, + "system": string +} \ No newline at end of file diff --git a/inventory/src/root.cue b/inventory/src/root.cue new file mode 100644 index 00000000..c3b7496a --- /dev/null +++ b/inventory/src/root.cue @@ -0,0 +1,28 @@ +package inventory + +import ( + "clan.lol/inventory/services" + "clan.lol/inventory/machines" + "clan.lol/inventory/users" +) + +@jsonschema(schema="http://json-schema.org/schema#") +#Root: { + meta: { + // A name of the clan (primarily shown by the UI) + name: string + // A description of the clan + description: string + // The icon path + icon: string + } + + // A map of services + services.#service + + // A map of machines + machines.#machine + + // A map of users + users.#user +} diff --git a/inventory/src/services/services.cue b/inventory/src/services/services.cue new file mode 100644 index 00000000..c24ef69f --- /dev/null +++ b/inventory/src/services/services.cue @@ -0,0 +1,21 @@ +package services + +#service: services: [string]: { + autoIncludeMachines: bool, + meta: { + name: string, + }, + // TODO: this should be the list of avilable modules + module: string, + machineConfig: { + [string]: { + config: { + defaultUser?: string + } + } + }, + globalConfig: { + // Should be one of the avilable users + defaultUser?: string, + } +} \ No newline at end of file diff --git a/inventory/src/users/users.cue b/inventory/src/users/users.cue new file mode 100644 index 00000000..bdd54067 --- /dev/null +++ b/inventory/src/users/users.cue @@ -0,0 +1,9 @@ +package users + +#user: users: [string]: { + "autoInclude": bool, + "schemas": [ string ], + "config": { + ... + } +} \ No newline at end of file From 13aa60529f8cfa06388b383b29afc22bb9a66af0 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Sat, 15 Jun 2024 13:41:51 +0200 Subject: [PATCH 2/2] Inventory: init draft ideas --- inventory/.vscode/settings.json | 6 - inventory/example_flake.nix | 216 +++++++++++++++------------ inventory/flake-module.nix | 28 ++++ inventory/inventory.json | 34 ----- inventory/src/machines/machines.cue | 20 ++- inventory/src/root.cue | 8 +- inventory/src/services/services.cue | 35 +++-- inventory/src/tests/1_inventory.json | 58 +++++++ inventory/src/users/users.cue | 9 -- 9 files changed, 243 insertions(+), 171 deletions(-) delete mode 100644 inventory/.vscode/settings.json delete mode 100644 inventory/inventory.json create mode 100644 inventory/src/tests/1_inventory.json delete mode 100644 inventory/src/users/users.cue diff --git a/inventory/.vscode/settings.json b/inventory/.vscode/settings.json deleted file mode 100644 index 82a476e3..00000000 --- a/inventory/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "cue.toolsPath": "/nix/store/x9471mp522cdi4c9gc8dchvyx6v01b3f-cue-0.8.2/bin/cue", - "[cue]": { - "editor.formatOnSave": false - } -} \ No newline at end of file diff --git a/inventory/example_flake.nix b/inventory/example_flake.nix index b6f7fca6..11be13a7 100644 --- a/inventory/example_flake.nix +++ b/inventory/example_flake.nix @@ -7,107 +7,125 @@ { clan-core, ... }: let pkgs = clan-core.inputs.nixpkgs.legacyPackages.${system}; - # Usage see: https://docs.clan.lol - - # nice_flake_interface -> buildClan() -> inventory -> buildClanFromInventory() -> nixosConfigurations - system = "x86_64-linux"; - - clan = - clan-core.lib.buildClanFromInventory [ - # Inventory 0 (loads the json file managed by the Python API) - (builtins.fromJSON (builtins.readFile ./inventory.json)) - # -> - # { - # services."backups_1".autoIncludeMachines = true; - # services."backups_1".module = "borgbackup"; - # ... etc. - # } - ] - ++ buildInventory { - clanName = "nice_flake_interface"; - description = "A nice flake interface"; - icon = "assets/icon.png"; - machines = { - jon = { - # Just regular nixos/clan configuration ? - # config = { - # imports = [ - # ./modules/shared.nix - # ./machines/jon/configuration.nix - # ]; - # nixpkgs.hostPlatform = system; - # # Set this for clan commands use ssh i.e. `clan machines update` - # # If you change the hostname, you need to update this line to root@ - # # This only works however if you have avahi running on your admin machine else use IP - # clan.networking.targetHost = pkgs.lib.mkDefault "root@jon"; - # # ssh root@flash-installer.local lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT - # disko.devices.disk.main = { - # device = "/dev/disk/by-id/__CHANGE_ME__"; - # }; - # # IMPORTANT! Add your SSH key here - # # e.g. > cat ~/.ssh/id_ed25519.pub - # users.users.root.openssh.authorizedKeys.keys = throw '' - # Don't forget to add your SSH key here! - # users.users.root.openssh.authorizedKeys.keys = [ "" ] - # ''; - # # Zerotier needs one controller to accept new nodes. Once accepted - # # the controller can be offline and routing still works. - # clan.networking.zerotier.controller.enable = true; - # }; - }; - }; - } - ++ [ - # Low level inventory overrides (comes at the end) - { - services."backups_2".autoIncludeMachines = true; - services."backups_2".module = "borgbackup"; - } - ]; - - /* - # Type - - buildInventory :: { - clanName :: string - machines :: { - ${name} :: { - config :: { - # NixOS configuration - }; - }; - }; - # ... More mapped inventory options - # i.e. shared config for all machines - } -> Inventory - */ - buildInventory = - options: - let - # TODO: Map over machines - name = "jon"; - inventory = { - # Set the clan meta - meta.name = options.clanName; - meta.description = options.description; - meta.icon = options.icon; - # Declare the services - # This "nixos" module simply provides the usual NixOS configuration options. - services."nixos".module = "nixos"; - services."nixos".machineConfig.${name}.config = options.machines.${name}.config; - - # Declare the machines - machines.${name} = { - name = options.machines.${name}.meta.name; - description = options.machines.${name}.meta.description; - icon = options.machines.${name}.meta.icon; - system = options.machines.${name}.config.nixpkgs.hostPlatform; - }; - }; - in - inventory; in + # Usage see: https://docs.clan.lol + # nice_flake_interface -> buildInventory() -> Inventory -> buildClanFromInventory() -> nixosConfigurations + # buildClanFromInventory = inventory: evalModules { + # extraAttrs = { inherit inventory; }; + # # (attrNames inventory.machines) + # }; + # clan = + # clan-core.lib.buildClanFromInventory [ + # # Inventory 0 (loads the json file managed by the Python API) + # (builtins.fromJSON (builtins.readFile ./inventory.json)) + # # -> + # # { + # # services."backups_1".autoIncludeMachines = true; + # # services."backups_1".module = "borgbackup"; + # # ... etc. + # # } + # ] + # ++ (buildInventory { + # clanName = "nice_flake_interface"; + # description = "A nice flake interface"; + # icon = "assets/icon.png"; + # machines = { + # jon = { + # # Just regular nixos/clan configuration ? + # # config = { + # # imports = [ + # # ./modules/shared.nix + # # ./machines/jon/configuration.nix + # # ]; + # # nixpkgs.hostPlatform = system; + # # # Set this for clan commands use ssh i.e. `clan machines update` + # # # If you change the hostname, you need to update this line to root@ + # # # This only works however if you have avahi running on your admin machine else use IP + # # clan.networking.targetHost = pkgs.lib.mkDefault "root@jon"; + # # # ssh root@flash-installer.local lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT + # # disko.devices.disk.main = { + # # device = "/dev/disk/by-id/__CHANGE_ME__"; + # # }; + # # # IMPORTANT! Add your SSH key here + # # # e.g. > cat ~/.ssh/id_ed25519.pub + # # users.users.root.openssh.authorizedKeys.keys = throw '' + # # Don't forget to add your SSH key here! + # # users.users.root.openssh.authorizedKeys.keys = [ "" ] + # # ''; + # # # Zerotier needs one controller to accept new nodes. Once accepted + # # # the controller can be offline and routing still works. + # # clan.networking.zerotier.controller.enable = true; + # # }; + # }; + # }; + # }) + # ++ [ + # # Low level inventory overrides (comes at the end) + # { + # services."backups_2".autoIncludeMachines = true; + # services."backups_2".module = "borgbackup"; + # } + # ]; + # # buildClan :: [ Partial ] -> Inventory + # # foldl' (acc: v: lib.recursiveUpdate acc v) {} [] + # inventory = [ + # # import json + # {...} + # # power user flake + # {...} + # ] + # # With Module system + # # Pros: Easy to understand, + # # Cons: Verbose, hard to maintain + # # buildClan :: { modules = [ { config = Partial; options :: InventoryOptions; } } ]; } -> Inventory + # eval = lib.evalModules { + # modules = [ + # { + # # Inventory Schema + # # Python validation + # options = {...} + # } + # { + # config = map lib.mkDefault + # (builtins.fromJSON (builtins.readFile ./inventory.json)) + # } + # { + # # User provided + # config = {...} + # } + # # Later overrides. + # { + # lib.mkForce ... + # } + # ]; + # } + # nixosConfigurations = lib.evalModules inventory; + # eval.config.inventory + # # + # eval.config.machines.jon#nixosConfig + # eval.config.machines.sara#nixosConfig + # + # {inventory, config, ...}:{ + # hostname = config.machines.sara # Invalid + # hostname = inventory.machines.sara.hostname # Valid + # } + /* + # Type + + buildInventory :: { + clanName :: string + machines :: { + ${name} :: { + config :: { + # NixOS configuration + }; + }; + }; + # ... More mapped inventory options + # i.e. shared config for all machines + } -> Inventory + */ { # all machines managed by Clan inherit (clan) nixosConfigurations clanInternals; diff --git a/inventory/flake-module.nix b/inventory/flake-module.nix index 4519f8e2..65c6c66f 100644 --- a/inventory/flake-module.nix +++ b/inventory/flake-module.nix @@ -14,5 +14,33 @@ ''; }; devShells.inventory-schema = pkgs.mkShell { inputsFrom = [ config.packages.inventory-schema ]; }; + + checks.inventory-schema-checks = pkgs.stdenv.mkDerivation { + name = "inventory-schema-checks"; + src = ./src; + buildInputs = [ pkgs.cue ]; + buildPhase = '' + echo "Running inventory tests..." + + echo "Export cue as json-schema..." + cue export --out openapi root.cue + + echo "Validate test/*.json against inventory-schema..." + + test_dir="test" + for file in "$test_dir"/*; do + # Check if the item is a file + if [ -f "$file" ]; then + # Print the filename + echo "Running test on: $file" + + # Run the cue vet command + cue vet "$file" root.cue -d "#Root" + fi + done + + touch $out + ''; + }; }; } diff --git a/inventory/inventory.json b/inventory/inventory.json deleted file mode 100644 index 0ee272e7..00000000 --- a/inventory/inventory.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "meta": { - "name": "My clan", - "description": "My clan description", - "icon": "assets/clan-icon.png" - }, - "services": { - "service_ref": { - "meta": { - "name": "backup" - }, - "autoIncludeMachines": true, - "module": "core" - } - }, - "machines": { - "jon_machine": { - "name": "jon_machine", - "description": "Jon's machine", - "icon": "assets/icon.png", - "system": "x86_64-linux" - } - }, - "users": { - "mic": { - "autoInclude": false, - "schemas": ["ssh-user"], - "config": { - "sshKey": "...", - "username": "mic92" - } - } - } -} diff --git a/inventory/src/machines/machines.cue b/inventory/src/machines/machines.cue index 36d77e37..cdbeed5f 100644 --- a/inventory/src/machines/machines.cue +++ b/inventory/src/machines/machines.cue @@ -1,8 +1,20 @@ package machines +#ServiceRole: "server" | "client" | "both" + #machine: machines: [string]: { - "name": string, - "description": string, - "icon": string, - "system": string + name: string, + description?: string, + icon?: string, + // each machines service + services?: [string]: { + // Roles if specificed must contain one or more roles + // If no roles are specified, the service module defines the default roles. + roles?: [ ...#ServiceRole ], + // The service config to use + // This config is scoped to the service.module, only serializable data (strings,numbers, etc) can be assigned here + config: { + ... + } + } } \ No newline at end of file diff --git a/inventory/src/root.cue b/inventory/src/root.cue index c3b7496a..3034dab8 100644 --- a/inventory/src/root.cue +++ b/inventory/src/root.cue @@ -3,7 +3,6 @@ package inventory import ( "clan.lol/inventory/services" "clan.lol/inventory/machines" - "clan.lol/inventory/users" ) @jsonschema(schema="http://json-schema.org/schema#") @@ -12,9 +11,9 @@ import ( // A name of the clan (primarily shown by the UI) name: string // A description of the clan - description: string + description?: string // The icon path - icon: string + icon?: string } // A map of services @@ -22,7 +21,4 @@ import ( // A map of machines machines.#machine - - // A map of users - users.#user } diff --git a/inventory/src/services/services.cue b/inventory/src/services/services.cue index c24ef69f..b95e117f 100644 --- a/inventory/src/services/services.cue +++ b/inventory/src/services/services.cue @@ -1,21 +1,30 @@ package services #service: services: [string]: { - autoIncludeMachines: bool, + // Required meta fields meta: { name: string, + icon?: string + description?: string, }, - // TODO: this should be the list of avilable modules + // Required module specifies the behavior of the service. module: string, - machineConfig: { - [string]: { - config: { - defaultUser?: string - } - } - }, - globalConfig: { - // Should be one of the avilable users - defaultUser?: string, + + // We moved the machine sepcific config to "machines". + // It may be moved back depending on what makes more sense in the future. + // machineConfig: { + // [string]: { + // roles: string[], + // config: { + // defaultUser?: string + // } + // } + // }, + + // Configuration for the service + config: { + // Schema depends on the module. + // It declares the interface how the service can be configured. + ... } -} \ No newline at end of file +} diff --git a/inventory/src/tests/1_inventory.json b/inventory/src/tests/1_inventory.json new file mode 100644 index 00000000..58347d2d --- /dev/null +++ b/inventory/src/tests/1_inventory.json @@ -0,0 +1,58 @@ +{ + "machines": { + "jon_machine": { + "name": "jon", + "description": "Jon's machine", + "icon": "assets/icon.png", + "services": { + "matrix": { + "roles": ["server"] + } + } + }, + "anna_machine": { + "name": "anna", + "description": "anna's machine" + } + }, + "meta": { + "name": "clan name" + }, + "services": { + "sync-home": { + "meta": { + "name": "My Home Sync" + }, + "module": "syncthing", + "config": { + "folders": ["/sync/my_f"] + } + }, + "matrix": { + "meta": { + "name": "Our matrix chat", + "description": "Matrix chat service for our clan" + }, + "module": "matrix-synapse", + "config": { + "compression": "zstd" + } + }, + "backup": { + "meta": { + "name": "My daily backup" + }, + "module": "borgbackup", + "config": {} + }, + "borgbackup_1": { + "meta": { + "name": "My weekly backup" + }, + "module": "borgbackup", + "config": { + "compression": "lz4" + } + } + } +} diff --git a/inventory/src/users/users.cue b/inventory/src/users/users.cue deleted file mode 100644 index bdd54067..00000000 --- a/inventory/src/users/users.cue +++ /dev/null @@ -1,9 +0,0 @@ -package users - -#user: users: [string]: { - "autoInclude": bool, - "schemas": [ string ], - "config": { - ... - } -} \ No newline at end of file