Skip to main content

CLI to manage Docker services under /srv/docker (ownership, permissions, ACLs)

Project description

coxyz

CLI to manage Docker services under /srv/docker following coxyz rules (ownership, permissions, POSIX ACLs).

Replaces check_fix_permission.zsh + services.zsh with a single typed Python tool driven by a YAML configuration.

Install

coxyz is published on PyPI as the coxyz-cli package — the installed command stays coxyz. It needs root for most operations (chown / setfacl), so install it system-wide and run it with sudo.

sudo apt install -y pipx

# Install into an isolated venv under /opt, with the binary on the system PATH.
sudo env PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install coxyz-cli

With pipx ≥ 1.5 you can use the shorter sudo pipx install --global coxyz-cli instead. Debian 12 ships pipx 1.4.3, which needs the env form above.

Then run:

sudo coxyz check

Optionally enable shell completion for your user (no sudo):

coxyz --install-completion

Update

sudo env PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx upgrade coxyz-cli

Migrating from a manual install

Earlier setups used hand-written coxyz / coxyz-update wrapper scripts and a venv in /usr/local/libexec/coxyz. Remove them before installing from PyPI:

sudo rm -f  /usr/local/bin/coxyz /usr/local/bin/coxyz-update
sudo rm -rf /usr/local/libexec/coxyz
rm -f ~/.zsh/completions/_coxyz ~/.zcompdump*   # stale completion artefacts

(/etc/coxyz/config.yaml is kept — it is your configuration, not part of the install.)

Configuration

coxyz reads, in order: --config FILE, /etc/coxyz/config.yaml, ~/.config/coxyz/config.yaml, then the bundled defaults.

coxyz show-config       # inspect the resolved config
sudo coxyz edit         # create/edit /etc/coxyz/config.yaml (seeded from defaults)

Example excludes in config.yaml:

exclude:
  - "*.bak"
  - "*/do_not_touch/"

Commands

coxyz list                      # list services with image, ports, status
coxyz list -C apps              # filter by category

coxyz check                     # audit all services (exit 1 on drift)
coxyz check bitwarden           # audit one service
coxyz check apps/bitwarden -v   # verbose (show OK findings too)

coxyz apply                     # preview planned fixes, confirm, then apply
coxyz apply bitwarden -y

coxyz create                    # interactive prompts
coxyz create -C apps -n myapp -i nginx:1.27 -p 80 --apply

coxyz show-config               # print resolved config
coxyz edit                      # edit /etc/coxyz/config.yaml

Most operations require root (chown / setfacl), so prefix with sudo.

How it works

  • Config (/etc/coxyz/config.yaml or bundled default) defines:
    • root dir, ACL principals, authorized categories
    • exclude glob patterns to ignore paths during audit/apply
    • per-path rules: mode, ACL perms, optional owner override, audit-only flag
  • check: read-only audit. Reports drift and warn-only (data/, .env).
  • apply: shows planned changes, asks for confirmation, then applies fixes.
    • Touches: category/service dirs, compose.yaml, the config/ directory.
    • Never touches: data/ contents, .env files (audit-only).
    • Creates required missing directories before applying path fixes.
  • create: scaffolds <category>/<service>/{compose.yaml,config/,data/} with correct owners + perms + ACL.
  • list: parses each compose.yaml for image/ports and runs an audit to show a compliance status.

ACL handling

A path governed by an ACL rule is brought to compliance with a single setfacl --set call that writes the base entries (u::/g::/o::, i.e. the octal mode) and the named entries together. setfacl then recomputes the ACL mask as the union of the owning group and every named entry, so each entry stays fully effective — getfacl never shows an #effective: restriction.

coxyz deliberately never runs chmod on an ACL-managed path: a chmod after a setfacl would rewrite the mask instead of the group bits and silently shrink the effective rights of every named entry.

One consequence: when a named entry grants more than the owning group (e.g. a principal with rw on a 750 directory), the mask widens and ls -l shows the wider group digit (770). That is correct POSIX behaviour — the audit compares ACL entries, not the displayed mode.

File layout (enforced)

/srv/docker/<category>/<service>/
├── compose.yaml      660  svc_<cat>:svc_<cat>  + ACL principals
├── config/           750  svc_<cat>:svc_<cat>  + ACL principals
│   └── ...           (contents not audited)
└── data/             750  svc_<cat>:svc_<cat>  no ACL (audit only)

Development

make test       # run the test suite
make build      # build sdist + wheel into dist/
make release    # tag the current version and push (CI publishes to PyPI)

Releasing: bump __version__ in src/coxyz/__init__.py, commit, then make release. The tag vX.Y.Z triggers .github/workflows/publish.yml, which publishes to PyPI via Trusted Publishing.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

coxyz_cli-0.2.0.tar.gz (26.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

coxyz_cli-0.2.0-py3-none-any.whl (24.0 kB view details)

Uploaded Python 3

File details

Details for the file coxyz_cli-0.2.0.tar.gz.

File metadata

  • Download URL: coxyz_cli-0.2.0.tar.gz
  • Upload date:
  • Size: 26.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for coxyz_cli-0.2.0.tar.gz
Algorithm Hash digest
SHA256 15be865c9d873588002b97fceaf74dadfec0d5fcd9e8753da8baea8c8d508d7b
MD5 595176ee707b31be0f2d37c158b463f8
BLAKE2b-256 9f245ca318a8d98a5bb712c452122036421c623c6c36810a29e043261defab57

See more details on using hashes here.

Provenance

The following attestation bundles were made for coxyz_cli-0.2.0.tar.gz:

Publisher: publish.yml on Ekyoz/Coxyz-CLI

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file coxyz_cli-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: coxyz_cli-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 24.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for coxyz_cli-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2c0d2363c8647f6f3c4a5b76621aea382f04e295c1bae70548c32feda36c2454
MD5 941f4a472d6597906992c28e7a850a12
BLAKE2b-256 f30df47b0ba9f09648bb9acacf1f6159c64d12c2993eb97d8bf75a849da9f692

See more details on using hashes here.

Provenance

The following attestation bundles were made for coxyz_cli-0.2.0-py3-none-any.whl:

Publisher: publish.yml on Ekyoz/Coxyz-CLI

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page