One toolchain across the estate. The tree carried 1.26.0, .1, .3, .4 and .5
at once, so which compiler built a binary depended on which repo it came
from.
Co-authored-by: Hanzo Dev <[email protected]>
Currency bump: golang builder images -> 1.26.5 (latest stable).
Adds ENV GOTOOLCHAIN=auto to each Go builder stage. The official golang
images set GOTOOLCHAIN=local, so a builder image older than the module's
go directive is a hard mid-build failure. The pin stays the hermetic fast
path; auto is the safety net for the next go.mod bump.
No go.mod go directive was changed. Builder images move; directives stay.
Co-authored-by: Hanzo Dev <[email protected]>
No v0.3.x tag ever published one. Three defects, each measured on the runner
fleet rather than reasoned about:
- The daemon binary sat at /app/amld and alpine has no /app on PATH, so the
smoke step exited 127 on `command -v amld` before anything ran. It installs
to /usr/local/bin/amld now and the entrypoint names it, so the one name works
from the entrypoint, from `docker run <image> amld`, and from a shell.
- Both smokes published a port and probed the loopback. The step runs inside a
job container while the docker daemon is the runner pod's own, so the
published port binds in the runner's network namespace and the loopback in
the step reaches nothing — measured 000 against a console that was logging
that it served. The probe container now shares the job container's
namespace and is read on its own port; measured 200.
- xxd is not in the runner image. AML_TOKEN_KEY came from it and failed quietly
to empty, because an env prefix on a backgrounded command reports the async
list's status and not the substitution's, so ci.yml has been green for
weeks against a daemon with no key. Hex comes from od/tr and the length is
asserted before the daemon starts.
No product code changes: pkg/, cmd/ and ui/ are untouched.
Co-authored-by: Hanzo Dev <[email protected]>
The daemon was serving its own dashboard from /_/aml/ inside the same pod
and the same image. That is one host doing two jobs: the API belongs at
api.<brand>/v1/aml, one door for data, and a console belongs on its own
host as a compiled bundle. Sharing a pod shares a blast radius and a
rollout, and the embedded copy was unreachable from outside in any case.
ghcr.io/luxfi/aml is now the daemon alone — no UI stage, no embedui tag, no
embed seam. ghcr.io/luxfi/aml-ui is ghcr.io/hanzoai/static with the bundle
in /public and -spa, so a hard refresh on /cases resolves. Both are built
by the release workflow under one tag, so a version names one state of the
product; the console's smoke proves it serves, that SPA_* reaches
config.json, and that a deep link falls back to index.html. CI typechecks
and builds the bundle on every branch, so a type error fails before a
release rather than during one.
Co-authored-by: Hanzo Dev <[email protected]>
A Go AML engine: a configurable rules DSL over expr-lang with weight-of-evidence
scoring, sanctions screening against OFAC/UN/EU/HMT, case management, and scored
alerting. Single binary, embedded SQLite per org, embedded UI.
Surface (all /v1, org-scoped):
/v1/aml/transactions ingest and score
/v1/aml/rules /rules/test the rules DSL and its dry-run
/v1/aml/sanctions/search list screening
/v1/aml/cases investigation workflow
/v1/aml/health
Build: make build produces one static binary with the UI embedded (embedui tag);
bare Go tooling needs no Node. Third-party license and notice texts are generated
from the module graph the linker actually walks and ship beside every artifact.
Co-authored-by: Hanzo Dev <[email protected]>