Control-plane CLI for the UTEM platform. Wiz-parity for the
utem code lane (wiz iac scan / wiz docker scan analogue).
From PyPI:
pip install utemFrom Homebrew (tap, since the formula isn't in homebrew-core):
brew tap innavoto/utem https://github.com/Innavoto/utem-homebrew-tap
brew install innavoto/utem/utemFrom source (development):
pip install -e .[dev]Build a wheel + sdist locally:
python -m pip install build
python -m build # -> dist/utem-<version>-py3-none-any.whl + dist/utem-<version>.tar.gzThe CLI reads three values from environment variables (or ~/.utem/config.toml):
| Variable | Default | Required |
|---|---|---|
UTEM_API_URL |
https://utem.innavoto.com |
no |
UTEM_TOKEN |
- | yes |
UTEM_TENANT_ID |
- | yes |
~/.utem/config.toml example:
[utem]
api_url = "https://utem.innavoto.com"
token = "eyJhbGciOi..."
tenant_id = "00000000-0000-0000-0000-000000000000"# 1. List repos visible to your tenant.
utem code repos --owner-type org
# 2. Trigger a scan and wait for it to finish.
utem code scan Innavoto/utem-code --wait
# 3. List the most recent critical secret findings as JSON.
utem code findings --severity critical --type secret --output json| Code | Meaning |
|---|---|
| 0 | Scan succeeded (or queued, no --wait) |
| 1 | Scan reached terminal failed state |
| 2 | --wait polling timed out |
| 3 | API or transport error |
pytest tests/Releases are built and published by CI (.github/workflows/release.yml), never
by hand from a laptop. The workflow is inert until a human triggers it —
it never runs on a normal push/PR.
- Bump
versioninpyproject.toml(and updatepackaging/homebrew/utem.rb'surl/sha256for the new sdist — see below). - Commit the bump, merge to
main. - Tag the release commit and push the tag:
Pushing a
git tag v0.2.0 git push origin v0.2.0
v*tag triggers.github/workflows/release.yml, which:- checks out the tag, runs
python -m build, - runs
twine check dist/*, - publishes to PyPI via
pypa/gh-action-pypi-publishusing the repo secretPYPI_API_TOKEN. The same workflow also supports a manualworkflow_dispatchrun (from the Actions tab) for a dry run (publish=falseinput skips the actualtwine upload/PyPI publish step so you can sanity-check the built artifacts first).
- checks out the tag, runs
- Homebrew tap (
Innavoto/utem-homebrew-tap,Formula/utem.rb) is a separate repo and is updated manually today: after the PyPI publish succeeds, regenerate the resource stanzas withhomebrew-pypi-poetagainst the new sdist and open a PR against the tap repo with the newurl/sha256/resources.packaging/homebrew/utem.rbin this repo is the formula skeleton kept in sync with the live tap for reference/review — it is not itself installed bybrew(the tap repo is).
No step in this flow runs automatically on a normal commit — publishing
always requires either a pushed v* tag or an explicit manual dispatch by a
human with the PYPI_API_TOKEN secret configured on the repo.