The screening proxy
imix proxy serve stands between ansible-galaxy, uv and pip and the real Galaxy and PyPI. It caches what they download and serves only what a list of rules allows.
imix proxy serve stands between ansible-galaxy, uv and pip and the real
Galaxy and PyPI. It caches what they download and serves only what a list
of rules allows: collections and roles (Galaxy’s v3 and v1 APIs) and pip
packages (PyPI’s simple index). Refused versions are left out of version
lists, a refused download is a 403, and every refusal is logged (proxy denials). When upstream can’t be reached, the proxy answers from what it
kept.
Lists of rules#
Rules come in named lists, and a client picks one by URL:
http://proxy:8470/web/. Without a list, a client gets default, which
is created empty the first time it’s needed. An empty list denies
everything. A list is text, one rule per line, and the first line that
matches decides, as in ipfw:
# web servers
allow collection nginxinc.nginx_core <0.8
allow collection community.* # nginx_core needs community.crypto
deny any *evil*
allow pip requests >=2.30
default allow role # without it, a kind is denied
Edit a list in $EDITOR with imix proxy -l web edit, which saves only
if every line reads. Tools can work by line number instead:
| Command | What it does |
|---|---|
show | the list (--plain for the raw text) |
insert [--at N] LINE... | add rules |
delete N... | remove rules by number |
replace N LINE | change one |
flush, load FILE | empty the list, or read it from a file |
check KIND NAME [VERSION] | report which line decides |
create, drop, lists | manage lists |
cache | list the cached files |
clean --older-than DAYS | --denied | --all | remove them; --denied removes only files that no list allows any more |
denials | what was refused, and the name the client asked for |
Fetching through it#
The lists live in ~/.instamix/proxy.db (SQLite) and the files in
~/.cache/instamix/proxy. Set INSTAMIX_PROXY=http://proxy:8470, and
env, install and the language server’s installs fetch through it. They
use the list the script names with proxy_list("web"), or
INSTAMIX_PROXY_LIST at run time, which takes precedence. The proxy.url
and proxy.list settings do the same from the config
files, below the environment and the script’s own list.
Pinning a script to reviewed versions#
A name that is no list can be mapped to one. That is how a script pins its
downloads to reviewed versions: proxy_list(script_sha256()) asks for the
list named after the script’s own SHA-256, which gets default (nothing)
until you approve that version:
$ imix proxy map $(sha256sum site.py | cut -c1-64) web
Every edit makes a new hash, so develop with INSTAMIX_PROXY_LIST=web,
and map each version you approve. maps lists the mappings, unmap
removes one, and denials shows the name a refused client asked for
(<hash> -> default).
A blacklist from OSV#
tools/osv_blacklist.py keeps a blacklist from OSV in
a list: deny rules for malicious PyPI packages (the OpenSSF reports) and,
with --vulnerable, for the versions of known vulnerabilities. Run it
again to update (from cron, say); it rewrites only its own # BEGIN osv-blacklist … # END osv-blacklist block, which it puts first in the
list, and each rule names its advisory. Galaxy has no such public source.
$ tools/osv_blacklist.py -l default --vulnerable
list default: 23200 rules from 11750 malicious packages and 13404 vulnerabilities; 3 unreadable versions left out
--allow-rest ends the list with allow any * (once), for a blacklist
rather than a whitelist. tools/install_proxy_units.sh [-l LIST] runs the
proxy as a systemd user service, and that update every 6 hours from a
timer (--print shows the units, --uninstall removes them).